{
  "config": {
    "configFile": "/var/www/360lm/playwright.config.js",
    "rootDir": "/var/www/360lm/tests",
    "forbidOnly": false,
    "fullyParallel": false,
    "globalSetup": null,
    "globalTeardown": null,
    "globalTimeout": 0,
    "grep": {},
    "grepInvert": null,
    "maxFailures": 0,
    "metadata": {
      "actualWorkers": 1
    },
    "preserveOutput": "always",
    "projects": [
      {
        "outputDir": "/var/www/360lm/test-results",
        "repeatEach": 1,
        "retries": 1,
        "metadata": {
          "actualWorkers": 1
        },
        "id": "android-chrome",
        "name": "android-chrome",
        "testDir": "/var/www/360lm/tests",
        "testIgnore": [],
        "testMatch": [
          "**/*.@(spec|test).?(c|m)[jt]s?(x)"
        ],
        "timeout": 30000
      },
      {
        "outputDir": "/var/www/360lm/test-results",
        "repeatEach": 1,
        "retries": 1,
        "metadata": {
          "actualWorkers": 1
        },
        "id": "desktop-chrome",
        "name": "desktop-chrome",
        "testDir": "/var/www/360lm/tests",
        "testIgnore": [],
        "testMatch": [
          "**/*.@(spec|test).?(c|m)[jt]s?(x)"
        ],
        "timeout": 30000
      }
    ],
    "quiet": false,
    "reporter": [
      [
        "json"
      ]
    ],
    "reportSlowTests": {
      "max": 5,
      "threshold": 300000
    },
    "shard": null,
    "tags": [],
    "updateSnapshots": "missing",
    "updateSourceMethod": "patch",
    "version": "1.60.0",
    "workers": 1,
    "webServer": null
  },
  "suites": [
    {
      "title": "recce.spec.js",
      "file": "recce.spec.js",
      "column": 0,
      "line": 0,
      "specs": [],
      "suites": [
        {
          "title": "Branding Recce — Page Load",
          "file": "recce.spec.js",
          "line": 24,
          "column": 6,
          "specs": [
            {
              "title": "no session — page either restricts or loads without crash",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1819,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:18.478Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-1753c18a0885d52c9a8b",
              "file": "recce.spec.js",
              "line": 25,
              "column": 3
            },
            {
              "title": "with hub session — home view renders",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 819,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:21.294Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-4e2ec7a3c80b44ada57c",
              "file": "recce.spec.js",
              "line": 33,
              "column": 3
            },
            {
              "title": "no session — page either restricts or loads without crash",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1039,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:36.078Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-a7868269ce4d683dca11",
              "file": "recce.spec.js",
              "line": 25,
              "column": 3
            },
            {
              "title": "with hub session — home view renders",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 527,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:37.320Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-266a5a3329e21b0c0eb9",
              "file": "recce.spec.js",
              "line": 33,
              "column": 3
            }
          ]
        },
        {
          "title": "Branding Recce — Hero Section",
          "file": "recce.spec.js",
          "line": 43,
          "column": 6,
          "specs": [
            {
              "title": "hero Hub button exists and navigates to /hub/",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1140,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:22.139Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-d0678eca61955c559273",
              "file": "recce.spec.js",
              "line": 48,
              "column": 3
            },
            {
              "title": "hero shows today-date populated (init complete)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 775,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:23.346Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-ce30c36ecd7a8bce1b47",
              "file": "recce.spec.js",
              "line": 58,
              "column": 3
            },
            {
              "title": "hero Hub button exists and navigates to /hub/",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 945,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:37.892Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-28ba7b0f3b4e7160480d",
              "file": "recce.spec.js",
              "line": 48,
              "column": 3
            },
            {
              "title": "hero shows today-date populated (init complete)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 585,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:38.868Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-b2b4a5b858c6f28097a1",
              "file": "recce.spec.js",
              "line": 58,
              "column": 3
            }
          ]
        },
        {
          "title": "Branding Recce — Settings Screen",
          "file": "recce.spec.js",
          "line": 67,
          "column": 6,
          "specs": [
            {
              "title": "settings screen opens via gear icon",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1017,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:24.151Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-7cfdb05507781d19e4c1",
              "file": "recce.spec.js",
              "line": 72,
              "column": 3
            },
            {
              "title": "settings hdr has Hub button (injected by injectHubButtons)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 902,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:25.216Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-43d147e7ce8304f4d248",
              "file": "recce.spec.js",
              "line": 81,
              "column": 3
            },
            {
              "title": "settings Hub button navigates to /hub/",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1019,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:26.154Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-bb4a3763afdab1fd351c",
              "file": "recce.spec.js",
              "line": 91,
              "column": 3
            },
            {
              "title": "settings screen opens via gear icon",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 767,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:39.492Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-44ed18ecb42e594c0b85",
              "file": "recce.spec.js",
              "line": 72,
              "column": 3
            },
            {
              "title": "settings hdr has Hub button (injected by injectHubButtons)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 687,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:40.283Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-a591eb06fe80a692ed9e",
              "file": "recce.spec.js",
              "line": 81,
              "column": 3
            },
            {
              "title": "settings Hub button navigates to /hub/",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1601,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:41.001Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-3a3c6537d3e93ee9628a",
              "file": "recce.spec.js",
              "line": 91,
              "column": 3
            }
          ]
        },
        {
          "title": "Branding Recce — Existing Functionality Unchanged",
          "file": "recce.spec.js",
          "line": 103,
          "column": 6,
          "specs": [
            {
              "title": "stats cards visible on home",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 765,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:27.205Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-583c8d69d0547dbfb56d",
              "file": "recce.spec.js",
              "line": 108,
              "column": 3
            },
            {
              "title": "New Recce button exists in DOM (hidden for admin users, visible for field agents)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 737,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:27.999Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-ec42f7c5c6dd7545fd67",
              "file": "recce.spec.js",
              "line": 115,
              "column": 3
            },
            {
              "title": "language toggle button visible in hero",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1094,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:28.764Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-d82c8374086879bd627f",
              "file": "recce.spec.js",
              "line": 123,
              "column": 3
            },
            {
              "title": "existing Hub button in hero still works",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1686,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:29.900Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-4a8ea58eef21687bc344",
              "file": "recce.spec.js",
              "line": 130,
              "column": 3
            },
            {
              "title": "stats cards visible on home",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1005,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:42.682Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-b8d172515e7502575bed",
              "file": "recce.spec.js",
              "line": 108,
              "column": 3
            },
            {
              "title": "New Recce button exists in DOM (hidden for admin users, visible for field agents)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 578,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:43.767Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-286cffb21bd655860a5c",
              "file": "recce.spec.js",
              "line": 115,
              "column": 3
            },
            {
              "title": "language toggle button visible in hero",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 579,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:44.372Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-d422b9473e63f3982a2e",
              "file": "recce.spec.js",
              "line": 123,
              "column": 3
            },
            {
              "title": "existing Hub button in hero still works",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 825,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:44.976Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-192ed33ae9f0ae180ff9",
              "file": "recce.spec.js",
              "line": 130,
              "column": 3
            }
          ]
        },
        {
          "title": "Branding Recce — v9 Delete Modal (B2/B3/B4 — I1/I3)",
          "file": "recce.spec.js",
          "line": 150,
          "column": 6,
          "specs": [
            {
              "title": "I1: delete toggle button shows \"View Deleted\" (not \"🗑 Deleted\")",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 157,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12878,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:31.628Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 157,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-ffb47deb7915088dce02",
              "file": "recce.spec.js",
              "line": 155,
              "column": 3
            },
            {
              "title": "I1: toggle label flips to \"Hide Deleted\" when clicked",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 166,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12828,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:44.564Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 166,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-7ffcdd277c5c49ea70b0",
              "file": "recce.spec.js",
              "line": 164,
              "column": 3
            },
            {
              "title": "delete modal opens on 🗑 button click",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 176,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 13061,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:42:57.433Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 176,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-74b7d917d5e58853863e",
              "file": "recce.spec.js",
              "line": 174,
              "column": 3
            },
            {
              "title": "B2: confirm button has no-reason class (grey) on modal open",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 186,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12946,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:43:10.541Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 186,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-d164c8cfa7c4ae7dc12d",
              "file": "recce.spec.js",
              "line": 184,
              "column": 3
            },
            {
              "title": "B2: no-reason class removed when reason is selected",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 199,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 13004,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:43:23.511Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 199,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-f28ceb5b4817a96370cd",
              "file": "recce.spec.js",
              "line": 197,
              "column": 3
            },
            {
              "title": "B3: toast fires when Delete clicked without selecting a reason",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 211,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12806,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:43:36.541Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 211,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-8d432e3c43ec933e624f",
              "file": "recce.spec.js",
              "line": 209,
              "column": 3
            },
            {
              "title": "B4: delete modal bdialog has max-height:85vh and overflow-y:auto",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1174,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:43:49.386Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-092aaa8f73d34c439292",
              "file": "recce.spec.js",
              "line": 222,
              "column": 3
            },
            {
              "title": "I3: Test Recce reason option has danger class",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1288,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:43:50.591Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-343e94f579d36f7a757e",
              "file": "recce.spec.js",
              "line": 229,
              "column": 3
            },
            {
              "title": "I3: Test Recce option shows ⚠️ icon",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 730,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:43:51.937Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-fe3ed23b6e3d4d7bf390",
              "file": "recce.spec.js",
              "line": 234,
              "column": 3
            },
            {
              "title": "cancel button closes delete modal cleanly",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 241,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12797,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:43:52.727Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 241,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-596c740377755ffd23af",
              "file": "recce.spec.js",
              "line": 239,
              "column": 3
            },
            {
              "title": "I1: delete toggle button shows \"View Deleted\" (not \"🗑 Deleted\")",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 157,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12740,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:45.823Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 157,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-adbba25ffb365b2f9f89",
              "file": "recce.spec.js",
              "line": 155,
              "column": 3
            },
            {
              "title": "I1: toggle label flips to \"Hide Deleted\" when clicked",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 166,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12820,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:58.589Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 166,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-b832889f85d6527d6aab",
              "file": "recce.spec.js",
              "line": 164,
              "column": 3
            },
            {
              "title": "delete modal opens on 🗑 button click",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 176,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12877,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:47:11.439Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 176,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-566aaf8dada24ba0adec",
              "file": "recce.spec.js",
              "line": 174,
              "column": 3
            },
            {
              "title": "B2: confirm button has no-reason class (grey) on modal open",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 186,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12624,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:47:24.335Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 186,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-02c0045840bc7dd39db5",
              "file": "recce.spec.js",
              "line": 184,
              "column": 3
            },
            {
              "title": "B2: no-reason class removed when reason is selected",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 199,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12899,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:47:36.987Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 199,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-68089c0e18f7fec862dc",
              "file": "recce.spec.js",
              "line": 197,
              "column": 3
            },
            {
              "title": "B3: toast fires when Delete clicked without selecting a reason",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 211,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12881,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:47:49.912Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 211,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-d97019103c7b86a9f55c",
              "file": "recce.spec.js",
              "line": 209,
              "column": 3
            },
            {
              "title": "B4: delete modal bdialog has max-height:85vh and overflow-y:auto",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1016,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:48:02.858Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-62f7a7730d892c776d77",
              "file": "recce.spec.js",
              "line": 222,
              "column": 3
            },
            {
              "title": "I3: Test Recce reason option has danger class",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 708,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:48:03.928Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-2c22af5cd25674047383",
              "file": "recce.spec.js",
              "line": 229,
              "column": 3
            },
            {
              "title": "I3: Test Recce option shows ⚠️ icon",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 555,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:48:04.664Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-2626ce0fbf43e023a673",
              "file": "recce.spec.js",
              "line": 234,
              "column": 3
            },
            {
              "title": "cancel button closes delete modal cleanly",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 241,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12608,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:48:05.257Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 241,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-a0f042117f9f304f199a",
              "file": "recce.spec.js",
              "line": 239,
              "column": 3
            }
          ]
        },
        {
          "title": "Branding Recce — v10 Inside View max 5 photos",
          "file": "recce.spec.js",
          "line": 292,
          "column": 6,
          "specs": [
            {
              "title": "inside view label shows \"(optional, max 5)\"",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 10889,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:44:05.574Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-e5a037bf3a572788f8a5",
              "file": "recce.spec.js",
              "line": 293,
              "column": 3
            },
            {
              "title": "front view label still shows \"(min 1, max 3)\"",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 10595,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:44:16.509Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-2ae6a84e5315a3352ec1",
              "file": "recce.spec.js",
              "line": 307,
              "column": 3
            },
            {
              "title": "add-inside button hidden after 3 photos (before limit) — regression guard",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 916,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:44:27.127Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-57db3c51e2e91116dd5a",
              "file": "recce.spec.js",
              "line": 319,
              "column": 3
            },
            {
              "title": "SW version is recce-v15",
              "ok": false,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 0,
                      "parallelIndex": 0,
                      "status": "failed",
                      "duration": 378,
                      "error": {
                        "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoContain\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // indexOf\u001b[22m\n\nExpected substring: \u001b[32m\"recce-v15\"\u001b[39m\nReceived string:    \u001b[31m\"<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\">\u001b[39m\n\u001b[31m<head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\">\u001b[39m\n\u001b[31m<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\\\">\u001b[39m\n\u001b[31m<meta name=\\\"theme-color\\\" content=\\\"#0f172a\\\">\u001b[39m\n\u001b[31m<meta name=\\\"apple-mobile-web-app-capable\\\" content=\\\"yes\\\">\u001b[39m\n\u001b[31m<title>Branding Recce</title>\u001b[39m\n\u001b[31m<link rel=\\\"manifest\\\" href=\\\"manifest.json\\\">\u001b[39m\n\u001b[31m<link rel=\\\"preconnect\\\" href=\\\"https://fonts.googleapis.com\\\">\u001b[39m\n\u001b[31m<link href=\\\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap\\\" rel=\\\"stylesheet\\\">\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--nv:#0f172a;--nv2:#1e293b;--or:#f97316;--orl:#fed7aa;--gn:#16a34a;--rd:#dc2626;--am:#d97706;--g50:#f8fafc;--g100:#f1f5f9;--g200:#e2e8f0;--g300:#cbd5e1;--g400:#94a3b8;--g500:#64748b;--g600:#475569;--r:12px;--rs:8px;--sh:0 1px 3px rgba(0,0,0,.1),0 1px 2px rgba(0,0,0,.06);--bnav-h:72px;--host-bar:0px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}\u001b[39m\n\u001b[31mbody{font-family:'DM Sans',sans-serif;background:var(--g50);color:var(--nv);min-height:100vh;overflow-x:hidden}\u001b[39m\n\u001b[31m.hdr{background:var(--nv);color:#fff;padding:0 16px;height:56px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}\u001b[39m\n\u001b[31m.hdr-l{display:flex;align-items:center;gap:10px}\u001b[39m\n\u001b[31m.hdr-title{font-size:16px;font-weight:600}.hdr-sub{font-size:11px;color:var(--g400)}\u001b[39m\n\u001b[31m.back-btn,.icon-btn{background:none;border:none;color:#fff;padding:8px;cursor:pointer;display:flex;align-items:center}\u001b[39m\n\u001b[31m.back-btn{margin-left:-8px}\u001b[39m\n\u001b[31m.pgbar{height:3px;background:var(--g200)}.pgfill{height:100%;background:var(--or);transition:width .3s}\u001b[39m\n\u001b[31m.view{display:none;min-height:calc(100vh - 56px);padding-bottom:calc(var(--bnav-h) + var(--host-bar) + 24px)}.view.active{display:block}\u001b[39m\n\u001b[31m.content{padding:16px}\u001b[39m\n\u001b[31m.card{background:#fff;border-radius:var(--r);padding:16px;box-shadow:var(--sh);margin-bottom:12px}\u001b[39m\n\u001b[31m.card-title{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;letter-spacing:.6px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between}\u001b[39m\n\u001b[31m.cnt-badge{background:var(--or);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;min-width:22px;text-align:center}\u001b[39m\n\u001b[31m.cnt-badge.gray{background:var(--g400)}\u001b[39m\n\u001b[31m.field{margin-bottom:16px}.field:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.field label{display:block;font-size:13px;font-weight:500;color:var(--g600);margin-bottom:6px}\u001b[39m\n\u001b[31m.req{color:var(--or);margin-left:2px}\u001b[39m\n\u001b[31m.field input,.field select,.field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;color:var(--nv);background:#fff;transition:border-color .15s;-webkit-appearance:none;appearance:none}\u001b[39m\n\u001b[31m.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--or)}\u001b[39m\n\u001b[31m.field input:read-only{background:var(--g50);color:var(--g600)}\u001b[39m\n\u001b[31m.field textarea{resize:vertical;min-height:68px}\u001b[39m\n\u001b[31m.field select{background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}\u001b[39m\n\u001b[31m.pslot{border:2px dashed var(--g300);border-radius:var(--r);min-height:110px;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all .15s;position:relative;overflow:hidden;text-align:center;padding:16px}\u001b[39m\n\u001b[31m.pslot:active{border-color:var(--or);background:var(--g50)}\u001b[39m\n\u001b[31m.pslot.filled{border-style:solid;border-color:var(--or);padding:0;min-height:0}\u001b[39m\n\u001b[31m.pslot img{width:100%;height:150px;object-fit:cover;border-radius:calc(var(--r) - 2px);display:block}\u001b[39m\n\u001b[31m.pslot-lbl{font-size:13px;color:var(--g400);margin-top:6px}.pslot-ico{font-size:28px;color:var(--g300)}\u001b[39m\n\u001b[31m.pbadge{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.premove{position:absolute;top:6px;right:6px;background:var(--rd);color:#fff;border:none;border-radius:50%;width:26px;height:26px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;z-index:5}\u001b[39m\n\u001b[31minput[type=file]{display:none}\u001b[39m\n\u001b[31m.rgroup{display:flex;gap:10px}\u001b[39m\n\u001b[31m.rbtn{flex:1;padding:13px;border:1.5px solid var(--g200);border-radius:var(--rs);text-align:center;cursor:pointer;font-size:14px;font-weight:500;color:var(--g500);transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.rbtn.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.chip-grid{display:flex;flex-wrap:wrap;gap:8px}\u001b[39m\n\u001b[31m.chip{padding:7px 12px;border:1.5px solid var(--g200);border-radius:20px;font-size:13px;color:var(--g600);cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.chip.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.brand-chip{display:flex;align-items:center;gap:6px;padding:5px 12px}\u001b[39m\n\u001b[31m.brand-chip-logo{width:28px;height:18px;object-fit:contain;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{display:block;width:100%;padding:15px;background:var(--or);color:#fff;border:none;border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:700;cursor:pointer;text-align:center;transition:background .15s}\u001b[39m\n\u001b[31m.btn-p:active{background:#ea6c05}.btn-p:disabled{background:var(--g300);cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-s{display:block;width:100%;padding:14px;background:#fff;color:var(--nv);border:1.5px solid var(--g200);border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:500;cursor:pointer;text-align:center}\u001b[39m\n\u001b[31m.btn-s:active{background:var(--g100)}\u001b[39m\n\u001b[31m.btn-o{display:inline-flex;align-items:center;gap:6px;padding:10px 16px;background:#fff;color:var(--or);border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer}\u001b[39m\n\u001b[31m.btn-o:active{background:var(--orl)}\u001b[39m\n\u001b[31m.btn-d{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;background:#fff;color:var(--rd);border:1.5px solid #fecaca;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:12px;cursor:pointer}\u001b[39m\n\u001b[31m.bnav{position:fixed;bottom:var(--host-bar);left:0;right:0;background:#fff;border-top:1px solid var(--g200);display:flex;padding:10px 16px;gap:10px;z-index:100}\u001b[39m\n\u001b[31m.hero{background:var(--nv);color:#fff;padding:20px 16px 24px}\u001b[39m\n\u001b[31m.hero-title{font-size:22px;font-weight:700;margin-bottom:2px}.hero-sub{font-size:13px;color:var(--g400)}\u001b[39m\n\u001b[31m.stats{display:flex;gap:10px;margin-top:16px}\u001b[39m\n\u001b[31m.scard{flex:1;background:rgba(255,255,255,.08);border-radius:var(--rs);padding:12px;text-align:center}\u001b[39m\n\u001b[31m.snum{font-size:22px;font-weight:700}.slbl{font-size:11px;color:var(--g400);margin-top:2px}\u001b[39m\n\u001b[31m.scard.g .snum{color:#4ade80}.scard.a .snum{color:#fbbf24}\u001b[39m\n\u001b[31m.new-btn{background:var(--or);color:#fff;border:none;border-radius:var(--r);padding:16px;font-family:'DM Sans',sans-serif;font-size:16px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:10px;cursor:pointer;width:100%;margin-bottom:10px}\u001b[39m\n\u001b[31m.new-btn:active{background:#ea6c05}\u001b[39m\n\u001b[31m.resume-btn{background:var(--nv2);color:#fff;border:none;border-radius:var(--r);padding:13px 16px;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;display:flex;align-items:center;justify-content:space-between;cursor:pointer;width:100%;margin-bottom:18px}\u001b[39m\n\u001b[31m.sub-card{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:10px;display:flex;align-items:center;gap:12px}\u001b[39m\n\u001b[31m.sub-ico{width:40px;height:40px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}\u001b[39m\n\u001b[31m.sub-ico.pending{background:#fef3c7}.sub-ico.synced{background:#dcfce7}.sub-ico.failed{background:#fee2e2}\u001b[39m\n\u001b[31m.sub-meta{flex:1;min-width:0}.sub-name{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.sub-dtl{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.sbadge{font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;flex-shrink:0}\u001b[39m\n\u001b[31m.sbadge.pending{background:#fef3c7;color:#92400e}.sbadge.synced{background:#dcfce7;color:#14532d}.sbadge.failed{background:#fee2e2;color:#991b1b}\u001b[39m\n\u001b[31m.sh{display:flex;align-items:center;justify-content:space-between;margin:20px 0 12px}\u001b[39m\n\u001b[31m.st{font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.toast{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 8px);left:16px;right:16px;background:var(--nv);color:#fff;padding:12px 16px;border-radius:var(--r);font-size:14px;z-index:1000;transform:translateY(120px);opacity:0;transition:all .3s;pointer-events:none}\u001b[39m\n\u001b[31m.toast.show{transform:translateY(0);opacity:1}.toast.success{background:#16a34a}.toast.error{background:var(--rd)}.toast.info{background:var(--nv2)}\u001b[39m\n\u001b[31m.srow{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:#fff;border-top:1px solid var(--g100);font-size:12px;color:var(--g500)}\u001b[39m\n\u001b[31m.sdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px}.sdot.on{background:var(--gn)}.sdot.off{background:var(--g300)}\u001b[39m\n\u001b[31m.set-item{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:8px}\u001b[39m\n\u001b[31m.set-lbl{font-size:14px;font-weight:600;color:var(--nv);margin-bottom:4px}\u001b[39m\n\u001b[31m.set-sub{font-size:12px;color:var(--g500);margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem{background:#fff;border-radius:var(--r);border:1.5px solid var(--g200);padding:14px;margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\u001b[39m\n\u001b[31m.bitem-title{font-size:14px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.dim-row{display:flex;gap:8px}.dim-row .field{flex:1}\u001b[39m\n\u001b[31m.sqft{display:inline-block;background:var(--g100);color:var(--g600);font-size:12px;padding:4px 10px;border-radius:20px;margin-top:6px}\u001b[39m\n\u001b[31m.divider{height:1px;background:var(--g100);margin:12px 0}\u001b[39m\n\u001b[31m.rev-lbl{font-size:12px;color:var(--g500);margin-bottom:2px}\u001b[39m\n\u001b[31m.rev-val{font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.rev-photos{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}\u001b[39m\n\u001b[31m.rev-thumb{width:56px;height:56px;object-fit:cover;border-radius:var(--rs)}\u001b[39m\n\u001b[31m.empty{text-align:center;padding:40px 20px;color:var(--g400)}.empty-ico{font-size:40px;margin-bottom:12px}.empty-txt{font-size:14px}\u001b[39m\n\u001b[31m/* store picker */\u001b[39m\n\u001b[31m.store-card{border:1.5px solid var(--g200);border-radius:var(--rs);padding:13px 14px;background:#fff;position:relative;cursor:pointer}\u001b[39m\n\u001b[31m.store-card:active{background:var(--g50)}\u001b[39m\n\u001b[31m.store-card-name{font-size:15px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.store-card-meta{font-size:13px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.store-card-change{position:absolute;top:11px;right:12px;background:none;border:none;color:var(--or);font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer}\u001b[39m\n\u001b[31m.brand-tag{display:inline-block;background:var(--nv);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-top:4px}\u001b[39m\n\u001b[31m.last-chip{display:inline-flex;align-items:center;gap:4px;background:#fef3c7;color:#92400e;font-size:11px;font-weight:500;padding:3px 9px;border-radius:20px;margin-left:6px}\u001b[39m\n\u001b[31m.pick-trigger{border:2px solid var(--or);border-radius:var(--rs);padding:14px 16px;background:#fff7ed;display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-size:15px;font-weight:600;color:var(--or)}\u001b[39m\n\u001b[31m.pick-trigger:active{background:#ffedd5;border-color:#ea6800}\u001b[39m\n\u001b[31m.manual-toggle{display:flex;align-items:center;gap:8px;padding:10px 14px;border:1.5px dashed var(--g300);border-radius:var(--rs);cursor:pointer;font-size:13px;color:var(--g600);margin-top:8px;user-select:none}\u001b[39m\n\u001b[31m/* client chip grid */\u001b[39m\n\u001b[31m.cl-chip-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}\u001b[39m\n\u001b[31m.cl-chip{padding:8px 14px;border-radius:20px;border:1.5px solid var(--g200);font-size:13px;font-weight:500;color:var(--g600);background:#fff;cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.cl-chip:active,.cl-chip.sel{background:var(--or);border-color:var(--or);color:#fff;font-weight:600}\u001b[39m\n\u001b[31m.cl-chip-other{border-style:dashed}\u001b[39m\n\u001b[31m.client-tag{display:inline-block;background:#e0f2fe;color:#0369a1;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-left:4px}\u001b[39m\n\u001b[31m.manual-toggle.on{border-color:var(--or);background:#fff7ed;color:var(--or)}\u001b[39m\n\u001b[31m/* picker overlay */\u001b[39m\n\u001b[31m.povl{display:none;position:fixed;inset:0;background:var(--g50);z-index:200;flex-direction:column}\u001b[39m\n\u001b[31m.povl.open{display:flex}\u001b[39m\n\u001b[31m.povl-hdr{background:var(--nv);padding:12px 16px;display:flex;align-items:center;gap:12px;flex-shrink:0}\u001b[39m\n\u001b[31m.psearch{flex:1;padding:10px 14px;border:none;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;background:rgba(255,255,255,.12);color:#fff;outline:none}\u001b[39m\n\u001b[31m.psearch::placeholder{color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.pcancel{background:none;border:none;color:rgba(255,255,255,.7);font-family:'DM Sans',sans-serif;font-size:14px;cursor:pointer;padding:4px;white-space:nowrap}\u001b[39m\n\u001b[31m.plist{overflow-y:auto;flex:1}\u001b[39m\n\u001b[31m.pitem{padding:14px 16px;border-bottom:.5px solid var(--g100);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px}\u001b[39m\n\u001b[31m.pitem:active{background:var(--g100)}\u001b[39m\n\u001b[31m.pi-name{font-size:15px;font-weight:600;color:var(--nv)}.pi-addr{font-size:12px;color:var(--g500);margin-top:2px}.pi-last{font-size:11px;color:var(--am);margin-top:2px}\u001b[39m\n\u001b[31m.pi-brand{font-size:11px;font-weight:700;padding:3px 8px;border-radius:20px;background:var(--nv);color:#fff;flex-shrink:0}\u001b[39m\n\u001b[31m.psec{padding:8px 16px 4px;font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;background:var(--g50)}\u001b[39m\n\u001b[31m.padd{padding:16px;text-align:center;font-size:14px;color:var(--or);font-weight:600;cursor:pointer;background:#fff7ed;border-top:1.5px dashed var(--or)}\u001b[39m\n\u001b[31m.gps-row{display:flex;gap:8px;margin-top:8px}\u001b[39m\n\u001b[31m.gps-btn{flex-shrink:0;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;color:var(--g500);display:flex;align-items:center;gap:6px}\u001b[39m\n\u001b[31m.gps-btn:active{background:var(--orl);border-color:var(--or);color:var(--or)}\u001b[39m\n\u001b[31m@keyframes spin{to{transform:rotate(360deg)}}.spin{animation:spin .7s linear infinite;display:inline-block}\u001b[39m\n\u001b[31m/* ANNOTATION TOOL */\u001b[39m\n\u001b[31m.annot-modal{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column}\u001b[39m\n\u001b[31m.annot-modal.open{display:flex}\u001b[39m\n\u001b[31m.annot-bar{background:var(--nv);padding:8px 12px;flex-shrink:0}\u001b[39m\n\u001b[31m.annot-row{display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap}\u001b[39m\n\u001b[31m.annot-row:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.atool{padding:6px 10px;background:rgba(255,255,255,.1);border:1.5px solid rgba(255,255,255,.2);border-radius:var(--rs);color:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:500;cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.atool.on{background:var(--or);border-color:var(--or)}\u001b[39m\n\u001b[31m.atool.sel-on{background:#7c3aed;border-color:#7c3aed}\u001b[39m\n\u001b[31m.acolor{width:24px;height:24px;border-radius:50%;border:2px solid rgba(255,255,255,.3);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.acolor.on{border-color:#fff;border-width:3px;transform:scale(1.15)}\u001b[39m\n\u001b[31m.annot-cvs-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#111;position:relative}\u001b[39m\n\u001b[31m#annot-cvs{max-width:100%;max-height:100%;display:block;touch-action:none;cursor:crosshair}\u001b[39m\n\u001b[31m.annot-foot{background:var(--nv);padding:10px 16px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.req-note{font-size:12px;color:var(--rd);margin-top:6px;font-weight:500}\u001b[39m\n\u001b[31m/* Bottom dialog */\u001b[39m\n\u001b[31m.bdialog-wrap{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:400;align-items:flex-end}\u001b[39m\n\u001b[31m.bdialog-wrap.open{display:flex}\u001b[39m\n\u001b[31m.bdialog{background:#fff;border-radius:var(--r) var(--r) 0 0;padding:20px 16px 32px;width:100%}\u001b[39m\n\u001b[31m.bdialog-title{font-size:16px;font-weight:700;color:var(--nv);margin-bottom:6px}\u001b[39m\n\u001b[31m.bdialog-sub{font-size:13px;color:var(--g500);margin-bottom:16px}\u001b[39m\n\u001b[31m.bdialog-btns{display:flex;gap:10px}\u001b[39m\n\u001b[31m/* Edit badge on sub-card */\u001b[39m\n\u001b[31m.edit-btn-sm{padding:5px 12px;background:var(--g50);border:1px solid var(--g200);border-radius:20px;font-family:'DM Sans',sans-serif;font-size:12px;color:var(--g600);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m/* Toggle switch */\u001b[39m\n\u001b[31m.tog{width:48px;height:26px;background:var(--g300);border-radius:13px;cursor:pointer;transition:background .2s;flex-shrink:0;position:relative;display:inline-block}\u001b[39m\n\u001b[31m.tog.on{background:var(--or)}\u001b[39m\n\u001b[31m.tog-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2);pointer-events:none}\u001b[39m\n\u001b[31m.tog.on .tog-knob{transform:translateX(22px)}\u001b[39m\n\u001b[31m/* ── ADMIN RECCE VIEW ── */\u001b[39m\n\u001b[31m.af-bar{background:var(--g100);padding:10px 16px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--g200);overflow:hidden}\u001b[39m\n\u001b[31m.af-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}\u001b[39m\n\u001b[31m.af-sel{width:100%;padding:8px 10px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv);cursor:pointer;\u001b[39m\n\u001b[31m  white-space:normal;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.af-sel:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.af-inp{width:100%;padding:8px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv)}\u001b[39m\n\u001b[31m.af-inp:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.grp-hdr{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;\u001b[39m\n\u001b[31m  letter-spacing:.5px;padding:14px 0 6px;border-bottom:1px solid var(--g200);margin-bottom:6px}\u001b[39m\n\u001b[31m.grp-hdr:first-child{padding-top:0}\u001b[39m\n\u001b[31m.asc{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:12px 14px;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;gap:6px;margin-bottom:8px;cursor:pointer;\u001b[39m\n\u001b[31m  transition:box-shadow .15s}\u001b[39m\n\u001b[31m.asc:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.asc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}\u001b[39m\n\u001b[31m.asc-name{font-size:14px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.asc-brand{display:inline-block;background:#fff7ed;color:var(--or);font-size:11px;\u001b[39m\n\u001b[31m  font-weight:600;padding:2px 8px;border-radius:20px;border:1px solid #fed7aa;white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chip{background:var(--g100);border-radius:20px;padding:2px 8px;font-size:11px;color:var(--g600);white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chips{display:flex;flex-wrap:wrap;gap:5px}\u001b[39m\n\u001b[31m.asc-agent{background:var(--nv);color:#fff;font-size:11px;font-weight:600;\u001b[39m\n\u001b[31m  padding:2px 8px;border-radius:20px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m/* Admin detail modal */\u001b[39m\n\u001b[31m.ardl-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:600;\u001b[39m\n\u001b[31m  display:flex;align-items:flex-end;justify-content:center}\u001b[39m\n\u001b[31m.ardl-box{background:#fff;border-radius:var(--r) var(--r) 0 0;width:100%;max-height:80vh;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ardl-hdr{display:flex;align-items:flex-start;justify-content:space-between;\u001b[39m\n\u001b[31m  padding:16px 16px 10px;border-bottom:1px solid var(--g200);gap:10px}\u001b[39m\n\u001b[31m.ardl-title{font-size:17px;font-weight:700;color:var(--nv);line-height:1.3}\u001b[39m\n\u001b[31m.ardl-body{flex:1;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:14px}\u001b[39m\n\u001b[31m.ardl-sec{display:flex;flex-direction:column;gap:6px}\u001b[39m\n\u001b[31m.ardl-lbl{font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.ardl-val{font-size:13px;color:var(--nv);line-height:1.5}\u001b[39m\n\u001b[31m.ardl-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\u001b[39m\n\u001b[31m/* Hub home button */\u001b[39m\n\u001b[31m.btn-hub{background:none;border:1px solid rgba(255,255,255,.25);color:rgba(255,255,255,.85);\u001b[39m\n\u001b[31m  font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;cursor:pointer;\u001b[39m\n\u001b[31m  display:flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-hub:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hdr-r{display:flex;align-items:center;gap:6px;margin-left:auto;flex-shrink:0}\u001b[39m\n\u001b[31m.hdr-user{font-size:11px;color:rgba(255,255,255,.7);white-space:nowrap;max-width:80px;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.btn-logout{background:none;border:1px solid rgba(255,255,255,.2);color:rgba(255,255,255,.7);font-size:11px;font-weight:600;padding:4px 8px;border-radius:20px;cursor:pointer;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-logout:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hero-ubar{display:flex;align-items:center;justify-content:space-between;padding-top:6px;margin-top:2px}\u001b[39m\n\u001b[31m.hero-uname{font-size:12px;color:rgba(255,255,255,.65)}\u001b[39m\n\u001b[31m.hi-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .en-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .hi-txt{display:inline}\u001b[39m\n\u001b[31m.lang-btn{background:none;border:1px solid rgba(255,255,255,.3);color:rgba(255,255,255,.8);font-size:12px;font-weight:700;padding:4px 10px;border-radius:20px;cursor:pointer;display:flex;align-items:center;gap:3px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.lang-btn:active{background:rgba(255,255,255,.15)}\u001b[39m\n\u001b[31m/* ── DELETE / AUDIT ── */\u001b[39m\n\u001b[31m.del-btn{background:none;border:none;padding:6px 8px;cursor:pointer;color:var(--g400);font-size:16px;flex-shrink:0;border-radius:var(--rs);transition:color .15s,background .15s}\u001b[39m\n\u001b[31m.del-btn:active{color:var(--rd);background:#fee2e2}\u001b[39m\n\u001b[31m.asc.deleted-row{background:#fff5f5;border:1px solid #fecaca;opacity:.85}\u001b[39m\n\u001b[31m.asc.deleted-row .asc-name{text-decoration:line-through;color:var(--g500)}\u001b[39m\n\u001b[31m.del-reason-tag{display:inline-block;background:#fee2e2;color:var(--rd);font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.del-by-txt{font-size:11px;color:var(--g400);margin-top:3px}\u001b[39m\n\u001b[31m.restore-btn{background:none;border:1.5px solid #bbf7d0;border-radius:20px;color:#16a34a;font-size:11px;font-weight:700;padding:3px 10px;cursor:pointer;white-space:nowrap;margin-top:5px}\u001b[39m\n\u001b[31m.restore-btn:active{background:#dcfce7}\u001b[39m\n\u001b[31m.sup-tile{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:20px 16px;cursor:pointer;display:flex;align-items:center;gap:14px;margin-bottom:12px;transition:box-shadow .15s}\u001b[39m\n\u001b[31m.sup-tile:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.sup-tile-ico{width:48px;height:48px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:26px;flex-shrink:0}\u001b[39m\n\u001b[31m.sup-tile-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.sup-tile-title{font-size:15px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.sup-tile-sub{font-size:12px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.del-toggle-btn{padding:6px 14px;border:1.5px solid var(--g200);border-radius:20px;background:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:600;color:var(--g500);cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.del-toggle-btn.active{background:#fee2e2;border-color:#fecaca;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1.5px solid var(--g200);border-radius:var(--r);margin-bottom:10px;cursor:pointer;transition:all .15s;font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.reason-opt:active{background:var(--g50)}\u001b[39m\n\u001b[31m.reason-opt.sel{border-color:var(--rd);background:#fff5f5;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt.danger{border-color:#fdba74;background:#fff7ed;color:#9a3412}\u001b[39m\n\u001b[31m.reason-opt.danger.sel{border-color:#c2410c;background:#fff1e6;color:#9a3412}\u001b[39m\n\u001b[31m#del-confirm-btn.no-reason{background:var(--g300)!important;cursor:default}\u001b[39m\n\u001b[31m@keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}\u001b[39m\n\u001b[31m.reason-opt-ico{font-size:22px;flex-shrink:0}\u001b[39m\n\u001b[31m/* ── APP UPDATE BANNER ── */\u001b[39m\n\u001b[31m.upd-banner{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);left:12px;right:12px;background:#16a34a;color:#fff;padding:11px 14px;border-radius:var(--r);display:flex;align-items:center;justify-content:space-between;gap:10px;z-index:550;box-shadow:0 4px 16px rgba(0,0,0,.18);transform:translateY(120px);opacity:0;transition:transform .35s ease,opacity .35s ease;pointer-events:none}\u001b[39m\n\u001b[31m.upd-banner.show{transform:translateY(0);opacity:1;pointer-events:auto}\u001b[39m\n\u001b[31m/* ── EDIT REQUEST ── */\u001b[39m\n\u001b[31m.req-edit-btn{padding:4px 10px;background:#fffbeb;border:1px solid #fde68a;border-radius:20px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:600;color:#92400e;cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.req-edit-btn:active{background:#fef3c7}\u001b[39m\n\u001b[31m.edit-req-badge{display:inline-block;background:#fef3c7;color:#92400e;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;white-space:nowrap}\u001b[39m\n\u001b[31m.edit-req-card{background:#fffbeb;border:1.5px solid #fde68a;border-radius:var(--r);padding:14px 16px;margin-bottom:10px;display:flex;align-items:flex-start;gap:12px}\u001b[39m\n\u001b[31m.edit-req-card-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.edit-req-card-name{font-size:14px;font-weight:600;color:var(--nv);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.edit-req-card-meta{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.edit-req-cmt{font-size:12px;color:#78350f;background:#fff;border:1px solid #fde68a;border-radius:var(--rs);padding:8px 10px;margin-top:8px;line-height:1.5}\u001b[39m\n\u001b[31m.edit-req-section-hdr{font-size:11px;font-weight:700;color:#92400e;text-transform:uppercase;letter-spacing:.5px;padding:10px 0 6px;border-bottom:1px solid #fde68a;margin-bottom:8px}\u001b[39m\n\u001b[31m.upd-banner-ok{background:rgba(255,255,255,.2);border:none;color:#fff;border-radius:20px;padding:5px 13px;font-size:12px;font-weight:600;cursor:pointer;font-family:'DM Sans',sans-serif;white-space:nowrap}\u001b[39m\n\u001b[31m.upd-banner-ok:active{background:rgba(255,255,255,.35)}\u001b[39m\n\u001b[31m/* ── FONT SIZE WIDGET ── */\u001b[39m\n\u001b[31m.fs-widget{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);right:12px;display:flex;align-items:center;gap:0;background:#fff;border:1.5px solid var(--g200);border-radius:24px;box-shadow:0 2px 8px rgba(0,0,0,.12);z-index:500;overflow:hidden;user-select:none}\u001b[39m\n\u001b[31m.fs-btn{background:none;border:none;cursor:pointer;padding:7px 11px;color:var(--g500);line-height:1;transition:background .15s}\u001b[39m\n\u001b[31m.fs-btn:active{background:var(--g100)}\u001b[39m\n\u001b[31m.fs-btn:disabled{color:var(--g300);cursor:default}\u001b[39m\n\u001b[31m.fs-label{font-size:11px;font-weight:700;color:var(--g500);padding:0 4px;pointer-events:none}\u001b[39m\n\u001b[31m/* Level 1 — Large (+15%) */\u001b[39m\n\u001b[31mbody.fs-1 .field label,body.fs-1 .card-title,body.fs-1 .set-lbl,body.fs-1 .set-sub,\u001b[39m\n\u001b[31mbody.fs-1 .hdr-title,body.fs-1 .hdr-sub,body.fs-1 .slbl,body.fs-1 .rev-lbl,body.fs-1 .rev-val,\u001b[39m\n\u001b[31mbody.fs-1 .rbtn,body.fs-1 .chip,body.fs-1 .btn-p,body.fs-1 .btn-s,body.fs-1 .btn-o,\u001b[39m\n\u001b[31mbody.fs-1 .bdialog-title,body.fs-1 .bdialog-sub,body.fs-1 .sub-name,body.fs-1 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-1 .pslot-lbl,body.fs-1 .bitem-title,body.fs-1 .pi-name,body.fs-1 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-1 .asc-name,body.fs-1 .new-btn,body.fs-1 .resume-btn,body.fs-1 .ardl-lbl,body.fs-1 .ardl-val{font-size:calc(1em * 1.15) !important}\u001b[39m\n\u001b[31m/* Level 2 — X-Large (+30%) */\u001b[39m\n\u001b[31mbody.fs-2 .field label,body.fs-2 .card-title,body.fs-2 .set-lbl,body.fs-2 .set-sub,\u001b[39m\n\u001b[31mbody.fs-2 .hdr-title,body.fs-2 .hdr-sub,body.fs-2 .slbl,body.fs-2 .rev-lbl,body.fs-2 .rev-val,\u001b[39m\n\u001b[31mbody.fs-2 .rbtn,body.fs-2 .chip,body.fs-2 .btn-p,body.fs-2 .btn-s,body.fs-2 .btn-o,\u001b[39m\n\u001b[31mbody.fs-2 .bdialog-title,body.fs-2 .bdialog-sub,body.fs-2 .sub-name,body.fs-2 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-2 .pslot-lbl,body.fs-2 .bitem-title,body.fs-2 .pi-name,body.fs-2 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-2 .asc-name,body.fs-2 .new-btn,body.fs-2 .resume-btn,body.fs-2 .ardl-lbl,body.fs-2 .ardl-val{font-size:calc(1em * 1.30) !important}\u001b[39m\n\u001b[31m/* Level 3 — XX-Large (+50%) */\u001b[39m\n\u001b[31mbody.fs-3 .field label,body.fs-3 .card-title,body.fs-3 .set-lbl,body.fs-3 .set-sub,\u001b[39m\n\u001b[31mbody.fs-3 .hdr-title,body.fs-3 .hdr-sub,body.fs-3 .slbl,body.fs-3 .rev-lbl,body.fs-3 .rev-val,\u001b[39m\n\u001b[31mbody.fs-3 .rbtn,body.fs-3 .chip,body.fs-3 .btn-p,body.fs-3 .btn-s,body.fs-3 .btn-o,\u001b[39m\n\u001b[31mbody.fs-3 .bdialog-title,body.fs-3 .bdialog-sub,body.fs-3 .sub-name,body.fs-3 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-3 .pslot-lbl,body.fs-3 .bitem-title,body.fs-3 .pi-name,body.fs-3 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-3 .asc-name,body.fs-3 .new-btn,body.fs-3 .resume-btn,body.fs-3 .ardl-lbl,body.fs-3 .ardl-val{font-size:calc(1em * 1.50) !important}\u001b[39m\n\u001b[31m/* Level 4 — Max (+70%) */\u001b[39m\n\u001b[31mbody.fs-4 .field label,body.fs-4 .card-title,body.fs-4 .set-lbl,body.fs-4 .set-sub,\u001b[39m\n\u001b[31mbody.fs-4 .hdr-title,body.fs-4 .hdr-sub,body.fs-4 .slbl,body.fs-4 .rev-lbl,body.fs-4 .rev-val,\u001b[39m\n\u001b[31mbody.fs-4 .rbtn,body.fs-4 .chip,body.fs-4 .btn-p,body.fs-4 .btn-s,body.fs-4 .btn-o,\u001b[39m\n\u001b[31mbody.fs-4 .bdialog-title,body.fs-4 .bdialog-sub,body.fs-4 .sub-name,body.fs-4 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-4 .pslot-lbl,body.fs-4 .bitem-title,body.fs-4 .pi-name,body.fs-4 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-4 .asc-name,body.fs-4 .new-btn,body.fs-4 .resume-btn,body.fs-4 .ardl-lbl,body.fs-4 .ardl-val{font-size:calc(1em * 1.70) !important}\u001b[39m\n\u001b[31m/* ── RECCE TILE ACTION BUTTONS ── */\u001b[39m\n\u001b[31m.rpt-btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid rgba(0,0,0,.06)}\u001b[39m\n\u001b[31m.rpt-btn{display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 14px;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;border:none;font-family:inherit;transition:background .15s,opacity .15s;flex:1;min-width:110px;letter-spacing:.1px;white-space:nowrap}\u001b[39m\n\u001b[31m.rpt-btn-report{background:#fff7ed;color:var(--or);border:1.5px solid var(--or)}\u001b[39m\n\u001b[31m.rpt-btn-report:active{background:#fed7aa}\u001b[39m\n\u001b[31m.rpt-btn-pdf{background:var(--g100);color:var(--g400);border:1.5px solid var(--g200)}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready{background:var(--or);color:#fff;border-color:transparent}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready:active{background:#ea6c00}\u001b[39m\n\u001b[31m/* PDF wait overlay */\u001b[39m\n\u001b[31m#pdf-wait-ov{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m</style>\u001b[39m\n\u001b[31m</head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<!-- PICKER OVERLAY -->\u001b[39m\n\u001b[31m<div class=\\\"povl\\\" id=\\\"povl\\\">\u001b[39m\n\u001b[31m  <div class=\\\"povl-hdr\\\">\u001b[39m\n\u001b[31m    <input class=\\\"psearch\\\" id=\\\"psearch\\\" type=\\\"text\\\" placeholder=\\\"Search store / दुकान खोजें…\\\" oninput=\\\"filterPicker(this.value)\\\" autocomplete=\\\"off\\\">\u001b[39m\n\u001b[31m    <button class=\\\"pcancel\\\" onclick=\\\"closePicker()\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"plist\\\" id=\\\"plist\\\"></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"app\\\">·\u001b[39m\n\u001b[31m<!-- HOME -->\u001b[39m\n\u001b[31m<div class=\\\"view active\\\" id=\\\"view-home\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hero\\\">\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;justify-content:space-between;align-items:center\\\">\u001b[39m\n\u001b[31m      <div><div class=\\\"hero-title\\\"><span class=\\\"en-txt\\\">Branding Recce</span><span class=\\\"hi-txt\\\">ब्रांडिंग रेकी</span></div><div class=\\\"hero-sub\\\" id=\\\"today-date\\\">—</div></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:6px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"lang-btn\\\" onclick=\\\"setLang(LANG==='en'?'hi':'en')\\\" id=\\\"lang-btn\\\" title=\\\"Switch language / भाषा बदलें\\\">EN | हि</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-hub\\\" onclick=\\\"goToHub()\\\">🏡 Hub</button>\u001b[39m\n\u001b[31m      <button class=\\\"icon-btn\\\" onclick=\\\"showView('settings')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12 15a3 3 0 100-6 3 3 0 000 6z\\\"/><path d=\\\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\\\"/></svg></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"hero-ubar\\\" id=\\\"recce-hero-ubar\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <span class=\\\"hero-uname\\\" id=\\\"recce-hero-name\\\"></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-logout\\\" onclick=\\\"recceLogout()\\\">Logout</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"stats\\\">\u001b[39m\n\u001b[31m      <div class=\\\"scard g\\\"><div class=\\\"snum\\\" id=\\\"stat-synced\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Synced</span><span class=\\\"hi-txt\\\">सिंक्ड</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard a\\\"><div class=\\\"snum\\\" id=\\\"stat-pending\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Pending</span><span class=\\\"hi-txt\\\">बाकी</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard\\\"><div class=\\\"snum\\\" id=\\\"stat-total\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Total</span><span class=\\\"hi-txt\\\">कुल</span></div></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <button class=\\\"new-btn\\\" onclick=\\\"startNewRecce()\\\"><svg width=\\\"20\\\" height=\\\"20\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">New Recce</span><span class=\\\"hi-txt\\\">नई रेकी</span></button>\u001b[39m\n\u001b[31m    <div id=\\\"resume-wrap\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"sh\\\"><span class=\\\"st\\\"><span class=\\\"en-txt\\\">Recent Submissions</span><span class=\\\"hi-txt\\\">हाल की सबमिशन</span></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"syncNow()\\\" id=\\\"sync-btn\\\" style=\\\"padding:7px 12px;font-size:12px\\\"><svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg><span class=\\\"en-txt\\\">Sync</span><span class=\\\"hi-txt\\\">सिंक</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"sub-list\\\"></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"srow\\\"><div><span class=\\\"sdot\\\" id=\\\"net-dot\\\"></span><span id=\\\"net-txt\\\"><span class=\\\"en-txt\\\">Checking…</span><span class=\\\"hi-txt\\\">जाँच…</span></span></div><span id=\\\"last-sync-txt\\\" style=\\\"font-size:11px\\\"><span class=\\\"en-txt\\\">Never synced</span><span class=\\\"hi-txt\\\">कभी सिंक नहीं</span></span></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- SETTINGS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-settings\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('home')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Settings</span><span class=\\\"hi-txt\\\">सेटिंग</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Brand List</span><span class=\\\"hi-txt\\\">ब्रांड सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Manage Brands</span><span class=\\\"hi-txt\\\">ब्रांड प्रबंधन</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">These appear in the brand dropdown and store picker. Add client brands as needed.</div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-manage-list\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-add-row\\\" style=\\\"display:none;gap:8px;align-items:center\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"brand-add-inp\\\" placeholder=\\\"Type brand name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addBrandToList()\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"addBrandToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Store Lists</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Supervisors can upload XLS/CSV store lists here. Updates sync to all devices via server.</span><span class=\\\"hi-txt\\\">सुपरवाइजर यहाँ XLS/CSV स्टोर सूची अपलोड कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m      <!-- Upload/Clear row — supervisor only -->\u001b[39m\n\u001b[31m      <div id=\\\"store-upload-row\\\" style=\\\"display:none;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;margin-top:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"document.getElementById('store-xl').click()\\\"><svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Add File</span><span class=\\\"hi-txt\\\">फ़ाइल जोड़ें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-d\\\" onclick=\\\"clearStoreList()\\\" style=\\\"font-size:12px\\\"><span class=\\\"en-txt\\\">Clear All Stores</span><span class=\\\"hi-txt\\\">सभी स्टोर हटाएं</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" id=\\\"store-push-btn\\\" onclick=\\\"pushStoresToServer()\\\" style=\\\"font-size:12px;display:none\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Push to Server</span><span class=\\\"hi-txt\\\">सर्वर पर पुश करें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"store-xl\\\" accept=\\\".xlsx,.xls,.csv\\\" onchange=\\\"handleStoreUpload(event)\\\">\u001b[39m\n\u001b[31m      <div id=\\\"store-count\\\" style=\\\"font-size:13px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"store-file-list\\\" style=\\\"margin-top:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Brand assignment dialog for files with no brand column -->\u001b[39m\n\u001b[31m    <div id=\\\"brand-assign-dialog\\\" style=\\\"display:none;margin-top:10px;padding:14px;background:#fff7ed;border:1.5px solid var(--or);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\">Which brand is this store list for?</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\" id=\\\"brand-assign-fname\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-assign-chips\\\" class=\\\"chip-grid\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"confirmBrandAssign()\\\" style=\\\"flex:2;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">Assign Brand</span><span class=\\\"hi-txt\\\">ब्रांड असाइन करें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"skipBrandAssign()\\\" style=\\\"flex:1;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">No Brand</span><span class=\\\"hi-txt\\\">कोई ब्रांड नहीं</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Server Store List URL (Admin)</span><span class=\\\"hi-txt\\\">सर्वर स्टोर सूची URL</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Admin pushes stores.json to any public URL. App auto-fetches on open and caches offline.</div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"srv-url\\\" placeholder=\\\"https://yourserver.com/stores.json\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"fetchServerStores()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Fetch Now</button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"saveServerUrl()\\\" style=\\\"padding:9px 14px;font-size:13px;width:auto\\\">Save URL</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Sync Endpoint</span><span class=\\\"hi-txt\\\">सिंक एंडपॉइंट</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Slides Generator</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Managed by admin. Deploy gas_slides.gs from /opt/slides-proxy/ to Google Apps Script and paste the URL here.</div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"slides-gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Not configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"slides-gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"saveSlidesGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Sheet Sync</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Legacy sync endpoint. Writes recce data to Google Sheet.</div>·\u001b[39m\n\u001b[31m      <!-- Locked state (default) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Endpoint configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Unlocked state (after admin login) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;align-items:center;gap:8px;margin-bottom:10px;padding:7px 12px;background:#dcfce7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          <span style=\\\"font-size:12px;color:#14532d;font-weight:600\\\">🔓 Admin mode active</span>\u001b[39m\n\u001b[31m          <button onclick=\\\"lockAdmin()\\\" style=\\\"margin-left:auto;background:none;border:none;color:#14532d;font-size:12px;cursor:pointer;font-weight:600\\\">Lock ×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"testEndpoint()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Test</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>·\u001b[39m\n\u001b[31m    <!-- Admin Login Modal -->\u001b[39m\n\u001b[31m    <div id=\\\"admin-login-modal\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m      <div style=\\\"background:#fff;border-radius:var(--r);padding:24px 20px;margin:20px;max-width:380px;width:100%;box-shadow:0 8px 32px rgba(0,0,0,.2)\\\">\u001b[39m\n\u001b[31m        <div style=\\\"font-size:17px;font-weight:700;color:var(--nv);margin-bottom:4px\\\">Admin Login</div>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:18px\\\">Enter admin password to unlock settings</div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m          <label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">Password</label>\u001b[39m\n\u001b[31m          <input type=\\\"password\\\" id=\\\"admin-pwd\\\" placeholder=\\\"Enter admin password\\\" style=\\\"width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px\\\" onkeydown=\\\"if(event.key==='Enter')verifyAdmin()\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div id=\\\"admin-error\\\" style=\\\"display:none;font-size:12px;color:var(--rd);margin-bottom:12px;padding:8px 12px;background:#fee2e2;border-radius:var(--rs)\\\">Incorrect password</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"verifyAdmin()\\\" style=\\\"flex:2;padding:13px\\\" id=\\\"admin-login-btn\\\">Login</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-s\\\" onclick=\\\"closeAdminLogin()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:14px;padding-top:14px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.4px;margin-bottom:8px\\\">Admin Password Config URL</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:8px\\\">URL to your admin.json file on server (contains hashed password)</div>\u001b[39m\n\u001b[31m          <input type=\\\"url\\\" id=\\\"admin-cfg-url\\\" placeholder=\\\"https://yourserver.com/admin.json\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px;margin-bottom:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveAdminCfgUrl()\\\" style=\\\"font-size:12px;padding:7px 12px;width:100%;justify-content:center\\\">Save Config URL</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Geolocation Stamp</span><span class=\\\"hi-txt\\\">जियोलोकेशन स्टैम्प</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;justify-content:space-between;gap:16px\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1\\\">\u001b[39m\n\u001b[31m          <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Stamp on Photos</span><span class=\\\"hi-txt\\\">फोटो पर स्टैम्प</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"set-sub\\\" style=\\\"margin-bottom:0\\\">Bakes GPS coordinates, store name and timestamp into every photo — visible in the image itself. Same as GPS Map Camera app. Default: On.</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"tog on\\\" id=\\\"geo-tog\\\" onclick=\\\"toggleGeoStamp()\\\"><div class=\\\"tog-knob\\\"></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"geo-status\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\">GPS not yet captured</div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Image Quality</span><span class=\\\"hi-txt\\\">फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Default Photo Quality</span><span class=\\\"hi-txt\\\">डिफ़ॉल्ट फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Applies to all photos — front view, inside view, branding, and additional. HD uses more storage and takes longer to sync on poor networks.</div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;gap:10px;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-compressed\\\" onclick=\\\"setImgQuality('compressed')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-compressed\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-compressed\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">Full Compression</span><span class=\\\"hi-txt\\\">पूर्ण कम्प्रेशन</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~150–200 KB · Max 1280px · Best for poor network</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-left:auto;font-size:11px;font-weight:700;color:var(--gn);background:#dcfce7;padding:3px 8px;border-radius:20px\\\"><span class=\\\"en-txt\\\">Recommended</span><span class=\\\"hi-txt\\\">अनुशंसित</span></div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-hd\\\" onclick=\\\"setImgQuality('hd')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-hd\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-hd\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">HD Quality</span><span class=\\\"hi-txt\\\">HD क्वालिटी</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~400–600 KB · Max 1920px · Better detail for print</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"q-current-badge\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Supervisor Config panel — shown only to supervisors via renderSupPanel() -->\u001b[39m\n\u001b[31m    <div id=\\\"sup-panel\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">🔐 Recce Access Config</span><span class=\\\"hi-txt\\\">🔐 रेकी एक्सेस कॉन्फ़िग</span></div>\u001b[39m\n\u001b[31m      <!-- Access mode — only H/P can change -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"mode-row\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Access Mode</span><span class=\\\"hi-txt\\\">एक्सेस मोड</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Public: any Hub user can submit Recces. Assigned: only Supervisors and Creators can access.</span><span class=\\\"hi-txt\\\">सार्वजनिक: कोई भी Hub यूजर। नियत: सिर्फ़ Supervisors और Creators।</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\" style=\\\"margin-bottom:8px;margin-top:8px\\\">\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-public\\\" onclick=\\\"setRecceMode('public')\\\"><span class=\\\"en-txt\\\">Public</span><span class=\\\"hi-txt\\\">सार्वजनिक</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-assigned\\\" onclick=\\\"setRecceMode('assigned')\\\"><span class=\\\"en-txt\\\">Assigned</span><span class=\\\"hi-txt\\\">नियत</span></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Supervisor list — view all + delete + create -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Supervisors</span><span class=\\\"hi-txt\\\">सुपरवाइजर</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can view all recces, delete with reason, and submit. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">सभी रेकी देख सकते हैं, कारण से हटा सकते हैं, और सबमिट कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"sup-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addSupervisor()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addSupervisor()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Creator list — creation only -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Creators</span><span class=\\\"hi-txt\\\">क्रिएटर्स</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can submit Recces only — no admin view or deletion rights. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">केवल रेकी सबमिट कर सकते हैं — एडमिन व्यू या डिलीट नहीं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"creator-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addCreator()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addCreator()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Client list — used for client portal scoping -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clients</span><span class=\\\"hi-txt\\\">क्लाइंट</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Names that appear as chips when submitting a recce. Add the brand or agency name (e.g. \\\"Marketing Vibe\\\"). These are used to scope what clients see in the Client Portal.</span><span class=\\\"hi-txt\\\">रेकी सबमिट करते समय दिखने वाले क्लाइंट नाम। ब्रांड या एजेंसी नाम जोड़ें।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-mgmt-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"client-add-inp\\\" placeholder=\\\"Client name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addClientToList()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addClientToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Sync to server — only H/P -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"cfg-sync-btn\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Sync Config to Server</span><span class=\\\"hi-txt\\\">सर्वर पर कॉन्फ़िग सिंक करें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Apply supervisor/creator/client lists and access mode to all devices.</span><span class=\\\"hi-txt\\\">सभी डिवाइस पर कॉन्फ़िग लागू करें।</span></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"syncCfgToServer()\\\" style=\\\"max-width:220px;font-size:14px;padding:12px;margin-top:8px\\\"><span class=\\\"en-txt\\\">Sync to Server</span><span class=\\\"hi-txt\\\">सर्वर पर सिंक करें</span></button>\u001b[39m\n\u001b[31m        <div id=\\\"cfg-sync-status\\\" style=\\\"margin-top:8px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Danger Zone</span><span class=\\\"hi-txt\\\">खतरनाक ज़ोन</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\"><div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clear All Local Data</span><span class=\\\"hi-txt\\\">सभी डेटा हटाएं</span></div><div class=\\\"set-sub\\\">Removes all submissions from this device.</div><button class=\\\"btn-d\\\" onclick=\\\"clearData()\\\" style=\\\"padding:9px 14px;font-size:13px\\\">Clear All</button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: STORE INFO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-store\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"exitForm()\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Details</span><span class=\\\"hi-txt\\\">दुकान विवरण</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 1 of 5</span><span class=\\\"hi-txt\\\">चरण 1 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:20%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Recce Info</span><span class=\\\"hi-txt\\\">रेकी जानकारी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Date of Recce</span><span class=\\\"hi-txt\\\">रेकी की तारीख</span> <span class=\\\"req\\\">*</span></label><input type=\\\"date\\\" id=\\\"f-date\\\" onchange=\\\"saveDraft()\\\" max=\\\"\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" id=\\\"campaign-field\\\">\u001b[39m\n\u001b[31m        <label><span class=\\\"en-txt\\\">Job / Campaign</span><span class=\\\"hi-txt\\\">जॉब / कैंपेन</span></label>\u001b[39m\n\u001b[31m        <select id=\\\"f-campaign-id\\\" onchange=\\\"onCampaignSelect()\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">Loading campaigns…</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <div id=\\\"campaign-notify-msg\\\" style=\\\"display:none;font-size:12px;color:#92400e;margin-top:6px;padding:8px 10px;background:#fef3c7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          ⚑ <span class=\\\"en-txt\\\">Recce will submit without a job ID. A notification will flag this for your supervisor to link it later.</span><span class=\\\"hi-txt\\\">रेकी बिना जॉब ID के सबमिट होगी। सुपरवाइजर बाद में लिंक करेगा।</span>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Store</span><span class=\\\"hi-txt\\\">दुकान</span> <span id=\\\"store-avail-tag\\\" style=\\\"font-size:11px;color:var(--g400);font-weight:400;text-transform:none;letter-spacing:0\\\"></span></div>·\u001b[39m\n\u001b[31m      <!-- When store is selected -->\u001b[39m\n\u001b[31m      <div id=\\\"store-selected\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"store-card\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:start;justify-content:space-between;gap:8px\\\">\u001b[39m\n\u001b[31m            <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m              <div class=\\\"store-card-name\\\" id=\\\"sc-name\\\">—</div>\u001b[39m\n\u001b[31m              <div style=\\\"display:flex;align-items:center;gap:6px;margin-top:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m                <span class=\\\"brand-tag\\\" id=\\\"sc-brand\\\">—</span>\u001b[39m\n\u001b[31m                <span class=\\\"last-chip\\\" id=\\\"sc-last\\\" style=\\\"display:none\\\">—</span>\u001b[39m\n\u001b[31m              </div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            <button class=\\\"store-card-change\\\" onclick=\\\"openPicker()\\\"><span class=\\\"en-txt\\\">Change ›</span><span class=\\\"hi-txt\\\">बदलें ›</span></button>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <!-- All fields from Excel shown here -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-details\\\" style=\\\"margin-top:10px;display:flex;flex-direction:column;gap:4px\\\"></div>\u001b[39m\n\u001b[31m          <!-- Missing required fields — editable inline -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-missing\\\" style=\\\"display:none;margin-top:12px;padding-top:12px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m            <div style=\\\"font-size:11px;font-weight:700;color:var(--rd);text-transform:uppercase;letter-spacing:.4px;margin-bottom:10px\\\">⚠ Please complete missing fields</div>\u001b[39m\n\u001b[31m            <div id=\\\"sc-missing-fields\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <!-- Brand selector — shown when store has no brand -->\u001b[39m\n\u001b[31m        <div id=\\\"brand-selector\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\"><span class=\\\"en-txt\\\">Select Brand</span><span class=\\\"hi-txt\\\">ब्रांड चुनें</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\">This store has no brand in the list — select one:</div>\u001b[39m\n\u001b[31m          <div id=\\\"brand-chips\\\" class=\\\"chip-grid\\\"></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Picker trigger (shown when stores loaded) -->\u001b[39m\n\u001b[31m      <div id=\\\"pick-trigger-wrap\\\">\u001b[39m\n\u001b[31m        <div class=\\\"pick-trigger\\\" onclick=\\\"openPicker()\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:center;gap:10px\\\">\u001b[39m\n\u001b[31m            <span style=\\\"font-size:20px\\\">🏪</span>\u001b[39m\n\u001b[31m            <div>\u001b[39m\n\u001b[31m              <div style=\\\"font-size:15px;font-weight:700;color:var(--or)\\\"><span class=\\\"en-txt\\\">Select Store from List</span><span class=\\\"hi-txt\\\">सूची से दुकान चुनें</span></div>\u001b[39m\n\u001b[31m              <div id=\\\"store-avail-count\\\" style=\\\"font-size:12px;font-weight:400;color:var(--am);margin-top:1px\\\"><span class=\\\"en-txt\\\">Tap to browse stores</span><span class=\\\"hi-txt\\\">दुकान खोजने के लिए दबाएं</span></div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual / new store toggle -->\u001b[39m\n\u001b[31m      <div class=\\\"manual-toggle\\\" id=\\\"manual-toggle\\\" onclick=\\\"toggleManual()\\\">\u001b[39m\n\u001b[31m        <svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\" id=\\\"mt-icon\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg>\u001b[39m\n\u001b[31m        <span id=\\\"mt-label\\\"><span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span></span>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual fields -->\u001b[39m\n\u001b[31m      <div id=\\\"manual-fields\\\" style=\\\"display:none;margin-top:14px\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\" style=\\\"margin-bottom:14px\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <select id=\\\"f-brand\\\" onchange=\\\"onManualBrandChange()\\\">\u001b[39m\n\u001b[31m            <option value=\\\"\\\">Select brand</option>\u001b[39m\n\u001b[31m          </select>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span> <span class=\\\"req\\\">*</span></label><input type=\\\"text\\\" id=\\\"f-store\\\" placeholder=\\\"Enter store name\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\">\u001b[39m\n\u001b[31m          <label><span class=\\\"en-txt\\\">Store Address</span><span class=\\\"hi-txt\\\">दुकान का पता</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <textarea id=\\\"f-addr\\\" rows=\\\"2\\\" placeholder=\\\"Full address\\\" onchange=\\\"saveDraft()\\\"></textarea>\u001b[39m\n\u001b[31m          <div class=\\\"gps-row\\\">\u001b[39m\n\u001b[31m            <button class=\\\"gps-btn\\\" onclick=\\\"captureGPS()\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\"/><path d=\\\"M12 2v3M12 19v3M2 12h3M19 12h3\\\"/></svg><span class=\\\"en-txt\\\">Capture GPS</span><span class=\\\"hi-txt\\\">GPS लें</span></button>\u001b[39m\n\u001b[31m            <span id=\\\"gps-status\\\" style=\\\"font-size:12px;color:var(--g500);align-self:center\\\"></span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Mobile No.</span><span class=\\\"hi-txt\\\">मोबाइल नंबर</span></label><input type=\\\"tel\\\" id=\\\"f-mobile\\\" placeholder=\\\"10-digit number\\\" maxlength=\\\"10\\\" inputmode=\\\"numeric\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Client card -->\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Client</span><span class=\\\"hi-txt\\\">क्लाइंट</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\"><span class=\\\"en-txt\\\">Select who this recce is for. Defaults to brand — change if work came via an agency.</span><span class=\\\"hi-txt\\\">यह रेकी किसके लिए है चुनें। ब्रांड से डिफ़ॉल्ट — एजेंसी के ज़रिए हो तो बदलें।</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"cl-chip-grid\\\" id=\\\"client-chips\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"client-other-wrap\\\" style=\\\"display:none;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"f-client-other\\\" placeholder=\\\"Type client name\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" oninput=\\\"onClientOtherInput()\\\">\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-p\\\" onclick=\\\"step2()\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: PHOTOS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-photos\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-store')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Photos</span><span class=\\\"hi-txt\\\">दुकान की फोटो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 2 of 5</span><span class=\\\"hi-txt\\\">चरण 2 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:40%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Front View</span><span class=\\\"hi-txt\\\">आगे का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(min 1, max 3)</span><span class=\\\"cnt-badge gray\\\" id=\\\"front-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"front-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-front\\\" onclick=\\\"addPhoto('front')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Front Photo</span><span class=\\\"hi-txt\\\">आगे की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Inside View</span><span class=\\\"hi-txt\\\">अंदर का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 5)</span><span class=\\\"cnt-badge gray\\\" id=\\\"inside-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"inside-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-inside\\\" onclick=\\\"addPhoto('inside')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Inside Photo</span><span class=\\\"hi-txt\\\">अंदर की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-store')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step3()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: VIDEO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-video\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-photos')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Recce Video</span><span class=\\\"hi-txt\\\">रेकी वीडियो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 3 of 5</span><span class=\\\"hi-txt\\\">चरण 3 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:60%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Video</span><span class=\\\"hi-txt\\\">वीडियो</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Recce video available?</span><span class=\\\"hi-txt\\\">रेकी वीडियो है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"vid-yes\\\" onclick=\\\"setVideo(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"vid-no\\\" onclick=\\\"setVideo(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"vid-sec\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Upload Video</span><span class=\\\"hi-txt\\\">वीडियो अपलोड करें</span></label>\u001b[39m\n\u001b[31m          <div class=\\\"pslot\\\" id=\\\"vid-slot\\\" onclick=\\\"document.getElementById('vid-inp').click()\\\"><div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div></div>\u001b[39m\n\u001b[31m          <input type=\\\"file\\\" id=\\\"vid-inp\\\" accept=\\\"video/*\\\" onchange=\\\"handleVideo(event)\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Video Comments</span><span class=\\\"hi-txt\\\">वीडियो टिप्पणी</span></label><input type=\\\"text\\\" id=\\\"f-vid-cmt\\\" placeholder=\\\"Optional\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-photos')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step4()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: BRANDING -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-branding\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-video')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Branding</span><span class=\\\"hi-txt\\\">ब्रांडिंग</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 4 of 5</span><span class=\\\"hi-txt\\\">चरण 4 / 5</span></div></div></div>\u001b[39m\n\u001b[31m    <span id=\\\"br-hdr-badge\\\" style=\\\"background:rgba(255,255,255,.2);color:#fff;font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px\\\"><span class=\\\"en-txt\\\">0 items</span><span class=\\\"hi-txt\\\">0 आइटम</span></span>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:80%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Branding Space</span><span class=\\\"hi-txt\\\">ब्रांडिंग स्थान</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Space available?</span><span class=\\\"hi-txt\\\">जगह उपलब्ध है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"br-yes\\\" onclick=\\\"setBranding(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"br-no\\\" onclick=\\\"setBranding(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"branding-lock-banner\\\" style=\\\"display:none;background:#fef3c7;border:1.5px solid #f59e0b;border-radius:10px;padding:12px 14px;margin-bottom:10px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:700;color:#92400e\\\">Client approval exists — branding locked</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:#78350f;margin-top:4px\\\"><span class=\\\"en-txt\\\">The client has reviewed this recce. Create a new recce to revise branding items.</span><span class=\\\"hi-txt\\\">क्लाइंट ने रेकी की समीक्षा की है। बदलाव के लिए नई रेकी बनाएं।</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"branding-override-wrap\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m        <button onclick=\\\"unlockBrandingOverride()\\\" style=\\\"background:#f59e0b;color:#000;border:none;border-radius:8px;padding:8px 14px;font-size:12px;font-weight:700;cursor:pointer\\\">Override Edit (H&amp;P only)</button>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:11px;color:#92400e;margin-top:5px\\\">Use only when client has verbally confirmed and app needs correction.</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"br-items\\\"></div>\u001b[39m\n\u001b[31m    <div id=\\\"br-add\\\" style=\\\"display:none;margin-bottom:80px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"addBranding()\\\" style=\\\"width:100%;justify-content:center\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Another Branding Item</span><span class=\\\"hi-txt\\\">एक और ब्रांडिंग जोड़ें</span></button>\u001b[39m\n\u001b[31m      <div style=\\\"text-align:center;font-size:12px;color:var(--g400);margin-top:8px\\\"><span class=\\\"en-txt\\\">Tap Continue below when done adding items</span><span class=\\\"hi-txt\\\">सभी आइटम जोड़ने के बाद आगे दबाएं</span></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-video')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step5()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: ADDITIONAL + SUBMIT -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-additional\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-branding')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Submit</span><span class=\\\"hi-txt\\\">सबमिट</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 5 of 5</span><span class=\\\"hi-txt\\\">चरण 5 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:100%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Mandatory Document</span><span class=\\\"hi-txt\\\">अनिवार्य दस्तावेज़</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"pslot\\\" id=\\\"doc-slot\\\" onclick=\\\"document.getElementById('doc-inp').click()\\\"><div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div></div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"doc-inp\\\" accept=\\\"image/*,.pdf\\\" onchange=\\\"handleDoc(event)\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Additional Photos</span><span class=\\\"hi-txt\\\">अतिरिक्त फोटो</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 8)</span><span class=\\\"cnt-badge gray\\\" id=\\\"addl-badge\\\">0 / 8</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"add-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-addl\\\" onclick=\\\"addAdditional()\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\"><div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Review</span><span class=\\\"hi-txt\\\">समीक्षा</span></div><div id=\\\"rev-body\\\"></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-branding')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"submitRecce()\\\" id=\\\"sub-btn\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Submit Recce ✓</span><span class=\\\"hi-txt\\\">रेकी सबमिट करें ✓</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- ANNOTATION MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"annot-modal\\\" id=\\\"annot-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"annot-bar\\\">\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Draw:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"at-rect\\\"    onclick=\\\"setATool('rect')\\\">▭ Rect</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-ellipse\\\" onclick=\\\"setATool('ellipse')\\\">◯ Ellipse</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-line\\\"    onclick=\\\"setATool('line')\\\">╱ Line</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-arrow\\\"   onclick=\\\"setATool('arrow')\\\">↗ Arrow</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-free\\\"    onclick=\\\"setATool('free')\\\">✏ Free</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool sel-on\\\" id=\\\"at-move\\\" onclick=\\\"setATool('move')\\\" style=\\\"margin-left:4px\\\">⊹ Move</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Color:</span>\u001b[39m\n\u001b[31m      <div class=\\\"acolor on\\\" id=\\\"ac-or\\\" style=\\\"background:#f97316\\\" onclick=\\\"setAColor('#f97316')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-rd\\\" style=\\\"background:#ef4444\\\" onclick=\\\"setAColor('#ef4444')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-wh\\\" style=\\\"background:#ffffff\\\" onclick=\\\"setAColor('#ffffff')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-yw\\\" style=\\\"background:#facc15\\\" onclick=\\\"setAColor('#facc15')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-gn\\\" style=\\\"background:#22c55e\\\" onclick=\\\"setAColor('#22c55e')\\\"></div>\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Width:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-2\\\" onclick=\\\"setAWidth(2)\\\" style=\\\"padding:5px 8px\\\">Thin</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"aw-4\\\" onclick=\\\"setAWidth(4)\\\" style=\\\"padding:5px 8px\\\">Med</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-7\\\" onclick=\\\"setAWidth(7)\\\" style=\\\"padding:5px 8px\\\">Thick</button>\u001b[39m\n\u001b[31m      <div style=\\\"flex:1\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"undoAnnot()\\\">↩</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"clearAnnot()\\\">✕</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"annot-sel-info\\\" style=\\\"display:none;font-size:11px;color:#facc15;padding:4px 0 2px\\\">\u001b[39m\n\u001b[31m      Shape selected — drag to move · drag corners to resize · tap elsewhere to deselect\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-cvs-wrap\\\"><canvas id=\\\"annot-cvs\\\"></canvas></div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-foot\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-s\\\" onclick=\\\"skipAnnot()\\\" style=\\\"flex:1;padding:12px;font-size:14px\\\"><span class=\\\"en-txt\\\">Skip markup</span><span class=\\\"hi-txt\\\">मार्कअप छोड़ें</span></button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" onclick=\\\"saveAnnot()\\\" style=\\\"flex:2;padding:12px\\\"><span class=\\\"en-txt\\\">Done — Save ✓</span><span class=\\\"hi-txt\\\">हो गया — सेव करें ✓</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EXIT DIALOG -->\u001b[39m\n\u001b[31m<!-- MODAL: Link Job to Recce (supervisor only) -->\u001b[39m\n\u001b[31m<div id=\\\"modal-link-job\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m  <div style=\\\"background:#fff;border-radius:14px;padding:20px;width:90%;max-width:380px;display:flex;flex-direction:column;gap:12px;box-shadow:0 8px 32px rgba(0,0,0,.35)\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:15px;font-weight:700;color:#1e293b\\\">&#x1F517; Link Job to Recce</div>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-store\\\" style=\\\"font-size:13px;color:#64748b\\\"></div>\u001b[39m\n\u001b[31m    <select id=\\\"link-job-sel\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m      <option value=\\\"\\\">&#x2014; Select campaign &#x2014;</option>\u001b[39m\n\u001b[31m    </select>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-err\\\" style=\\\"font-size:12px;color:#ef4444;min-height:14px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"closeLinkJobModal()\\\" style=\\\"flex:1;padding:12px;border:1px solid #cbd5e1;border-radius:8px;cursor:pointer;background:#f8fafc;font-size:14px\\\">Cancel</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"saveLinkJob()\\\" style=\\\"flex:2;padding:12px;background:#f59e0b;color:#000;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:700\\\">&#x1F517; Link Job</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"exit-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Exit Recce?</span><span class=\\\"hi-txt\\\">रेकी से बाहर?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Your progress and photos will be saved as a draft. Resume anytime from the home screen.</span><span class=\\\"hi-txt\\\">आपकी प्रगति और फोटो ड्राफ्ट में सेव होंगी। होम स्क्रीन से कभी भी जारी रखें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"exitSaveAndLeave()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">💾 Save Draft & Exit</span><span class=\\\"hi-txt\\\">💾 ड्राफ्ट सेव करें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-d\\\" onclick=\\\"exitDiscard()\\\" style=\\\"flex:1;padding:13px;font-size:13px\\\"><span class=\\\"en-txt\\\">Discard</span><span class=\\\"hi-txt\\\">हटाएं</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"exitCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">← Continue Recce</span><span class=\\\"hi-txt\\\">← रेकी जारी रखें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- PHOTO SOURCE PICKER -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"photo-src-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Camera photos get GPS stamp baked in. Gallery photos are added without stamp.</span><span class=\\\"hi-txt\\\">कैमरा फोटो में GPS स्टैम्प लगती है। गैलरी फोटो में नहीं।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"photoSrcCamera()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">📷 Use Camera</span><span class=\\\"hi-txt\\\">📷 कैमरा</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">GPS stamp applied</span><span class=\\\"hi-txt\\\">GPS स्टैम्प लगेगी</span></span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"photoSrcGallery()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">🖼 Choose from Gallery</span><span class=\\\"hi-txt\\\">🖼 गैलरी से चुनें</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">No stamp</span><span class=\\\"hi-txt\\\">स्टैम्प नहीं</span></span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"photoSrcCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- STORE PREVIEW DIALOG -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"store-preview-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:80vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"store-preview-title\\\"><span class=\\\"en-txt\\\">Preview Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची का प्रीव्यू</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Review before adding to your store list:</span><span class=\\\"hi-txt\\\">जोड़ने से पहले जाँचें:</span></div>\u001b[39m\n\u001b[31m    <div style=\\\"overflow-x:auto;margin-bottom:14px\\\">\u001b[39m\n\u001b[31m      <table style=\\\"width:100%;border-collapse:collapse;font-size:12px\\\">\u001b[39m\n\u001b[31m        <thead><tr style=\\\"background:var(--nv);color:#fff\\\">\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Address</span><span class=\\\"hi-txt\\\">पता</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Mobile</span><span class=\\\"hi-txt\\\">मोबाइल</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span></th>\u001b[39m\n\u001b[31m        </tr></thead>\u001b[39m\n\u001b[31m        <tbody id=\\\"store-preview-body\\\"></tbody>\u001b[39m\n\u001b[31m      </table>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"confirmStorePreview()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">✓ Confirm & Add Stores</span><span class=\\\"hi-txt\\\">✓ स्टोर जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"cancelStorePreview()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BOTTOM DIALOG (branding additional photo prompt) -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"bdialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add reference photos?</span><span class=\\\"hi-txt\\\">संदर्भ फोटो जोड़ें?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Add extra photos for this branding item for future reference.</span><span class=\\\"hi-txt\\\">इस ब्रांडिंग आइटम के लिए अतिरिक्त फोटो जोड़ें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"bdialogYes()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">Yes, add photos</span><span class=\\\"hi-txt\\\">हाँ, जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"bdialogNo()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Skip</span><span class=\\\"hi-txt\\\">छोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- DELETE REASON MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"delete-reason-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"padding-bottom:28px;max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">🗑 Delete Recce</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"del-modal-sub\\\">Select reason for deletion:</div>\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-wrong\\\" onclick=\\\"selectDeleteReason('wrong')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">❌</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Wrong</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Incorrect store / submission error</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-duplicate\\\" onclick=\\\"selectDeleteReason('duplicate')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">📋</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Duplicate</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Same store submitted more than once</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt danger\\\" id=\\\"reason-test\\\" onclick=\\\"selectDeleteReason('test')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">⚠️</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Test Recce</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:#9a3412;margin-top:2px\\\">Permanently deleted — no audit trail</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p no-reason\\\" id=\\\"del-confirm-btn\\\" onclick=\\\"confirmDelete()\\\" style=\\\"flex:2;padding:13px;background:var(--rd)\\\">Delete</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"closeDeleteModal()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EDIT REQUEST MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"edit-req-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Request Edit</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"er-store-name\\\" style=\\\"font-weight:600;color:var(--nv);margin-bottom:4px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:14px\\\">Add a note for the creator (optional)</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m      <textarea id=\\\"er-comment\\\" placeholder=\\\"e.g. Please re-check store address and re-upload front photo\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;color:var(--nv);resize:vertical;min-height:80px;background:#fff\\\"></textarea>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button id=\\\"er-assign-btn\\\" class=\\\"btn-p\\\" onclick=\\\"assignEditToCreator()\\\" style=\\\"padding:14px\\\">👤 Assign to Creator</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"supervisorEditMyself()\\\" style=\\\"padding:14px\\\">✏ Edit Myself</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"closeEditRequestModal()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BRAND EDIT MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"brand-edit-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Edit Brand</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Brand Name <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"text\\\" id=\\\"be-name\\\" placeholder=\\\"e.g. PHILIPS\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:600;text-transform:uppercase\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Logo URL <span style=\\\"font-size:11px;font-weight:400;color:var(--g400)\\\">(optional)</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"url\\\" id=\\\"be-logo\\\" placeholder=\\\"https://…/logo.svg\\\" oninput=\\\"previewBrandLogo()\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px\\\">\u001b[39m\n\u001b[31m      <div id=\\\"be-logo-preview\\\" style=\\\"margin-top:8px;min-height:36px;display:flex;align-items:center;gap:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"be-cascade-info\\\" style=\\\"display:none;font-size:12px;color:var(--g500);padding:8px 12px;background:var(--g50);border-radius:var(--rs);margin-bottom:12px\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"saveBrandEdit()\\\" style=\\\"padding:14px\\\">Save</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"closeBrandEditModal()\\\" style=\\\"width:100%;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FONT SIZE WIDGET -->\u001b[39m\n\u001b[31m<div class=\\\"fs-widget\\\" id=\\\"fs-widget\\\">\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-dec\\\" onclick=\\\"changeFontSize(-1)\\\" title=\\\"Decrease font size\\\" aria-label=\\\"Decrease font size\\\">A<sup style=\\\"font-size:9px\\\">−</sup></button>\u001b[39m\n\u001b[31m  <span class=\\\"fs-label\\\" id=\\\"fs-lbl\\\">A</span>\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-inc\\\" onclick=\\\"changeFontSize(1)\\\" title=\\\"Increase font size\\\" aria-label=\\\"Increase font size\\\"><strong>A</strong><sup style=\\\"font-size:9px\\\">+</sup></button>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"upd-banner\\\" id=\\\"upd-banner\\\">\u001b[39m\n\u001b[31m  <span style=\\\"font-size:13px;font-weight:600;line-height:1.4\\\"><span class=\\\"en-txt\\\">✓ App updated to latest version</span><span class=\\\"hi-txt\\\">✓ ऐप नया संस्करण अपडेट हुआ</span></span>\u001b[39m\n\u001b[31m  <button class=\\\"upd-banner-ok\\\" onclick=\\\"dismissUpdateBanner()\\\"><span class=\\\"en-txt\\\">OK</span><span class=\\\"hi-txt\\\">ठीक है</span></button>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m<div class=\\\"toast\\\" id=\\\"toast\\\"></div>\u001b[39m\n\u001b[31m<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js\\\"></script>\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m// LANGUAGE\u001b[39m\n\u001b[31mlet LANG = localStorage.getItem('recce-lang') || 'en';\u001b[39m\n\u001b[31mfunction setLang(l) {\u001b[39m\n\u001b[31m  LANG = l;\u001b[39m\n\u001b[31m  localStorage.setItem('recce-lang', l);\u001b[39m\n\u001b[31m  document.body.classList.toggle('lang-hi', l === 'hi');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction t(en, hi) { return LANG === 'hi' ? hi : en; }·\u001b[39m\n\u001b[31m// FONT SIZE\u001b[39m\n\u001b[31mlet FS_LEVEL = parseInt(localStorage.getItem('recce-fs') || '0', 10);\u001b[39m\n\u001b[31mconst FS_LABELS = ['A', 'A+', 'A++', 'A+++', 'A++++'];\u001b[39m\n\u001b[31mfunction applyFontSize() {\u001b[39m\n\u001b[31m  document.body.classList.remove('fs-0', 'fs-1', 'fs-2');\u001b[39m\n\u001b[31m  if (FS_LEVEL > 0) document.body.classList.add('fs-' + FS_LEVEL);\u001b[39m\n\u001b[31m  const lbl = document.getElementById('fs-lbl');\u001b[39m\n\u001b[31m  if (lbl) lbl.textContent = FS_LABELS[FS_LEVEL];\u001b[39m\n\u001b[31m  const dec = document.getElementById('fs-dec');\u001b[39m\n\u001b[31m  const inc = document.getElementById('fs-inc');\u001b[39m\n\u001b[31m  if (dec) dec.disabled = FS_LEVEL === 0;\u001b[39m\n\u001b[31m  if (inc) inc.disabled = FS_LEVEL === 4;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction changeFontSize(delta) {\u001b[39m\n\u001b[31m  FS_LEVEL = Math.min(4, Math.max(0, FS_LEVEL + delta));\u001b[39m\n\u001b[31m  localStorage.setItem('recce-fs', FS_LEVEL);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Hub auth gate\u001b[39m\n\u001b[31m(function() {\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (!s || !s.loginAt || Date.now() - new Date(s.loginAt).getTime() > 12 * 3600 * 1000) {\u001b[39m\n\u001b[31m      window.location.replace('/hub/');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) { window.location.replace('/hub/'); }\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31m// STATE\u001b[39m\n\u001b[31mlet F={},frontPhotos=[],insidePhotos=[],addlPhotos=[],brandings=[];\u001b[39m\n\u001b[31mlet videoBlob=null,submissionDoc=null,_docExistingUrl=null,gpsCoords=null;\u001b[39m\n\u001b[31mlet stores=[],selectedStore=null,manualMode=false,DB;\u001b[39m\n\u001b[31mlet imgQuality='compressed'; // 'compressed' | 'hd'\u001b[39m\n\u001b[31mlet geoStampEnabled=true;    // stamp GPS+timestamp on every photo\u001b[39m\n\u001b[31mlet brands=['PHILIPS']; // editable brand list\u001b[39m\n\u001b[31mlet _brandLogos={};   // name → logo_url, loaded from DB\u001b[39m\n\u001b[31mlet _selectedClient=''; // currently selected client chip value\u001b[39m\n\u001b[31mlet _clientOtherMode=false; // true when \\\"Other\\\" chip selected\u001b[39m\n\u001b[31mconst BTYPE=['Glow Sign Board','Inshop Branding','ACP Board','One Way Vision','Fabric Board','Lollypop','Non Lit Flex','Double Side GSB','Clip on Board','Translit','Vinyl Printing','Roll up Standee','Sunboard Standee'];\u001b[39m\n\u001b[31mconst CACHE_VER='recce-v37'; // campaign dropdown + pending job link tab·\u001b[39m\n\u001b[31m// DB\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',3);r.onupgradeneeded=e=>{const d=e.target.result;['subs','cfg','draft'].forEach(s=>{if(!d.objectStoreNames.contains(s))d.createObjectStore(s,{keyPath:'k'||'id'});});if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);});}\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',4);r.onupgradeneeded=e=>{const d=e.target.result;if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);})}\u001b[39m\n\u001b[31mfunction dbGet(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).get(k);r.onsuccess=()=>res(r.result);r.onerror=()=>res(null);}catch{res(null)}})}\u001b[39m\n\u001b[31mfunction dbPut(s,v){return new Promise((res,rej)=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).put(v);r.onsuccess=()=>res();r.onerror=()=>rej();}catch(e){rej(e)}})}\u001b[39m\n\u001b[31mfunction dbAll(s){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).getAll();r.onsuccess=()=>res(r.result);r.onerror=()=>res([]);}catch{res([])}})}\u001b[39m\n\u001b[31mfunction dbDel(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).delete(k);r.onsuccess=()=>res();r.onerror=()=>res();}catch{res()}})}\u001b[39m\n\u001b[31masync function cfg(k,v){if(v===undefined){const r=await dbGet('cfg',k);return r?r.v:null;}await dbPut('cfg',{k,v});}·\u001b[39m\n\u001b[31m// COMPRESS — respects imgQuality setting\u001b[39m\n\u001b[31mfunction compress(file, maxPxOverride, qOverride){\u001b[39m\n\u001b[31m  const maxPx = maxPxOverride || (imgQuality==='hd' ? 1920 : 1280);\u001b[39m\n\u001b[31m  const q     = qOverride     || (imgQuality==='hd' ? 0.90 : 0.78);\u001b[39m\n\u001b[31m  return new Promise(res=>{const img=new Image(),url=URL.createObjectURL(file);img.onload=()=>{const sc=Math.min(1,maxPx/Math.max(img.width,img.height));const c=document.createElement('canvas');c.width=Math.round(img.width*sc);c.height=Math.round(img.height*sc);c.getContext('2d').drawImage(img,0,0,c.width,c.height);URL.revokeObjectURL(url);c.toBlob(b=>res(b),'image/jpeg',q);};img.onerror=()=>{URL.revokeObjectURL(url);res(file)};img.src=url;});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction b64(blob){return new Promise(res=>{const r=new FileReader();r.onload=()=>res(r.result);r.readAsDataURL(blob)})}\u001b[39m\n\u001b[31mfunction fmtSz(b){if(b<1024)return b+'B';if(b<1048576)return(b/1024).toFixed(0)+'KB';return(b/1048576).toFixed(1)+'MB'}·\u001b[39m\n\u001b[31m// STORE LIST\u001b[39m\n\u001b[31mlet _storeFiles=[]; // track uploaded files {name, brand, count}\u001b[39m\n\u001b[31mlet _pendingParse=null; // parsed rows waiting for brand assignment·\u001b[39m\n\u001b[31mfunction parseStoreRow(row, keyFn){\u001b[39m\n\u001b[31m  const v=k=>{\u001b[39m\n\u001b[31m    // Try exact match first, then partial\u001b[39m\n\u001b[31m    const exactKey=Object.keys(row||{}).find(hk=>hk.toLowerCase()===k);\u001b[39m\n\u001b[31m    const partKey=Object.keys(row||{}).find(hk=>hk.toLowerCase().includes(k));\u001b[39m\n\u001b[31m    const useKey=exactKey||partKey;\u001b[39m\n\u001b[31m    if(useKey)return row[useKey]!=null?row[useKey].toString().trim():'';\u001b[39m\n\u001b[31m    // CSV path: keyFn provides value directly\u001b[39m\n\u001b[31m    const col=keyFn(k);return col!=null?col.toString().trim():'';\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const name    = v('sub dealer name')||v('sub dealer')||v('dealer name')||v('store name')||v('store')||v('name');\u001b[39m\n\u001b[31m  const address = v('address')||v('addr')||v('location')||v('area');\u001b[39m\n\u001b[31m  // Contact Detail often stored as a number — toString handles it\u001b[39m\n\u001b[31m  const rawMob  = v('contact detail')||v('contact no.')||v('contact no')||v('mobile no')||v('mobile')||v('phone')||v('mob')||v('contact');\u001b[39m\n\u001b[31m  const mobile  = rawMob.replace(/\\\\D/g,'').slice(-10);\u001b[39m\n\u001b[31m  // Brand: EXACT match only — \\\"Brand\\\" or \\\"Brand Name\\\" columns\u001b[39m\n\u001b[31m  // Partial match is intentionally avoided here because \\\"Inshop Branding\\\" contains \\\"brand\\\"\u001b[39m\n\u001b[31m  const brandKey=Object.keys(row||{}).find(hk=>{\u001b[39m\n\u001b[31m    const lk=hk.toLowerCase().trim();\u001b[39m\n\u001b[31m    return lk==='brand'||lk==='brand name'||lk==='brand_name'||lk==='brandname';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const brand=brandKey?(row[brandKey]||'').toString().trim().toUpperCase():'';\u001b[39m\n\u001b[31m  const distName= v('dist name')||v('distributor name')||v('distributor')||v('dist')||v('territory')||v('tsm')||v('asm');\u001b[39m\n\u001b[31m  const city    = v('city')||v('district')||v('town');\u001b[39m\n\u001b[31m  const sales   = v('2025 full year')||v('2025')||v('full year sales')||v('fy25')||v('sales');\u001b[39m\n\u001b[31m  const proj    = v('2026 projection')||v('2026')||v('projection')||v('fy26')||v('target');\u001b[39m\n\u001b[31m  const glowSign= v('glow sign')||v('glow');\u001b[39m\n\u001b[31m  const inshop  = v('inshop branding')||v('inshop')||v('in-shop')||v('in shop');\u001b[39m\n\u001b[31m  return {name, brand, address, mobile, distName, city, sales, proj, glowSign, inshop};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction dedupeStores(list){\u001b[39m\n\u001b[31m  const seen=new Map();\u001b[39m\n\u001b[31m  list.forEach(s=>{\u001b[39m\n\u001b[31m    // Include address in key — same store name at different locations = different stores\u001b[39m\n\u001b[31m    const key=(s.name.toLowerCase().trim())+'__'+(s.brand||'').toLowerCase()\u001b[39m\n\u001b[31m              +'__'+(s.address||'').toLowerCase().trim().slice(0,30);\u001b[39m\n\u001b[31m    if(!seen.has(key))seen.set(key,s);\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // True duplicate — merge missing fields from second record\u001b[39m\n\u001b[31m      const ex=seen.get(key);\u001b[39m\n\u001b[31m      Object.keys(s).forEach(k=>{ if(!ex[k]&&s[k])ex[k]=s[k]; });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  return Array.from(seen.values());\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderStoreFileList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-file-list');if(!el)return;\u001b[39m\n\u001b[31m  if(!_storeFiles.length){el.innerHTML='';return;}\u001b[39m\n\u001b[31m  el.innerHTML=_storeFiles.map((f,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:5px;font-size:12px\\\">\u001b[39m\n\u001b[31m      <div>\u001b[39m\n\u001b[31m        <span style=\\\"font-weight:600;color:var(--nv)\\\">${f.name}</span>\u001b[39m\n\u001b[31m        <span style=\\\"color:var(--g500);margin-left:6px\\\">${f.count} stores</span>\u001b[39m\n\u001b[31m        ${f.brand?`<span style=\\\"background:var(--nv);color:#fff;font-size:10px;font-weight:700;padding:1px 7px;border-radius:20px;margin-left:5px\\\">${f.brand}</span>`:'<span style=\\\"background:var(--g300);color:var(--g600);font-size:10px;padding:1px 7px;border-radius:20px;margin-left:5px\\\">Mixed brands</span>'}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <button onclick=\\\"removeStoreFile(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:17px;cursor:pointer;padding:0 4px;line-height:1\\\">×</button>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function removeStoreFile(i){\u001b[39m\n\u001b[31m  _storeFiles.splice(i,1);\u001b[39m\n\u001b[31m  // Rebuild stores from remaining files — re-parse from cache not possible, so just reload from DB and remove this file's contribution\u001b[39m\n\u001b[31m  // Simplest approach: clear and ask user to re-upload remaining files\u001b[39m\n\u001b[31m  if(!_storeFiles.length){stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    // Can't re-parse without original files; just note it and keep current store list\u001b[39m\n\u001b[31m    toast('Removed from list. Re-upload the remaining files to refresh store list.','info');\u001b[39m\n\u001b[31m    _storeFiles.splice(0); // clear tracking since we can't reconstruct\u001b[39m\n\u001b[31m    stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderStoreFileList();\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=stores.length?`✓ ${stores.length} stores`:'No stores loaded';\u001b[39m\n\u001b[31m  updAvailTag();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function clearStoreList(){\u001b[39m\n\u001b[31m  if(!confirm('Remove all loaded stores?'))return;\u001b[39m\n\u001b[31m  stores=[];_storeFiles=[];\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent='';\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast('Store list cleared','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function handleStoreUpload(e){\u001b[39m\n\u001b[31m  const file=e.target.files[0];if(!file)return;\u001b[39m\n\u001b[31m  e.target.value=''; // allow same file re-upload\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    let data=[];\u001b[39m\n\u001b[31m    if(file.name.toLowerCase().endsWith('.csv')){\u001b[39m\n\u001b[31m      const txt=await file.text();\u001b[39m\n\u001b[31m      const rows=txt.split('\\\\n').map(r=>r.split(',').map(c=>c.trim().replace(/^\\\"|\\\"$/g,'')));\u001b[39m\n\u001b[31m      if(!rows.length||!rows[0].length){toast('Empty CSV','error');return;}\u001b[39m\n\u001b[31m      const h=rows[0];\u001b[39m\n\u001b[31m      data=rows.slice(1).filter(r=>r.length>1&&r.some(c=>c)).map(r=>{\u001b[39m\n\u001b[31m        const rowObj={};h.forEach((hk,i)=>{rowObj[hk]=r[i]||'';});\u001b[39m\n\u001b[31m        return parseStoreRow(rowObj, ()=>'');\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }else{\u001b[39m\n\u001b[31m      const ab=await file.arrayBuffer();const wb=XLSX.read(ab,{type:'array'});\u001b[39m\n\u001b[31m      const js=XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]],{defval:''});\u001b[39m\n\u001b[31m      data=js.map(row=>parseStoreRow(row,()=>''));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    data=data.filter(d=>d.name.trim());\u001b[39m\n\u001b[31m    if(!data.length){toast('No valid rows found in file','error');return;}\u001b[39m\n\u001b[31m    // Check if any store has a brand\u001b[39m\n\u001b[31m    const hasBrand=data.some(d=>d.brand);\u001b[39m\n\u001b[31m    // Always show preview first before merging\u001b[39m\n\u001b[31m    _pendingParse={file:file.name,data,hasBrand};\u001b[39m\n\u001b[31m    showStorePreview(file.name, data, hasBrand);\u001b[39m\n\u001b[31m  }catch(err){toast('Failed: '+err.message,'error')}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mlet _pendingBrand='';\u001b[39m\n\u001b[31mfunction setPendingBrand(b){\u001b[39m\n\u001b[31m  _pendingBrand=b;\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-assign-chips .chip').forEach(c=>{\u001b[39m\n\u001b[31m    c.classList.toggle('sel',c.textContent===b);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  if(!_pendingBrand){toast('Select a brand first','error');return;}\u001b[39m\n\u001b[31m  // Assign brand to all rows in this file\u001b[39m\n\u001b[31m  const data=_pendingParse.data.map(s=>({...s,brand:_pendingBrand}));\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, data, _pendingBrand);\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function skipBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, _pendingParse.data, '');\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showStorePreview(filename, data, hasBrand){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-preview-dialog');\u001b[39m\n\u001b[31m  const tbody=document.getElementById('store-preview-body');\u001b[39m\n\u001b[31m  document.getElementById('store-preview-title').textContent=`${filename} · ${data.length} ${t('stores found','स्टोर मिले')}`;\u001b[39m\n\u001b[31m  // Show first 8 rows\u001b[39m\n\u001b[31m  const sample=data.slice(0,8);\u001b[39m\n\u001b[31m  tbody.innerHTML=sample.map(s=>`<tr>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;font-weight:500\\\">${s.name||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.address||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.mobile||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px\\\"><span style=\\\"background:${s.brand?'var(--nv)':'var(--rd)'};color:#fff;padding:1px 7px;border-radius:10px;font-size:10px\\\">${s.brand||'?'}</span></td>\u001b[39m\n\u001b[31m  </tr>`).join('');\u001b[39m\n\u001b[31m  if(data.length>8)tbody.innerHTML+=`<tr><td colspan=\\\"4\\\" style=\\\"text-align:center;padding:8px;font-size:12px;color:var(--g400)\\\">…and ${data.length-8} more stores</td></tr>`;\u001b[39m\n\u001b[31m  el.classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function confirmStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  const {file,data,hasBrand}=_pendingParse;\u001b[39m\n\u001b[31m  if(!hasBrand){\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-fname').textContent=`File: ${file} · ${data.length} stores found · No brand column detected`;\u001b[39m\n\u001b[31m    const chips=document.getElementById('brand-assign-chips');\u001b[39m\n\u001b[31m    chips.innerHTML=brands.map(b=>`<div class=\\\"chip\\\" onclick=\\\"setPendingBrand('${b}')\\\" id=\\\"bac-${b}\\\">${b}</div>`).join('');\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').style.display='block';\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    await mergeStores(file, data, '');\u001b[39m\n\u001b[31m    _pendingParse=null;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction cancelStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingParse=null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function mergeStores(filename, newData, assignedBrand){\u001b[39m\n\u001b[31m  const before=stores.length;\u001b[39m\n\u001b[31m  stores=[...stores,...newData];\u001b[39m\n\u001b[31m  stores=dedupeStores(stores);\u001b[39m\n\u001b[31m  const added=stores.length-before;\u001b[39m\n\u001b[31m  const dupes=newData.length-added;\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify(stores));\u001b[39m\n\u001b[31m  // Track file\u001b[39m\n\u001b[31m  _storeFiles.push({name:filename,count:newData.length,brand:assignedBrand||''});\u001b[39m\n\u001b[31m  await cfg('store-files',JSON.stringify(_storeFiles));\u001b[39m\n\u001b[31m  const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m    `✓ ${stores.length} total stores${dupes>0?` · ${dupes} duplicate${dupes>1?'s':''} removed`:''}${noBrand?` · ${noBrand} without brand`:' · All have brand'}`;\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast(`${added} stores added${dupes>0?`, ${dupes} duplicates skipped`:''}${assignedBrand?' as '+assignedBrand:''}`, 'success');\u001b[39m\n\u001b[31m  // Show server-push button for supervisors\u001b[39m\n\u001b[31m  const pb = document.getElementById('store-push-btn');\u001b[39m\n\u001b[31m  if (pb) pb.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function fetchServerStores(){const url=document.getElementById('srv-url').value.trim();if(!url){toast('Enter a URL first','error');return;}try{toast('Fetching…','info');const r=await fetch(url);const j=await r.json();const fetched=Array.isArray(j)?j:j.stores||[];await mergeStores('Server ('+url.split('/').pop()+')',fetched,'');await cfg('srv-url',url);}catch{toast('Fetch failed — check URL','error')}}\u001b[39m\n\u001b[31masync function saveServerUrl(){await cfg('srv-url',document.getElementById('srv-url').value.trim());toast('URL saved','success')}\u001b[39m\n\u001b[31mconst DEFAULT_GAS_URL='https://script.google.com/macros/s/AKfycbwyufC7gQyu1BErCxiDlbQUn0AWiIWv7nEmjk4UcAx3dvlV6bGk7q5fQOiv82CTbokbkA/exec';·\u001b[39m\n\u001b[31mconst DEFAULT_STORES_URL='/recce/stores.json';\u001b[39m\n\u001b[31mconst _RECCE_CFG_URL='/recce/recce-cfg.json';·\u001b[39m\n\u001b[31m// Admin auto-unlock for harish/pramod via hub session\u001b[39m\n\u001b[31mconst _RECCE_ADMIN_IDS = ['harish', 'pramod', 'rakesh'];\u001b[39m\n\u001b[31mconst _RECCE_CFG_ADMINS = ['harish', 'pramod'];\u001b[39m\n\u001b[31mlet _adminRows = [];\u001b[39m\n\u001b[31mlet _myServerRows = [];\u001b[39m\n\u001b[31mlet _adminUnlocked = false;\u001b[39m\n\u001b[31mlet _recceCfg = { version: 1, supervisors: ['harish','pramod','rakesh'], mode: 'public', creators: [], allowed_users: [] };\u001b[39m\n\u001b[31mfunction _isSupervisor() {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  return !!(hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId));\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _showDeletedView = false;\u001b[39m\n\u001b[31mlet _supCreateMode = false;\u001b[39m\n\u001b[31mlet _pendingDeleteId = null;\u001b[39m\n\u001b[31mlet _pendingDeleteReason = null;\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (s?.empId && _RECCE_ADMIN_IDS.includes(s.empId)) _adminUnlocked = true;\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31masync function loadRecceCfg(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(_RECCE_CFG_URL + '?t=' + Date.now());\u001b[39m\n\u001b[31m    if (r.ok) {\u001b[39m\n\u001b[31m      const j = await r.json();\u001b[39m\n\u001b[31m      if (j && j.version) {\u001b[39m\n\u001b[31m        _recceCfg = j;\u001b[39m\n\u001b[31m        if (Array.isArray(j.supervisors) && j.supervisors.length) {\u001b[39m\n\u001b[31m          _recceCfg.supervisors = j.supervisors;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.creators)) _recceCfg.creators = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.allowed_users)) _recceCfg.allowed_users = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.clients)) _recceCfg.clients = [];\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  // Re-check admin status against server supervisor list\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId)) {\u001b[39m\n\u001b[31m    _adminUnlocked = true;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _checkAccessMode(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (_recceCfg.mode !== 'assigned') return;\u001b[39m\n\u001b[31m  const allowed = [\u001b[39m\n\u001b[31m    ...(_recceCfg.supervisors || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.creators || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.allowed_users || []),\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  if (hub?.empId && allowed.includes(hub.empId)) return;\u001b[39m\n\u001b[31m  // Block access — show locked overlay\u001b[39m\n\u001b[31m  document.body.innerHTML = `<div style=\\\"min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0f172a;color:#fff;padding:32px;text-align:center\\\"><div style=\\\"font-size:48px;margin-bottom:16px\\\">🔒</div><div style=\\\"font-size:20px;font-weight:700;margin-bottom:8px\\\">${t('Access Restricted','एक्सेस प्रतिबंधित')}</div><div style=\\\"font-size:14px;color:#94a3b8\\\">${t('You are not authorised to use Branding Recce. Please contact your supervisor.','आप ब्रांडिंग रेक्की उपयोग के लिए अधिकृत नहीं हैं।')}</div></div>`;\u001b[39m\n\u001b[31m  throw new Error('access-restricted');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _recceHubUser() {\u001b[39m\n\u001b[31m  try { return JSON.parse(localStorage.getItem('lm360-session') || '{}'); }\u001b[39m\n\u001b[31m  catch(_) { return {}; }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── Supervisor config management ────────────────────────────────────\u001b[39m\n\u001b[31mfunction renderSupPanel(){\u001b[39m\n\u001b[31m  if (!_adminUnlocked) return;\u001b[39m\n\u001b[31m  const panel = document.getElementById('sup-panel');\u001b[39m\n\u001b[31m  if (panel) panel.style.display = 'block';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const modePublic = document.getElementById('mode-public');\u001b[39m\n\u001b[31m  const modeAssigned = document.getElementById('mode-assigned');\u001b[39m\n\u001b[31m  if (modePublic && modeAssigned) {\u001b[39m\n\u001b[31m    modePublic.classList.toggle('sel', _recceCfg.mode !== 'assigned');\u001b[39m\n\u001b[31m    modeAssigned.classList.toggle('sel', _recceCfg.mode === 'assigned');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  const addRow = document.getElementById('sup-add-row');\u001b[39m\n\u001b[31m  if (addRow) addRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const creatorAddRow = document.getElementById('creator-add-row');\u001b[39m\n\u001b[31m  if (creatorAddRow) creatorAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const clientAddRow = document.getElementById('client-add-row');\u001b[39m\n\u001b[31m  if (clientAddRow) clientAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const modeRow = document.getElementById('mode-row');\u001b[39m\n\u001b[31m  if (modeRow) {\u001b[39m\n\u001b[31m    modeRow.style.display = 'block';\u001b[39m\n\u001b[31m    // Non-cfg-admins see mode as read-only (toggles exist but setRecceMode guards them)\u001b[39m\n\u001b[31m    modeRow.style.opacity = isCfgAdmin ? '1' : '0.65';\u001b[39m\n\u001b[31m    modeRow.style.pointerEvents = isCfgAdmin ? '' : 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const syncBtn = document.getElementById('cfg-sync-btn');\u001b[39m\n\u001b[31m  if (syncBtn) syncBtn.style.display = isCfgAdmin ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('sup-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const sups = _recceCfg.supervisors || [];\u001b[39m\n\u001b[31m  el.innerHTML = sups.map((s,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${s}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin && sups.length > 1 ? `<button onclick=\\\"removeSupervisor(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderCreatorsList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('creator-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const creators = _recceCfg.creators || [];\u001b[39m\n\u001b[31m  el.innerHTML = creators.length ? creators.map((u,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${u}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeCreator(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No creators yet — any Hub user can submit in Public mode.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setRecceMode(mode){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.mode = mode;\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addSupervisor(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('sup-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.supervisors = [...(_recceCfg.supervisors || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeSupervisor(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.supervisors = (_recceCfg.supervisors || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addCreator(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('creator-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.creators || []).includes(val)) { toast(t('Already a creator','पहले से क्रिएटर है'), 'info'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor (includes creation rights)','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.creators = [...(_recceCfg.creators || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeCreator(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.creators = (_recceCfg.creators || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderClientMgmtList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('client-mgmt-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const list = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  el.innerHTML = list.length ? list.map((c,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${esc(c)}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeClientFromList(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No clients yet — add client or agency names to show them as chips in the form.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addClientToList(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('client-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter client name','क्लाइंट नाम दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.clients || []).includes(val)) { toast(t('Already in list','पहले से मौजूद है'), 'info'); return; }\u001b[39m\n\u001b[31m  if (!_recceCfg.clients) _recceCfg.clients = [];\u001b[39m\n\u001b[31m  _recceCfg.clients.push(val);\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeClientFromList(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.clients = (_recceCfg.clients || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncCfgToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast(t('Not authorised','अधिकृत नहीं'), 'error'); return; }\u001b[39m\n\u001b[31m  const st = document.getElementById('cfg-sync-status');\u001b[39m\n\u001b[31m  if (st) st.textContent = t('Syncing…','सिंक हो रहा है…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-cfg', empId: hub.empId, cfg: {\u001b[39m\n\u001b[31m        version: _recceCfg.version || 1,\u001b[39m\n\u001b[31m        supervisors: _recceCfg.supervisors || [],\u001b[39m\n\u001b[31m        mode: _recceCfg.mode || 'public',\u001b[39m\n\u001b[31m        creators: _recceCfg.creators || [],\u001b[39m\n\u001b[31m        allowed_users: _recceCfg.allowed_users || [],\u001b[39m\n\u001b[31m        clients: _recceCfg.clients || [],\u001b[39m\n\u001b[31m      }})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) {\u001b[39m\n\u001b[31m      toast(t('Config synced to server ✓','कॉन्फ़िग सर्वर पर सेव हुआ ✓'), 'success');\u001b[39m\n\u001b[31m      if (st) st.textContent = t('Last synced: just now','अभी सिंक हुआ');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast(j.error || t('Sync failed','सिंक विफल'), 'error');\u001b[39m\n\u001b[31m      if (st) st.textContent = j.error || '';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Network error','नेटवर्क त्रुटि'), 'error');\u001b[39m\n\u001b[31m    if (st) st.textContent = e.message;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function pushStoresToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!hub?.empId || !_adminUnlocked) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-stores', empId: hub.empId, stores })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) toast(`${t('Pushed to server','सर्वर पर पुश हुआ')} · ${j.count} ${t('stores','स्टोर')}`, 'success');\u001b[39m\n\u001b[31m    else toast(j.error || t('Server push failed','सर्वर पुश विफल'), 'error');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Could not reach server','सर्वर से संपर्क नहीं हो सका'), 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── End supervisor config management ────────────────────────────────·\u001b[39m\n\u001b[31m// PostgREST sync constants\u001b[39m\n\u001b[31mconst _RC_BASE      = '/db';\u001b[39m\n\u001b[31mconst _RC_READ      = { 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_WRITE     = { 'Content-Type': 'application/json', 'Content-Profile': 'recce', 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_UPSERT    = { ..._RC_WRITE, 'Prefer': 'resolution=merge-duplicates,return=minimal' };\u001b[39m\n\u001b[31mconst _INSTALL_RD   = { 'Content-Type': 'application/json', 'Accept-Profile': 'installation' };\u001b[39m\n\u001b[31mconst _INSTALL_WR   = { 'Content-Type': 'application/json', 'Content-Profile': 'installation', 'Accept-Profile': 'installation', 'Prefer': 'return=minimal' };·\u001b[39m\n\u001b[31m// ── Campaign selection state ──\u001b[39m\n\u001b[31mlet _selectedCampaignId = null;\u001b[39m\n\u001b[31mlet _notifySupervisor   = false;\u001b[39m\n\u001b[31mlet _campaignList       = [];\u001b[39m\n\u001b[31mlet _pendingJobFilter   = false;\u001b[39m\n\u001b[31mlet _linkJobSubId       = null;\u001b[39m\n\u001b[31mlet _brandingLocked     = false;·\u001b[39m\n\u001b[31mfunction _updateBrandingLock() {\u001b[39m\n\u001b[31m  const hub  = _recceHubUser();\u001b[39m\n\u001b[31m  const isHP = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const banner   = document.getElementById('branding-lock-banner');\u001b[39m\n\u001b[31m  const ovWrap   = document.getElementById('branding-override-wrap');\u001b[39m\n\u001b[31m  const brItems  = document.getElementById('br-items');\u001b[39m\n\u001b[31m  const brAdd    = document.getElementById('br-add');\u001b[39m\n\u001b[31m  const brYes    = document.getElementById('br-yes');\u001b[39m\n\u001b[31m  const brNo     = document.getElementById('br-no');\u001b[39m\n\u001b[31m  if (!banner) return;\u001b[39m\n\u001b[31m  if (_brandingLocked) {\u001b[39m\n\u001b[31m    banner.style.display   = '';\u001b[39m\n\u001b[31m    if (ovWrap)  ovWrap.style.display  = isHP ? '' : 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.pointerEvents = 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.opacity = '0.55';\u001b[39m\n\u001b[31m    if (brAdd)   brAdd.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='none'; brYes.style.opacity='0.5'; }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='none';  brNo.style.opacity='0.5';  }\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    banner.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brItems) { brItems.style.pointerEvents=''; brItems.style.opacity=''; }\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='';  brYes.style.opacity='';   }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='';   brNo.style.opacity='';    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction unlockBrandingOverride() {\u001b[39m\n\u001b[31m  if (!confirm(\u001b[39m\n\u001b[31m    'Client has already reviewed this recce.\\\\n' +\u001b[39m\n\u001b[31m    'Editing brandings will NOT remove their approval.\\\\n' +\u001b[39m\n\u001b[31m    'Continue ONLY if the client has verbally confirmed. Proceed?'\u001b[39m\n\u001b[31m  )) return;\u001b[39m\n\u001b[31m  _brandingLocked = false;\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  renderBrandings();\u001b[39m\n\u001b[31m  toast(t('Branding unlocked for this session', 'ब्रांडिंग इस सत्र के लिए अनलॉक'), 'info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadCampaignsForForm() {\u001b[39m\n\u001b[31m  const sel = document.getElementById('f-campaign-id');\u001b[39m\n\u001b[31m  if (!sel) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m    _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m  } catch(_) { _campaignList = []; }\u001b[39m\n\u001b[31m  sel.innerHTML =\u001b[39m\n\u001b[31m    '<option value=\\\"\\\">— Select job / campaign (optional) —</option>' +\u001b[39m\n\u001b[31m    _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('') +\u001b[39m\n\u001b[31m    '<option value=\\\"__NOTIFY__\\\">⚑ No campaign yet — notify supervisor</option>';\u001b[39m\n\u001b[31m  if (_selectedCampaignId) sel.value = _selectedCampaignId;\u001b[39m\n\u001b[31m  else if (_notifySupervisor) sel.value = '__NOTIFY__';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onCampaignSelect() {\u001b[39m\n\u001b[31m  const val = document.getElementById('f-campaign-id')?.value || '';\u001b[39m\n\u001b[31m  const noticeEl = document.getElementById('campaign-notify-msg');\u001b[39m\n\u001b[31m  if (val === '__NOTIFY__') {\u001b[39m\n\u001b[31m    _selectedCampaignId = null;\u001b[39m\n\u001b[31m    _notifySupervisor   = true;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'block';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    _selectedCampaignId = val || null;\u001b[39m\n\u001b[31m    _notifySupervisor   = false;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction generateRecceReportHtml(entry, photoUrls) {\u001b[39m\n\u001b[31m  const d    = entry.data || {};\u001b[39m\n\u001b[31m  const urls = photoUrls || {};\u001b[39m\n\u001b[31m  const agent = entry.submittedByName || entry.submittedBy || 'Field Agent';\u001b[39m\n\u001b[31m  const _safeId      = (entry.id||'').replace(/\\\\//g,'_').replace(/\\\\.\\\\./g,'');\u001b[39m\n\u001b[31m  const serverPdfUrl = _safeId ? `https://srv1111289.hstgr.cloud/screenshots/recce/views/${_safeId}.pdf` : '';\u001b[39m\n\u001b[31m  const brandLogoUrl = d.brandLogoUrl || _brandLogos[d.brand] || '';\u001b[39m\n\u001b[31m  const tsStr = new Date(entry.timestamp).toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric',hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\u001b[39m\n\u001b[31m  const gpsUrl = d.gpsCoords ? `https://maps.google.com/?q=${d.gpsCoords.lat},${d.gpsCoords.lng}` : null;·\u001b[39m\n\u001b[31m  const frontCount  = (urls.front||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const insideCount = (urls.inside||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const addlCount   = (urls.addl||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const brCount     = (d.brandings||[]).length;·\u001b[39m\n\u001b[31m  // pages: { id, url, bandHtml, cmt, dotLabel, dotColor }\u001b[39m\n\u001b[31m  const pages = [];·\u001b[39m\n\u001b[31m  (urls.front||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Front View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${frontCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.frontPhotos||[])[i]?.cmt||'', dotLabel:`FV${i+1}`, dotColor:'#3b82f6', catLabel:'Front View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.inside||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Inside View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${insideCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.insidePhotos||[])[i]?.cmt||'', dotLabel:`IV${i+1}`, dotColor:'#14b8a6', catLabel:'Inside View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (d.brandings||[]).forEach((b,i)=>{\u001b[39m\n\u001b[31m    const url=(urls.brandings||[])[i]; if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">${esc(b.type||'Branding')}</div><div class=\\\"ph-dims\\\">Width : ${esc(b.w||'?')}&Prime;&nbsp;&times;&nbsp;Height : ${esc(b.h||'?')}&Prime;&nbsp;&mdash;&nbsp;${esc(b.qty||1)} Nos</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${brCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:'', dotLabel:`B${i+1}`, dotColor:'#f97316', catLabel:b.type||'Branding',\u001b[39m\n\u001b[31m      tileDims:`${b.w||'?'}″×${b.h||'?'}″ — ${String(b.qty||1).padStart(2,'0')} Nos` });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.addl||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Additional</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${addlCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.addlPhotos||[])[i]?.desc||'', dotLabel:`A${i+1}`, dotColor:'#94a3b8', catLabel:'Additional', tileDims:'' });\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const sideItems = [\u001b[39m\n\u001b[31m    `<div class=\\\"si-item active\\\" data-tgt=\\\"pg-cover\\\" title=\\\"Cover\\\"><div class=\\\"si-dot\\\" style=\\\"background:#475569\\\">CV</div></div>`\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  pages.forEach(p => {\u001b[39m\n\u001b[31m    sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"${p.id}\\\" title=\\\"${p.dotLabel}\\\"><div class=\\\"si-dot\\\" style=\\\"background:${p.dotColor}\\\">${p.dotLabel}</div></div>`);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(d.hasVideo) sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-vid\\\" title=\\\"Video\\\"><div class=\\\"si-dot\\\" style=\\\"background:#a855f7\\\">VD</div></div>`);\u001b[39m\n\u001b[31m  if(urls.doc)   sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-doc\\\" title=\\\"Document\\\"><div class=\\\"si-dot\\\" style=\\\"background:#64748b\\\">DC</div></div>`);·\u001b[39m\n\u001b[31m  const thumbItems = [\u001b[39m\n\u001b[31m    ...pages,\u001b[39m\n\u001b[31m    ...(d.hasVideo?[{id:'pg-vid',url:null,catLabel:'Video',tileDims:'',dotLabel:'VD',dotColor:'#a855f7'}]:[]),\u001b[39m\n\u001b[31m    ...(urls.doc?[{id:'pg-doc',url:urls.doc,catLabel:'Document',tileDims:'',dotLabel:'DC',dotColor:'#64748b'}]:[])\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  const thumbsHtml = thumbItems.map(p=>`<div class=\\\"cov-thumb\\\" onclick=\\\"document.getElementById('${p.id}').scrollIntoView({behavior:'smooth'})\\\">${p.url?`<img src=\\\"${p.url}\\\" alt=\\\"\\\">`:(`<div class=\\\"cov-thumb-vid\\\">${p.catLabel==='Video'?'&#x25B6;&#xFE0F;':'&#x1F4C4;'}</div>`)}<div class=\\\"cov-thumb-ov\\\" style=\\\"border-top:3px solid ${p.dotColor}\\\"><div class=\\\"cov-thumb-cat\\\">${esc(p.catLabel)}</div>${p.tileDims?`<div class=\\\"cov-thumb-dims\\\">${esc(p.tileDims)}</div>`:''}<div class=\\\"cov-thumb-no\\\">${p.dotLabel}</div></div></div>`).join('');·\u001b[39m\n\u001b[31m  const pagesHtml = pages.map(p => `\u001b[39m\n\u001b[31m<div class=\\\"photo-page\\\" id=\\\"${p.id}\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\">${p.bandHtml}</div>\u001b[39m\n\u001b[31m  <div class=\\\"ph-img\\\"><a href=\\\"${p.url}\\\" target=\\\"_blank\\\"><img src=\\\"${p.url}\\\" loading=\\\"lazy\\\" alt=\\\"\\\"></a>${p.cmt?`<div class=\\\"ph-cmt\\\">${esc(p.cmt)}</div>`:''}</div>\u001b[39m\n\u001b[31m</div>`).join('');·\u001b[39m\n\u001b[31m  return `<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\"><head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m<title>Recce — ${esc(d.storeName||'Unknown')} · ${esc(d.brand||'')}</title>\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--dk:#0f172a;--nv2:#1a2f52;--or:#f97316;--g200:#e2e8f0;--g400:#94a3b8;--g600:#475569;--si:54px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0}\u001b[39m\n\u001b[31mhtml,body{height:100%;overflow:hidden}\u001b[39m\n\u001b[31mbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#111;color:var(--dk);display:flex}\u001b[39m\n\u001b[31ma{color:var(--or);text-decoration:none}\u001b[39m\n\u001b[31mimg{display:block}·\u001b[39m\n\u001b[31m/* ── Side index ── */\u001b[39m\n\u001b[31m.side-idx{width:var(--si);flex-shrink:0;background:var(--dk);overflow-y:auto;display:flex;flex-direction:column;align-items:center;padding:4px 0;scrollbar-width:none;z-index:50}\u001b[39m\n\u001b[31m.side-idx::-webkit-scrollbar{display:none}\u001b[39m\n\u001b[31m.si-item{width:100%;min-height:56px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s}\u001b[39m\n\u001b[31m.si-item:hover{background:rgba(255,255,255,.07)}\u001b[39m\n\u001b[31m.si-dot{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff;opacity:.4;transition:opacity .18s,transform .18s;line-height:1;text-align:center}\u001b[39m\n\u001b[31m.si-item.active .si-dot{opacity:1;transform:scale(1.15)}·\u001b[39m\n\u001b[31m/* ── Main scroll area ── */\u001b[39m\n\u001b[31m.main{flex:1;overflow-y:scroll;scroll-snap-type:y mandatory;scroll-behavior:smooth;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar{width:3px}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15)}·\u001b[39m\n\u001b[31m/* ── Cover ── */\u001b[39m\n\u001b[31m.cover{height:100vh;scroll-snap-align:start;flex-shrink:0;background:linear-gradient(135deg,#0f172a 0%,var(--nv2) 100%);color:#fff;display:flex;flex-direction:column;padding:24px 20px 20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.cover-badge{display:inline-flex;align-items:center;gap:5px;background:var(--or);color:#fff;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:1px;padding:3px 12px;border-radius:20px;margin-bottom:12px;align-self:flex-start}\u001b[39m\n\u001b[31m.cover h1{font-size:20px;font-weight:700;line-height:1.3;margin-bottom:4px}\u001b[39m\n\u001b[31m.cover-addr{color:rgba(255,255,255,.55);font-size:12px;margin-bottom:16px}\u001b[39m\n\u001b[31m.cg{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}\u001b[39m\n\u001b[31m.cm{background:rgba(255,255,255,.08);border-radius:8px;padding:8px 12px}\u001b[39m\n\u001b[31m.cm-l{font-size:9px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}\u001b[39m\n\u001b[31m.cm-v{font-size:13px;font-weight:600;color:#fff}\u001b[39m\n\u001b[31m.cm-v a{color:#fb923c}\u001b[39m\n\u001b[31m.cover-pbar{padding-top:8px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{background:var(--or);color:#fff;border:none;padding:10px 22px;border-radius:22px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}\u001b[39m\n\u001b[31m.btn-p:disabled{opacity:.4;cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-c{background:rgba(255,255,255,.1);color:rgba(255,255,255,.75);border:1px solid rgba(255,255,255,.2);padding:10px 18px;border-radius:22px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit}·\u001b[39m\n\u001b[31m/* ── Cover thumbnail grid ── */\u001b[39m\n\u001b[31m.cov-grid-hdr{font-size:10px;font-weight:700;color:rgba(255,255,255,.35);text-transform:uppercase;letter-spacing:1.2px;padding:10px 0 5px;flex-shrink:0}\u001b[39m\n\u001b[31m.cov-grid{flex:1;min-height:0;display:grid;gap:5px;overflow:hidden;align-content:start}\u001b[39m\n\u001b[31m.cov-thumb{position:relative;overflow:hidden;border-radius:7px;cursor:pointer;background:#1e293b;transition:transform .18s,box-shadow .18s}\u001b[39m\n\u001b[31m.cov-thumb:hover{transform:scale(1.05);box-shadow:0 4px 18px rgba(0,0,0,.55)}\u001b[39m\n\u001b[31m.cov-thumb img{width:100%;height:100%;object-fit:cover;display:block}\u001b[39m\n\u001b[31m.cov-thumb-vid{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:#0f172a}\u001b[39m\n\u001b[31m.cov-thumb-ov{position:absolute;inset:0;background:rgba(0,0,0,.28);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:5px;border-radius:7px}\u001b[39m\n\u001b[31m.cov-thumb-cat{color:rgba(255,255,255,.5);font-weight:900;text-align:center;text-transform:uppercase;letter-spacing:.8px;text-shadow:0 1px 6px rgba(0,0,0,.95);line-height:1.2;word-break:break-word}\u001b[39m\n\u001b[31m.cov-thumb-dims{color:rgba(255,255,255,.5);font-weight:700;text-align:center;text-shadow:0 1px 5px rgba(0,0,0,.95);letter-spacing:.3px;line-height:1.3}\u001b[39m\n\u001b[31m.cov-thumb-no{color:rgba(255,255,255,.5);font-weight:800;text-shadow:0 1px 4px rgba(0,0,0,.95);letter-spacing:.5px}\u001b[39m\n\u001b[31m#cover-btn{position:fixed;bottom:20px;right:16px;display:none;align-items:center;gap:6px;background:rgba(255,255,255,.15);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.25);color:#fff;padding:10px 22px;border-radius:50px;font-size:13px;font-weight:700;cursor:pointer;z-index:200;letter-spacing:.3px;box-shadow:0 2px 12px rgba(0,0,0,.3);font-family:inherit;transition:background .15s,transform .15s}\u001b[39m\n\u001b[31m#cover-btn:hover{background:rgba(255,255,255,.22);transform:scale(1.04)}·\u001b[39m\n\u001b[31m/* ── Print wait overlay ── */\u001b[39m\n\u001b[31m#print-overlay{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m@media print{#print-overlay{display:none!important}}·\u001b[39m\n\u001b[31m/* ── Loading progress bar ── */\u001b[39m\n\u001b[31m.load-bar{position:fixed;bottom:0;left:0;right:0;background:rgba(15,23,42,.95);padding:9px 16px;z-index:9999;display:flex;align-items:center;gap:12px;backdrop-filter:blur(6px)}\u001b[39m\n\u001b[31m.load-track{flex:1;height:5px;background:rgba(255,255,255,.12);border-radius:3px;overflow:hidden}\u001b[39m\n\u001b[31m.load-fill{height:100%;background:var(--or);width:0%;transition:width .35s ease;border-radius:3px}\u001b[39m\n\u001b[31m.load-txt{font-size:11px;color:rgba(255,255,255,.6);white-space:nowrap;min-width:160px}·\u001b[39m\n\u001b[31m/* ── Photo page ── */\u001b[39m\n\u001b[31m.photo-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ph-band{background:var(--dk);padding:16px 26px;flex-shrink:0;display:flex;align-items:center;gap:20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.ph-cat{font-size:35px;font-weight:800;color:#fff;letter-spacing:-.5px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.ph-dims{flex:1;font-size:18px;font-weight:600;color:var(--or);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}\u001b[39m\n\u001b[31m.ph-no{margin-left:auto;flex-shrink:0;font-size:21px;font-weight:700;color:rgba(255,255,255,.85);background:rgba(255,255,255,.1);padding:5px 20px;border-radius:24px;white-space:nowrap}\u001b[39m\n\u001b[31m.ph-of{font-size:18px;font-weight:400;color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.ph-img{flex:1;overflow:hidden;position:relative;background:#111}\u001b[39m\n\u001b[31m.ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m.ph-img img{width:100%;height:100%;object-fit:contain;display:block}\u001b[39m\n\u001b[31m.ph-cmt{position:absolute;bottom:0;left:0;right:0;padding:6px 14px;background:rgba(0,0,0,.62);font-size:11px;color:rgba(255,255,255,.75);font-style:italic;pointer-events:none}·\u001b[39m\n\u001b[31m/* ── Video / Doc pages ── */\u001b[39m\n\u001b[31m.vid-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;background:#fff}\u001b[39m\n\u001b[31m.vid-body{flex:1;padding:20px 24px;font-size:14px;color:var(--g600);border-left:4px solid var(--or)}\u001b[39m\n\u001b[31m.vid-body em{display:block;font-size:12px;color:var(--g400);margin-top:6px}\u001b[39m\n\u001b[31m.doc-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m.doc-wrap{flex:1;display:flex;align-items:center;justify-content:center;background:#111;overflow:hidden}\u001b[39m\n\u001b[31m.doc-img{max-width:100%;max-height:100%;object-fit:contain}·\u001b[39m\n\u001b[31m/* ── Cover header band ── */\u001b[39m\n\u001b[31m.cov-hdr{display:flex;gap:0;margin-bottom:12px;flex-shrink:0;border-radius:10px;overflow:hidden;border:1px solid rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.cov-hdr-l{flex:1;padding:14px 18px;display:flex;flex-direction:column;gap:5px;border-right:1px solid rgba(255,255,255,.1);min-width:0}\u001b[39m\n\u001b[31m.cov-hdr-r{width:170px;flex-shrink:0;padding:14px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:rgba(255,255,255,.04)}\u001b[39m\n\u001b[31m.cov-store{font-size:18px;font-weight:800;color:#fff;line-height:1.25;margin-bottom:2px}\u001b[39m\n\u001b[31m.cov-meta{font-size:12px;color:rgba(255,255,255,.55);display:flex;align-items:center;gap:5px;line-height:1.5}\u001b[39m\n\u001b[31m.cov-brand{background:var(--or);color:#fff;font-size:13px;font-weight:800;padding:5px 16px;border-radius:20px;text-align:center;letter-spacing:.3px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\u001b[39m\n\u001b[31m.cov-date-l{font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.8px;margin-bottom:2px;text-align:center}\u001b[39m\n\u001b[31m.cov-date-v{font-size:13px;font-weight:700;color:#fff;text-align:center}\u001b[39m\n\u001b[31m.cov-logo-box{background:#fff;border-radius:8px;padding:8px 14px;display:flex;align-items:center;justify-content:center;width:100%;max-width:138px}\u001b[39m\n\u001b[31m.cov-logo-box img{max-width:110px;max-height:44px;object-fit:contain;display:block}·\u001b[39m\n\u001b[31m/* ── Print ── */\u001b[39m\n\u001b[31m@page{size:A4 landscape;margin:12mm}\u001b[39m\n\u001b[31m@media print{\u001b[39m\n\u001b[31m  html,body{height:auto;overflow:visible;display:block}\u001b[39m\n\u001b[31m  .side-idx{display:none}\u001b[39m\n\u001b[31m  .main{overflow:visible;display:block;height:auto;scroll-snap-type:none}\u001b[39m\n\u001b[31m  .cover,.vid-page,.doc-page{height:auto;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m  .photo-page{height:186mm;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m  .cover{padding:20px 24px}\u001b[39m\n\u001b[31m  .cover-pbar{display:none}\u001b[39m\n\u001b[31m  .cov-hdr{margin-bottom:8px;border-radius:7px}\u001b[39m\n\u001b[31m  .cov-hdr-l{padding:10px 14px}\u001b[39m\n\u001b[31m  .cov-hdr-r{padding:10px 12px;width:150px}\u001b[39m\n\u001b[31m  .cov-store{font-size:15px}\u001b[39m\n\u001b[31m  .cov-meta{font-size:10px}\u001b[39m\n\u001b[31m  .cov-brand{font-size:11px;padding:3px 12px}\u001b[39m\n\u001b[31m  .cov-date-v{font-size:11px}\u001b[39m\n\u001b[31m  .ph-band{padding:5mm 13mm;gap:10mm}\u001b[39m\n\u001b[31m  .ph-cat{font-size:15mm}\u001b[39m\n\u001b[31m  .ph-dims{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-no{font-size:12mm;padding:2mm 8mm}\u001b[39m\n\u001b[31m  .ph-of{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-img{flex:1;display:flex;align-items:center;justify-content:center;background:#fff;overflow:hidden}\u001b[39m\n\u001b[31m  .ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m  .ph-img img{width:100%;height:100%;object-fit:contain}\u001b[39m\n\u001b[31m  .ph-cmt{position:static;background:transparent;color:#475569;padding:2mm 8mm;font-size:6mm}\u001b[39m\n\u001b[31m  .main>*:last-child{page-break-after:avoid;break-after:avoid}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m</style></head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<div class=\\\"side-idx\\\" id=\\\"side-idx\\\">${sideItems.join('')}</div>·\u001b[39m\n\u001b[31m<div class=\\\"main\\\" id=\\\"main\\\">·\u001b[39m\n\u001b[31m<div class=\\\"cover\\\" id=\\\"pg-cover\\\">\u001b[39m\n\u001b[31m  <div class=\\\"cov-hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-l\\\">\u001b[39m\n\u001b[31m      <div class=\\\"cov-store\\\">${esc(d.storeName||'Unknown Store')}</div>\u001b[39m\n\u001b[31m      ${(d.address||d.city)?`<div class=\\\"cov-meta\\\">&#x1F4CD; ${esc(d.address||'')}${d.city&&!(d.address||'').includes(d.city)?', '+esc(d.city):''}</div>`:''}\u001b[39m\n\u001b[31m      ${d.mobile?`<div class=\\\"cov-meta\\\">&#x1F4DE; ${esc(d.mobile)}</div>`:''}\u001b[39m\n\u001b[31m      ${d.email?`<div class=\\\"cov-meta\\\">&#x2709; ${esc(d.email)}</div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-r\\\">\u001b[39m\n\u001b[31m      ${brandLogoUrl\u001b[39m\n\u001b[31m        ? `<div class=\\\"cov-logo-box\\\"><img src=\\\"${brandLogoUrl}\\\" alt=\\\"${esc(d.brand||'')}\\\"></div>`\u001b[39m\n\u001b[31m        : (d.brand?`<div class=\\\"cov-brand\\\">${esc(d.brand)}</div>`:'')}\u001b[39m\n\u001b[31m      ${d.date?`<div><div class=\\\"cov-date-l\\\">Recce Date</div><div class=\\\"cov-date-v\\\">${esc(d.date)}</div></div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${thumbItems.length ? `<div class=\\\"cov-grid-hdr\\\">&#x1F4F7; ${thumbItems.length} page${thumbItems.length!==1?'s':''} &mdash; tap any to jump</div><div class=\\\"cov-grid\\\" id=\\\"cov-grid\\\">${thumbsHtml}</div>` : ''}\u001b[39m\n\u001b[31m  <div class=\\\"cover-pbar\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" id=\\\"btn-print\\\" onclick=\\\"doPDF()\\\">&#x1F4C4;&nbsp;PDF</button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-c\\\" onclick=\\\"window.close()\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m${pagesHtml}·\u001b[39m\n\u001b[31m${d.hasVideo?`\u001b[39m\n\u001b[31m<div class=\\\"vid-page\\\" id=\\\"pg-vid\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Video</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"vid-body\\\">${esc(d.videoNote||'Video recorded during visit')}${d.videoCmt?`<em>${esc(d.videoCmt)}</em>`:''}</div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m${urls.doc?`\u001b[39m\n\u001b[31m<div class=\\\"doc-page\\\" id=\\\"pg-doc\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Document</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"doc-wrap\\\"><a href=\\\"${urls.doc}\\\" target=\\\"_blank\\\"><img class=\\\"doc-img\\\" src=\\\"${urls.doc}\\\" loading=\\\"lazy\\\" alt=\\\"Document\\\"></a></div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"print-overlay\\\"><div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Preparing print&hellip;</div><div class=\\\"po-sub\\\" id=\\\"po-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"po-pfill\\\"></div></div></div>\u001b[39m\n\u001b[31m${pages.length ? `<div class=\\\"load-bar\\\" id=\\\"load-bar\\\"><div class=\\\"load-track\\\"><div class=\\\"load-fill\\\" id=\\\"load-fill\\\"></div></div><div class=\\\"load-txt\\\" id=\\\"load-txt\\\">Loading photos&#x2026;</div></div>` : ''}\u001b[39m\n\u001b[31m${thumbItems.length ? `<button id=\\\"cover-btn\\\" onclick=\\\"document.getElementById('pg-cover').scrollIntoView({behavior:'smooth'})\\\">&#x1F3E0;&nbsp;Cover Page</button>` : ''}·\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var main=document.getElementById('main');\u001b[39m\n\u001b[31m  var items=document.querySelectorAll('.si-item');\u001b[39m\n\u001b[31m  var covBtn=document.getElementById('cover-btn');\u001b[39m\n\u001b[31m  function setActive(id){\u001b[39m\n\u001b[31m    items.forEach(function(el){el.classList.toggle('active',el.dataset.tgt===id);});\u001b[39m\n\u001b[31m    var a=document.querySelector('.si-item[data-tgt=\\\"'+id+'\\\"]');\u001b[39m\n\u001b[31m    if(a) a.scrollIntoView({block:'nearest'});\u001b[39m\n\u001b[31m    if(covBtn) covBtn.style.display=id==='pg-cover'?'none':'flex';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  items.forEach(function(el){\u001b[39m\n\u001b[31m    el.addEventListener('click',function(){\u001b[39m\n\u001b[31m      var t=document.getElementById(el.dataset.tgt);\u001b[39m\n\u001b[31m      if(t) t.scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if('IntersectionObserver' in window){\u001b[39m\n\u001b[31m    var obs=new IntersectionObserver(function(entries){\u001b[39m\n\u001b[31m      entries.forEach(function(e){if(e.isIntersecting&&e.intersectionRatio>=0.45) setActive(e.target.id);});\u001b[39m\n\u001b[31m    },{root:main,threshold:0.45});\u001b[39m\n\u001b[31m    document.querySelectorAll('[id^=\\\"pg-\\\"]').forEach(function(p){obs.observe(p);});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  setActive('pg-cover');\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var imgs=Array.from(document.querySelectorAll('img'));\u001b[39m\n\u001b[31m  var total=imgs.length,loaded=0;\u001b[39m\n\u001b[31m  var bar=document.getElementById('load-bar');\u001b[39m\n\u001b[31m  var fill=document.getElementById('load-fill');\u001b[39m\n\u001b[31m  var txt=document.getElementById('load-txt');\u001b[39m\n\u001b[31m  var printPending=false,printShowTime=0;\u001b[39m\n\u001b[31m  var mm=96/25.4;\u001b[39m\n\u001b[31m  var SERVER_PDF='${serverPdfUrl}';\u001b[39m\n\u001b[31m  function updatePoBar(){\u001b[39m\n\u001b[31m    var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m    var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(poFill) poFill.style.width=(total?Math.round(loaded/total*100):100)+'%';\u001b[39m\n\u001b[31m    if(poSub) poSub.textContent=loaded+' / '+total+' photos ready';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function done(){\u001b[39m\n\u001b[31m    if(fill) fill.style.width='100%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='✓ All '+total+' photos ready';\u001b[39m\n\u001b[31m    setTimeout(function(){\u001b[39m\n\u001b[31m      if(bar){bar.style.transition='opacity .6s';bar.style.opacity='0';}\u001b[39m\n\u001b[31m      setTimeout(function(){if(bar)bar.style.display='none';},650);\u001b[39m\n\u001b[31m    },2000);\u001b[39m\n\u001b[31m    if(printPending){\u001b[39m\n\u001b[31m      printPending=false;\u001b[39m\n\u001b[31m      var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m      var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m      var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(poFill) poFill.style.width='100%';\u001b[39m\n\u001b[31m      if(poSub) poSub.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},Math.max(400,2000-(Date.now()-printShowTime)));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function onImg(){\u001b[39m\n\u001b[31m    loaded++;\u001b[39m\n\u001b[31m    if(fill) fill.style.width=Math.round(loaded/total*100)+'%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… '+loaded+' / '+total;\u001b[39m\n\u001b[31m    if(printPending) updatePoBar();\u001b[39m\n\u001b[31m    if(loaded>=total) done();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  /* ── PDF layout helpers ── */\u001b[39m\n\u001b[31m  function fitBandFonts(pageW){\u001b[39m\n\u001b[31m    var padH=2*13*mm,gapH=2*10*mm,noPadH=2*8*mm;\u001b[39m\n\u001b[31m    var avail=pageW-padH-gapH;\u001b[39m\n\u001b[31m    var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-band').forEach(function(band){\u001b[39m\n\u001b[31m      var cat=band.querySelector('.ph-cat');\u001b[39m\n\u001b[31m      var dims=band.querySelector('.ph-dims');\u001b[39m\n\u001b[31m      var no=band.querySelector('.ph-no');\u001b[39m\n\u001b[31m      if(!cat) return;\u001b[39m\n\u001b[31m      var catTxt=cat.textContent.trim();\u001b[39m\n\u001b[31m      var dimsTxt=dims?dims.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      var noTxt=no?no.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      function tw(sc){\u001b[39m\n\u001b[31m        var cf=15*sc*mm,df=10*sc*mm,nf=12*sc*mm;\u001b[39m\n\u001b[31m        ctx.font='800 '+cf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var cw=ctx.measureText(catTxt).width;\u001b[39m\n\u001b[31m        ctx.font='600 '+df+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var dw=dims?ctx.measureText(dimsTxt).width:0;\u001b[39m\n\u001b[31m        ctx.font='700 '+nf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var nw=no?ctx.measureText(noTxt).width+noPadH:0;\u001b[39m\n\u001b[31m        return cw+dw+nw;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      var scale=1.0;\u001b[39m\n\u001b[31m      if(tw(scale)>avail){\u001b[39m\n\u001b[31m        var lo=0.3,hi=1.0;\u001b[39m\n\u001b[31m        for(var i=0;i<10;i++){var mid=(lo+hi)/2;if(tw(mid)<=avail)lo=mid;else hi=mid;}\u001b[39m\n\u001b[31m        scale=lo*0.93;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      cat.style.setProperty('font-size',Math.round(15*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(dims) dims.style.setProperty('font-size',Math.round(10*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(no) no.style.setProperty('font-size',Math.round(12*scale*mm)+'px','important');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function sizePdfThumbs(pageW,pageH){\u001b[39m\n\u001b[31m    var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m    if(!grid||!grid.children.length) return;\u001b[39m\n\u001b[31m    var coverPage=document.getElementById('pg-cover');\u001b[39m\n\u001b[31m    var usedH=56;\u001b[39m\n\u001b[31m    if(coverPage){\u001b[39m\n\u001b[31m      Array.from(coverPage.children).forEach(function(el){\u001b[39m\n\u001b[31m        if(el!==grid) usedH+=el.offsetHeight||0;\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    var gridH=Math.max(80,pageH-usedH);\u001b[39m\n\u001b[31m    var n=grid.children.length,gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m    for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m      var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m      var w=(pageW-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m      var h=w*asp;\u001b[39m\n\u001b[31m      if(rows*h+(rows-1)*gap<=gridH&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m    grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m    grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m    var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m    var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m    var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function preparePdfLayout(){\u001b[39m\n\u001b[31m    var pageW=Math.round((297-24)*mm);\u001b[39m\n\u001b[31m    var pageH=Math.round((210-24)*mm);\u001b[39m\n\u001b[31m    fitBandFonts(pageW);\u001b[39m\n\u001b[31m    sizePdfThumbs(pageW,pageH);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.preparePdfLayout=preparePdfLayout;\u001b[39m\n\u001b[31m  function restorePdfLayout(){\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-cat,.ph-dims,.ph-no').forEach(function(el){\u001b[39m\n\u001b[31m      el.style.removeProperty('font-size');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(window._screenSizeThumbs) window._screenSizeThumbs();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.addEventListener('afterprint',restorePdfLayout);\u001b[39m\n\u001b[31m  function _doBrowserPrint(){\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    printShowTime=Date.now();\u001b[39m\n\u001b[31m    preparePdfLayout();\u001b[39m\n\u001b[31m    if(total===0||loaded>=total){\u001b[39m\n\u001b[31m      var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m      if(ps) ps.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},2000);\u001b[39m\n\u001b[31m      return;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    printPending=true;\u001b[39m\n\u001b[31m    updatePoBar();\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if((!img.complete||img.naturalWidth===0)&&img.getAttribute('loading')==='lazy'){\u001b[39m\n\u001b[31m        img.loading='eager';var s=img.src;img.src='';img.src=s;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.doPDF=async function(){\u001b[39m\n\u001b[31m    if(!SERVER_PDF){_doBrowserPrint();return;}\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      var r=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m      if(r.ok){window.open(SERVER_PDF,'_blank');return;}\u001b[39m\n\u001b[31m    }catch(_){}\u001b[39m\n\u001b[31m    // PDF not ready yet — show overlay and poll\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    if(pf) pf.style.width='0%';\u001b[39m\n\u001b[31m    if(ps) ps.textContent='Waiting for server PDF…';\u001b[39m\n\u001b[31m    var tries=0;\u001b[39m\n\u001b[31m    (async function poll(){\u001b[39m\n\u001b[31m      tries++;\u001b[39m\n\u001b[31m      if(pf) pf.style.width=Math.min(88,tries*8)+'%';\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        var r2=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m        if(r2.ok){\u001b[39m\n\u001b[31m          if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m          setTimeout(function(){if(ov)ov.style.display='none';window.open(SERVER_PDF,'_blank');},400);\u001b[39m\n\u001b[31m          return;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      }catch(_){}\u001b[39m\n\u001b[31m      if(tries>=12){if(ov)ov.style.display='none';_doBrowserPrint();return;}\u001b[39m\n\u001b[31m      setTimeout(poll,5000);\u001b[39m\n\u001b[31m    })();\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  if(total===0){if(bar)bar.style.display='none';}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… 0 / '+total;\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if(img.complete&&img.naturalWidth>0) onImg();\u001b[39m\n\u001b[31m      else{img.addEventListener('load',onImg);img.addEventListener('error',onImg);}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m  if(grid&&grid.children.length>0){\u001b[39m\n\u001b[31m    function sizeThumbs(){\u001b[39m\n\u001b[31m      var n=grid.children.length;\u001b[39m\n\u001b[31m      var gw=grid.clientWidth,gh=grid.clientHeight;\u001b[39m\n\u001b[31m      if(!gw||!gh) return;\u001b[39m\n\u001b[31m      var gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m      for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m        var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m        var w=(gw-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m        var h=w*asp;\u001b[39m\n\u001b[31m        if(rows*h+(rows-1)*gap<=gh&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m      grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m      grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m      var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m      var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m      var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    window._screenSizeThumbs=sizeThumbs;\u001b[39m\n\u001b[31m    requestAnimationFrame(function(){requestAnimationFrame(sizeThumbs);});\u001b[39m\n\u001b[31m    window.addEventListener('resize',sizeThumbs);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m</scr`+'ipt>'+`\u001b[39m\n\u001b[31m</body></html>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncToPostgres(entry) {\u001b[39m\n\u001b[31m  const d   = entry.data || {};\u001b[39m\n\u001b[31m  const hub = _recceHubUser();·\u001b[39m\n\u001b[31m  // Step 1 — upload all photos to VPS, get permanent server URLs\u001b[39m\n\u001b[31m  let photoUrls = { front:[], inside:[], brandings:[], addl:[], doc:null };\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const pResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type: 'save-photos', subId: entry.id,\u001b[39m\n\u001b[31m        photos: {\u001b[39m\n\u001b[31m          front:    (d.frontPhotos||[]).map(p=>({b64:p.b64,   cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64,  cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||null})),\u001b[39m\n\u001b[31m          addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64,   desc:p.desc||''})),\u001b[39m\n\u001b[31m          doc:      d.docB64 || null,\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (pResp.ok) { const r=await pResp.json(); if(r.success) {\u001b[39m\n\u001b[31m      photoUrls=r.photoUrls;\u001b[39m\n\u001b[31m      // Merge retained existing URLs for edit re-submits\u001b[39m\n\u001b[31m      if (entry.editedAt) {\u001b[39m\n\u001b[31m        photoUrls.front    =(photoUrls.front   ||[]).map((u,i)=>u||(d.frontPhotos  ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.inside   =(photoUrls.inside  ||[]).map((u,i)=>u||(d.insidePhotos ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.addl     =(photoUrls.addl    ||[]).map((u,i)=>u||(d.addlPhotos   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.brandings=(photoUrls.brandings||[]).map((u,i)=>u||(d.brandings   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        if(!photoUrls.doc) photoUrls.doc=d._docExistingUrl||null;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }}\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-photos] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 1.5 — trigger Google Slides via proxy using permanent photo URLs (fire-and-forget)\u001b[39m\n\u001b[31m  (async()=>{try{\u001b[39m\n\u001b[31m    const _hasPh=(photoUrls.front||[]).some(Boolean)||(photoUrls.inside||[]).some(Boolean)||(photoUrls.brandings||[]).some(Boolean);\u001b[39m\n\u001b[31m    if(!_hasPh)return;\u001b[39m\n\u001b[31m    const _gu=(await cfg('slides-gas-url'))||(await cfg('gas-url'))||DEFAULT_GAS_URL;if(!_gu)return;\u001b[39m\n\u001b[31m    await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({\u001b[39m\n\u001b[31m      type:'make-slides',gasUrl:_gu,subId:entry.id,\u001b[39m\n\u001b[31m      storeInfo:{storeName:d.storeName||'',brand:d.brand||'',address:d.address||'',mobile:d.mobile||'',date:d.date||'',city:d.city||'',gpsCoords:d.gpsCoords||null},\u001b[39m\n\u001b[31m      photoGroups:{\u001b[39m\n\u001b[31m        front:    (photoUrls.front   ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.frontPhotos  ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        inside:   (photoUrls.inside  ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.insidePhotos ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        brandings:(photoUrls.brandings||[]).filter(Boolean).map((url,i)=>({url,meta:{type:(d.brandings||[])[i]?.type,w:(d.brandings||[])[i]?.w,h:(d.brandings||[])[i]?.h,qty:(d.brandings||[])[i]?.qty,sqft:(d.brandings||[])[i]?.sqft}})),\u001b[39m\n\u001b[31m        addl:    (photoUrls.addl    ||[]).filter(Boolean).map((url,i)=>({url,desc:(d.addlPhotos  ||[])[i]?.desc||''})),\u001b[39m\n\u001b[31m      },\u001b[39m\n\u001b[31m    })});\u001b[39m\n\u001b[31m    entry.gasAt=new Date().toISOString();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[recce-slides]',e.message);}}\u001b[39m\n\u001b[31m  )();·\u001b[39m\n\u001b[31m  // Step 2 — generate rich HTML report using server URLs, save to VPS\u001b[39m\n\u001b[31m  let view_url = null;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const html  = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m    const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-view', subId: entry.id, html })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (vResp.ok) { const r=await vResp.json(); if(r.success) view_url=r.url; }\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-view] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 3 — upsert to PostgreSQL with photo URLs + view URL\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch(`${_RC_BASE}/submissions`, {\u001b[39m\n\u001b[31m      method: 'POST', headers: _RC_UPSERT,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        sub_id:         entry.id,\u001b[39m\n\u001b[31m        store_name:     d.storeName    || 'Unknown',\u001b[39m\n\u001b[31m        brand:          d.brand        || null,\u001b[39m\n\u001b[31m        client_name:    d.clientName   || null,\u001b[39m\n\u001b[31m        visit_date:     d.date         || new Date().toISOString().slice(0,10),\u001b[39m\n\u001b[31m        address:        d.address      || null,\u001b[39m\n\u001b[31m        mobile:         d.mobile       || null,\u001b[39m\n\u001b[31m        city:           d.city         || null,\u001b[39m\n\u001b[31m        has_branding:   !!(d.brandings?.length),\u001b[39m\n\u001b[31m        branding_count: d.brandings?.length || 0,\u001b[39m\n\u001b[31m        has_video:      !!d.hasVideo,\u001b[39m\n\u001b[31m        front_photos:   d.frontPhotos?.length  || 0,\u001b[39m\n\u001b[31m        inside_photos:  d.insidePhotos?.length || 0,\u001b[39m\n\u001b[31m        addl_photos:    d.addlPhotos?.length   || 0,\u001b[39m\n\u001b[31m        gps_lat:        d.gpsCoords?.lat       || null,\u001b[39m\n\u001b[31m        gps_lng:        d.gpsCoords?.lng       || null,\u001b[39m\n\u001b[31m        submitted_by:   hub.empId              || null,\u001b[39m\n\u001b[31m        submitted_at:   entry.timestamp,\u001b[39m\n\u001b[31m        campaign_id:    entry.campaignId       || null,\u001b[39m\n\u001b[31m        photo_urls:     photoUrls,\u001b[39m\n\u001b[31m        view_url,\u001b[39m\n\u001b[31m        meta: {\u001b[39m\n\u001b[31m          brandings: (d.brandings||[]).map(b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft})),\u001b[39m\n\u001b[31m          videoNote: d.videoNote || null,\u001b[39m\n\u001b[31m          videoCmt:  d.videoCmt  || null,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        status: 'submitted',\u001b[39m\n\u001b[31m        edit_assigned_to: null,\u001b[39m\n\u001b[31m        edit_comment: null,\u001b[39m\n\u001b[31m        edited_at: entry.editedAt || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    return { ok: true, viewUrl: view_url };\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    console.warn('[recce-db] sync error:', e.message);\u001b[39m\n\u001b[31m    return { ok: false, viewUrl: null };\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mconst DEFAULT_ADMIN_HASH='42d372e6110bee134990ac6881c3d5eb568482008add9a859f37f10d759430e8';·\u001b[39m\n\u001b[31masync function saveGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('gas-url',url||DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  toast('Endpoint saved','success');\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function testEndpoint(){\u001b[39m\n\u001b[31m  const url=(await cfg('gas-url'))||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  try{await fetch(url,{method:'POST',mode:'no-cors',body:JSON.stringify({test:true})});toast('Endpoint reachable ✓','success');}\u001b[39m\n\u001b[31m  catch{toast('Cannot reach endpoint','error')}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  cfg('gas-url').then(url=>{\u001b[39m\n\u001b[31m    const u=url||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    // Show last 30 chars only for privacy\u001b[39m\n\u001b[31m    el.textContent='Endpoint: …'+u.slice(-30);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── SLIDES GAS URL ────────────────────────────────────────────\u001b[39m\n\u001b[31masync function saveSlidesGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('slides-gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('slides-gas-url', url);\u001b[39m\n\u001b[31m  toast('Slides GAS URL saved','success');\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function updateSlidesGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('slides-gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  const u=await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  el.textContent=u?'Configured: …'+u.slice(-30):'Not configured';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── MAKE SLIDES ───────────────────────────────────────────────\u001b[39m\n\u001b[31masync function makeSlides(id){\u001b[39m\n\u001b[31m  const gasUrl = await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  if(!gasUrl){\u001b[39m\n\u001b[31m    toast('Configure Slides GAS URL in Settings first','error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const entry = await dbGet('subs', id);\u001b[39m\n\u001b[31m  if(!entry){ toast('Entry not found','error'); return; }\u001b[39m\n\u001b[31m  const d = entry.data;·\u001b[39m\n\u001b[31m  toast('Uploading photos & generating slides…','info');·\u001b[39m\n\u001b[31m  // Build photo groups payload\u001b[39m\n\u001b[31m  const photoGroups = {\u001b[39m\n\u001b[31m    front:    (d.frontPhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64, cmt:p.desc||''})),\u001b[39m\n\u001b[31m    brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||'', meta:{type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft}})),\u001b[39m\n\u001b[31m  };·\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type:       'recce',\u001b[39m\n\u001b[31m        subId:      id,\u001b[39m\n\u001b[31m        gasUrl:     gasUrl,\u001b[39m\n\u001b[31m        storeInfo:  {\u001b[39m\n\u001b[31m          storeName: d.storeName, brand: d.brand,\u001b[39m\n\u001b[31m          date: d.date, address: d.address,\u001b[39m\n\u001b[31m          mobile: d.mobile, gpsCoords: d.gpsCoords,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        photoGroups,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const result = await resp.json();\u001b[39m\n\u001b[31m    if(result.success && result.slideUrl){\u001b[39m\n\u001b[31m      // Store slide URL on the entry\u001b[39m\n\u001b[31m      entry.slideUrl = result.slideUrl;\u001b[39m\n\u001b[31m      await dbPut('subs', entry);\u001b[39m\n\u001b[31m      toast('✅ Slides ready!','success');\u001b[39m\n\u001b[31m      window.open(result.slideUrl, '_blank');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast('Slides error: '+(result.error||'Unknown'),'error');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e){\u001b[39m\n\u001b[31m    toast('Network error: '+e.message,'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN LOGIN ──────────────────────────────────────────────\u001b[39m\n\u001b[31mfunction showAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-error').style.display='none';\u001b[39m\n\u001b[31m  // Restore saved config URL\u001b[39m\n\u001b[31m  cfg('admin-cfg-url').then(u=>{if(u&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=u;});\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('admin-pwd').focus(),100);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveAdminCfgUrl(){\u001b[39m\n\u001b[31m  // Admin cfg URL can be saved without login (needed to set up auth itself)\u001b[39m\n\u001b[31m  // But we warn if saving while unlocked only\u001b[39m\n\u001b[31m  const url=document.getElementById('admin-cfg-url').value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  await cfg('admin-cfg-url',url);\u001b[39m\n\u001b[31m  toast('Config URL saved — will use on next login attempt','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function verifyAdmin(){\u001b[39m\n\u001b[31m  // Hub admins (harish/pramod) are auto-unlocked — no password needed\u001b[39m\n\u001b[31m  if (_adminUnlocked) { adminLoginSuccess(); return; }\u001b[39m\n\u001b[31m  const pwd=document.getElementById('admin-pwd').value;\u001b[39m\n\u001b[31m  if(!pwd){document.getElementById('admin-error').style.display='block';document.getElementById('admin-error').textContent='Enter password';return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('admin-login-btn');btn.disabled=true;btn.textContent='Verifying…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // Try server verification first\u001b[39m\n\u001b[31m    const cfgUrl=(await cfg('admin-cfg-url'))||'';\u001b[39m\n\u001b[31m    if(cfgUrl){\u001b[39m\n\u001b[31m      const r=await fetch(cfgUrl,{cache:'no-store'});\u001b[39m\n\u001b[31m      const j=await r.json();\u001b[39m\n\u001b[31m      // Server JSON format: {\\\"password\\\":\\\"plaintext\\\"} or {\\\"hash\\\":\\\"sha256hash\\\"}\u001b[39m\n\u001b[31m      let match=false;\u001b[39m\n\u001b[31m      if(j.password){match=(j.password===pwd);}\u001b[39m\n\u001b[31m      else if(j.hash){\u001b[39m\n\u001b[31m        // SHA-256 comparison\u001b[39m\n\u001b[31m        const enc=new TextEncoder();\u001b[39m\n\u001b[31m        const data=enc.encode(pwd);\u001b[39m\n\u001b[31m        const hashBuf=await crypto.subtle.digest('SHA-256',data);\u001b[39m\n\u001b[31m        const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m        match=(hashHex===j.hash);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      if(match){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m      else{showAdminError('Incorrect password');return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Fallback: local password stored in settings\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if(localHash){\u001b[39m\n\u001b[31m      const enc=new TextEncoder();\u001b[39m\n\u001b[31m      const hashBuf=await crypto.subtle.digest('SHA-256',enc.encode(pwd));\u001b[39m\n\u001b[31m      const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m      if(hashHex===localHash){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Final fallback: check against hardcoded default hash\u001b[39m\n\u001b[31m    const enc2=new TextEncoder();\u001b[39m\n\u001b[31m    const hb2=await crypto.subtle.digest('SHA-256',enc2.encode(pwd));\u001b[39m\n\u001b[31m    const hh2=Array.from(new Uint8Array(hb2)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    if(hh2===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }catch(err){\u001b[39m\n\u001b[31m    // Network error — try all local fallbacks\u001b[39m\n\u001b[31m    const enc3=new TextEncoder();\u001b[39m\n\u001b[31m    const hb3=await crypto.subtle.digest('SHA-256',enc3.encode(pwd));\u001b[39m\n\u001b[31m    const hh3=Array.from(new Uint8Array(hb3)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if((localHash&&hh3===localHash)||hh3===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }finally{btn.disabled=false;btn.textContent='Login';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showAdminError(msg){\u001b[39m\n\u001b[31m  const el=document.getElementById('admin-error');\u001b[39m\n\u001b[31m  el.textContent=msg;el.style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminLoginSuccess(){\u001b[39m\n\u001b[31m  _adminUnlocked=true;\u001b[39m\n\u001b[31m  closeAdminLogin();\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  cfg('gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  cfg('slides-gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('slides-gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||'';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  toast('Admin mode unlocked','success');\u001b[39m\n\u001b[31m  setTimeout(lockAdmin,10*60*1000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction lockAdmin(){\u001b[39m\n\u001b[31m  _adminUnlocked=false;\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  toast('Admin session ended','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updAvailTag(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-avail-tag');\u001b[39m\n\u001b[31m  const ct=document.getElementById('store-avail-count');\u001b[39m\n\u001b[31m  const txt=stores.length?`${stores.length} stores`:'No store list';\u001b[39m\n\u001b[31m  if(el)el.textContent=txt;\u001b[39m\n\u001b[31m  if(ct)ct.textContent=stores.length?t(`${stores.length} stores available — tap to browse`,`${stores.length} स्टोर उपलब्ध — दबाएं`):t('No store list loaded yet','कोई स्टोर सूची नहीं');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PICKER\u001b[39m\n\u001b[31mfunction openPicker(){\u001b[39m\n\u001b[31m  if(!stores.length){toast('Load a store list in Settings first','error');return;}\u001b[39m\n\u001b[31m  document.getElementById('povl').classList.add('open');\u001b[39m\n\u001b[31m  document.getElementById('psearch').value='';\u001b[39m\n\u001b[31m  filterPicker('');\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('psearch').focus(),150);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closePicker(){document.getElementById('povl').classList.remove('open');}\u001b[39m\n\u001b[31masync function filterPicker(q){\u001b[39m\n\u001b[31m  const list=document.getElementById('plist');\u001b[39m\n\u001b[31m  const words=q.toLowerCase().trim().split(/\\\\s+/).filter(Boolean);\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const lastVisit={};\u001b[39m\n\u001b[31m  subs.forEach(s=>{const nm=s.data?.storeName;if(nm&&(!lastVisit[nm]||s.timestamp>lastVisit[nm]))lastVisit[nm]=s.timestamp;});·\u001b[39m\n\u001b[31m  // Multi-word: ALL words must match somewhere in any field (search across both English and Hindi)\u001b[39m\n\u001b[31m  let fl=stores.filter(s=>{\u001b[39m\n\u001b[31m    if(!words.length)return true;\u001b[39m\n\u001b[31m    const hay=[s.name,s.nameHi,s.address,s.addressHi,s.mobile,s.city,s.cityHi,s.distName,s.distNameHi,s.brand,s.sales,s.proj,s.glowSign,s.inshop]\u001b[39m\n\u001b[31m               .map(x=>(x||'').toLowerCase()).join(' ');\u001b[39m\n\u001b[31m    return words.every(w=>hay.includes(w));\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(fl.length>100)fl=fl.slice(0,100);·\u001b[39m\n\u001b[31m  if(!fl.length){\u001b[39m\n\u001b[31m    const esc=q.replace(/'/g,\\\"\\\\\\\\'\\\");\u001b[39m\n\u001b[31m    list.innerHTML=`<div style=\\\"text-align:center;padding:32px 16px;color:var(--g400);font-size:14px\\\">No stores match \\\"${q}\\\"<br><span style=\\\"font-size:12px\\\">Try fewer or different words</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('${esc}')\\\">+ Add \\\"${q}\\\" as new store</div>`;\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Group by brand (including empty brand)\u001b[39m\n\u001b[31m  const g={};\u001b[39m\n\u001b[31m  fl.forEach(s=>{\u001b[39m\n\u001b[31m    const b=s.brand||'(No Brand — will ask)';\u001b[39m\n\u001b[31m    if(!g[b])g[b]=[];\u001b[39m\n\u001b[31m    g[b].push(s);\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html='';\u001b[39m\n\u001b[31m  Object.keys(g).sort().forEach(br=>{\u001b[39m\n\u001b[31m    html+=`<div class=\\\"psec\\\">${br}</div>`;\u001b[39m\n\u001b[31m    g[br].forEach(s=>{\u001b[39m\n\u001b[31m      const lv=lastVisit[s.name];\u001b[39m\n\u001b[31m      const lvStr=lv?`🕐 Last: ${new Date(lv).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'2-digit'})}`:'';\u001b[39m\n\u001b[31m      const chips=[];\u001b[39m\n\u001b[31m      if(s.glowSign&&s.glowSign.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dcfce7;color:#14532d;padding:2px 6px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m      if(s.inshop&&s.inshop.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dbeafe;color:#1e40af;padding:2px 6px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m      if(s.proj)chips.push(`<span style=\\\"font-size:10px;background:var(--g100);color:var(--g600);padding:2px 6px;border-radius:10px\\\">Target: ${s.proj}</span>`);\u001b[39m\n\u001b[31m      const enc=JSON.stringify(s).replace(/\\\"/g,'&quot;');\u001b[39m\n\u001b[31m      const mapsUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m      const waUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const telUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const dispName=LANG==='hi'&&s.nameHi?s.nameHi:s.name;\u001b[39m\n\u001b[31m      const dispAddr=LANG==='hi'&&s.addressHi?s.addressHi:s.address;\u001b[39m\n\u001b[31m      const dispDist=LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m      html+=`<div class=\\\"pitem\\\" onclick=\\\"pickStore(${enc})\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"pi-name\\\">${dispName}</div>\u001b[39m\n\u001b[31m          ${dispAddr?`<div class=\\\"pi-addr\\\">📍 ${dispAddr}</div>`:''}\u001b[39m\n\u001b[31m          ${s.mobile?`<div class=\\\"pi-addr\\\">📞 ${s.mobile}</div>`:''}\u001b[39m\n\u001b[31m          ${dispDist?`<div class=\\\"pi-addr\\\" style=\\\"color:var(--am)\\\">👤 ${dispDist}</div>`:''}\u001b[39m\n\u001b[31m          ${lvStr?`<div class=\\\"pi-last\\\">${lvStr}</div>`:''}\u001b[39m\n\u001b[31m          ${chips.length?`<div style=\\\"display:flex;gap:4px;flex-wrap:wrap;margin-top:4px\\\">${chips.join('')}</div>`:''}\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;gap:6px;margin-top:7px\\\" onclick=\\\"event.stopPropagation()\\\">\u001b[39m\n\u001b[31m            ${mapsUrl?`<a href=\\\"${mapsUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#e0f2fe;color:#0369a1;border-radius:20px;text-decoration:none;font-weight:600\\\">🗺 Maps</a>`:''}\u001b[39m\n\u001b[31m            ${waUrl?`<a href=\\\"${waUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#dcfce7;color:#15803d;border-radius:20px;text-decoration:none;font-weight:600\\\">💬 WhatsApp</a>`:''}\u001b[39m\n\u001b[31m            ${telUrl?`<a href=\\\"${telUrl}\\\" style=\\\"font-size:11px;padding:4px 10px;background:#f0fdf4;color:#166534;border-radius:20px;text-decoration:none;font-weight:600\\\">📞 Call</a>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        ${s.brand?`<div class=\\\"pi-brand\\\">${s.brand}</div>`:'<div class=\\\"pi-brand\\\" style=\\\"background:var(--rd)\\\">?</div>'}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html+=`<div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('')\\\">+ Not in list? Add new store</div>`;\u001b[39m\n\u001b[31m  list.innerHTML=html;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function pickStore(s){\u001b[39m\n\u001b[31m  selectedStore=s;manualMode=false;closePicker();\u001b[39m\n\u001b[31m  const _dn =LANG==='hi'&&s.nameHi    ?s.nameHi    :s.name;\u001b[39m\n\u001b[31m  const _da =LANG==='hi'&&s.addressHi ?s.addressHi :s.address;\u001b[39m\n\u001b[31m  const _dd =LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m  const _dc =LANG==='hi'&&s.cityHi    ?s.cityHi    :s.city;\u001b[39m\n\u001b[31m  document.getElementById('sc-name').textContent=_dn;\u001b[39m\n\u001b[31m  const brandEl=document.getElementById('sc-brand');\u001b[39m\n\u001b[31m  brandEl.textContent=s.brand||'No Brand';brandEl.style.background=s.brand?'var(--nv)':'var(--rd)';\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const prev=subs.filter(x=>x.data?.storeName===s.name).sort((a,b)=>new Date(b.timestamp)-new Date(a.timestamp))[0];\u001b[39m\n\u001b[31m  const lc=document.getElementById('sc-last');\u001b[39m\n\u001b[31m  if(prev){const d=new Date(prev.timestamp);lc.textContent='Last: '+d.toLocaleDateString('en-IN',{day:'numeric',month:'short'});lc.style.display='inline-flex';}\u001b[39m\n\u001b[31m  else lc.style.display='none';\u001b[39m\n\u001b[31m  // All Excel fields — display in active language\u001b[39m\n\u001b[31m  const mUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m  const wUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const tUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const details=[];\u001b[39m\n\u001b[31m  if(_da)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📍 ${_da}${mUrl?` <a href=\\\"${mUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#0369a1;margin-left:6px\\\">🗺 Navigate</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(s.mobile)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📞 ${s.mobile}${tUrl?` <a href=\\\"${tUrl}\\\" style=\\\"font-size:11px;color:#166534;margin-left:6px\\\">Call</a>`:''}${wUrl?` <a href=\\\"${wUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#15803d;margin-left:6px\\\">WhatsApp</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(_dd)details.push(`<div style=\\\"font-size:12px;color:var(--am)\\\">👤 ${_dd}</div>`);\u001b[39m\n\u001b[31m  if(_dc)details.push(`<div style=\\\"font-size:12px;color:var(--g500)\\\">🏙 ${_dc}</div>`);\u001b[39m\n\u001b[31m  const opp=[];\u001b[39m\n\u001b[31m  if(s.glowSign&&s.glowSign.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dcfce7;color:#14532d;padding:2px 7px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m  if(s.inshop&&s.inshop.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dbeafe;color:#1e40af;padding:2px 7px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m  if(s.proj)opp.push(`<span style=\\\"font-size:11px;background:var(--g100);color:var(--g600);padding:2px 7px;border-radius:10px\\\">Target 2026: ${s.proj}</span>`);\u001b[39m\n\u001b[31m  if(opp.length)details.push(`<div style=\\\"display:flex;gap:5px;flex-wrap:wrap;margin-top:3px\\\">${opp.join('')}</div>`);\u001b[39m\n\u001b[31m  document.getElementById('sc-details').innerHTML=details.join('');\u001b[39m\n\u001b[31m  // Missing fields\u001b[39m\n\u001b[31m  const missing=[];\u001b[39m\n\u001b[31m  if(!s.address)missing.push({key:'address',label:'Store Address',type:'textarea',placeholder:'Full address'});\u001b[39m\n\u001b[31m  if(!s.mobile)missing.push({key:'mobile',label:'Mobile No.',type:'tel',placeholder:'10-digit number',maxlen:'10'});\u001b[39m\n\u001b[31m  const mw=document.getElementById('sc-missing'),mf=document.getElementById('sc-missing-fields');\u001b[39m\n\u001b[31m  if(missing.length){\u001b[39m\n\u001b[31m    mf.innerHTML=missing.map(m=>`<div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\"><label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">${m.label} <span class=\\\"req\\\">*</span></label>${m.type==='textarea'?`<textarea id=\\\"sc-miss-${m.key}\\\" rows=\\\"2\\\" placeholder=\\\"${m.placeholder}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></textarea>`:`<input type=\\\"${m.type}\\\" id=\\\"sc-miss-${m.key}\\\" placeholder=\\\"${m.placeholder}\\\" ${m.maxlen?`maxlength=\\\"${m.maxlen}\\\"`:''}  inputmode=\\\"${m.type==='tel'?'numeric':'text'}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\">`}</div>`).join('');\u001b[39m\n\u001b[31m    mw.style.display='block';\u001b[39m\n\u001b[31m  } else {mw.style.display='none';}\u001b[39m\n\u001b[31m  // Brand selector\u001b[39m\n\u001b[31m  const bSel=document.getElementById('brand-selector'),bChips=document.getElementById('brand-chips');\u001b[39m\n\u001b[31m  if(!s.brand){\u001b[39m\n\u001b[31m    renderBrandChips();\u001b[39m\n\u001b[31m    bSel.style.display='block';\u001b[39m\n\u001b[31m  } else {bSel.style.display='none';}\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  F.storeName=s.name;F.brand=s.brand||'';F.address=s.address||'';F.mobile=s.mobile||'';\u001b[39m\n\u001b[31m  if(s.brand&&!_selectedClient&&!_clientOtherMode) autoSetClient(s.brand);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateMissingField(key,val){if(!selectedStore)return;selectedStore[key]=val.trim();F[key]=val.trim();saveDraft();}\u001b[39m\n\u001b[31mfunction selectStoreBrand(b){\u001b[39m\n\u001b[31m  F.brand=b;F.brandLogoUrl=_brandLogos[b]||'';\u001b[39m\n\u001b[31m  if(selectedStore)selectedStore.brand=b;\u001b[39m\n\u001b[31m  const el=document.getElementById('sc-brand');if(el){el.textContent=b;el.style.background='var(--nv)';}\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-chips .chip').forEach(c=>{c.classList.toggle('sel',c.querySelector('span')?.textContent===b||c.textContent.trim()===b);});\u001b[39m\n\u001b[31m  if(!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction onManualBrandChange(){\u001b[39m\n\u001b[31m  const b=document.getElementById('f-brand')?.value||'';\u001b[39m\n\u001b[31m  F.brandLogoUrl=b?(_brandLogos[b]||''):'';\u001b[39m\n\u001b[31m  if(b&&!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction openManual(prefill){\u001b[39m\n\u001b[31m  manualMode=true;\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').classList.add('on');\u001b[39m\n\u001b[31m  document.getElementById('mt-label').innerHTML='← Back to store list';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='block';\u001b[39m\n\u001b[31m  // Pre-fill from selectedStore if available (e.g. when toggling after picker selection)\u001b[39m\n\u001b[31m  const s=selectedStore;\u001b[39m\n\u001b[31m  if(s){\u001b[39m\n\u001b[31m    if(document.getElementById('f-brand'))document.getElementById('f-brand').value=s.brand||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-store'))document.getElementById('f-store').value=s.name||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-addr'))document.getElementById('f-addr').value=s.address||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-mobile'))document.getElementById('f-mobile').value=s.mobile||'';\u001b[39m\n\u001b[31m  } else if(prefill){\u001b[39m\n\u001b[31m    document.getElementById('f-store').value=prefill;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  selectedStore=null;\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction toggleManual(){\u001b[39m\n\u001b[31m  if(manualMode){\u001b[39m\n\u001b[31m    manualMode=false;\u001b[39m\n\u001b[31m    document.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31m    document.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31m    document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    openManual('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// GPS\u001b[39m\n\u001b[31mfunction captureGPS(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gps-status');el.textContent='Getting location…';el.style.color='var(--g500)';\u001b[39m\n\u001b[31m  if(!navigator.geolocation){el.textContent='GPS not available';return;}\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(pos=>{\u001b[39m\n\u001b[31m    gpsCoords={lat:pos.coords.latitude.toFixed(6),lng:pos.coords.longitude.toFixed(6),acc:Math.round(pos.coords.accuracy)};\u001b[39m\n\u001b[31m    el.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${gpsCoords.acc}m)`;el.style.color='var(--gn)';saveDraft();\u001b[39m\n\u001b[31m  },()=>{el.textContent='GPS failed — enter address manually';el.style.color='var(--rd)';},{enableHighAccuracy:true,timeout:10000});\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// DRAFT\u001b[39m\n\u001b[31mlet draftT;\u001b[39m\n\u001b[31mfunction saveDraft(){\u001b[39m\n\u001b[31m  clearTimeout(draftT);\u001b[39m\n\u001b[31m  draftT=setTimeout(async()=>{\u001b[39m\n\u001b[31m    const draft={k:'current',ts:Date.now(),F:{...F,date:document.getElementById('f-date')?.value||'',brand:manualMode?(document.getElementById('f-brand')?.value||''):(selectedStore?.brand||F.brand||''),storeName:selectedStore?selectedStore.name:(document.getElementById('f-store')?.value||''),address:manualMode?(document.getElementById('f-addr')?.value||''):(selectedStore?.address||F.address||''),mobile:manualMode?(document.getElementById('f-mobile')?.value||''):(selectedStore?.mobile||F.mobile||''),clientName:getClientName()},selectedStore,manualMode,gpsCoords,_selectedClient,_clientOtherMode,fCnt:frontPhotos.length,iCnt:insidePhotos.length,bCnt:brandings.length};\u001b[39m\n\u001b[31m    await dbPut('draft',draft);\u001b[39m\n\u001b[31m    // Also save photos as b64 blobs to draft so they survive exit\u001b[39m\n\u001b[31m    await saveDraftPhotos();\u001b[39m\n\u001b[31m  },500);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveDraftPhotos(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const photoData={\u001b[39m\n\u001b[31m      front:await Promise.all(frontPhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      inside:await Promise.all(insidePhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      addl:await Promise.all(addlPhotos.map(async p=>({b64:await b64(p.blob),desc:p.desc||''}))),\u001b[39m\n\u001b[31m      brand:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,b64:b.blob?await b64(b.blob):null})))\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    await dbPut('draft',{k:'photos',...photoData});\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function checkDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');const wrap=document.getElementById('resume-wrap');\u001b[39m\n\u001b[31m  if(!d||!d.F?.storeName){wrap.innerHTML='';return;}\u001b[39m\n\u001b[31m  const ago=Math.round((Date.now()-d.ts)/60000);\u001b[39m\n\u001b[31m  const agoStr=ago<1?'just now':ago<60?`${ago}m ago`:`${Math.round(ago/60)}h ago`;\u001b[39m\n\u001b[31m  wrap.innerHTML=`<button class=\\\"resume-btn\\\" onclick=\\\"resumeDraft()\\\">\u001b[39m\n\u001b[31m    <div><div style=\\\"font-size:12px;color:rgba(255,255,255,.5);margin-bottom:3px\\\">Resume draft · ${agoStr}</div><div>${d.F.storeName} · ${d.F.brand||'No brand'}</div></div>\u001b[39m\n\u001b[31m    <div style=\\\"text-align:right\\\"><div style=\\\"font-size:13px;color:var(--or)\\\">${d.fCnt||0} photos · ${d.bCnt||0} brandings →</div></div>\u001b[39m\n\u001b[31m  </button>`;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function resumeDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');if(!d)return;\u001b[39m\n\u001b[31m  F=d.F||{};gpsCoords=d.gpsCoords||null;\u001b[39m\n\u001b[31m  if(d.selectedStore){await pickStore(d.selectedStore);}\u001b[39m\n\u001b[31m  else if(d.manualMode){openManual('');if(F.brand)document.getElementById('f-brand').value=F.brand;if(F.storeName)document.getElementById('f-store').value=F.storeName;if(F.address)document.getElementById('f-addr').value=F.address;if(F.mobile)document.getElementById('f-mobile').value=F.mobile;}\u001b[39m\n\u001b[31m  if(F.date)document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  // Restore client chip state\u001b[39m\n\u001b[31m  if(d._clientOtherMode){_clientOtherMode=true;_selectedClient='';const inp=document.getElementById('f-client-other');if(inp&&F.clientName)inp.value=F.clientName;}\u001b[39m\n\u001b[31m  else if(d._selectedClient){_selectedClient=d._selectedClient;_clientOtherMode=false;}\u001b[39m\n\u001b[31m  else if(F.clientName){autoSetClient(F.clientName);}\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  // Restore photos from draft\u001b[39m\n\u001b[31m  const pd=await dbGet('draft','photos');\u001b[39m\n\u001b[31m  if(pd){\u001b[39m\n\u001b[31m    async function b64ToBlob(b64str){if(!b64str)return null;try{const r=await fetch(b64str);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m    for(const p of(pd.front||[])){const bl=await b64ToBlob(p.b64);if(bl)frontPhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.inside||[])){const bl=await b64ToBlob(p.b64);if(bl)insidePhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.addl||[])){const bl=await b64ToBlob(p.b64);if(bl)addlPhotos.push({blob:bl,prev:URL.createObjectURL(bl),desc:p.desc||''});}\u001b[39m\n\u001b[31m    for(const b of(pd.brand||[])){const bl=await b64ToBlob(b.b64);brandings.push({type:b.type,w:b.w,h:b.h,qty:b.qty,blob:bl,prev:bl?URL.createObjectURL(bl):null});}\u001b[39m\n\u001b[31m    toast('Draft restored with '+frontPhotos.length+' photos ✓','success');\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    toast('Draft restored — photos could not be recovered','info');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PHOTOS\u001b[39m\n\u001b[31mfunction updPhotoBadge(type){const arr=type==='front'?frontPhotos:insidePhotos;const el=document.getElementById(type+'-badge');if(el){el.textContent=arr.length;el.className='cnt-badge '+(arr.length?'':'gray');}}\u001b[39m\n\u001b[31mfunction renderPhotos(type){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  const cont=document.getElementById(type+'-cont');const addBtn=document.getElementById('add-'+type);\u001b[39m\n\u001b[31m  updPhotoBadge(type);\u001b[39m\n\u001b[31m  if(arr.length===0){cont.innerHTML=`<div class=\\\"pslot\\\" onclick=\\\"addPhoto('${type}')\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to capture or upload</span><span class=\\\"hi-txt\\\">फोटो खींचें या अपलोड करें</span></div></div>`;addBtn.style.display='none';return;}\u001b[39m\n\u001b[31m  cont.innerHTML=arr.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const badge=isRetained?`<span class=\\\"pbadge\\\" style=\\\"background:#475569\\\">Existing</span>`:`<span class=\\\"pbadge\\\">${fmtSz(p.blob.size)}</span>`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replacePhoto('${type}',${i})\\\" style=\\\"right:36px;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"margin-bottom:12px\\\"><div class=\\\"pslot filled\\\" style=\\\"margin-bottom:8px\\\"><img src=\\\"${p.prev}\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmPhoto('${type}',${i})\\\">×</button>${badge}</div><input type=\\\"text\\\" placeholder=\\\"Comments (optional)\\\" value=\\\"${p.cmt||''}\\\" onchange=\\\"${type==='front'?'frontPhotos':'insidePhotos'}[${i}].cmt=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  addBtn.style.display=arr.length<(type==='inside'?5:3)?'inline-flex':'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// Photo source: 'camera' stamps geo, 'gallery' does not\u001b[39m\n\u001b[31mlet _photoSourceCb=null,_photoSourceQuality=null;·\u001b[39m\n\u001b[31mfunction capPhoto(cb,forceSource,quality){\u001b[39m\n\u001b[31m  // quality override: null=use setting, 'hd', 'compressed'\u001b[39m\n\u001b[31m  _photoSourceCb=cb;_photoSourceQuality=quality||null;\u001b[39m\n\u001b[31m  if(forceSource==='camera'){_doCapture(cb,'camera',quality);return;}\u001b[39m\n\u001b[31m  if(forceSource==='gallery'){_doCapture(cb,'gallery',quality);return;}\u001b[39m\n\u001b[31m  // Show picker\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _doCapture(cb,src,quality){\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  const i=document.createElement('input');\u001b[39m\n\u001b[31m  i.type='file';i.accept='image/*';\u001b[39m\n\u001b[31m  if(src==='camera')i.setAttribute('capture','environment');\u001b[39m\n\u001b[31m  i.style.display='none';\u001b[39m\n\u001b[31m  i.onchange=async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f)return;\u001b[39m\n\u001b[31m    const q=quality||_photoSourceQuality||null;\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      const blob=await compress(f,q==='hd'?1920:q==='compressed'?1280:null,q==='hd'?0.90:q==='compressed'?0.78:null);\u001b[39m\n\u001b[31m      // Only stamp if from camera (live photo)\u001b[39m\n\u001b[31m      const stamped=(src==='camera')?await stampPhoto(blob):blob;\u001b[39m\n\u001b[31m      // Save to device (auto-download trigger)\u001b[39m\n\u001b[31m      savePhotoToDevice(stamped);\u001b[39m\n\u001b[31m      cb({target:{files:[f]},_blob:stamped,_src:src});\u001b[39m\n\u001b[31m    }catch(err){toast('Photo processing failed — try again','error');console.error('_doCapture error:',err);}\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  document.body.appendChild(i);i.click();setTimeout(()=>i.remove(),8000);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction photoSrcCamera(){_doCapture(_photoSourceCb,'camera',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcGallery(){_doCapture(_photoSourceCb,'gallery',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcCancel(){document.getElementById('photo-src-dialog').classList.remove('open');_photoSourceCb=null;}·\u001b[39m\n\u001b[31m// Save photo to device gallery/downloads\u001b[39m\n\u001b[31mfunction savePhotoToDevice(blob){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    const a=document.createElement('a');\u001b[39m\n\u001b[31m    a.href=url;\u001b[39m\n\u001b[31m    a.download='Recce_'+Date.now()+'.jpg';\u001b[39m\n\u001b[31m    a.style.display='none';\u001b[39m\n\u001b[31m    document.body.appendChild(a);a.click();\u001b[39m\n\u001b[31m    setTimeout(()=>{URL.revokeObjectURL(url);a.remove();},1000);\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addPhoto(type){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}${e._src==='camera'&&geoStampEnabled?' · Stamped':''}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31masync function handleCapture(e,type){\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmPhoto(type,i){(type==='front'?frontPhotos:insidePhotos).splice(i,1);renderPhotos(type);saveDraft();}\u001b[39m\n\u001b[31mfunction replacePhoto(type,idx){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m    arr[idx]={...arr[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAddl(){\u001b[39m\n\u001b[31m  const cont=document.getElementById('add-cont');const btn=document.getElementById('add-addl');\u001b[39m\n\u001b[31m  const badge=document.getElementById('addl-badge');if(badge){badge.textContent=`${addlPhotos.length} / 8`;badge.className='cnt-badge '+(addlPhotos.length?'':'gray');}\u001b[39m\n\u001b[31m  cont.innerHTML=addlPhotos.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const sizeInfo=isRetained?'<span style=\\\"color:#475569\\\">Existing</span>':`${fmtSz(p.blob.size)}`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replaceAddl(${i})\\\" style=\\\"top:3px;left:3px;right:auto;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;gap:10px;align-items:start;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--g100)\\\"><div style=\\\"position:relative;flex-shrink:0\\\"><img src=\\\"${p.prev}\\\" style=\\\"width:80px;height:80px;object-fit:cover;border-radius:var(--rs)\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmAddl(${i})\\\" style=\\\"top:3px;right:3px\\\">×</button></div><div style=\\\"flex:1\\\"><input type=\\\"text\\\" placeholder=\\\"Description (optional)\\\" value=\\\"${p.desc||''}\\\" onchange=\\\"addlPhotos[${i}].desc=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"><div style=\\\"font-size:11px;color:var(--g400);margin-top:4px\\\">${sizeInfo}</div></div></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  btn.style.display=addlPhotos.length>=8?'none':'inline-flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction addAdditional(){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  addlPhotos.push({blob:bs,prev:URL.createObjectURL(bs),desc:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderAddl();saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31mfunction rmAddl(i){addlPhotos.splice(i,1);renderAddl();saveDraft();}\u001b[39m\n\u001b[31mfunction replaceAddl(idx){\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m    addlPhotos[idx]={...addlPhotos[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderAddl();saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// BRANDING\u001b[39m\n\u001b[31mfunction calcSqft(w,h){const wf=parseFloat(w),hf=parseFloat(h);if(!wf||!hf)return '';return `${(wf*hf).toFixed(0)} sq.in = ${(wf*hf/144).toFixed(2)} sq.ft`;}\u001b[39m\n\u001b[31mfunction renderBrandings(){\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  const cont=document.getElementById('br-items');\u001b[39m\n\u001b[31m  const hb=document.getElementById('br-hdr-badge');if(hb)hb.textContent=`${brandings.length} ${t(brandings.length!==1?'items':'item',brandings.length!==1?'आइटम':'आइटम')}`;\u001b[39m\n\u001b[31m  cont.innerHTML=brandings.map((b,i)=>`<div class=\\\"bitem\\\"><div class=\\\"bitem-hdr\\\"><div class=\\\"bitem-title\\\">${t('Branding','ब्रांडिंग')} ${i+1}${b.type?' — '+b.type:''}</div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:6px\\\">${i>0?`<button class=\\\"btn-d\\\" onclick=\\\"dupBr(${i})\\\" style=\\\"color:var(--or);border-color:var(--orl)\\\">${t('Dup ↑','डुप ↑')}</button>`:''}<button class=\\\"btn-d\\\" onclick=\\\"rmBr(${i})\\\">${t('Remove','हटाएं')}</button></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\"><label>${t('Type','प्रकार')} <span class=\\\"req\\\">*</span></label><div class=\\\"chip-grid\\\">${BTYPE.map(tp=>`<div class=\\\"chip${b.type===tp?' sel':''}\\\" onclick=\\\"setBType(${i},'${tp.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\"> ${tp}</div>`).join('')}</div></div>\u001b[39m\n\u001b[31m    <div class=\\\"dim-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Width (in)','चौड़ाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.w||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].w=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Height (in)','ऊंचाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.h||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].h=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"max-width:74px\\\"><label>${t('Qty','मात्रा')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.qty||''}\\\" placeholder=\\\"1\\\" inputmode=\\\"numeric\\\" onchange=\\\"brandings[${i}].qty=this.value;saveDraft()\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <span class=\\\"sqft\\\" id=\\\"sf${i}\\\">${calcSqft(b.w,b.h)||t('Enter W × H','W × H दर्ज करें')}</span>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-top:12px\\\"><label>${t('Photo','फोटो')} <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      ${b.prev?`<div class=\\\"pslot filled\\\" onclick=\\\"capBr(${i})\\\"><img src=\\\"${b.prev}\\\"><button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();rmBrPh(${i})\\\">×</button><span class=\\\"pbadge\\\">${b.blob?fmtSz(b.blob.size):'Existing'}</span></div>`:`<div><div class=\\\"pslot\\\" onclick=\\\"capBr(${i})\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\">${t('Tap to capture','दबाकर कैप्चर करें')}</div></div><div style=\\\"display:flex;gap:6px;margin-top:6px\\\"><button class=\\\"atool${(b.quality||imgQuality)==='compressed'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'compressed');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">${t('Compressed','कम्प्रेस्ड')}</button><button class=\\\"atool${(b.quality||imgQuality)==='hd'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'hd');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">HD</button></div></div>`}\u001b[39m\n\u001b[31m    </div></div>`).join('');\u001b[39m\n\u001b[31m  // Only show \\\"Add Another\\\" when last item is fully complete\u001b[39m\n\u001b[31m  const addDiv=document.getElementById('br-add');\u001b[39m\n\u001b[31m  if(addDiv&&brandings.length>0){\u001b[39m\n\u001b[31m    const last=brandings[brandings.length-1];\u001b[39m\n\u001b[31m    const lastComplete=last.type&&last.w&&last.h&&last.qty&&last.prev;\u001b[39m\n\u001b[31m    addDiv.style.display=(lastComplete&&brandings.length<15)?'block':'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updSqft(i){const el=document.getElementById('sf'+i);if(el)el.textContent=calcSqft(brandings[i].w,brandings[i].h)||t('Enter W × H','W × H दर्ज करें');saveDraft();}\u001b[39m\n\u001b[31mfunction setBType(i,tp){brandings[i].type=tp;renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction addBranding(){if(brandings.length>=15){toast(t('Max 15 items','अधिकतम 15 आइटम'),'error');return;}brandings.push({type:'',w:'',h:'',qty:'1',blob:null,prev:null});renderBrandings();}\u001b[39m\n\u001b[31mfunction dupBr(i){if(brandings.length>=10){toast(t('Max 10 items','अधिकतम 10 आइटम'),'error');return;}const s=brandings[i-1];brandings.splice(i,0,{type:s.type,w:s.w,h:s.h,qty:s.qty,blob:null,prev:null});renderBrandings();toast(t('Duplicated — add photo','डुप्लीकेट — फोटो जोड़ें'),'info');}\u001b[39m\n\u001b[31mfunction rmBr(i){brandings.splice(i,1);renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction capBr(i){\u001b[39m\n\u001b[31m  const q=brandings[i]?.quality||imgQuality;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f,q==='hd'?1920:1280,q==='hd'?0.90:0.78));\u001b[39m\n\u001b[31m    brandings[i].blob=bs;brandings[i].prev=URL.createObjectURL(bs);\u001b[39m\n\u001b[31m    brandings[i].fromCamera=(e._src==='camera');\u001b[39m\n\u001b[31m    openAnnot(i);\u001b[39m\n\u001b[31m  },null,q);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmBrPh(i){brandings[i].blob=null;brandings[i].prev=null;renderBrandings();}\u001b[39m\n\u001b[31mfunction setBrQuality(i,q){brandings[i].quality=q;renderBrandings();}·\u001b[39m\n\u001b[31m// VIDEO / DOC\u001b[39m\n\u001b[31mfunction setVideo(v){F.hasVideo=v;document.getElementById('vid-yes').classList.toggle('sel',v);document.getElementById('vid-no').classList.toggle('sel',!v);document.getElementById('vid-sec').style.display=v?'block':'none';saveDraft();}\u001b[39m\n\u001b[31masync function handleVideo(e){videoBlob=e.target.files[0];if(!videoBlob)return;document.getElementById('vid-slot').innerHTML=`<div style=\\\"padding:14px;font-size:13px;color:var(--gn)\\\">✓ ${videoBlob.name} (${fmtSz(videoBlob.size)})</div>`;}\u001b[39m\n\u001b[31mfunction setBranding(v){F.hasBranding=v;document.getElementById('br-yes').classList.toggle('sel',v);document.getElementById('br-no').classList.toggle('sel',!v);document.getElementById('br-add').style.display=v?'block':'none';if(v&&brandings.length===0)addBranding();saveDraft();}\u001b[39m\n\u001b[31masync function handleDoc(e){const f=e.target.files[0];if(!f)return;submissionDoc=f.type.startsWith('image/')?await compress(f,1600,.85):f;const slot=document.getElementById('doc-slot');if(f.type.startsWith('image/')){slot.classList.add('filled');slot.innerHTML=`<img src=\\\"${URL.createObjectURL(submissionDoc)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}else{slot.innerHTML=`<div style=\\\"padding:16px;font-size:13px;color:var(--gn)\\\">✓ ${f.name} (${fmtSz(f.size)})</div>`;}buildReview();}·\u001b[39m\n\u001b[31m// CLIENT CHIPS\u001b[39m\n\u001b[31mfunction renderClientChips(){\u001b[39m\n\u001b[31m  const grid = document.getElementById('client-chips'); if (!grid) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  clientList.forEach(c => {\u001b[39m\n\u001b[31m    const sel = !_clientOtherMode && _selectedClient === c;\u001b[39m\n\u001b[31m    html += `<div class=\\\"cl-chip${sel?' sel':''}\\\" onclick=\\\"selectClientChip('${esc(c)}')\\\">${esc(c)}</div>`;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html += `<div class=\\\"cl-chip cl-chip-other${_clientOtherMode?' sel':''}\\\" onclick=\\\"selectClientOther()\\\"><span class=\\\"en-txt\\\">Other…</span><span class=\\\"hi-txt\\\">अन्य…</span></div>`;\u001b[39m\n\u001b[31m  grid.innerHTML = html;\u001b[39m\n\u001b[31m  document.getElementById('client-other-wrap').style.display = _clientOtherMode ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientChip(name){\u001b[39m\n\u001b[31m  _selectedClient = name; _clientOtherMode = false;\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').value = '';\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientOther(){\u001b[39m\n\u001b[31m  _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onClientOtherInput(){\u001b[39m\n\u001b[31m  _selectedClient = document.getElementById('f-client-other').value.trim();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction getClientName(){\u001b[39m\n\u001b[31m  if (_clientOtherMode) return (document.getElementById('f-client-other')?.value||'').trim();\u001b[39m\n\u001b[31m  return _selectedClient;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction autoSetClient(brandName){\u001b[39m\n\u001b[31m  if (!brandName) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  if (clientList.includes(brandName)){\u001b[39m\n\u001b[31m    _selectedClient = brandName; _clientOtherMode = false;\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    // Not in list — pre-fill the Other field\u001b[39m\n\u001b[31m    _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m    const inp = document.getElementById('f-client-other');\u001b[39m\n\u001b[31m    if (inp && !inp.value) inp.value = brandName;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// STEP VALIDATION\u001b[39m\n\u001b[31mfunction getSD(){if(selectedStore&&!manualMode)return{storeName:selectedStore.name,brand:selectedStore.brand||'',address:selectedStore.address||'',mobile:selectedStore.mobile||''};return{storeName:(document.getElementById('f-store')?.value||'').trim(),brand:document.getElementById('f-brand')?.value||'',address:(document.getElementById('f-addr')?.value||'').trim(),mobile:(document.getElementById('f-mobile')?.value||'').trim()};}\u001b[39m\n\u001b[31mfunction step2(){\u001b[39m\n\u001b[31m  const d=document.getElementById('f-date').value;\u001b[39m\n\u001b[31m  if(!d){toast('Select date','error');return;}\u001b[39m\n\u001b[31m  const sd=getSD();\u001b[39m\n\u001b[31m  if(!sd.storeName){toast('Select or enter store name','error');return;}\u001b[39m\n\u001b[31m  if(!sd.brand){toast('Select a brand','error');document.getElementById('brand-selector').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  if(!sd.address){toast('Enter store address','error');return;}\u001b[39m\n\u001b[31m  const clientName=getClientName();\u001b[39m\n\u001b[31m  if(!clientName){toast(t('Select a client','क्लाइंट चुनें'),'error');document.getElementById('client-chips').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  // Check missing fields filled\u001b[39m\n\u001b[31m  const missAddr=document.getElementById('sc-miss-address');\u001b[39m\n\u001b[31m  if(missAddr&&!missAddr.value.trim()){toast('Enter store address in the highlighted field','error');missAddr.focus();return;}\u001b[39m\n\u001b[31m  const missMob=document.getElementById('sc-miss-mobile');\u001b[39m\n\u001b[31m  // mobile not required — just copy if filled\u001b[39m\n\u001b[31m  if(missMob&&missMob.value.trim()&&!F.mobile)F.mobile=missMob.value.trim();\u001b[39m\n\u001b[31m  Object.assign(F,{date:d,...sd,clientName});saveDraft();\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');showView('form-photos');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction step3(){if(!frontPhotos.length){toast('Add at least 1 front view photo','error');return;}showView('form-video');}\u001b[39m\n\u001b[31mfunction step4(){if(F.hasVideo===undefined||F.hasVideo===null){toast('Select Yes or No for video','error');return;}renderBrandings();showView('form-branding');}\u001b[39m\n\u001b[31mfunction step5(){if(F.hasBranding===undefined||F.hasBranding===null){toast('Select Yes or No for branding space','error');return;}if(F.hasBranding){for(let i=0;i<brandings.length;i++){const b=brandings[i];if(!b.type){toast(`Select branding type for item ${i+1}`,'error');return;}if(!b.w||!b.h){toast(`Enter W and H dimensions for item ${i+1}`,'error');return;}if(!b.qty){toast(`Enter qty for item ${i+1}`,'error');return;}if(!b.blob&&!b.prev){toast(`Add photo for item ${i+1}`,'error');return;}}}renderAddl();buildReview();showView('form-additional');}·\u001b[39m\n\u001b[31m// REVIEW\u001b[39m\n\u001b[31mfunction buildReview(){const el=document.getElementById('rev-body');if(!el)return;const sd=getSD();const cn=getClientName();el.innerHTML=`<div><div class=\\\"rev-lbl\\\">Store</div><div class=\\\"rev-val\\\">${sd.storeName||'—'} · ${sd.brand||'—'}</div><div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">${sd.address||'—'}${sd.mobile?' · '+sd.mobile:''}</div>${gpsCoords?`<div style=\\\"font-size:11px;color:var(--gn);margin-top:3px\\\">📍 ${gpsCoords.lat}, ${gpsCoords.lng} ±${gpsCoords.acc}m</div>`:''}</div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Client</div><div class=\\\"rev-val\\\" style=\\\"color:${cn?'var(--nv)':'var(--rd)'}\\\">${cn||'⚠ Not selected — required'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Photos — Front · Inside · Additional</div><div class=\\\"rev-val\\\">${frontPhotos.length} · ${insidePhotos.length} · ${addlPhotos.length}</div><div class=\\\"rev-photos\\\">${[...frontPhotos,...insidePhotos].slice(0,6).map(p=>`<img class=\\\"rev-thumb\\\" src=\\\"${p.prev}\\\">`).join('')}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Video · Branding items</div><div class=\\\"rev-val\\\">${F.hasVideo?'Yes':'No'} · ${brandings.length} item(s)</div></div>${F.hasBranding&&brandings.length?`<div style=\\\"margin-top:8px\\\">${brandings.map((b,i)=>`<div style=\\\"font-size:12px;color:var(--g600);padding:4px 0;border-bottom:1px solid var(--g100)\\\">${i+1}. ${b.type||'No type'} — ${b.w||'?'}×${b.h||'?'}\\\" × ${b.qty||'?'} — ${calcSqft(b.w,b.h)||'?'}</div>`).join('')}</div>`:''}<div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Additional photos <span style=\\\"font-size:11px;color:var(--g400)\\\">(optional)</span></div><div class=\\\"rev-val\\\" style=\\\"color:${addlPhotos.length?'var(--gn)':'var(--g500)'}\\\">${addlPhotos.length?`✓ ${addlPhotos.length} photo(s) added`:'None added'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Mandatory document</div><div class=\\\"rev-val\\\" style=\\\"color:${(submissionDoc||_docExistingUrl)?'var(--gn)':'var(--rd)'}\\\">${(submissionDoc||_docExistingUrl)?'✓ Uploaded':'⚠ Missing — required'}</div></div>`;}·\u001b[39m\n\u001b[31m// SUBMIT\u001b[39m\n\u001b[31masync function submitRecce(){\u001b[39m\n\u001b[31m  if(!submissionDoc&&!_docExistingUrl){toast('Upload mandatory doc first','error');return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('sub-btn');btn.disabled=true;btn.textContent='Saving…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const isEdit=!!(F.editingId);\u001b[39m\n\u001b[31m    const id=isEdit?F.editingId:('RC_'+Date.now()+'_'+Math.random().toString(36).slice(2,6).toUpperCase());\u001b[39m\n\u001b[31m    const sd=getSD();\u001b[39m\n\u001b[31m    const _hub=_recceHubUser();\u001b[39m\n\u001b[31m    const entry={id,timestamp:isEdit?(await dbGet('subs',id))?.timestamp||new Date().toISOString():new Date().toISOString(),editedAt:isEdit?new Date().toISOString():undefined,status:'pending',submittedBy:_hub.empId||null,submittedByName:_hub.name||null,data:{...F,...sd,gpsCoords,frontPhotos:await Promise.all(frontPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),insidePhotos:await Promise.all(insidePhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),videoNote:F.hasVideo&&videoBlob?`Video local (${fmtSz(videoBlob.size)}) — share via WhatsApp`:null,videoCmt:document.getElementById('f-vid-cmt')?.value||'',brandings:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:calcSqft(b.w,b.h),photoB64:b.blob?await b64(b.blob):null,existingUrl:b.existingUrl||null}))),addlPhotos:await Promise.all(addlPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,desc:p.desc,existingUrl:p.existingUrl||null}))),docB64:submissionDoc?await b64(submissionDoc):null,_docExistingUrl:_docExistingUrl||null}};\u001b[39m\n\u001b[31m    entry.campaignId       = _selectedCampaignId || null;\u001b[39m\n\u001b[31m    entry.notifySupervisor = _notifySupervisor   || false;\u001b[39m\n\u001b[31m    await dbPut('subs',entry);\u001b[39m\n\u001b[31m    await dbDel('draft','current');\u001b[39m\n\u001b[31m    toast(isEdit?'Recce updated ✓':'Recce saved ✓','success');\u001b[39m\n\u001b[31m    if(navigator.onLine)syncNow();\u001b[39m\n\u001b[31m    showView('home');loadHome();checkDraft();\u001b[39m\n\u001b[31m  }catch(err){toast('Error: '+err.message,'error');}\u001b[39m\n\u001b[31m  finally{btn.disabled=false;btn.textContent='Submit Recce ✓';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// SYNC\u001b[39m\n\u001b[31masync function syncNow() {\u001b[39m\n\u001b[31m  if (!navigator.onLine) { toast('Offline — sync when back online', 'info'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('sync-btn');\u001b[39m\n\u001b[31m  const SYNC_ICON = '<svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg>Sync';\u001b[39m\n\u001b[31m  if (btn) { btn.innerHTML = '<span class=\\\"spin\\\">↻</span> Syncing'; btn.disabled = true; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const all      = await dbAll('subs');\u001b[39m\n\u001b[31m    const pend     = all.filter(s => s.status === 'pending' || s.status === 'failed');\u001b[39m\n\u001b[31m    const backfill = all.filter(s => s.status === 'synced' && !s.gasAt);\u001b[39m\n\u001b[31m    if (!pend.length && !backfill.length) { toast('All synced ✓', 'success'); return; }·\u001b[39m\n\u001b[31m    const gasUrl = (await cfg('gas-url')) || DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    function fireGas(s) {\u001b[39m\n\u001b[31m      if (!gasUrl) return;\u001b[39m\n\u001b[31m      fetch(gasUrl, { method:'POST', mode:'no-cors',\u001b[39m\n\u001b[31m        body: JSON.stringify({ action:'syncSheet', submission: s }) })\u001b[39m\n\u001b[31m        .catch(() => {});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    let ok = 0;\u001b[39m\n\u001b[31m    for (const s of pend) {\u001b[39m\n\u001b[31m      // Fire Sheet sync (no-cors fire-and-forget — writes row to Google Sheet)\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      // Primary: upload photos → auto-trigger slides → generate report → store in PostgreSQL\u001b[39m\n\u001b[31m      const { ok: pgOk, viewUrl } = await syncToPostgres(s);\u001b[39m\n\u001b[31m      if (pgOk) {\u001b[39m\n\u001b[31m        s.status = 'synced'; s.syncedAt = new Date().toISOString();\u001b[39m\n\u001b[31m        if (viewUrl) s.viewUrl = viewUrl;\u001b[39m\n\u001b[31m        await dbPut('subs', s); ok++;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        s.status = 'failed'; await dbPut('subs', s);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Backfill: entries synced to Postgres but never reached Sheet GAS\u001b[39m\n\u001b[31m    for (const s of backfill) {\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      await dbPut('subs', s);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if (backfill.length) toast(`Sent ${backfill.length} older entries to Sheet`, 'info');·\u001b[39m\n\u001b[31m    await cfg('last-sync', new Date().toISOString());\u001b[39m\n\u001b[31m    if (pend.length) toast(`Synced ${ok}/${pend.length}`, ok === pend.length ? 'success' : 'error');\u001b[39m\n\u001b[31m    loadHome();\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.innerHTML = SYNC_ICON; btn.disabled = false; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN HOME ──────────────────────────────────────────────\u001b[39m\n\u001b[31masync function loadHomeAdmin() {\u001b[39m\n\u001b[31m  // Adapt UI for admin view\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const _sh = document.querySelector('.sh'); if (_sh) _sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = 'All Submissions';\u001b[39m\n\u001b[31m  const slbls = document.querySelectorAll('.slbl');\u001b[39m\n\u001b[31m  if (slbls[0]) slbls[0].textContent = 'Showing';\u001b[39m\n\u001b[31m  if (slbls[1]) slbls[1].textContent = 'Agents';·\u001b[39m\n\u001b[31m  // Back-to-menu button for supervisors\u001b[39m\n\u001b[31m  if (_isSupervisor() && !document.getElementById('sup-back-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => { document.getElementById('sup-back-btn').remove(); renderSupLanding(); };\u001b[39m\n\u001b[31m    const content = document.querySelector('#view-home .content');\u001b[39m\n\u001b[31m    content.prepend(bb);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Show filter bar — restore if hidden by renderSupLanding, else inject fresh\u001b[39m\n\u001b[31m  const _existingFb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (_existingFb) { _existingFb.style.display = ''; }\u001b[39m\n\u001b[31m  if (!_existingFb) {\u001b[39m\n\u001b[31m    const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m    const fb = document.createElement('div');\u001b[39m\n\u001b[31m    fb.id = 'admin-filter-bar';\u001b[39m\n\u001b[31m    fb.className = 'af-bar';\u001b[39m\n\u001b[31m    fb.innerHTML =\u001b[39m\n\u001b[31m      `<div class=\\\"af-grid\\\">\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-agent\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Agents</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-brand\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Brands</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-client\\\" onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Clients</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-period\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">All Time</option>\u001b[39m\n\u001b[31m          <option value=\\\"7\\\">Last 7 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"30\\\">Last 30 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"90\\\">Last 3 months</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-group\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"date\\\">Sort: Recent</option>\u001b[39m\n\u001b[31m          <option value=\\\"agent\\\">Group: Agent</option>\u001b[39m\n\u001b[31m          <option value=\\\"brand\\\">Group: Brand</option>\u001b[39m\n\u001b[31m          <option value=\\\"client\\\">Group: Client</option>\u001b[39m\n\u001b[31m          <option value=\\\"city\\\">Group: City</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m        <input class=\\\"af-inp\\\" id=\\\"af-search\\\" type=\\\"text\\\" placeholder=\\\"🔍 Search store or city…\\\" oninput=\\\"renderAdminList()\\\" style=\\\"flex:1;min-width:120px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"del-toggle-btn\\\" id=\\\"del-toggle-btn\\\" onclick=\\\"toggleDeletedView()\\\" style=\\\"flex-shrink:0\\\">📋 View Deleted</button>\u001b[39m\n\u001b[31m        ${_isSupervisor() ? `<button class=\\\"del-toggle-btn\\\" id=\\\"pending-job-btn\\\" onclick=\\\"togglePendingJobView()\\\" style=\\\"flex-shrink:0;background:#fef3c7;color:#92400e;border-color:#f59e0b\\\">⚑ Unlinked <span id=\\\"pending-job-count\\\" style=\\\"font-weight:900\\\"></span></button>` : ''}\u001b[39m\n\u001b[31m        ${_adminUnlocked ? `<button class=\\\"del-toggle-btn\\\" id=\\\"regen-rpt-btn\\\" onclick=\\\"regenAllReports()\\\" style=\\\"flex-shrink:0\\\">&#x21BB; Regen Reports</button>` : ''}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    sh.parentNode.insertBefore(fb, sh);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Fetch\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  list.innerHTML = '<div style=\\\"text-align:center;padding:40px\\\"><div class=\\\"spinner\\\"></div></div>';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?order=submitted_at.desc&limit=500`, { headers: _RC_READ });\u001b[39m\n\u001b[31m    _adminRows = resp.ok ? await resp.json() : [];\u001b[39m\n\u001b[31m    document.getElementById('stat-total').textContent = _adminRows.length;\u001b[39m\n\u001b[31m    if (resp.ok) {\u001b[39m\n\u001b[31m      const now = new Date();\u001b[39m\n\u001b[31m      document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m        'Loaded ' + now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Populate agent dropdown\u001b[39m\n\u001b[31m    const agents = [...new Set(_adminRows.map(r => r.submitted_by).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-agent').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Agents (${agents.length})</option>` +\u001b[39m\n\u001b[31m      agents.map(a => `<option value=\\\"${a}\\\">${a}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate brand dropdown\u001b[39m\n\u001b[31m    const brands = [...new Set(_adminRows.map(r => r.brand).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-brand').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Brands (${brands.length})</option>` +\u001b[39m\n\u001b[31m      brands.map(b => `<option value=\\\"${b}\\\">${b}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate client dropdown\u001b[39m\n\u001b[31m    const clients = [...new Set(_adminRows.map(r => r.client_name).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-client').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Clients (${clients.length})</option>` +\u001b[39m\n\u001b[31m      clients.map(c => `<option value=\\\"${c}\\\">${c}</option>`).join('');·\u001b[39m\n\u001b[31m    // Update pending-job count badge\u001b[39m\n\u001b[31m    const unlinkedCount = _adminRows.filter(r => !r.deleted_at && !r.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinkedCount ? `(${unlinkedCount})` : '';·\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">⚠️</div><div class=\\\"empty-txt\\\">Could not load — check connection</div></div>';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction togglePendingJobView() {\u001b[39m\n\u001b[31m  _pendingJobFilter = !_pendingJobFilter;\u001b[39m\n\u001b[31m  _showDeletedView  = false;\u001b[39m\n\u001b[31m  const btn = document.getElementById('pending-job-btn');\u001b[39m\n\u001b[31m  if (btn) btn.style.background = _pendingJobFilter ? '#f59e0b' : '#fef3c7';\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function openLinkJobModal(subId, storeName) {\u001b[39m\n\u001b[31m  _linkJobSubId = subId;\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  const storeEl = document.getElementById('link-job-store');\u001b[39m\n\u001b[31m  const sel = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  if (!modal) return;\u001b[39m\n\u001b[31m  if (storeEl) storeEl.textContent = storeName || subId;\u001b[39m\n\u001b[31m  if (errEl) errEl.textContent = '';\u001b[39m\n\u001b[31m  // Load campaigns into dropdown\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (!_campaignList.length) {\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m      _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  if (sel) {\u001b[39m\n\u001b[31m    sel.innerHTML = '<option value=\\\"\\\">— Select campaign —</option>' +\u001b[39m\n\u001b[31m      _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  modal.style.display = 'flex';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeLinkJobModal() {\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  if (modal) modal.style.display = 'none';\u001b[39m\n\u001b[31m  _linkJobSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function saveLinkJob() {\u001b[39m\n\u001b[31m  const sel    = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl  = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  const campId = sel?.value || '';\u001b[39m\n\u001b[31m  if (!campId) { if (errEl) errEl.textContent = 'Select a campaign'; return; }\u001b[39m\n\u001b[31m  if (!_linkJobSubId) return;\u001b[39m\n\u001b[31m  const btn = document.querySelector('#modal-link-job button[onclick=\\\"saveLinkJob()\\\"]');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Linking…'; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(_linkJobSubId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ campaign_id: campId }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Patch failed');\u001b[39m\n\u001b[31m    // Update local cache\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === _linkJobSubId);\u001b[39m\n\u001b[31m    if (idx >= 0) _adminRows[idx].campaign_id = campId;\u001b[39m\n\u001b[31m    // Update pending count badge\u001b[39m\n\u001b[31m    const unlinked = _adminRows.filter(x => !x.deleted_at && !x.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinked ? `(${unlinked})` : '';\u001b[39m\n\u001b[31m    closeLinkJobModal();\u001b[39m\n\u001b[31m    toast('Job linked ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    if (errEl) errEl.textContent = 'Failed to link — try again';\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.disabled = false; btn.textContent = '🔗 Link Job'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAdminList() {\u001b[39m\n\u001b[31m  const agent  = document.getElementById('af-agent')?.value  || '';\u001b[39m\n\u001b[31m  const brand  = document.getElementById('af-brand')?.value  || '';\u001b[39m\n\u001b[31m  const period = document.getElementById('af-period')?.value || '';\u001b[39m\n\u001b[31m  const search = (document.getElementById('af-search')?.value || '').toLowerCase().trim();\u001b[39m\n\u001b[31m  const group  = document.getElementById('af-group')?.value  || 'date';·\u001b[39m\n\u001b[31m  // Pending-job filter overrides deleted/normal modes\u001b[39m\n\u001b[31m  let rows;\u001b[39m\n\u001b[31m  if (_pendingJobFilter) {\u001b[39m\n\u001b[31m    rows = _adminRows.filter(r => !r.deleted_at && !r.campaign_id);\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows = _showDeletedView\u001b[39m\n\u001b[31m      ? _adminRows.filter(r => r.deleted_at)\u001b[39m\n\u001b[31m      : _adminRows.filter(r => !r.deleted_at);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const client = document.getElementById('af-client')?.value || '';\u001b[39m\n\u001b[31m  if (agent)  rows = rows.filter(r => r.submitted_by === agent);\u001b[39m\n\u001b[31m  if (brand)  rows = rows.filter(r => r.brand === brand);\u001b[39m\n\u001b[31m  if (client) rows = rows.filter(r => r.client_name === client);\u001b[39m\n\u001b[31m  if (search) rows = rows.filter(r => (r.store_name||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.city||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.client_name||'').toLowerCase().includes(search));\u001b[39m\n\u001b[31m  if (period && !_showDeletedView) {\u001b[39m\n\u001b[31m    const cut = new Date(); cut.setDate(cut.getDate() - parseInt(period));\u001b[39m\n\u001b[31m    rows = rows.filter(r => new Date(r.submitted_at) >= cut);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const uniqueAgents = new Set(rows.map(r => r.submitted_by).filter(Boolean)).size;\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = rows.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = uniqueAgents;\u001b[39m\n\u001b[31m  const deletedCount = _adminRows.filter(r => r.deleted_at).length;\u001b[39m\n\u001b[31m  const delBtn = document.getElementById('del-toggle-btn');\u001b[39m\n\u001b[31m  if (delBtn) {\u001b[39m\n\u001b[31m    if (_showDeletedView) {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 Hide Deleted (${deletedCount})` : '📋 Hide Deleted';\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 View Deleted (${deletedCount})` : '📋 View Deleted';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    delBtn.classList.toggle('active', _showDeletedView);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!rows.length) {\u001b[39m\n\u001b[31m    list.innerHTML = _showDeletedView\u001b[39m\n\u001b[31m      ? '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">✅</div><div class=\\\"empty-txt\\\">No deleted recces</div></div>'\u001b[39m\n\u001b[31m      : '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">🔍</div><div class=\\\"empty-txt\\\">No matching submissions</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (group === 'agent') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.submitted_by||'').localeCompare(b.submitted_by||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.submitted_by || 'Unknown';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">👤 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'brand') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.brand||'').localeCompare(b.brand||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.brand || 'No Brand';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🏷 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'client') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.client_name||'').localeCompare(b.client_name||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.client_name || 'No Client';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🤝 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'city') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.city||'').localeCompare(b.city||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.city || 'No City';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">📍 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows.sort((a,b) => new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    rows.forEach(r => { html += adminCard(r); });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminCard(r) {\u001b[39m\n\u001b[31m  const dt    = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds    = dt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m  const tm    = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const photos = (r.front_photos||0) + (r.inside_photos||0) + (r.addl_photos||0);\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const canDelete  = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const canArchive = _RECCE_CFG_ADMINS.includes(hub?.empId) && !r.client_archived;·\u001b[39m\n\u001b[31m  // Client status badge\u001b[39m\n\u001b[31m  const clientStatusMap = {\u001b[39m\n\u001b[31m    approved:              {t:'✓ Approved',    s:'color:#166534;background:#dcfce7;border:1px solid #86efac'},\u001b[39m\n\u001b[31m    rejected:              {t:'✕ Rejected',    s:'color:#991b1b;background:#fee2e2;border:1px solid #fca5a5'},\u001b[39m\n\u001b[31m    approved_with_changes: {t:'✎ Approved w/ Comments', s:'color:#92400e;background:#fef3c7;border:1px solid #fcd34d'},\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const csCfg = clientStatusMap[r.client_status];\u001b[39m\n\u001b[31m  const clientStatusBadge = csCfg\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;${csCfg.s}\\\">${csCfg.t}</span>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const archiveBadge = r.client_archived\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;color:#475569;background:#f1f5f9;border:1px solid #cbd5e1\\\">⬚ Client hidden</span>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  if (r.deleted_at) {\u001b[39m\n\u001b[31m    const delDt = new Date(r.deleted_at);\u001b[39m\n\u001b[31m    const delDs = delDt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m    const reasonLabel = r.deletion_reason === 'wrong' ? 'Wrong' : r.deletion_reason === 'duplicate' ? 'Duplicate' : 'Test';\u001b[39m\n\u001b[31m    return `<div class=\\\"asc deleted-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m        <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m            <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds}</span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m          <span class=\\\"del-reason-tag\\\">❌ ${reasonLabel}</span>\u001b[39m\n\u001b[31m          <div class=\\\"del-by-txt\\\">by ${r.deleted_by||'?'} · ${delDs}</div>\u001b[39m\n\u001b[31m          ${canDelete ? `<button class=\\\"restore-btn\\\" onclick=\\\"event.stopPropagation();restoreRecce('${r.sub_id}')\\\">↩ Restore</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Submitted by ${r.submitted_by||'?'}</div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const chips = [\u001b[39m\n\u001b[31m    photos > 0   ? `📷 ${photos} photo${photos!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.has_video  ? '🎥 Video' : null,\u001b[39m\n\u001b[31m    r.has_branding ? `🪧 ${r.branding_count} branding${r.branding_count!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.city       ? `📍 ${r.city}` : (r.address ? `📍 ${r.address}` : null),\u001b[39m\n\u001b[31m    r.view_url   ? '👁 View available' : null,\u001b[39m\n\u001b[31m  ].filter(Boolean);·\u001b[39m\n\u001b[31m  const delBtnHtml = canDelete\u001b[39m\n\u001b[31m    ? `<button class=\\\"del-btn\\\" onclick=\\\"event.stopPropagation();openDeleteModal('${r.sub_id}')\\\" title=\\\"Delete recce\\\">🗑</button>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const editReqHtml = r.edit_assigned_to\u001b[39m\n\u001b[31m    ? `<span class=\\\"edit-req-badge\\\">✏ Edit sent to ${r.edit_assigned_to}</span>`\u001b[39m\n\u001b[31m    : (_isSupervisor()\u001b[39m\n\u001b[31m        ? `<button class=\\\"req-edit-btn\\\" onclick=\\\"event.stopPropagation();openEditRequestModal('${r.sub_id}')\\\">✏ Request Edit</button>`\u001b[39m\n\u001b[31m        : '');·\u001b[39m\n\u001b[31m  const editRow = editReqHtml\u001b[39m\n\u001b[31m    ? `<div style=\\\"margin-top:6px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">${editReqHtml}</div>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const showPdfBtn = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m  const pdfClass = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m  const pdfLabel = '📄 PDF';\u001b[39m\n\u001b[31m  const linkJobBtn = (_pendingJobFilter && _isSupervisor() && !r.campaign_id)\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:#f59e0b;color:#000;border-color:#f59e0b;font-weight:700\\\" onclick=\\\"event.stopPropagation();openLinkJobModal('${r.sub_id}','${(r.store_name||'Unknown').replace(/'/g,'\\\\\\\\\\\\'')}')\\\">🔗 Link Job</button>`\u001b[39m\n\u001b[31m    : (r.campaign_id ? `<span style=\\\"font-size:10px;color:var(--g400);align-self:center\\\">🔗 ${r.campaign_id}</span>` : '');\u001b[39m\n\u001b[31m  const archiveBtn = canArchive\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:rgba(99,102,241,.08);border-color:var(--nv);color:var(--nv)\\\" onclick=\\\"event.stopPropagation();archiveRecce('${r.sub_id}')\\\">⛚ Archive</button>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const btnsRow = `<div class=\\\"rpt-btns\\\">\u001b[39m\n\u001b[31m    <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openAdminRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m    ${showPdfBtn ? `<button class=\\\"${pdfClass}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">${pdfLabel}</button>` : ''}\u001b[39m\n\u001b[31m    ${linkJobBtn}\u001b[39m\n\u001b[31m    ${archiveBtn}\u001b[39m\n\u001b[31m  </div>`;·\u001b[39m\n\u001b[31m  return `<div class=\\\"asc\\\">\u001b[39m\n\u001b[31m    <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m      <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m          ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          ${r.client_name&&r.client_name!==r.brand?`<span class=\\\"client-tag\\\">🤝 ${r.client_name}</span>`:''}\u001b[39m\n\u001b[31m          <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds} · ${tm}</span>\u001b[39m\n\u001b[31m          ${clientStatusBadge}\u001b[39m\n\u001b[31m          ${archiveBadge}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <span class=\\\"asc-agent\\\">👤 ${r.submitted_by||'?'}</span>\u001b[39m\n\u001b[31m        ${delBtnHtml}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    ${chips.length?`<div class=\\\"asc-chips\\\">${chips.map(c=>`<span class=\\\"asc-chip\\\">${c}</span>`).join('')}</div>`:''}\u001b[39m\n\u001b[31m    ${editRow}\u001b[39m\n\u001b[31m    ${btnsRow}\u001b[39m\n\u001b[31m  </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _ensurePdfOverlay() {\u001b[39m\n\u001b[31m  if (document.getElementById('pdf-wait-ov')) return;\u001b[39m\n\u001b[31m  const ov = document.createElement('div');\u001b[39m\n\u001b[31m  ov.id = 'pdf-wait-ov';\u001b[39m\n\u001b[31m  ov.innerHTML = '<div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Generating PDF…</div><div class=\\\"po-sub\\\" id=\\\"pw-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"pw-pfill\\\"></div></div>';\u001b[39m\n\u001b[31m  document.body.appendChild(ov);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _showPdfOverlay(msg) {\u001b[39m\n\u001b[31m  _ensurePdfOverlay();\u001b[39m\n\u001b[31m  document.getElementById('pw-sub').textContent = msg || '';\u001b[39m\n\u001b[31m  document.getElementById('pw-pfill').style.width = '0%';\u001b[39m\n\u001b[31m  document.getElementById('pdf-wait-ov').style.display = 'flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _hidePdfOverlay() {\u001b[39m\n\u001b[31m  const ov = document.getElementById('pdf-wait-ov');\u001b[39m\n\u001b[31m  if (ov) ov.style.display = 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function openPdf(subId, pdfUrl, viewUrl) {\u001b[39m\n\u001b[31m  if (pdfUrl) { window.open(pdfUrl, '_blank'); return; }\u001b[39m\n\u001b[31m  if (!viewUrl) {\u001b[39m\n\u001b[31m    toast('Report view not available yet — please try after the report is generated.', 'info');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _showPdfOverlay('Requesting PDF generation…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type': 'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({type: 'regen-pdf', subId, viewUrl})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  let attempts = 0;\u001b[39m\n\u001b[31m  const MAX = 24;\u001b[39m\n\u001b[31m  const poll = async () => {\u001b[39m\n\u001b[31m    attempts++;\u001b[39m\n\u001b[31m    const pct = Math.min(88, Math.round(attempts / MAX * 88));\u001b[39m\n\u001b[31m    document.getElementById('pw-pfill').style.width = pct + '%';\u001b[39m\n\u001b[31m    const left = Math.ceil((MAX - attempts) * 5);\u001b[39m\n\u001b[31m    document.getElementById('pw-sub').textContent = 'Checking… (' + left + 's remaining)';\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const res = await fetch('/db/submissions?sub_id=eq.' + subId + '&select=pdf_url', {\u001b[39m\n\u001b[31m        headers: {'Content-Profile': 'recce', 'Accept-Profile': 'recce'}\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      const rows = await res.json();\u001b[39m\n\u001b[31m      if (rows && rows[0] && rows[0].pdf_url) {\u001b[39m\n\u001b[31m        document.getElementById('pw-pfill').style.width = '100%';\u001b[39m\n\u001b[31m        setTimeout(() => { _hidePdfOverlay(); window.open(rows[0].pdf_url, '_blank'); }, 400);\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(_) {}\u001b[39m\n\u001b[31m    if (attempts >= MAX) { _hidePdfOverlay(); toast('PDF generation timed out. Please try again later.', 'error'); return; }\u001b[39m\n\u001b[31m    setTimeout(poll, 5000);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  setTimeout(poll, 4000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openAdminRecce(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];·\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">\u001b[39m\n\u001b[31m         📍 View on Google Maps (${Number(r.gps_lat).toFixed(4)}, ${Number(r.gps_lng).toFixed(4)})\u001b[39m\n\u001b[31m       </a>` : '';·\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} ft × ${b.h||'?'} ft · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos not yet available — field agent must re-sync from their device to upload view\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Submission Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">👤 ${r.submitted_by||'Unknown'}</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            ${meta.videoCmt?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500);font-size:12px\\\">${meta.videoCmt}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m          ${(()=>{\u001b[39m\n\u001b[31m            const hub2 = _recceHubUser();\u001b[39m\n\u001b[31m            const isHP = _RECCE_CFG_ADMINS.includes(hub2?.empId);\u001b[39m\n\u001b[31m            const csMap = {\u001b[39m\n\u001b[31m              approved:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#166534;background:#dcfce7\\\">✓ Approved</span>',\u001b[39m\n\u001b[31m              rejected:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#991b1b;background:#fee2e2\\\">✕ Rejected</span>',\u001b[39m\n\u001b[31m              approved_with_changes: '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#92400e;background:#fef3c7\\\">✎ Approved w/ Comments</span>',\u001b[39m\n\u001b[31m            };\u001b[39m\n\u001b[31m            const csBadge = csMap[r.client_status] || '';\u001b[39m\n\u001b[31m            const approvedAt = r.client_approved_at\u001b[39m\n\u001b[31m              ? new Date(r.client_approved_at).toLocaleString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit',timeZone:'Asia/Kolkata'})\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const pdfLink = r.client_approval_pdf_url\u001b[39m\n\u001b[31m              ? `<a href=\\\"${r.client_approval_pdf_url}\\\" target=\\\"_blank\\\" style=\\\"font-size:12px;color:var(--or);text-decoration:none\\\">⬇ Approval PDF</a>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const archAct = isHP && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveRecce('${r.sub_id}')\\\" style=\\\"font-size:12px;color:var(--nv);background:none;border:1px solid var(--nv);border-radius:6px;padding:4px 10px;cursor:pointer\\\">⦽ Archive from client</button>`\u001b[39m\n\u001b[31m              : (r.client_archived ? '<span style=\\\"font-size:11px;color:var(--g400)\\\">⦽ Hidden from client</span>' : '');\u001b[39m\n\u001b[31m            const campAct = isHP && r.campaign_id && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveAllForCampaign('${r.campaign_id}')\\\" style=\\\"font-size:11px;color:#991b1b;background:none;border:1px solid #fca5a5;border-radius:6px;padding:3px 8px;cursor:pointer\\\">Archive ALL for ${r.campaign_id}</button>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            if (!csBadge && !pdfLink && !archAct) return '';\u001b[39m\n\u001b[31m            return `<div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m              <div class=\\\"ardl-lbl\\\">Client Approval</div>\u001b[39m\n\u001b[31m              ${csBadge ? `<div style=\\\"margin-bottom:5px\\\">${csBadge}${approvedAt ? ' <span style=\\\"font-size:11px;color:var(--g400)\\\">' + approvedAt + '</span>' : ''}</div>` : ''}\u001b[39m\n\u001b[31m              ${r.client_comment ? `<div style=\\\"font-size:12px;color:var(--g600);background:var(--g50);border-radius:6px;padding:7px 10px;margin-bottom:5px\\\">\\\"${r.client_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m              ${pdfLink ? `<div style=\\\"margin-bottom:4px\\\">${pdfLink}</div>` : ''}\u001b[39m\n\u001b[31m              ${archAct ? `<div style=\\\"margin-bottom:4px\\\">${archAct}</div>` : ''}\u001b[39m\n\u001b[31m              ${campAct ? `<div>${campAct}</div>` : ''}\u001b[39m\n\u001b[31m            </div>`;\u001b[39m\n\u001b[31m          })()}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeAdminDetail() {\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveRecce(subId) {\u001b[39m\n\u001b[31m  if (!confirm('Archive this recce from client view? The client will no longer see it.')) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(subId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) Object.assign(_adminRows[idx], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    toast('Archived from client view ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveAllForCampaign(campaignId) {\u001b[39m\n\u001b[31m  if (!confirm(`Archive ALL recces for campaign \\\"${campaignId}\\\" from client view?\\\\nClients will no longer see any recce from this campaign.`)) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?campaign_id=eq.${encodeURIComponent(campaignId)}&client_archived=eq.false`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    _adminRows.forEach((row, i) => {\u001b[39m\n\u001b[31m      if (row.campaign_id === campaignId) Object.assign(_adminRows[i], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    toast(`All recces for ${campaignId} archived ✓`, 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function regenAllReports() {\u001b[39m\n\u001b[31m  if (!_adminUnlocked) { toast('Admin access required', 'error'); return; }\u001b[39m\n\u001b[31m  const rows = _adminRows.filter(r => !r.deleted_at && r.photo_urls);\u001b[39m\n\u001b[31m  if (!rows.length) { toast('No synced rows with photos found', 'error'); return; }·\u001b[39m\n\u001b[31m  const btn = document.getElementById('regen-rpt-btn');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Regenerating…'; }\u001b[39m\n\u001b[31m  toast(`Regenerating ${rows.length} reports…`, 'info');·\u001b[39m\n\u001b[31m  let done = 0, failed = 0;\u001b[39m\n\u001b[31m  for (const r of rows) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const photoUrls = typeof r.photo_urls === 'string' ? JSON.parse(r.photo_urls) : (r.photo_urls || {});\u001b[39m\n\u001b[31m      let meta = {};\u001b[39m\n\u001b[31m      try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m      const entry = {\u001b[39m\n\u001b[31m        id: r.sub_id,\u001b[39m\n\u001b[31m        timestamp: r.submitted_at,\u001b[39m\n\u001b[31m        submittedBy: r.submitted_by,\u001b[39m\n\u001b[31m        data: {\u001b[39m\n\u001b[31m          storeName:    r.store_name,\u001b[39m\n\u001b[31m          brand:        r.brand,\u001b[39m\n\u001b[31m          clientName:   r.client_name,\u001b[39m\n\u001b[31m          date:         r.visit_date,\u001b[39m\n\u001b[31m          address:      r.address,\u001b[39m\n\u001b[31m          city:         r.city,\u001b[39m\n\u001b[31m          mobile:       r.mobile,\u001b[39m\n\u001b[31m          gpsCoords:    (r.gps_lat && r.gps_lng) ? { lat: r.gps_lat, lng: r.gps_lng } : null,\u001b[39m\n\u001b[31m          hasVideo:     r.has_video,\u001b[39m\n\u001b[31m          videoNote:    meta.videoNote || '',\u001b[39m\n\u001b[31m          videoCmt:     meta.videoCmt  || '',\u001b[39m\n\u001b[31m          frontPhotos:  (photoUrls.front   || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          insidePhotos: (photoUrls.inside  || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          addlPhotos:   (photoUrls.addl    || []).map(() => ({ desc: '' })),\u001b[39m\n\u001b[31m          brandings:    (meta.brandings    || []),\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      };·\u001b[39m\n\u001b[31m      const html = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m      const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m        method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m        body: JSON.stringify({ type: 'save-view', subId: r.sub_id, html })\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!vResp.ok) { failed++; continue; }\u001b[39m\n\u001b[31m      const vr = await vResp.json();\u001b[39m\n\u001b[31m      if (!vr.success) { failed++; continue; }·\u001b[39m\n\u001b[31m      if (vr.url && vr.url !== r.view_url) {\u001b[39m\n\u001b[31m        await fetch(`${_RC_BASE}/submissions?sub_id=eq.${r.sub_id}`, {\u001b[39m\n\u001b[31m          method: 'PATCH', headers: _RC_WRITE,\u001b[39m\n\u001b[31m          body: JSON.stringify({ view_url: vr.url })\u001b[39m\n\u001b[31m        });\u001b[39m\n\u001b[31m        const idx = _adminRows.findIndex(x => x.sub_id === r.sub_id);\u001b[39m\n\u001b[31m        if (idx >= 0) _adminRows[idx].view_url = vr.url;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      done++;\u001b[39m\n\u001b[31m    } catch(e) { failed++; }\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = false; btn.textContent = '↻ Regen Reports'; }\u001b[39m\n\u001b[31m  toast(`Done: ${done} regenerated${failed ? `, ${failed} failed` : ''}`, done > 0 ? 'success' : 'error');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction toggleDeletedView() {\u001b[39m\n\u001b[31m  _showDeletedView = !_showDeletedView;\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openDeleteModal(subId) {\u001b[39m\n\u001b[31m  _pendingDeleteId = subId;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  const sub = document.getElementById('del-modal-sub');\u001b[39m\n\u001b[31m  if (sub) sub.textContent = r ? `Delete: \\\"${r.store_name||'Unknown'}\\\"` : 'Select reason for deletion:';\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectDeleteReason(reason) {\u001b[39m\n\u001b[31m  _pendingDeleteReason = reason;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  document.getElementById('reason-' + reason)?.classList.add('sel');\u001b[39m\n\u001b[31m  document.getElementById('del-confirm-btn').classList.remove('no-reason');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeDeleteModal() {\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingDeleteId = null;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  clearTimeout(_tt);\u001b[39m\n\u001b[31m  document.getElementById('toast').classList.remove('show');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function restoreRecce(subId) {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({ deleted_at: null, deleted_by: null, deletion_reason: null }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Restore failed: ' + r.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_at = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_by = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deletion_reason = null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    toast('Recce restored ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Restore failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmDelete() {\u001b[39m\n\u001b[31m  if (!_pendingDeleteReason) {\u001b[39m\n\u001b[31m    const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m    btn.style.animation = 'none';\u001b[39m\n\u001b[31m    btn.offsetHeight; // reflow\u001b[39m\n\u001b[31m    btn.style.animation = 'shake .35s ease';\u001b[39m\n\u001b[31m    toast('Select a reason first', 'error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if (!_pendingDeleteId) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Deleting…';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      // Hard delete — no audit trail\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'DELETE',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Delete failed: ' + r.status);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Soft delete — stamp deleted_at, deleted_by, deletion_reason\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'PATCH',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m        body: JSON.stringify({\u001b[39m\n\u001b[31m          deleted_at: new Date().toISOString(),\u001b[39m\n\u001b[31m          deleted_by: hub.empId,\u001b[39m\n\u001b[31m          deletion_reason: _pendingDeleteReason,\u001b[39m\n\u001b[31m        }),\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Update failed: ' + r.status);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Remove or update in local cache\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      _adminRows = _adminRows.filter(x => x.sub_id !== _pendingDeleteId);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      const idx = _adminRows.findIndex(x => x.sub_id === _pendingDeleteId);\u001b[39m\n\u001b[31m      if (idx >= 0) {\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_at = new Date().toISOString();\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_by = hub.empId;\u001b[39m\n\u001b[31m        _adminRows[idx].deletion_reason = _pendingDeleteReason;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeDeleteModal();\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast('Recce deleted', 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Delete failed', 'error');\u001b[39m\n\u001b[31m    btn.classList.remove('no-reason');\u001b[39m\n\u001b[31m    btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openMyServerRecce(subId) {\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  // No view yet — show metadata modal (same layout as admin detail)\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta==='string' ? JSON.parse(r.meta) : (r.meta||{}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">📍 View on Google Maps</a>` : '';\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} × ${b.h||'?'} in · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos will appear after next sync from original device\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Visit Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupLanding() {\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = 'none';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = 'none';\u001b[39m\n\u001b[31m  // Clean up admin + create-mode UI\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('sup-back-btn')?.remove();\u001b[39m\n\u001b[31m  document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m  _supCreateMode = false;\u001b[39m\n\u001b[31m  // Resume-wrap may have been hidden by loadHomeAdmin() — restore it so draft banner shows\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = '';\u001b[39m\n\u001b[31m  document.getElementById('sub-list').innerHTML = `\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorViewAll()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0f9ff\\\">📋</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">View All Recces</span><span class=\\\"hi-txt\\\">सभी रेकी देखें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">Browse & review submissions from all agents</span><span class=\\\"hi-txt\\\">सभी एजेंट की सबमिशन देखें</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorCreateView()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0fdf4\\\">✍️</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">Create Recce</span><span class=\\\"hi-txt\\\">नई रेकी बनाएं</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">My submissions + New Recce button</span><span class=\\\"hi-txt\\\">मेरी सबमिशन + नई रेकी</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorViewAll() {\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  await loadHomeAdmin();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorCreateView() {\u001b[39m\n\u001b[31m  _supCreateMode = true;\u001b[39m\n\u001b[31m  // Restore field-agent UI\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh'); if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = t('My Submissions','मेरी सबमिशन');\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar'); if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  // Add Back to Menu button (once)\u001b[39m\n\u001b[31m  if (!document.getElementById('sup-back-create-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-create-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => {\u001b[39m\n\u001b[31m      _supCreateMode = false;\u001b[39m\n\u001b[31m      document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m      renderSupLanding();\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    document.querySelector('#view-home .content').prepend(bb);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  await loadHome();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadHome() {\u001b[39m\n\u001b[31m  if (_isSupervisor() && !_supCreateMode) { renderSupLanding(); return; }\u001b[39m\n\u001b[31m  if (_adminUnlocked && !_supCreateMode) { await loadHomeAdmin(); return; }·\u001b[39m\n\u001b[31m  const all  = await dbAll('subs');\u001b[39m\n\u001b[31m  const sy   = all.filter(s => s.status === 'synced').length;\u001b[39m\n\u001b[31m  const pe   = all.filter(s => s.status !== 'synced').length;·\u001b[39m\n\u001b[31m  // Fetch this agent's submissions from server — works on any device\u001b[39m\n\u001b[31m  let serverOnly = [];\u001b[39m\n\u001b[31m  let editAssigned = [];\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (navigator.onLine && hub?.empId) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?submitted_by=eq.${encodeURIComponent(hub.empId)}&order=submitted_at.desc&limit=200`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp.ok) {\u001b[39m\n\u001b[31m        const rows = await resp.json();\u001b[39m\n\u001b[31m        const localIds = new Set(all.map(s => s.id));\u001b[39m\n\u001b[31m        serverOnly = rows.filter(r => !localIds.has(r.sub_id));\u001b[39m\n\u001b[31m        _myServerRows = serverOnly;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m    // Fetch edit-assigned recces (supervisor assigned this creator to edit)\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp2 = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?edit_assigned_to=eq.${encodeURIComponent(hub.empId)}&deleted_at=is.null&order=submitted_at.desc`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp2.ok) editAssigned = await resp2.json();\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = sy + serverOnly.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = pe;\u001b[39m\n\u001b[31m  document.getElementById('stat-total').textContent   = all.length + serverOnly.length;·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!all.length && !serverOnly.length && !editAssigned.length) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">📋</div><div class=\\\"empty-txt\\\">No submissions yet</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const icos   = { synced:'✅', pending:'⏳', failed:'❌' };\u001b[39m\n\u001b[31m  const sorted = [...all].sort((a,b) => new Date(b.timestamp) - new Date(a.timestamp)).slice(0, 50);·\u001b[39m\n\u001b[31m  const localCards = sorted.map(s => {\u001b[39m\n\u001b[31m    const dt = new Date(s.timestamp);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const viewBtn = s.viewUrl\u001b[39m\n\u001b[31m      ? `<button class=\\\"edit-btn-sm\\\" onclick=\\\"window.open('${s.viewUrl}','_blank')\\\">👁 View</button>`\u001b[39m\n\u001b[31m      : `<button class=\\\"edit-btn-sm\\\" onclick=\\\"viewRecce('${s.id}')\\\">👁 View</button>`;\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico ${s.status}\\\">${icos[s.status]||'📋'}</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${s.data.storeName||'Unknown'} · ${s.data.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${s.data.address||''}</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge ${s.status}\\\">${s.status}</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          ${viewBtn}\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"editRecce('${s.id}')\\\" style=\\\"background:#fff7ed;border-color:var(--or);color:var(--or)\\\">✏ Edit</button>\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"makeSlides('${s.id}')\\\" style=\\\"background:#eff6ff;border-color:#3b82f6;color:#1d4ed8\\\">📊 Slides</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const serverCards = serverOnly.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const showPdf = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m    const pdfCls = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico synced\\\">✅</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\" style=\\\"min-width:0;flex:1\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"rpt-btns\\\" style=\\\"margin-top:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openMyServerRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m          ${showPdf ? `<button class=\\\"${pdfCls}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">📄 PDF</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge synced\\\">synced</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const editAssignedCards = editAssigned.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    return `<div class=\\\"edit-req-card\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:26px;flex-shrink:0\\\">✏</div>\u001b[39m\n\u001b[31m      <div class=\\\"edit-req-card-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-meta\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        ${r.edit_comment ? `<div class=\\\"edit-req-cmt\\\">\\\"${r.edit_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:10px;display:flex;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"startCreatorEdit('${r.sub_id}')\\\" style=\\\"padding:9px 16px;font-size:13px;font-weight:600\\\">✏ Edit this Recce</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (editAssignedCards.length) {\u001b[39m\n\u001b[31m    html += `<div class=\\\"edit-req-section-hdr\\\">✏ Edit Requested (${editAssignedCards.length})</div>`;\u001b[39m\n\u001b[31m    html += editAssignedCards.join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  html += localCards.join('') + serverCards.join('');\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m  const ls = await cfg('last-sync');\u001b[39m\n\u001b[31m  if (ls) {\u001b[39m\n\u001b[31m    const d = new Date(ls);\u001b[39m\n\u001b[31m    document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m      'Synced ' + d.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// RESET\u001b[39m\n\u001b[31mfunction startNewRecce(){F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  if(geoStampEnabled)autoRequestGPS();\u001b[39m\n\u001b[31m['f-date','f-brand','f-store','f-addr','f-mobile','f-client-other'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';});\u001b[39m\n\u001b[31m_selectedClient='';_clientOtherMode=false;\u001b[39m\n\u001b[31m_selectedCampaignId=null;_notifySupervisor=false;_brandingLocked=false;\u001b[39m\n\u001b[31mconst _camSel=document.getElementById('f-campaign-id');if(_camSel)_camSel.value='';\u001b[39m\n\u001b[31mconst _camNotice=document.getElementById('campaign-notify-msg');if(_camNotice)_camNotice.style.display='none';\u001b[39m\n\u001b[31mloadCampaignsForForm();\u001b[39m\n\u001b[31mrenderClientChips();\u001b[39m\n\u001b[31mdocument.getElementById('f-date').value=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31m// Block future dates\u001b[39m\n\u001b[31mdocument.getElementById('f-date').max=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31mdocument.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('pick-trigger-wrap').style.display=stores.length?'block':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').style.display=stores.length?'flex':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31mdocument.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31mdocument.getElementById('manual-fields').style.display=stores.length?'none':'block';\u001b[39m\n\u001b[31mdocument.getElementById('gps-status').textContent='';\u001b[39m\n\u001b[31m['vid-yes','vid-no','br-yes','br-no'].forEach(id=>document.getElementById(id).classList.remove('sel'));\u001b[39m\n\u001b[31mdocument.getElementById('vid-sec').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('vid-slot').innerHTML=`<div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('br-add').style.display='none';document.getElementById('br-items').innerHTML='';\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').classList.remove('filled');\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').innerHTML=`<div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('brand-selector').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('sc-missing').style.display='none';\u001b[39m\n\u001b[31mpopulateBrandDropdown();\u001b[39m\n\u001b[31mrenderPhotos('front');renderPhotos('inside');renderAddl();updAvailTag();showView('form-store');}\u001b[39m\n\u001b[31mfunction exitForm(){\u001b[39m\n\u001b[31m  // Show safe exit dialog instead of confirm\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitSaveAndLeave(){\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m  checkDraft();\u001b[39m\n\u001b[31m  toast('Draft saved — tap Resume to continue','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitDiscard(){\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];\u001b[39m\n\u001b[31m  videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  dbDel('draft','current');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitCancel(){document.getElementById('exit-dialog').classList.remove('open');}\u001b[39m\n\u001b[31mfunction showView(n){document.querySelectorAll('.view').forEach(v=>v.classList.remove('active'));const t=document.getElementById('view-'+n);if(t){t.classList.add('active');window.scrollTo(0,0);}}\u001b[39m\n\u001b[31mlet _tt;\u001b[39m\n\u001b[31mfunction toast(msg,type='info'){const el=document.getElementById('toast');el.textContent=msg;el.className='toast show '+type;clearTimeout(_tt);_tt=setTimeout(()=>el.classList.remove('show'),3000);}\u001b[39m\n\u001b[31mfunction netStatus(){const on=navigator.onLine;const dot=document.getElementById('net-dot');const txt=document.getElementById('net-txt');if(dot)dot.className='sdot '+(on?'on':'off');if(txt)txt.textContent=on?t('Online','ऑनलाइन'):t('Offline — saves locally','ऑफलाइन — स्थानीय रूप से सेव');}\u001b[39m\n\u001b[31masync function loadSettings(){\u001b[39m\n\u001b[31m  // Gas URL: pre-load default if none saved, update preview\u001b[39m\n\u001b[31m  const gu=await cfg('gas-url');\u001b[39m\n\u001b[31m  if(!gu)await cfg('gas-url',DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m  // Admin cfg url\u001b[39m\n\u001b[31m  const acu=await cfg('admin-cfg-url');if(acu&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=acu;\u001b[39m\n\u001b[31m  const su=await cfg('srv-url')||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su)document.getElementById('srv-url').value=su;\u001b[39m\n\u001b[31m  const sc=await cfg('stores');\u001b[39m\n\u001b[31m  if(sc){\u001b[39m\n\u001b[31m    stores=JSON.parse(sc);\u001b[39m\n\u001b[31m    const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m    document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m      `✓ ${stores.length} stores in cache${noBrand?` · ${noBrand} without brand`:''}`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const sf=await cfg('store-files');if(sf){_storeFiles=JSON.parse(sf);renderStoreFileList();}\u001b[39m\n\u001b[31m  const iq=await cfg('img-quality');imgQuality=iq||'compressed';applyQualityUI(imgQuality);\u001b[39m\n\u001b[31m  const gs=await cfg('geo-stamp');geoStampEnabled=(gs===null||gs==='1');applyGeoStampUI();\u001b[39m\n\u001b[31m  const bl=await cfg('brands');if(bl)brands=JSON.parse(bl);\u001b[39m\n\u001b[31m  loadBrandsFromDb();  // async — updates brands + logos from DB in background\u001b[39m\n\u001b[31m  renderBrandManageList();\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m  // Show store upload row + brand add row to supervisors only\u001b[39m\n\u001b[31m  const sur = document.getElementById('store-upload-row');\u001b[39m\n\u001b[31m  if (sur) sur.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const bar = document.getElementById('brand-add-row');\u001b[39m\n\u001b[31m  if (bar) bar.style.display = _isSupervisor() ? 'flex' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction populateBrandDropdown(){\u001b[39m\n\u001b[31m  const sel=document.getElementById('f-brand');if(!sel)return;\u001b[39m\n\u001b[31m  const cur=sel.value;\u001b[39m\n\u001b[31m  sel.innerHTML='<option value=\\\"\\\">Select brand</option>'+brands.map(b=>`<option${cur===b?' selected':''}>${b}</option>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderBrandManageList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('brand-manage-list');if(!el)return;\u001b[39m\n\u001b[31m  const isSup=_isSupervisor();\u001b[39m\n\u001b[31m  el.innerHTML=brands.map((b,i)=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    const logoHtml=logo?`<img src=\\\"${logo}\\\" style=\\\"height:20px;max-width:48px;object-fit:contain;flex-shrink:0;border-radius:3px\\\">`:'';\u001b[39m\n\u001b[31m    const ctrlHtml=isSup?`<div style=\\\"display:flex;gap:2px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"openEditBrandDialog(${i})\\\" style=\\\"background:none;border:none;color:var(--nv);font-size:15px;cursor:pointer;padding:2px 6px\\\" title=\\\"Edit\\\">✏</button>\u001b[39m\n\u001b[31m      ${brands.length>1?`<button onclick=\\\"confirmRemoveBrand(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:2px 4px\\\">×</button>`:'<span style=\\\"font-size:11px;color:var(--g400);padding:0 6px\\\">Last</span>'}\u001b[39m\n\u001b[31m    </div>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;min-width:0\\\">${logoHtml}<span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${b}</span></div>\u001b[39m\n\u001b[31m      ${ctrlHtml}\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function addBrandToList(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const inp=document.getElementById('brand-add-inp');\u001b[39m\n\u001b[31m  const val=(inp.value.trim()||'').toUpperCase();\u001b[39m\n\u001b[31m  if(!val){toast('Enter a brand name','error');return;}\u001b[39m\n\u001b[31m  if(brands.some(b=>b.toLowerCase()===val.toLowerCase())){toast(`${val} already in list`,'error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands`,{method:'POST',headers:{..._RC_WRITE,'Prefer':'return=minimal'},body:JSON.stringify({name:val,sort_order:99})});\u001b[39m\n\u001b[31m    if(resp.status===409){toast(`${val} already exists in DB`,'error');return;}\u001b[39m\n\u001b[31m    if(!resp.ok){const e=await resp.json().catch(()=>({}));throw new Error(e.message||resp.status);}\u001b[39m\n\u001b[31m    inp.value='';\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${val} added ✓`,'success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Add failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmRemoveBrand(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const name=brands[idx];\u001b[39m\n\u001b[31m  if(brands.length<=1){toast('Need at least one brand','error');return;}\u001b[39m\n\u001b[31m  let count=0;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(name)}&select=sub_id`,{headers:_RC_READ});\u001b[39m\n\u001b[31m    if(r.ok){const rows=await r.json();count=rows.length;}\u001b[39m\n\u001b[31m  }catch(_){}\u001b[39m\n\u001b[31m  const msg=count>0?`Delete \\\"${name}\\\" from brand list?\\\\n(${count} submission${count!==1?'s':''} reference this brand — they keep the name as text.)`:`Delete \\\"${name}\\\" from brand list?`;\u001b[39m\n\u001b[31m  if(!confirm(msg))return;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(name)}`,{method:'DELETE',headers:{'Content-Profile':'recce','Accept-Profile':'recce'}});\u001b[39m\n\u001b[31m    if(!resp.ok&&resp.status!==204){throw new Error(resp.status);}\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${name} removed ✓`,'info');\u001b[39m\n\u001b[31m  }catch(e){toast(`Remove failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadBrandsFromDb(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch('/db/brands?select=name,logo_url&order=sort_order',{\u001b[39m\n\u001b[31m      headers:{'Content-Profile':'recce','Accept-Profile':'recce'}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(!r.ok) return;\u001b[39m\n\u001b[31m    const rows=await r.json();\u001b[39m\n\u001b[31m    if(!rows||!rows.length) return;\u001b[39m\n\u001b[31m    const dbNames=rows.map(r=>r.name);\u001b[39m\n\u001b[31m    const logos={};rows.forEach(r=>{if(r.logo_url)logos[r.name]=r.logo_url;});\u001b[39m\n\u001b[31m    // Merge: DB brands canonical, keep locally-added extras\u001b[39m\n\u001b[31m    const extras=brands.filter(b=>!dbNames.some(n=>n.toLowerCase()===b.toLowerCase()));\u001b[39m\n\u001b[31m    brands=[...dbNames,...extras];\u001b[39m\n\u001b[31m    _brandLogos=logos;\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    // Refresh brand chips if brand-selector is visible\u001b[39m\n\u001b[31m    const bSel=document.getElementById('brand-selector');\u001b[39m\n\u001b[31m    if(bSel&&bSel.style.display!=='none') renderBrandChips();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[brands-db]',e.message);}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction renderBrandChips(){\u001b[39m\n\u001b[31m  const bChips=document.getElementById('brand-chips');if(!bChips)return;\u001b[39m\n\u001b[31m  bChips.innerHTML=brands.map(b=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    return `<div class=\\\"chip brand-chip${F.brand===b?' sel':''}\\\" onclick=\\\"selectStoreBrand('${b.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\">` +\u001b[39m\n\u001b[31m      (logo?`<img src=\\\"${logo}\\\" class=\\\"brand-chip-logo\\\" alt=\\\"\\\">`:'') +\u001b[39m\n\u001b[31m      `<span>${b}</span></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _editBrandIdx=null,_editBrandOld=null;\u001b[39m\n\u001b[31mfunction openEditBrandDialog(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor())return;\u001b[39m\n\u001b[31m  _editBrandIdx=idx;_editBrandOld=brands[idx];\u001b[39m\n\u001b[31m  document.getElementById('be-name').value=brands[idx];\u001b[39m\n\u001b[31m  const logo=_brandLogos[brands[idx]]||'';\u001b[39m\n\u001b[31m  document.getElementById('be-logo').value=logo;\u001b[39m\n\u001b[31m  document.getElementById('be-logo-preview').innerHTML=logo?`<img src=\\\"${logo}\\\" style=\\\"height:28px;object-fit:contain\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Current logo</span>`:'';\u001b[39m\n\u001b[31m  document.getElementById('be-cascade-info').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('brand-edit-modal').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeBrandEditModal(){document.getElementById('brand-edit-modal').classList.remove('open');_editBrandIdx=null;_editBrandOld=null;}\u001b[39m\n\u001b[31mfunction previewBrandLogo(){\u001b[39m\n\u001b[31m  const url=(document.getElementById('be-logo')?.value||'').trim();\u001b[39m\n\u001b[31m  const prev=document.getElementById('be-logo-preview');\u001b[39m\n\u001b[31m  if(prev)prev.innerHTML=url?`<img src=\\\"${url}\\\" style=\\\"height:28px;object-fit:contain\\\" onerror=\\\"this.style.display='none'\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Preview</span>`:'';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveBrandEdit(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const oldName=_editBrandOld;\u001b[39m\n\u001b[31m  const newName=(document.getElementById('be-name').value||'').trim().toUpperCase();\u001b[39m\n\u001b[31m  const newLogo=(document.getElementById('be-logo').value||'').trim();\u001b[39m\n\u001b[31m  if(!newName){toast('Brand name required','error');return;}\u001b[39m\n\u001b[31m  const isRename=newName!==oldName;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // 1. Update recce.brands\u001b[39m\n\u001b[31m    const pResp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m      method:'PATCH',headers:{..._RC_WRITE,'Prefer':'return=minimal'},\u001b[39m\n\u001b[31m      body:JSON.stringify({name:newName,logo_url:newLogo||null})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(pResp.status===409){toast(`\\\"${newName}\\\" already exists`,'error');return;}\u001b[39m\n\u001b[31m    if(!pResp.ok&&pResp.status!==204){const e=await pResp.json().catch(()=>({}));throw new Error(e.message||pResp.status);}\u001b[39m\n\u001b[31m    if(isRename){\u001b[39m\n\u001b[31m      const hub=_recceHubUser();\u001b[39m\n\u001b[31m      // 2. Cascade to submissions\u001b[39m\n\u001b[31m      await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m        method:'PATCH',headers:_RC_WRITE,body:JSON.stringify({brand:newName})\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      // 3. Cascade to stores.json + view HTML files + PDFs\u001b[39m\n\u001b[31m      toast('Cascading rename to reports…','info');\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        const cResp=await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},\u001b[39m\n\u001b[31m          body:JSON.stringify({type:'cascade-rename-brand',oldName,newName,empId:hub?.empId||''})});\u001b[39m\n\u001b[31m        const cRes=cResp.ok?await cResp.json():{};\u001b[39m\n\u001b[31m        const msg=`Brand renamed ✓${cRes.viewsUpdated?` · ${cRes.viewsUpdated} reports re-queued`:''}`;\u001b[39m\n\u001b[31m        closeBrandEditModal();\u001b[39m\n\u001b[31m        await loadBrandsFromDb();\u001b[39m\n\u001b[31m        toast(msg,'success');\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }catch(e){console.warn('[cascade-rename]',e.message);}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeBrandEditModal();\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast('Brand updated ✓','success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Save failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function fetchServerBrands(){\u001b[39m\n\u001b[31m  const url=document.getElementById('brands-url')?.value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    toast('Fetching brands…','info');\u001b[39m\n\u001b[31m    const r=await fetch(url);const j=await r.json();\u001b[39m\n\u001b[31m    const list=Array.isArray(j)?j:j.brands||[];\u001b[39m\n\u001b[31m    if(!list.length){toast('No brands found in response','error');return;}\u001b[39m\n\u001b[31m    brands=list.map(b=>b.toString().toUpperCase());\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    toast(`${brands.length} brands loaded from server`,'success');\u001b[39m\n\u001b[31m  }catch{toast('Failed to fetch — check URL','error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setImgQuality(q){\u001b[39m\n\u001b[31m  imgQuality=q;\u001b[39m\n\u001b[31m  cfg('img-quality',q);\u001b[39m\n\u001b[31m  applyQualityUI(q);\u001b[39m\n\u001b[31m  toast(q==='hd'?'HD Quality selected (~400–600 KB per photo)':'Full Compression selected (~150–200 KB per photo)','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction applyQualityUI(q){\u001b[39m\n\u001b[31m  ['compressed','hd'].forEach(opt=>{\u001b[39m\n\u001b[31m    const label=document.getElementById('q-opt-'+opt);\u001b[39m\n\u001b[31m    const radio=document.getElementById('q-radio-'+opt);\u001b[39m\n\u001b[31m    const dot  =document.getElementById('q-dot-'+opt);\u001b[39m\n\u001b[31m    if(!label)return;\u001b[39m\n\u001b[31m    const active=opt===q;\u001b[39m\n\u001b[31m    label.style.borderColor=active?'var(--or)':'var(--g200)';\u001b[39m\n\u001b[31m    label.style.background=active?'#fff7ed':'var(--g50)';\u001b[39m\n\u001b[31m    if(radio)radio.style.borderColor=active?'var(--or)':'var(--g300)';\u001b[39m\n\u001b[31m    if(dot)dot.style.display=active?'block':'none';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const badge=document.getElementById('q-current-badge');\u001b[39m\n\u001b[31m  if(badge){\u001b[39m\n\u001b[31m    const label=q==='hd'?'HD Quality (~400–600 KB)':'Full Compression (~150–200 KB)';\u001b[39m\n\u001b[31m    badge.innerHTML=`Active: <strong>${label}</strong>`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function clearData(){if(!confirm('Delete ALL local data?'))return;const all=await dbAll('subs');for(const s of all)await dbDel('subs',s.id);stores=[];await cfg('stores',null);toast('All cleared','success');loadHome();}\u001b[39m\n\u001b[31mif('serviceWorker' in navigator){const sw=`const C='recce-v37';self.addEventListener('install',e=>{e.waitUntil(caches.open(C).then(c=>c.add('/')));self.skipWaiting();});self.addEventListener('activate',e=>e.waitUntil(clients.claim()));self.addEventListener('fetch',e=>{if(e.request.method!=='GET')return;e.respondWith(caches.match(e.request).then(r=>{if(r)return r;return fetch(e.request).then(res=>{if(res&&res.status===200&&res.type==='basic'){const cl=res.clone();caches.open(C).then(c=>c.put(e.request,cl));}return res;}).catch(()=>caches.match('/'));}))}); `;const blob=new Blob([sw],{type:'application/javascript'});navigator.serviceWorker.register(URL.createObjectURL(blob),{scope:'/'}).catch(()=>{});}·\u001b[39m\n\u001b[31m// ── GEOLOCATION STAMP ────────────────────────────────────────\u001b[39m\n\u001b[31mfunction applyGeoStampUI(){\u001b[39m\n\u001b[31m  const tog=document.getElementById('geo-tog');\u001b[39m\n\u001b[31m  if(tog)tog.classList.toggle('on',geoStampEnabled);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function toggleGeoStamp(){\u001b[39m\n\u001b[31m  geoStampEnabled=!geoStampEnabled;\u001b[39m\n\u001b[31m  await cfg('geo-stamp',geoStampEnabled?'1':'0');\u001b[39m\n\u001b[31m  applyGeoStampUI();\u001b[39m\n\u001b[31m  toast(geoStampEnabled?'Geolocation stamp enabled':'Geolocation stamp disabled','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Auto-request GPS silently when a new recce starts\u001b[39m\n\u001b[31mfunction autoRequestGPS(){\u001b[39m\n\u001b[31m  if(!navigator.geolocation)return;\u001b[39m\n\u001b[31m  const statusEl=document.getElementById('geo-status');\u001b[39m\n\u001b[31m  if(statusEl)statusEl.textContent='Acquiring GPS…';\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(\u001b[39m\n\u001b[31m    pos=>{\u001b[39m\n\u001b[31m      gpsCoords={\u001b[39m\n\u001b[31m        lat:pos.coords.latitude.toFixed(6),\u001b[39m\n\u001b[31m        lng:pos.coords.longitude.toFixed(6),\u001b[39m\n\u001b[31m        acc:Math.round(pos.coords.accuracy)\u001b[39m\n\u001b[31m      };\u001b[39m\n\u001b[31m      const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m      const quality=acc<=15?'Excellent':acc<=50?'Good':acc<=200?'Fair':'Poor (cell tower)';\u001b[39m\n\u001b[31m      const color=acc<=15?'var(--gn)':acc<=50?'#16a34a':acc<=200?'var(--am)':'var(--rd)';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.innerHTML=`GPS: ${gpsCoords.lat}, ${gpsCoords.lng} · ±${acc}m · <span style=\\\"color:${color};font-weight:600\\\">${quality}</span>`;\u001b[39m\n\u001b[31m      // Update form GPS status too\u001b[39m\n\u001b[31m      const fs=document.getElementById('gps-status');\u001b[39m\n\u001b[31m      if(fs){fs.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${acc}m)`;fs.style.color='var(--gn)';}\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    err=>{\u001b[39m\n\u001b[31m      const msgs={1:'Location permission denied in Chrome',2:'GPS signal unavailable',3:'GPS timed out'};\u001b[39m\n\u001b[31m      const msg=msgs[err.code]||'GPS unavailable';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.textContent=msg+' — stamp will use store address';\u001b[39m\n\u001b[31m      if(err.code===1)toast('Tap the lock icon in Chrome address bar → allow Location','info');\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    {enableHighAccuracy:true,timeout:20000,maximumAge:60000}\u001b[39m\n\u001b[31m  );\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Draw stamp on a photo blob — returns new blob with stamp baked in\u001b[39m\n\u001b[31mfunction roundRectPath(ctx,x,y,w,h,r){\u001b[39m\n\u001b[31m  ctx.beginPath();ctx.moveTo(x+r,y);ctx.lineTo(x+w-r,y);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y,x+w,y+r);ctx.lineTo(x+w,y+h-r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);ctx.lineTo(x+r,y+h);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y+h,x,y+h-r);ctx.lineTo(x,y+r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y,x+r,y);ctx.closePath();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction fitText(ctx,text,maxW){\u001b[39m\n\u001b[31m  if(ctx.measureText(text).width<=maxW)return text;\u001b[39m\n\u001b[31m  while(text.length>1&&ctx.measureText(text+'…').width>maxW)text=text.slice(0,-1);\u001b[39m\n\u001b[31m  return text+'…';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction stampPhoto(blob){\u001b[39m\n\u001b[31m  if(!geoStampEnabled)return Promise.resolve(blob);\u001b[39m\n\u001b[31m  return new Promise(res=>{\u001b[39m\n\u001b[31m    const img=new Image(),url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    img.onload=()=>{\u001b[39m\n\u001b[31m      URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m      const W=img.width,H=img.height;\u001b[39m\n\u001b[31m      const c=document.createElement('canvas');c.width=W;c.height=H;\u001b[39m\n\u001b[31m      const ctx=c.getContext('2d');\u001b[39m\n\u001b[31m      ctx.drawImage(img,0,0);·\u001b[39m\n\u001b[31m      // Stamp dimensions — 18% of image height\u001b[39m\n\u001b[31m      const SH=Math.round(H*0.18);\u001b[39m\n\u001b[31m      const pad=Math.round(W*0.03);\u001b[39m\n\u001b[31m      const SY=H-SH;·\u001b[39m\n\u001b[31m      // Semi-transparent background\u001b[39m\n\u001b[31m      ctx.fillStyle='rgba(10,18,35,0.78)';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,SH);·\u001b[39m\n\u001b[31m      // Orange top accent line\u001b[39m\n\u001b[31m      ctx.fillStyle='#f97316';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,Math.max(3,Math.round(H*0.004)));·\u001b[39m\n\u001b[31m      // Font sizes scaled to image\u001b[39m\n\u001b[31m      const f1=Math.round(SH*0.26); // store name\u001b[39m\n\u001b[31m      const f2=Math.round(SH*0.22); // coords / address\u001b[39m\n\u001b[31m      const f3=Math.round(SH*0.20); // timestamp·\u001b[39m\n\u001b[31m      // Row Y centres\u001b[39m\n\u001b[31m      const r1=SY+SH*0.26;\u001b[39m\n\u001b[31m      const r2=SY+SH*0.55;\u001b[39m\n\u001b[31m      const r3=SY+SH*0.82;·\u001b[39m\n\u001b[31m      // Get stamp data\u001b[39m\n\u001b[31m      const storeName=F.storeName||selectedStore?.name||'';\u001b[39m\n\u001b[31m      const brand=F.brand||selectedStore?.brand||'';\u001b[39m\n\u001b[31m      const addr=F.address||selectedStore?.address||'';\u001b[39m\n\u001b[31m      const now=new Date();\u001b[39m\n\u001b[31m      const dateStr=now.toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m      const timeStr=now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit',hour12:true});·\u001b[39m\n\u001b[31m      // Badge (right side — GPS quality)\u001b[39m\n\u001b[31m      let badgeLabel='',badgeColor='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m        if(acc<=15){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=50){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=200){badgeLabel='~'+acc+'m';badgeColor='#d97706';}\u001b[39m\n\u001b[31m        else{badgeLabel='Cell ~'+acc+'m';badgeColor='#dc2626';}\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        badgeLabel='No GPS';badgeColor='#64748b';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      const bFontSz=Math.round(SH*0.18);\u001b[39m\n\u001b[31m      ctx.font=`bold ${bFontSz}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      const bW=Math.round(ctx.measureText(badgeLabel).width+pad);\u001b[39m\n\u001b[31m      const bH=Math.round(SH*0.32);\u001b[39m\n\u001b[31m      const bX=W-bW-pad;const bY=SY+(SH-bH)/2;\u001b[39m\n\u001b[31m      ctx.fillStyle=badgeColor+'cc';\u001b[39m\n\u001b[31m      roundRectPath(ctx,bX,bY,bW,bH,4);ctx.fill();\u001b[39m\n\u001b[31m      ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';\u001b[39m\n\u001b[31m      ctx.fillText(badgeLabel,bX+bW/2,bY+bH/2);\u001b[39m\n\u001b[31m      ctx.textAlign='left';ctx.textBaseline='alphabetic';·\u001b[39m\n\u001b[31m      const textMaxW=bX-pad*2;·\u001b[39m\n\u001b[31m      // Row 1 — store name + brand\u001b[39m\n\u001b[31m      ctx.font=`bold ${f1}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#ffffff';\u001b[39m\n\u001b[31m      const nameText=storeName+(brand?' · '+brand:'');\u001b[39m\n\u001b[31m      ctx.fillText('📍 '+fitText(ctx,nameText,textMaxW-f1*1.4),pad,r1);·\u001b[39m\n\u001b[31m      // Row 2 — GPS coords OR address\u001b[39m\n\u001b[31m      ctx.font=`${f2}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#cbd5e1';\u001b[39m\n\u001b[31m      let row2='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        row2=`Lat ${gpsCoords.lat}°   Long ${gpsCoords.lng}°`;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        row2=addr?fitText(ctx,addr,textMaxW):'GPS coordinates unavailable';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      ctx.fillText(row2,pad,r2);·\u001b[39m\n\u001b[31m      // Row 3 — date and time\u001b[39m\n\u001b[31m      ctx.font=`${f3}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#94a3b8';\u001b[39m\n\u001b[31m      ctx.fillText(`${dateStr}   ${timeStr}`,pad,r3);·\u001b[39m\n\u001b[31m      c.toBlob(b=>res(b||blob),'image/jpeg',imgQuality==='hd'?0.88:0.82);\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    img.onerror=()=>{URL.revokeObjectURL(url);res(blob);};\u001b[39m\n\u001b[31m    img.src=url;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _aTool='rect',_aColor='#f97316',_aWidth=4,_aTarget=-1;\u001b[39m\n\u001b[31mlet _aImg=null,_aHistory=[],_aDrawing=false,_aStart={},_aPts=[];\u001b[39m\n\u001b[31mlet _aSel=-1,_aDragMode=null,_aDragOff={x:0,y:0};\u001b[39m\n\u001b[31m// Larger hit radius on touch devices for easier finger selection\u001b[39m\n\u001b[31mconst HIT_R=()=>('ontouchstart' in window)?32:16;·\u001b[39m\n\u001b[31mfunction setATool(t){\u001b[39m\n\u001b[31m  _aTool=t;\u001b[39m\n\u001b[31m  ['rect','ellipse','line','arrow','free'].forEach(id=>{const el=document.getElementById('at-'+id);if(el)el.classList.toggle('on',id===t&&t!=='move');});\u001b[39m\n\u001b[31m  const mv=document.getElementById('at-move');if(mv)mv.classList.toggle('sel-on',t==='move');\u001b[39m\n\u001b[31m  const info=document.getElementById('annot-sel-info');if(info)info.style.display=t==='move'?'block':'none';\u001b[39m\n\u001b[31m  if(t!=='move'){_aSel=-1;redrawAnnot();}\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(cvs)cvs.style.cursor=t==='move'?'default':'crosshair';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAColor(c){\u001b[39m\n\u001b[31m  _aColor=c;\u001b[39m\n\u001b[31m  const m={'#f97316':'or','#ef4444':'rd','#ffffff':'wh','#facc15':'yw','#22c55e':'gn'};\u001b[39m\n\u001b[31m  Object.entries(m).forEach(([col,id])=>{const el=document.getElementById('ac-'+id);if(el)el.classList.toggle('on',col===c);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAWidth(w){_aWidth=w;[2,4,7].forEach(v=>{const el=document.getElementById('aw-'+v);if(el)el.classList.toggle('on',v===w);});}·\u001b[39m\n\u001b[31mfunction openAnnot(idx){\u001b[39m\n\u001b[31m  _aTarget=idx;_aHistory=[];_aDrawing=false;_aPts=[];_aSel=-1;_aDragMode=null;\u001b[39m\n\u001b[31m  document.getElementById('annot-modal').classList.add('open');\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');\u001b[39m\n\u001b[31m  const img=new Image(),url=URL.createObjectURL(brandings[idx].blob);\u001b[39m\n\u001b[31m  img.onload=()=>{\u001b[39m\n\u001b[31m    const sc=Math.min(1,window.innerWidth/img.width,(window.innerHeight-185)/img.height);\u001b[39m\n\u001b[31m    cvs.width=Math.round(img.width*sc);cvs.height=Math.round(img.height*sc);\u001b[39m\n\u001b[31m    _aImg=img;redrawAnnot();URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  img.src=url;\u001b[39m\n\u001b[31m  cvs.ontouchstart=aDown;cvs.ontouchmove=aMove;cvs.ontouchend=aUp;\u001b[39m\n\u001b[31m  cvs.onmousedown=aDown;cvs.onmousemove=aMove;cvs.onmouseup=aUp;\u001b[39m\n\u001b[31m  setATool('rect');setAColor('#f97316');setAWidth(4);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aPos(e){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const r=cvs.getBoundingClientRect();\u001b[39m\n\u001b[31m  const src=e.touches?e.touches[0]:e;\u001b[39m\n\u001b[31m  return{x:(src.clientX-r.left)*(cvs.width/r.width),y:(src.clientY-r.top)*(cvs.height/r.height)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Always return normalised (positive w,h) bounds\u001b[39m\n\u001b[31mfunction sBounds(s){\u001b[39m\n\u001b[31m  if(s.type==='free'){\u001b[39m\n\u001b[31m    if(!s.pts||!s.pts.length)return null;\u001b[39m\n\u001b[31m    const xs=s.pts.map(p=>p.x),ys=s.pts.map(p=>p.y);\u001b[39m\n\u001b[31m    const x=Math.min(...xs),y=Math.min(...ys);\u001b[39m\n\u001b[31m    return{x,y,w:Math.max(...xs)-x,h:Math.max(...ys)-y};\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  return{x:Math.min(s.x,s.x+s.w),y:Math.min(s.y,s.y+s.h),w:Math.abs(s.w),h:Math.abs(s.h)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction hitHandle(px,py,s){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return null;\u001b[39m\n\u001b[31m  const b=sBounds(s);const hr=HIT_R();\u001b[39m\n\u001b[31m  for(const[n,x,y]of[['tl',b.x,b.y],['tr',b.x+b.w,b.y],['bl',b.x,b.y+b.h],['br',b.x+b.w,b.y+b.h]])\u001b[39m\n\u001b[31m    if(Math.hypot(px-x,py-y)<hr)return n;\u001b[39m\n\u001b[31m  return null;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction hitShape(px,py,s){\u001b[39m\n\u001b[31m  const b=sBounds(s);if(!b)return false;\u001b[39m\n\u001b[31m  const pad=HIT_R();\u001b[39m\n\u001b[31m  return px>=b.x-pad&&px<=b.x+b.w+pad&&py>=b.y-pad&&py<=b.y+b.h+pad;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aDown(e){\u001b[39m\n\u001b[31m  e.preventDefault();const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'){\u001b[39m\n\u001b[31m    // Check handles of selected shape first\u001b[39m\n\u001b[31m    if(_aSel>=0&&_aSel<_aHistory.length){\u001b[39m\n\u001b[31m      const h=hitHandle(p.x,p.y,_aHistory[_aSel]);\u001b[39m\n\u001b[31m      if(h){_aDragMode='r-'+h;_aDragOff={x:p.x,y:p.y};_aDrawing=true;return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Hit test all shapes topmost first\u001b[39m\n\u001b[31m    for(let i=_aHistory.length-1;i>=0;i--){\u001b[39m\n\u001b[31m      if(hitShape(p.x,p.y,_aHistory[i])){\u001b[39m\n\u001b[31m        _aSel=i;_aDragMode='move';\u001b[39m\n\u001b[31m        const s=_aHistory[i];\u001b[39m\n\u001b[31m        const b=sBounds(s);\u001b[39m\n\u001b[31m        // Store offset from shape top-left corner (normalised)\u001b[39m\n\u001b[31m        _aDragOff={x:p.x-b.x,y:p.y-b.y};\u001b[39m\n\u001b[31m        _aDrawing=true;redrawAnnot();return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    _aSel=-1;redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _aDrawing=true;_aStart={x:p.x,y:p.y};if(_aTool==='free')_aPts=[{x:p.x,y:p.y}];\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aMove(e){\u001b[39m\n\u001b[31m  e.preventDefault();if(!_aDrawing)return;const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'&&_aDragMode){\u001b[39m\n\u001b[31m    const s=_aHistory[_aSel];if(!s)return;\u001b[39m\n\u001b[31m    if(_aDragMode==='move'){\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      // New top-left position\u001b[39m\n\u001b[31m      const nx=p.x-_aDragOff.x;\u001b[39m\n\u001b[31m      const ny=p.y-_aDragOff.y;\u001b[39m\n\u001b[31m      const dx=nx-b.x,dy=ny-b.y;\u001b[39m\n\u001b[31m      if(s.type==='free'){\u001b[39m\n\u001b[31m        s.pts=s.pts.map(pt=>({x:pt.x+dx,y:pt.y+dy}));\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        // Move preserving w/h sign (don't normalise — keep original drawing direction)\u001b[39m\n\u001b[31m        s.x+=dx;s.y+=dy;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Resize from corner — always work on normalised bounds then re-apply\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      const n=_aDragMode.slice(2);\u001b[39m\n\u001b[31m      let nx=b.x,ny=b.y,nw=b.w,nh=b.h;\u001b[39m\n\u001b[31m      if(n==='br'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,p.y-b.y);}\u001b[39m\n\u001b[31m      else if(n==='tl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,b.y+b.h-p.y);nx=p.x;ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='tr'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,b.y+b.h-p.y);ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='bl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,p.y-b.y);nx=p.x;}\u001b[39m\n\u001b[31m      s.x=nx;s.y=ny;s.w=nw;s.h=nh; // store as normalised going forward\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if(_aTool==='free'){_aPts.push({x:p.x,y:p.y});redrawAnnot();drawSh({type:'free',pts:[..._aPts],color:_aColor,lw:_aWidth},true);return;}\u001b[39m\n\u001b[31m  redrawAnnot();drawSh({type:_aTool,x:_aStart.x,y:_aStart.y,w:p.x-_aStart.x,h:p.y-_aStart.y,color:_aColor,lw:_aWidth},true);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction aUp(e){\u001b[39m\n\u001b[31m  if(!_aDrawing)return;_aDrawing=false;\u001b[39m\n\u001b[31m  if(_aTool==='move'){_aDragMode=null;return;}\u001b[39m\n\u001b[31m  const p=aPos(e||{touches:[{clientX:0,clientY:0}]});\u001b[39m\n\u001b[31m  if(_aTool==='free'){if(_aPts.length>2){_aHistory.push({type:'free',pts:[..._aPts],x:_aPts[0].x,y:_aPts[0].y,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  else{const w=p.x-_aStart.x,h=p.y-_aStart.y;if(Math.abs(w)>4||Math.abs(h)>4){_aHistory.push({type:_aTool,x:_aStart.x,y:_aStart.y,w,h,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  _aPts=[];redrawAnnot();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction redrawAnnot(){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.clearRect(0,0,cvs.width,cvs.height);if(_aImg)ctx.drawImage(_aImg,0,0,cvs.width,cvs.height);\u001b[39m\n\u001b[31m  _aHistory.forEach((s,i)=>{drawSh(s,false,ctx);if(_aTool==='move'&&i===_aSel)drawHandles(s,ctx);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawHandles(s,ctx){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return;const b=sBounds(s);ctx.save();\u001b[39m\n\u001b[31m  ctx.setLineDash([5,3]);ctx.strokeStyle='#facc15';ctx.lineWidth=1.5;ctx.strokeRect(b.x-2,b.y-2,b.w+4,b.h+4);ctx.setLineDash([]);\u001b[39m\n\u001b[31m  [[b.x,b.y],[b.x+b.w,b.y],[b.x,b.y+b.h],[b.x+b.w,b.y+b.h]].forEach(([x,y])=>{ctx.beginPath();ctx.arc(x,y,7,0,2*Math.PI);ctx.fillStyle='#f97316';ctx.fill();ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();});\u001b[39m\n\u001b[31m  ctx.restore();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawSh(s,preview=false,ctx){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(!ctx)ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.save();ctx.strokeStyle=s.color;ctx.lineWidth=preview?Math.max(s.lw||4,2):s.lw||4;\u001b[39m\n\u001b[31m  ctx.lineCap='round';ctx.lineJoin='round';ctx.setLineDash(preview?[6,3]:[]);\u001b[39m\n\u001b[31m  if(s.type==='rect'){ctx.strokeRect(s.x,s.y,s.w,s.h);ctx.fillStyle=s.color+'28';ctx.fillRect(s.x,s.y,s.w,s.h);}\u001b[39m\n\u001b[31m  else if(s.type==='ellipse'){const cx=s.x+s.w/2,cy=s.y+s.h/2;ctx.beginPath();ctx.ellipse(cx,cy,Math.abs(s.w/2),Math.abs(s.h/2),0,0,2*Math.PI);ctx.stroke();ctx.fillStyle=s.color+'28';ctx.fill();}\u001b[39m\n\u001b[31m  else if(s.type==='line'){ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(s.x+s.w,s.y+s.h);ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='arrow'){const ex=s.x+s.w,ey=s.y+s.h;ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(ex,ey);ctx.stroke();const a=Math.atan2(s.h,s.w),al=20,aa=0.4;ctx.setLineDash([]);ctx.beginPath();ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a-aa),ey-al*Math.sin(a-aa));ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a+aa),ey-al*Math.sin(a+aa));ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='free'){if(s.pts.length<2){ctx.restore();return;}ctx.beginPath();s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));ctx.stroke();}\u001b[39m\n\u001b[31m  ctx.setLineDash([]);ctx.restore();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction undoAnnot(){if(_aHistory.length){_aHistory.pop();_aSel=Math.min(_aSel,_aHistory.length-1);redrawAnnot();}}\u001b[39m\n\u001b[31mfunction clearAnnot(){_aHistory=[];_aSel=-1;redrawAnnot();}·\u001b[39m\n\u001b[31m// Bottom dialog\u001b[39m\n\u001b[31mlet _bdCb=null;\u001b[39m\n\u001b[31mfunction showBDialog(title,sub,onYes){\u001b[39m\n\u001b[31m  document.getElementById('bdialog-title').textContent=title;\u001b[39m\n\u001b[31m  document.getElementById('bdialog-sub').textContent=sub;\u001b[39m\n\u001b[31m  _bdCb=onYes;document.getElementById('bdialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction bdialogYes(){document.getElementById('bdialog').classList.remove('open');if(_bdCb)_bdCb();_bdCb=null;}\u001b[39m\n\u001b[31mfunction bdialogNo(){document.getElementById('bdialog').classList.remove('open');_bdCb=null;}·\u001b[39m\n\u001b[31mfunction _afterBrandingPhoto(){\u001b[39m\n\u001b[31m  const idx=_aTarget;\u001b[39m\n\u001b[31m  showBDialog(t(`Add reference photos for Branding ${idx+1}?`,`ब्रांडिंग ${idx+1} के लिए अतिरिक्त फोटो?`),t('Optional extra photos for future reference.','वैकल्पिक — भविष्य के लिए अतिरिक्त फोटो।'),()=>{showView('form-additional');setTimeout(()=>addAdditional(),200);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction skipAnnot(){document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo added (${fmtSz(brandings[_aTarget].blob.size)})`,'success');_afterBrandingPhoto();}\u001b[39m\n\u001b[31mfunction saveAnnot(){const cvs=document.getElementById('annot-cvs');cvs.toBlob(blob=>{brandings[_aTarget].blob=blob;brandings[_aTarget].prev=URL.createObjectURL(blob);document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo + markup saved (${fmtSz(blob.size)})`,'success');_afterBrandingPhoto();},'image/jpeg',0.88);}·\u001b[39m\n\u001b[31m// ── VIEW RECCE (read-only) ──────────────────────────────────\u001b[39m\n\u001b[31masync function viewRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  // Synced entries have a server-side rich report — open it directly\u001b[39m\n\u001b[31m  if(entry.viewUrl){window.open(entry.viewUrl,'_blank');return;}\u001b[39m\n\u001b[31m  // Offline / not-yet-synced fallback: generate from local base64 data\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  const ts=new Date(entry.timestamp).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'});·\u001b[39m\n\u001b[31m  async function b64ToUrl(b64){if(!b64)return'';try{const r=await fetch(b64);const bl=await r.blob();return URL.createObjectURL(bl);}catch{return'';}}·\u001b[39m\n\u001b[31m  const fvUrls=await Promise.all((d.frontPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const ivUrls=await Promise.all((d.insidePhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const brUrls=await Promise.all((d.brandings||[]).map(b=>b64ToUrl(b.photoB64)));\u001b[39m\n\u001b[31m  const adUrls=await Promise.all((d.addlPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const docUrl=await b64ToUrl(d.docB64);·\u001b[39m\n\u001b[31m  const brRows=(d.brandings||[]).map((b,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:16px;padding:12px;background:#f8fafc;border-radius:8px;border-left:3px solid #f97316\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-weight:600;font-size:14px;color:#0f172a;margin-bottom:6px\\\">${i+1}. ${b.type||'—'}: ${b.w||'?'}\\\"×${b.h||'?'}\\\" · Qty: ${b.qty||'?'} · ${b.sqft||'?'}</div>\u001b[39m\n\u001b[31m      ${brUrls[i]?`<img src=\\\"${brUrls[i]}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:6px\\\">`:'<div style=\\\"color:#94a3b8;font-size:12px\\\">No photo</div>'}\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  const html=`<!DOCTYPE html><html><head><meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m  <title>Recce — ${d.storeName||'Unknown'}</title>\u001b[39m\n\u001b[31m  <style>body{font-family:Arial,sans-serif;margin:0;padding:16px;background:#f1f5f9}\u001b[39m\n\u001b[31m  .card{background:#fff;border-radius:12px;padding:16px;margin-bottom:14px;box-shadow:0 1px 4px rgba(0,0,0,.08)}\u001b[39m\n\u001b[31m  h1{font-size:18px;color:#0f172a;margin:0 0 4px}h2{font-size:14px;color:#f97316;text-transform:uppercase;letter-spacing:.5px;margin:0 0 10px}\u001b[39m\n\u001b[31m  .meta{font-size:12px;color:#64748b;margin-bottom:12px}.photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}\u001b[39m\n\u001b[31m  img{width:100%;border-radius:8px;object-fit:cover}\u001b[39m\n\u001b[31m  .tag{display:inline-block;background:#0f172a;color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-right:4px}\u001b[39m\n\u001b[31m  @media print{body{background:#fff}.card{box-shadow:none}}</style></head><body>\u001b[39m\n\u001b[31m  <div class=\\\"card\\\">\u001b[39m\n\u001b[31m    <h1>${d.storeName||'Unknown Store'}</h1>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\"><span class=\\\"tag\\\">${d.brand||'No Brand'}</span>${d.address||''}</div>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\">📞 ${d.mobile||'—'} &nbsp;|&nbsp; 📅 ${d.date||'—'} &nbsp;|&nbsp; Submitted: ${ts}</div>\u001b[39m\n\u001b[31m    ${d.gpsCoords?`<div class=\\\"meta\\\">📍 ${d.gpsCoords.lat}, ${d.gpsCoords.lng} ±${d.gpsCoords.acc}m</div>`:''}\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${fvUrls.length?`<div class=\\\"card\\\"><h2>Front View Photos</h2><div class=\\\"photos\\\">${fvUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${ivUrls.length?`<div class=\\\"card\\\"><h2>Inside View Photos</h2><div class=\\\"photos\\\">${ivUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${d.hasVideo?`<div class=\\\"card\\\"><h2>Video</h2><div>${d.videoNote||'Video recorded'}</div></div>`:''}\u001b[39m\n\u001b[31m  ${(d.brandings||[]).length?`<div class=\\\"card\\\"><h2>Branding Items (${(d.brandings||[]).length})</h2>${brRows}</div>`:''}\u001b[39m\n\u001b[31m  ${adUrls.length?`<div class=\\\"card\\\"><h2>Additional Photos</h2><div class=\\\"photos\\\">${adUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${docUrl?`<div class=\\\"card\\\"><h2>Submission Document</h2><img src=\\\"${docUrl}\\\" style=\\\"width:100%;max-height:300px;object-fit:contain\\\"></div>`:''}\u001b[39m\n\u001b[31m  <div style=\\\"text-align:center;margin:16px 0\\\">\u001b[39m\n\u001b[31m    <button onclick=\\\"window.print()\\\" style=\\\"background:#f97316;color:#fff;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer\\\">🖨 Print / Save as PDF</button>\u001b[39m\n\u001b[31m    <button onclick=\\\"window.close()\\\" style=\\\"background:#e2e8f0;color:#475569;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer;margin-left:10px\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  </body></html>`;\u001b[39m\n\u001b[31m  const blob=new Blob([html],{type:'text/html'});\u001b[39m\n\u001b[31m  const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m  window.open(url,'_blank');\u001b[39m\n\u001b[31m  setTimeout(()=>URL.revokeObjectURL(url),30000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── EDIT OLD RECCE ───────────────────────────────────────────\u001b[39m\n\u001b[31masync function editRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=d.gpsCoords||null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  F.editingId=id;F.date=d.date||'';F.brand=d.brand||'';F.storeName=d.storeName||'';F.address=d.address||'';F.mobile=d.mobile||'';F.hasVideo=d.hasVideo;F.hasBranding=d.hasBranding;\u001b[39m\n\u001b[31m  async function b64ToBlob(b64){if(!b64)return null;try{const r=await fetch(b64);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m  toast('Loading recce data…','info');\u001b[39m\n\u001b[31m  for(const p of(d.frontPhotos||[])){const b=await b64ToBlob(p.b64);if(b)frontPhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const p of(d.insidePhotos||[])){const b=await b64ToBlob(p.b64);if(b)insidePhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const br of(d.brandings||[])){const b=await b64ToBlob(br.photoB64);brandings.push({type:br.type,w:br.w,h:br.h,qty:br.qty,blob:b,prev:b?URL.createObjectURL(b):null});}\u001b[39m\n\u001b[31m  for(const p of(d.addlPhotos||[])){const b=await b64ToBlob(p.b64);if(b)addlPhotos.push({blob:b,prev:URL.createObjectURL(b),desc:p.desc||''});}\u001b[39m\n\u001b[31m  if(d.docB64){const b=await b64ToBlob(d.docB64);if(b){submissionDoc=b;const sl=document.getElementById('doc-slot');sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${URL.createObjectURL(b)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}}\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  if(F.brand)document.getElementById('f-brand').value=F.brand;\u001b[39m\n\u001b[31m  if(F.storeName)document.getElementById('f-store').value=F.storeName;\u001b[39m\n\u001b[31m  if(F.address)document.getElementById('f-addr').value=F.address;\u001b[39m\n\u001b[31m  if(F.mobile)document.getElementById('f-mobile').value=F.mobile;\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();updAvailTag();\u001b[39m\n\u001b[31m  toast('Recce loaded — make changes and re-submit','success');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── EDIT REQUEST ────────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mlet _editReqSubId = null;·\u001b[39m\n\u001b[31mfunction _hydratePhotosFromRow(r) {\u001b[39m\n\u001b[31m  let pu={};\u001b[39m\n\u001b[31m  try{pu=typeof r.photo_urls==='string'?JSON.parse(r.photo_urls):(r.photo_urls||{});}catch(_){}\u001b[39m\n\u001b[31m  let meta={};\u001b[39m\n\u001b[31m  try{meta=typeof r.meta==='string'?JSON.parse(r.meta):(r.meta||{});}catch(_){}\u001b[39m\n\u001b[31m  frontPhotos =(pu.front   ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  insidePhotos=(pu.inside  ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  addlPhotos  =(pu.addl    ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,desc:''}));\u001b[39m\n\u001b[31m  brandings   =(meta.brandings||[]).map((b,i)=>({type:b.type,w:b.w,h:b.h,qty:b.qty,existingUrl:(pu.brandings||[])[i]||null,blob:null,prev:(pu.brandings||[])[i]||null}));\u001b[39m\n\u001b[31m  _docExistingUrl=pu.doc||null;\u001b[39m\n\u001b[31m  // Show retained doc in slot\u001b[39m\n\u001b[31m  const sl=document.getElementById('doc-slot');\u001b[39m\n\u001b[31m  if(sl&&_docExistingUrl){sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${_docExistingUrl}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openEditRequestModal(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  _editReqSubId = subId;\u001b[39m\n\u001b[31m  document.getElementById('er-store-name').textContent = r.store_name || 'Unknown';\u001b[39m\n\u001b[31m  document.getElementById('er-comment').value = '';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const assignBtn = document.getElementById('er-assign-btn');\u001b[39m\n\u001b[31m  if (r.submitted_by && r.submitted_by !== hub?.empId) {\u001b[39m\n\u001b[31m    assignBtn.textContent = `👤 Assign to ${r.submitted_by}`;\u001b[39m\n\u001b[31m    assignBtn.style.display = '';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    assignBtn.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeEditRequestModal() {\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _editReqSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorEditMyself() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  // Lock branding if client has reviewed (preserve their approval)\u001b[39m\n\u001b[31m  _brandingLocked = !!(r.client_status && r.client_status !== 'pending');\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function assignEditToCreator() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r || !r.submitted_by) { toast('No creator found for this recce', 'error'); return; }\u001b[39m\n\u001b[31m  const comment = (document.getElementById('er-comment').value || '').trim();\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        status: 'edit_requested',\u001b[39m\n\u001b[31m        edit_assigned_to: r.submitted_by,\u001b[39m\n\u001b[31m        edit_comment: comment || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!resp.ok) throw new Error('Update failed: ' + resp.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].status = 'edit_requested';\u001b[39m\n\u001b[31m      _adminRows[idx].edit_assigned_to = r.submitted_by;\u001b[39m\n\u001b[31m      _adminRows[idx].edit_comment = comment || null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Push notification to creator\u001b[39m\n\u001b[31m    const notifBody = comment || `Please review and re-submit: ${r.store_name || 'your recce'}`;\u001b[39m\n\u001b[31m    fetch('/push-server/notify', {\u001b[39m\n\u001b[31m      method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        user_id: r.submitted_by, title: '✏ Edit Requested',\u001b[39m\n\u001b[31m        body: notifBody, tag: `recce-edit-${subId}`, url: '/recce/',\u001b[39m\n\u001b[31m        icon: '/hub/icons/icon-192.png', badge: '/hub/icons/icon-192.png',\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    }).catch(() => {});\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast(`Edit assigned to ${r.submitted_by} ✓`, 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Assign failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function startCreatorEdit(subId) {\u001b[39m\n\u001b[31m  // Try local IndexedDB first (has photos)\u001b[39m\n\u001b[31m  const local = await dbGet('subs', subId);\u001b[39m\n\u001b[31m  if (local) { await editRecce(subId); return; }\u001b[39m\n\u001b[31m  // Fallback: load text fields from server row\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId)\u001b[39m\n\u001b[31m         || (await (async () => {\u001b[39m\n\u001b[31m              try {\u001b[39m\n\u001b[31m                const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, { headers: _RC_READ });\u001b[39m\n\u001b[31m                if (resp.ok) { const arr = await resp.json(); return arr[0]; }\u001b[39m\n\u001b[31m              } catch(_) {} return null;\u001b[39m\n\u001b[31m            })());\u001b[39m\n\u001b[31m  if (!r) { toast('Record not found', 'error'); return; }\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── End edit request ─────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mfunction goToHub() { window.location.href = '/hub/'; }\u001b[39m\n\u001b[31mfunction recceLogout() {\u001b[39m\n\u001b[31m  if (!confirm('Log out?')) return;\u001b[39m\n\u001b[31m  localStorage.removeItem('lm360-session');\u001b[39m\n\u001b[31m  localStorage.removeItem('360exp-session');\u001b[39m\n\u001b[31m  window.location.href = '/hub/';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction injectHubButtons() {\u001b[39m\n\u001b[31m  const u = _recceHubUser();\u001b[39m\n\u001b[31m  const name = u ? (u.name || '') : '';\u001b[39m\n\u001b[31m  if (name) {\u001b[39m\n\u001b[31m    const bar = document.getElementById('recce-hero-ubar');\u001b[39m\n\u001b[31m    const nm  = document.getElementById('recce-hero-name');\u001b[39m\n\u001b[31m    if (bar) { nm.textContent = name; bar.style.display = 'flex'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.querySelectorAll('.hdr').forEach(hdr => {\u001b[39m\n\u001b[31m    const r = document.createElement('div');\u001b[39m\n\u001b[31m    r.className = 'hdr-r';\u001b[39m\n\u001b[31m    if (name) {\u001b[39m\n\u001b[31m      const un = document.createElement('span');\u001b[39m\n\u001b[31m      un.className = 'hdr-user';\u001b[39m\n\u001b[31m      un.textContent = name;\u001b[39m\n\u001b[31m      r.appendChild(un);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    const hub = document.createElement('button');\u001b[39m\n\u001b[31m    hub.className = 'btn-hub';\u001b[39m\n\u001b[31m    hub.innerHTML = '🏡 Hub';\u001b[39m\n\u001b[31m    hub.addEventListener('click', goToHub);\u001b[39m\n\u001b[31m    r.appendChild(hub);\u001b[39m\n\u001b[31m    const lo = document.createElement('button');\u001b[39m\n\u001b[31m    lo.className = 'btn-logout';\u001b[39m\n\u001b[31m    lo.textContent = 'Logout';\u001b[39m\n\u001b[31m    lo.addEventListener('click', recceLogout);\u001b[39m\n\u001b[31m    r.appendChild(lo);\u001b[39m\n\u001b[31m    hdr.appendChild(r);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction checkAppUpdate(){\u001b[39m\n\u001b[31m  const seen=localStorage.getItem('recce-ver-seen');\u001b[39m\n\u001b[31m  localStorage.setItem('recce-ver-seen',CACHE_VER);\u001b[39m\n\u001b[31m  if(seen&&seen!==CACHE_VER){\u001b[39m\n\u001b[31m    const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m    if(b){b.classList.add('show');setTimeout(()=>b.classList.remove('show'),5000);}\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction dismissUpdateBanner(){\u001b[39m\n\u001b[31m  const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m  if(b)b.classList.remove('show');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function init(){\u001b[39m\n\u001b[31m  // Detect host banners (tiiny.host, etc) and raise bnav above them\u001b[39m\n\u001b[31m  (function detectHostBar(){\u001b[39m\n\u001b[31m    const h=window.location.hostname;\u001b[39m\n\u001b[31m    let extra=0;\u001b[39m\n\u001b[31m    if(h.includes('tiiny'))extra=58;\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // Generic detection: check if window is shorter than expected (host injected a bar)\u001b[39m\n\u001b[31m      const gap=screen.height - window.innerHeight;\u001b[39m\n\u001b[31m      if(gap>100&&gap<200)extra=58; // a fixed bar is roughly 56-60px\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if(extra>0){\u001b[39m\n\u001b[31m      document.documentElement.style.setProperty('--host-bar',extra+'px');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  })();\u001b[39m\n\u001b[31m  setLang(LANG);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m  checkAppUpdate();\u001b[39m\n\u001b[31m  await loadRecceCfg();\u001b[39m\n\u001b[31m  _checkAccessMode();\u001b[39m\n\u001b[31m  await initDB();await loadSettings();await loadHome();await checkDraft();netStatus();window.addEventListener('online',()=>{netStatus();syncNow();});window.addEventListener('offline',netStatus);injectHubButtons();document.getElementById('today-date').textContent=new Date().toLocaleDateString('en-IN',{weekday:'long',day:'numeric',month:'long',year:'numeric'});updAvailTag();\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m  // Auto-fetch stores from server on every startup (uses default Netlify URL if none saved)\u001b[39m\n\u001b[31m  const su=(await cfg('srv-url'))||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su&&navigator.onLine){\u001b[39m\n\u001b[31m    fetch(su).then(r=>r.json()).then(async j=>{\u001b[39m\n\u001b[31m      const d=Array.isArray(j)?j:j.stores||[];\u001b[39m\n\u001b[31m      if(d.length){stores=d;await cfg('stores',JSON.stringify(d));await cfg('srv-url',su);updAvailTag();\u001b[39m\n\u001b[31m        document.getElementById('srv-url').value=su;}\u001b[39m\n\u001b[31m    }).catch(()=>{});\u001b[39m\n\u001b[31m  }}init();\u001b[39m\n\u001b[31m</script>\u001b[39m\n\u001b[31m</body>\u001b[39m\n\u001b[31m</html>\u001b[39m\n\u001b[31m\"\u001b[39m",
                        "stack": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoContain\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // indexOf\u001b[22m\n\nExpected substring: \u001b[32m\"recce-v15\"\u001b[39m\nReceived string:    \u001b[31m\"<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\">\u001b[39m\n\u001b[31m<head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\">\u001b[39m\n\u001b[31m<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\\\">\u001b[39m\n\u001b[31m<meta name=\\\"theme-color\\\" content=\\\"#0f172a\\\">\u001b[39m\n\u001b[31m<meta name=\\\"apple-mobile-web-app-capable\\\" content=\\\"yes\\\">\u001b[39m\n\u001b[31m<title>Branding Recce</title>\u001b[39m\n\u001b[31m<link rel=\\\"manifest\\\" href=\\\"manifest.json\\\">\u001b[39m\n\u001b[31m<link rel=\\\"preconnect\\\" href=\\\"https://fonts.googleapis.com\\\">\u001b[39m\n\u001b[31m<link href=\\\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap\\\" rel=\\\"stylesheet\\\">\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--nv:#0f172a;--nv2:#1e293b;--or:#f97316;--orl:#fed7aa;--gn:#16a34a;--rd:#dc2626;--am:#d97706;--g50:#f8fafc;--g100:#f1f5f9;--g200:#e2e8f0;--g300:#cbd5e1;--g400:#94a3b8;--g500:#64748b;--g600:#475569;--r:12px;--rs:8px;--sh:0 1px 3px rgba(0,0,0,.1),0 1px 2px rgba(0,0,0,.06);--bnav-h:72px;--host-bar:0px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}\u001b[39m\n\u001b[31mbody{font-family:'DM Sans',sans-serif;background:var(--g50);color:var(--nv);min-height:100vh;overflow-x:hidden}\u001b[39m\n\u001b[31m.hdr{background:var(--nv);color:#fff;padding:0 16px;height:56px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}\u001b[39m\n\u001b[31m.hdr-l{display:flex;align-items:center;gap:10px}\u001b[39m\n\u001b[31m.hdr-title{font-size:16px;font-weight:600}.hdr-sub{font-size:11px;color:var(--g400)}\u001b[39m\n\u001b[31m.back-btn,.icon-btn{background:none;border:none;color:#fff;padding:8px;cursor:pointer;display:flex;align-items:center}\u001b[39m\n\u001b[31m.back-btn{margin-left:-8px}\u001b[39m\n\u001b[31m.pgbar{height:3px;background:var(--g200)}.pgfill{height:100%;background:var(--or);transition:width .3s}\u001b[39m\n\u001b[31m.view{display:none;min-height:calc(100vh - 56px);padding-bottom:calc(var(--bnav-h) + var(--host-bar) + 24px)}.view.active{display:block}\u001b[39m\n\u001b[31m.content{padding:16px}\u001b[39m\n\u001b[31m.card{background:#fff;border-radius:var(--r);padding:16px;box-shadow:var(--sh);margin-bottom:12px}\u001b[39m\n\u001b[31m.card-title{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;letter-spacing:.6px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between}\u001b[39m\n\u001b[31m.cnt-badge{background:var(--or);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;min-width:22px;text-align:center}\u001b[39m\n\u001b[31m.cnt-badge.gray{background:var(--g400)}\u001b[39m\n\u001b[31m.field{margin-bottom:16px}.field:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.field label{display:block;font-size:13px;font-weight:500;color:var(--g600);margin-bottom:6px}\u001b[39m\n\u001b[31m.req{color:var(--or);margin-left:2px}\u001b[39m\n\u001b[31m.field input,.field select,.field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;color:var(--nv);background:#fff;transition:border-color .15s;-webkit-appearance:none;appearance:none}\u001b[39m\n\u001b[31m.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--or)}\u001b[39m\n\u001b[31m.field input:read-only{background:var(--g50);color:var(--g600)}\u001b[39m\n\u001b[31m.field textarea{resize:vertical;min-height:68px}\u001b[39m\n\u001b[31m.field select{background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}\u001b[39m\n\u001b[31m.pslot{border:2px dashed var(--g300);border-radius:var(--r);min-height:110px;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all .15s;position:relative;overflow:hidden;text-align:center;padding:16px}\u001b[39m\n\u001b[31m.pslot:active{border-color:var(--or);background:var(--g50)}\u001b[39m\n\u001b[31m.pslot.filled{border-style:solid;border-color:var(--or);padding:0;min-height:0}\u001b[39m\n\u001b[31m.pslot img{width:100%;height:150px;object-fit:cover;border-radius:calc(var(--r) - 2px);display:block}\u001b[39m\n\u001b[31m.pslot-lbl{font-size:13px;color:var(--g400);margin-top:6px}.pslot-ico{font-size:28px;color:var(--g300)}\u001b[39m\n\u001b[31m.pbadge{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.premove{position:absolute;top:6px;right:6px;background:var(--rd);color:#fff;border:none;border-radius:50%;width:26px;height:26px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;z-index:5}\u001b[39m\n\u001b[31minput[type=file]{display:none}\u001b[39m\n\u001b[31m.rgroup{display:flex;gap:10px}\u001b[39m\n\u001b[31m.rbtn{flex:1;padding:13px;border:1.5px solid var(--g200);border-radius:var(--rs);text-align:center;cursor:pointer;font-size:14px;font-weight:500;color:var(--g500);transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.rbtn.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.chip-grid{display:flex;flex-wrap:wrap;gap:8px}\u001b[39m\n\u001b[31m.chip{padding:7px 12px;border:1.5px solid var(--g200);border-radius:20px;font-size:13px;color:var(--g600);cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.chip.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.brand-chip{display:flex;align-items:center;gap:6px;padding:5px 12px}\u001b[39m\n\u001b[31m.brand-chip-logo{width:28px;height:18px;object-fit:contain;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{display:block;width:100%;padding:15px;background:var(--or);color:#fff;border:none;border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:700;cursor:pointer;text-align:center;transition:background .15s}\u001b[39m\n\u001b[31m.btn-p:active{background:#ea6c05}.btn-p:disabled{background:var(--g300);cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-s{display:block;width:100%;padding:14px;background:#fff;color:var(--nv);border:1.5px solid var(--g200);border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:500;cursor:pointer;text-align:center}\u001b[39m\n\u001b[31m.btn-s:active{background:var(--g100)}\u001b[39m\n\u001b[31m.btn-o{display:inline-flex;align-items:center;gap:6px;padding:10px 16px;background:#fff;color:var(--or);border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer}\u001b[39m\n\u001b[31m.btn-o:active{background:var(--orl)}\u001b[39m\n\u001b[31m.btn-d{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;background:#fff;color:var(--rd);border:1.5px solid #fecaca;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:12px;cursor:pointer}\u001b[39m\n\u001b[31m.bnav{position:fixed;bottom:var(--host-bar);left:0;right:0;background:#fff;border-top:1px solid var(--g200);display:flex;padding:10px 16px;gap:10px;z-index:100}\u001b[39m\n\u001b[31m.hero{background:var(--nv);color:#fff;padding:20px 16px 24px}\u001b[39m\n\u001b[31m.hero-title{font-size:22px;font-weight:700;margin-bottom:2px}.hero-sub{font-size:13px;color:var(--g400)}\u001b[39m\n\u001b[31m.stats{display:flex;gap:10px;margin-top:16px}\u001b[39m\n\u001b[31m.scard{flex:1;background:rgba(255,255,255,.08);border-radius:var(--rs);padding:12px;text-align:center}\u001b[39m\n\u001b[31m.snum{font-size:22px;font-weight:700}.slbl{font-size:11px;color:var(--g400);margin-top:2px}\u001b[39m\n\u001b[31m.scard.g .snum{color:#4ade80}.scard.a .snum{color:#fbbf24}\u001b[39m\n\u001b[31m.new-btn{background:var(--or);color:#fff;border:none;border-radius:var(--r);padding:16px;font-family:'DM Sans',sans-serif;font-size:16px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:10px;cursor:pointer;width:100%;margin-bottom:10px}\u001b[39m\n\u001b[31m.new-btn:active{background:#ea6c05}\u001b[39m\n\u001b[31m.resume-btn{background:var(--nv2);color:#fff;border:none;border-radius:var(--r);padding:13px 16px;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;display:flex;align-items:center;justify-content:space-between;cursor:pointer;width:100%;margin-bottom:18px}\u001b[39m\n\u001b[31m.sub-card{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:10px;display:flex;align-items:center;gap:12px}\u001b[39m\n\u001b[31m.sub-ico{width:40px;height:40px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}\u001b[39m\n\u001b[31m.sub-ico.pending{background:#fef3c7}.sub-ico.synced{background:#dcfce7}.sub-ico.failed{background:#fee2e2}\u001b[39m\n\u001b[31m.sub-meta{flex:1;min-width:0}.sub-name{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.sub-dtl{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.sbadge{font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;flex-shrink:0}\u001b[39m\n\u001b[31m.sbadge.pending{background:#fef3c7;color:#92400e}.sbadge.synced{background:#dcfce7;color:#14532d}.sbadge.failed{background:#fee2e2;color:#991b1b}\u001b[39m\n\u001b[31m.sh{display:flex;align-items:center;justify-content:space-between;margin:20px 0 12px}\u001b[39m\n\u001b[31m.st{font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.toast{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 8px);left:16px;right:16px;background:var(--nv);color:#fff;padding:12px 16px;border-radius:var(--r);font-size:14px;z-index:1000;transform:translateY(120px);opacity:0;transition:all .3s;pointer-events:none}\u001b[39m\n\u001b[31m.toast.show{transform:translateY(0);opacity:1}.toast.success{background:#16a34a}.toast.error{background:var(--rd)}.toast.info{background:var(--nv2)}\u001b[39m\n\u001b[31m.srow{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:#fff;border-top:1px solid var(--g100);font-size:12px;color:var(--g500)}\u001b[39m\n\u001b[31m.sdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px}.sdot.on{background:var(--gn)}.sdot.off{background:var(--g300)}\u001b[39m\n\u001b[31m.set-item{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:8px}\u001b[39m\n\u001b[31m.set-lbl{font-size:14px;font-weight:600;color:var(--nv);margin-bottom:4px}\u001b[39m\n\u001b[31m.set-sub{font-size:12px;color:var(--g500);margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem{background:#fff;border-radius:var(--r);border:1.5px solid var(--g200);padding:14px;margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\u001b[39m\n\u001b[31m.bitem-title{font-size:14px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.dim-row{display:flex;gap:8px}.dim-row .field{flex:1}\u001b[39m\n\u001b[31m.sqft{display:inline-block;background:var(--g100);color:var(--g600);font-size:12px;padding:4px 10px;border-radius:20px;margin-top:6px}\u001b[39m\n\u001b[31m.divider{height:1px;background:var(--g100);margin:12px 0}\u001b[39m\n\u001b[31m.rev-lbl{font-size:12px;color:var(--g500);margin-bottom:2px}\u001b[39m\n\u001b[31m.rev-val{font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.rev-photos{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}\u001b[39m\n\u001b[31m.rev-thumb{width:56px;height:56px;object-fit:cover;border-radius:var(--rs)}\u001b[39m\n\u001b[31m.empty{text-align:center;padding:40px 20px;color:var(--g400)}.empty-ico{font-size:40px;margin-bottom:12px}.empty-txt{font-size:14px}\u001b[39m\n\u001b[31m/* store picker */\u001b[39m\n\u001b[31m.store-card{border:1.5px solid var(--g200);border-radius:var(--rs);padding:13px 14px;background:#fff;position:relative;cursor:pointer}\u001b[39m\n\u001b[31m.store-card:active{background:var(--g50)}\u001b[39m\n\u001b[31m.store-card-name{font-size:15px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.store-card-meta{font-size:13px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.store-card-change{position:absolute;top:11px;right:12px;background:none;border:none;color:var(--or);font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer}\u001b[39m\n\u001b[31m.brand-tag{display:inline-block;background:var(--nv);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-top:4px}\u001b[39m\n\u001b[31m.last-chip{display:inline-flex;align-items:center;gap:4px;background:#fef3c7;color:#92400e;font-size:11px;font-weight:500;padding:3px 9px;border-radius:20px;margin-left:6px}\u001b[39m\n\u001b[31m.pick-trigger{border:2px solid var(--or);border-radius:var(--rs);padding:14px 16px;background:#fff7ed;display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-size:15px;font-weight:600;color:var(--or)}\u001b[39m\n\u001b[31m.pick-trigger:active{background:#ffedd5;border-color:#ea6800}\u001b[39m\n\u001b[31m.manual-toggle{display:flex;align-items:center;gap:8px;padding:10px 14px;border:1.5px dashed var(--g300);border-radius:var(--rs);cursor:pointer;font-size:13px;color:var(--g600);margin-top:8px;user-select:none}\u001b[39m\n\u001b[31m/* client chip grid */\u001b[39m\n\u001b[31m.cl-chip-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}\u001b[39m\n\u001b[31m.cl-chip{padding:8px 14px;border-radius:20px;border:1.5px solid var(--g200);font-size:13px;font-weight:500;color:var(--g600);background:#fff;cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.cl-chip:active,.cl-chip.sel{background:var(--or);border-color:var(--or);color:#fff;font-weight:600}\u001b[39m\n\u001b[31m.cl-chip-other{border-style:dashed}\u001b[39m\n\u001b[31m.client-tag{display:inline-block;background:#e0f2fe;color:#0369a1;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-left:4px}\u001b[39m\n\u001b[31m.manual-toggle.on{border-color:var(--or);background:#fff7ed;color:var(--or)}\u001b[39m\n\u001b[31m/* picker overlay */\u001b[39m\n\u001b[31m.povl{display:none;position:fixed;inset:0;background:var(--g50);z-index:200;flex-direction:column}\u001b[39m\n\u001b[31m.povl.open{display:flex}\u001b[39m\n\u001b[31m.povl-hdr{background:var(--nv);padding:12px 16px;display:flex;align-items:center;gap:12px;flex-shrink:0}\u001b[39m\n\u001b[31m.psearch{flex:1;padding:10px 14px;border:none;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;background:rgba(255,255,255,.12);color:#fff;outline:none}\u001b[39m\n\u001b[31m.psearch::placeholder{color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.pcancel{background:none;border:none;color:rgba(255,255,255,.7);font-family:'DM Sans',sans-serif;font-size:14px;cursor:pointer;padding:4px;white-space:nowrap}\u001b[39m\n\u001b[31m.plist{overflow-y:auto;flex:1}\u001b[39m\n\u001b[31m.pitem{padding:14px 16px;border-bottom:.5px solid var(--g100);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px}\u001b[39m\n\u001b[31m.pitem:active{background:var(--g100)}\u001b[39m\n\u001b[31m.pi-name{font-size:15px;font-weight:600;color:var(--nv)}.pi-addr{font-size:12px;color:var(--g500);margin-top:2px}.pi-last{font-size:11px;color:var(--am);margin-top:2px}\u001b[39m\n\u001b[31m.pi-brand{font-size:11px;font-weight:700;padding:3px 8px;border-radius:20px;background:var(--nv);color:#fff;flex-shrink:0}\u001b[39m\n\u001b[31m.psec{padding:8px 16px 4px;font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;background:var(--g50)}\u001b[39m\n\u001b[31m.padd{padding:16px;text-align:center;font-size:14px;color:var(--or);font-weight:600;cursor:pointer;background:#fff7ed;border-top:1.5px dashed var(--or)}\u001b[39m\n\u001b[31m.gps-row{display:flex;gap:8px;margin-top:8px}\u001b[39m\n\u001b[31m.gps-btn{flex-shrink:0;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;color:var(--g500);display:flex;align-items:center;gap:6px}\u001b[39m\n\u001b[31m.gps-btn:active{background:var(--orl);border-color:var(--or);color:var(--or)}\u001b[39m\n\u001b[31m@keyframes spin{to{transform:rotate(360deg)}}.spin{animation:spin .7s linear infinite;display:inline-block}\u001b[39m\n\u001b[31m/* ANNOTATION TOOL */\u001b[39m\n\u001b[31m.annot-modal{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column}\u001b[39m\n\u001b[31m.annot-modal.open{display:flex}\u001b[39m\n\u001b[31m.annot-bar{background:var(--nv);padding:8px 12px;flex-shrink:0}\u001b[39m\n\u001b[31m.annot-row{display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap}\u001b[39m\n\u001b[31m.annot-row:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.atool{padding:6px 10px;background:rgba(255,255,255,.1);border:1.5px solid rgba(255,255,255,.2);border-radius:var(--rs);color:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:500;cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.atool.on{background:var(--or);border-color:var(--or)}\u001b[39m\n\u001b[31m.atool.sel-on{background:#7c3aed;border-color:#7c3aed}\u001b[39m\n\u001b[31m.acolor{width:24px;height:24px;border-radius:50%;border:2px solid rgba(255,255,255,.3);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.acolor.on{border-color:#fff;border-width:3px;transform:scale(1.15)}\u001b[39m\n\u001b[31m.annot-cvs-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#111;position:relative}\u001b[39m\n\u001b[31m#annot-cvs{max-width:100%;max-height:100%;display:block;touch-action:none;cursor:crosshair}\u001b[39m\n\u001b[31m.annot-foot{background:var(--nv);padding:10px 16px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.req-note{font-size:12px;color:var(--rd);margin-top:6px;font-weight:500}\u001b[39m\n\u001b[31m/* Bottom dialog */\u001b[39m\n\u001b[31m.bdialog-wrap{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:400;align-items:flex-end}\u001b[39m\n\u001b[31m.bdialog-wrap.open{display:flex}\u001b[39m\n\u001b[31m.bdialog{background:#fff;border-radius:var(--r) var(--r) 0 0;padding:20px 16px 32px;width:100%}\u001b[39m\n\u001b[31m.bdialog-title{font-size:16px;font-weight:700;color:var(--nv);margin-bottom:6px}\u001b[39m\n\u001b[31m.bdialog-sub{font-size:13px;color:var(--g500);margin-bottom:16px}\u001b[39m\n\u001b[31m.bdialog-btns{display:flex;gap:10px}\u001b[39m\n\u001b[31m/* Edit badge on sub-card */\u001b[39m\n\u001b[31m.edit-btn-sm{padding:5px 12px;background:var(--g50);border:1px solid var(--g200);border-radius:20px;font-family:'DM Sans',sans-serif;font-size:12px;color:var(--g600);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m/* Toggle switch */\u001b[39m\n\u001b[31m.tog{width:48px;height:26px;background:var(--g300);border-radius:13px;cursor:pointer;transition:background .2s;flex-shrink:0;position:relative;display:inline-block}\u001b[39m\n\u001b[31m.tog.on{background:var(--or)}\u001b[39m\n\u001b[31m.tog-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2);pointer-events:none}\u001b[39m\n\u001b[31m.tog.on .tog-knob{transform:translateX(22px)}\u001b[39m\n\u001b[31m/* ── ADMIN RECCE VIEW ── */\u001b[39m\n\u001b[31m.af-bar{background:var(--g100);padding:10px 16px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--g200);overflow:hidden}\u001b[39m\n\u001b[31m.af-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}\u001b[39m\n\u001b[31m.af-sel{width:100%;padding:8px 10px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv);cursor:pointer;\u001b[39m\n\u001b[31m  white-space:normal;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.af-sel:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.af-inp{width:100%;padding:8px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv)}\u001b[39m\n\u001b[31m.af-inp:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.grp-hdr{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;\u001b[39m\n\u001b[31m  letter-spacing:.5px;padding:14px 0 6px;border-bottom:1px solid var(--g200);margin-bottom:6px}\u001b[39m\n\u001b[31m.grp-hdr:first-child{padding-top:0}\u001b[39m\n\u001b[31m.asc{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:12px 14px;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;gap:6px;margin-bottom:8px;cursor:pointer;\u001b[39m\n\u001b[31m  transition:box-shadow .15s}\u001b[39m\n\u001b[31m.asc:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.asc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}\u001b[39m\n\u001b[31m.asc-name{font-size:14px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.asc-brand{display:inline-block;background:#fff7ed;color:var(--or);font-size:11px;\u001b[39m\n\u001b[31m  font-weight:600;padding:2px 8px;border-radius:20px;border:1px solid #fed7aa;white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chip{background:var(--g100);border-radius:20px;padding:2px 8px;font-size:11px;color:var(--g600);white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chips{display:flex;flex-wrap:wrap;gap:5px}\u001b[39m\n\u001b[31m.asc-agent{background:var(--nv);color:#fff;font-size:11px;font-weight:600;\u001b[39m\n\u001b[31m  padding:2px 8px;border-radius:20px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m/* Admin detail modal */\u001b[39m\n\u001b[31m.ardl-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:600;\u001b[39m\n\u001b[31m  display:flex;align-items:flex-end;justify-content:center}\u001b[39m\n\u001b[31m.ardl-box{background:#fff;border-radius:var(--r) var(--r) 0 0;width:100%;max-height:80vh;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ardl-hdr{display:flex;align-items:flex-start;justify-content:space-between;\u001b[39m\n\u001b[31m  padding:16px 16px 10px;border-bottom:1px solid var(--g200);gap:10px}\u001b[39m\n\u001b[31m.ardl-title{font-size:17px;font-weight:700;color:var(--nv);line-height:1.3}\u001b[39m\n\u001b[31m.ardl-body{flex:1;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:14px}\u001b[39m\n\u001b[31m.ardl-sec{display:flex;flex-direction:column;gap:6px}\u001b[39m\n\u001b[31m.ardl-lbl{font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.ardl-val{font-size:13px;color:var(--nv);line-height:1.5}\u001b[39m\n\u001b[31m.ardl-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\u001b[39m\n\u001b[31m/* Hub home button */\u001b[39m\n\u001b[31m.btn-hub{background:none;border:1px solid rgba(255,255,255,.25);color:rgba(255,255,255,.85);\u001b[39m\n\u001b[31m  font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;cursor:pointer;\u001b[39m\n\u001b[31m  display:flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-hub:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hdr-r{display:flex;align-items:center;gap:6px;margin-left:auto;flex-shrink:0}\u001b[39m\n\u001b[31m.hdr-user{font-size:11px;color:rgba(255,255,255,.7);white-space:nowrap;max-width:80px;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.btn-logout{background:none;border:1px solid rgba(255,255,255,.2);color:rgba(255,255,255,.7);font-size:11px;font-weight:600;padding:4px 8px;border-radius:20px;cursor:pointer;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-logout:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hero-ubar{display:flex;align-items:center;justify-content:space-between;padding-top:6px;margin-top:2px}\u001b[39m\n\u001b[31m.hero-uname{font-size:12px;color:rgba(255,255,255,.65)}\u001b[39m\n\u001b[31m.hi-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .en-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .hi-txt{display:inline}\u001b[39m\n\u001b[31m.lang-btn{background:none;border:1px solid rgba(255,255,255,.3);color:rgba(255,255,255,.8);font-size:12px;font-weight:700;padding:4px 10px;border-radius:20px;cursor:pointer;display:flex;align-items:center;gap:3px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.lang-btn:active{background:rgba(255,255,255,.15)}\u001b[39m\n\u001b[31m/* ── DELETE / AUDIT ── */\u001b[39m\n\u001b[31m.del-btn{background:none;border:none;padding:6px 8px;cursor:pointer;color:var(--g400);font-size:16px;flex-shrink:0;border-radius:var(--rs);transition:color .15s,background .15s}\u001b[39m\n\u001b[31m.del-btn:active{color:var(--rd);background:#fee2e2}\u001b[39m\n\u001b[31m.asc.deleted-row{background:#fff5f5;border:1px solid #fecaca;opacity:.85}\u001b[39m\n\u001b[31m.asc.deleted-row .asc-name{text-decoration:line-through;color:var(--g500)}\u001b[39m\n\u001b[31m.del-reason-tag{display:inline-block;background:#fee2e2;color:var(--rd);font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.del-by-txt{font-size:11px;color:var(--g400);margin-top:3px}\u001b[39m\n\u001b[31m.restore-btn{background:none;border:1.5px solid #bbf7d0;border-radius:20px;color:#16a34a;font-size:11px;font-weight:700;padding:3px 10px;cursor:pointer;white-space:nowrap;margin-top:5px}\u001b[39m\n\u001b[31m.restore-btn:active{background:#dcfce7}\u001b[39m\n\u001b[31m.sup-tile{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:20px 16px;cursor:pointer;display:flex;align-items:center;gap:14px;margin-bottom:12px;transition:box-shadow .15s}\u001b[39m\n\u001b[31m.sup-tile:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.sup-tile-ico{width:48px;height:48px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:26px;flex-shrink:0}\u001b[39m\n\u001b[31m.sup-tile-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.sup-tile-title{font-size:15px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.sup-tile-sub{font-size:12px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.del-toggle-btn{padding:6px 14px;border:1.5px solid var(--g200);border-radius:20px;background:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:600;color:var(--g500);cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.del-toggle-btn.active{background:#fee2e2;border-color:#fecaca;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1.5px solid var(--g200);border-radius:var(--r);margin-bottom:10px;cursor:pointer;transition:all .15s;font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.reason-opt:active{background:var(--g50)}\u001b[39m\n\u001b[31m.reason-opt.sel{border-color:var(--rd);background:#fff5f5;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt.danger{border-color:#fdba74;background:#fff7ed;color:#9a3412}\u001b[39m\n\u001b[31m.reason-opt.danger.sel{border-color:#c2410c;background:#fff1e6;color:#9a3412}\u001b[39m\n\u001b[31m#del-confirm-btn.no-reason{background:var(--g300)!important;cursor:default}\u001b[39m\n\u001b[31m@keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}\u001b[39m\n\u001b[31m.reason-opt-ico{font-size:22px;flex-shrink:0}\u001b[39m\n\u001b[31m/* ── APP UPDATE BANNER ── */\u001b[39m\n\u001b[31m.upd-banner{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);left:12px;right:12px;background:#16a34a;color:#fff;padding:11px 14px;border-radius:var(--r);display:flex;align-items:center;justify-content:space-between;gap:10px;z-index:550;box-shadow:0 4px 16px rgba(0,0,0,.18);transform:translateY(120px);opacity:0;transition:transform .35s ease,opacity .35s ease;pointer-events:none}\u001b[39m\n\u001b[31m.upd-banner.show{transform:translateY(0);opacity:1;pointer-events:auto}\u001b[39m\n\u001b[31m/* ── EDIT REQUEST ── */\u001b[39m\n\u001b[31m.req-edit-btn{padding:4px 10px;background:#fffbeb;border:1px solid #fde68a;border-radius:20px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:600;color:#92400e;cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.req-edit-btn:active{background:#fef3c7}\u001b[39m\n\u001b[31m.edit-req-badge{display:inline-block;background:#fef3c7;color:#92400e;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;white-space:nowrap}\u001b[39m\n\u001b[31m.edit-req-card{background:#fffbeb;border:1.5px solid #fde68a;border-radius:var(--r);padding:14px 16px;margin-bottom:10px;display:flex;align-items:flex-start;gap:12px}\u001b[39m\n\u001b[31m.edit-req-card-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.edit-req-card-name{font-size:14px;font-weight:600;color:var(--nv);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.edit-req-card-meta{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.edit-req-cmt{font-size:12px;color:#78350f;background:#fff;border:1px solid #fde68a;border-radius:var(--rs);padding:8px 10px;margin-top:8px;line-height:1.5}\u001b[39m\n\u001b[31m.edit-req-section-hdr{font-size:11px;font-weight:700;color:#92400e;text-transform:uppercase;letter-spacing:.5px;padding:10px 0 6px;border-bottom:1px solid #fde68a;margin-bottom:8px}\u001b[39m\n\u001b[31m.upd-banner-ok{background:rgba(255,255,255,.2);border:none;color:#fff;border-radius:20px;padding:5px 13px;font-size:12px;font-weight:600;cursor:pointer;font-family:'DM Sans',sans-serif;white-space:nowrap}\u001b[39m\n\u001b[31m.upd-banner-ok:active{background:rgba(255,255,255,.35)}\u001b[39m\n\u001b[31m/* ── FONT SIZE WIDGET ── */\u001b[39m\n\u001b[31m.fs-widget{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);right:12px;display:flex;align-items:center;gap:0;background:#fff;border:1.5px solid var(--g200);border-radius:24px;box-shadow:0 2px 8px rgba(0,0,0,.12);z-index:500;overflow:hidden;user-select:none}\u001b[39m\n\u001b[31m.fs-btn{background:none;border:none;cursor:pointer;padding:7px 11px;color:var(--g500);line-height:1;transition:background .15s}\u001b[39m\n\u001b[31m.fs-btn:active{background:var(--g100)}\u001b[39m\n\u001b[31m.fs-btn:disabled{color:var(--g300);cursor:default}\u001b[39m\n\u001b[31m.fs-label{font-size:11px;font-weight:700;color:var(--g500);padding:0 4px;pointer-events:none}\u001b[39m\n\u001b[31m/* Level 1 — Large (+15%) */\u001b[39m\n\u001b[31mbody.fs-1 .field label,body.fs-1 .card-title,body.fs-1 .set-lbl,body.fs-1 .set-sub,\u001b[39m\n\u001b[31mbody.fs-1 .hdr-title,body.fs-1 .hdr-sub,body.fs-1 .slbl,body.fs-1 .rev-lbl,body.fs-1 .rev-val,\u001b[39m\n\u001b[31mbody.fs-1 .rbtn,body.fs-1 .chip,body.fs-1 .btn-p,body.fs-1 .btn-s,body.fs-1 .btn-o,\u001b[39m\n\u001b[31mbody.fs-1 .bdialog-title,body.fs-1 .bdialog-sub,body.fs-1 .sub-name,body.fs-1 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-1 .pslot-lbl,body.fs-1 .bitem-title,body.fs-1 .pi-name,body.fs-1 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-1 .asc-name,body.fs-1 .new-btn,body.fs-1 .resume-btn,body.fs-1 .ardl-lbl,body.fs-1 .ardl-val{font-size:calc(1em * 1.15) !important}\u001b[39m\n\u001b[31m/* Level 2 — X-Large (+30%) */\u001b[39m\n\u001b[31mbody.fs-2 .field label,body.fs-2 .card-title,body.fs-2 .set-lbl,body.fs-2 .set-sub,\u001b[39m\n\u001b[31mbody.fs-2 .hdr-title,body.fs-2 .hdr-sub,body.fs-2 .slbl,body.fs-2 .rev-lbl,body.fs-2 .rev-val,\u001b[39m\n\u001b[31mbody.fs-2 .rbtn,body.fs-2 .chip,body.fs-2 .btn-p,body.fs-2 .btn-s,body.fs-2 .btn-o,\u001b[39m\n\u001b[31mbody.fs-2 .bdialog-title,body.fs-2 .bdialog-sub,body.fs-2 .sub-name,body.fs-2 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-2 .pslot-lbl,body.fs-2 .bitem-title,body.fs-2 .pi-name,body.fs-2 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-2 .asc-name,body.fs-2 .new-btn,body.fs-2 .resume-btn,body.fs-2 .ardl-lbl,body.fs-2 .ardl-val{font-size:calc(1em * 1.30) !important}\u001b[39m\n\u001b[31m/* Level 3 — XX-Large (+50%) */\u001b[39m\n\u001b[31mbody.fs-3 .field label,body.fs-3 .card-title,body.fs-3 .set-lbl,body.fs-3 .set-sub,\u001b[39m\n\u001b[31mbody.fs-3 .hdr-title,body.fs-3 .hdr-sub,body.fs-3 .slbl,body.fs-3 .rev-lbl,body.fs-3 .rev-val,\u001b[39m\n\u001b[31mbody.fs-3 .rbtn,body.fs-3 .chip,body.fs-3 .btn-p,body.fs-3 .btn-s,body.fs-3 .btn-o,\u001b[39m\n\u001b[31mbody.fs-3 .bdialog-title,body.fs-3 .bdialog-sub,body.fs-3 .sub-name,body.fs-3 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-3 .pslot-lbl,body.fs-3 .bitem-title,body.fs-3 .pi-name,body.fs-3 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-3 .asc-name,body.fs-3 .new-btn,body.fs-3 .resume-btn,body.fs-3 .ardl-lbl,body.fs-3 .ardl-val{font-size:calc(1em * 1.50) !important}\u001b[39m\n\u001b[31m/* Level 4 — Max (+70%) */\u001b[39m\n\u001b[31mbody.fs-4 .field label,body.fs-4 .card-title,body.fs-4 .set-lbl,body.fs-4 .set-sub,\u001b[39m\n\u001b[31mbody.fs-4 .hdr-title,body.fs-4 .hdr-sub,body.fs-4 .slbl,body.fs-4 .rev-lbl,body.fs-4 .rev-val,\u001b[39m\n\u001b[31mbody.fs-4 .rbtn,body.fs-4 .chip,body.fs-4 .btn-p,body.fs-4 .btn-s,body.fs-4 .btn-o,\u001b[39m\n\u001b[31mbody.fs-4 .bdialog-title,body.fs-4 .bdialog-sub,body.fs-4 .sub-name,body.fs-4 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-4 .pslot-lbl,body.fs-4 .bitem-title,body.fs-4 .pi-name,body.fs-4 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-4 .asc-name,body.fs-4 .new-btn,body.fs-4 .resume-btn,body.fs-4 .ardl-lbl,body.fs-4 .ardl-val{font-size:calc(1em * 1.70) !important}\u001b[39m\n\u001b[31m/* ── RECCE TILE ACTION BUTTONS ── */\u001b[39m\n\u001b[31m.rpt-btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid rgba(0,0,0,.06)}\u001b[39m\n\u001b[31m.rpt-btn{display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 14px;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;border:none;font-family:inherit;transition:background .15s,opacity .15s;flex:1;min-width:110px;letter-spacing:.1px;white-space:nowrap}\u001b[39m\n\u001b[31m.rpt-btn-report{background:#fff7ed;color:var(--or);border:1.5px solid var(--or)}\u001b[39m\n\u001b[31m.rpt-btn-report:active{background:#fed7aa}\u001b[39m\n\u001b[31m.rpt-btn-pdf{background:var(--g100);color:var(--g400);border:1.5px solid var(--g200)}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready{background:var(--or);color:#fff;border-color:transparent}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready:active{background:#ea6c00}\u001b[39m\n\u001b[31m/* PDF wait overlay */\u001b[39m\n\u001b[31m#pdf-wait-ov{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m</style>\u001b[39m\n\u001b[31m</head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<!-- PICKER OVERLAY -->\u001b[39m\n\u001b[31m<div class=\\\"povl\\\" id=\\\"povl\\\">\u001b[39m\n\u001b[31m  <div class=\\\"povl-hdr\\\">\u001b[39m\n\u001b[31m    <input class=\\\"psearch\\\" id=\\\"psearch\\\" type=\\\"text\\\" placeholder=\\\"Search store / दुकान खोजें…\\\" oninput=\\\"filterPicker(this.value)\\\" autocomplete=\\\"off\\\">\u001b[39m\n\u001b[31m    <button class=\\\"pcancel\\\" onclick=\\\"closePicker()\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"plist\\\" id=\\\"plist\\\"></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"app\\\">·\u001b[39m\n\u001b[31m<!-- HOME -->\u001b[39m\n\u001b[31m<div class=\\\"view active\\\" id=\\\"view-home\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hero\\\">\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;justify-content:space-between;align-items:center\\\">\u001b[39m\n\u001b[31m      <div><div class=\\\"hero-title\\\"><span class=\\\"en-txt\\\">Branding Recce</span><span class=\\\"hi-txt\\\">ब्रांडिंग रेकी</span></div><div class=\\\"hero-sub\\\" id=\\\"today-date\\\">—</div></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:6px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"lang-btn\\\" onclick=\\\"setLang(LANG==='en'?'hi':'en')\\\" id=\\\"lang-btn\\\" title=\\\"Switch language / भाषा बदलें\\\">EN | हि</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-hub\\\" onclick=\\\"goToHub()\\\">🏡 Hub</button>\u001b[39m\n\u001b[31m      <button class=\\\"icon-btn\\\" onclick=\\\"showView('settings')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12 15a3 3 0 100-6 3 3 0 000 6z\\\"/><path d=\\\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\\\"/></svg></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"hero-ubar\\\" id=\\\"recce-hero-ubar\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <span class=\\\"hero-uname\\\" id=\\\"recce-hero-name\\\"></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-logout\\\" onclick=\\\"recceLogout()\\\">Logout</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"stats\\\">\u001b[39m\n\u001b[31m      <div class=\\\"scard g\\\"><div class=\\\"snum\\\" id=\\\"stat-synced\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Synced</span><span class=\\\"hi-txt\\\">सिंक्ड</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard a\\\"><div class=\\\"snum\\\" id=\\\"stat-pending\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Pending</span><span class=\\\"hi-txt\\\">बाकी</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard\\\"><div class=\\\"snum\\\" id=\\\"stat-total\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Total</span><span class=\\\"hi-txt\\\">कुल</span></div></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <button class=\\\"new-btn\\\" onclick=\\\"startNewRecce()\\\"><svg width=\\\"20\\\" height=\\\"20\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">New Recce</span><span class=\\\"hi-txt\\\">नई रेकी</span></button>\u001b[39m\n\u001b[31m    <div id=\\\"resume-wrap\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"sh\\\"><span class=\\\"st\\\"><span class=\\\"en-txt\\\">Recent Submissions</span><span class=\\\"hi-txt\\\">हाल की सबमिशन</span></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"syncNow()\\\" id=\\\"sync-btn\\\" style=\\\"padding:7px 12px;font-size:12px\\\"><svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg><span class=\\\"en-txt\\\">Sync</span><span class=\\\"hi-txt\\\">सिंक</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"sub-list\\\"></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"srow\\\"><div><span class=\\\"sdot\\\" id=\\\"net-dot\\\"></span><span id=\\\"net-txt\\\"><span class=\\\"en-txt\\\">Checking…</span><span class=\\\"hi-txt\\\">जाँच…</span></span></div><span id=\\\"last-sync-txt\\\" style=\\\"font-size:11px\\\"><span class=\\\"en-txt\\\">Never synced</span><span class=\\\"hi-txt\\\">कभी सिंक नहीं</span></span></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- SETTINGS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-settings\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('home')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Settings</span><span class=\\\"hi-txt\\\">सेटिंग</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Brand List</span><span class=\\\"hi-txt\\\">ब्रांड सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Manage Brands</span><span class=\\\"hi-txt\\\">ब्रांड प्रबंधन</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">These appear in the brand dropdown and store picker. Add client brands as needed.</div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-manage-list\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-add-row\\\" style=\\\"display:none;gap:8px;align-items:center\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"brand-add-inp\\\" placeholder=\\\"Type brand name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addBrandToList()\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"addBrandToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Store Lists</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Supervisors can upload XLS/CSV store lists here. Updates sync to all devices via server.</span><span class=\\\"hi-txt\\\">सुपरवाइजर यहाँ XLS/CSV स्टोर सूची अपलोड कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m      <!-- Upload/Clear row — supervisor only -->\u001b[39m\n\u001b[31m      <div id=\\\"store-upload-row\\\" style=\\\"display:none;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;margin-top:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"document.getElementById('store-xl').click()\\\"><svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Add File</span><span class=\\\"hi-txt\\\">फ़ाइल जोड़ें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-d\\\" onclick=\\\"clearStoreList()\\\" style=\\\"font-size:12px\\\"><span class=\\\"en-txt\\\">Clear All Stores</span><span class=\\\"hi-txt\\\">सभी स्टोर हटाएं</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" id=\\\"store-push-btn\\\" onclick=\\\"pushStoresToServer()\\\" style=\\\"font-size:12px;display:none\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Push to Server</span><span class=\\\"hi-txt\\\">सर्वर पर पुश करें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"store-xl\\\" accept=\\\".xlsx,.xls,.csv\\\" onchange=\\\"handleStoreUpload(event)\\\">\u001b[39m\n\u001b[31m      <div id=\\\"store-count\\\" style=\\\"font-size:13px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"store-file-list\\\" style=\\\"margin-top:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Brand assignment dialog for files with no brand column -->\u001b[39m\n\u001b[31m    <div id=\\\"brand-assign-dialog\\\" style=\\\"display:none;margin-top:10px;padding:14px;background:#fff7ed;border:1.5px solid var(--or);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\">Which brand is this store list for?</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\" id=\\\"brand-assign-fname\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-assign-chips\\\" class=\\\"chip-grid\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"confirmBrandAssign()\\\" style=\\\"flex:2;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">Assign Brand</span><span class=\\\"hi-txt\\\">ब्रांड असाइन करें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"skipBrandAssign()\\\" style=\\\"flex:1;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">No Brand</span><span class=\\\"hi-txt\\\">कोई ब्रांड नहीं</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Server Store List URL (Admin)</span><span class=\\\"hi-txt\\\">सर्वर स्टोर सूची URL</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Admin pushes stores.json to any public URL. App auto-fetches on open and caches offline.</div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"srv-url\\\" placeholder=\\\"https://yourserver.com/stores.json\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"fetchServerStores()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Fetch Now</button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"saveServerUrl()\\\" style=\\\"padding:9px 14px;font-size:13px;width:auto\\\">Save URL</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Sync Endpoint</span><span class=\\\"hi-txt\\\">सिंक एंडपॉइंट</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Slides Generator</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Managed by admin. Deploy gas_slides.gs from /opt/slides-proxy/ to Google Apps Script and paste the URL here.</div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"slides-gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Not configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"slides-gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"saveSlidesGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Sheet Sync</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Legacy sync endpoint. Writes recce data to Google Sheet.</div>·\u001b[39m\n\u001b[31m      <!-- Locked state (default) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Endpoint configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Unlocked state (after admin login) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;align-items:center;gap:8px;margin-bottom:10px;padding:7px 12px;background:#dcfce7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          <span style=\\\"font-size:12px;color:#14532d;font-weight:600\\\">🔓 Admin mode active</span>\u001b[39m\n\u001b[31m          <button onclick=\\\"lockAdmin()\\\" style=\\\"margin-left:auto;background:none;border:none;color:#14532d;font-size:12px;cursor:pointer;font-weight:600\\\">Lock ×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"testEndpoint()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Test</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>·\u001b[39m\n\u001b[31m    <!-- Admin Login Modal -->\u001b[39m\n\u001b[31m    <div id=\\\"admin-login-modal\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m      <div style=\\\"background:#fff;border-radius:var(--r);padding:24px 20px;margin:20px;max-width:380px;width:100%;box-shadow:0 8px 32px rgba(0,0,0,.2)\\\">\u001b[39m\n\u001b[31m        <div style=\\\"font-size:17px;font-weight:700;color:var(--nv);margin-bottom:4px\\\">Admin Login</div>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:18px\\\">Enter admin password to unlock settings</div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m          <label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">Password</label>\u001b[39m\n\u001b[31m          <input type=\\\"password\\\" id=\\\"admin-pwd\\\" placeholder=\\\"Enter admin password\\\" style=\\\"width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px\\\" onkeydown=\\\"if(event.key==='Enter')verifyAdmin()\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div id=\\\"admin-error\\\" style=\\\"display:none;font-size:12px;color:var(--rd);margin-bottom:12px;padding:8px 12px;background:#fee2e2;border-radius:var(--rs)\\\">Incorrect password</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"verifyAdmin()\\\" style=\\\"flex:2;padding:13px\\\" id=\\\"admin-login-btn\\\">Login</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-s\\\" onclick=\\\"closeAdminLogin()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:14px;padding-top:14px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.4px;margin-bottom:8px\\\">Admin Password Config URL</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:8px\\\">URL to your admin.json file on server (contains hashed password)</div>\u001b[39m\n\u001b[31m          <input type=\\\"url\\\" id=\\\"admin-cfg-url\\\" placeholder=\\\"https://yourserver.com/admin.json\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px;margin-bottom:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveAdminCfgUrl()\\\" style=\\\"font-size:12px;padding:7px 12px;width:100%;justify-content:center\\\">Save Config URL</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Geolocation Stamp</span><span class=\\\"hi-txt\\\">जियोलोकेशन स्टैम्प</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;justify-content:space-between;gap:16px\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1\\\">\u001b[39m\n\u001b[31m          <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Stamp on Photos</span><span class=\\\"hi-txt\\\">फोटो पर स्टैम्प</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"set-sub\\\" style=\\\"margin-bottom:0\\\">Bakes GPS coordinates, store name and timestamp into every photo — visible in the image itself. Same as GPS Map Camera app. Default: On.</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"tog on\\\" id=\\\"geo-tog\\\" onclick=\\\"toggleGeoStamp()\\\"><div class=\\\"tog-knob\\\"></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"geo-status\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\">GPS not yet captured</div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Image Quality</span><span class=\\\"hi-txt\\\">फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Default Photo Quality</span><span class=\\\"hi-txt\\\">डिफ़ॉल्ट फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Applies to all photos — front view, inside view, branding, and additional. HD uses more storage and takes longer to sync on poor networks.</div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;gap:10px;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-compressed\\\" onclick=\\\"setImgQuality('compressed')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-compressed\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-compressed\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">Full Compression</span><span class=\\\"hi-txt\\\">पूर्ण कम्प्रेशन</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~150–200 KB · Max 1280px · Best for poor network</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-left:auto;font-size:11px;font-weight:700;color:var(--gn);background:#dcfce7;padding:3px 8px;border-radius:20px\\\"><span class=\\\"en-txt\\\">Recommended</span><span class=\\\"hi-txt\\\">अनुशंसित</span></div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-hd\\\" onclick=\\\"setImgQuality('hd')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-hd\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-hd\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">HD Quality</span><span class=\\\"hi-txt\\\">HD क्वालिटी</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~400–600 KB · Max 1920px · Better detail for print</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"q-current-badge\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Supervisor Config panel — shown only to supervisors via renderSupPanel() -->\u001b[39m\n\u001b[31m    <div id=\\\"sup-panel\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">🔐 Recce Access Config</span><span class=\\\"hi-txt\\\">🔐 रेकी एक्सेस कॉन्फ़िग</span></div>\u001b[39m\n\u001b[31m      <!-- Access mode — only H/P can change -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"mode-row\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Access Mode</span><span class=\\\"hi-txt\\\">एक्सेस मोड</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Public: any Hub user can submit Recces. Assigned: only Supervisors and Creators can access.</span><span class=\\\"hi-txt\\\">सार्वजनिक: कोई भी Hub यूजर। नियत: सिर्फ़ Supervisors और Creators।</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\" style=\\\"margin-bottom:8px;margin-top:8px\\\">\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-public\\\" onclick=\\\"setRecceMode('public')\\\"><span class=\\\"en-txt\\\">Public</span><span class=\\\"hi-txt\\\">सार्वजनिक</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-assigned\\\" onclick=\\\"setRecceMode('assigned')\\\"><span class=\\\"en-txt\\\">Assigned</span><span class=\\\"hi-txt\\\">नियत</span></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Supervisor list — view all + delete + create -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Supervisors</span><span class=\\\"hi-txt\\\">सुपरवाइजर</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can view all recces, delete with reason, and submit. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">सभी रेकी देख सकते हैं, कारण से हटा सकते हैं, और सबमिट कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"sup-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addSupervisor()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addSupervisor()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Creator list — creation only -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Creators</span><span class=\\\"hi-txt\\\">क्रिएटर्स</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can submit Recces only — no admin view or deletion rights. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">केवल रेकी सबमिट कर सकते हैं — एडमिन व्यू या डिलीट नहीं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"creator-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addCreator()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addCreator()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Client list — used for client portal scoping -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clients</span><span class=\\\"hi-txt\\\">क्लाइंट</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Names that appear as chips when submitting a recce. Add the brand or agency name (e.g. \\\"Marketing Vibe\\\"). These are used to scope what clients see in the Client Portal.</span><span class=\\\"hi-txt\\\">रेकी सबमिट करते समय दिखने वाले क्लाइंट नाम। ब्रांड या एजेंसी नाम जोड़ें।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-mgmt-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"client-add-inp\\\" placeholder=\\\"Client name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addClientToList()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addClientToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Sync to server — only H/P -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"cfg-sync-btn\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Sync Config to Server</span><span class=\\\"hi-txt\\\">सर्वर पर कॉन्फ़िग सिंक करें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Apply supervisor/creator/client lists and access mode to all devices.</span><span class=\\\"hi-txt\\\">सभी डिवाइस पर कॉन्फ़िग लागू करें।</span></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"syncCfgToServer()\\\" style=\\\"max-width:220px;font-size:14px;padding:12px;margin-top:8px\\\"><span class=\\\"en-txt\\\">Sync to Server</span><span class=\\\"hi-txt\\\">सर्वर पर सिंक करें</span></button>\u001b[39m\n\u001b[31m        <div id=\\\"cfg-sync-status\\\" style=\\\"margin-top:8px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Danger Zone</span><span class=\\\"hi-txt\\\">खतरनाक ज़ोन</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\"><div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clear All Local Data</span><span class=\\\"hi-txt\\\">सभी डेटा हटाएं</span></div><div class=\\\"set-sub\\\">Removes all submissions from this device.</div><button class=\\\"btn-d\\\" onclick=\\\"clearData()\\\" style=\\\"padding:9px 14px;font-size:13px\\\">Clear All</button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: STORE INFO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-store\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"exitForm()\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Details</span><span class=\\\"hi-txt\\\">दुकान विवरण</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 1 of 5</span><span class=\\\"hi-txt\\\">चरण 1 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:20%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Recce Info</span><span class=\\\"hi-txt\\\">रेकी जानकारी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Date of Recce</span><span class=\\\"hi-txt\\\">रेकी की तारीख</span> <span class=\\\"req\\\">*</span></label><input type=\\\"date\\\" id=\\\"f-date\\\" onchange=\\\"saveDraft()\\\" max=\\\"\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" id=\\\"campaign-field\\\">\u001b[39m\n\u001b[31m        <label><span class=\\\"en-txt\\\">Job / Campaign</span><span class=\\\"hi-txt\\\">जॉब / कैंपेन</span></label>\u001b[39m\n\u001b[31m        <select id=\\\"f-campaign-id\\\" onchange=\\\"onCampaignSelect()\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">Loading campaigns…</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <div id=\\\"campaign-notify-msg\\\" style=\\\"display:none;font-size:12px;color:#92400e;margin-top:6px;padding:8px 10px;background:#fef3c7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          ⚑ <span class=\\\"en-txt\\\">Recce will submit without a job ID. A notification will flag this for your supervisor to link it later.</span><span class=\\\"hi-txt\\\">रेकी बिना जॉब ID के सबमिट होगी। सुपरवाइजर बाद में लिंक करेगा।</span>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Store</span><span class=\\\"hi-txt\\\">दुकान</span> <span id=\\\"store-avail-tag\\\" style=\\\"font-size:11px;color:var(--g400);font-weight:400;text-transform:none;letter-spacing:0\\\"></span></div>·\u001b[39m\n\u001b[31m      <!-- When store is selected -->\u001b[39m\n\u001b[31m      <div id=\\\"store-selected\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"store-card\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:start;justify-content:space-between;gap:8px\\\">\u001b[39m\n\u001b[31m            <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m              <div class=\\\"store-card-name\\\" id=\\\"sc-name\\\">—</div>\u001b[39m\n\u001b[31m              <div style=\\\"display:flex;align-items:center;gap:6px;margin-top:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m                <span class=\\\"brand-tag\\\" id=\\\"sc-brand\\\">—</span>\u001b[39m\n\u001b[31m                <span class=\\\"last-chip\\\" id=\\\"sc-last\\\" style=\\\"display:none\\\">—</span>\u001b[39m\n\u001b[31m              </div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            <button class=\\\"store-card-change\\\" onclick=\\\"openPicker()\\\"><span class=\\\"en-txt\\\">Change ›</span><span class=\\\"hi-txt\\\">बदलें ›</span></button>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <!-- All fields from Excel shown here -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-details\\\" style=\\\"margin-top:10px;display:flex;flex-direction:column;gap:4px\\\"></div>\u001b[39m\n\u001b[31m          <!-- Missing required fields — editable inline -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-missing\\\" style=\\\"display:none;margin-top:12px;padding-top:12px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m            <div style=\\\"font-size:11px;font-weight:700;color:var(--rd);text-transform:uppercase;letter-spacing:.4px;margin-bottom:10px\\\">⚠ Please complete missing fields</div>\u001b[39m\n\u001b[31m            <div id=\\\"sc-missing-fields\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <!-- Brand selector — shown when store has no brand -->\u001b[39m\n\u001b[31m        <div id=\\\"brand-selector\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\"><span class=\\\"en-txt\\\">Select Brand</span><span class=\\\"hi-txt\\\">ब्रांड चुनें</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\">This store has no brand in the list — select one:</div>\u001b[39m\n\u001b[31m          <div id=\\\"brand-chips\\\" class=\\\"chip-grid\\\"></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Picker trigger (shown when stores loaded) -->\u001b[39m\n\u001b[31m      <div id=\\\"pick-trigger-wrap\\\">\u001b[39m\n\u001b[31m        <div class=\\\"pick-trigger\\\" onclick=\\\"openPicker()\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:center;gap:10px\\\">\u001b[39m\n\u001b[31m            <span style=\\\"font-size:20px\\\">🏪</span>\u001b[39m\n\u001b[31m            <div>\u001b[39m\n\u001b[31m              <div style=\\\"font-size:15px;font-weight:700;color:var(--or)\\\"><span class=\\\"en-txt\\\">Select Store from List</span><span class=\\\"hi-txt\\\">सूची से दुकान चुनें</span></div>\u001b[39m\n\u001b[31m              <div id=\\\"store-avail-count\\\" style=\\\"font-size:12px;font-weight:400;color:var(--am);margin-top:1px\\\"><span class=\\\"en-txt\\\">Tap to browse stores</span><span class=\\\"hi-txt\\\">दुकान खोजने के लिए दबाएं</span></div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual / new store toggle -->\u001b[39m\n\u001b[31m      <div class=\\\"manual-toggle\\\" id=\\\"manual-toggle\\\" onclick=\\\"toggleManual()\\\">\u001b[39m\n\u001b[31m        <svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\" id=\\\"mt-icon\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg>\u001b[39m\n\u001b[31m        <span id=\\\"mt-label\\\"><span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span></span>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual fields -->\u001b[39m\n\u001b[31m      <div id=\\\"manual-fields\\\" style=\\\"display:none;margin-top:14px\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\" style=\\\"margin-bottom:14px\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <select id=\\\"f-brand\\\" onchange=\\\"onManualBrandChange()\\\">\u001b[39m\n\u001b[31m            <option value=\\\"\\\">Select brand</option>\u001b[39m\n\u001b[31m          </select>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span> <span class=\\\"req\\\">*</span></label><input type=\\\"text\\\" id=\\\"f-store\\\" placeholder=\\\"Enter store name\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\">\u001b[39m\n\u001b[31m          <label><span class=\\\"en-txt\\\">Store Address</span><span class=\\\"hi-txt\\\">दुकान का पता</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <textarea id=\\\"f-addr\\\" rows=\\\"2\\\" placeholder=\\\"Full address\\\" onchange=\\\"saveDraft()\\\"></textarea>\u001b[39m\n\u001b[31m          <div class=\\\"gps-row\\\">\u001b[39m\n\u001b[31m            <button class=\\\"gps-btn\\\" onclick=\\\"captureGPS()\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\"/><path d=\\\"M12 2v3M12 19v3M2 12h3M19 12h3\\\"/></svg><span class=\\\"en-txt\\\">Capture GPS</span><span class=\\\"hi-txt\\\">GPS लें</span></button>\u001b[39m\n\u001b[31m            <span id=\\\"gps-status\\\" style=\\\"font-size:12px;color:var(--g500);align-self:center\\\"></span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Mobile No.</span><span class=\\\"hi-txt\\\">मोबाइल नंबर</span></label><input type=\\\"tel\\\" id=\\\"f-mobile\\\" placeholder=\\\"10-digit number\\\" maxlength=\\\"10\\\" inputmode=\\\"numeric\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Client card -->\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Client</span><span class=\\\"hi-txt\\\">क्लाइंट</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\"><span class=\\\"en-txt\\\">Select who this recce is for. Defaults to brand — change if work came via an agency.</span><span class=\\\"hi-txt\\\">यह रेकी किसके लिए है चुनें। ब्रांड से डिफ़ॉल्ट — एजेंसी के ज़रिए हो तो बदलें।</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"cl-chip-grid\\\" id=\\\"client-chips\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"client-other-wrap\\\" style=\\\"display:none;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"f-client-other\\\" placeholder=\\\"Type client name\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" oninput=\\\"onClientOtherInput()\\\">\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-p\\\" onclick=\\\"step2()\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: PHOTOS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-photos\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-store')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Photos</span><span class=\\\"hi-txt\\\">दुकान की फोटो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 2 of 5</span><span class=\\\"hi-txt\\\">चरण 2 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:40%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Front View</span><span class=\\\"hi-txt\\\">आगे का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(min 1, max 3)</span><span class=\\\"cnt-badge gray\\\" id=\\\"front-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"front-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-front\\\" onclick=\\\"addPhoto('front')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Front Photo</span><span class=\\\"hi-txt\\\">आगे की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Inside View</span><span class=\\\"hi-txt\\\">अंदर का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 5)</span><span class=\\\"cnt-badge gray\\\" id=\\\"inside-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"inside-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-inside\\\" onclick=\\\"addPhoto('inside')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Inside Photo</span><span class=\\\"hi-txt\\\">अंदर की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-store')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step3()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: VIDEO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-video\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-photos')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Recce Video</span><span class=\\\"hi-txt\\\">रेकी वीडियो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 3 of 5</span><span class=\\\"hi-txt\\\">चरण 3 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:60%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Video</span><span class=\\\"hi-txt\\\">वीडियो</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Recce video available?</span><span class=\\\"hi-txt\\\">रेकी वीडियो है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"vid-yes\\\" onclick=\\\"setVideo(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"vid-no\\\" onclick=\\\"setVideo(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"vid-sec\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Upload Video</span><span class=\\\"hi-txt\\\">वीडियो अपलोड करें</span></label>\u001b[39m\n\u001b[31m          <div class=\\\"pslot\\\" id=\\\"vid-slot\\\" onclick=\\\"document.getElementById('vid-inp').click()\\\"><div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div></div>\u001b[39m\n\u001b[31m          <input type=\\\"file\\\" id=\\\"vid-inp\\\" accept=\\\"video/*\\\" onchange=\\\"handleVideo(event)\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Video Comments</span><span class=\\\"hi-txt\\\">वीडियो टिप्पणी</span></label><input type=\\\"text\\\" id=\\\"f-vid-cmt\\\" placeholder=\\\"Optional\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-photos')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step4()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: BRANDING -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-branding\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-video')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Branding</span><span class=\\\"hi-txt\\\">ब्रांडिंग</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 4 of 5</span><span class=\\\"hi-txt\\\">चरण 4 / 5</span></div></div></div>\u001b[39m\n\u001b[31m    <span id=\\\"br-hdr-badge\\\" style=\\\"background:rgba(255,255,255,.2);color:#fff;font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px\\\"><span class=\\\"en-txt\\\">0 items</span><span class=\\\"hi-txt\\\">0 आइटम</span></span>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:80%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Branding Space</span><span class=\\\"hi-txt\\\">ब्रांडिंग स्थान</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Space available?</span><span class=\\\"hi-txt\\\">जगह उपलब्ध है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"br-yes\\\" onclick=\\\"setBranding(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"br-no\\\" onclick=\\\"setBranding(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"branding-lock-banner\\\" style=\\\"display:none;background:#fef3c7;border:1.5px solid #f59e0b;border-radius:10px;padding:12px 14px;margin-bottom:10px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:700;color:#92400e\\\">Client approval exists — branding locked</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:#78350f;margin-top:4px\\\"><span class=\\\"en-txt\\\">The client has reviewed this recce. Create a new recce to revise branding items.</span><span class=\\\"hi-txt\\\">क्लाइंट ने रेकी की समीक्षा की है। बदलाव के लिए नई रेकी बनाएं।</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"branding-override-wrap\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m        <button onclick=\\\"unlockBrandingOverride()\\\" style=\\\"background:#f59e0b;color:#000;border:none;border-radius:8px;padding:8px 14px;font-size:12px;font-weight:700;cursor:pointer\\\">Override Edit (H&amp;P only)</button>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:11px;color:#92400e;margin-top:5px\\\">Use only when client has verbally confirmed and app needs correction.</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"br-items\\\"></div>\u001b[39m\n\u001b[31m    <div id=\\\"br-add\\\" style=\\\"display:none;margin-bottom:80px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"addBranding()\\\" style=\\\"width:100%;justify-content:center\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Another Branding Item</span><span class=\\\"hi-txt\\\">एक और ब्रांडिंग जोड़ें</span></button>\u001b[39m\n\u001b[31m      <div style=\\\"text-align:center;font-size:12px;color:var(--g400);margin-top:8px\\\"><span class=\\\"en-txt\\\">Tap Continue below when done adding items</span><span class=\\\"hi-txt\\\">सभी आइटम जोड़ने के बाद आगे दबाएं</span></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-video')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step5()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: ADDITIONAL + SUBMIT -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-additional\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-branding')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Submit</span><span class=\\\"hi-txt\\\">सबमिट</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 5 of 5</span><span class=\\\"hi-txt\\\">चरण 5 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:100%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Mandatory Document</span><span class=\\\"hi-txt\\\">अनिवार्य दस्तावेज़</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"pslot\\\" id=\\\"doc-slot\\\" onclick=\\\"document.getElementById('doc-inp').click()\\\"><div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div></div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"doc-inp\\\" accept=\\\"image/*,.pdf\\\" onchange=\\\"handleDoc(event)\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Additional Photos</span><span class=\\\"hi-txt\\\">अतिरिक्त फोटो</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 8)</span><span class=\\\"cnt-badge gray\\\" id=\\\"addl-badge\\\">0 / 8</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"add-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-addl\\\" onclick=\\\"addAdditional()\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\"><div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Review</span><span class=\\\"hi-txt\\\">समीक्षा</span></div><div id=\\\"rev-body\\\"></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-branding')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"submitRecce()\\\" id=\\\"sub-btn\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Submit Recce ✓</span><span class=\\\"hi-txt\\\">रेकी सबमिट करें ✓</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- ANNOTATION MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"annot-modal\\\" id=\\\"annot-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"annot-bar\\\">\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Draw:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"at-rect\\\"    onclick=\\\"setATool('rect')\\\">▭ Rect</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-ellipse\\\" onclick=\\\"setATool('ellipse')\\\">◯ Ellipse</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-line\\\"    onclick=\\\"setATool('line')\\\">╱ Line</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-arrow\\\"   onclick=\\\"setATool('arrow')\\\">↗ Arrow</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-free\\\"    onclick=\\\"setATool('free')\\\">✏ Free</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool sel-on\\\" id=\\\"at-move\\\" onclick=\\\"setATool('move')\\\" style=\\\"margin-left:4px\\\">⊹ Move</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Color:</span>\u001b[39m\n\u001b[31m      <div class=\\\"acolor on\\\" id=\\\"ac-or\\\" style=\\\"background:#f97316\\\" onclick=\\\"setAColor('#f97316')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-rd\\\" style=\\\"background:#ef4444\\\" onclick=\\\"setAColor('#ef4444')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-wh\\\" style=\\\"background:#ffffff\\\" onclick=\\\"setAColor('#ffffff')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-yw\\\" style=\\\"background:#facc15\\\" onclick=\\\"setAColor('#facc15')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-gn\\\" style=\\\"background:#22c55e\\\" onclick=\\\"setAColor('#22c55e')\\\"></div>\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Width:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-2\\\" onclick=\\\"setAWidth(2)\\\" style=\\\"padding:5px 8px\\\">Thin</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"aw-4\\\" onclick=\\\"setAWidth(4)\\\" style=\\\"padding:5px 8px\\\">Med</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-7\\\" onclick=\\\"setAWidth(7)\\\" style=\\\"padding:5px 8px\\\">Thick</button>\u001b[39m\n\u001b[31m      <div style=\\\"flex:1\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"undoAnnot()\\\">↩</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"clearAnnot()\\\">✕</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"annot-sel-info\\\" style=\\\"display:none;font-size:11px;color:#facc15;padding:4px 0 2px\\\">\u001b[39m\n\u001b[31m      Shape selected — drag to move · drag corners to resize · tap elsewhere to deselect\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-cvs-wrap\\\"><canvas id=\\\"annot-cvs\\\"></canvas></div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-foot\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-s\\\" onclick=\\\"skipAnnot()\\\" style=\\\"flex:1;padding:12px;font-size:14px\\\"><span class=\\\"en-txt\\\">Skip markup</span><span class=\\\"hi-txt\\\">मार्कअप छोड़ें</span></button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" onclick=\\\"saveAnnot()\\\" style=\\\"flex:2;padding:12px\\\"><span class=\\\"en-txt\\\">Done — Save ✓</span><span class=\\\"hi-txt\\\">हो गया — सेव करें ✓</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EXIT DIALOG -->\u001b[39m\n\u001b[31m<!-- MODAL: Link Job to Recce (supervisor only) -->\u001b[39m\n\u001b[31m<div id=\\\"modal-link-job\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m  <div style=\\\"background:#fff;border-radius:14px;padding:20px;width:90%;max-width:380px;display:flex;flex-direction:column;gap:12px;box-shadow:0 8px 32px rgba(0,0,0,.35)\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:15px;font-weight:700;color:#1e293b\\\">&#x1F517; Link Job to Recce</div>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-store\\\" style=\\\"font-size:13px;color:#64748b\\\"></div>\u001b[39m\n\u001b[31m    <select id=\\\"link-job-sel\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m      <option value=\\\"\\\">&#x2014; Select campaign &#x2014;</option>\u001b[39m\n\u001b[31m    </select>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-err\\\" style=\\\"font-size:12px;color:#ef4444;min-height:14px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"closeLinkJobModal()\\\" style=\\\"flex:1;padding:12px;border:1px solid #cbd5e1;border-radius:8px;cursor:pointer;background:#f8fafc;font-size:14px\\\">Cancel</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"saveLinkJob()\\\" style=\\\"flex:2;padding:12px;background:#f59e0b;color:#000;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:700\\\">&#x1F517; Link Job</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"exit-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Exit Recce?</span><span class=\\\"hi-txt\\\">रेकी से बाहर?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Your progress and photos will be saved as a draft. Resume anytime from the home screen.</span><span class=\\\"hi-txt\\\">आपकी प्रगति और फोटो ड्राफ्ट में सेव होंगी। होम स्क्रीन से कभी भी जारी रखें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"exitSaveAndLeave()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">💾 Save Draft & Exit</span><span class=\\\"hi-txt\\\">💾 ड्राफ्ट सेव करें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-d\\\" onclick=\\\"exitDiscard()\\\" style=\\\"flex:1;padding:13px;font-size:13px\\\"><span class=\\\"en-txt\\\">Discard</span><span class=\\\"hi-txt\\\">हटाएं</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"exitCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">← Continue Recce</span><span class=\\\"hi-txt\\\">← रेकी जारी रखें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- PHOTO SOURCE PICKER -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"photo-src-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Camera photos get GPS stamp baked in. Gallery photos are added without stamp.</span><span class=\\\"hi-txt\\\">कैमरा फोटो में GPS स्टैम्प लगती है। गैलरी फोटो में नहीं।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"photoSrcCamera()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">📷 Use Camera</span><span class=\\\"hi-txt\\\">📷 कैमरा</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">GPS stamp applied</span><span class=\\\"hi-txt\\\">GPS स्टैम्प लगेगी</span></span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"photoSrcGallery()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">🖼 Choose from Gallery</span><span class=\\\"hi-txt\\\">🖼 गैलरी से चुनें</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">No stamp</span><span class=\\\"hi-txt\\\">स्टैम्प नहीं</span></span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"photoSrcCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- STORE PREVIEW DIALOG -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"store-preview-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:80vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"store-preview-title\\\"><span class=\\\"en-txt\\\">Preview Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची का प्रीव्यू</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Review before adding to your store list:</span><span class=\\\"hi-txt\\\">जोड़ने से पहले जाँचें:</span></div>\u001b[39m\n\u001b[31m    <div style=\\\"overflow-x:auto;margin-bottom:14px\\\">\u001b[39m\n\u001b[31m      <table style=\\\"width:100%;border-collapse:collapse;font-size:12px\\\">\u001b[39m\n\u001b[31m        <thead><tr style=\\\"background:var(--nv);color:#fff\\\">\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Address</span><span class=\\\"hi-txt\\\">पता</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Mobile</span><span class=\\\"hi-txt\\\">मोबाइल</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span></th>\u001b[39m\n\u001b[31m        </tr></thead>\u001b[39m\n\u001b[31m        <tbody id=\\\"store-preview-body\\\"></tbody>\u001b[39m\n\u001b[31m      </table>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"confirmStorePreview()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">✓ Confirm & Add Stores</span><span class=\\\"hi-txt\\\">✓ स्टोर जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"cancelStorePreview()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BOTTOM DIALOG (branding additional photo prompt) -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"bdialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add reference photos?</span><span class=\\\"hi-txt\\\">संदर्भ फोटो जोड़ें?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Add extra photos for this branding item for future reference.</span><span class=\\\"hi-txt\\\">इस ब्रांडिंग आइटम के लिए अतिरिक्त फोटो जोड़ें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"bdialogYes()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">Yes, add photos</span><span class=\\\"hi-txt\\\">हाँ, जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"bdialogNo()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Skip</span><span class=\\\"hi-txt\\\">छोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- DELETE REASON MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"delete-reason-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"padding-bottom:28px;max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">🗑 Delete Recce</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"del-modal-sub\\\">Select reason for deletion:</div>\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-wrong\\\" onclick=\\\"selectDeleteReason('wrong')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">❌</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Wrong</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Incorrect store / submission error</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-duplicate\\\" onclick=\\\"selectDeleteReason('duplicate')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">📋</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Duplicate</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Same store submitted more than once</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt danger\\\" id=\\\"reason-test\\\" onclick=\\\"selectDeleteReason('test')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">⚠️</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Test Recce</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:#9a3412;margin-top:2px\\\">Permanently deleted — no audit trail</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p no-reason\\\" id=\\\"del-confirm-btn\\\" onclick=\\\"confirmDelete()\\\" style=\\\"flex:2;padding:13px;background:var(--rd)\\\">Delete</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"closeDeleteModal()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EDIT REQUEST MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"edit-req-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Request Edit</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"er-store-name\\\" style=\\\"font-weight:600;color:var(--nv);margin-bottom:4px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:14px\\\">Add a note for the creator (optional)</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m      <textarea id=\\\"er-comment\\\" placeholder=\\\"e.g. Please re-check store address and re-upload front photo\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;color:var(--nv);resize:vertical;min-height:80px;background:#fff\\\"></textarea>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button id=\\\"er-assign-btn\\\" class=\\\"btn-p\\\" onclick=\\\"assignEditToCreator()\\\" style=\\\"padding:14px\\\">👤 Assign to Creator</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"supervisorEditMyself()\\\" style=\\\"padding:14px\\\">✏ Edit Myself</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"closeEditRequestModal()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BRAND EDIT MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"brand-edit-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Edit Brand</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Brand Name <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"text\\\" id=\\\"be-name\\\" placeholder=\\\"e.g. PHILIPS\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:600;text-transform:uppercase\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Logo URL <span style=\\\"font-size:11px;font-weight:400;color:var(--g400)\\\">(optional)</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"url\\\" id=\\\"be-logo\\\" placeholder=\\\"https://…/logo.svg\\\" oninput=\\\"previewBrandLogo()\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px\\\">\u001b[39m\n\u001b[31m      <div id=\\\"be-logo-preview\\\" style=\\\"margin-top:8px;min-height:36px;display:flex;align-items:center;gap:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"be-cascade-info\\\" style=\\\"display:none;font-size:12px;color:var(--g500);padding:8px 12px;background:var(--g50);border-radius:var(--rs);margin-bottom:12px\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"saveBrandEdit()\\\" style=\\\"padding:14px\\\">Save</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"closeBrandEditModal()\\\" style=\\\"width:100%;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FONT SIZE WIDGET -->\u001b[39m\n\u001b[31m<div class=\\\"fs-widget\\\" id=\\\"fs-widget\\\">\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-dec\\\" onclick=\\\"changeFontSize(-1)\\\" title=\\\"Decrease font size\\\" aria-label=\\\"Decrease font size\\\">A<sup style=\\\"font-size:9px\\\">−</sup></button>\u001b[39m\n\u001b[31m  <span class=\\\"fs-label\\\" id=\\\"fs-lbl\\\">A</span>\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-inc\\\" onclick=\\\"changeFontSize(1)\\\" title=\\\"Increase font size\\\" aria-label=\\\"Increase font size\\\"><strong>A</strong><sup style=\\\"font-size:9px\\\">+</sup></button>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"upd-banner\\\" id=\\\"upd-banner\\\">\u001b[39m\n\u001b[31m  <span style=\\\"font-size:13px;font-weight:600;line-height:1.4\\\"><span class=\\\"en-txt\\\">✓ App updated to latest version</span><span class=\\\"hi-txt\\\">✓ ऐप नया संस्करण अपडेट हुआ</span></span>\u001b[39m\n\u001b[31m  <button class=\\\"upd-banner-ok\\\" onclick=\\\"dismissUpdateBanner()\\\"><span class=\\\"en-txt\\\">OK</span><span class=\\\"hi-txt\\\">ठीक है</span></button>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m<div class=\\\"toast\\\" id=\\\"toast\\\"></div>\u001b[39m\n\u001b[31m<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js\\\"></script>\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m// LANGUAGE\u001b[39m\n\u001b[31mlet LANG = localStorage.getItem('recce-lang') || 'en';\u001b[39m\n\u001b[31mfunction setLang(l) {\u001b[39m\n\u001b[31m  LANG = l;\u001b[39m\n\u001b[31m  localStorage.setItem('recce-lang', l);\u001b[39m\n\u001b[31m  document.body.classList.toggle('lang-hi', l === 'hi');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction t(en, hi) { return LANG === 'hi' ? hi : en; }·\u001b[39m\n\u001b[31m// FONT SIZE\u001b[39m\n\u001b[31mlet FS_LEVEL = parseInt(localStorage.getItem('recce-fs') || '0', 10);\u001b[39m\n\u001b[31mconst FS_LABELS = ['A', 'A+', 'A++', 'A+++', 'A++++'];\u001b[39m\n\u001b[31mfunction applyFontSize() {\u001b[39m\n\u001b[31m  document.body.classList.remove('fs-0', 'fs-1', 'fs-2');\u001b[39m\n\u001b[31m  if (FS_LEVEL > 0) document.body.classList.add('fs-' + FS_LEVEL);\u001b[39m\n\u001b[31m  const lbl = document.getElementById('fs-lbl');\u001b[39m\n\u001b[31m  if (lbl) lbl.textContent = FS_LABELS[FS_LEVEL];\u001b[39m\n\u001b[31m  const dec = document.getElementById('fs-dec');\u001b[39m\n\u001b[31m  const inc = document.getElementById('fs-inc');\u001b[39m\n\u001b[31m  if (dec) dec.disabled = FS_LEVEL === 0;\u001b[39m\n\u001b[31m  if (inc) inc.disabled = FS_LEVEL === 4;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction changeFontSize(delta) {\u001b[39m\n\u001b[31m  FS_LEVEL = Math.min(4, Math.max(0, FS_LEVEL + delta));\u001b[39m\n\u001b[31m  localStorage.setItem('recce-fs', FS_LEVEL);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Hub auth gate\u001b[39m\n\u001b[31m(function() {\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (!s || !s.loginAt || Date.now() - new Date(s.loginAt).getTime() > 12 * 3600 * 1000) {\u001b[39m\n\u001b[31m      window.location.replace('/hub/');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) { window.location.replace('/hub/'); }\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31m// STATE\u001b[39m\n\u001b[31mlet F={},frontPhotos=[],insidePhotos=[],addlPhotos=[],brandings=[];\u001b[39m\n\u001b[31mlet videoBlob=null,submissionDoc=null,_docExistingUrl=null,gpsCoords=null;\u001b[39m\n\u001b[31mlet stores=[],selectedStore=null,manualMode=false,DB;\u001b[39m\n\u001b[31mlet imgQuality='compressed'; // 'compressed' | 'hd'\u001b[39m\n\u001b[31mlet geoStampEnabled=true;    // stamp GPS+timestamp on every photo\u001b[39m\n\u001b[31mlet brands=['PHILIPS']; // editable brand list\u001b[39m\n\u001b[31mlet _brandLogos={};   // name → logo_url, loaded from DB\u001b[39m\n\u001b[31mlet _selectedClient=''; // currently selected client chip value\u001b[39m\n\u001b[31mlet _clientOtherMode=false; // true when \\\"Other\\\" chip selected\u001b[39m\n\u001b[31mconst BTYPE=['Glow Sign Board','Inshop Branding','ACP Board','One Way Vision','Fabric Board','Lollypop','Non Lit Flex','Double Side GSB','Clip on Board','Translit','Vinyl Printing','Roll up Standee','Sunboard Standee'];\u001b[39m\n\u001b[31mconst CACHE_VER='recce-v37'; // campaign dropdown + pending job link tab·\u001b[39m\n\u001b[31m// DB\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',3);r.onupgradeneeded=e=>{const d=e.target.result;['subs','cfg','draft'].forEach(s=>{if(!d.objectStoreNames.contains(s))d.createObjectStore(s,{keyPath:'k'||'id'});});if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);});}\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',4);r.onupgradeneeded=e=>{const d=e.target.result;if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);})}\u001b[39m\n\u001b[31mfunction dbGet(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).get(k);r.onsuccess=()=>res(r.result);r.onerror=()=>res(null);}catch{res(null)}})}\u001b[39m\n\u001b[31mfunction dbPut(s,v){return new Promise((res,rej)=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).put(v);r.onsuccess=()=>res();r.onerror=()=>rej();}catch(e){rej(e)}})}\u001b[39m\n\u001b[31mfunction dbAll(s){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).getAll();r.onsuccess=()=>res(r.result);r.onerror=()=>res([]);}catch{res([])}})}\u001b[39m\n\u001b[31mfunction dbDel(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).delete(k);r.onsuccess=()=>res();r.onerror=()=>res();}catch{res()}})}\u001b[39m\n\u001b[31masync function cfg(k,v){if(v===undefined){const r=await dbGet('cfg',k);return r?r.v:null;}await dbPut('cfg',{k,v});}·\u001b[39m\n\u001b[31m// COMPRESS — respects imgQuality setting\u001b[39m\n\u001b[31mfunction compress(file, maxPxOverride, qOverride){\u001b[39m\n\u001b[31m  const maxPx = maxPxOverride || (imgQuality==='hd' ? 1920 : 1280);\u001b[39m\n\u001b[31m  const q     = qOverride     || (imgQuality==='hd' ? 0.90 : 0.78);\u001b[39m\n\u001b[31m  return new Promise(res=>{const img=new Image(),url=URL.createObjectURL(file);img.onload=()=>{const sc=Math.min(1,maxPx/Math.max(img.width,img.height));const c=document.createElement('canvas');c.width=Math.round(img.width*sc);c.height=Math.round(img.height*sc);c.getContext('2d').drawImage(img,0,0,c.width,c.height);URL.revokeObjectURL(url);c.toBlob(b=>res(b),'image/jpeg',q);};img.onerror=()=>{URL.revokeObjectURL(url);res(file)};img.src=url;});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction b64(blob){return new Promise(res=>{const r=new FileReader();r.onload=()=>res(r.result);r.readAsDataURL(blob)})}\u001b[39m\n\u001b[31mfunction fmtSz(b){if(b<1024)return b+'B';if(b<1048576)return(b/1024).toFixed(0)+'KB';return(b/1048576).toFixed(1)+'MB'}·\u001b[39m\n\u001b[31m// STORE LIST\u001b[39m\n\u001b[31mlet _storeFiles=[]; // track uploaded files {name, brand, count}\u001b[39m\n\u001b[31mlet _pendingParse=null; // parsed rows waiting for brand assignment·\u001b[39m\n\u001b[31mfunction parseStoreRow(row, keyFn){\u001b[39m\n\u001b[31m  const v=k=>{\u001b[39m\n\u001b[31m    // Try exact match first, then partial\u001b[39m\n\u001b[31m    const exactKey=Object.keys(row||{}).find(hk=>hk.toLowerCase()===k);\u001b[39m\n\u001b[31m    const partKey=Object.keys(row||{}).find(hk=>hk.toLowerCase().includes(k));\u001b[39m\n\u001b[31m    const useKey=exactKey||partKey;\u001b[39m\n\u001b[31m    if(useKey)return row[useKey]!=null?row[useKey].toString().trim():'';\u001b[39m\n\u001b[31m    // CSV path: keyFn provides value directly\u001b[39m\n\u001b[31m    const col=keyFn(k);return col!=null?col.toString().trim():'';\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const name    = v('sub dealer name')||v('sub dealer')||v('dealer name')||v('store name')||v('store')||v('name');\u001b[39m\n\u001b[31m  const address = v('address')||v('addr')||v('location')||v('area');\u001b[39m\n\u001b[31m  // Contact Detail often stored as a number — toString handles it\u001b[39m\n\u001b[31m  const rawMob  = v('contact detail')||v('contact no.')||v('contact no')||v('mobile no')||v('mobile')||v('phone')||v('mob')||v('contact');\u001b[39m\n\u001b[31m  const mobile  = rawMob.replace(/\\\\D/g,'').slice(-10);\u001b[39m\n\u001b[31m  // Brand: EXACT match only — \\\"Brand\\\" or \\\"Brand Name\\\" columns\u001b[39m\n\u001b[31m  // Partial match is intentionally avoided here because \\\"Inshop Branding\\\" contains \\\"brand\\\"\u001b[39m\n\u001b[31m  const brandKey=Object.keys(row||{}).find(hk=>{\u001b[39m\n\u001b[31m    const lk=hk.toLowerCase().trim();\u001b[39m\n\u001b[31m    return lk==='brand'||lk==='brand name'||lk==='brand_name'||lk==='brandname';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const brand=brandKey?(row[brandKey]||'').toString().trim().toUpperCase():'';\u001b[39m\n\u001b[31m  const distName= v('dist name')||v('distributor name')||v('distributor')||v('dist')||v('territory')||v('tsm')||v('asm');\u001b[39m\n\u001b[31m  const city    = v('city')||v('district')||v('town');\u001b[39m\n\u001b[31m  const sales   = v('2025 full year')||v('2025')||v('full year sales')||v('fy25')||v('sales');\u001b[39m\n\u001b[31m  const proj    = v('2026 projection')||v('2026')||v('projection')||v('fy26')||v('target');\u001b[39m\n\u001b[31m  const glowSign= v('glow sign')||v('glow');\u001b[39m\n\u001b[31m  const inshop  = v('inshop branding')||v('inshop')||v('in-shop')||v('in shop');\u001b[39m\n\u001b[31m  return {name, brand, address, mobile, distName, city, sales, proj, glowSign, inshop};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction dedupeStores(list){\u001b[39m\n\u001b[31m  const seen=new Map();\u001b[39m\n\u001b[31m  list.forEach(s=>{\u001b[39m\n\u001b[31m    // Include address in key — same store name at different locations = different stores\u001b[39m\n\u001b[31m    const key=(s.name.toLowerCase().trim())+'__'+(s.brand||'').toLowerCase()\u001b[39m\n\u001b[31m              +'__'+(s.address||'').toLowerCase().trim().slice(0,30);\u001b[39m\n\u001b[31m    if(!seen.has(key))seen.set(key,s);\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // True duplicate — merge missing fields from second record\u001b[39m\n\u001b[31m      const ex=seen.get(key);\u001b[39m\n\u001b[31m      Object.keys(s).forEach(k=>{ if(!ex[k]&&s[k])ex[k]=s[k]; });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  return Array.from(seen.values());\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderStoreFileList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-file-list');if(!el)return;\u001b[39m\n\u001b[31m  if(!_storeFiles.length){el.innerHTML='';return;}\u001b[39m\n\u001b[31m  el.innerHTML=_storeFiles.map((f,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:5px;font-size:12px\\\">\u001b[39m\n\u001b[31m      <div>\u001b[39m\n\u001b[31m        <span style=\\\"font-weight:600;color:var(--nv)\\\">${f.name}</span>\u001b[39m\n\u001b[31m        <span style=\\\"color:var(--g500);margin-left:6px\\\">${f.count} stores</span>\u001b[39m\n\u001b[31m        ${f.brand?`<span style=\\\"background:var(--nv);color:#fff;font-size:10px;font-weight:700;padding:1px 7px;border-radius:20px;margin-left:5px\\\">${f.brand}</span>`:'<span style=\\\"background:var(--g300);color:var(--g600);font-size:10px;padding:1px 7px;border-radius:20px;margin-left:5px\\\">Mixed brands</span>'}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <button onclick=\\\"removeStoreFile(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:17px;cursor:pointer;padding:0 4px;line-height:1\\\">×</button>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function removeStoreFile(i){\u001b[39m\n\u001b[31m  _storeFiles.splice(i,1);\u001b[39m\n\u001b[31m  // Rebuild stores from remaining files — re-parse from cache not possible, so just reload from DB and remove this file's contribution\u001b[39m\n\u001b[31m  // Simplest approach: clear and ask user to re-upload remaining files\u001b[39m\n\u001b[31m  if(!_storeFiles.length){stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    // Can't re-parse without original files; just note it and keep current store list\u001b[39m\n\u001b[31m    toast('Removed from list. Re-upload the remaining files to refresh store list.','info');\u001b[39m\n\u001b[31m    _storeFiles.splice(0); // clear tracking since we can't reconstruct\u001b[39m\n\u001b[31m    stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderStoreFileList();\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=stores.length?`✓ ${stores.length} stores`:'No stores loaded';\u001b[39m\n\u001b[31m  updAvailTag();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function clearStoreList(){\u001b[39m\n\u001b[31m  if(!confirm('Remove all loaded stores?'))return;\u001b[39m\n\u001b[31m  stores=[];_storeFiles=[];\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent='';\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast('Store list cleared','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function handleStoreUpload(e){\u001b[39m\n\u001b[31m  const file=e.target.files[0];if(!file)return;\u001b[39m\n\u001b[31m  e.target.value=''; // allow same file re-upload\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    let data=[];\u001b[39m\n\u001b[31m    if(file.name.toLowerCase().endsWith('.csv')){\u001b[39m\n\u001b[31m      const txt=await file.text();\u001b[39m\n\u001b[31m      const rows=txt.split('\\\\n').map(r=>r.split(',').map(c=>c.trim().replace(/^\\\"|\\\"$/g,'')));\u001b[39m\n\u001b[31m      if(!rows.length||!rows[0].length){toast('Empty CSV','error');return;}\u001b[39m\n\u001b[31m      const h=rows[0];\u001b[39m\n\u001b[31m      data=rows.slice(1).filter(r=>r.length>1&&r.some(c=>c)).map(r=>{\u001b[39m\n\u001b[31m        const rowObj={};h.forEach((hk,i)=>{rowObj[hk]=r[i]||'';});\u001b[39m\n\u001b[31m        return parseStoreRow(rowObj, ()=>'');\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }else{\u001b[39m\n\u001b[31m      const ab=await file.arrayBuffer();const wb=XLSX.read(ab,{type:'array'});\u001b[39m\n\u001b[31m      const js=XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]],{defval:''});\u001b[39m\n\u001b[31m      data=js.map(row=>parseStoreRow(row,()=>''));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    data=data.filter(d=>d.name.trim());\u001b[39m\n\u001b[31m    if(!data.length){toast('No valid rows found in file','error');return;}\u001b[39m\n\u001b[31m    // Check if any store has a brand\u001b[39m\n\u001b[31m    const hasBrand=data.some(d=>d.brand);\u001b[39m\n\u001b[31m    // Always show preview first before merging\u001b[39m\n\u001b[31m    _pendingParse={file:file.name,data,hasBrand};\u001b[39m\n\u001b[31m    showStorePreview(file.name, data, hasBrand);\u001b[39m\n\u001b[31m  }catch(err){toast('Failed: '+err.message,'error')}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mlet _pendingBrand='';\u001b[39m\n\u001b[31mfunction setPendingBrand(b){\u001b[39m\n\u001b[31m  _pendingBrand=b;\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-assign-chips .chip').forEach(c=>{\u001b[39m\n\u001b[31m    c.classList.toggle('sel',c.textContent===b);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  if(!_pendingBrand){toast('Select a brand first','error');return;}\u001b[39m\n\u001b[31m  // Assign brand to all rows in this file\u001b[39m\n\u001b[31m  const data=_pendingParse.data.map(s=>({...s,brand:_pendingBrand}));\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, data, _pendingBrand);\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function skipBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, _pendingParse.data, '');\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showStorePreview(filename, data, hasBrand){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-preview-dialog');\u001b[39m\n\u001b[31m  const tbody=document.getElementById('store-preview-body');\u001b[39m\n\u001b[31m  document.getElementById('store-preview-title').textContent=`${filename} · ${data.length} ${t('stores found','स्टोर मिले')}`;\u001b[39m\n\u001b[31m  // Show first 8 rows\u001b[39m\n\u001b[31m  const sample=data.slice(0,8);\u001b[39m\n\u001b[31m  tbody.innerHTML=sample.map(s=>`<tr>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;font-weight:500\\\">${s.name||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.address||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.mobile||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px\\\"><span style=\\\"background:${s.brand?'var(--nv)':'var(--rd)'};color:#fff;padding:1px 7px;border-radius:10px;font-size:10px\\\">${s.brand||'?'}</span></td>\u001b[39m\n\u001b[31m  </tr>`).join('');\u001b[39m\n\u001b[31m  if(data.length>8)tbody.innerHTML+=`<tr><td colspan=\\\"4\\\" style=\\\"text-align:center;padding:8px;font-size:12px;color:var(--g400)\\\">…and ${data.length-8} more stores</td></tr>`;\u001b[39m\n\u001b[31m  el.classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function confirmStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  const {file,data,hasBrand}=_pendingParse;\u001b[39m\n\u001b[31m  if(!hasBrand){\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-fname').textContent=`File: ${file} · ${data.length} stores found · No brand column detected`;\u001b[39m\n\u001b[31m    const chips=document.getElementById('brand-assign-chips');\u001b[39m\n\u001b[31m    chips.innerHTML=brands.map(b=>`<div class=\\\"chip\\\" onclick=\\\"setPendingBrand('${b}')\\\" id=\\\"bac-${b}\\\">${b}</div>`).join('');\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').style.display='block';\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    await mergeStores(file, data, '');\u001b[39m\n\u001b[31m    _pendingParse=null;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction cancelStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingParse=null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function mergeStores(filename, newData, assignedBrand){\u001b[39m\n\u001b[31m  const before=stores.length;\u001b[39m\n\u001b[31m  stores=[...stores,...newData];\u001b[39m\n\u001b[31m  stores=dedupeStores(stores);\u001b[39m\n\u001b[31m  const added=stores.length-before;\u001b[39m\n\u001b[31m  const dupes=newData.length-added;\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify(stores));\u001b[39m\n\u001b[31m  // Track file\u001b[39m\n\u001b[31m  _storeFiles.push({name:filename,count:newData.length,brand:assignedBrand||''});\u001b[39m\n\u001b[31m  await cfg('store-files',JSON.stringify(_storeFiles));\u001b[39m\n\u001b[31m  const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m    `✓ ${stores.length} total stores${dupes>0?` · ${dupes} duplicate${dupes>1?'s':''} removed`:''}${noBrand?` · ${noBrand} without brand`:' · All have brand'}`;\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast(`${added} stores added${dupes>0?`, ${dupes} duplicates skipped`:''}${assignedBrand?' as '+assignedBrand:''}`, 'success');\u001b[39m\n\u001b[31m  // Show server-push button for supervisors\u001b[39m\n\u001b[31m  const pb = document.getElementById('store-push-btn');\u001b[39m\n\u001b[31m  if (pb) pb.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function fetchServerStores(){const url=document.getElementById('srv-url').value.trim();if(!url){toast('Enter a URL first','error');return;}try{toast('Fetching…','info');const r=await fetch(url);const j=await r.json();const fetched=Array.isArray(j)?j:j.stores||[];await mergeStores('Server ('+url.split('/').pop()+')',fetched,'');await cfg('srv-url',url);}catch{toast('Fetch failed — check URL','error')}}\u001b[39m\n\u001b[31masync function saveServerUrl(){await cfg('srv-url',document.getElementById('srv-url').value.trim());toast('URL saved','success')}\u001b[39m\n\u001b[31mconst DEFAULT_GAS_URL='https://script.google.com/macros/s/AKfycbwyufC7gQyu1BErCxiDlbQUn0AWiIWv7nEmjk4UcAx3dvlV6bGk7q5fQOiv82CTbokbkA/exec';·\u001b[39m\n\u001b[31mconst DEFAULT_STORES_URL='/recce/stores.json';\u001b[39m\n\u001b[31mconst _RECCE_CFG_URL='/recce/recce-cfg.json';·\u001b[39m\n\u001b[31m// Admin auto-unlock for harish/pramod via hub session\u001b[39m\n\u001b[31mconst _RECCE_ADMIN_IDS = ['harish', 'pramod', 'rakesh'];\u001b[39m\n\u001b[31mconst _RECCE_CFG_ADMINS = ['harish', 'pramod'];\u001b[39m\n\u001b[31mlet _adminRows = [];\u001b[39m\n\u001b[31mlet _myServerRows = [];\u001b[39m\n\u001b[31mlet _adminUnlocked = false;\u001b[39m\n\u001b[31mlet _recceCfg = { version: 1, supervisors: ['harish','pramod','rakesh'], mode: 'public', creators: [], allowed_users: [] };\u001b[39m\n\u001b[31mfunction _isSupervisor() {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  return !!(hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId));\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _showDeletedView = false;\u001b[39m\n\u001b[31mlet _supCreateMode = false;\u001b[39m\n\u001b[31mlet _pendingDeleteId = null;\u001b[39m\n\u001b[31mlet _pendingDeleteReason = null;\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (s?.empId && _RECCE_ADMIN_IDS.includes(s.empId)) _adminUnlocked = true;\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31masync function loadRecceCfg(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(_RECCE_CFG_URL + '?t=' + Date.now());\u001b[39m\n\u001b[31m    if (r.ok) {\u001b[39m\n\u001b[31m      const j = await r.json();\u001b[39m\n\u001b[31m      if (j && j.version) {\u001b[39m\n\u001b[31m        _recceCfg = j;\u001b[39m\n\u001b[31m        if (Array.isArray(j.supervisors) && j.supervisors.length) {\u001b[39m\n\u001b[31m          _recceCfg.supervisors = j.supervisors;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.creators)) _recceCfg.creators = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.allowed_users)) _recceCfg.allowed_users = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.clients)) _recceCfg.clients = [];\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  // Re-check admin status against server supervisor list\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId)) {\u001b[39m\n\u001b[31m    _adminUnlocked = true;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _checkAccessMode(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (_recceCfg.mode !== 'assigned') return;\u001b[39m\n\u001b[31m  const allowed = [\u001b[39m\n\u001b[31m    ...(_recceCfg.supervisors || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.creators || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.allowed_users || []),\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  if (hub?.empId && allowed.includes(hub.empId)) return;\u001b[39m\n\u001b[31m  // Block access — show locked overlay\u001b[39m\n\u001b[31m  document.body.innerHTML = `<div style=\\\"min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0f172a;color:#fff;padding:32px;text-align:center\\\"><div style=\\\"font-size:48px;margin-bottom:16px\\\">🔒</div><div style=\\\"font-size:20px;font-weight:700;margin-bottom:8px\\\">${t('Access Restricted','एक्सेस प्रतिबंधित')}</div><div style=\\\"font-size:14px;color:#94a3b8\\\">${t('You are not authorised to use Branding Recce. Please contact your supervisor.','आप ब्रांडिंग रेक्की उपयोग के लिए अधिकृत नहीं हैं।')}</div></div>`;\u001b[39m\n\u001b[31m  throw new Error('access-restricted');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _recceHubUser() {\u001b[39m\n\u001b[31m  try { return JSON.parse(localStorage.getItem('lm360-session') || '{}'); }\u001b[39m\n\u001b[31m  catch(_) { return {}; }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── Supervisor config management ────────────────────────────────────\u001b[39m\n\u001b[31mfunction renderSupPanel(){\u001b[39m\n\u001b[31m  if (!_adminUnlocked) return;\u001b[39m\n\u001b[31m  const panel = document.getElementById('sup-panel');\u001b[39m\n\u001b[31m  if (panel) panel.style.display = 'block';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const modePublic = document.getElementById('mode-public');\u001b[39m\n\u001b[31m  const modeAssigned = document.getElementById('mode-assigned');\u001b[39m\n\u001b[31m  if (modePublic && modeAssigned) {\u001b[39m\n\u001b[31m    modePublic.classList.toggle('sel', _recceCfg.mode !== 'assigned');\u001b[39m\n\u001b[31m    modeAssigned.classList.toggle('sel', _recceCfg.mode === 'assigned');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  const addRow = document.getElementById('sup-add-row');\u001b[39m\n\u001b[31m  if (addRow) addRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const creatorAddRow = document.getElementById('creator-add-row');\u001b[39m\n\u001b[31m  if (creatorAddRow) creatorAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const clientAddRow = document.getElementById('client-add-row');\u001b[39m\n\u001b[31m  if (clientAddRow) clientAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const modeRow = document.getElementById('mode-row');\u001b[39m\n\u001b[31m  if (modeRow) {\u001b[39m\n\u001b[31m    modeRow.style.display = 'block';\u001b[39m\n\u001b[31m    // Non-cfg-admins see mode as read-only (toggles exist but setRecceMode guards them)\u001b[39m\n\u001b[31m    modeRow.style.opacity = isCfgAdmin ? '1' : '0.65';\u001b[39m\n\u001b[31m    modeRow.style.pointerEvents = isCfgAdmin ? '' : 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const syncBtn = document.getElementById('cfg-sync-btn');\u001b[39m\n\u001b[31m  if (syncBtn) syncBtn.style.display = isCfgAdmin ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('sup-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const sups = _recceCfg.supervisors || [];\u001b[39m\n\u001b[31m  el.innerHTML = sups.map((s,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${s}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin && sups.length > 1 ? `<button onclick=\\\"removeSupervisor(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderCreatorsList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('creator-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const creators = _recceCfg.creators || [];\u001b[39m\n\u001b[31m  el.innerHTML = creators.length ? creators.map((u,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${u}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeCreator(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No creators yet — any Hub user can submit in Public mode.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setRecceMode(mode){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.mode = mode;\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addSupervisor(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('sup-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.supervisors = [...(_recceCfg.supervisors || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeSupervisor(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.supervisors = (_recceCfg.supervisors || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addCreator(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('creator-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.creators || []).includes(val)) { toast(t('Already a creator','पहले से क्रिएटर है'), 'info'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor (includes creation rights)','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.creators = [...(_recceCfg.creators || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeCreator(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.creators = (_recceCfg.creators || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderClientMgmtList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('client-mgmt-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const list = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  el.innerHTML = list.length ? list.map((c,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${esc(c)}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeClientFromList(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No clients yet — add client or agency names to show them as chips in the form.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addClientToList(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('client-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter client name','क्लाइंट नाम दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.clients || []).includes(val)) { toast(t('Already in list','पहले से मौजूद है'), 'info'); return; }\u001b[39m\n\u001b[31m  if (!_recceCfg.clients) _recceCfg.clients = [];\u001b[39m\n\u001b[31m  _recceCfg.clients.push(val);\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeClientFromList(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.clients = (_recceCfg.clients || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncCfgToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast(t('Not authorised','अधिकृत नहीं'), 'error'); return; }\u001b[39m\n\u001b[31m  const st = document.getElementById('cfg-sync-status');\u001b[39m\n\u001b[31m  if (st) st.textContent = t('Syncing…','सिंक हो रहा है…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-cfg', empId: hub.empId, cfg: {\u001b[39m\n\u001b[31m        version: _recceCfg.version || 1,\u001b[39m\n\u001b[31m        supervisors: _recceCfg.supervisors || [],\u001b[39m\n\u001b[31m        mode: _recceCfg.mode || 'public',\u001b[39m\n\u001b[31m        creators: _recceCfg.creators || [],\u001b[39m\n\u001b[31m        allowed_users: _recceCfg.allowed_users || [],\u001b[39m\n\u001b[31m        clients: _recceCfg.clients || [],\u001b[39m\n\u001b[31m      }})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) {\u001b[39m\n\u001b[31m      toast(t('Config synced to server ✓','कॉन्फ़िग सर्वर पर सेव हुआ ✓'), 'success');\u001b[39m\n\u001b[31m      if (st) st.textContent = t('Last synced: just now','अभी सिंक हुआ');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast(j.error || t('Sync failed','सिंक विफल'), 'error');\u001b[39m\n\u001b[31m      if (st) st.textContent = j.error || '';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Network error','नेटवर्क त्रुटि'), 'error');\u001b[39m\n\u001b[31m    if (st) st.textContent = e.message;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function pushStoresToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!hub?.empId || !_adminUnlocked) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-stores', empId: hub.empId, stores })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) toast(`${t('Pushed to server','सर्वर पर पुश हुआ')} · ${j.count} ${t('stores','स्टोर')}`, 'success');\u001b[39m\n\u001b[31m    else toast(j.error || t('Server push failed','सर्वर पुश विफल'), 'error');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Could not reach server','सर्वर से संपर्क नहीं हो सका'), 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── End supervisor config management ────────────────────────────────·\u001b[39m\n\u001b[31m// PostgREST sync constants\u001b[39m\n\u001b[31mconst _RC_BASE      = '/db';\u001b[39m\n\u001b[31mconst _RC_READ      = { 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_WRITE     = { 'Content-Type': 'application/json', 'Content-Profile': 'recce', 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_UPSERT    = { ..._RC_WRITE, 'Prefer': 'resolution=merge-duplicates,return=minimal' };\u001b[39m\n\u001b[31mconst _INSTALL_RD   = { 'Content-Type': 'application/json', 'Accept-Profile': 'installation' };\u001b[39m\n\u001b[31mconst _INSTALL_WR   = { 'Content-Type': 'application/json', 'Content-Profile': 'installation', 'Accept-Profile': 'installation', 'Prefer': 'return=minimal' };·\u001b[39m\n\u001b[31m// ── Campaign selection state ──\u001b[39m\n\u001b[31mlet _selectedCampaignId = null;\u001b[39m\n\u001b[31mlet _notifySupervisor   = false;\u001b[39m\n\u001b[31mlet _campaignList       = [];\u001b[39m\n\u001b[31mlet _pendingJobFilter   = false;\u001b[39m\n\u001b[31mlet _linkJobSubId       = null;\u001b[39m\n\u001b[31mlet _brandingLocked     = false;·\u001b[39m\n\u001b[31mfunction _updateBrandingLock() {\u001b[39m\n\u001b[31m  const hub  = _recceHubUser();\u001b[39m\n\u001b[31m  const isHP = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const banner   = document.getElementById('branding-lock-banner');\u001b[39m\n\u001b[31m  const ovWrap   = document.getElementById('branding-override-wrap');\u001b[39m\n\u001b[31m  const brItems  = document.getElementById('br-items');\u001b[39m\n\u001b[31m  const brAdd    = document.getElementById('br-add');\u001b[39m\n\u001b[31m  const brYes    = document.getElementById('br-yes');\u001b[39m\n\u001b[31m  const brNo     = document.getElementById('br-no');\u001b[39m\n\u001b[31m  if (!banner) return;\u001b[39m\n\u001b[31m  if (_brandingLocked) {\u001b[39m\n\u001b[31m    banner.style.display   = '';\u001b[39m\n\u001b[31m    if (ovWrap)  ovWrap.style.display  = isHP ? '' : 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.pointerEvents = 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.opacity = '0.55';\u001b[39m\n\u001b[31m    if (brAdd)   brAdd.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='none'; brYes.style.opacity='0.5'; }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='none';  brNo.style.opacity='0.5';  }\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    banner.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brItems) { brItems.style.pointerEvents=''; brItems.style.opacity=''; }\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='';  brYes.style.opacity='';   }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='';   brNo.style.opacity='';    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction unlockBrandingOverride() {\u001b[39m\n\u001b[31m  if (!confirm(\u001b[39m\n\u001b[31m    'Client has already reviewed this recce.\\\\n' +\u001b[39m\n\u001b[31m    'Editing brandings will NOT remove their approval.\\\\n' +\u001b[39m\n\u001b[31m    'Continue ONLY if the client has verbally confirmed. Proceed?'\u001b[39m\n\u001b[31m  )) return;\u001b[39m\n\u001b[31m  _brandingLocked = false;\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  renderBrandings();\u001b[39m\n\u001b[31m  toast(t('Branding unlocked for this session', 'ब्रांडिंग इस सत्र के लिए अनलॉक'), 'info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadCampaignsForForm() {\u001b[39m\n\u001b[31m  const sel = document.getElementById('f-campaign-id');\u001b[39m\n\u001b[31m  if (!sel) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m    _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m  } catch(_) { _campaignList = []; }\u001b[39m\n\u001b[31m  sel.innerHTML =\u001b[39m\n\u001b[31m    '<option value=\\\"\\\">— Select job / campaign (optional) —</option>' +\u001b[39m\n\u001b[31m    _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('') +\u001b[39m\n\u001b[31m    '<option value=\\\"__NOTIFY__\\\">⚑ No campaign yet — notify supervisor</option>';\u001b[39m\n\u001b[31m  if (_selectedCampaignId) sel.value = _selectedCampaignId;\u001b[39m\n\u001b[31m  else if (_notifySupervisor) sel.value = '__NOTIFY__';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onCampaignSelect() {\u001b[39m\n\u001b[31m  const val = document.getElementById('f-campaign-id')?.value || '';\u001b[39m\n\u001b[31m  const noticeEl = document.getElementById('campaign-notify-msg');\u001b[39m\n\u001b[31m  if (val === '__NOTIFY__') {\u001b[39m\n\u001b[31m    _selectedCampaignId = null;\u001b[39m\n\u001b[31m    _notifySupervisor   = true;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'block';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    _selectedCampaignId = val || null;\u001b[39m\n\u001b[31m    _notifySupervisor   = false;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction generateRecceReportHtml(entry, photoUrls) {\u001b[39m\n\u001b[31m  const d    = entry.data || {};\u001b[39m\n\u001b[31m  const urls = photoUrls || {};\u001b[39m\n\u001b[31m  const agent = entry.submittedByName || entry.submittedBy || 'Field Agent';\u001b[39m\n\u001b[31m  const _safeId      = (entry.id||'').replace(/\\\\//g,'_').replace(/\\\\.\\\\./g,'');\u001b[39m\n\u001b[31m  const serverPdfUrl = _safeId ? `https://srv1111289.hstgr.cloud/screenshots/recce/views/${_safeId}.pdf` : '';\u001b[39m\n\u001b[31m  const brandLogoUrl = d.brandLogoUrl || _brandLogos[d.brand] || '';\u001b[39m\n\u001b[31m  const tsStr = new Date(entry.timestamp).toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric',hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\u001b[39m\n\u001b[31m  const gpsUrl = d.gpsCoords ? `https://maps.google.com/?q=${d.gpsCoords.lat},${d.gpsCoords.lng}` : null;·\u001b[39m\n\u001b[31m  const frontCount  = (urls.front||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const insideCount = (urls.inside||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const addlCount   = (urls.addl||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const brCount     = (d.brandings||[]).length;·\u001b[39m\n\u001b[31m  // pages: { id, url, bandHtml, cmt, dotLabel, dotColor }\u001b[39m\n\u001b[31m  const pages = [];·\u001b[39m\n\u001b[31m  (urls.front||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Front View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${frontCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.frontPhotos||[])[i]?.cmt||'', dotLabel:`FV${i+1}`, dotColor:'#3b82f6', catLabel:'Front View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.inside||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Inside View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${insideCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.insidePhotos||[])[i]?.cmt||'', dotLabel:`IV${i+1}`, dotColor:'#14b8a6', catLabel:'Inside View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (d.brandings||[]).forEach((b,i)=>{\u001b[39m\n\u001b[31m    const url=(urls.brandings||[])[i]; if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">${esc(b.type||'Branding')}</div><div class=\\\"ph-dims\\\">Width : ${esc(b.w||'?')}&Prime;&nbsp;&times;&nbsp;Height : ${esc(b.h||'?')}&Prime;&nbsp;&mdash;&nbsp;${esc(b.qty||1)} Nos</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${brCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:'', dotLabel:`B${i+1}`, dotColor:'#f97316', catLabel:b.type||'Branding',\u001b[39m\n\u001b[31m      tileDims:`${b.w||'?'}″×${b.h||'?'}″ — ${String(b.qty||1).padStart(2,'0')} Nos` });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.addl||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Additional</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${addlCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.addlPhotos||[])[i]?.desc||'', dotLabel:`A${i+1}`, dotColor:'#94a3b8', catLabel:'Additional', tileDims:'' });\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const sideItems = [\u001b[39m\n\u001b[31m    `<div class=\\\"si-item active\\\" data-tgt=\\\"pg-cover\\\" title=\\\"Cover\\\"><div class=\\\"si-dot\\\" style=\\\"background:#475569\\\">CV</div></div>`\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  pages.forEach(p => {\u001b[39m\n\u001b[31m    sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"${p.id}\\\" title=\\\"${p.dotLabel}\\\"><div class=\\\"si-dot\\\" style=\\\"background:${p.dotColor}\\\">${p.dotLabel}</div></div>`);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(d.hasVideo) sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-vid\\\" title=\\\"Video\\\"><div class=\\\"si-dot\\\" style=\\\"background:#a855f7\\\">VD</div></div>`);\u001b[39m\n\u001b[31m  if(urls.doc)   sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-doc\\\" title=\\\"Document\\\"><div class=\\\"si-dot\\\" style=\\\"background:#64748b\\\">DC</div></div>`);·\u001b[39m\n\u001b[31m  const thumbItems = [\u001b[39m\n\u001b[31m    ...pages,\u001b[39m\n\u001b[31m    ...(d.hasVideo?[{id:'pg-vid',url:null,catLabel:'Video',tileDims:'',dotLabel:'VD',dotColor:'#a855f7'}]:[]),\u001b[39m\n\u001b[31m    ...(urls.doc?[{id:'pg-doc',url:urls.doc,catLabel:'Document',tileDims:'',dotLabel:'DC',dotColor:'#64748b'}]:[])\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  const thumbsHtml = thumbItems.map(p=>`<div class=\\\"cov-thumb\\\" onclick=\\\"document.getElementById('${p.id}').scrollIntoView({behavior:'smooth'})\\\">${p.url?`<img src=\\\"${p.url}\\\" alt=\\\"\\\">`:(`<div class=\\\"cov-thumb-vid\\\">${p.catLabel==='Video'?'&#x25B6;&#xFE0F;':'&#x1F4C4;'}</div>`)}<div class=\\\"cov-thumb-ov\\\" style=\\\"border-top:3px solid ${p.dotColor}\\\"><div class=\\\"cov-thumb-cat\\\">${esc(p.catLabel)}</div>${p.tileDims?`<div class=\\\"cov-thumb-dims\\\">${esc(p.tileDims)}</div>`:''}<div class=\\\"cov-thumb-no\\\">${p.dotLabel}</div></div></div>`).join('');·\u001b[39m\n\u001b[31m  const pagesHtml = pages.map(p => `\u001b[39m\n\u001b[31m<div class=\\\"photo-page\\\" id=\\\"${p.id}\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\">${p.bandHtml}</div>\u001b[39m\n\u001b[31m  <div class=\\\"ph-img\\\"><a href=\\\"${p.url}\\\" target=\\\"_blank\\\"><img src=\\\"${p.url}\\\" loading=\\\"lazy\\\" alt=\\\"\\\"></a>${p.cmt?`<div class=\\\"ph-cmt\\\">${esc(p.cmt)}</div>`:''}</div>\u001b[39m\n\u001b[31m</div>`).join('');·\u001b[39m\n\u001b[31m  return `<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\"><head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m<title>Recce — ${esc(d.storeName||'Unknown')} · ${esc(d.brand||'')}</title>\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--dk:#0f172a;--nv2:#1a2f52;--or:#f97316;--g200:#e2e8f0;--g400:#94a3b8;--g600:#475569;--si:54px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0}\u001b[39m\n\u001b[31mhtml,body{height:100%;overflow:hidden}\u001b[39m\n\u001b[31mbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#111;color:var(--dk);display:flex}\u001b[39m\n\u001b[31ma{color:var(--or);text-decoration:none}\u001b[39m\n\u001b[31mimg{display:block}·\u001b[39m\n\u001b[31m/* ── Side index ── */\u001b[39m\n\u001b[31m.side-idx{width:var(--si);flex-shrink:0;background:var(--dk);overflow-y:auto;display:flex;flex-direction:column;align-items:center;padding:4px 0;scrollbar-width:none;z-index:50}\u001b[39m\n\u001b[31m.side-idx::-webkit-scrollbar{display:none}\u001b[39m\n\u001b[31m.si-item{width:100%;min-height:56px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s}\u001b[39m\n\u001b[31m.si-item:hover{background:rgba(255,255,255,.07)}\u001b[39m\n\u001b[31m.si-dot{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff;opacity:.4;transition:opacity .18s,transform .18s;line-height:1;text-align:center}\u001b[39m\n\u001b[31m.si-item.active .si-dot{opacity:1;transform:scale(1.15)}·\u001b[39m\n\u001b[31m/* ── Main scroll area ── */\u001b[39m\n\u001b[31m.main{flex:1;overflow-y:scroll;scroll-snap-type:y mandatory;scroll-behavior:smooth;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar{width:3px}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15)}·\u001b[39m\n\u001b[31m/* ── Cover ── */\u001b[39m\n\u001b[31m.cover{height:100vh;scroll-snap-align:start;flex-shrink:0;background:linear-gradient(135deg,#0f172a 0%,var(--nv2) 100%);color:#fff;display:flex;flex-direction:column;padding:24px 20px 20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.cover-badge{display:inline-flex;align-items:center;gap:5px;background:var(--or);color:#fff;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:1px;padding:3px 12px;border-radius:20px;margin-bottom:12px;align-self:flex-start}\u001b[39m\n\u001b[31m.cover h1{font-size:20px;font-weight:700;line-height:1.3;margin-bottom:4px}\u001b[39m\n\u001b[31m.cover-addr{color:rgba(255,255,255,.55);font-size:12px;margin-bottom:16px}\u001b[39m\n\u001b[31m.cg{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}\u001b[39m\n\u001b[31m.cm{background:rgba(255,255,255,.08);border-radius:8px;padding:8px 12px}\u001b[39m\n\u001b[31m.cm-l{font-size:9px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}\u001b[39m\n\u001b[31m.cm-v{font-size:13px;font-weight:600;color:#fff}\u001b[39m\n\u001b[31m.cm-v a{color:#fb923c}\u001b[39m\n\u001b[31m.cover-pbar{padding-top:8px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{background:var(--or);color:#fff;border:none;padding:10px 22px;border-radius:22px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}\u001b[39m\n\u001b[31m.btn-p:disabled{opacity:.4;cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-c{background:rgba(255,255,255,.1);color:rgba(255,255,255,.75);border:1px solid rgba(255,255,255,.2);padding:10px 18px;border-radius:22px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit}·\u001b[39m\n\u001b[31m/* ── Cover thumbnail grid ── */\u001b[39m\n\u001b[31m.cov-grid-hdr{font-size:10px;font-weight:700;color:rgba(255,255,255,.35);text-transform:uppercase;letter-spacing:1.2px;padding:10px 0 5px;flex-shrink:0}\u001b[39m\n\u001b[31m.cov-grid{flex:1;min-height:0;display:grid;gap:5px;overflow:hidden;align-content:start}\u001b[39m\n\u001b[31m.cov-thumb{position:relative;overflow:hidden;border-radius:7px;cursor:pointer;background:#1e293b;transition:transform .18s,box-shadow .18s}\u001b[39m\n\u001b[31m.cov-thumb:hover{transform:scale(1.05);box-shadow:0 4px 18px rgba(0,0,0,.55)}\u001b[39m\n\u001b[31m.cov-thumb img{width:100%;height:100%;object-fit:cover;display:block}\u001b[39m\n\u001b[31m.cov-thumb-vid{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:#0f172a}\u001b[39m\n\u001b[31m.cov-thumb-ov{position:absolute;inset:0;background:rgba(0,0,0,.28);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:5px;border-radius:7px}\u001b[39m\n\u001b[31m.cov-thumb-cat{color:rgba(255,255,255,.5);font-weight:900;text-align:center;text-transform:uppercase;letter-spacing:.8px;text-shadow:0 1px 6px rgba(0,0,0,.95);line-height:1.2;word-break:break-word}\u001b[39m\n\u001b[31m.cov-thumb-dims{color:rgba(255,255,255,.5);font-weight:700;text-align:center;text-shadow:0 1px 5px rgba(0,0,0,.95);letter-spacing:.3px;line-height:1.3}\u001b[39m\n\u001b[31m.cov-thumb-no{color:rgba(255,255,255,.5);font-weight:800;text-shadow:0 1px 4px rgba(0,0,0,.95);letter-spacing:.5px}\u001b[39m\n\u001b[31m#cover-btn{position:fixed;bottom:20px;right:16px;display:none;align-items:center;gap:6px;background:rgba(255,255,255,.15);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.25);color:#fff;padding:10px 22px;border-radius:50px;font-size:13px;font-weight:700;cursor:pointer;z-index:200;letter-spacing:.3px;box-shadow:0 2px 12px rgba(0,0,0,.3);font-family:inherit;transition:background .15s,transform .15s}\u001b[39m\n\u001b[31m#cover-btn:hover{background:rgba(255,255,255,.22);transform:scale(1.04)}·\u001b[39m\n\u001b[31m/* ── Print wait overlay ── */\u001b[39m\n\u001b[31m#print-overlay{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m@media print{#print-overlay{display:none!important}}·\u001b[39m\n\u001b[31m/* ── Loading progress bar ── */\u001b[39m\n\u001b[31m.load-bar{position:fixed;bottom:0;left:0;right:0;background:rgba(15,23,42,.95);padding:9px 16px;z-index:9999;display:flex;align-items:center;gap:12px;backdrop-filter:blur(6px)}\u001b[39m\n\u001b[31m.load-track{flex:1;height:5px;background:rgba(255,255,255,.12);border-radius:3px;overflow:hidden}\u001b[39m\n\u001b[31m.load-fill{height:100%;background:var(--or);width:0%;transition:width .35s ease;border-radius:3px}\u001b[39m\n\u001b[31m.load-txt{font-size:11px;color:rgba(255,255,255,.6);white-space:nowrap;min-width:160px}·\u001b[39m\n\u001b[31m/* ── Photo page ── */\u001b[39m\n\u001b[31m.photo-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ph-band{background:var(--dk);padding:16px 26px;flex-shrink:0;display:flex;align-items:center;gap:20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.ph-cat{font-size:35px;font-weight:800;color:#fff;letter-spacing:-.5px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.ph-dims{flex:1;font-size:18px;font-weight:600;color:var(--or);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}\u001b[39m\n\u001b[31m.ph-no{margin-left:auto;flex-shrink:0;font-size:21px;font-weight:700;color:rgba(255,255,255,.85);background:rgba(255,255,255,.1);padding:5px 20px;border-radius:24px;white-space:nowrap}\u001b[39m\n\u001b[31m.ph-of{font-size:18px;font-weight:400;color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.ph-img{flex:1;overflow:hidden;position:relative;background:#111}\u001b[39m\n\u001b[31m.ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m.ph-img img{width:100%;height:100%;object-fit:contain;display:block}\u001b[39m\n\u001b[31m.ph-cmt{position:absolute;bottom:0;left:0;right:0;padding:6px 14px;background:rgba(0,0,0,.62);font-size:11px;color:rgba(255,255,255,.75);font-style:italic;pointer-events:none}·\u001b[39m\n\u001b[31m/* ── Video / Doc pages ── */\u001b[39m\n\u001b[31m.vid-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;background:#fff}\u001b[39m\n\u001b[31m.vid-body{flex:1;padding:20px 24px;font-size:14px;color:var(--g600);border-left:4px solid var(--or)}\u001b[39m\n\u001b[31m.vid-body em{display:block;font-size:12px;color:var(--g400);margin-top:6px}\u001b[39m\n\u001b[31m.doc-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m.doc-wrap{flex:1;display:flex;align-items:center;justify-content:center;background:#111;overflow:hidden}\u001b[39m\n\u001b[31m.doc-img{max-width:100%;max-height:100%;object-fit:contain}·\u001b[39m\n\u001b[31m/* ── Cover header band ── */\u001b[39m\n\u001b[31m.cov-hdr{display:flex;gap:0;margin-bottom:12px;flex-shrink:0;border-radius:10px;overflow:hidden;border:1px solid rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.cov-hdr-l{flex:1;padding:14px 18px;display:flex;flex-direction:column;gap:5px;border-right:1px solid rgba(255,255,255,.1);min-width:0}\u001b[39m\n\u001b[31m.cov-hdr-r{width:170px;flex-shrink:0;padding:14px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:rgba(255,255,255,.04)}\u001b[39m\n\u001b[31m.cov-store{font-size:18px;font-weight:800;color:#fff;line-height:1.25;margin-bottom:2px}\u001b[39m\n\u001b[31m.cov-meta{font-size:12px;color:rgba(255,255,255,.55);display:flex;align-items:center;gap:5px;line-height:1.5}\u001b[39m\n\u001b[31m.cov-brand{background:var(--or);color:#fff;font-size:13px;font-weight:800;padding:5px 16px;border-radius:20px;text-align:center;letter-spacing:.3px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\u001b[39m\n\u001b[31m.cov-date-l{font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.8px;margin-bottom:2px;text-align:center}\u001b[39m\n\u001b[31m.cov-date-v{font-size:13px;font-weight:700;color:#fff;text-align:center}\u001b[39m\n\u001b[31m.cov-logo-box{background:#fff;border-radius:8px;padding:8px 14px;display:flex;align-items:center;justify-content:center;width:100%;max-width:138px}\u001b[39m\n\u001b[31m.cov-logo-box img{max-width:110px;max-height:44px;object-fit:contain;display:block}·\u001b[39m\n\u001b[31m/* ── Print ── */\u001b[39m\n\u001b[31m@page{size:A4 landscape;margin:12mm}\u001b[39m\n\u001b[31m@media print{\u001b[39m\n\u001b[31m  html,body{height:auto;overflow:visible;display:block}\u001b[39m\n\u001b[31m  .side-idx{display:none}\u001b[39m\n\u001b[31m  .main{overflow:visible;display:block;height:auto;scroll-snap-type:none}\u001b[39m\n\u001b[31m  .cover,.vid-page,.doc-page{height:auto;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m  .photo-page{height:186mm;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m  .cover{padding:20px 24px}\u001b[39m\n\u001b[31m  .cover-pbar{display:none}\u001b[39m\n\u001b[31m  .cov-hdr{margin-bottom:8px;border-radius:7px}\u001b[39m\n\u001b[31m  .cov-hdr-l{padding:10px 14px}\u001b[39m\n\u001b[31m  .cov-hdr-r{padding:10px 12px;width:150px}\u001b[39m\n\u001b[31m  .cov-store{font-size:15px}\u001b[39m\n\u001b[31m  .cov-meta{font-size:10px}\u001b[39m\n\u001b[31m  .cov-brand{font-size:11px;padding:3px 12px}\u001b[39m\n\u001b[31m  .cov-date-v{font-size:11px}\u001b[39m\n\u001b[31m  .ph-band{padding:5mm 13mm;gap:10mm}\u001b[39m\n\u001b[31m  .ph-cat{font-size:15mm}\u001b[39m\n\u001b[31m  .ph-dims{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-no{font-size:12mm;padding:2mm 8mm}\u001b[39m\n\u001b[31m  .ph-of{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-img{flex:1;display:flex;align-items:center;justify-content:center;background:#fff;overflow:hidden}\u001b[39m\n\u001b[31m  .ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m  .ph-img img{width:100%;height:100%;object-fit:contain}\u001b[39m\n\u001b[31m  .ph-cmt{position:static;background:transparent;color:#475569;padding:2mm 8mm;font-size:6mm}\u001b[39m\n\u001b[31m  .main>*:last-child{page-break-after:avoid;break-after:avoid}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m</style></head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<div class=\\\"side-idx\\\" id=\\\"side-idx\\\">${sideItems.join('')}</div>·\u001b[39m\n\u001b[31m<div class=\\\"main\\\" id=\\\"main\\\">·\u001b[39m\n\u001b[31m<div class=\\\"cover\\\" id=\\\"pg-cover\\\">\u001b[39m\n\u001b[31m  <div class=\\\"cov-hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-l\\\">\u001b[39m\n\u001b[31m      <div class=\\\"cov-store\\\">${esc(d.storeName||'Unknown Store')}</div>\u001b[39m\n\u001b[31m      ${(d.address||d.city)?`<div class=\\\"cov-meta\\\">&#x1F4CD; ${esc(d.address||'')}${d.city&&!(d.address||'').includes(d.city)?', '+esc(d.city):''}</div>`:''}\u001b[39m\n\u001b[31m      ${d.mobile?`<div class=\\\"cov-meta\\\">&#x1F4DE; ${esc(d.mobile)}</div>`:''}\u001b[39m\n\u001b[31m      ${d.email?`<div class=\\\"cov-meta\\\">&#x2709; ${esc(d.email)}</div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-r\\\">\u001b[39m\n\u001b[31m      ${brandLogoUrl\u001b[39m\n\u001b[31m        ? `<div class=\\\"cov-logo-box\\\"><img src=\\\"${brandLogoUrl}\\\" alt=\\\"${esc(d.brand||'')}\\\"></div>`\u001b[39m\n\u001b[31m        : (d.brand?`<div class=\\\"cov-brand\\\">${esc(d.brand)}</div>`:'')}\u001b[39m\n\u001b[31m      ${d.date?`<div><div class=\\\"cov-date-l\\\">Recce Date</div><div class=\\\"cov-date-v\\\">${esc(d.date)}</div></div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${thumbItems.length ? `<div class=\\\"cov-grid-hdr\\\">&#x1F4F7; ${thumbItems.length} page${thumbItems.length!==1?'s':''} &mdash; tap any to jump</div><div class=\\\"cov-grid\\\" id=\\\"cov-grid\\\">${thumbsHtml}</div>` : ''}\u001b[39m\n\u001b[31m  <div class=\\\"cover-pbar\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" id=\\\"btn-print\\\" onclick=\\\"doPDF()\\\">&#x1F4C4;&nbsp;PDF</button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-c\\\" onclick=\\\"window.close()\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m${pagesHtml}·\u001b[39m\n\u001b[31m${d.hasVideo?`\u001b[39m\n\u001b[31m<div class=\\\"vid-page\\\" id=\\\"pg-vid\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Video</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"vid-body\\\">${esc(d.videoNote||'Video recorded during visit')}${d.videoCmt?`<em>${esc(d.videoCmt)}</em>`:''}</div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m${urls.doc?`\u001b[39m\n\u001b[31m<div class=\\\"doc-page\\\" id=\\\"pg-doc\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Document</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"doc-wrap\\\"><a href=\\\"${urls.doc}\\\" target=\\\"_blank\\\"><img class=\\\"doc-img\\\" src=\\\"${urls.doc}\\\" loading=\\\"lazy\\\" alt=\\\"Document\\\"></a></div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"print-overlay\\\"><div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Preparing print&hellip;</div><div class=\\\"po-sub\\\" id=\\\"po-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"po-pfill\\\"></div></div></div>\u001b[39m\n\u001b[31m${pages.length ? `<div class=\\\"load-bar\\\" id=\\\"load-bar\\\"><div class=\\\"load-track\\\"><div class=\\\"load-fill\\\" id=\\\"load-fill\\\"></div></div><div class=\\\"load-txt\\\" id=\\\"load-txt\\\">Loading photos&#x2026;</div></div>` : ''}\u001b[39m\n\u001b[31m${thumbItems.length ? `<button id=\\\"cover-btn\\\" onclick=\\\"document.getElementById('pg-cover').scrollIntoView({behavior:'smooth'})\\\">&#x1F3E0;&nbsp;Cover Page</button>` : ''}·\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var main=document.getElementById('main');\u001b[39m\n\u001b[31m  var items=document.querySelectorAll('.si-item');\u001b[39m\n\u001b[31m  var covBtn=document.getElementById('cover-btn');\u001b[39m\n\u001b[31m  function setActive(id){\u001b[39m\n\u001b[31m    items.forEach(function(el){el.classList.toggle('active',el.dataset.tgt===id);});\u001b[39m\n\u001b[31m    var a=document.querySelector('.si-item[data-tgt=\\\"'+id+'\\\"]');\u001b[39m\n\u001b[31m    if(a) a.scrollIntoView({block:'nearest'});\u001b[39m\n\u001b[31m    if(covBtn) covBtn.style.display=id==='pg-cover'?'none':'flex';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  items.forEach(function(el){\u001b[39m\n\u001b[31m    el.addEventListener('click',function(){\u001b[39m\n\u001b[31m      var t=document.getElementById(el.dataset.tgt);\u001b[39m\n\u001b[31m      if(t) t.scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if('IntersectionObserver' in window){\u001b[39m\n\u001b[31m    var obs=new IntersectionObserver(function(entries){\u001b[39m\n\u001b[31m      entries.forEach(function(e){if(e.isIntersecting&&e.intersectionRatio>=0.45) setActive(e.target.id);});\u001b[39m\n\u001b[31m    },{root:main,threshold:0.45});\u001b[39m\n\u001b[31m    document.querySelectorAll('[id^=\\\"pg-\\\"]').forEach(function(p){obs.observe(p);});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  setActive('pg-cover');\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var imgs=Array.from(document.querySelectorAll('img'));\u001b[39m\n\u001b[31m  var total=imgs.length,loaded=0;\u001b[39m\n\u001b[31m  var bar=document.getElementById('load-bar');\u001b[39m\n\u001b[31m  var fill=document.getElementById('load-fill');\u001b[39m\n\u001b[31m  var txt=document.getElementById('load-txt');\u001b[39m\n\u001b[31m  var printPending=false,printShowTime=0;\u001b[39m\n\u001b[31m  var mm=96/25.4;\u001b[39m\n\u001b[31m  var SERVER_PDF='${serverPdfUrl}';\u001b[39m\n\u001b[31m  function updatePoBar(){\u001b[39m\n\u001b[31m    var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m    var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(poFill) poFill.style.width=(total?Math.round(loaded/total*100):100)+'%';\u001b[39m\n\u001b[31m    if(poSub) poSub.textContent=loaded+' / '+total+' photos ready';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function done(){\u001b[39m\n\u001b[31m    if(fill) fill.style.width='100%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='✓ All '+total+' photos ready';\u001b[39m\n\u001b[31m    setTimeout(function(){\u001b[39m\n\u001b[31m      if(bar){bar.style.transition='opacity .6s';bar.style.opacity='0';}\u001b[39m\n\u001b[31m      setTimeout(function(){if(bar)bar.style.display='none';},650);\u001b[39m\n\u001b[31m    },2000);\u001b[39m\n\u001b[31m    if(printPending){\u001b[39m\n\u001b[31m      printPending=false;\u001b[39m\n\u001b[31m      var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m      var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m      var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(poFill) poFill.style.width='100%';\u001b[39m\n\u001b[31m      if(poSub) poSub.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},Math.max(400,2000-(Date.now()-printShowTime)));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function onImg(){\u001b[39m\n\u001b[31m    loaded++;\u001b[39m\n\u001b[31m    if(fill) fill.style.width=Math.round(loaded/total*100)+'%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… '+loaded+' / '+total;\u001b[39m\n\u001b[31m    if(printPending) updatePoBar();\u001b[39m\n\u001b[31m    if(loaded>=total) done();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  /* ── PDF layout helpers ── */\u001b[39m\n\u001b[31m  function fitBandFonts(pageW){\u001b[39m\n\u001b[31m    var padH=2*13*mm,gapH=2*10*mm,noPadH=2*8*mm;\u001b[39m\n\u001b[31m    var avail=pageW-padH-gapH;\u001b[39m\n\u001b[31m    var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-band').forEach(function(band){\u001b[39m\n\u001b[31m      var cat=band.querySelector('.ph-cat');\u001b[39m\n\u001b[31m      var dims=band.querySelector('.ph-dims');\u001b[39m\n\u001b[31m      var no=band.querySelector('.ph-no');\u001b[39m\n\u001b[31m      if(!cat) return;\u001b[39m\n\u001b[31m      var catTxt=cat.textContent.trim();\u001b[39m\n\u001b[31m      var dimsTxt=dims?dims.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      var noTxt=no?no.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      function tw(sc){\u001b[39m\n\u001b[31m        var cf=15*sc*mm,df=10*sc*mm,nf=12*sc*mm;\u001b[39m\n\u001b[31m        ctx.font='800 '+cf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var cw=ctx.measureText(catTxt).width;\u001b[39m\n\u001b[31m        ctx.font='600 '+df+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var dw=dims?ctx.measureText(dimsTxt).width:0;\u001b[39m\n\u001b[31m        ctx.font='700 '+nf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var nw=no?ctx.measureText(noTxt).width+noPadH:0;\u001b[39m\n\u001b[31m        return cw+dw+nw;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      var scale=1.0;\u001b[39m\n\u001b[31m      if(tw(scale)>avail){\u001b[39m\n\u001b[31m        var lo=0.3,hi=1.0;\u001b[39m\n\u001b[31m        for(var i=0;i<10;i++){var mid=(lo+hi)/2;if(tw(mid)<=avail)lo=mid;else hi=mid;}\u001b[39m\n\u001b[31m        scale=lo*0.93;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      cat.style.setProperty('font-size',Math.round(15*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(dims) dims.style.setProperty('font-size',Math.round(10*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(no) no.style.setProperty('font-size',Math.round(12*scale*mm)+'px','important');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function sizePdfThumbs(pageW,pageH){\u001b[39m\n\u001b[31m    var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m    if(!grid||!grid.children.length) return;\u001b[39m\n\u001b[31m    var coverPage=document.getElementById('pg-cover');\u001b[39m\n\u001b[31m    var usedH=56;\u001b[39m\n\u001b[31m    if(coverPage){\u001b[39m\n\u001b[31m      Array.from(coverPage.children).forEach(function(el){\u001b[39m\n\u001b[31m        if(el!==grid) usedH+=el.offsetHeight||0;\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    var gridH=Math.max(80,pageH-usedH);\u001b[39m\n\u001b[31m    var n=grid.children.length,gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m    for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m      var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m      var w=(pageW-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m      var h=w*asp;\u001b[39m\n\u001b[31m      if(rows*h+(rows-1)*gap<=gridH&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m    grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m    grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m    var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m    var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m    var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function preparePdfLayout(){\u001b[39m\n\u001b[31m    var pageW=Math.round((297-24)*mm);\u001b[39m\n\u001b[31m    var pageH=Math.round((210-24)*mm);\u001b[39m\n\u001b[31m    fitBandFonts(pageW);\u001b[39m\n\u001b[31m    sizePdfThumbs(pageW,pageH);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.preparePdfLayout=preparePdfLayout;\u001b[39m\n\u001b[31m  function restorePdfLayout(){\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-cat,.ph-dims,.ph-no').forEach(function(el){\u001b[39m\n\u001b[31m      el.style.removeProperty('font-size');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(window._screenSizeThumbs) window._screenSizeThumbs();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.addEventListener('afterprint',restorePdfLayout);\u001b[39m\n\u001b[31m  function _doBrowserPrint(){\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    printShowTime=Date.now();\u001b[39m\n\u001b[31m    preparePdfLayout();\u001b[39m\n\u001b[31m    if(total===0||loaded>=total){\u001b[39m\n\u001b[31m      var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m      if(ps) ps.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},2000);\u001b[39m\n\u001b[31m      return;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    printPending=true;\u001b[39m\n\u001b[31m    updatePoBar();\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if((!img.complete||img.naturalWidth===0)&&img.getAttribute('loading')==='lazy'){\u001b[39m\n\u001b[31m        img.loading='eager';var s=img.src;img.src='';img.src=s;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.doPDF=async function(){\u001b[39m\n\u001b[31m    if(!SERVER_PDF){_doBrowserPrint();return;}\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      var r=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m      if(r.ok){window.open(SERVER_PDF,'_blank');return;}\u001b[39m\n\u001b[31m    }catch(_){}\u001b[39m\n\u001b[31m    // PDF not ready yet — show overlay and poll\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    if(pf) pf.style.width='0%';\u001b[39m\n\u001b[31m    if(ps) ps.textContent='Waiting for server PDF…';\u001b[39m\n\u001b[31m    var tries=0;\u001b[39m\n\u001b[31m    (async function poll(){\u001b[39m\n\u001b[31m      tries++;\u001b[39m\n\u001b[31m      if(pf) pf.style.width=Math.min(88,tries*8)+'%';\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        var r2=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m        if(r2.ok){\u001b[39m\n\u001b[31m          if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m          setTimeout(function(){if(ov)ov.style.display='none';window.open(SERVER_PDF,'_blank');},400);\u001b[39m\n\u001b[31m          return;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      }catch(_){}\u001b[39m\n\u001b[31m      if(tries>=12){if(ov)ov.style.display='none';_doBrowserPrint();return;}\u001b[39m\n\u001b[31m      setTimeout(poll,5000);\u001b[39m\n\u001b[31m    })();\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  if(total===0){if(bar)bar.style.display='none';}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… 0 / '+total;\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if(img.complete&&img.naturalWidth>0) onImg();\u001b[39m\n\u001b[31m      else{img.addEventListener('load',onImg);img.addEventListener('error',onImg);}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m  if(grid&&grid.children.length>0){\u001b[39m\n\u001b[31m    function sizeThumbs(){\u001b[39m\n\u001b[31m      var n=grid.children.length;\u001b[39m\n\u001b[31m      var gw=grid.clientWidth,gh=grid.clientHeight;\u001b[39m\n\u001b[31m      if(!gw||!gh) return;\u001b[39m\n\u001b[31m      var gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m      for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m        var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m        var w=(gw-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m        var h=w*asp;\u001b[39m\n\u001b[31m        if(rows*h+(rows-1)*gap<=gh&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m      grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m      grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m      var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m      var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m      var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    window._screenSizeThumbs=sizeThumbs;\u001b[39m\n\u001b[31m    requestAnimationFrame(function(){requestAnimationFrame(sizeThumbs);});\u001b[39m\n\u001b[31m    window.addEventListener('resize',sizeThumbs);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m</scr`+'ipt>'+`\u001b[39m\n\u001b[31m</body></html>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncToPostgres(entry) {\u001b[39m\n\u001b[31m  const d   = entry.data || {};\u001b[39m\n\u001b[31m  const hub = _recceHubUser();·\u001b[39m\n\u001b[31m  // Step 1 — upload all photos to VPS, get permanent server URLs\u001b[39m\n\u001b[31m  let photoUrls = { front:[], inside:[], brandings:[], addl:[], doc:null };\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const pResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type: 'save-photos', subId: entry.id,\u001b[39m\n\u001b[31m        photos: {\u001b[39m\n\u001b[31m          front:    (d.frontPhotos||[]).map(p=>({b64:p.b64,   cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64,  cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||null})),\u001b[39m\n\u001b[31m          addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64,   desc:p.desc||''})),\u001b[39m\n\u001b[31m          doc:      d.docB64 || null,\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (pResp.ok) { const r=await pResp.json(); if(r.success) {\u001b[39m\n\u001b[31m      photoUrls=r.photoUrls;\u001b[39m\n\u001b[31m      // Merge retained existing URLs for edit re-submits\u001b[39m\n\u001b[31m      if (entry.editedAt) {\u001b[39m\n\u001b[31m        photoUrls.front    =(photoUrls.front   ||[]).map((u,i)=>u||(d.frontPhotos  ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.inside   =(photoUrls.inside  ||[]).map((u,i)=>u||(d.insidePhotos ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.addl     =(photoUrls.addl    ||[]).map((u,i)=>u||(d.addlPhotos   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.brandings=(photoUrls.brandings||[]).map((u,i)=>u||(d.brandings   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        if(!photoUrls.doc) photoUrls.doc=d._docExistingUrl||null;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }}\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-photos] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 1.5 — trigger Google Slides via proxy using permanent photo URLs (fire-and-forget)\u001b[39m\n\u001b[31m  (async()=>{try{\u001b[39m\n\u001b[31m    const _hasPh=(photoUrls.front||[]).some(Boolean)||(photoUrls.inside||[]).some(Boolean)||(photoUrls.brandings||[]).some(Boolean);\u001b[39m\n\u001b[31m    if(!_hasPh)return;\u001b[39m\n\u001b[31m    const _gu=(await cfg('slides-gas-url'))||(await cfg('gas-url'))||DEFAULT_GAS_URL;if(!_gu)return;\u001b[39m\n\u001b[31m    await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({\u001b[39m\n\u001b[31m      type:'make-slides',gasUrl:_gu,subId:entry.id,\u001b[39m\n\u001b[31m      storeInfo:{storeName:d.storeName||'',brand:d.brand||'',address:d.address||'',mobile:d.mobile||'',date:d.date||'',city:d.city||'',gpsCoords:d.gpsCoords||null},\u001b[39m\n\u001b[31m      photoGroups:{\u001b[39m\n\u001b[31m        front:    (photoUrls.front   ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.frontPhotos  ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        inside:   (photoUrls.inside  ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.insidePhotos ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        brandings:(photoUrls.brandings||[]).filter(Boolean).map((url,i)=>({url,meta:{type:(d.brandings||[])[i]?.type,w:(d.brandings||[])[i]?.w,h:(d.brandings||[])[i]?.h,qty:(d.brandings||[])[i]?.qty,sqft:(d.brandings||[])[i]?.sqft}})),\u001b[39m\n\u001b[31m        addl:    (photoUrls.addl    ||[]).filter(Boolean).map((url,i)=>({url,desc:(d.addlPhotos  ||[])[i]?.desc||''})),\u001b[39m\n\u001b[31m      },\u001b[39m\n\u001b[31m    })});\u001b[39m\n\u001b[31m    entry.gasAt=new Date().toISOString();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[recce-slides]',e.message);}}\u001b[39m\n\u001b[31m  )();·\u001b[39m\n\u001b[31m  // Step 2 — generate rich HTML report using server URLs, save to VPS\u001b[39m\n\u001b[31m  let view_url = null;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const html  = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m    const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-view', subId: entry.id, html })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (vResp.ok) { const r=await vResp.json(); if(r.success) view_url=r.url; }\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-view] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 3 — upsert to PostgreSQL with photo URLs + view URL\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch(`${_RC_BASE}/submissions`, {\u001b[39m\n\u001b[31m      method: 'POST', headers: _RC_UPSERT,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        sub_id:         entry.id,\u001b[39m\n\u001b[31m        store_name:     d.storeName    || 'Unknown',\u001b[39m\n\u001b[31m        brand:          d.brand        || null,\u001b[39m\n\u001b[31m        client_name:    d.clientName   || null,\u001b[39m\n\u001b[31m        visit_date:     d.date         || new Date().toISOString().slice(0,10),\u001b[39m\n\u001b[31m        address:        d.address      || null,\u001b[39m\n\u001b[31m        mobile:         d.mobile       || null,\u001b[39m\n\u001b[31m        city:           d.city         || null,\u001b[39m\n\u001b[31m        has_branding:   !!(d.brandings?.length),\u001b[39m\n\u001b[31m        branding_count: d.brandings?.length || 0,\u001b[39m\n\u001b[31m        has_video:      !!d.hasVideo,\u001b[39m\n\u001b[31m        front_photos:   d.frontPhotos?.length  || 0,\u001b[39m\n\u001b[31m        inside_photos:  d.insidePhotos?.length || 0,\u001b[39m\n\u001b[31m        addl_photos:    d.addlPhotos?.length   || 0,\u001b[39m\n\u001b[31m        gps_lat:        d.gpsCoords?.lat       || null,\u001b[39m\n\u001b[31m        gps_lng:        d.gpsCoords?.lng       || null,\u001b[39m\n\u001b[31m        submitted_by:   hub.empId              || null,\u001b[39m\n\u001b[31m        submitted_at:   entry.timestamp,\u001b[39m\n\u001b[31m        campaign_id:    entry.campaignId       || null,\u001b[39m\n\u001b[31m        photo_urls:     photoUrls,\u001b[39m\n\u001b[31m        view_url,\u001b[39m\n\u001b[31m        meta: {\u001b[39m\n\u001b[31m          brandings: (d.brandings||[]).map(b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft})),\u001b[39m\n\u001b[31m          videoNote: d.videoNote || null,\u001b[39m\n\u001b[31m          videoCmt:  d.videoCmt  || null,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        status: 'submitted',\u001b[39m\n\u001b[31m        edit_assigned_to: null,\u001b[39m\n\u001b[31m        edit_comment: null,\u001b[39m\n\u001b[31m        edited_at: entry.editedAt || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    return { ok: true, viewUrl: view_url };\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    console.warn('[recce-db] sync error:', e.message);\u001b[39m\n\u001b[31m    return { ok: false, viewUrl: null };\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mconst DEFAULT_ADMIN_HASH='42d372e6110bee134990ac6881c3d5eb568482008add9a859f37f10d759430e8';·\u001b[39m\n\u001b[31masync function saveGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('gas-url',url||DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  toast('Endpoint saved','success');\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function testEndpoint(){\u001b[39m\n\u001b[31m  const url=(await cfg('gas-url'))||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  try{await fetch(url,{method:'POST',mode:'no-cors',body:JSON.stringify({test:true})});toast('Endpoint reachable ✓','success');}\u001b[39m\n\u001b[31m  catch{toast('Cannot reach endpoint','error')}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  cfg('gas-url').then(url=>{\u001b[39m\n\u001b[31m    const u=url||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    // Show last 30 chars only for privacy\u001b[39m\n\u001b[31m    el.textContent='Endpoint: …'+u.slice(-30);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── SLIDES GAS URL ────────────────────────────────────────────\u001b[39m\n\u001b[31masync function saveSlidesGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('slides-gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('slides-gas-url', url);\u001b[39m\n\u001b[31m  toast('Slides GAS URL saved','success');\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function updateSlidesGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('slides-gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  const u=await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  el.textContent=u?'Configured: …'+u.slice(-30):'Not configured';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── MAKE SLIDES ───────────────────────────────────────────────\u001b[39m\n\u001b[31masync function makeSlides(id){\u001b[39m\n\u001b[31m  const gasUrl = await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  if(!gasUrl){\u001b[39m\n\u001b[31m    toast('Configure Slides GAS URL in Settings first','error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const entry = await dbGet('subs', id);\u001b[39m\n\u001b[31m  if(!entry){ toast('Entry not found','error'); return; }\u001b[39m\n\u001b[31m  const d = entry.data;·\u001b[39m\n\u001b[31m  toast('Uploading photos & generating slides…','info');·\u001b[39m\n\u001b[31m  // Build photo groups payload\u001b[39m\n\u001b[31m  const photoGroups = {\u001b[39m\n\u001b[31m    front:    (d.frontPhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64, cmt:p.desc||''})),\u001b[39m\n\u001b[31m    brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||'', meta:{type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft}})),\u001b[39m\n\u001b[31m  };·\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type:       'recce',\u001b[39m\n\u001b[31m        subId:      id,\u001b[39m\n\u001b[31m        gasUrl:     gasUrl,\u001b[39m\n\u001b[31m        storeInfo:  {\u001b[39m\n\u001b[31m          storeName: d.storeName, brand: d.brand,\u001b[39m\n\u001b[31m          date: d.date, address: d.address,\u001b[39m\n\u001b[31m          mobile: d.mobile, gpsCoords: d.gpsCoords,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        photoGroups,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const result = await resp.json();\u001b[39m\n\u001b[31m    if(result.success && result.slideUrl){\u001b[39m\n\u001b[31m      // Store slide URL on the entry\u001b[39m\n\u001b[31m      entry.slideUrl = result.slideUrl;\u001b[39m\n\u001b[31m      await dbPut('subs', entry);\u001b[39m\n\u001b[31m      toast('✅ Slides ready!','success');\u001b[39m\n\u001b[31m      window.open(result.slideUrl, '_blank');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast('Slides error: '+(result.error||'Unknown'),'error');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e){\u001b[39m\n\u001b[31m    toast('Network error: '+e.message,'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN LOGIN ──────────────────────────────────────────────\u001b[39m\n\u001b[31mfunction showAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-error').style.display='none';\u001b[39m\n\u001b[31m  // Restore saved config URL\u001b[39m\n\u001b[31m  cfg('admin-cfg-url').then(u=>{if(u&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=u;});\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('admin-pwd').focus(),100);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveAdminCfgUrl(){\u001b[39m\n\u001b[31m  // Admin cfg URL can be saved without login (needed to set up auth itself)\u001b[39m\n\u001b[31m  // But we warn if saving while unlocked only\u001b[39m\n\u001b[31m  const url=document.getElementById('admin-cfg-url').value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  await cfg('admin-cfg-url',url);\u001b[39m\n\u001b[31m  toast('Config URL saved — will use on next login attempt','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function verifyAdmin(){\u001b[39m\n\u001b[31m  // Hub admins (harish/pramod) are auto-unlocked — no password needed\u001b[39m\n\u001b[31m  if (_adminUnlocked) { adminLoginSuccess(); return; }\u001b[39m\n\u001b[31m  const pwd=document.getElementById('admin-pwd').value;\u001b[39m\n\u001b[31m  if(!pwd){document.getElementById('admin-error').style.display='block';document.getElementById('admin-error').textContent='Enter password';return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('admin-login-btn');btn.disabled=true;btn.textContent='Verifying…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // Try server verification first\u001b[39m\n\u001b[31m    const cfgUrl=(await cfg('admin-cfg-url'))||'';\u001b[39m\n\u001b[31m    if(cfgUrl){\u001b[39m\n\u001b[31m      const r=await fetch(cfgUrl,{cache:'no-store'});\u001b[39m\n\u001b[31m      const j=await r.json();\u001b[39m\n\u001b[31m      // Server JSON format: {\\\"password\\\":\\\"plaintext\\\"} or {\\\"hash\\\":\\\"sha256hash\\\"}\u001b[39m\n\u001b[31m      let match=false;\u001b[39m\n\u001b[31m      if(j.password){match=(j.password===pwd);}\u001b[39m\n\u001b[31m      else if(j.hash){\u001b[39m\n\u001b[31m        // SHA-256 comparison\u001b[39m\n\u001b[31m        const enc=new TextEncoder();\u001b[39m\n\u001b[31m        const data=enc.encode(pwd);\u001b[39m\n\u001b[31m        const hashBuf=await crypto.subtle.digest('SHA-256',data);\u001b[39m\n\u001b[31m        const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m        match=(hashHex===j.hash);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      if(match){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m      else{showAdminError('Incorrect password');return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Fallback: local password stored in settings\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if(localHash){\u001b[39m\n\u001b[31m      const enc=new TextEncoder();\u001b[39m\n\u001b[31m      const hashBuf=await crypto.subtle.digest('SHA-256',enc.encode(pwd));\u001b[39m\n\u001b[31m      const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m      if(hashHex===localHash){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Final fallback: check against hardcoded default hash\u001b[39m\n\u001b[31m    const enc2=new TextEncoder();\u001b[39m\n\u001b[31m    const hb2=await crypto.subtle.digest('SHA-256',enc2.encode(pwd));\u001b[39m\n\u001b[31m    const hh2=Array.from(new Uint8Array(hb2)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    if(hh2===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }catch(err){\u001b[39m\n\u001b[31m    // Network error — try all local fallbacks\u001b[39m\n\u001b[31m    const enc3=new TextEncoder();\u001b[39m\n\u001b[31m    const hb3=await crypto.subtle.digest('SHA-256',enc3.encode(pwd));\u001b[39m\n\u001b[31m    const hh3=Array.from(new Uint8Array(hb3)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if((localHash&&hh3===localHash)||hh3===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }finally{btn.disabled=false;btn.textContent='Login';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showAdminError(msg){\u001b[39m\n\u001b[31m  const el=document.getElementById('admin-error');\u001b[39m\n\u001b[31m  el.textContent=msg;el.style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminLoginSuccess(){\u001b[39m\n\u001b[31m  _adminUnlocked=true;\u001b[39m\n\u001b[31m  closeAdminLogin();\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  cfg('gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  cfg('slides-gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('slides-gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||'';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  toast('Admin mode unlocked','success');\u001b[39m\n\u001b[31m  setTimeout(lockAdmin,10*60*1000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction lockAdmin(){\u001b[39m\n\u001b[31m  _adminUnlocked=false;\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  toast('Admin session ended','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updAvailTag(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-avail-tag');\u001b[39m\n\u001b[31m  const ct=document.getElementById('store-avail-count');\u001b[39m\n\u001b[31m  const txt=stores.length?`${stores.length} stores`:'No store list';\u001b[39m\n\u001b[31m  if(el)el.textContent=txt;\u001b[39m\n\u001b[31m  if(ct)ct.textContent=stores.length?t(`${stores.length} stores available — tap to browse`,`${stores.length} स्टोर उपलब्ध — दबाएं`):t('No store list loaded yet','कोई स्टोर सूची नहीं');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PICKER\u001b[39m\n\u001b[31mfunction openPicker(){\u001b[39m\n\u001b[31m  if(!stores.length){toast('Load a store list in Settings first','error');return;}\u001b[39m\n\u001b[31m  document.getElementById('povl').classList.add('open');\u001b[39m\n\u001b[31m  document.getElementById('psearch').value='';\u001b[39m\n\u001b[31m  filterPicker('');\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('psearch').focus(),150);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closePicker(){document.getElementById('povl').classList.remove('open');}\u001b[39m\n\u001b[31masync function filterPicker(q){\u001b[39m\n\u001b[31m  const list=document.getElementById('plist');\u001b[39m\n\u001b[31m  const words=q.toLowerCase().trim().split(/\\\\s+/).filter(Boolean);\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const lastVisit={};\u001b[39m\n\u001b[31m  subs.forEach(s=>{const nm=s.data?.storeName;if(nm&&(!lastVisit[nm]||s.timestamp>lastVisit[nm]))lastVisit[nm]=s.timestamp;});·\u001b[39m\n\u001b[31m  // Multi-word: ALL words must match somewhere in any field (search across both English and Hindi)\u001b[39m\n\u001b[31m  let fl=stores.filter(s=>{\u001b[39m\n\u001b[31m    if(!words.length)return true;\u001b[39m\n\u001b[31m    const hay=[s.name,s.nameHi,s.address,s.addressHi,s.mobile,s.city,s.cityHi,s.distName,s.distNameHi,s.brand,s.sales,s.proj,s.glowSign,s.inshop]\u001b[39m\n\u001b[31m               .map(x=>(x||'').toLowerCase()).join(' ');\u001b[39m\n\u001b[31m    return words.every(w=>hay.includes(w));\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(fl.length>100)fl=fl.slice(0,100);·\u001b[39m\n\u001b[31m  if(!fl.length){\u001b[39m\n\u001b[31m    const esc=q.replace(/'/g,\\\"\\\\\\\\'\\\");\u001b[39m\n\u001b[31m    list.innerHTML=`<div style=\\\"text-align:center;padding:32px 16px;color:var(--g400);font-size:14px\\\">No stores match \\\"${q}\\\"<br><span style=\\\"font-size:12px\\\">Try fewer or different words</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('${esc}')\\\">+ Add \\\"${q}\\\" as new store</div>`;\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Group by brand (including empty brand)\u001b[39m\n\u001b[31m  const g={};\u001b[39m\n\u001b[31m  fl.forEach(s=>{\u001b[39m\n\u001b[31m    const b=s.brand||'(No Brand — will ask)';\u001b[39m\n\u001b[31m    if(!g[b])g[b]=[];\u001b[39m\n\u001b[31m    g[b].push(s);\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html='';\u001b[39m\n\u001b[31m  Object.keys(g).sort().forEach(br=>{\u001b[39m\n\u001b[31m    html+=`<div class=\\\"psec\\\">${br}</div>`;\u001b[39m\n\u001b[31m    g[br].forEach(s=>{\u001b[39m\n\u001b[31m      const lv=lastVisit[s.name];\u001b[39m\n\u001b[31m      const lvStr=lv?`🕐 Last: ${new Date(lv).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'2-digit'})}`:'';\u001b[39m\n\u001b[31m      const chips=[];\u001b[39m\n\u001b[31m      if(s.glowSign&&s.glowSign.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dcfce7;color:#14532d;padding:2px 6px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m      if(s.inshop&&s.inshop.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dbeafe;color:#1e40af;padding:2px 6px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m      if(s.proj)chips.push(`<span style=\\\"font-size:10px;background:var(--g100);color:var(--g600);padding:2px 6px;border-radius:10px\\\">Target: ${s.proj}</span>`);\u001b[39m\n\u001b[31m      const enc=JSON.stringify(s).replace(/\\\"/g,'&quot;');\u001b[39m\n\u001b[31m      const mapsUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m      const waUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const telUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const dispName=LANG==='hi'&&s.nameHi?s.nameHi:s.name;\u001b[39m\n\u001b[31m      const dispAddr=LANG==='hi'&&s.addressHi?s.addressHi:s.address;\u001b[39m\n\u001b[31m      const dispDist=LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m      html+=`<div class=\\\"pitem\\\" onclick=\\\"pickStore(${enc})\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"pi-name\\\">${dispName}</div>\u001b[39m\n\u001b[31m          ${dispAddr?`<div class=\\\"pi-addr\\\">📍 ${dispAddr}</div>`:''}\u001b[39m\n\u001b[31m          ${s.mobile?`<div class=\\\"pi-addr\\\">📞 ${s.mobile}</div>`:''}\u001b[39m\n\u001b[31m          ${dispDist?`<div class=\\\"pi-addr\\\" style=\\\"color:var(--am)\\\">👤 ${dispDist}</div>`:''}\u001b[39m\n\u001b[31m          ${lvStr?`<div class=\\\"pi-last\\\">${lvStr}</div>`:''}\u001b[39m\n\u001b[31m          ${chips.length?`<div style=\\\"display:flex;gap:4px;flex-wrap:wrap;margin-top:4px\\\">${chips.join('')}</div>`:''}\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;gap:6px;margin-top:7px\\\" onclick=\\\"event.stopPropagation()\\\">\u001b[39m\n\u001b[31m            ${mapsUrl?`<a href=\\\"${mapsUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#e0f2fe;color:#0369a1;border-radius:20px;text-decoration:none;font-weight:600\\\">🗺 Maps</a>`:''}\u001b[39m\n\u001b[31m            ${waUrl?`<a href=\\\"${waUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#dcfce7;color:#15803d;border-radius:20px;text-decoration:none;font-weight:600\\\">💬 WhatsApp</a>`:''}\u001b[39m\n\u001b[31m            ${telUrl?`<a href=\\\"${telUrl}\\\" style=\\\"font-size:11px;padding:4px 10px;background:#f0fdf4;color:#166534;border-radius:20px;text-decoration:none;font-weight:600\\\">📞 Call</a>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        ${s.brand?`<div class=\\\"pi-brand\\\">${s.brand}</div>`:'<div class=\\\"pi-brand\\\" style=\\\"background:var(--rd)\\\">?</div>'}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html+=`<div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('')\\\">+ Not in list? Add new store</div>`;\u001b[39m\n\u001b[31m  list.innerHTML=html;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function pickStore(s){\u001b[39m\n\u001b[31m  selectedStore=s;manualMode=false;closePicker();\u001b[39m\n\u001b[31m  const _dn =LANG==='hi'&&s.nameHi    ?s.nameHi    :s.name;\u001b[39m\n\u001b[31m  const _da =LANG==='hi'&&s.addressHi ?s.addressHi :s.address;\u001b[39m\n\u001b[31m  const _dd =LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m  const _dc =LANG==='hi'&&s.cityHi    ?s.cityHi    :s.city;\u001b[39m\n\u001b[31m  document.getElementById('sc-name').textContent=_dn;\u001b[39m\n\u001b[31m  const brandEl=document.getElementById('sc-brand');\u001b[39m\n\u001b[31m  brandEl.textContent=s.brand||'No Brand';brandEl.style.background=s.brand?'var(--nv)':'var(--rd)';\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const prev=subs.filter(x=>x.data?.storeName===s.name).sort((a,b)=>new Date(b.timestamp)-new Date(a.timestamp))[0];\u001b[39m\n\u001b[31m  const lc=document.getElementById('sc-last');\u001b[39m\n\u001b[31m  if(prev){const d=new Date(prev.timestamp);lc.textContent='Last: '+d.toLocaleDateString('en-IN',{day:'numeric',month:'short'});lc.style.display='inline-flex';}\u001b[39m\n\u001b[31m  else lc.style.display='none';\u001b[39m\n\u001b[31m  // All Excel fields — display in active language\u001b[39m\n\u001b[31m  const mUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m  const wUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const tUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const details=[];\u001b[39m\n\u001b[31m  if(_da)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📍 ${_da}${mUrl?` <a href=\\\"${mUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#0369a1;margin-left:6px\\\">🗺 Navigate</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(s.mobile)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📞 ${s.mobile}${tUrl?` <a href=\\\"${tUrl}\\\" style=\\\"font-size:11px;color:#166534;margin-left:6px\\\">Call</a>`:''}${wUrl?` <a href=\\\"${wUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#15803d;margin-left:6px\\\">WhatsApp</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(_dd)details.push(`<div style=\\\"font-size:12px;color:var(--am)\\\">👤 ${_dd}</div>`);\u001b[39m\n\u001b[31m  if(_dc)details.push(`<div style=\\\"font-size:12px;color:var(--g500)\\\">🏙 ${_dc}</div>`);\u001b[39m\n\u001b[31m  const opp=[];\u001b[39m\n\u001b[31m  if(s.glowSign&&s.glowSign.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dcfce7;color:#14532d;padding:2px 7px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m  if(s.inshop&&s.inshop.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dbeafe;color:#1e40af;padding:2px 7px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m  if(s.proj)opp.push(`<span style=\\\"font-size:11px;background:var(--g100);color:var(--g600);padding:2px 7px;border-radius:10px\\\">Target 2026: ${s.proj}</span>`);\u001b[39m\n\u001b[31m  if(opp.length)details.push(`<div style=\\\"display:flex;gap:5px;flex-wrap:wrap;margin-top:3px\\\">${opp.join('')}</div>`);\u001b[39m\n\u001b[31m  document.getElementById('sc-details').innerHTML=details.join('');\u001b[39m\n\u001b[31m  // Missing fields\u001b[39m\n\u001b[31m  const missing=[];\u001b[39m\n\u001b[31m  if(!s.address)missing.push({key:'address',label:'Store Address',type:'textarea',placeholder:'Full address'});\u001b[39m\n\u001b[31m  if(!s.mobile)missing.push({key:'mobile',label:'Mobile No.',type:'tel',placeholder:'10-digit number',maxlen:'10'});\u001b[39m\n\u001b[31m  const mw=document.getElementById('sc-missing'),mf=document.getElementById('sc-missing-fields');\u001b[39m\n\u001b[31m  if(missing.length){\u001b[39m\n\u001b[31m    mf.innerHTML=missing.map(m=>`<div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\"><label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">${m.label} <span class=\\\"req\\\">*</span></label>${m.type==='textarea'?`<textarea id=\\\"sc-miss-${m.key}\\\" rows=\\\"2\\\" placeholder=\\\"${m.placeholder}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></textarea>`:`<input type=\\\"${m.type}\\\" id=\\\"sc-miss-${m.key}\\\" placeholder=\\\"${m.placeholder}\\\" ${m.maxlen?`maxlength=\\\"${m.maxlen}\\\"`:''}  inputmode=\\\"${m.type==='tel'?'numeric':'text'}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\">`}</div>`).join('');\u001b[39m\n\u001b[31m    mw.style.display='block';\u001b[39m\n\u001b[31m  } else {mw.style.display='none';}\u001b[39m\n\u001b[31m  // Brand selector\u001b[39m\n\u001b[31m  const bSel=document.getElementById('brand-selector'),bChips=document.getElementById('brand-chips');\u001b[39m\n\u001b[31m  if(!s.brand){\u001b[39m\n\u001b[31m    renderBrandChips();\u001b[39m\n\u001b[31m    bSel.style.display='block';\u001b[39m\n\u001b[31m  } else {bSel.style.display='none';}\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  F.storeName=s.name;F.brand=s.brand||'';F.address=s.address||'';F.mobile=s.mobile||'';\u001b[39m\n\u001b[31m  if(s.brand&&!_selectedClient&&!_clientOtherMode) autoSetClient(s.brand);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateMissingField(key,val){if(!selectedStore)return;selectedStore[key]=val.trim();F[key]=val.trim();saveDraft();}\u001b[39m\n\u001b[31mfunction selectStoreBrand(b){\u001b[39m\n\u001b[31m  F.brand=b;F.brandLogoUrl=_brandLogos[b]||'';\u001b[39m\n\u001b[31m  if(selectedStore)selectedStore.brand=b;\u001b[39m\n\u001b[31m  const el=document.getElementById('sc-brand');if(el){el.textContent=b;el.style.background='var(--nv)';}\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-chips .chip').forEach(c=>{c.classList.toggle('sel',c.querySelector('span')?.textContent===b||c.textContent.trim()===b);});\u001b[39m\n\u001b[31m  if(!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction onManualBrandChange(){\u001b[39m\n\u001b[31m  const b=document.getElementById('f-brand')?.value||'';\u001b[39m\n\u001b[31m  F.brandLogoUrl=b?(_brandLogos[b]||''):'';\u001b[39m\n\u001b[31m  if(b&&!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction openManual(prefill){\u001b[39m\n\u001b[31m  manualMode=true;\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').classList.add('on');\u001b[39m\n\u001b[31m  document.getElementById('mt-label').innerHTML='← Back to store list';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='block';\u001b[39m\n\u001b[31m  // Pre-fill from selectedStore if available (e.g. when toggling after picker selection)\u001b[39m\n\u001b[31m  const s=selectedStore;\u001b[39m\n\u001b[31m  if(s){\u001b[39m\n\u001b[31m    if(document.getElementById('f-brand'))document.getElementById('f-brand').value=s.brand||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-store'))document.getElementById('f-store').value=s.name||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-addr'))document.getElementById('f-addr').value=s.address||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-mobile'))document.getElementById('f-mobile').value=s.mobile||'';\u001b[39m\n\u001b[31m  } else if(prefill){\u001b[39m\n\u001b[31m    document.getElementById('f-store').value=prefill;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  selectedStore=null;\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction toggleManual(){\u001b[39m\n\u001b[31m  if(manualMode){\u001b[39m\n\u001b[31m    manualMode=false;\u001b[39m\n\u001b[31m    document.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31m    document.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31m    document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    openManual('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// GPS\u001b[39m\n\u001b[31mfunction captureGPS(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gps-status');el.textContent='Getting location…';el.style.color='var(--g500)';\u001b[39m\n\u001b[31m  if(!navigator.geolocation){el.textContent='GPS not available';return;}\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(pos=>{\u001b[39m\n\u001b[31m    gpsCoords={lat:pos.coords.latitude.toFixed(6),lng:pos.coords.longitude.toFixed(6),acc:Math.round(pos.coords.accuracy)};\u001b[39m\n\u001b[31m    el.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${gpsCoords.acc}m)`;el.style.color='var(--gn)';saveDraft();\u001b[39m\n\u001b[31m  },()=>{el.textContent='GPS failed — enter address manually';el.style.color='var(--rd)';},{enableHighAccuracy:true,timeout:10000});\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// DRAFT\u001b[39m\n\u001b[31mlet draftT;\u001b[39m\n\u001b[31mfunction saveDraft(){\u001b[39m\n\u001b[31m  clearTimeout(draftT);\u001b[39m\n\u001b[31m  draftT=setTimeout(async()=>{\u001b[39m\n\u001b[31m    const draft={k:'current',ts:Date.now(),F:{...F,date:document.getElementById('f-date')?.value||'',brand:manualMode?(document.getElementById('f-brand')?.value||''):(selectedStore?.brand||F.brand||''),storeName:selectedStore?selectedStore.name:(document.getElementById('f-store')?.value||''),address:manualMode?(document.getElementById('f-addr')?.value||''):(selectedStore?.address||F.address||''),mobile:manualMode?(document.getElementById('f-mobile')?.value||''):(selectedStore?.mobile||F.mobile||''),clientName:getClientName()},selectedStore,manualMode,gpsCoords,_selectedClient,_clientOtherMode,fCnt:frontPhotos.length,iCnt:insidePhotos.length,bCnt:brandings.length};\u001b[39m\n\u001b[31m    await dbPut('draft',draft);\u001b[39m\n\u001b[31m    // Also save photos as b64 blobs to draft so they survive exit\u001b[39m\n\u001b[31m    await saveDraftPhotos();\u001b[39m\n\u001b[31m  },500);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveDraftPhotos(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const photoData={\u001b[39m\n\u001b[31m      front:await Promise.all(frontPhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      inside:await Promise.all(insidePhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      addl:await Promise.all(addlPhotos.map(async p=>({b64:await b64(p.blob),desc:p.desc||''}))),\u001b[39m\n\u001b[31m      brand:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,b64:b.blob?await b64(b.blob):null})))\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    await dbPut('draft',{k:'photos',...photoData});\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function checkDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');const wrap=document.getElementById('resume-wrap');\u001b[39m\n\u001b[31m  if(!d||!d.F?.storeName){wrap.innerHTML='';return;}\u001b[39m\n\u001b[31m  const ago=Math.round((Date.now()-d.ts)/60000);\u001b[39m\n\u001b[31m  const agoStr=ago<1?'just now':ago<60?`${ago}m ago`:`${Math.round(ago/60)}h ago`;\u001b[39m\n\u001b[31m  wrap.innerHTML=`<button class=\\\"resume-btn\\\" onclick=\\\"resumeDraft()\\\">\u001b[39m\n\u001b[31m    <div><div style=\\\"font-size:12px;color:rgba(255,255,255,.5);margin-bottom:3px\\\">Resume draft · ${agoStr}</div><div>${d.F.storeName} · ${d.F.brand||'No brand'}</div></div>\u001b[39m\n\u001b[31m    <div style=\\\"text-align:right\\\"><div style=\\\"font-size:13px;color:var(--or)\\\">${d.fCnt||0} photos · ${d.bCnt||0} brandings →</div></div>\u001b[39m\n\u001b[31m  </button>`;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function resumeDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');if(!d)return;\u001b[39m\n\u001b[31m  F=d.F||{};gpsCoords=d.gpsCoords||null;\u001b[39m\n\u001b[31m  if(d.selectedStore){await pickStore(d.selectedStore);}\u001b[39m\n\u001b[31m  else if(d.manualMode){openManual('');if(F.brand)document.getElementById('f-brand').value=F.brand;if(F.storeName)document.getElementById('f-store').value=F.storeName;if(F.address)document.getElementById('f-addr').value=F.address;if(F.mobile)document.getElementById('f-mobile').value=F.mobile;}\u001b[39m\n\u001b[31m  if(F.date)document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  // Restore client chip state\u001b[39m\n\u001b[31m  if(d._clientOtherMode){_clientOtherMode=true;_selectedClient='';const inp=document.getElementById('f-client-other');if(inp&&F.clientName)inp.value=F.clientName;}\u001b[39m\n\u001b[31m  else if(d._selectedClient){_selectedClient=d._selectedClient;_clientOtherMode=false;}\u001b[39m\n\u001b[31m  else if(F.clientName){autoSetClient(F.clientName);}\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  // Restore photos from draft\u001b[39m\n\u001b[31m  const pd=await dbGet('draft','photos');\u001b[39m\n\u001b[31m  if(pd){\u001b[39m\n\u001b[31m    async function b64ToBlob(b64str){if(!b64str)return null;try{const r=await fetch(b64str);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m    for(const p of(pd.front||[])){const bl=await b64ToBlob(p.b64);if(bl)frontPhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.inside||[])){const bl=await b64ToBlob(p.b64);if(bl)insidePhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.addl||[])){const bl=await b64ToBlob(p.b64);if(bl)addlPhotos.push({blob:bl,prev:URL.createObjectURL(bl),desc:p.desc||''});}\u001b[39m\n\u001b[31m    for(const b of(pd.brand||[])){const bl=await b64ToBlob(b.b64);brandings.push({type:b.type,w:b.w,h:b.h,qty:b.qty,blob:bl,prev:bl?URL.createObjectURL(bl):null});}\u001b[39m\n\u001b[31m    toast('Draft restored with '+frontPhotos.length+' photos ✓','success');\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    toast('Draft restored — photos could not be recovered','info');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PHOTOS\u001b[39m\n\u001b[31mfunction updPhotoBadge(type){const arr=type==='front'?frontPhotos:insidePhotos;const el=document.getElementById(type+'-badge');if(el){el.textContent=arr.length;el.className='cnt-badge '+(arr.length?'':'gray');}}\u001b[39m\n\u001b[31mfunction renderPhotos(type){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  const cont=document.getElementById(type+'-cont');const addBtn=document.getElementById('add-'+type);\u001b[39m\n\u001b[31m  updPhotoBadge(type);\u001b[39m\n\u001b[31m  if(arr.length===0){cont.innerHTML=`<div class=\\\"pslot\\\" onclick=\\\"addPhoto('${type}')\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to capture or upload</span><span class=\\\"hi-txt\\\">फोटो खींचें या अपलोड करें</span></div></div>`;addBtn.style.display='none';return;}\u001b[39m\n\u001b[31m  cont.innerHTML=arr.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const badge=isRetained?`<span class=\\\"pbadge\\\" style=\\\"background:#475569\\\">Existing</span>`:`<span class=\\\"pbadge\\\">${fmtSz(p.blob.size)}</span>`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replacePhoto('${type}',${i})\\\" style=\\\"right:36px;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"margin-bottom:12px\\\"><div class=\\\"pslot filled\\\" style=\\\"margin-bottom:8px\\\"><img src=\\\"${p.prev}\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmPhoto('${type}',${i})\\\">×</button>${badge}</div><input type=\\\"text\\\" placeholder=\\\"Comments (optional)\\\" value=\\\"${p.cmt||''}\\\" onchange=\\\"${type==='front'?'frontPhotos':'insidePhotos'}[${i}].cmt=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  addBtn.style.display=arr.length<(type==='inside'?5:3)?'inline-flex':'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// Photo source: 'camera' stamps geo, 'gallery' does not\u001b[39m\n\u001b[31mlet _photoSourceCb=null,_photoSourceQuality=null;·\u001b[39m\n\u001b[31mfunction capPhoto(cb,forceSource,quality){\u001b[39m\n\u001b[31m  // quality override: null=use setting, 'hd', 'compressed'\u001b[39m\n\u001b[31m  _photoSourceCb=cb;_photoSourceQuality=quality||null;\u001b[39m\n\u001b[31m  if(forceSource==='camera'){_doCapture(cb,'camera',quality);return;}\u001b[39m\n\u001b[31m  if(forceSource==='gallery'){_doCapture(cb,'gallery',quality);return;}\u001b[39m\n\u001b[31m  // Show picker\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _doCapture(cb,src,quality){\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  const i=document.createElement('input');\u001b[39m\n\u001b[31m  i.type='file';i.accept='image/*';\u001b[39m\n\u001b[31m  if(src==='camera')i.setAttribute('capture','environment');\u001b[39m\n\u001b[31m  i.style.display='none';\u001b[39m\n\u001b[31m  i.onchange=async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f)return;\u001b[39m\n\u001b[31m    const q=quality||_photoSourceQuality||null;\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      const blob=await compress(f,q==='hd'?1920:q==='compressed'?1280:null,q==='hd'?0.90:q==='compressed'?0.78:null);\u001b[39m\n\u001b[31m      // Only stamp if from camera (live photo)\u001b[39m\n\u001b[31m      const stamped=(src==='camera')?await stampPhoto(blob):blob;\u001b[39m\n\u001b[31m      // Save to device (auto-download trigger)\u001b[39m\n\u001b[31m      savePhotoToDevice(stamped);\u001b[39m\n\u001b[31m      cb({target:{files:[f]},_blob:stamped,_src:src});\u001b[39m\n\u001b[31m    }catch(err){toast('Photo processing failed — try again','error');console.error('_doCapture error:',err);}\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  document.body.appendChild(i);i.click();setTimeout(()=>i.remove(),8000);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction photoSrcCamera(){_doCapture(_photoSourceCb,'camera',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcGallery(){_doCapture(_photoSourceCb,'gallery',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcCancel(){document.getElementById('photo-src-dialog').classList.remove('open');_photoSourceCb=null;}·\u001b[39m\n\u001b[31m// Save photo to device gallery/downloads\u001b[39m\n\u001b[31mfunction savePhotoToDevice(blob){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    const a=document.createElement('a');\u001b[39m\n\u001b[31m    a.href=url;\u001b[39m\n\u001b[31m    a.download='Recce_'+Date.now()+'.jpg';\u001b[39m\n\u001b[31m    a.style.display='none';\u001b[39m\n\u001b[31m    document.body.appendChild(a);a.click();\u001b[39m\n\u001b[31m    setTimeout(()=>{URL.revokeObjectURL(url);a.remove();},1000);\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addPhoto(type){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}${e._src==='camera'&&geoStampEnabled?' · Stamped':''}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31masync function handleCapture(e,type){\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmPhoto(type,i){(type==='front'?frontPhotos:insidePhotos).splice(i,1);renderPhotos(type);saveDraft();}\u001b[39m\n\u001b[31mfunction replacePhoto(type,idx){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m    arr[idx]={...arr[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAddl(){\u001b[39m\n\u001b[31m  const cont=document.getElementById('add-cont');const btn=document.getElementById('add-addl');\u001b[39m\n\u001b[31m  const badge=document.getElementById('addl-badge');if(badge){badge.textContent=`${addlPhotos.length} / 8`;badge.className='cnt-badge '+(addlPhotos.length?'':'gray');}\u001b[39m\n\u001b[31m  cont.innerHTML=addlPhotos.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const sizeInfo=isRetained?'<span style=\\\"color:#475569\\\">Existing</span>':`${fmtSz(p.blob.size)}`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replaceAddl(${i})\\\" style=\\\"top:3px;left:3px;right:auto;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;gap:10px;align-items:start;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--g100)\\\"><div style=\\\"position:relative;flex-shrink:0\\\"><img src=\\\"${p.prev}\\\" style=\\\"width:80px;height:80px;object-fit:cover;border-radius:var(--rs)\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmAddl(${i})\\\" style=\\\"top:3px;right:3px\\\">×</button></div><div style=\\\"flex:1\\\"><input type=\\\"text\\\" placeholder=\\\"Description (optional)\\\" value=\\\"${p.desc||''}\\\" onchange=\\\"addlPhotos[${i}].desc=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"><div style=\\\"font-size:11px;color:var(--g400);margin-top:4px\\\">${sizeInfo}</div></div></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  btn.style.display=addlPhotos.length>=8?'none':'inline-flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction addAdditional(){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  addlPhotos.push({blob:bs,prev:URL.createObjectURL(bs),desc:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderAddl();saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31mfunction rmAddl(i){addlPhotos.splice(i,1);renderAddl();saveDraft();}\u001b[39m\n\u001b[31mfunction replaceAddl(idx){\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m    addlPhotos[idx]={...addlPhotos[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderAddl();saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// BRANDING\u001b[39m\n\u001b[31mfunction calcSqft(w,h){const wf=parseFloat(w),hf=parseFloat(h);if(!wf||!hf)return '';return `${(wf*hf).toFixed(0)} sq.in = ${(wf*hf/144).toFixed(2)} sq.ft`;}\u001b[39m\n\u001b[31mfunction renderBrandings(){\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  const cont=document.getElementById('br-items');\u001b[39m\n\u001b[31m  const hb=document.getElementById('br-hdr-badge');if(hb)hb.textContent=`${brandings.length} ${t(brandings.length!==1?'items':'item',brandings.length!==1?'आइटम':'आइटम')}`;\u001b[39m\n\u001b[31m  cont.innerHTML=brandings.map((b,i)=>`<div class=\\\"bitem\\\"><div class=\\\"bitem-hdr\\\"><div class=\\\"bitem-title\\\">${t('Branding','ब्रांडिंग')} ${i+1}${b.type?' — '+b.type:''}</div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:6px\\\">${i>0?`<button class=\\\"btn-d\\\" onclick=\\\"dupBr(${i})\\\" style=\\\"color:var(--or);border-color:var(--orl)\\\">${t('Dup ↑','डुप ↑')}</button>`:''}<button class=\\\"btn-d\\\" onclick=\\\"rmBr(${i})\\\">${t('Remove','हटाएं')}</button></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\"><label>${t('Type','प्रकार')} <span class=\\\"req\\\">*</span></label><div class=\\\"chip-grid\\\">${BTYPE.map(tp=>`<div class=\\\"chip${b.type===tp?' sel':''}\\\" onclick=\\\"setBType(${i},'${tp.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\"> ${tp}</div>`).join('')}</div></div>\u001b[39m\n\u001b[31m    <div class=\\\"dim-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Width (in)','चौड़ाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.w||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].w=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Height (in)','ऊंचाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.h||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].h=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"max-width:74px\\\"><label>${t('Qty','मात्रा')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.qty||''}\\\" placeholder=\\\"1\\\" inputmode=\\\"numeric\\\" onchange=\\\"brandings[${i}].qty=this.value;saveDraft()\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <span class=\\\"sqft\\\" id=\\\"sf${i}\\\">${calcSqft(b.w,b.h)||t('Enter W × H','W × H दर्ज करें')}</span>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-top:12px\\\"><label>${t('Photo','फोटो')} <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      ${b.prev?`<div class=\\\"pslot filled\\\" onclick=\\\"capBr(${i})\\\"><img src=\\\"${b.prev}\\\"><button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();rmBrPh(${i})\\\">×</button><span class=\\\"pbadge\\\">${b.blob?fmtSz(b.blob.size):'Existing'}</span></div>`:`<div><div class=\\\"pslot\\\" onclick=\\\"capBr(${i})\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\">${t('Tap to capture','दबाकर कैप्चर करें')}</div></div><div style=\\\"display:flex;gap:6px;margin-top:6px\\\"><button class=\\\"atool${(b.quality||imgQuality)==='compressed'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'compressed');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">${t('Compressed','कम्प्रेस्ड')}</button><button class=\\\"atool${(b.quality||imgQuality)==='hd'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'hd');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">HD</button></div></div>`}\u001b[39m\n\u001b[31m    </div></div>`).join('');\u001b[39m\n\u001b[31m  // Only show \\\"Add Another\\\" when last item is fully complete\u001b[39m\n\u001b[31m  const addDiv=document.getElementById('br-add');\u001b[39m\n\u001b[31m  if(addDiv&&brandings.length>0){\u001b[39m\n\u001b[31m    const last=brandings[brandings.length-1];\u001b[39m\n\u001b[31m    const lastComplete=last.type&&last.w&&last.h&&last.qty&&last.prev;\u001b[39m\n\u001b[31m    addDiv.style.display=(lastComplete&&brandings.length<15)?'block':'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updSqft(i){const el=document.getElementById('sf'+i);if(el)el.textContent=calcSqft(brandings[i].w,brandings[i].h)||t('Enter W × H','W × H दर्ज करें');saveDraft();}\u001b[39m\n\u001b[31mfunction setBType(i,tp){brandings[i].type=tp;renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction addBranding(){if(brandings.length>=15){toast(t('Max 15 items','अधिकतम 15 आइटम'),'error');return;}brandings.push({type:'',w:'',h:'',qty:'1',blob:null,prev:null});renderBrandings();}\u001b[39m\n\u001b[31mfunction dupBr(i){if(brandings.length>=10){toast(t('Max 10 items','अधिकतम 10 आइटम'),'error');return;}const s=brandings[i-1];brandings.splice(i,0,{type:s.type,w:s.w,h:s.h,qty:s.qty,blob:null,prev:null});renderBrandings();toast(t('Duplicated — add photo','डुप्लीकेट — फोटो जोड़ें'),'info');}\u001b[39m\n\u001b[31mfunction rmBr(i){brandings.splice(i,1);renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction capBr(i){\u001b[39m\n\u001b[31m  const q=brandings[i]?.quality||imgQuality;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f,q==='hd'?1920:1280,q==='hd'?0.90:0.78));\u001b[39m\n\u001b[31m    brandings[i].blob=bs;brandings[i].prev=URL.createObjectURL(bs);\u001b[39m\n\u001b[31m    brandings[i].fromCamera=(e._src==='camera');\u001b[39m\n\u001b[31m    openAnnot(i);\u001b[39m\n\u001b[31m  },null,q);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmBrPh(i){brandings[i].blob=null;brandings[i].prev=null;renderBrandings();}\u001b[39m\n\u001b[31mfunction setBrQuality(i,q){brandings[i].quality=q;renderBrandings();}·\u001b[39m\n\u001b[31m// VIDEO / DOC\u001b[39m\n\u001b[31mfunction setVideo(v){F.hasVideo=v;document.getElementById('vid-yes').classList.toggle('sel',v);document.getElementById('vid-no').classList.toggle('sel',!v);document.getElementById('vid-sec').style.display=v?'block':'none';saveDraft();}\u001b[39m\n\u001b[31masync function handleVideo(e){videoBlob=e.target.files[0];if(!videoBlob)return;document.getElementById('vid-slot').innerHTML=`<div style=\\\"padding:14px;font-size:13px;color:var(--gn)\\\">✓ ${videoBlob.name} (${fmtSz(videoBlob.size)})</div>`;}\u001b[39m\n\u001b[31mfunction setBranding(v){F.hasBranding=v;document.getElementById('br-yes').classList.toggle('sel',v);document.getElementById('br-no').classList.toggle('sel',!v);document.getElementById('br-add').style.display=v?'block':'none';if(v&&brandings.length===0)addBranding();saveDraft();}\u001b[39m\n\u001b[31masync function handleDoc(e){const f=e.target.files[0];if(!f)return;submissionDoc=f.type.startsWith('image/')?await compress(f,1600,.85):f;const slot=document.getElementById('doc-slot');if(f.type.startsWith('image/')){slot.classList.add('filled');slot.innerHTML=`<img src=\\\"${URL.createObjectURL(submissionDoc)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}else{slot.innerHTML=`<div style=\\\"padding:16px;font-size:13px;color:var(--gn)\\\">✓ ${f.name} (${fmtSz(f.size)})</div>`;}buildReview();}·\u001b[39m\n\u001b[31m// CLIENT CHIPS\u001b[39m\n\u001b[31mfunction renderClientChips(){\u001b[39m\n\u001b[31m  const grid = document.getElementById('client-chips'); if (!grid) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  clientList.forEach(c => {\u001b[39m\n\u001b[31m    const sel = !_clientOtherMode && _selectedClient === c;\u001b[39m\n\u001b[31m    html += `<div class=\\\"cl-chip${sel?' sel':''}\\\" onclick=\\\"selectClientChip('${esc(c)}')\\\">${esc(c)}</div>`;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html += `<div class=\\\"cl-chip cl-chip-other${_clientOtherMode?' sel':''}\\\" onclick=\\\"selectClientOther()\\\"><span class=\\\"en-txt\\\">Other…</span><span class=\\\"hi-txt\\\">अन्य…</span></div>`;\u001b[39m\n\u001b[31m  grid.innerHTML = html;\u001b[39m\n\u001b[31m  document.getElementById('client-other-wrap').style.display = _clientOtherMode ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientChip(name){\u001b[39m\n\u001b[31m  _selectedClient = name; _clientOtherMode = false;\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').value = '';\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientOther(){\u001b[39m\n\u001b[31m  _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onClientOtherInput(){\u001b[39m\n\u001b[31m  _selectedClient = document.getElementById('f-client-other').value.trim();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction getClientName(){\u001b[39m\n\u001b[31m  if (_clientOtherMode) return (document.getElementById('f-client-other')?.value||'').trim();\u001b[39m\n\u001b[31m  return _selectedClient;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction autoSetClient(brandName){\u001b[39m\n\u001b[31m  if (!brandName) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  if (clientList.includes(brandName)){\u001b[39m\n\u001b[31m    _selectedClient = brandName; _clientOtherMode = false;\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    // Not in list — pre-fill the Other field\u001b[39m\n\u001b[31m    _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m    const inp = document.getElementById('f-client-other');\u001b[39m\n\u001b[31m    if (inp && !inp.value) inp.value = brandName;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// STEP VALIDATION\u001b[39m\n\u001b[31mfunction getSD(){if(selectedStore&&!manualMode)return{storeName:selectedStore.name,brand:selectedStore.brand||'',address:selectedStore.address||'',mobile:selectedStore.mobile||''};return{storeName:(document.getElementById('f-store')?.value||'').trim(),brand:document.getElementById('f-brand')?.value||'',address:(document.getElementById('f-addr')?.value||'').trim(),mobile:(document.getElementById('f-mobile')?.value||'').trim()};}\u001b[39m\n\u001b[31mfunction step2(){\u001b[39m\n\u001b[31m  const d=document.getElementById('f-date').value;\u001b[39m\n\u001b[31m  if(!d){toast('Select date','error');return;}\u001b[39m\n\u001b[31m  const sd=getSD();\u001b[39m\n\u001b[31m  if(!sd.storeName){toast('Select or enter store name','error');return;}\u001b[39m\n\u001b[31m  if(!sd.brand){toast('Select a brand','error');document.getElementById('brand-selector').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  if(!sd.address){toast('Enter store address','error');return;}\u001b[39m\n\u001b[31m  const clientName=getClientName();\u001b[39m\n\u001b[31m  if(!clientName){toast(t('Select a client','क्लाइंट चुनें'),'error');document.getElementById('client-chips').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  // Check missing fields filled\u001b[39m\n\u001b[31m  const missAddr=document.getElementById('sc-miss-address');\u001b[39m\n\u001b[31m  if(missAddr&&!missAddr.value.trim()){toast('Enter store address in the highlighted field','error');missAddr.focus();return;}\u001b[39m\n\u001b[31m  const missMob=document.getElementById('sc-miss-mobile');\u001b[39m\n\u001b[31m  // mobile not required — just copy if filled\u001b[39m\n\u001b[31m  if(missMob&&missMob.value.trim()&&!F.mobile)F.mobile=missMob.value.trim();\u001b[39m\n\u001b[31m  Object.assign(F,{date:d,...sd,clientName});saveDraft();\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');showView('form-photos');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction step3(){if(!frontPhotos.length){toast('Add at least 1 front view photo','error');return;}showView('form-video');}\u001b[39m\n\u001b[31mfunction step4(){if(F.hasVideo===undefined||F.hasVideo===null){toast('Select Yes or No for video','error');return;}renderBrandings();showView('form-branding');}\u001b[39m\n\u001b[31mfunction step5(){if(F.hasBranding===undefined||F.hasBranding===null){toast('Select Yes or No for branding space','error');return;}if(F.hasBranding){for(let i=0;i<brandings.length;i++){const b=brandings[i];if(!b.type){toast(`Select branding type for item ${i+1}`,'error');return;}if(!b.w||!b.h){toast(`Enter W and H dimensions for item ${i+1}`,'error');return;}if(!b.qty){toast(`Enter qty for item ${i+1}`,'error');return;}if(!b.blob&&!b.prev){toast(`Add photo for item ${i+1}`,'error');return;}}}renderAddl();buildReview();showView('form-additional');}·\u001b[39m\n\u001b[31m// REVIEW\u001b[39m\n\u001b[31mfunction buildReview(){const el=document.getElementById('rev-body');if(!el)return;const sd=getSD();const cn=getClientName();el.innerHTML=`<div><div class=\\\"rev-lbl\\\">Store</div><div class=\\\"rev-val\\\">${sd.storeName||'—'} · ${sd.brand||'—'}</div><div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">${sd.address||'—'}${sd.mobile?' · '+sd.mobile:''}</div>${gpsCoords?`<div style=\\\"font-size:11px;color:var(--gn);margin-top:3px\\\">📍 ${gpsCoords.lat}, ${gpsCoords.lng} ±${gpsCoords.acc}m</div>`:''}</div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Client</div><div class=\\\"rev-val\\\" style=\\\"color:${cn?'var(--nv)':'var(--rd)'}\\\">${cn||'⚠ Not selected — required'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Photos — Front · Inside · Additional</div><div class=\\\"rev-val\\\">${frontPhotos.length} · ${insidePhotos.length} · ${addlPhotos.length}</div><div class=\\\"rev-photos\\\">${[...frontPhotos,...insidePhotos].slice(0,6).map(p=>`<img class=\\\"rev-thumb\\\" src=\\\"${p.prev}\\\">`).join('')}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Video · Branding items</div><div class=\\\"rev-val\\\">${F.hasVideo?'Yes':'No'} · ${brandings.length} item(s)</div></div>${F.hasBranding&&brandings.length?`<div style=\\\"margin-top:8px\\\">${brandings.map((b,i)=>`<div style=\\\"font-size:12px;color:var(--g600);padding:4px 0;border-bottom:1px solid var(--g100)\\\">${i+1}. ${b.type||'No type'} — ${b.w||'?'}×${b.h||'?'}\\\" × ${b.qty||'?'} — ${calcSqft(b.w,b.h)||'?'}</div>`).join('')}</div>`:''}<div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Additional photos <span style=\\\"font-size:11px;color:var(--g400)\\\">(optional)</span></div><div class=\\\"rev-val\\\" style=\\\"color:${addlPhotos.length?'var(--gn)':'var(--g500)'}\\\">${addlPhotos.length?`✓ ${addlPhotos.length} photo(s) added`:'None added'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Mandatory document</div><div class=\\\"rev-val\\\" style=\\\"color:${(submissionDoc||_docExistingUrl)?'var(--gn)':'var(--rd)'}\\\">${(submissionDoc||_docExistingUrl)?'✓ Uploaded':'⚠ Missing — required'}</div></div>`;}·\u001b[39m\n\u001b[31m// SUBMIT\u001b[39m\n\u001b[31masync function submitRecce(){\u001b[39m\n\u001b[31m  if(!submissionDoc&&!_docExistingUrl){toast('Upload mandatory doc first','error');return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('sub-btn');btn.disabled=true;btn.textContent='Saving…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const isEdit=!!(F.editingId);\u001b[39m\n\u001b[31m    const id=isEdit?F.editingId:('RC_'+Date.now()+'_'+Math.random().toString(36).slice(2,6).toUpperCase());\u001b[39m\n\u001b[31m    const sd=getSD();\u001b[39m\n\u001b[31m    const _hub=_recceHubUser();\u001b[39m\n\u001b[31m    const entry={id,timestamp:isEdit?(await dbGet('subs',id))?.timestamp||new Date().toISOString():new Date().toISOString(),editedAt:isEdit?new Date().toISOString():undefined,status:'pending',submittedBy:_hub.empId||null,submittedByName:_hub.name||null,data:{...F,...sd,gpsCoords,frontPhotos:await Promise.all(frontPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),insidePhotos:await Promise.all(insidePhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),videoNote:F.hasVideo&&videoBlob?`Video local (${fmtSz(videoBlob.size)}) — share via WhatsApp`:null,videoCmt:document.getElementById('f-vid-cmt')?.value||'',brandings:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:calcSqft(b.w,b.h),photoB64:b.blob?await b64(b.blob):null,existingUrl:b.existingUrl||null}))),addlPhotos:await Promise.all(addlPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,desc:p.desc,existingUrl:p.existingUrl||null}))),docB64:submissionDoc?await b64(submissionDoc):null,_docExistingUrl:_docExistingUrl||null}};\u001b[39m\n\u001b[31m    entry.campaignId       = _selectedCampaignId || null;\u001b[39m\n\u001b[31m    entry.notifySupervisor = _notifySupervisor   || false;\u001b[39m\n\u001b[31m    await dbPut('subs',entry);\u001b[39m\n\u001b[31m    await dbDel('draft','current');\u001b[39m\n\u001b[31m    toast(isEdit?'Recce updated ✓':'Recce saved ✓','success');\u001b[39m\n\u001b[31m    if(navigator.onLine)syncNow();\u001b[39m\n\u001b[31m    showView('home');loadHome();checkDraft();\u001b[39m\n\u001b[31m  }catch(err){toast('Error: '+err.message,'error');}\u001b[39m\n\u001b[31m  finally{btn.disabled=false;btn.textContent='Submit Recce ✓';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// SYNC\u001b[39m\n\u001b[31masync function syncNow() {\u001b[39m\n\u001b[31m  if (!navigator.onLine) { toast('Offline — sync when back online', 'info'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('sync-btn');\u001b[39m\n\u001b[31m  const SYNC_ICON = '<svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg>Sync';\u001b[39m\n\u001b[31m  if (btn) { btn.innerHTML = '<span class=\\\"spin\\\">↻</span> Syncing'; btn.disabled = true; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const all      = await dbAll('subs');\u001b[39m\n\u001b[31m    const pend     = all.filter(s => s.status === 'pending' || s.status === 'failed');\u001b[39m\n\u001b[31m    const backfill = all.filter(s => s.status === 'synced' && !s.gasAt);\u001b[39m\n\u001b[31m    if (!pend.length && !backfill.length) { toast('All synced ✓', 'success'); return; }·\u001b[39m\n\u001b[31m    const gasUrl = (await cfg('gas-url')) || DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    function fireGas(s) {\u001b[39m\n\u001b[31m      if (!gasUrl) return;\u001b[39m\n\u001b[31m      fetch(gasUrl, { method:'POST', mode:'no-cors',\u001b[39m\n\u001b[31m        body: JSON.stringify({ action:'syncSheet', submission: s }) })\u001b[39m\n\u001b[31m        .catch(() => {});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    let ok = 0;\u001b[39m\n\u001b[31m    for (const s of pend) {\u001b[39m\n\u001b[31m      // Fire Sheet sync (no-cors fire-and-forget — writes row to Google Sheet)\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      // Primary: upload photos → auto-trigger slides → generate report → store in PostgreSQL\u001b[39m\n\u001b[31m      const { ok: pgOk, viewUrl } = await syncToPostgres(s);\u001b[39m\n\u001b[31m      if (pgOk) {\u001b[39m\n\u001b[31m        s.status = 'synced'; s.syncedAt = new Date().toISOString();\u001b[39m\n\u001b[31m        if (viewUrl) s.viewUrl = viewUrl;\u001b[39m\n\u001b[31m        await dbPut('subs', s); ok++;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        s.status = 'failed'; await dbPut('subs', s);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Backfill: entries synced to Postgres but never reached Sheet GAS\u001b[39m\n\u001b[31m    for (const s of backfill) {\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      await dbPut('subs', s);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if (backfill.length) toast(`Sent ${backfill.length} older entries to Sheet`, 'info');·\u001b[39m\n\u001b[31m    await cfg('last-sync', new Date().toISOString());\u001b[39m\n\u001b[31m    if (pend.length) toast(`Synced ${ok}/${pend.length}`, ok === pend.length ? 'success' : 'error');\u001b[39m\n\u001b[31m    loadHome();\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.innerHTML = SYNC_ICON; btn.disabled = false; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN HOME ──────────────────────────────────────────────\u001b[39m\n\u001b[31masync function loadHomeAdmin() {\u001b[39m\n\u001b[31m  // Adapt UI for admin view\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const _sh = document.querySelector('.sh'); if (_sh) _sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = 'All Submissions';\u001b[39m\n\u001b[31m  const slbls = document.querySelectorAll('.slbl');\u001b[39m\n\u001b[31m  if (slbls[0]) slbls[0].textContent = 'Showing';\u001b[39m\n\u001b[31m  if (slbls[1]) slbls[1].textContent = 'Agents';·\u001b[39m\n\u001b[31m  // Back-to-menu button for supervisors\u001b[39m\n\u001b[31m  if (_isSupervisor() && !document.getElementById('sup-back-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => { document.getElementById('sup-back-btn').remove(); renderSupLanding(); };\u001b[39m\n\u001b[31m    const content = document.querySelector('#view-home .content');\u001b[39m\n\u001b[31m    content.prepend(bb);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Show filter bar — restore if hidden by renderSupLanding, else inject fresh\u001b[39m\n\u001b[31m  const _existingFb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (_existingFb) { _existingFb.style.display = ''; }\u001b[39m\n\u001b[31m  if (!_existingFb) {\u001b[39m\n\u001b[31m    const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m    const fb = document.createElement('div');\u001b[39m\n\u001b[31m    fb.id = 'admin-filter-bar';\u001b[39m\n\u001b[31m    fb.className = 'af-bar';\u001b[39m\n\u001b[31m    fb.innerHTML =\u001b[39m\n\u001b[31m      `<div class=\\\"af-grid\\\">\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-agent\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Agents</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-brand\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Brands</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-client\\\" onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Clients</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-period\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">All Time</option>\u001b[39m\n\u001b[31m          <option value=\\\"7\\\">Last 7 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"30\\\">Last 30 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"90\\\">Last 3 months</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-group\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"date\\\">Sort: Recent</option>\u001b[39m\n\u001b[31m          <option value=\\\"agent\\\">Group: Agent</option>\u001b[39m\n\u001b[31m          <option value=\\\"brand\\\">Group: Brand</option>\u001b[39m\n\u001b[31m          <option value=\\\"client\\\">Group: Client</option>\u001b[39m\n\u001b[31m          <option value=\\\"city\\\">Group: City</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m        <input class=\\\"af-inp\\\" id=\\\"af-search\\\" type=\\\"text\\\" placeholder=\\\"🔍 Search store or city…\\\" oninput=\\\"renderAdminList()\\\" style=\\\"flex:1;min-width:120px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"del-toggle-btn\\\" id=\\\"del-toggle-btn\\\" onclick=\\\"toggleDeletedView()\\\" style=\\\"flex-shrink:0\\\">📋 View Deleted</button>\u001b[39m\n\u001b[31m        ${_isSupervisor() ? `<button class=\\\"del-toggle-btn\\\" id=\\\"pending-job-btn\\\" onclick=\\\"togglePendingJobView()\\\" style=\\\"flex-shrink:0;background:#fef3c7;color:#92400e;border-color:#f59e0b\\\">⚑ Unlinked <span id=\\\"pending-job-count\\\" style=\\\"font-weight:900\\\"></span></button>` : ''}\u001b[39m\n\u001b[31m        ${_adminUnlocked ? `<button class=\\\"del-toggle-btn\\\" id=\\\"regen-rpt-btn\\\" onclick=\\\"regenAllReports()\\\" style=\\\"flex-shrink:0\\\">&#x21BB; Regen Reports</button>` : ''}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    sh.parentNode.insertBefore(fb, sh);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Fetch\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  list.innerHTML = '<div style=\\\"text-align:center;padding:40px\\\"><div class=\\\"spinner\\\"></div></div>';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?order=submitted_at.desc&limit=500`, { headers: _RC_READ });\u001b[39m\n\u001b[31m    _adminRows = resp.ok ? await resp.json() : [];\u001b[39m\n\u001b[31m    document.getElementById('stat-total').textContent = _adminRows.length;\u001b[39m\n\u001b[31m    if (resp.ok) {\u001b[39m\n\u001b[31m      const now = new Date();\u001b[39m\n\u001b[31m      document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m        'Loaded ' + now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Populate agent dropdown\u001b[39m\n\u001b[31m    const agents = [...new Set(_adminRows.map(r => r.submitted_by).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-agent').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Agents (${agents.length})</option>` +\u001b[39m\n\u001b[31m      agents.map(a => `<option value=\\\"${a}\\\">${a}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate brand dropdown\u001b[39m\n\u001b[31m    const brands = [...new Set(_adminRows.map(r => r.brand).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-brand').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Brands (${brands.length})</option>` +\u001b[39m\n\u001b[31m      brands.map(b => `<option value=\\\"${b}\\\">${b}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate client dropdown\u001b[39m\n\u001b[31m    const clients = [...new Set(_adminRows.map(r => r.client_name).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-client').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Clients (${clients.length})</option>` +\u001b[39m\n\u001b[31m      clients.map(c => `<option value=\\\"${c}\\\">${c}</option>`).join('');·\u001b[39m\n\u001b[31m    // Update pending-job count badge\u001b[39m\n\u001b[31m    const unlinkedCount = _adminRows.filter(r => !r.deleted_at && !r.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinkedCount ? `(${unlinkedCount})` : '';·\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">⚠️</div><div class=\\\"empty-txt\\\">Could not load — check connection</div></div>';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction togglePendingJobView() {\u001b[39m\n\u001b[31m  _pendingJobFilter = !_pendingJobFilter;\u001b[39m\n\u001b[31m  _showDeletedView  = false;\u001b[39m\n\u001b[31m  const btn = document.getElementById('pending-job-btn');\u001b[39m\n\u001b[31m  if (btn) btn.style.background = _pendingJobFilter ? '#f59e0b' : '#fef3c7';\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function openLinkJobModal(subId, storeName) {\u001b[39m\n\u001b[31m  _linkJobSubId = subId;\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  const storeEl = document.getElementById('link-job-store');\u001b[39m\n\u001b[31m  const sel = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  if (!modal) return;\u001b[39m\n\u001b[31m  if (storeEl) storeEl.textContent = storeName || subId;\u001b[39m\n\u001b[31m  if (errEl) errEl.textContent = '';\u001b[39m\n\u001b[31m  // Load campaigns into dropdown\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (!_campaignList.length) {\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m      _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  if (sel) {\u001b[39m\n\u001b[31m    sel.innerHTML = '<option value=\\\"\\\">— Select campaign —</option>' +\u001b[39m\n\u001b[31m      _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  modal.style.display = 'flex';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeLinkJobModal() {\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  if (modal) modal.style.display = 'none';\u001b[39m\n\u001b[31m  _linkJobSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function saveLinkJob() {\u001b[39m\n\u001b[31m  const sel    = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl  = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  const campId = sel?.value || '';\u001b[39m\n\u001b[31m  if (!campId) { if (errEl) errEl.textContent = 'Select a campaign'; return; }\u001b[39m\n\u001b[31m  if (!_linkJobSubId) return;\u001b[39m\n\u001b[31m  const btn = document.querySelector('#modal-link-job button[onclick=\\\"saveLinkJob()\\\"]');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Linking…'; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(_linkJobSubId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ campaign_id: campId }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Patch failed');\u001b[39m\n\u001b[31m    // Update local cache\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === _linkJobSubId);\u001b[39m\n\u001b[31m    if (idx >= 0) _adminRows[idx].campaign_id = campId;\u001b[39m\n\u001b[31m    // Update pending count badge\u001b[39m\n\u001b[31m    const unlinked = _adminRows.filter(x => !x.deleted_at && !x.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinked ? `(${unlinked})` : '';\u001b[39m\n\u001b[31m    closeLinkJobModal();\u001b[39m\n\u001b[31m    toast('Job linked ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    if (errEl) errEl.textContent = 'Failed to link — try again';\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.disabled = false; btn.textContent = '🔗 Link Job'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAdminList() {\u001b[39m\n\u001b[31m  const agent  = document.getElementById('af-agent')?.value  || '';\u001b[39m\n\u001b[31m  const brand  = document.getElementById('af-brand')?.value  || '';\u001b[39m\n\u001b[31m  const period = document.getElementById('af-period')?.value || '';\u001b[39m\n\u001b[31m  const search = (document.getElementById('af-search')?.value || '').toLowerCase().trim();\u001b[39m\n\u001b[31m  const group  = document.getElementById('af-group')?.value  || 'date';·\u001b[39m\n\u001b[31m  // Pending-job filter overrides deleted/normal modes\u001b[39m\n\u001b[31m  let rows;\u001b[39m\n\u001b[31m  if (_pendingJobFilter) {\u001b[39m\n\u001b[31m    rows = _adminRows.filter(r => !r.deleted_at && !r.campaign_id);\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows = _showDeletedView\u001b[39m\n\u001b[31m      ? _adminRows.filter(r => r.deleted_at)\u001b[39m\n\u001b[31m      : _adminRows.filter(r => !r.deleted_at);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const client = document.getElementById('af-client')?.value || '';\u001b[39m\n\u001b[31m  if (agent)  rows = rows.filter(r => r.submitted_by === agent);\u001b[39m\n\u001b[31m  if (brand)  rows = rows.filter(r => r.brand === brand);\u001b[39m\n\u001b[31m  if (client) rows = rows.filter(r => r.client_name === client);\u001b[39m\n\u001b[31m  if (search) rows = rows.filter(r => (r.store_name||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.city||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.client_name||'').toLowerCase().includes(search));\u001b[39m\n\u001b[31m  if (period && !_showDeletedView) {\u001b[39m\n\u001b[31m    const cut = new Date(); cut.setDate(cut.getDate() - parseInt(period));\u001b[39m\n\u001b[31m    rows = rows.filter(r => new Date(r.submitted_at) >= cut);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const uniqueAgents = new Set(rows.map(r => r.submitted_by).filter(Boolean)).size;\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = rows.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = uniqueAgents;\u001b[39m\n\u001b[31m  const deletedCount = _adminRows.filter(r => r.deleted_at).length;\u001b[39m\n\u001b[31m  const delBtn = document.getElementById('del-toggle-btn');\u001b[39m\n\u001b[31m  if (delBtn) {\u001b[39m\n\u001b[31m    if (_showDeletedView) {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 Hide Deleted (${deletedCount})` : '📋 Hide Deleted';\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 View Deleted (${deletedCount})` : '📋 View Deleted';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    delBtn.classList.toggle('active', _showDeletedView);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!rows.length) {\u001b[39m\n\u001b[31m    list.innerHTML = _showDeletedView\u001b[39m\n\u001b[31m      ? '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">✅</div><div class=\\\"empty-txt\\\">No deleted recces</div></div>'\u001b[39m\n\u001b[31m      : '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">🔍</div><div class=\\\"empty-txt\\\">No matching submissions</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (group === 'agent') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.submitted_by||'').localeCompare(b.submitted_by||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.submitted_by || 'Unknown';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">👤 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'brand') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.brand||'').localeCompare(b.brand||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.brand || 'No Brand';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🏷 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'client') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.client_name||'').localeCompare(b.client_name||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.client_name || 'No Client';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🤝 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'city') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.city||'').localeCompare(b.city||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.city || 'No City';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">📍 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows.sort((a,b) => new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    rows.forEach(r => { html += adminCard(r); });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminCard(r) {\u001b[39m\n\u001b[31m  const dt    = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds    = dt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m  const tm    = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const photos = (r.front_photos||0) + (r.inside_photos||0) + (r.addl_photos||0);\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const canDelete  = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const canArchive = _RECCE_CFG_ADMINS.includes(hub?.empId) && !r.client_archived;·\u001b[39m\n\u001b[31m  // Client status badge\u001b[39m\n\u001b[31m  const clientStatusMap = {\u001b[39m\n\u001b[31m    approved:              {t:'✓ Approved',    s:'color:#166534;background:#dcfce7;border:1px solid #86efac'},\u001b[39m\n\u001b[31m    rejected:              {t:'✕ Rejected',    s:'color:#991b1b;background:#fee2e2;border:1px solid #fca5a5'},\u001b[39m\n\u001b[31m    approved_with_changes: {t:'✎ Approved w/ Comments', s:'color:#92400e;background:#fef3c7;border:1px solid #fcd34d'},\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const csCfg = clientStatusMap[r.client_status];\u001b[39m\n\u001b[31m  const clientStatusBadge = csCfg\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;${csCfg.s}\\\">${csCfg.t}</span>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const archiveBadge = r.client_archived\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;color:#475569;background:#f1f5f9;border:1px solid #cbd5e1\\\">⬚ Client hidden</span>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  if (r.deleted_at) {\u001b[39m\n\u001b[31m    const delDt = new Date(r.deleted_at);\u001b[39m\n\u001b[31m    const delDs = delDt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m    const reasonLabel = r.deletion_reason === 'wrong' ? 'Wrong' : r.deletion_reason === 'duplicate' ? 'Duplicate' : 'Test';\u001b[39m\n\u001b[31m    return `<div class=\\\"asc deleted-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m        <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m            <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds}</span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m          <span class=\\\"del-reason-tag\\\">❌ ${reasonLabel}</span>\u001b[39m\n\u001b[31m          <div class=\\\"del-by-txt\\\">by ${r.deleted_by||'?'} · ${delDs}</div>\u001b[39m\n\u001b[31m          ${canDelete ? `<button class=\\\"restore-btn\\\" onclick=\\\"event.stopPropagation();restoreRecce('${r.sub_id}')\\\">↩ Restore</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Submitted by ${r.submitted_by||'?'}</div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const chips = [\u001b[39m\n\u001b[31m    photos > 0   ? `📷 ${photos} photo${photos!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.has_video  ? '🎥 Video' : null,\u001b[39m\n\u001b[31m    r.has_branding ? `🪧 ${r.branding_count} branding${r.branding_count!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.city       ? `📍 ${r.city}` : (r.address ? `📍 ${r.address}` : null),\u001b[39m\n\u001b[31m    r.view_url   ? '👁 View available' : null,\u001b[39m\n\u001b[31m  ].filter(Boolean);·\u001b[39m\n\u001b[31m  const delBtnHtml = canDelete\u001b[39m\n\u001b[31m    ? `<button class=\\\"del-btn\\\" onclick=\\\"event.stopPropagation();openDeleteModal('${r.sub_id}')\\\" title=\\\"Delete recce\\\">🗑</button>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const editReqHtml = r.edit_assigned_to\u001b[39m\n\u001b[31m    ? `<span class=\\\"edit-req-badge\\\">✏ Edit sent to ${r.edit_assigned_to}</span>`\u001b[39m\n\u001b[31m    : (_isSupervisor()\u001b[39m\n\u001b[31m        ? `<button class=\\\"req-edit-btn\\\" onclick=\\\"event.stopPropagation();openEditRequestModal('${r.sub_id}')\\\">✏ Request Edit</button>`\u001b[39m\n\u001b[31m        : '');·\u001b[39m\n\u001b[31m  const editRow = editReqHtml\u001b[39m\n\u001b[31m    ? `<div style=\\\"margin-top:6px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">${editReqHtml}</div>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const showPdfBtn = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m  const pdfClass = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m  const pdfLabel = '📄 PDF';\u001b[39m\n\u001b[31m  const linkJobBtn = (_pendingJobFilter && _isSupervisor() && !r.campaign_id)\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:#f59e0b;color:#000;border-color:#f59e0b;font-weight:700\\\" onclick=\\\"event.stopPropagation();openLinkJobModal('${r.sub_id}','${(r.store_name||'Unknown').replace(/'/g,'\\\\\\\\\\\\'')}')\\\">🔗 Link Job</button>`\u001b[39m\n\u001b[31m    : (r.campaign_id ? `<span style=\\\"font-size:10px;color:var(--g400);align-self:center\\\">🔗 ${r.campaign_id}</span>` : '');\u001b[39m\n\u001b[31m  const archiveBtn = canArchive\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:rgba(99,102,241,.08);border-color:var(--nv);color:var(--nv)\\\" onclick=\\\"event.stopPropagation();archiveRecce('${r.sub_id}')\\\">⛚ Archive</button>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const btnsRow = `<div class=\\\"rpt-btns\\\">\u001b[39m\n\u001b[31m    <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openAdminRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m    ${showPdfBtn ? `<button class=\\\"${pdfClass}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">${pdfLabel}</button>` : ''}\u001b[39m\n\u001b[31m    ${linkJobBtn}\u001b[39m\n\u001b[31m    ${archiveBtn}\u001b[39m\n\u001b[31m  </div>`;·\u001b[39m\n\u001b[31m  return `<div class=\\\"asc\\\">\u001b[39m\n\u001b[31m    <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m      <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m          ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          ${r.client_name&&r.client_name!==r.brand?`<span class=\\\"client-tag\\\">🤝 ${r.client_name}</span>`:''}\u001b[39m\n\u001b[31m          <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds} · ${tm}</span>\u001b[39m\n\u001b[31m          ${clientStatusBadge}\u001b[39m\n\u001b[31m          ${archiveBadge}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <span class=\\\"asc-agent\\\">👤 ${r.submitted_by||'?'}</span>\u001b[39m\n\u001b[31m        ${delBtnHtml}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    ${chips.length?`<div class=\\\"asc-chips\\\">${chips.map(c=>`<span class=\\\"asc-chip\\\">${c}</span>`).join('')}</div>`:''}\u001b[39m\n\u001b[31m    ${editRow}\u001b[39m\n\u001b[31m    ${btnsRow}\u001b[39m\n\u001b[31m  </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _ensurePdfOverlay() {\u001b[39m\n\u001b[31m  if (document.getElementById('pdf-wait-ov')) return;\u001b[39m\n\u001b[31m  const ov = document.createElement('div');\u001b[39m\n\u001b[31m  ov.id = 'pdf-wait-ov';\u001b[39m\n\u001b[31m  ov.innerHTML = '<div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Generating PDF…</div><div class=\\\"po-sub\\\" id=\\\"pw-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"pw-pfill\\\"></div></div>';\u001b[39m\n\u001b[31m  document.body.appendChild(ov);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _showPdfOverlay(msg) {\u001b[39m\n\u001b[31m  _ensurePdfOverlay();\u001b[39m\n\u001b[31m  document.getElementById('pw-sub').textContent = msg || '';\u001b[39m\n\u001b[31m  document.getElementById('pw-pfill').style.width = '0%';\u001b[39m\n\u001b[31m  document.getElementById('pdf-wait-ov').style.display = 'flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _hidePdfOverlay() {\u001b[39m\n\u001b[31m  const ov = document.getElementById('pdf-wait-ov');\u001b[39m\n\u001b[31m  if (ov) ov.style.display = 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function openPdf(subId, pdfUrl, viewUrl) {\u001b[39m\n\u001b[31m  if (pdfUrl) { window.open(pdfUrl, '_blank'); return; }\u001b[39m\n\u001b[31m  if (!viewUrl) {\u001b[39m\n\u001b[31m    toast('Report view not available yet — please try after the report is generated.', 'info');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _showPdfOverlay('Requesting PDF generation…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type': 'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({type: 'regen-pdf', subId, viewUrl})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  let attempts = 0;\u001b[39m\n\u001b[31m  const MAX = 24;\u001b[39m\n\u001b[31m  const poll = async () => {\u001b[39m\n\u001b[31m    attempts++;\u001b[39m\n\u001b[31m    const pct = Math.min(88, Math.round(attempts / MAX * 88));\u001b[39m\n\u001b[31m    document.getElementById('pw-pfill').style.width = pct + '%';\u001b[39m\n\u001b[31m    const left = Math.ceil((MAX - attempts) * 5);\u001b[39m\n\u001b[31m    document.getElementById('pw-sub').textContent = 'Checking… (' + left + 's remaining)';\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const res = await fetch('/db/submissions?sub_id=eq.' + subId + '&select=pdf_url', {\u001b[39m\n\u001b[31m        headers: {'Content-Profile': 'recce', 'Accept-Profile': 'recce'}\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      const rows = await res.json();\u001b[39m\n\u001b[31m      if (rows && rows[0] && rows[0].pdf_url) {\u001b[39m\n\u001b[31m        document.getElementById('pw-pfill').style.width = '100%';\u001b[39m\n\u001b[31m        setTimeout(() => { _hidePdfOverlay(); window.open(rows[0].pdf_url, '_blank'); }, 400);\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(_) {}\u001b[39m\n\u001b[31m    if (attempts >= MAX) { _hidePdfOverlay(); toast('PDF generation timed out. Please try again later.', 'error'); return; }\u001b[39m\n\u001b[31m    setTimeout(poll, 5000);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  setTimeout(poll, 4000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openAdminRecce(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];·\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">\u001b[39m\n\u001b[31m         📍 View on Google Maps (${Number(r.gps_lat).toFixed(4)}, ${Number(r.gps_lng).toFixed(4)})\u001b[39m\n\u001b[31m       </a>` : '';·\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} ft × ${b.h||'?'} ft · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos not yet available — field agent must re-sync from their device to upload view\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Submission Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">👤 ${r.submitted_by||'Unknown'}</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            ${meta.videoCmt?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500);font-size:12px\\\">${meta.videoCmt}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m          ${(()=>{\u001b[39m\n\u001b[31m            const hub2 = _recceHubUser();\u001b[39m\n\u001b[31m            const isHP = _RECCE_CFG_ADMINS.includes(hub2?.empId);\u001b[39m\n\u001b[31m            const csMap = {\u001b[39m\n\u001b[31m              approved:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#166534;background:#dcfce7\\\">✓ Approved</span>',\u001b[39m\n\u001b[31m              rejected:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#991b1b;background:#fee2e2\\\">✕ Rejected</span>',\u001b[39m\n\u001b[31m              approved_with_changes: '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#92400e;background:#fef3c7\\\">✎ Approved w/ Comments</span>',\u001b[39m\n\u001b[31m            };\u001b[39m\n\u001b[31m            const csBadge = csMap[r.client_status] || '';\u001b[39m\n\u001b[31m            const approvedAt = r.client_approved_at\u001b[39m\n\u001b[31m              ? new Date(r.client_approved_at).toLocaleString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit',timeZone:'Asia/Kolkata'})\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const pdfLink = r.client_approval_pdf_url\u001b[39m\n\u001b[31m              ? `<a href=\\\"${r.client_approval_pdf_url}\\\" target=\\\"_blank\\\" style=\\\"font-size:12px;color:var(--or);text-decoration:none\\\">⬇ Approval PDF</a>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const archAct = isHP && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveRecce('${r.sub_id}')\\\" style=\\\"font-size:12px;color:var(--nv);background:none;border:1px solid var(--nv);border-radius:6px;padding:4px 10px;cursor:pointer\\\">⦽ Archive from client</button>`\u001b[39m\n\u001b[31m              : (r.client_archived ? '<span style=\\\"font-size:11px;color:var(--g400)\\\">⦽ Hidden from client</span>' : '');\u001b[39m\n\u001b[31m            const campAct = isHP && r.campaign_id && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveAllForCampaign('${r.campaign_id}')\\\" style=\\\"font-size:11px;color:#991b1b;background:none;border:1px solid #fca5a5;border-radius:6px;padding:3px 8px;cursor:pointer\\\">Archive ALL for ${r.campaign_id}</button>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            if (!csBadge && !pdfLink && !archAct) return '';\u001b[39m\n\u001b[31m            return `<div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m              <div class=\\\"ardl-lbl\\\">Client Approval</div>\u001b[39m\n\u001b[31m              ${csBadge ? `<div style=\\\"margin-bottom:5px\\\">${csBadge}${approvedAt ? ' <span style=\\\"font-size:11px;color:var(--g400)\\\">' + approvedAt + '</span>' : ''}</div>` : ''}\u001b[39m\n\u001b[31m              ${r.client_comment ? `<div style=\\\"font-size:12px;color:var(--g600);background:var(--g50);border-radius:6px;padding:7px 10px;margin-bottom:5px\\\">\\\"${r.client_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m              ${pdfLink ? `<div style=\\\"margin-bottom:4px\\\">${pdfLink}</div>` : ''}\u001b[39m\n\u001b[31m              ${archAct ? `<div style=\\\"margin-bottom:4px\\\">${archAct}</div>` : ''}\u001b[39m\n\u001b[31m              ${campAct ? `<div>${campAct}</div>` : ''}\u001b[39m\n\u001b[31m            </div>`;\u001b[39m\n\u001b[31m          })()}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeAdminDetail() {\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveRecce(subId) {\u001b[39m\n\u001b[31m  if (!confirm('Archive this recce from client view? The client will no longer see it.')) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(subId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) Object.assign(_adminRows[idx], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    toast('Archived from client view ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveAllForCampaign(campaignId) {\u001b[39m\n\u001b[31m  if (!confirm(`Archive ALL recces for campaign \\\"${campaignId}\\\" from client view?\\\\nClients will no longer see any recce from this campaign.`)) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?campaign_id=eq.${encodeURIComponent(campaignId)}&client_archived=eq.false`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    _adminRows.forEach((row, i) => {\u001b[39m\n\u001b[31m      if (row.campaign_id === campaignId) Object.assign(_adminRows[i], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    toast(`All recces for ${campaignId} archived ✓`, 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function regenAllReports() {\u001b[39m\n\u001b[31m  if (!_adminUnlocked) { toast('Admin access required', 'error'); return; }\u001b[39m\n\u001b[31m  const rows = _adminRows.filter(r => !r.deleted_at && r.photo_urls);\u001b[39m\n\u001b[31m  if (!rows.length) { toast('No synced rows with photos found', 'error'); return; }·\u001b[39m\n\u001b[31m  const btn = document.getElementById('regen-rpt-btn');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Regenerating…'; }\u001b[39m\n\u001b[31m  toast(`Regenerating ${rows.length} reports…`, 'info');·\u001b[39m\n\u001b[31m  let done = 0, failed = 0;\u001b[39m\n\u001b[31m  for (const r of rows) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const photoUrls = typeof r.photo_urls === 'string' ? JSON.parse(r.photo_urls) : (r.photo_urls || {});\u001b[39m\n\u001b[31m      let meta = {};\u001b[39m\n\u001b[31m      try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m      const entry = {\u001b[39m\n\u001b[31m        id: r.sub_id,\u001b[39m\n\u001b[31m        timestamp: r.submitted_at,\u001b[39m\n\u001b[31m        submittedBy: r.submitted_by,\u001b[39m\n\u001b[31m        data: {\u001b[39m\n\u001b[31m          storeName:    r.store_name,\u001b[39m\n\u001b[31m          brand:        r.brand,\u001b[39m\n\u001b[31m          clientName:   r.client_name,\u001b[39m\n\u001b[31m          date:         r.visit_date,\u001b[39m\n\u001b[31m          address:      r.address,\u001b[39m\n\u001b[31m          city:         r.city,\u001b[39m\n\u001b[31m          mobile:       r.mobile,\u001b[39m\n\u001b[31m          gpsCoords:    (r.gps_lat && r.gps_lng) ? { lat: r.gps_lat, lng: r.gps_lng } : null,\u001b[39m\n\u001b[31m          hasVideo:     r.has_video,\u001b[39m\n\u001b[31m          videoNote:    meta.videoNote || '',\u001b[39m\n\u001b[31m          videoCmt:     meta.videoCmt  || '',\u001b[39m\n\u001b[31m          frontPhotos:  (photoUrls.front   || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          insidePhotos: (photoUrls.inside  || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          addlPhotos:   (photoUrls.addl    || []).map(() => ({ desc: '' })),\u001b[39m\n\u001b[31m          brandings:    (meta.brandings    || []),\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      };·\u001b[39m\n\u001b[31m      const html = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m      const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m        method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m        body: JSON.stringify({ type: 'save-view', subId: r.sub_id, html })\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!vResp.ok) { failed++; continue; }\u001b[39m\n\u001b[31m      const vr = await vResp.json();\u001b[39m\n\u001b[31m      if (!vr.success) { failed++; continue; }·\u001b[39m\n\u001b[31m      if (vr.url && vr.url !== r.view_url) {\u001b[39m\n\u001b[31m        await fetch(`${_RC_BASE}/submissions?sub_id=eq.${r.sub_id}`, {\u001b[39m\n\u001b[31m          method: 'PATCH', headers: _RC_WRITE,\u001b[39m\n\u001b[31m          body: JSON.stringify({ view_url: vr.url })\u001b[39m\n\u001b[31m        });\u001b[39m\n\u001b[31m        const idx = _adminRows.findIndex(x => x.sub_id === r.sub_id);\u001b[39m\n\u001b[31m        if (idx >= 0) _adminRows[idx].view_url = vr.url;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      done++;\u001b[39m\n\u001b[31m    } catch(e) { failed++; }\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = false; btn.textContent = '↻ Regen Reports'; }\u001b[39m\n\u001b[31m  toast(`Done: ${done} regenerated${failed ? `, ${failed} failed` : ''}`, done > 0 ? 'success' : 'error');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction toggleDeletedView() {\u001b[39m\n\u001b[31m  _showDeletedView = !_showDeletedView;\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openDeleteModal(subId) {\u001b[39m\n\u001b[31m  _pendingDeleteId = subId;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  const sub = document.getElementById('del-modal-sub');\u001b[39m\n\u001b[31m  if (sub) sub.textContent = r ? `Delete: \\\"${r.store_name||'Unknown'}\\\"` : 'Select reason for deletion:';\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectDeleteReason(reason) {\u001b[39m\n\u001b[31m  _pendingDeleteReason = reason;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  document.getElementById('reason-' + reason)?.classList.add('sel');\u001b[39m\n\u001b[31m  document.getElementById('del-confirm-btn').classList.remove('no-reason');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeDeleteModal() {\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingDeleteId = null;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  clearTimeout(_tt);\u001b[39m\n\u001b[31m  document.getElementById('toast').classList.remove('show');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function restoreRecce(subId) {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({ deleted_at: null, deleted_by: null, deletion_reason: null }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Restore failed: ' + r.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_at = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_by = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deletion_reason = null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    toast('Recce restored ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Restore failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmDelete() {\u001b[39m\n\u001b[31m  if (!_pendingDeleteReason) {\u001b[39m\n\u001b[31m    const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m    btn.style.animation = 'none';\u001b[39m\n\u001b[31m    btn.offsetHeight; // reflow\u001b[39m\n\u001b[31m    btn.style.animation = 'shake .35s ease';\u001b[39m\n\u001b[31m    toast('Select a reason first', 'error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if (!_pendingDeleteId) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Deleting…';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      // Hard delete — no audit trail\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'DELETE',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Delete failed: ' + r.status);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Soft delete — stamp deleted_at, deleted_by, deletion_reason\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'PATCH',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m        body: JSON.stringify({\u001b[39m\n\u001b[31m          deleted_at: new Date().toISOString(),\u001b[39m\n\u001b[31m          deleted_by: hub.empId,\u001b[39m\n\u001b[31m          deletion_reason: _pendingDeleteReason,\u001b[39m\n\u001b[31m        }),\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Update failed: ' + r.status);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Remove or update in local cache\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      _adminRows = _adminRows.filter(x => x.sub_id !== _pendingDeleteId);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      const idx = _adminRows.findIndex(x => x.sub_id === _pendingDeleteId);\u001b[39m\n\u001b[31m      if (idx >= 0) {\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_at = new Date().toISOString();\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_by = hub.empId;\u001b[39m\n\u001b[31m        _adminRows[idx].deletion_reason = _pendingDeleteReason;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeDeleteModal();\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast('Recce deleted', 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Delete failed', 'error');\u001b[39m\n\u001b[31m    btn.classList.remove('no-reason');\u001b[39m\n\u001b[31m    btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openMyServerRecce(subId) {\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  // No view yet — show metadata modal (same layout as admin detail)\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta==='string' ? JSON.parse(r.meta) : (r.meta||{}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">📍 View on Google Maps</a>` : '';\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} × ${b.h||'?'} in · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos will appear after next sync from original device\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Visit Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupLanding() {\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = 'none';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = 'none';\u001b[39m\n\u001b[31m  // Clean up admin + create-mode UI\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('sup-back-btn')?.remove();\u001b[39m\n\u001b[31m  document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m  _supCreateMode = false;\u001b[39m\n\u001b[31m  // Resume-wrap may have been hidden by loadHomeAdmin() — restore it so draft banner shows\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = '';\u001b[39m\n\u001b[31m  document.getElementById('sub-list').innerHTML = `\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorViewAll()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0f9ff\\\">📋</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">View All Recces</span><span class=\\\"hi-txt\\\">सभी रेकी देखें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">Browse & review submissions from all agents</span><span class=\\\"hi-txt\\\">सभी एजेंट की सबमिशन देखें</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorCreateView()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0fdf4\\\">✍️</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">Create Recce</span><span class=\\\"hi-txt\\\">नई रेकी बनाएं</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">My submissions + New Recce button</span><span class=\\\"hi-txt\\\">मेरी सबमिशन + नई रेकी</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorViewAll() {\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  await loadHomeAdmin();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorCreateView() {\u001b[39m\n\u001b[31m  _supCreateMode = true;\u001b[39m\n\u001b[31m  // Restore field-agent UI\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh'); if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = t('My Submissions','मेरी सबमिशन');\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar'); if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  // Add Back to Menu button (once)\u001b[39m\n\u001b[31m  if (!document.getElementById('sup-back-create-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-create-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => {\u001b[39m\n\u001b[31m      _supCreateMode = false;\u001b[39m\n\u001b[31m      document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m      renderSupLanding();\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    document.querySelector('#view-home .content').prepend(bb);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  await loadHome();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadHome() {\u001b[39m\n\u001b[31m  if (_isSupervisor() && !_supCreateMode) { renderSupLanding(); return; }\u001b[39m\n\u001b[31m  if (_adminUnlocked && !_supCreateMode) { await loadHomeAdmin(); return; }·\u001b[39m\n\u001b[31m  const all  = await dbAll('subs');\u001b[39m\n\u001b[31m  const sy   = all.filter(s => s.status === 'synced').length;\u001b[39m\n\u001b[31m  const pe   = all.filter(s => s.status !== 'synced').length;·\u001b[39m\n\u001b[31m  // Fetch this agent's submissions from server — works on any device\u001b[39m\n\u001b[31m  let serverOnly = [];\u001b[39m\n\u001b[31m  let editAssigned = [];\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (navigator.onLine && hub?.empId) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?submitted_by=eq.${encodeURIComponent(hub.empId)}&order=submitted_at.desc&limit=200`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp.ok) {\u001b[39m\n\u001b[31m        const rows = await resp.json();\u001b[39m\n\u001b[31m        const localIds = new Set(all.map(s => s.id));\u001b[39m\n\u001b[31m        serverOnly = rows.filter(r => !localIds.has(r.sub_id));\u001b[39m\n\u001b[31m        _myServerRows = serverOnly;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m    // Fetch edit-assigned recces (supervisor assigned this creator to edit)\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp2 = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?edit_assigned_to=eq.${encodeURIComponent(hub.empId)}&deleted_at=is.null&order=submitted_at.desc`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp2.ok) editAssigned = await resp2.json();\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = sy + serverOnly.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = pe;\u001b[39m\n\u001b[31m  document.getElementById('stat-total').textContent   = all.length + serverOnly.length;·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!all.length && !serverOnly.length && !editAssigned.length) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">📋</div><div class=\\\"empty-txt\\\">No submissions yet</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const icos   = { synced:'✅', pending:'⏳', failed:'❌' };\u001b[39m\n\u001b[31m  const sorted = [...all].sort((a,b) => new Date(b.timestamp) - new Date(a.timestamp)).slice(0, 50);·\u001b[39m\n\u001b[31m  const localCards = sorted.map(s => {\u001b[39m\n\u001b[31m    const dt = new Date(s.timestamp);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const viewBtn = s.viewUrl\u001b[39m\n\u001b[31m      ? `<button class=\\\"edit-btn-sm\\\" onclick=\\\"window.open('${s.viewUrl}','_blank')\\\">👁 View</button>`\u001b[39m\n\u001b[31m      : `<button class=\\\"edit-btn-sm\\\" onclick=\\\"viewRecce('${s.id}')\\\">👁 View</button>`;\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico ${s.status}\\\">${icos[s.status]||'📋'}</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${s.data.storeName||'Unknown'} · ${s.data.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${s.data.address||''}</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge ${s.status}\\\">${s.status}</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          ${viewBtn}\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"editRecce('${s.id}')\\\" style=\\\"background:#fff7ed;border-color:var(--or);color:var(--or)\\\">✏ Edit</button>\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"makeSlides('${s.id}')\\\" style=\\\"background:#eff6ff;border-color:#3b82f6;color:#1d4ed8\\\">📊 Slides</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const serverCards = serverOnly.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const showPdf = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m    const pdfCls = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico synced\\\">✅</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\" style=\\\"min-width:0;flex:1\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"rpt-btns\\\" style=\\\"margin-top:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openMyServerRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m          ${showPdf ? `<button class=\\\"${pdfCls}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">📄 PDF</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge synced\\\">synced</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const editAssignedCards = editAssigned.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    return `<div class=\\\"edit-req-card\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:26px;flex-shrink:0\\\">✏</div>\u001b[39m\n\u001b[31m      <div class=\\\"edit-req-card-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-meta\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        ${r.edit_comment ? `<div class=\\\"edit-req-cmt\\\">\\\"${r.edit_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:10px;display:flex;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"startCreatorEdit('${r.sub_id}')\\\" style=\\\"padding:9px 16px;font-size:13px;font-weight:600\\\">✏ Edit this Recce</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (editAssignedCards.length) {\u001b[39m\n\u001b[31m    html += `<div class=\\\"edit-req-section-hdr\\\">✏ Edit Requested (${editAssignedCards.length})</div>`;\u001b[39m\n\u001b[31m    html += editAssignedCards.join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  html += localCards.join('') + serverCards.join('');\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m  const ls = await cfg('last-sync');\u001b[39m\n\u001b[31m  if (ls) {\u001b[39m\n\u001b[31m    const d = new Date(ls);\u001b[39m\n\u001b[31m    document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m      'Synced ' + d.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// RESET\u001b[39m\n\u001b[31mfunction startNewRecce(){F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  if(geoStampEnabled)autoRequestGPS();\u001b[39m\n\u001b[31m['f-date','f-brand','f-store','f-addr','f-mobile','f-client-other'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';});\u001b[39m\n\u001b[31m_selectedClient='';_clientOtherMode=false;\u001b[39m\n\u001b[31m_selectedCampaignId=null;_notifySupervisor=false;_brandingLocked=false;\u001b[39m\n\u001b[31mconst _camSel=document.getElementById('f-campaign-id');if(_camSel)_camSel.value='';\u001b[39m\n\u001b[31mconst _camNotice=document.getElementById('campaign-notify-msg');if(_camNotice)_camNotice.style.display='none';\u001b[39m\n\u001b[31mloadCampaignsForForm();\u001b[39m\n\u001b[31mrenderClientChips();\u001b[39m\n\u001b[31mdocument.getElementById('f-date').value=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31m// Block future dates\u001b[39m\n\u001b[31mdocument.getElementById('f-date').max=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31mdocument.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('pick-trigger-wrap').style.display=stores.length?'block':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').style.display=stores.length?'flex':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31mdocument.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31mdocument.getElementById('manual-fields').style.display=stores.length?'none':'block';\u001b[39m\n\u001b[31mdocument.getElementById('gps-status').textContent='';\u001b[39m\n\u001b[31m['vid-yes','vid-no','br-yes','br-no'].forEach(id=>document.getElementById(id).classList.remove('sel'));\u001b[39m\n\u001b[31mdocument.getElementById('vid-sec').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('vid-slot').innerHTML=`<div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('br-add').style.display='none';document.getElementById('br-items').innerHTML='';\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').classList.remove('filled');\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').innerHTML=`<div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('brand-selector').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('sc-missing').style.display='none';\u001b[39m\n\u001b[31mpopulateBrandDropdown();\u001b[39m\n\u001b[31mrenderPhotos('front');renderPhotos('inside');renderAddl();updAvailTag();showView('form-store');}\u001b[39m\n\u001b[31mfunction exitForm(){\u001b[39m\n\u001b[31m  // Show safe exit dialog instead of confirm\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitSaveAndLeave(){\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m  checkDraft();\u001b[39m\n\u001b[31m  toast('Draft saved — tap Resume to continue','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitDiscard(){\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];\u001b[39m\n\u001b[31m  videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  dbDel('draft','current');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitCancel(){document.getElementById('exit-dialog').classList.remove('open');}\u001b[39m\n\u001b[31mfunction showView(n){document.querySelectorAll('.view').forEach(v=>v.classList.remove('active'));const t=document.getElementById('view-'+n);if(t){t.classList.add('active');window.scrollTo(0,0);}}\u001b[39m\n\u001b[31mlet _tt;\u001b[39m\n\u001b[31mfunction toast(msg,type='info'){const el=document.getElementById('toast');el.textContent=msg;el.className='toast show '+type;clearTimeout(_tt);_tt=setTimeout(()=>el.classList.remove('show'),3000);}\u001b[39m\n\u001b[31mfunction netStatus(){const on=navigator.onLine;const dot=document.getElementById('net-dot');const txt=document.getElementById('net-txt');if(dot)dot.className='sdot '+(on?'on':'off');if(txt)txt.textContent=on?t('Online','ऑनलाइन'):t('Offline — saves locally','ऑफलाइन — स्थानीय रूप से सेव');}\u001b[39m\n\u001b[31masync function loadSettings(){\u001b[39m\n\u001b[31m  // Gas URL: pre-load default if none saved, update preview\u001b[39m\n\u001b[31m  const gu=await cfg('gas-url');\u001b[39m\n\u001b[31m  if(!gu)await cfg('gas-url',DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m  // Admin cfg url\u001b[39m\n\u001b[31m  const acu=await cfg('admin-cfg-url');if(acu&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=acu;\u001b[39m\n\u001b[31m  const su=await cfg('srv-url')||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su)document.getElementById('srv-url').value=su;\u001b[39m\n\u001b[31m  const sc=await cfg('stores');\u001b[39m\n\u001b[31m  if(sc){\u001b[39m\n\u001b[31m    stores=JSON.parse(sc);\u001b[39m\n\u001b[31m    const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m    document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m      `✓ ${stores.length} stores in cache${noBrand?` · ${noBrand} without brand`:''}`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const sf=await cfg('store-files');if(sf){_storeFiles=JSON.parse(sf);renderStoreFileList();}\u001b[39m\n\u001b[31m  const iq=await cfg('img-quality');imgQuality=iq||'compressed';applyQualityUI(imgQuality);\u001b[39m\n\u001b[31m  const gs=await cfg('geo-stamp');geoStampEnabled=(gs===null||gs==='1');applyGeoStampUI();\u001b[39m\n\u001b[31m  const bl=await cfg('brands');if(bl)brands=JSON.parse(bl);\u001b[39m\n\u001b[31m  loadBrandsFromDb();  // async — updates brands + logos from DB in background\u001b[39m\n\u001b[31m  renderBrandManageList();\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m  // Show store upload row + brand add row to supervisors only\u001b[39m\n\u001b[31m  const sur = document.getElementById('store-upload-row');\u001b[39m\n\u001b[31m  if (sur) sur.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const bar = document.getElementById('brand-add-row');\u001b[39m\n\u001b[31m  if (bar) bar.style.display = _isSupervisor() ? 'flex' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction populateBrandDropdown(){\u001b[39m\n\u001b[31m  const sel=document.getElementById('f-brand');if(!sel)return;\u001b[39m\n\u001b[31m  const cur=sel.value;\u001b[39m\n\u001b[31m  sel.innerHTML='<option value=\\\"\\\">Select brand</option>'+brands.map(b=>`<option${cur===b?' selected':''}>${b}</option>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderBrandManageList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('brand-manage-list');if(!el)return;\u001b[39m\n\u001b[31m  const isSup=_isSupervisor();\u001b[39m\n\u001b[31m  el.innerHTML=brands.map((b,i)=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    const logoHtml=logo?`<img src=\\\"${logo}\\\" style=\\\"height:20px;max-width:48px;object-fit:contain;flex-shrink:0;border-radius:3px\\\">`:'';\u001b[39m\n\u001b[31m    const ctrlHtml=isSup?`<div style=\\\"display:flex;gap:2px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"openEditBrandDialog(${i})\\\" style=\\\"background:none;border:none;color:var(--nv);font-size:15px;cursor:pointer;padding:2px 6px\\\" title=\\\"Edit\\\">✏</button>\u001b[39m\n\u001b[31m      ${brands.length>1?`<button onclick=\\\"confirmRemoveBrand(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:2px 4px\\\">×</button>`:'<span style=\\\"font-size:11px;color:var(--g400);padding:0 6px\\\">Last</span>'}\u001b[39m\n\u001b[31m    </div>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;min-width:0\\\">${logoHtml}<span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${b}</span></div>\u001b[39m\n\u001b[31m      ${ctrlHtml}\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function addBrandToList(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const inp=document.getElementById('brand-add-inp');\u001b[39m\n\u001b[31m  const val=(inp.value.trim()||'').toUpperCase();\u001b[39m\n\u001b[31m  if(!val){toast('Enter a brand name','error');return;}\u001b[39m\n\u001b[31m  if(brands.some(b=>b.toLowerCase()===val.toLowerCase())){toast(`${val} already in list`,'error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands`,{method:'POST',headers:{..._RC_WRITE,'Prefer':'return=minimal'},body:JSON.stringify({name:val,sort_order:99})});\u001b[39m\n\u001b[31m    if(resp.status===409){toast(`${val} already exists in DB`,'error');return;}\u001b[39m\n\u001b[31m    if(!resp.ok){const e=await resp.json().catch(()=>({}));throw new Error(e.message||resp.status);}\u001b[39m\n\u001b[31m    inp.value='';\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${val} added ✓`,'success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Add failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmRemoveBrand(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const name=brands[idx];\u001b[39m\n\u001b[31m  if(brands.length<=1){toast('Need at least one brand','error');return;}\u001b[39m\n\u001b[31m  let count=0;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(name)}&select=sub_id`,{headers:_RC_READ});\u001b[39m\n\u001b[31m    if(r.ok){const rows=await r.json();count=rows.length;}\u001b[39m\n\u001b[31m  }catch(_){}\u001b[39m\n\u001b[31m  const msg=count>0?`Delete \\\"${name}\\\" from brand list?\\\\n(${count} submission${count!==1?'s':''} reference this brand — they keep the name as text.)`:`Delete \\\"${name}\\\" from brand list?`;\u001b[39m\n\u001b[31m  if(!confirm(msg))return;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(name)}`,{method:'DELETE',headers:{'Content-Profile':'recce','Accept-Profile':'recce'}});\u001b[39m\n\u001b[31m    if(!resp.ok&&resp.status!==204){throw new Error(resp.status);}\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${name} removed ✓`,'info');\u001b[39m\n\u001b[31m  }catch(e){toast(`Remove failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadBrandsFromDb(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch('/db/brands?select=name,logo_url&order=sort_order',{\u001b[39m\n\u001b[31m      headers:{'Content-Profile':'recce','Accept-Profile':'recce'}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(!r.ok) return;\u001b[39m\n\u001b[31m    const rows=await r.json();\u001b[39m\n\u001b[31m    if(!rows||!rows.length) return;\u001b[39m\n\u001b[31m    const dbNames=rows.map(r=>r.name);\u001b[39m\n\u001b[31m    const logos={};rows.forEach(r=>{if(r.logo_url)logos[r.name]=r.logo_url;});\u001b[39m\n\u001b[31m    // Merge: DB brands canonical, keep locally-added extras\u001b[39m\n\u001b[31m    const extras=brands.filter(b=>!dbNames.some(n=>n.toLowerCase()===b.toLowerCase()));\u001b[39m\n\u001b[31m    brands=[...dbNames,...extras];\u001b[39m\n\u001b[31m    _brandLogos=logos;\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    // Refresh brand chips if brand-selector is visible\u001b[39m\n\u001b[31m    const bSel=document.getElementById('brand-selector');\u001b[39m\n\u001b[31m    if(bSel&&bSel.style.display!=='none') renderBrandChips();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[brands-db]',e.message);}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction renderBrandChips(){\u001b[39m\n\u001b[31m  const bChips=document.getElementById('brand-chips');if(!bChips)return;\u001b[39m\n\u001b[31m  bChips.innerHTML=brands.map(b=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    return `<div class=\\\"chip brand-chip${F.brand===b?' sel':''}\\\" onclick=\\\"selectStoreBrand('${b.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\">` +\u001b[39m\n\u001b[31m      (logo?`<img src=\\\"${logo}\\\" class=\\\"brand-chip-logo\\\" alt=\\\"\\\">`:'') +\u001b[39m\n\u001b[31m      `<span>${b}</span></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _editBrandIdx=null,_editBrandOld=null;\u001b[39m\n\u001b[31mfunction openEditBrandDialog(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor())return;\u001b[39m\n\u001b[31m  _editBrandIdx=idx;_editBrandOld=brands[idx];\u001b[39m\n\u001b[31m  document.getElementById('be-name').value=brands[idx];\u001b[39m\n\u001b[31m  const logo=_brandLogos[brands[idx]]||'';\u001b[39m\n\u001b[31m  document.getElementById('be-logo').value=logo;\u001b[39m\n\u001b[31m  document.getElementById('be-logo-preview').innerHTML=logo?`<img src=\\\"${logo}\\\" style=\\\"height:28px;object-fit:contain\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Current logo</span>`:'';\u001b[39m\n\u001b[31m  document.getElementById('be-cascade-info').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('brand-edit-modal').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeBrandEditModal(){document.getElementById('brand-edit-modal').classList.remove('open');_editBrandIdx=null;_editBrandOld=null;}\u001b[39m\n\u001b[31mfunction previewBrandLogo(){\u001b[39m\n\u001b[31m  const url=(document.getElementById('be-logo')?.value||'').trim();\u001b[39m\n\u001b[31m  const prev=document.getElementById('be-logo-preview');\u001b[39m\n\u001b[31m  if(prev)prev.innerHTML=url?`<img src=\\\"${url}\\\" style=\\\"height:28px;object-fit:contain\\\" onerror=\\\"this.style.display='none'\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Preview</span>`:'';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveBrandEdit(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const oldName=_editBrandOld;\u001b[39m\n\u001b[31m  const newName=(document.getElementById('be-name').value||'').trim().toUpperCase();\u001b[39m\n\u001b[31m  const newLogo=(document.getElementById('be-logo').value||'').trim();\u001b[39m\n\u001b[31m  if(!newName){toast('Brand name required','error');return;}\u001b[39m\n\u001b[31m  const isRename=newName!==oldName;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // 1. Update recce.brands\u001b[39m\n\u001b[31m    const pResp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m      method:'PATCH',headers:{..._RC_WRITE,'Prefer':'return=minimal'},\u001b[39m\n\u001b[31m      body:JSON.stringify({name:newName,logo_url:newLogo||null})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(pResp.status===409){toast(`\\\"${newName}\\\" already exists`,'error');return;}\u001b[39m\n\u001b[31m    if(!pResp.ok&&pResp.status!==204){const e=await pResp.json().catch(()=>({}));throw new Error(e.message||pResp.status);}\u001b[39m\n\u001b[31m    if(isRename){\u001b[39m\n\u001b[31m      const hub=_recceHubUser();\u001b[39m\n\u001b[31m      // 2. Cascade to submissions\u001b[39m\n\u001b[31m      await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m        method:'PATCH',headers:_RC_WRITE,body:JSON.stringify({brand:newName})\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      // 3. Cascade to stores.json + view HTML files + PDFs\u001b[39m\n\u001b[31m      toast('Cascading rename to reports…','info');\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        const cResp=await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},\u001b[39m\n\u001b[31m          body:JSON.stringify({type:'cascade-rename-brand',oldName,newName,empId:hub?.empId||''})});\u001b[39m\n\u001b[31m        const cRes=cResp.ok?await cResp.json():{};\u001b[39m\n\u001b[31m        const msg=`Brand renamed ✓${cRes.viewsUpdated?` · ${cRes.viewsUpdated} reports re-queued`:''}`;\u001b[39m\n\u001b[31m        closeBrandEditModal();\u001b[39m\n\u001b[31m        await loadBrandsFromDb();\u001b[39m\n\u001b[31m        toast(msg,'success');\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }catch(e){console.warn('[cascade-rename]',e.message);}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeBrandEditModal();\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast('Brand updated ✓','success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Save failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function fetchServerBrands(){\u001b[39m\n\u001b[31m  const url=document.getElementById('brands-url')?.value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    toast('Fetching brands…','info');\u001b[39m\n\u001b[31m    const r=await fetch(url);const j=await r.json();\u001b[39m\n\u001b[31m    const list=Array.isArray(j)?j:j.brands||[];\u001b[39m\n\u001b[31m    if(!list.length){toast('No brands found in response','error');return;}\u001b[39m\n\u001b[31m    brands=list.map(b=>b.toString().toUpperCase());\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    toast(`${brands.length} brands loaded from server`,'success');\u001b[39m\n\u001b[31m  }catch{toast('Failed to fetch — check URL','error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setImgQuality(q){\u001b[39m\n\u001b[31m  imgQuality=q;\u001b[39m\n\u001b[31m  cfg('img-quality',q);\u001b[39m\n\u001b[31m  applyQualityUI(q);\u001b[39m\n\u001b[31m  toast(q==='hd'?'HD Quality selected (~400–600 KB per photo)':'Full Compression selected (~150–200 KB per photo)','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction applyQualityUI(q){\u001b[39m\n\u001b[31m  ['compressed','hd'].forEach(opt=>{\u001b[39m\n\u001b[31m    const label=document.getElementById('q-opt-'+opt);\u001b[39m\n\u001b[31m    const radio=document.getElementById('q-radio-'+opt);\u001b[39m\n\u001b[31m    const dot  =document.getElementById('q-dot-'+opt);\u001b[39m\n\u001b[31m    if(!label)return;\u001b[39m\n\u001b[31m    const active=opt===q;\u001b[39m\n\u001b[31m    label.style.borderColor=active?'var(--or)':'var(--g200)';\u001b[39m\n\u001b[31m    label.style.background=active?'#fff7ed':'var(--g50)';\u001b[39m\n\u001b[31m    if(radio)radio.style.borderColor=active?'var(--or)':'var(--g300)';\u001b[39m\n\u001b[31m    if(dot)dot.style.display=active?'block':'none';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const badge=document.getElementById('q-current-badge');\u001b[39m\n\u001b[31m  if(badge){\u001b[39m\n\u001b[31m    const label=q==='hd'?'HD Quality (~400–600 KB)':'Full Compression (~150–200 KB)';\u001b[39m\n\u001b[31m    badge.innerHTML=`Active: <strong>${label}</strong>`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function clearData(){if(!confirm('Delete ALL local data?'))return;const all=await dbAll('subs');for(const s of all)await dbDel('subs',s.id);stores=[];await cfg('stores',null);toast('All cleared','success');loadHome();}\u001b[39m\n\u001b[31mif('serviceWorker' in navigator){const sw=`const C='recce-v37';self.addEventListener('install',e=>{e.waitUntil(caches.open(C).then(c=>c.add('/')));self.skipWaiting();});self.addEventListener('activate',e=>e.waitUntil(clients.claim()));self.addEventListener('fetch',e=>{if(e.request.method!=='GET')return;e.respondWith(caches.match(e.request).then(r=>{if(r)return r;return fetch(e.request).then(res=>{if(res&&res.status===200&&res.type==='basic'){const cl=res.clone();caches.open(C).then(c=>c.put(e.request,cl));}return res;}).catch(()=>caches.match('/'));}))}); `;const blob=new Blob([sw],{type:'application/javascript'});navigator.serviceWorker.register(URL.createObjectURL(blob),{scope:'/'}).catch(()=>{});}·\u001b[39m\n\u001b[31m// ── GEOLOCATION STAMP ────────────────────────────────────────\u001b[39m\n\u001b[31mfunction applyGeoStampUI(){\u001b[39m\n\u001b[31m  const tog=document.getElementById('geo-tog');\u001b[39m\n\u001b[31m  if(tog)tog.classList.toggle('on',geoStampEnabled);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function toggleGeoStamp(){\u001b[39m\n\u001b[31m  geoStampEnabled=!geoStampEnabled;\u001b[39m\n\u001b[31m  await cfg('geo-stamp',geoStampEnabled?'1':'0');\u001b[39m\n\u001b[31m  applyGeoStampUI();\u001b[39m\n\u001b[31m  toast(geoStampEnabled?'Geolocation stamp enabled':'Geolocation stamp disabled','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Auto-request GPS silently when a new recce starts\u001b[39m\n\u001b[31mfunction autoRequestGPS(){\u001b[39m\n\u001b[31m  if(!navigator.geolocation)return;\u001b[39m\n\u001b[31m  const statusEl=document.getElementById('geo-status');\u001b[39m\n\u001b[31m  if(statusEl)statusEl.textContent='Acquiring GPS…';\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(\u001b[39m\n\u001b[31m    pos=>{\u001b[39m\n\u001b[31m      gpsCoords={\u001b[39m\n\u001b[31m        lat:pos.coords.latitude.toFixed(6),\u001b[39m\n\u001b[31m        lng:pos.coords.longitude.toFixed(6),\u001b[39m\n\u001b[31m        acc:Math.round(pos.coords.accuracy)\u001b[39m\n\u001b[31m      };\u001b[39m\n\u001b[31m      const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m      const quality=acc<=15?'Excellent':acc<=50?'Good':acc<=200?'Fair':'Poor (cell tower)';\u001b[39m\n\u001b[31m      const color=acc<=15?'var(--gn)':acc<=50?'#16a34a':acc<=200?'var(--am)':'var(--rd)';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.innerHTML=`GPS: ${gpsCoords.lat}, ${gpsCoords.lng} · ±${acc}m · <span style=\\\"color:${color};font-weight:600\\\">${quality}</span>`;\u001b[39m\n\u001b[31m      // Update form GPS status too\u001b[39m\n\u001b[31m      const fs=document.getElementById('gps-status');\u001b[39m\n\u001b[31m      if(fs){fs.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${acc}m)`;fs.style.color='var(--gn)';}\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    err=>{\u001b[39m\n\u001b[31m      const msgs={1:'Location permission denied in Chrome',2:'GPS signal unavailable',3:'GPS timed out'};\u001b[39m\n\u001b[31m      const msg=msgs[err.code]||'GPS unavailable';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.textContent=msg+' — stamp will use store address';\u001b[39m\n\u001b[31m      if(err.code===1)toast('Tap the lock icon in Chrome address bar → allow Location','info');\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    {enableHighAccuracy:true,timeout:20000,maximumAge:60000}\u001b[39m\n\u001b[31m  );\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Draw stamp on a photo blob — returns new blob with stamp baked in\u001b[39m\n\u001b[31mfunction roundRectPath(ctx,x,y,w,h,r){\u001b[39m\n\u001b[31m  ctx.beginPath();ctx.moveTo(x+r,y);ctx.lineTo(x+w-r,y);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y,x+w,y+r);ctx.lineTo(x+w,y+h-r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);ctx.lineTo(x+r,y+h);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y+h,x,y+h-r);ctx.lineTo(x,y+r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y,x+r,y);ctx.closePath();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction fitText(ctx,text,maxW){\u001b[39m\n\u001b[31m  if(ctx.measureText(text).width<=maxW)return text;\u001b[39m\n\u001b[31m  while(text.length>1&&ctx.measureText(text+'…').width>maxW)text=text.slice(0,-1);\u001b[39m\n\u001b[31m  return text+'…';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction stampPhoto(blob){\u001b[39m\n\u001b[31m  if(!geoStampEnabled)return Promise.resolve(blob);\u001b[39m\n\u001b[31m  return new Promise(res=>{\u001b[39m\n\u001b[31m    const img=new Image(),url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    img.onload=()=>{\u001b[39m\n\u001b[31m      URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m      const W=img.width,H=img.height;\u001b[39m\n\u001b[31m      const c=document.createElement('canvas');c.width=W;c.height=H;\u001b[39m\n\u001b[31m      const ctx=c.getContext('2d');\u001b[39m\n\u001b[31m      ctx.drawImage(img,0,0);·\u001b[39m\n\u001b[31m      // Stamp dimensions — 18% of image height\u001b[39m\n\u001b[31m      const SH=Math.round(H*0.18);\u001b[39m\n\u001b[31m      const pad=Math.round(W*0.03);\u001b[39m\n\u001b[31m      const SY=H-SH;·\u001b[39m\n\u001b[31m      // Semi-transparent background\u001b[39m\n\u001b[31m      ctx.fillStyle='rgba(10,18,35,0.78)';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,SH);·\u001b[39m\n\u001b[31m      // Orange top accent line\u001b[39m\n\u001b[31m      ctx.fillStyle='#f97316';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,Math.max(3,Math.round(H*0.004)));·\u001b[39m\n\u001b[31m      // Font sizes scaled to image\u001b[39m\n\u001b[31m      const f1=Math.round(SH*0.26); // store name\u001b[39m\n\u001b[31m      const f2=Math.round(SH*0.22); // coords / address\u001b[39m\n\u001b[31m      const f3=Math.round(SH*0.20); // timestamp·\u001b[39m\n\u001b[31m      // Row Y centres\u001b[39m\n\u001b[31m      const r1=SY+SH*0.26;\u001b[39m\n\u001b[31m      const r2=SY+SH*0.55;\u001b[39m\n\u001b[31m      const r3=SY+SH*0.82;·\u001b[39m\n\u001b[31m      // Get stamp data\u001b[39m\n\u001b[31m      const storeName=F.storeName||selectedStore?.name||'';\u001b[39m\n\u001b[31m      const brand=F.brand||selectedStore?.brand||'';\u001b[39m\n\u001b[31m      const addr=F.address||selectedStore?.address||'';\u001b[39m\n\u001b[31m      const now=new Date();\u001b[39m\n\u001b[31m      const dateStr=now.toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m      const timeStr=now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit',hour12:true});·\u001b[39m\n\u001b[31m      // Badge (right side — GPS quality)\u001b[39m\n\u001b[31m      let badgeLabel='',badgeColor='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m        if(acc<=15){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=50){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=200){badgeLabel='~'+acc+'m';badgeColor='#d97706';}\u001b[39m\n\u001b[31m        else{badgeLabel='Cell ~'+acc+'m';badgeColor='#dc2626';}\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        badgeLabel='No GPS';badgeColor='#64748b';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      const bFontSz=Math.round(SH*0.18);\u001b[39m\n\u001b[31m      ctx.font=`bold ${bFontSz}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      const bW=Math.round(ctx.measureText(badgeLabel).width+pad);\u001b[39m\n\u001b[31m      const bH=Math.round(SH*0.32);\u001b[39m\n\u001b[31m      const bX=W-bW-pad;const bY=SY+(SH-bH)/2;\u001b[39m\n\u001b[31m      ctx.fillStyle=badgeColor+'cc';\u001b[39m\n\u001b[31m      roundRectPath(ctx,bX,bY,bW,bH,4);ctx.fill();\u001b[39m\n\u001b[31m      ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';\u001b[39m\n\u001b[31m      ctx.fillText(badgeLabel,bX+bW/2,bY+bH/2);\u001b[39m\n\u001b[31m      ctx.textAlign='left';ctx.textBaseline='alphabetic';·\u001b[39m\n\u001b[31m      const textMaxW=bX-pad*2;·\u001b[39m\n\u001b[31m      // Row 1 — store name + brand\u001b[39m\n\u001b[31m      ctx.font=`bold ${f1}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#ffffff';\u001b[39m\n\u001b[31m      const nameText=storeName+(brand?' · '+brand:'');\u001b[39m\n\u001b[31m      ctx.fillText('📍 '+fitText(ctx,nameText,textMaxW-f1*1.4),pad,r1);·\u001b[39m\n\u001b[31m      // Row 2 — GPS coords OR address\u001b[39m\n\u001b[31m      ctx.font=`${f2}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#cbd5e1';\u001b[39m\n\u001b[31m      let row2='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        row2=`Lat ${gpsCoords.lat}°   Long ${gpsCoords.lng}°`;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        row2=addr?fitText(ctx,addr,textMaxW):'GPS coordinates unavailable';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      ctx.fillText(row2,pad,r2);·\u001b[39m\n\u001b[31m      // Row 3 — date and time\u001b[39m\n\u001b[31m      ctx.font=`${f3}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#94a3b8';\u001b[39m\n\u001b[31m      ctx.fillText(`${dateStr}   ${timeStr}`,pad,r3);·\u001b[39m\n\u001b[31m      c.toBlob(b=>res(b||blob),'image/jpeg',imgQuality==='hd'?0.88:0.82);\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    img.onerror=()=>{URL.revokeObjectURL(url);res(blob);};\u001b[39m\n\u001b[31m    img.src=url;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _aTool='rect',_aColor='#f97316',_aWidth=4,_aTarget=-1;\u001b[39m\n\u001b[31mlet _aImg=null,_aHistory=[],_aDrawing=false,_aStart={},_aPts=[];\u001b[39m\n\u001b[31mlet _aSel=-1,_aDragMode=null,_aDragOff={x:0,y:0};\u001b[39m\n\u001b[31m// Larger hit radius on touch devices for easier finger selection\u001b[39m\n\u001b[31mconst HIT_R=()=>('ontouchstart' in window)?32:16;·\u001b[39m\n\u001b[31mfunction setATool(t){\u001b[39m\n\u001b[31m  _aTool=t;\u001b[39m\n\u001b[31m  ['rect','ellipse','line','arrow','free'].forEach(id=>{const el=document.getElementById('at-'+id);if(el)el.classList.toggle('on',id===t&&t!=='move');});\u001b[39m\n\u001b[31m  const mv=document.getElementById('at-move');if(mv)mv.classList.toggle('sel-on',t==='move');\u001b[39m\n\u001b[31m  const info=document.getElementById('annot-sel-info');if(info)info.style.display=t==='move'?'block':'none';\u001b[39m\n\u001b[31m  if(t!=='move'){_aSel=-1;redrawAnnot();}\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(cvs)cvs.style.cursor=t==='move'?'default':'crosshair';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAColor(c){\u001b[39m\n\u001b[31m  _aColor=c;\u001b[39m\n\u001b[31m  const m={'#f97316':'or','#ef4444':'rd','#ffffff':'wh','#facc15':'yw','#22c55e':'gn'};\u001b[39m\n\u001b[31m  Object.entries(m).forEach(([col,id])=>{const el=document.getElementById('ac-'+id);if(el)el.classList.toggle('on',col===c);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAWidth(w){_aWidth=w;[2,4,7].forEach(v=>{const el=document.getElementById('aw-'+v);if(el)el.classList.toggle('on',v===w);});}·\u001b[39m\n\u001b[31mfunction openAnnot(idx){\u001b[39m\n\u001b[31m  _aTarget=idx;_aHistory=[];_aDrawing=false;_aPts=[];_aSel=-1;_aDragMode=null;\u001b[39m\n\u001b[31m  document.getElementById('annot-modal').classList.add('open');\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');\u001b[39m\n\u001b[31m  const img=new Image(),url=URL.createObjectURL(brandings[idx].blob);\u001b[39m\n\u001b[31m  img.onload=()=>{\u001b[39m\n\u001b[31m    const sc=Math.min(1,window.innerWidth/img.width,(window.innerHeight-185)/img.height);\u001b[39m\n\u001b[31m    cvs.width=Math.round(img.width*sc);cvs.height=Math.round(img.height*sc);\u001b[39m\n\u001b[31m    _aImg=img;redrawAnnot();URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  img.src=url;\u001b[39m\n\u001b[31m  cvs.ontouchstart=aDown;cvs.ontouchmove=aMove;cvs.ontouchend=aUp;\u001b[39m\n\u001b[31m  cvs.onmousedown=aDown;cvs.onmousemove=aMove;cvs.onmouseup=aUp;\u001b[39m\n\u001b[31m  setATool('rect');setAColor('#f97316');setAWidth(4);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aPos(e){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const r=cvs.getBoundingClientRect();\u001b[39m\n\u001b[31m  const src=e.touches?e.touches[0]:e;\u001b[39m\n\u001b[31m  return{x:(src.clientX-r.left)*(cvs.width/r.width),y:(src.clientY-r.top)*(cvs.height/r.height)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Always return normalised (positive w,h) bounds\u001b[39m\n\u001b[31mfunction sBounds(s){\u001b[39m\n\u001b[31m  if(s.type==='free'){\u001b[39m\n\u001b[31m    if(!s.pts||!s.pts.length)return null;\u001b[39m\n\u001b[31m    const xs=s.pts.map(p=>p.x),ys=s.pts.map(p=>p.y);\u001b[39m\n\u001b[31m    const x=Math.min(...xs),y=Math.min(...ys);\u001b[39m\n\u001b[31m    return{x,y,w:Math.max(...xs)-x,h:Math.max(...ys)-y};\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  return{x:Math.min(s.x,s.x+s.w),y:Math.min(s.y,s.y+s.h),w:Math.abs(s.w),h:Math.abs(s.h)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction hitHandle(px,py,s){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return null;\u001b[39m\n\u001b[31m  const b=sBounds(s);const hr=HIT_R();\u001b[39m\n\u001b[31m  for(const[n,x,y]of[['tl',b.x,b.y],['tr',b.x+b.w,b.y],['bl',b.x,b.y+b.h],['br',b.x+b.w,b.y+b.h]])\u001b[39m\n\u001b[31m    if(Math.hypot(px-x,py-y)<hr)return n;\u001b[39m\n\u001b[31m  return null;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction hitShape(px,py,s){\u001b[39m\n\u001b[31m  const b=sBounds(s);if(!b)return false;\u001b[39m\n\u001b[31m  const pad=HIT_R();\u001b[39m\n\u001b[31m  return px>=b.x-pad&&px<=b.x+b.w+pad&&py>=b.y-pad&&py<=b.y+b.h+pad;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aDown(e){\u001b[39m\n\u001b[31m  e.preventDefault();const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'){\u001b[39m\n\u001b[31m    // Check handles of selected shape first\u001b[39m\n\u001b[31m    if(_aSel>=0&&_aSel<_aHistory.length){\u001b[39m\n\u001b[31m      const h=hitHandle(p.x,p.y,_aHistory[_aSel]);\u001b[39m\n\u001b[31m      if(h){_aDragMode='r-'+h;_aDragOff={x:p.x,y:p.y};_aDrawing=true;return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Hit test all shapes topmost first\u001b[39m\n\u001b[31m    for(let i=_aHistory.length-1;i>=0;i--){\u001b[39m\n\u001b[31m      if(hitShape(p.x,p.y,_aHistory[i])){\u001b[39m\n\u001b[31m        _aSel=i;_aDragMode='move';\u001b[39m\n\u001b[31m        const s=_aHistory[i];\u001b[39m\n\u001b[31m        const b=sBounds(s);\u001b[39m\n\u001b[31m        // Store offset from shape top-left corner (normalised)\u001b[39m\n\u001b[31m        _aDragOff={x:p.x-b.x,y:p.y-b.y};\u001b[39m\n\u001b[31m        _aDrawing=true;redrawAnnot();return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    _aSel=-1;redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _aDrawing=true;_aStart={x:p.x,y:p.y};if(_aTool==='free')_aPts=[{x:p.x,y:p.y}];\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aMove(e){\u001b[39m\n\u001b[31m  e.preventDefault();if(!_aDrawing)return;const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'&&_aDragMode){\u001b[39m\n\u001b[31m    const s=_aHistory[_aSel];if(!s)return;\u001b[39m\n\u001b[31m    if(_aDragMode==='move'){\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      // New top-left position\u001b[39m\n\u001b[31m      const nx=p.x-_aDragOff.x;\u001b[39m\n\u001b[31m      const ny=p.y-_aDragOff.y;\u001b[39m\n\u001b[31m      const dx=nx-b.x,dy=ny-b.y;\u001b[39m\n\u001b[31m      if(s.type==='free'){\u001b[39m\n\u001b[31m        s.pts=s.pts.map(pt=>({x:pt.x+dx,y:pt.y+dy}));\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        // Move preserving w/h sign (don't normalise — keep original drawing direction)\u001b[39m\n\u001b[31m        s.x+=dx;s.y+=dy;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Resize from corner — always work on normalised bounds then re-apply\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      const n=_aDragMode.slice(2);\u001b[39m\n\u001b[31m      let nx=b.x,ny=b.y,nw=b.w,nh=b.h;\u001b[39m\n\u001b[31m      if(n==='br'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,p.y-b.y);}\u001b[39m\n\u001b[31m      else if(n==='tl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,b.y+b.h-p.y);nx=p.x;ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='tr'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,b.y+b.h-p.y);ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='bl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,p.y-b.y);nx=p.x;}\u001b[39m\n\u001b[31m      s.x=nx;s.y=ny;s.w=nw;s.h=nh; // store as normalised going forward\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if(_aTool==='free'){_aPts.push({x:p.x,y:p.y});redrawAnnot();drawSh({type:'free',pts:[..._aPts],color:_aColor,lw:_aWidth},true);return;}\u001b[39m\n\u001b[31m  redrawAnnot();drawSh({type:_aTool,x:_aStart.x,y:_aStart.y,w:p.x-_aStart.x,h:p.y-_aStart.y,color:_aColor,lw:_aWidth},true);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction aUp(e){\u001b[39m\n\u001b[31m  if(!_aDrawing)return;_aDrawing=false;\u001b[39m\n\u001b[31m  if(_aTool==='move'){_aDragMode=null;return;}\u001b[39m\n\u001b[31m  const p=aPos(e||{touches:[{clientX:0,clientY:0}]});\u001b[39m\n\u001b[31m  if(_aTool==='free'){if(_aPts.length>2){_aHistory.push({type:'free',pts:[..._aPts],x:_aPts[0].x,y:_aPts[0].y,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  else{const w=p.x-_aStart.x,h=p.y-_aStart.y;if(Math.abs(w)>4||Math.abs(h)>4){_aHistory.push({type:_aTool,x:_aStart.x,y:_aStart.y,w,h,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  _aPts=[];redrawAnnot();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction redrawAnnot(){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.clearRect(0,0,cvs.width,cvs.height);if(_aImg)ctx.drawImage(_aImg,0,0,cvs.width,cvs.height);\u001b[39m\n\u001b[31m  _aHistory.forEach((s,i)=>{drawSh(s,false,ctx);if(_aTool==='move'&&i===_aSel)drawHandles(s,ctx);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawHandles(s,ctx){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return;const b=sBounds(s);ctx.save();\u001b[39m\n\u001b[31m  ctx.setLineDash([5,3]);ctx.strokeStyle='#facc15';ctx.lineWidth=1.5;ctx.strokeRect(b.x-2,b.y-2,b.w+4,b.h+4);ctx.setLineDash([]);\u001b[39m\n\u001b[31m  [[b.x,b.y],[b.x+b.w,b.y],[b.x,b.y+b.h],[b.x+b.w,b.y+b.h]].forEach(([x,y])=>{ctx.beginPath();ctx.arc(x,y,7,0,2*Math.PI);ctx.fillStyle='#f97316';ctx.fill();ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();});\u001b[39m\n\u001b[31m  ctx.restore();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawSh(s,preview=false,ctx){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(!ctx)ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.save();ctx.strokeStyle=s.color;ctx.lineWidth=preview?Math.max(s.lw||4,2):s.lw||4;\u001b[39m\n\u001b[31m  ctx.lineCap='round';ctx.lineJoin='round';ctx.setLineDash(preview?[6,3]:[]);\u001b[39m\n\u001b[31m  if(s.type==='rect'){ctx.strokeRect(s.x,s.y,s.w,s.h);ctx.fillStyle=s.color+'28';ctx.fillRect(s.x,s.y,s.w,s.h);}\u001b[39m\n\u001b[31m  else if(s.type==='ellipse'){const cx=s.x+s.w/2,cy=s.y+s.h/2;ctx.beginPath();ctx.ellipse(cx,cy,Math.abs(s.w/2),Math.abs(s.h/2),0,0,2*Math.PI);ctx.stroke();ctx.fillStyle=s.color+'28';ctx.fill();}\u001b[39m\n\u001b[31m  else if(s.type==='line'){ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(s.x+s.w,s.y+s.h);ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='arrow'){const ex=s.x+s.w,ey=s.y+s.h;ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(ex,ey);ctx.stroke();const a=Math.atan2(s.h,s.w),al=20,aa=0.4;ctx.setLineDash([]);ctx.beginPath();ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a-aa),ey-al*Math.sin(a-aa));ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a+aa),ey-al*Math.sin(a+aa));ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='free'){if(s.pts.length<2){ctx.restore();return;}ctx.beginPath();s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));ctx.stroke();}\u001b[39m\n\u001b[31m  ctx.setLineDash([]);ctx.restore();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction undoAnnot(){if(_aHistory.length){_aHistory.pop();_aSel=Math.min(_aSel,_aHistory.length-1);redrawAnnot();}}\u001b[39m\n\u001b[31mfunction clearAnnot(){_aHistory=[];_aSel=-1;redrawAnnot();}·\u001b[39m\n\u001b[31m// Bottom dialog\u001b[39m\n\u001b[31mlet _bdCb=null;\u001b[39m\n\u001b[31mfunction showBDialog(title,sub,onYes){\u001b[39m\n\u001b[31m  document.getElementById('bdialog-title').textContent=title;\u001b[39m\n\u001b[31m  document.getElementById('bdialog-sub').textContent=sub;\u001b[39m\n\u001b[31m  _bdCb=onYes;document.getElementById('bdialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction bdialogYes(){document.getElementById('bdialog').classList.remove('open');if(_bdCb)_bdCb();_bdCb=null;}\u001b[39m\n\u001b[31mfunction bdialogNo(){document.getElementById('bdialog').classList.remove('open');_bdCb=null;}·\u001b[39m\n\u001b[31mfunction _afterBrandingPhoto(){\u001b[39m\n\u001b[31m  const idx=_aTarget;\u001b[39m\n\u001b[31m  showBDialog(t(`Add reference photos for Branding ${idx+1}?`,`ब्रांडिंग ${idx+1} के लिए अतिरिक्त फोटो?`),t('Optional extra photos for future reference.','वैकल्पिक — भविष्य के लिए अतिरिक्त फोटो।'),()=>{showView('form-additional');setTimeout(()=>addAdditional(),200);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction skipAnnot(){document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo added (${fmtSz(brandings[_aTarget].blob.size)})`,'success');_afterBrandingPhoto();}\u001b[39m\n\u001b[31mfunction saveAnnot(){const cvs=document.getElementById('annot-cvs');cvs.toBlob(blob=>{brandings[_aTarget].blob=blob;brandings[_aTarget].prev=URL.createObjectURL(blob);document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo + markup saved (${fmtSz(blob.size)})`,'success');_afterBrandingPhoto();},'image/jpeg',0.88);}·\u001b[39m\n\u001b[31m// ── VIEW RECCE (read-only) ──────────────────────────────────\u001b[39m\n\u001b[31masync function viewRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  // Synced entries have a server-side rich report — open it directly\u001b[39m\n\u001b[31m  if(entry.viewUrl){window.open(entry.viewUrl,'_blank');return;}\u001b[39m\n\u001b[31m  // Offline / not-yet-synced fallback: generate from local base64 data\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  const ts=new Date(entry.timestamp).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'});·\u001b[39m\n\u001b[31m  async function b64ToUrl(b64){if(!b64)return'';try{const r=await fetch(b64);const bl=await r.blob();return URL.createObjectURL(bl);}catch{return'';}}·\u001b[39m\n\u001b[31m  const fvUrls=await Promise.all((d.frontPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const ivUrls=await Promise.all((d.insidePhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const brUrls=await Promise.all((d.brandings||[]).map(b=>b64ToUrl(b.photoB64)));\u001b[39m\n\u001b[31m  const adUrls=await Promise.all((d.addlPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const docUrl=await b64ToUrl(d.docB64);·\u001b[39m\n\u001b[31m  const brRows=(d.brandings||[]).map((b,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:16px;padding:12px;background:#f8fafc;border-radius:8px;border-left:3px solid #f97316\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-weight:600;font-size:14px;color:#0f172a;margin-bottom:6px\\\">${i+1}. ${b.type||'—'}: ${b.w||'?'}\\\"×${b.h||'?'}\\\" · Qty: ${b.qty||'?'} · ${b.sqft||'?'}</div>\u001b[39m\n\u001b[31m      ${brUrls[i]?`<img src=\\\"${brUrls[i]}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:6px\\\">`:'<div style=\\\"color:#94a3b8;font-size:12px\\\">No photo</div>'}\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  const html=`<!DOCTYPE html><html><head><meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m  <title>Recce — ${d.storeName||'Unknown'}</title>\u001b[39m\n\u001b[31m  <style>body{font-family:Arial,sans-serif;margin:0;padding:16px;background:#f1f5f9}\u001b[39m\n\u001b[31m  .card{background:#fff;border-radius:12px;padding:16px;margin-bottom:14px;box-shadow:0 1px 4px rgba(0,0,0,.08)}\u001b[39m\n\u001b[31m  h1{font-size:18px;color:#0f172a;margin:0 0 4px}h2{font-size:14px;color:#f97316;text-transform:uppercase;letter-spacing:.5px;margin:0 0 10px}\u001b[39m\n\u001b[31m  .meta{font-size:12px;color:#64748b;margin-bottom:12px}.photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}\u001b[39m\n\u001b[31m  img{width:100%;border-radius:8px;object-fit:cover}\u001b[39m\n\u001b[31m  .tag{display:inline-block;background:#0f172a;color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-right:4px}\u001b[39m\n\u001b[31m  @media print{body{background:#fff}.card{box-shadow:none}}</style></head><body>\u001b[39m\n\u001b[31m  <div class=\\\"card\\\">\u001b[39m\n\u001b[31m    <h1>${d.storeName||'Unknown Store'}</h1>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\"><span class=\\\"tag\\\">${d.brand||'No Brand'}</span>${d.address||''}</div>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\">📞 ${d.mobile||'—'} &nbsp;|&nbsp; 📅 ${d.date||'—'} &nbsp;|&nbsp; Submitted: ${ts}</div>\u001b[39m\n\u001b[31m    ${d.gpsCoords?`<div class=\\\"meta\\\">📍 ${d.gpsCoords.lat}, ${d.gpsCoords.lng} ±${d.gpsCoords.acc}m</div>`:''}\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${fvUrls.length?`<div class=\\\"card\\\"><h2>Front View Photos</h2><div class=\\\"photos\\\">${fvUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${ivUrls.length?`<div class=\\\"card\\\"><h2>Inside View Photos</h2><div class=\\\"photos\\\">${ivUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${d.hasVideo?`<div class=\\\"card\\\"><h2>Video</h2><div>${d.videoNote||'Video recorded'}</div></div>`:''}\u001b[39m\n\u001b[31m  ${(d.brandings||[]).length?`<div class=\\\"card\\\"><h2>Branding Items (${(d.brandings||[]).length})</h2>${brRows}</div>`:''}\u001b[39m\n\u001b[31m  ${adUrls.length?`<div class=\\\"card\\\"><h2>Additional Photos</h2><div class=\\\"photos\\\">${adUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${docUrl?`<div class=\\\"card\\\"><h2>Submission Document</h2><img src=\\\"${docUrl}\\\" style=\\\"width:100%;max-height:300px;object-fit:contain\\\"></div>`:''}\u001b[39m\n\u001b[31m  <div style=\\\"text-align:center;margin:16px 0\\\">\u001b[39m\n\u001b[31m    <button onclick=\\\"window.print()\\\" style=\\\"background:#f97316;color:#fff;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer\\\">🖨 Print / Save as PDF</button>\u001b[39m\n\u001b[31m    <button onclick=\\\"window.close()\\\" style=\\\"background:#e2e8f0;color:#475569;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer;margin-left:10px\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  </body></html>`;\u001b[39m\n\u001b[31m  const blob=new Blob([html],{type:'text/html'});\u001b[39m\n\u001b[31m  const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m  window.open(url,'_blank');\u001b[39m\n\u001b[31m  setTimeout(()=>URL.revokeObjectURL(url),30000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── EDIT OLD RECCE ───────────────────────────────────────────\u001b[39m\n\u001b[31masync function editRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=d.gpsCoords||null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  F.editingId=id;F.date=d.date||'';F.brand=d.brand||'';F.storeName=d.storeName||'';F.address=d.address||'';F.mobile=d.mobile||'';F.hasVideo=d.hasVideo;F.hasBranding=d.hasBranding;\u001b[39m\n\u001b[31m  async function b64ToBlob(b64){if(!b64)return null;try{const r=await fetch(b64);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m  toast('Loading recce data…','info');\u001b[39m\n\u001b[31m  for(const p of(d.frontPhotos||[])){const b=await b64ToBlob(p.b64);if(b)frontPhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const p of(d.insidePhotos||[])){const b=await b64ToBlob(p.b64);if(b)insidePhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const br of(d.brandings||[])){const b=await b64ToBlob(br.photoB64);brandings.push({type:br.type,w:br.w,h:br.h,qty:br.qty,blob:b,prev:b?URL.createObjectURL(b):null});}\u001b[39m\n\u001b[31m  for(const p of(d.addlPhotos||[])){const b=await b64ToBlob(p.b64);if(b)addlPhotos.push({blob:b,prev:URL.createObjectURL(b),desc:p.desc||''});}\u001b[39m\n\u001b[31m  if(d.docB64){const b=await b64ToBlob(d.docB64);if(b){submissionDoc=b;const sl=document.getElementById('doc-slot');sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${URL.createObjectURL(b)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}}\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  if(F.brand)document.getElementById('f-brand').value=F.brand;\u001b[39m\n\u001b[31m  if(F.storeName)document.getElementById('f-store').value=F.storeName;\u001b[39m\n\u001b[31m  if(F.address)document.getElementById('f-addr').value=F.address;\u001b[39m\n\u001b[31m  if(F.mobile)document.getElementById('f-mobile').value=F.mobile;\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();updAvailTag();\u001b[39m\n\u001b[31m  toast('Recce loaded — make changes and re-submit','success');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── EDIT REQUEST ────────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mlet _editReqSubId = null;·\u001b[39m\n\u001b[31mfunction _hydratePhotosFromRow(r) {\u001b[39m\n\u001b[31m  let pu={};\u001b[39m\n\u001b[31m  try{pu=typeof r.photo_urls==='string'?JSON.parse(r.photo_urls):(r.photo_urls||{});}catch(_){}\u001b[39m\n\u001b[31m  let meta={};\u001b[39m\n\u001b[31m  try{meta=typeof r.meta==='string'?JSON.parse(r.meta):(r.meta||{});}catch(_){}\u001b[39m\n\u001b[31m  frontPhotos =(pu.front   ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  insidePhotos=(pu.inside  ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  addlPhotos  =(pu.addl    ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,desc:''}));\u001b[39m\n\u001b[31m  brandings   =(meta.brandings||[]).map((b,i)=>({type:b.type,w:b.w,h:b.h,qty:b.qty,existingUrl:(pu.brandings||[])[i]||null,blob:null,prev:(pu.brandings||[])[i]||null}));\u001b[39m\n\u001b[31m  _docExistingUrl=pu.doc||null;\u001b[39m\n\u001b[31m  // Show retained doc in slot\u001b[39m\n\u001b[31m  const sl=document.getElementById('doc-slot');\u001b[39m\n\u001b[31m  if(sl&&_docExistingUrl){sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${_docExistingUrl}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openEditRequestModal(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  _editReqSubId = subId;\u001b[39m\n\u001b[31m  document.getElementById('er-store-name').textContent = r.store_name || 'Unknown';\u001b[39m\n\u001b[31m  document.getElementById('er-comment').value = '';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const assignBtn = document.getElementById('er-assign-btn');\u001b[39m\n\u001b[31m  if (r.submitted_by && r.submitted_by !== hub?.empId) {\u001b[39m\n\u001b[31m    assignBtn.textContent = `👤 Assign to ${r.submitted_by}`;\u001b[39m\n\u001b[31m    assignBtn.style.display = '';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    assignBtn.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeEditRequestModal() {\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _editReqSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorEditMyself() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  // Lock branding if client has reviewed (preserve their approval)\u001b[39m\n\u001b[31m  _brandingLocked = !!(r.client_status && r.client_status !== 'pending');\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function assignEditToCreator() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r || !r.submitted_by) { toast('No creator found for this recce', 'error'); return; }\u001b[39m\n\u001b[31m  const comment = (document.getElementById('er-comment').value || '').trim();\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        status: 'edit_requested',\u001b[39m\n\u001b[31m        edit_assigned_to: r.submitted_by,\u001b[39m\n\u001b[31m        edit_comment: comment || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!resp.ok) throw new Error('Update failed: ' + resp.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].status = 'edit_requested';\u001b[39m\n\u001b[31m      _adminRows[idx].edit_assigned_to = r.submitted_by;\u001b[39m\n\u001b[31m      _adminRows[idx].edit_comment = comment || null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Push notification to creator\u001b[39m\n\u001b[31m    const notifBody = comment || `Please review and re-submit: ${r.store_name || 'your recce'}`;\u001b[39m\n\u001b[31m    fetch('/push-server/notify', {\u001b[39m\n\u001b[31m      method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        user_id: r.submitted_by, title: '✏ Edit Requested',\u001b[39m\n\u001b[31m        body: notifBody, tag: `recce-edit-${subId}`, url: '/recce/',\u001b[39m\n\u001b[31m        icon: '/hub/icons/icon-192.png', badge: '/hub/icons/icon-192.png',\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    }).catch(() => {});\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast(`Edit assigned to ${r.submitted_by} ✓`, 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Assign failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function startCreatorEdit(subId) {\u001b[39m\n\u001b[31m  // Try local IndexedDB first (has photos)\u001b[39m\n\u001b[31m  const local = await dbGet('subs', subId);\u001b[39m\n\u001b[31m  if (local) { await editRecce(subId); return; }\u001b[39m\n\u001b[31m  // Fallback: load text fields from server row\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId)\u001b[39m\n\u001b[31m         || (await (async () => {\u001b[39m\n\u001b[31m              try {\u001b[39m\n\u001b[31m                const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, { headers: _RC_READ });\u001b[39m\n\u001b[31m                if (resp.ok) { const arr = await resp.json(); return arr[0]; }\u001b[39m\n\u001b[31m              } catch(_) {} return null;\u001b[39m\n\u001b[31m            })());\u001b[39m\n\u001b[31m  if (!r) { toast('Record not found', 'error'); return; }\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── End edit request ─────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mfunction goToHub() { window.location.href = '/hub/'; }\u001b[39m\n\u001b[31mfunction recceLogout() {\u001b[39m\n\u001b[31m  if (!confirm('Log out?')) return;\u001b[39m\n\u001b[31m  localStorage.removeItem('lm360-session');\u001b[39m\n\u001b[31m  localStorage.removeItem('360exp-session');\u001b[39m\n\u001b[31m  window.location.href = '/hub/';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction injectHubButtons() {\u001b[39m\n\u001b[31m  const u = _recceHubUser();\u001b[39m\n\u001b[31m  const name = u ? (u.name || '') : '';\u001b[39m\n\u001b[31m  if (name) {\u001b[39m\n\u001b[31m    const bar = document.getElementById('recce-hero-ubar');\u001b[39m\n\u001b[31m    const nm  = document.getElementById('recce-hero-name');\u001b[39m\n\u001b[31m    if (bar) { nm.textContent = name; bar.style.display = 'flex'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.querySelectorAll('.hdr').forEach(hdr => {\u001b[39m\n\u001b[31m    const r = document.createElement('div');\u001b[39m\n\u001b[31m    r.className = 'hdr-r';\u001b[39m\n\u001b[31m    if (name) {\u001b[39m\n\u001b[31m      const un = document.createElement('span');\u001b[39m\n\u001b[31m      un.className = 'hdr-user';\u001b[39m\n\u001b[31m      un.textContent = name;\u001b[39m\n\u001b[31m      r.appendChild(un);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    const hub = document.createElement('button');\u001b[39m\n\u001b[31m    hub.className = 'btn-hub';\u001b[39m\n\u001b[31m    hub.innerHTML = '🏡 Hub';\u001b[39m\n\u001b[31m    hub.addEventListener('click', goToHub);\u001b[39m\n\u001b[31m    r.appendChild(hub);\u001b[39m\n\u001b[31m    const lo = document.createElement('button');\u001b[39m\n\u001b[31m    lo.className = 'btn-logout';\u001b[39m\n\u001b[31m    lo.textContent = 'Logout';\u001b[39m\n\u001b[31m    lo.addEventListener('click', recceLogout);\u001b[39m\n\u001b[31m    r.appendChild(lo);\u001b[39m\n\u001b[31m    hdr.appendChild(r);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction checkAppUpdate(){\u001b[39m\n\u001b[31m  const seen=localStorage.getItem('recce-ver-seen');\u001b[39m\n\u001b[31m  localStorage.setItem('recce-ver-seen',CACHE_VER);\u001b[39m\n\u001b[31m  if(seen&&seen!==CACHE_VER){\u001b[39m\n\u001b[31m    const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m    if(b){b.classList.add('show');setTimeout(()=>b.classList.remove('show'),5000);}\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction dismissUpdateBanner(){\u001b[39m\n\u001b[31m  const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m  if(b)b.classList.remove('show');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function init(){\u001b[39m\n\u001b[31m  // Detect host banners (tiiny.host, etc) and raise bnav above them\u001b[39m\n\u001b[31m  (function detectHostBar(){\u001b[39m\n\u001b[31m    const h=window.location.hostname;\u001b[39m\n\u001b[31m    let extra=0;\u001b[39m\n\u001b[31m    if(h.includes('tiiny'))extra=58;\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // Generic detection: check if window is shorter than expected (host injected a bar)\u001b[39m\n\u001b[31m      const gap=screen.height - window.innerHeight;\u001b[39m\n\u001b[31m      if(gap>100&&gap<200)extra=58; // a fixed bar is roughly 56-60px\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if(extra>0){\u001b[39m\n\u001b[31m      document.documentElement.style.setProperty('--host-bar',extra+'px');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  })();\u001b[39m\n\u001b[31m  setLang(LANG);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m  checkAppUpdate();\u001b[39m\n\u001b[31m  await loadRecceCfg();\u001b[39m\n\u001b[31m  _checkAccessMode();\u001b[39m\n\u001b[31m  await initDB();await loadSettings();await loadHome();await checkDraft();netStatus();window.addEventListener('online',()=>{netStatus();syncNow();});window.addEventListener('offline',netStatus);injectHubButtons();document.getElementById('today-date').textContent=new Date().toLocaleDateString('en-IN',{weekday:'long',day:'numeric',month:'long',year:'numeric'});updAvailTag();\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m  // Auto-fetch stores from server on every startup (uses default Netlify URL if none saved)\u001b[39m\n\u001b[31m  const su=(await cfg('srv-url'))||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su&&navigator.onLine){\u001b[39m\n\u001b[31m    fetch(su).then(r=>r.json()).then(async j=>{\u001b[39m\n\u001b[31m      const d=Array.isArray(j)?j:j.stores||[];\u001b[39m\n\u001b[31m      if(d.length){stores=d;await cfg('stores',JSON.stringify(d));await cfg('srv-url',su);updAvailTag();\u001b[39m\n\u001b[31m        document.getElementById('srv-url').value=su;}\u001b[39m\n\u001b[31m    }).catch(()=>{});\u001b[39m\n\u001b[31m  }}init();\u001b[39m\n\u001b[31m</script>\u001b[39m\n\u001b[31m</body>\u001b[39m\n\u001b[31m</html>\u001b[39m\n\u001b[31m\"\u001b[39m\n    at /var/www/360lm/tests/recce.spec.js:337:17",
                        "location": {
                          "file": "/var/www/360lm/tests/recce.spec.js",
                          "column": 17,
                          "line": 337
                        },
                        "snippet": "  335 |     const resp = await page.request.get(BASE_URL);\n  336 |     const src = await resp.text();\n> 337 |     expect(src).toContain('recce-v15');\n      |                 ^\n  338 |     expect(src).not.toContain('recce-v14');\n  339 |   });\n  340 | });"
                      },
                      "errors": [
                        {
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "column": 17,
                            "line": 337
                          },
                          "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoContain\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // indexOf\u001b[22m\n\nExpected substring: \u001b[32m\"recce-v15\"\u001b[39m\nReceived string:    \u001b[31m\"<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\">\u001b[39m\n\u001b[31m<head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\">\u001b[39m\n\u001b[31m<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\\\">\u001b[39m\n\u001b[31m<meta name=\\\"theme-color\\\" content=\\\"#0f172a\\\">\u001b[39m\n\u001b[31m<meta name=\\\"apple-mobile-web-app-capable\\\" content=\\\"yes\\\">\u001b[39m\n\u001b[31m<title>Branding Recce</title>\u001b[39m\n\u001b[31m<link rel=\\\"manifest\\\" href=\\\"manifest.json\\\">\u001b[39m\n\u001b[31m<link rel=\\\"preconnect\\\" href=\\\"https://fonts.googleapis.com\\\">\u001b[39m\n\u001b[31m<link href=\\\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap\\\" rel=\\\"stylesheet\\\">\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--nv:#0f172a;--nv2:#1e293b;--or:#f97316;--orl:#fed7aa;--gn:#16a34a;--rd:#dc2626;--am:#d97706;--g50:#f8fafc;--g100:#f1f5f9;--g200:#e2e8f0;--g300:#cbd5e1;--g400:#94a3b8;--g500:#64748b;--g600:#475569;--r:12px;--rs:8px;--sh:0 1px 3px rgba(0,0,0,.1),0 1px 2px rgba(0,0,0,.06);--bnav-h:72px;--host-bar:0px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}\u001b[39m\n\u001b[31mbody{font-family:'DM Sans',sans-serif;background:var(--g50);color:var(--nv);min-height:100vh;overflow-x:hidden}\u001b[39m\n\u001b[31m.hdr{background:var(--nv);color:#fff;padding:0 16px;height:56px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}\u001b[39m\n\u001b[31m.hdr-l{display:flex;align-items:center;gap:10px}\u001b[39m\n\u001b[31m.hdr-title{font-size:16px;font-weight:600}.hdr-sub{font-size:11px;color:var(--g400)}\u001b[39m\n\u001b[31m.back-btn,.icon-btn{background:none;border:none;color:#fff;padding:8px;cursor:pointer;display:flex;align-items:center}\u001b[39m\n\u001b[31m.back-btn{margin-left:-8px}\u001b[39m\n\u001b[31m.pgbar{height:3px;background:var(--g200)}.pgfill{height:100%;background:var(--or);transition:width .3s}\u001b[39m\n\u001b[31m.view{display:none;min-height:calc(100vh - 56px);padding-bottom:calc(var(--bnav-h) + var(--host-bar) + 24px)}.view.active{display:block}\u001b[39m\n\u001b[31m.content{padding:16px}\u001b[39m\n\u001b[31m.card{background:#fff;border-radius:var(--r);padding:16px;box-shadow:var(--sh);margin-bottom:12px}\u001b[39m\n\u001b[31m.card-title{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;letter-spacing:.6px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between}\u001b[39m\n\u001b[31m.cnt-badge{background:var(--or);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;min-width:22px;text-align:center}\u001b[39m\n\u001b[31m.cnt-badge.gray{background:var(--g400)}\u001b[39m\n\u001b[31m.field{margin-bottom:16px}.field:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.field label{display:block;font-size:13px;font-weight:500;color:var(--g600);margin-bottom:6px}\u001b[39m\n\u001b[31m.req{color:var(--or);margin-left:2px}\u001b[39m\n\u001b[31m.field input,.field select,.field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;color:var(--nv);background:#fff;transition:border-color .15s;-webkit-appearance:none;appearance:none}\u001b[39m\n\u001b[31m.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--or)}\u001b[39m\n\u001b[31m.field input:read-only{background:var(--g50);color:var(--g600)}\u001b[39m\n\u001b[31m.field textarea{resize:vertical;min-height:68px}\u001b[39m\n\u001b[31m.field select{background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}\u001b[39m\n\u001b[31m.pslot{border:2px dashed var(--g300);border-radius:var(--r);min-height:110px;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all .15s;position:relative;overflow:hidden;text-align:center;padding:16px}\u001b[39m\n\u001b[31m.pslot:active{border-color:var(--or);background:var(--g50)}\u001b[39m\n\u001b[31m.pslot.filled{border-style:solid;border-color:var(--or);padding:0;min-height:0}\u001b[39m\n\u001b[31m.pslot img{width:100%;height:150px;object-fit:cover;border-radius:calc(var(--r) - 2px);display:block}\u001b[39m\n\u001b[31m.pslot-lbl{font-size:13px;color:var(--g400);margin-top:6px}.pslot-ico{font-size:28px;color:var(--g300)}\u001b[39m\n\u001b[31m.pbadge{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.premove{position:absolute;top:6px;right:6px;background:var(--rd);color:#fff;border:none;border-radius:50%;width:26px;height:26px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;z-index:5}\u001b[39m\n\u001b[31minput[type=file]{display:none}\u001b[39m\n\u001b[31m.rgroup{display:flex;gap:10px}\u001b[39m\n\u001b[31m.rbtn{flex:1;padding:13px;border:1.5px solid var(--g200);border-radius:var(--rs);text-align:center;cursor:pointer;font-size:14px;font-weight:500;color:var(--g500);transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.rbtn.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.chip-grid{display:flex;flex-wrap:wrap;gap:8px}\u001b[39m\n\u001b[31m.chip{padding:7px 12px;border:1.5px solid var(--g200);border-radius:20px;font-size:13px;color:var(--g600);cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.chip.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.brand-chip{display:flex;align-items:center;gap:6px;padding:5px 12px}\u001b[39m\n\u001b[31m.brand-chip-logo{width:28px;height:18px;object-fit:contain;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{display:block;width:100%;padding:15px;background:var(--or);color:#fff;border:none;border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:700;cursor:pointer;text-align:center;transition:background .15s}\u001b[39m\n\u001b[31m.btn-p:active{background:#ea6c05}.btn-p:disabled{background:var(--g300);cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-s{display:block;width:100%;padding:14px;background:#fff;color:var(--nv);border:1.5px solid var(--g200);border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:500;cursor:pointer;text-align:center}\u001b[39m\n\u001b[31m.btn-s:active{background:var(--g100)}\u001b[39m\n\u001b[31m.btn-o{display:inline-flex;align-items:center;gap:6px;padding:10px 16px;background:#fff;color:var(--or);border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer}\u001b[39m\n\u001b[31m.btn-o:active{background:var(--orl)}\u001b[39m\n\u001b[31m.btn-d{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;background:#fff;color:var(--rd);border:1.5px solid #fecaca;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:12px;cursor:pointer}\u001b[39m\n\u001b[31m.bnav{position:fixed;bottom:var(--host-bar);left:0;right:0;background:#fff;border-top:1px solid var(--g200);display:flex;padding:10px 16px;gap:10px;z-index:100}\u001b[39m\n\u001b[31m.hero{background:var(--nv);color:#fff;padding:20px 16px 24px}\u001b[39m\n\u001b[31m.hero-title{font-size:22px;font-weight:700;margin-bottom:2px}.hero-sub{font-size:13px;color:var(--g400)}\u001b[39m\n\u001b[31m.stats{display:flex;gap:10px;margin-top:16px}\u001b[39m\n\u001b[31m.scard{flex:1;background:rgba(255,255,255,.08);border-radius:var(--rs);padding:12px;text-align:center}\u001b[39m\n\u001b[31m.snum{font-size:22px;font-weight:700}.slbl{font-size:11px;color:var(--g400);margin-top:2px}\u001b[39m\n\u001b[31m.scard.g .snum{color:#4ade80}.scard.a .snum{color:#fbbf24}\u001b[39m\n\u001b[31m.new-btn{background:var(--or);color:#fff;border:none;border-radius:var(--r);padding:16px;font-family:'DM Sans',sans-serif;font-size:16px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:10px;cursor:pointer;width:100%;margin-bottom:10px}\u001b[39m\n\u001b[31m.new-btn:active{background:#ea6c05}\u001b[39m\n\u001b[31m.resume-btn{background:var(--nv2);color:#fff;border:none;border-radius:var(--r);padding:13px 16px;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;display:flex;align-items:center;justify-content:space-between;cursor:pointer;width:100%;margin-bottom:18px}\u001b[39m\n\u001b[31m.sub-card{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:10px;display:flex;align-items:center;gap:12px}\u001b[39m\n\u001b[31m.sub-ico{width:40px;height:40px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}\u001b[39m\n\u001b[31m.sub-ico.pending{background:#fef3c7}.sub-ico.synced{background:#dcfce7}.sub-ico.failed{background:#fee2e2}\u001b[39m\n\u001b[31m.sub-meta{flex:1;min-width:0}.sub-name{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.sub-dtl{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.sbadge{font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;flex-shrink:0}\u001b[39m\n\u001b[31m.sbadge.pending{background:#fef3c7;color:#92400e}.sbadge.synced{background:#dcfce7;color:#14532d}.sbadge.failed{background:#fee2e2;color:#991b1b}\u001b[39m\n\u001b[31m.sh{display:flex;align-items:center;justify-content:space-between;margin:20px 0 12px}\u001b[39m\n\u001b[31m.st{font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.toast{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 8px);left:16px;right:16px;background:var(--nv);color:#fff;padding:12px 16px;border-radius:var(--r);font-size:14px;z-index:1000;transform:translateY(120px);opacity:0;transition:all .3s;pointer-events:none}\u001b[39m\n\u001b[31m.toast.show{transform:translateY(0);opacity:1}.toast.success{background:#16a34a}.toast.error{background:var(--rd)}.toast.info{background:var(--nv2)}\u001b[39m\n\u001b[31m.srow{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:#fff;border-top:1px solid var(--g100);font-size:12px;color:var(--g500)}\u001b[39m\n\u001b[31m.sdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px}.sdot.on{background:var(--gn)}.sdot.off{background:var(--g300)}\u001b[39m\n\u001b[31m.set-item{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:8px}\u001b[39m\n\u001b[31m.set-lbl{font-size:14px;font-weight:600;color:var(--nv);margin-bottom:4px}\u001b[39m\n\u001b[31m.set-sub{font-size:12px;color:var(--g500);margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem{background:#fff;border-radius:var(--r);border:1.5px solid var(--g200);padding:14px;margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\u001b[39m\n\u001b[31m.bitem-title{font-size:14px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.dim-row{display:flex;gap:8px}.dim-row .field{flex:1}\u001b[39m\n\u001b[31m.sqft{display:inline-block;background:var(--g100);color:var(--g600);font-size:12px;padding:4px 10px;border-radius:20px;margin-top:6px}\u001b[39m\n\u001b[31m.divider{height:1px;background:var(--g100);margin:12px 0}\u001b[39m\n\u001b[31m.rev-lbl{font-size:12px;color:var(--g500);margin-bottom:2px}\u001b[39m\n\u001b[31m.rev-val{font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.rev-photos{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}\u001b[39m\n\u001b[31m.rev-thumb{width:56px;height:56px;object-fit:cover;border-radius:var(--rs)}\u001b[39m\n\u001b[31m.empty{text-align:center;padding:40px 20px;color:var(--g400)}.empty-ico{font-size:40px;margin-bottom:12px}.empty-txt{font-size:14px}\u001b[39m\n\u001b[31m/* store picker */\u001b[39m\n\u001b[31m.store-card{border:1.5px solid var(--g200);border-radius:var(--rs);padding:13px 14px;background:#fff;position:relative;cursor:pointer}\u001b[39m\n\u001b[31m.store-card:active{background:var(--g50)}\u001b[39m\n\u001b[31m.store-card-name{font-size:15px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.store-card-meta{font-size:13px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.store-card-change{position:absolute;top:11px;right:12px;background:none;border:none;color:var(--or);font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer}\u001b[39m\n\u001b[31m.brand-tag{display:inline-block;background:var(--nv);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-top:4px}\u001b[39m\n\u001b[31m.last-chip{display:inline-flex;align-items:center;gap:4px;background:#fef3c7;color:#92400e;font-size:11px;font-weight:500;padding:3px 9px;border-radius:20px;margin-left:6px}\u001b[39m\n\u001b[31m.pick-trigger{border:2px solid var(--or);border-radius:var(--rs);padding:14px 16px;background:#fff7ed;display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-size:15px;font-weight:600;color:var(--or)}\u001b[39m\n\u001b[31m.pick-trigger:active{background:#ffedd5;border-color:#ea6800}\u001b[39m\n\u001b[31m.manual-toggle{display:flex;align-items:center;gap:8px;padding:10px 14px;border:1.5px dashed var(--g300);border-radius:var(--rs);cursor:pointer;font-size:13px;color:var(--g600);margin-top:8px;user-select:none}\u001b[39m\n\u001b[31m/* client chip grid */\u001b[39m\n\u001b[31m.cl-chip-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}\u001b[39m\n\u001b[31m.cl-chip{padding:8px 14px;border-radius:20px;border:1.5px solid var(--g200);font-size:13px;font-weight:500;color:var(--g600);background:#fff;cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.cl-chip:active,.cl-chip.sel{background:var(--or);border-color:var(--or);color:#fff;font-weight:600}\u001b[39m\n\u001b[31m.cl-chip-other{border-style:dashed}\u001b[39m\n\u001b[31m.client-tag{display:inline-block;background:#e0f2fe;color:#0369a1;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-left:4px}\u001b[39m\n\u001b[31m.manual-toggle.on{border-color:var(--or);background:#fff7ed;color:var(--or)}\u001b[39m\n\u001b[31m/* picker overlay */\u001b[39m\n\u001b[31m.povl{display:none;position:fixed;inset:0;background:var(--g50);z-index:200;flex-direction:column}\u001b[39m\n\u001b[31m.povl.open{display:flex}\u001b[39m\n\u001b[31m.povl-hdr{background:var(--nv);padding:12px 16px;display:flex;align-items:center;gap:12px;flex-shrink:0}\u001b[39m\n\u001b[31m.psearch{flex:1;padding:10px 14px;border:none;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;background:rgba(255,255,255,.12);color:#fff;outline:none}\u001b[39m\n\u001b[31m.psearch::placeholder{color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.pcancel{background:none;border:none;color:rgba(255,255,255,.7);font-family:'DM Sans',sans-serif;font-size:14px;cursor:pointer;padding:4px;white-space:nowrap}\u001b[39m\n\u001b[31m.plist{overflow-y:auto;flex:1}\u001b[39m\n\u001b[31m.pitem{padding:14px 16px;border-bottom:.5px solid var(--g100);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px}\u001b[39m\n\u001b[31m.pitem:active{background:var(--g100)}\u001b[39m\n\u001b[31m.pi-name{font-size:15px;font-weight:600;color:var(--nv)}.pi-addr{font-size:12px;color:var(--g500);margin-top:2px}.pi-last{font-size:11px;color:var(--am);margin-top:2px}\u001b[39m\n\u001b[31m.pi-brand{font-size:11px;font-weight:700;padding:3px 8px;border-radius:20px;background:var(--nv);color:#fff;flex-shrink:0}\u001b[39m\n\u001b[31m.psec{padding:8px 16px 4px;font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;background:var(--g50)}\u001b[39m\n\u001b[31m.padd{padding:16px;text-align:center;font-size:14px;color:var(--or);font-weight:600;cursor:pointer;background:#fff7ed;border-top:1.5px dashed var(--or)}\u001b[39m\n\u001b[31m.gps-row{display:flex;gap:8px;margin-top:8px}\u001b[39m\n\u001b[31m.gps-btn{flex-shrink:0;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;color:var(--g500);display:flex;align-items:center;gap:6px}\u001b[39m\n\u001b[31m.gps-btn:active{background:var(--orl);border-color:var(--or);color:var(--or)}\u001b[39m\n\u001b[31m@keyframes spin{to{transform:rotate(360deg)}}.spin{animation:spin .7s linear infinite;display:inline-block}\u001b[39m\n\u001b[31m/* ANNOTATION TOOL */\u001b[39m\n\u001b[31m.annot-modal{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column}\u001b[39m\n\u001b[31m.annot-modal.open{display:flex}\u001b[39m\n\u001b[31m.annot-bar{background:var(--nv);padding:8px 12px;flex-shrink:0}\u001b[39m\n\u001b[31m.annot-row{display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap}\u001b[39m\n\u001b[31m.annot-row:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.atool{padding:6px 10px;background:rgba(255,255,255,.1);border:1.5px solid rgba(255,255,255,.2);border-radius:var(--rs);color:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:500;cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.atool.on{background:var(--or);border-color:var(--or)}\u001b[39m\n\u001b[31m.atool.sel-on{background:#7c3aed;border-color:#7c3aed}\u001b[39m\n\u001b[31m.acolor{width:24px;height:24px;border-radius:50%;border:2px solid rgba(255,255,255,.3);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.acolor.on{border-color:#fff;border-width:3px;transform:scale(1.15)}\u001b[39m\n\u001b[31m.annot-cvs-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#111;position:relative}\u001b[39m\n\u001b[31m#annot-cvs{max-width:100%;max-height:100%;display:block;touch-action:none;cursor:crosshair}\u001b[39m\n\u001b[31m.annot-foot{background:var(--nv);padding:10px 16px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.req-note{font-size:12px;color:var(--rd);margin-top:6px;font-weight:500}\u001b[39m\n\u001b[31m/* Bottom dialog */\u001b[39m\n\u001b[31m.bdialog-wrap{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:400;align-items:flex-end}\u001b[39m\n\u001b[31m.bdialog-wrap.open{display:flex}\u001b[39m\n\u001b[31m.bdialog{background:#fff;border-radius:var(--r) var(--r) 0 0;padding:20px 16px 32px;width:100%}\u001b[39m\n\u001b[31m.bdialog-title{font-size:16px;font-weight:700;color:var(--nv);margin-bottom:6px}\u001b[39m\n\u001b[31m.bdialog-sub{font-size:13px;color:var(--g500);margin-bottom:16px}\u001b[39m\n\u001b[31m.bdialog-btns{display:flex;gap:10px}\u001b[39m\n\u001b[31m/* Edit badge on sub-card */\u001b[39m\n\u001b[31m.edit-btn-sm{padding:5px 12px;background:var(--g50);border:1px solid var(--g200);border-radius:20px;font-family:'DM Sans',sans-serif;font-size:12px;color:var(--g600);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m/* Toggle switch */\u001b[39m\n\u001b[31m.tog{width:48px;height:26px;background:var(--g300);border-radius:13px;cursor:pointer;transition:background .2s;flex-shrink:0;position:relative;display:inline-block}\u001b[39m\n\u001b[31m.tog.on{background:var(--or)}\u001b[39m\n\u001b[31m.tog-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2);pointer-events:none}\u001b[39m\n\u001b[31m.tog.on .tog-knob{transform:translateX(22px)}\u001b[39m\n\u001b[31m/* ── ADMIN RECCE VIEW ── */\u001b[39m\n\u001b[31m.af-bar{background:var(--g100);padding:10px 16px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--g200);overflow:hidden}\u001b[39m\n\u001b[31m.af-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}\u001b[39m\n\u001b[31m.af-sel{width:100%;padding:8px 10px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv);cursor:pointer;\u001b[39m\n\u001b[31m  white-space:normal;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.af-sel:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.af-inp{width:100%;padding:8px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv)}\u001b[39m\n\u001b[31m.af-inp:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.grp-hdr{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;\u001b[39m\n\u001b[31m  letter-spacing:.5px;padding:14px 0 6px;border-bottom:1px solid var(--g200);margin-bottom:6px}\u001b[39m\n\u001b[31m.grp-hdr:first-child{padding-top:0}\u001b[39m\n\u001b[31m.asc{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:12px 14px;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;gap:6px;margin-bottom:8px;cursor:pointer;\u001b[39m\n\u001b[31m  transition:box-shadow .15s}\u001b[39m\n\u001b[31m.asc:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.asc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}\u001b[39m\n\u001b[31m.asc-name{font-size:14px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.asc-brand{display:inline-block;background:#fff7ed;color:var(--or);font-size:11px;\u001b[39m\n\u001b[31m  font-weight:600;padding:2px 8px;border-radius:20px;border:1px solid #fed7aa;white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chip{background:var(--g100);border-radius:20px;padding:2px 8px;font-size:11px;color:var(--g600);white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chips{display:flex;flex-wrap:wrap;gap:5px}\u001b[39m\n\u001b[31m.asc-agent{background:var(--nv);color:#fff;font-size:11px;font-weight:600;\u001b[39m\n\u001b[31m  padding:2px 8px;border-radius:20px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m/* Admin detail modal */\u001b[39m\n\u001b[31m.ardl-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:600;\u001b[39m\n\u001b[31m  display:flex;align-items:flex-end;justify-content:center}\u001b[39m\n\u001b[31m.ardl-box{background:#fff;border-radius:var(--r) var(--r) 0 0;width:100%;max-height:80vh;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ardl-hdr{display:flex;align-items:flex-start;justify-content:space-between;\u001b[39m\n\u001b[31m  padding:16px 16px 10px;border-bottom:1px solid var(--g200);gap:10px}\u001b[39m\n\u001b[31m.ardl-title{font-size:17px;font-weight:700;color:var(--nv);line-height:1.3}\u001b[39m\n\u001b[31m.ardl-body{flex:1;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:14px}\u001b[39m\n\u001b[31m.ardl-sec{display:flex;flex-direction:column;gap:6px}\u001b[39m\n\u001b[31m.ardl-lbl{font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.ardl-val{font-size:13px;color:var(--nv);line-height:1.5}\u001b[39m\n\u001b[31m.ardl-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\u001b[39m\n\u001b[31m/* Hub home button */\u001b[39m\n\u001b[31m.btn-hub{background:none;border:1px solid rgba(255,255,255,.25);color:rgba(255,255,255,.85);\u001b[39m\n\u001b[31m  font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;cursor:pointer;\u001b[39m\n\u001b[31m  display:flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-hub:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hdr-r{display:flex;align-items:center;gap:6px;margin-left:auto;flex-shrink:0}\u001b[39m\n\u001b[31m.hdr-user{font-size:11px;color:rgba(255,255,255,.7);white-space:nowrap;max-width:80px;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.btn-logout{background:none;border:1px solid rgba(255,255,255,.2);color:rgba(255,255,255,.7);font-size:11px;font-weight:600;padding:4px 8px;border-radius:20px;cursor:pointer;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-logout:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hero-ubar{display:flex;align-items:center;justify-content:space-between;padding-top:6px;margin-top:2px}\u001b[39m\n\u001b[31m.hero-uname{font-size:12px;color:rgba(255,255,255,.65)}\u001b[39m\n\u001b[31m.hi-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .en-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .hi-txt{display:inline}\u001b[39m\n\u001b[31m.lang-btn{background:none;border:1px solid rgba(255,255,255,.3);color:rgba(255,255,255,.8);font-size:12px;font-weight:700;padding:4px 10px;border-radius:20px;cursor:pointer;display:flex;align-items:center;gap:3px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.lang-btn:active{background:rgba(255,255,255,.15)}\u001b[39m\n\u001b[31m/* ── DELETE / AUDIT ── */\u001b[39m\n\u001b[31m.del-btn{background:none;border:none;padding:6px 8px;cursor:pointer;color:var(--g400);font-size:16px;flex-shrink:0;border-radius:var(--rs);transition:color .15s,background .15s}\u001b[39m\n\u001b[31m.del-btn:active{color:var(--rd);background:#fee2e2}\u001b[39m\n\u001b[31m.asc.deleted-row{background:#fff5f5;border:1px solid #fecaca;opacity:.85}\u001b[39m\n\u001b[31m.asc.deleted-row .asc-name{text-decoration:line-through;color:var(--g500)}\u001b[39m\n\u001b[31m.del-reason-tag{display:inline-block;background:#fee2e2;color:var(--rd);font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.del-by-txt{font-size:11px;color:var(--g400);margin-top:3px}\u001b[39m\n\u001b[31m.restore-btn{background:none;border:1.5px solid #bbf7d0;border-radius:20px;color:#16a34a;font-size:11px;font-weight:700;padding:3px 10px;cursor:pointer;white-space:nowrap;margin-top:5px}\u001b[39m\n\u001b[31m.restore-btn:active{background:#dcfce7}\u001b[39m\n\u001b[31m.sup-tile{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:20px 16px;cursor:pointer;display:flex;align-items:center;gap:14px;margin-bottom:12px;transition:box-shadow .15s}\u001b[39m\n\u001b[31m.sup-tile:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.sup-tile-ico{width:48px;height:48px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:26px;flex-shrink:0}\u001b[39m\n\u001b[31m.sup-tile-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.sup-tile-title{font-size:15px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.sup-tile-sub{font-size:12px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.del-toggle-btn{padding:6px 14px;border:1.5px solid var(--g200);border-radius:20px;background:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:600;color:var(--g500);cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.del-toggle-btn.active{background:#fee2e2;border-color:#fecaca;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1.5px solid var(--g200);border-radius:var(--r);margin-bottom:10px;cursor:pointer;transition:all .15s;font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.reason-opt:active{background:var(--g50)}\u001b[39m\n\u001b[31m.reason-opt.sel{border-color:var(--rd);background:#fff5f5;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt.danger{border-color:#fdba74;background:#fff7ed;color:#9a3412}\u001b[39m\n\u001b[31m.reason-opt.danger.sel{border-color:#c2410c;background:#fff1e6;color:#9a3412}\u001b[39m\n\u001b[31m#del-confirm-btn.no-reason{background:var(--g300)!important;cursor:default}\u001b[39m\n\u001b[31m@keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}\u001b[39m\n\u001b[31m.reason-opt-ico{font-size:22px;flex-shrink:0}\u001b[39m\n\u001b[31m/* ── APP UPDATE BANNER ── */\u001b[39m\n\u001b[31m.upd-banner{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);left:12px;right:12px;background:#16a34a;color:#fff;padding:11px 14px;border-radius:var(--r);display:flex;align-items:center;justify-content:space-between;gap:10px;z-index:550;box-shadow:0 4px 16px rgba(0,0,0,.18);transform:translateY(120px);opacity:0;transition:transform .35s ease,opacity .35s ease;pointer-events:none}\u001b[39m\n\u001b[31m.upd-banner.show{transform:translateY(0);opacity:1;pointer-events:auto}\u001b[39m\n\u001b[31m/* ── EDIT REQUEST ── */\u001b[39m\n\u001b[31m.req-edit-btn{padding:4px 10px;background:#fffbeb;border:1px solid #fde68a;border-radius:20px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:600;color:#92400e;cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.req-edit-btn:active{background:#fef3c7}\u001b[39m\n\u001b[31m.edit-req-badge{display:inline-block;background:#fef3c7;color:#92400e;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;white-space:nowrap}\u001b[39m\n\u001b[31m.edit-req-card{background:#fffbeb;border:1.5px solid #fde68a;border-radius:var(--r);padding:14px 16px;margin-bottom:10px;display:flex;align-items:flex-start;gap:12px}\u001b[39m\n\u001b[31m.edit-req-card-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.edit-req-card-name{font-size:14px;font-weight:600;color:var(--nv);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.edit-req-card-meta{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.edit-req-cmt{font-size:12px;color:#78350f;background:#fff;border:1px solid #fde68a;border-radius:var(--rs);padding:8px 10px;margin-top:8px;line-height:1.5}\u001b[39m\n\u001b[31m.edit-req-section-hdr{font-size:11px;font-weight:700;color:#92400e;text-transform:uppercase;letter-spacing:.5px;padding:10px 0 6px;border-bottom:1px solid #fde68a;margin-bottom:8px}\u001b[39m\n\u001b[31m.upd-banner-ok{background:rgba(255,255,255,.2);border:none;color:#fff;border-radius:20px;padding:5px 13px;font-size:12px;font-weight:600;cursor:pointer;font-family:'DM Sans',sans-serif;white-space:nowrap}\u001b[39m\n\u001b[31m.upd-banner-ok:active{background:rgba(255,255,255,.35)}\u001b[39m\n\u001b[31m/* ── FONT SIZE WIDGET ── */\u001b[39m\n\u001b[31m.fs-widget{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);right:12px;display:flex;align-items:center;gap:0;background:#fff;border:1.5px solid var(--g200);border-radius:24px;box-shadow:0 2px 8px rgba(0,0,0,.12);z-index:500;overflow:hidden;user-select:none}\u001b[39m\n\u001b[31m.fs-btn{background:none;border:none;cursor:pointer;padding:7px 11px;color:var(--g500);line-height:1;transition:background .15s}\u001b[39m\n\u001b[31m.fs-btn:active{background:var(--g100)}\u001b[39m\n\u001b[31m.fs-btn:disabled{color:var(--g300);cursor:default}\u001b[39m\n\u001b[31m.fs-label{font-size:11px;font-weight:700;color:var(--g500);padding:0 4px;pointer-events:none}\u001b[39m\n\u001b[31m/* Level 1 — Large (+15%) */\u001b[39m\n\u001b[31mbody.fs-1 .field label,body.fs-1 .card-title,body.fs-1 .set-lbl,body.fs-1 .set-sub,\u001b[39m\n\u001b[31mbody.fs-1 .hdr-title,body.fs-1 .hdr-sub,body.fs-1 .slbl,body.fs-1 .rev-lbl,body.fs-1 .rev-val,\u001b[39m\n\u001b[31mbody.fs-1 .rbtn,body.fs-1 .chip,body.fs-1 .btn-p,body.fs-1 .btn-s,body.fs-1 .btn-o,\u001b[39m\n\u001b[31mbody.fs-1 .bdialog-title,body.fs-1 .bdialog-sub,body.fs-1 .sub-name,body.fs-1 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-1 .pslot-lbl,body.fs-1 .bitem-title,body.fs-1 .pi-name,body.fs-1 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-1 .asc-name,body.fs-1 .new-btn,body.fs-1 .resume-btn,body.fs-1 .ardl-lbl,body.fs-1 .ardl-val{font-size:calc(1em * 1.15) !important}\u001b[39m\n\u001b[31m/* Level 2 — X-Large (+30%) */\u001b[39m\n\u001b[31mbody.fs-2 .field label,body.fs-2 .card-title,body.fs-2 .set-lbl,body.fs-2 .set-sub,\u001b[39m\n\u001b[31mbody.fs-2 .hdr-title,body.fs-2 .hdr-sub,body.fs-2 .slbl,body.fs-2 .rev-lbl,body.fs-2 .rev-val,\u001b[39m\n\u001b[31mbody.fs-2 .rbtn,body.fs-2 .chip,body.fs-2 .btn-p,body.fs-2 .btn-s,body.fs-2 .btn-o,\u001b[39m\n\u001b[31mbody.fs-2 .bdialog-title,body.fs-2 .bdialog-sub,body.fs-2 .sub-name,body.fs-2 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-2 .pslot-lbl,body.fs-2 .bitem-title,body.fs-2 .pi-name,body.fs-2 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-2 .asc-name,body.fs-2 .new-btn,body.fs-2 .resume-btn,body.fs-2 .ardl-lbl,body.fs-2 .ardl-val{font-size:calc(1em * 1.30) !important}\u001b[39m\n\u001b[31m/* Level 3 — XX-Large (+50%) */\u001b[39m\n\u001b[31mbody.fs-3 .field label,body.fs-3 .card-title,body.fs-3 .set-lbl,body.fs-3 .set-sub,\u001b[39m\n\u001b[31mbody.fs-3 .hdr-title,body.fs-3 .hdr-sub,body.fs-3 .slbl,body.fs-3 .rev-lbl,body.fs-3 .rev-val,\u001b[39m\n\u001b[31mbody.fs-3 .rbtn,body.fs-3 .chip,body.fs-3 .btn-p,body.fs-3 .btn-s,body.fs-3 .btn-o,\u001b[39m\n\u001b[31mbody.fs-3 .bdialog-title,body.fs-3 .bdialog-sub,body.fs-3 .sub-name,body.fs-3 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-3 .pslot-lbl,body.fs-3 .bitem-title,body.fs-3 .pi-name,body.fs-3 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-3 .asc-name,body.fs-3 .new-btn,body.fs-3 .resume-btn,body.fs-3 .ardl-lbl,body.fs-3 .ardl-val{font-size:calc(1em * 1.50) !important}\u001b[39m\n\u001b[31m/* Level 4 — Max (+70%) */\u001b[39m\n\u001b[31mbody.fs-4 .field label,body.fs-4 .card-title,body.fs-4 .set-lbl,body.fs-4 .set-sub,\u001b[39m\n\u001b[31mbody.fs-4 .hdr-title,body.fs-4 .hdr-sub,body.fs-4 .slbl,body.fs-4 .rev-lbl,body.fs-4 .rev-val,\u001b[39m\n\u001b[31mbody.fs-4 .rbtn,body.fs-4 .chip,body.fs-4 .btn-p,body.fs-4 .btn-s,body.fs-4 .btn-o,\u001b[39m\n\u001b[31mbody.fs-4 .bdialog-title,body.fs-4 .bdialog-sub,body.fs-4 .sub-name,body.fs-4 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-4 .pslot-lbl,body.fs-4 .bitem-title,body.fs-4 .pi-name,body.fs-4 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-4 .asc-name,body.fs-4 .new-btn,body.fs-4 .resume-btn,body.fs-4 .ardl-lbl,body.fs-4 .ardl-val{font-size:calc(1em * 1.70) !important}\u001b[39m\n\u001b[31m/* ── RECCE TILE ACTION BUTTONS ── */\u001b[39m\n\u001b[31m.rpt-btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid rgba(0,0,0,.06)}\u001b[39m\n\u001b[31m.rpt-btn{display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 14px;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;border:none;font-family:inherit;transition:background .15s,opacity .15s;flex:1;min-width:110px;letter-spacing:.1px;white-space:nowrap}\u001b[39m\n\u001b[31m.rpt-btn-report{background:#fff7ed;color:var(--or);border:1.5px solid var(--or)}\u001b[39m\n\u001b[31m.rpt-btn-report:active{background:#fed7aa}\u001b[39m\n\u001b[31m.rpt-btn-pdf{background:var(--g100);color:var(--g400);border:1.5px solid var(--g200)}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready{background:var(--or);color:#fff;border-color:transparent}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready:active{background:#ea6c00}\u001b[39m\n\u001b[31m/* PDF wait overlay */\u001b[39m\n\u001b[31m#pdf-wait-ov{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m</style>\u001b[39m\n\u001b[31m</head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<!-- PICKER OVERLAY -->\u001b[39m\n\u001b[31m<div class=\\\"povl\\\" id=\\\"povl\\\">\u001b[39m\n\u001b[31m  <div class=\\\"povl-hdr\\\">\u001b[39m\n\u001b[31m    <input class=\\\"psearch\\\" id=\\\"psearch\\\" type=\\\"text\\\" placeholder=\\\"Search store / दुकान खोजें…\\\" oninput=\\\"filterPicker(this.value)\\\" autocomplete=\\\"off\\\">\u001b[39m\n\u001b[31m    <button class=\\\"pcancel\\\" onclick=\\\"closePicker()\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"plist\\\" id=\\\"plist\\\"></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"app\\\">·\u001b[39m\n\u001b[31m<!-- HOME -->\u001b[39m\n\u001b[31m<div class=\\\"view active\\\" id=\\\"view-home\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hero\\\">\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;justify-content:space-between;align-items:center\\\">\u001b[39m\n\u001b[31m      <div><div class=\\\"hero-title\\\"><span class=\\\"en-txt\\\">Branding Recce</span><span class=\\\"hi-txt\\\">ब्रांडिंग रेकी</span></div><div class=\\\"hero-sub\\\" id=\\\"today-date\\\">—</div></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:6px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"lang-btn\\\" onclick=\\\"setLang(LANG==='en'?'hi':'en')\\\" id=\\\"lang-btn\\\" title=\\\"Switch language / भाषा बदलें\\\">EN | हि</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-hub\\\" onclick=\\\"goToHub()\\\">🏡 Hub</button>\u001b[39m\n\u001b[31m      <button class=\\\"icon-btn\\\" onclick=\\\"showView('settings')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12 15a3 3 0 100-6 3 3 0 000 6z\\\"/><path d=\\\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\\\"/></svg></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"hero-ubar\\\" id=\\\"recce-hero-ubar\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <span class=\\\"hero-uname\\\" id=\\\"recce-hero-name\\\"></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-logout\\\" onclick=\\\"recceLogout()\\\">Logout</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"stats\\\">\u001b[39m\n\u001b[31m      <div class=\\\"scard g\\\"><div class=\\\"snum\\\" id=\\\"stat-synced\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Synced</span><span class=\\\"hi-txt\\\">सिंक्ड</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard a\\\"><div class=\\\"snum\\\" id=\\\"stat-pending\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Pending</span><span class=\\\"hi-txt\\\">बाकी</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard\\\"><div class=\\\"snum\\\" id=\\\"stat-total\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Total</span><span class=\\\"hi-txt\\\">कुल</span></div></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <button class=\\\"new-btn\\\" onclick=\\\"startNewRecce()\\\"><svg width=\\\"20\\\" height=\\\"20\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">New Recce</span><span class=\\\"hi-txt\\\">नई रेकी</span></button>\u001b[39m\n\u001b[31m    <div id=\\\"resume-wrap\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"sh\\\"><span class=\\\"st\\\"><span class=\\\"en-txt\\\">Recent Submissions</span><span class=\\\"hi-txt\\\">हाल की सबमिशन</span></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"syncNow()\\\" id=\\\"sync-btn\\\" style=\\\"padding:7px 12px;font-size:12px\\\"><svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg><span class=\\\"en-txt\\\">Sync</span><span class=\\\"hi-txt\\\">सिंक</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"sub-list\\\"></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"srow\\\"><div><span class=\\\"sdot\\\" id=\\\"net-dot\\\"></span><span id=\\\"net-txt\\\"><span class=\\\"en-txt\\\">Checking…</span><span class=\\\"hi-txt\\\">जाँच…</span></span></div><span id=\\\"last-sync-txt\\\" style=\\\"font-size:11px\\\"><span class=\\\"en-txt\\\">Never synced</span><span class=\\\"hi-txt\\\">कभी सिंक नहीं</span></span></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- SETTINGS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-settings\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('home')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Settings</span><span class=\\\"hi-txt\\\">सेटिंग</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Brand List</span><span class=\\\"hi-txt\\\">ब्रांड सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Manage Brands</span><span class=\\\"hi-txt\\\">ब्रांड प्रबंधन</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">These appear in the brand dropdown and store picker. Add client brands as needed.</div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-manage-list\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-add-row\\\" style=\\\"display:none;gap:8px;align-items:center\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"brand-add-inp\\\" placeholder=\\\"Type brand name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addBrandToList()\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"addBrandToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Store Lists</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Supervisors can upload XLS/CSV store lists here. Updates sync to all devices via server.</span><span class=\\\"hi-txt\\\">सुपरवाइजर यहाँ XLS/CSV स्टोर सूची अपलोड कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m      <!-- Upload/Clear row — supervisor only -->\u001b[39m\n\u001b[31m      <div id=\\\"store-upload-row\\\" style=\\\"display:none;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;margin-top:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"document.getElementById('store-xl').click()\\\"><svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Add File</span><span class=\\\"hi-txt\\\">फ़ाइल जोड़ें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-d\\\" onclick=\\\"clearStoreList()\\\" style=\\\"font-size:12px\\\"><span class=\\\"en-txt\\\">Clear All Stores</span><span class=\\\"hi-txt\\\">सभी स्टोर हटाएं</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" id=\\\"store-push-btn\\\" onclick=\\\"pushStoresToServer()\\\" style=\\\"font-size:12px;display:none\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Push to Server</span><span class=\\\"hi-txt\\\">सर्वर पर पुश करें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"store-xl\\\" accept=\\\".xlsx,.xls,.csv\\\" onchange=\\\"handleStoreUpload(event)\\\">\u001b[39m\n\u001b[31m      <div id=\\\"store-count\\\" style=\\\"font-size:13px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"store-file-list\\\" style=\\\"margin-top:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Brand assignment dialog for files with no brand column -->\u001b[39m\n\u001b[31m    <div id=\\\"brand-assign-dialog\\\" style=\\\"display:none;margin-top:10px;padding:14px;background:#fff7ed;border:1.5px solid var(--or);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\">Which brand is this store list for?</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\" id=\\\"brand-assign-fname\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-assign-chips\\\" class=\\\"chip-grid\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"confirmBrandAssign()\\\" style=\\\"flex:2;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">Assign Brand</span><span class=\\\"hi-txt\\\">ब्रांड असाइन करें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"skipBrandAssign()\\\" style=\\\"flex:1;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">No Brand</span><span class=\\\"hi-txt\\\">कोई ब्रांड नहीं</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Server Store List URL (Admin)</span><span class=\\\"hi-txt\\\">सर्वर स्टोर सूची URL</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Admin pushes stores.json to any public URL. App auto-fetches on open and caches offline.</div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"srv-url\\\" placeholder=\\\"https://yourserver.com/stores.json\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"fetchServerStores()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Fetch Now</button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"saveServerUrl()\\\" style=\\\"padding:9px 14px;font-size:13px;width:auto\\\">Save URL</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Sync Endpoint</span><span class=\\\"hi-txt\\\">सिंक एंडपॉइंट</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Slides Generator</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Managed by admin. Deploy gas_slides.gs from /opt/slides-proxy/ to Google Apps Script and paste the URL here.</div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"slides-gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Not configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"slides-gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"saveSlidesGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Sheet Sync</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Legacy sync endpoint. Writes recce data to Google Sheet.</div>·\u001b[39m\n\u001b[31m      <!-- Locked state (default) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Endpoint configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Unlocked state (after admin login) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;align-items:center;gap:8px;margin-bottom:10px;padding:7px 12px;background:#dcfce7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          <span style=\\\"font-size:12px;color:#14532d;font-weight:600\\\">🔓 Admin mode active</span>\u001b[39m\n\u001b[31m          <button onclick=\\\"lockAdmin()\\\" style=\\\"margin-left:auto;background:none;border:none;color:#14532d;font-size:12px;cursor:pointer;font-weight:600\\\">Lock ×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"testEndpoint()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Test</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>·\u001b[39m\n\u001b[31m    <!-- Admin Login Modal -->\u001b[39m\n\u001b[31m    <div id=\\\"admin-login-modal\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m      <div style=\\\"background:#fff;border-radius:var(--r);padding:24px 20px;margin:20px;max-width:380px;width:100%;box-shadow:0 8px 32px rgba(0,0,0,.2)\\\">\u001b[39m\n\u001b[31m        <div style=\\\"font-size:17px;font-weight:700;color:var(--nv);margin-bottom:4px\\\">Admin Login</div>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:18px\\\">Enter admin password to unlock settings</div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m          <label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">Password</label>\u001b[39m\n\u001b[31m          <input type=\\\"password\\\" id=\\\"admin-pwd\\\" placeholder=\\\"Enter admin password\\\" style=\\\"width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px\\\" onkeydown=\\\"if(event.key==='Enter')verifyAdmin()\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div id=\\\"admin-error\\\" style=\\\"display:none;font-size:12px;color:var(--rd);margin-bottom:12px;padding:8px 12px;background:#fee2e2;border-radius:var(--rs)\\\">Incorrect password</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"verifyAdmin()\\\" style=\\\"flex:2;padding:13px\\\" id=\\\"admin-login-btn\\\">Login</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-s\\\" onclick=\\\"closeAdminLogin()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:14px;padding-top:14px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.4px;margin-bottom:8px\\\">Admin Password Config URL</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:8px\\\">URL to your admin.json file on server (contains hashed password)</div>\u001b[39m\n\u001b[31m          <input type=\\\"url\\\" id=\\\"admin-cfg-url\\\" placeholder=\\\"https://yourserver.com/admin.json\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px;margin-bottom:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveAdminCfgUrl()\\\" style=\\\"font-size:12px;padding:7px 12px;width:100%;justify-content:center\\\">Save Config URL</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Geolocation Stamp</span><span class=\\\"hi-txt\\\">जियोलोकेशन स्टैम्प</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;justify-content:space-between;gap:16px\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1\\\">\u001b[39m\n\u001b[31m          <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Stamp on Photos</span><span class=\\\"hi-txt\\\">फोटो पर स्टैम्प</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"set-sub\\\" style=\\\"margin-bottom:0\\\">Bakes GPS coordinates, store name and timestamp into every photo — visible in the image itself. Same as GPS Map Camera app. Default: On.</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"tog on\\\" id=\\\"geo-tog\\\" onclick=\\\"toggleGeoStamp()\\\"><div class=\\\"tog-knob\\\"></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"geo-status\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\">GPS not yet captured</div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Image Quality</span><span class=\\\"hi-txt\\\">फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Default Photo Quality</span><span class=\\\"hi-txt\\\">डिफ़ॉल्ट फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Applies to all photos — front view, inside view, branding, and additional. HD uses more storage and takes longer to sync on poor networks.</div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;gap:10px;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-compressed\\\" onclick=\\\"setImgQuality('compressed')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-compressed\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-compressed\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">Full Compression</span><span class=\\\"hi-txt\\\">पूर्ण कम्प्रेशन</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~150–200 KB · Max 1280px · Best for poor network</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-left:auto;font-size:11px;font-weight:700;color:var(--gn);background:#dcfce7;padding:3px 8px;border-radius:20px\\\"><span class=\\\"en-txt\\\">Recommended</span><span class=\\\"hi-txt\\\">अनुशंसित</span></div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-hd\\\" onclick=\\\"setImgQuality('hd')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-hd\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-hd\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">HD Quality</span><span class=\\\"hi-txt\\\">HD क्वालिटी</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~400–600 KB · Max 1920px · Better detail for print</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"q-current-badge\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Supervisor Config panel — shown only to supervisors via renderSupPanel() -->\u001b[39m\n\u001b[31m    <div id=\\\"sup-panel\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">🔐 Recce Access Config</span><span class=\\\"hi-txt\\\">🔐 रेकी एक्सेस कॉन्फ़िग</span></div>\u001b[39m\n\u001b[31m      <!-- Access mode — only H/P can change -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"mode-row\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Access Mode</span><span class=\\\"hi-txt\\\">एक्सेस मोड</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Public: any Hub user can submit Recces. Assigned: only Supervisors and Creators can access.</span><span class=\\\"hi-txt\\\">सार्वजनिक: कोई भी Hub यूजर। नियत: सिर्फ़ Supervisors और Creators।</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\" style=\\\"margin-bottom:8px;margin-top:8px\\\">\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-public\\\" onclick=\\\"setRecceMode('public')\\\"><span class=\\\"en-txt\\\">Public</span><span class=\\\"hi-txt\\\">सार्वजनिक</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-assigned\\\" onclick=\\\"setRecceMode('assigned')\\\"><span class=\\\"en-txt\\\">Assigned</span><span class=\\\"hi-txt\\\">नियत</span></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Supervisor list — view all + delete + create -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Supervisors</span><span class=\\\"hi-txt\\\">सुपरवाइजर</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can view all recces, delete with reason, and submit. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">सभी रेकी देख सकते हैं, कारण से हटा सकते हैं, और सबमिट कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"sup-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addSupervisor()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addSupervisor()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Creator list — creation only -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Creators</span><span class=\\\"hi-txt\\\">क्रिएटर्स</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can submit Recces only — no admin view or deletion rights. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">केवल रेकी सबमिट कर सकते हैं — एडमिन व्यू या डिलीट नहीं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"creator-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addCreator()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addCreator()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Client list — used for client portal scoping -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clients</span><span class=\\\"hi-txt\\\">क्लाइंट</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Names that appear as chips when submitting a recce. Add the brand or agency name (e.g. \\\"Marketing Vibe\\\"). These are used to scope what clients see in the Client Portal.</span><span class=\\\"hi-txt\\\">रेकी सबमिट करते समय दिखने वाले क्लाइंट नाम। ब्रांड या एजेंसी नाम जोड़ें।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-mgmt-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"client-add-inp\\\" placeholder=\\\"Client name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addClientToList()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addClientToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Sync to server — only H/P -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"cfg-sync-btn\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Sync Config to Server</span><span class=\\\"hi-txt\\\">सर्वर पर कॉन्फ़िग सिंक करें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Apply supervisor/creator/client lists and access mode to all devices.</span><span class=\\\"hi-txt\\\">सभी डिवाइस पर कॉन्फ़िग लागू करें।</span></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"syncCfgToServer()\\\" style=\\\"max-width:220px;font-size:14px;padding:12px;margin-top:8px\\\"><span class=\\\"en-txt\\\">Sync to Server</span><span class=\\\"hi-txt\\\">सर्वर पर सिंक करें</span></button>\u001b[39m\n\u001b[31m        <div id=\\\"cfg-sync-status\\\" style=\\\"margin-top:8px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Danger Zone</span><span class=\\\"hi-txt\\\">खतरनाक ज़ोन</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\"><div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clear All Local Data</span><span class=\\\"hi-txt\\\">सभी डेटा हटाएं</span></div><div class=\\\"set-sub\\\">Removes all submissions from this device.</div><button class=\\\"btn-d\\\" onclick=\\\"clearData()\\\" style=\\\"padding:9px 14px;font-size:13px\\\">Clear All</button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: STORE INFO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-store\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"exitForm()\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Details</span><span class=\\\"hi-txt\\\">दुकान विवरण</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 1 of 5</span><span class=\\\"hi-txt\\\">चरण 1 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:20%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Recce Info</span><span class=\\\"hi-txt\\\">रेकी जानकारी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Date of Recce</span><span class=\\\"hi-txt\\\">रेकी की तारीख</span> <span class=\\\"req\\\">*</span></label><input type=\\\"date\\\" id=\\\"f-date\\\" onchange=\\\"saveDraft()\\\" max=\\\"\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" id=\\\"campaign-field\\\">\u001b[39m\n\u001b[31m        <label><span class=\\\"en-txt\\\">Job / Campaign</span><span class=\\\"hi-txt\\\">जॉब / कैंपेन</span></label>\u001b[39m\n\u001b[31m        <select id=\\\"f-campaign-id\\\" onchange=\\\"onCampaignSelect()\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">Loading campaigns…</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <div id=\\\"campaign-notify-msg\\\" style=\\\"display:none;font-size:12px;color:#92400e;margin-top:6px;padding:8px 10px;background:#fef3c7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          ⚑ <span class=\\\"en-txt\\\">Recce will submit without a job ID. A notification will flag this for your supervisor to link it later.</span><span class=\\\"hi-txt\\\">रेकी बिना जॉब ID के सबमिट होगी। सुपरवाइजर बाद में लिंक करेगा।</span>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Store</span><span class=\\\"hi-txt\\\">दुकान</span> <span id=\\\"store-avail-tag\\\" style=\\\"font-size:11px;color:var(--g400);font-weight:400;text-transform:none;letter-spacing:0\\\"></span></div>·\u001b[39m\n\u001b[31m      <!-- When store is selected -->\u001b[39m\n\u001b[31m      <div id=\\\"store-selected\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"store-card\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:start;justify-content:space-between;gap:8px\\\">\u001b[39m\n\u001b[31m            <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m              <div class=\\\"store-card-name\\\" id=\\\"sc-name\\\">—</div>\u001b[39m\n\u001b[31m              <div style=\\\"display:flex;align-items:center;gap:6px;margin-top:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m                <span class=\\\"brand-tag\\\" id=\\\"sc-brand\\\">—</span>\u001b[39m\n\u001b[31m                <span class=\\\"last-chip\\\" id=\\\"sc-last\\\" style=\\\"display:none\\\">—</span>\u001b[39m\n\u001b[31m              </div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            <button class=\\\"store-card-change\\\" onclick=\\\"openPicker()\\\"><span class=\\\"en-txt\\\">Change ›</span><span class=\\\"hi-txt\\\">बदलें ›</span></button>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <!-- All fields from Excel shown here -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-details\\\" style=\\\"margin-top:10px;display:flex;flex-direction:column;gap:4px\\\"></div>\u001b[39m\n\u001b[31m          <!-- Missing required fields — editable inline -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-missing\\\" style=\\\"display:none;margin-top:12px;padding-top:12px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m            <div style=\\\"font-size:11px;font-weight:700;color:var(--rd);text-transform:uppercase;letter-spacing:.4px;margin-bottom:10px\\\">⚠ Please complete missing fields</div>\u001b[39m\n\u001b[31m            <div id=\\\"sc-missing-fields\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <!-- Brand selector — shown when store has no brand -->\u001b[39m\n\u001b[31m        <div id=\\\"brand-selector\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\"><span class=\\\"en-txt\\\">Select Brand</span><span class=\\\"hi-txt\\\">ब्रांड चुनें</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\">This store has no brand in the list — select one:</div>\u001b[39m\n\u001b[31m          <div id=\\\"brand-chips\\\" class=\\\"chip-grid\\\"></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Picker trigger (shown when stores loaded) -->\u001b[39m\n\u001b[31m      <div id=\\\"pick-trigger-wrap\\\">\u001b[39m\n\u001b[31m        <div class=\\\"pick-trigger\\\" onclick=\\\"openPicker()\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:center;gap:10px\\\">\u001b[39m\n\u001b[31m            <span style=\\\"font-size:20px\\\">🏪</span>\u001b[39m\n\u001b[31m            <div>\u001b[39m\n\u001b[31m              <div style=\\\"font-size:15px;font-weight:700;color:var(--or)\\\"><span class=\\\"en-txt\\\">Select Store from List</span><span class=\\\"hi-txt\\\">सूची से दुकान चुनें</span></div>\u001b[39m\n\u001b[31m              <div id=\\\"store-avail-count\\\" style=\\\"font-size:12px;font-weight:400;color:var(--am);margin-top:1px\\\"><span class=\\\"en-txt\\\">Tap to browse stores</span><span class=\\\"hi-txt\\\">दुकान खोजने के लिए दबाएं</span></div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual / new store toggle -->\u001b[39m\n\u001b[31m      <div class=\\\"manual-toggle\\\" id=\\\"manual-toggle\\\" onclick=\\\"toggleManual()\\\">\u001b[39m\n\u001b[31m        <svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\" id=\\\"mt-icon\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg>\u001b[39m\n\u001b[31m        <span id=\\\"mt-label\\\"><span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span></span>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual fields -->\u001b[39m\n\u001b[31m      <div id=\\\"manual-fields\\\" style=\\\"display:none;margin-top:14px\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\" style=\\\"margin-bottom:14px\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <select id=\\\"f-brand\\\" onchange=\\\"onManualBrandChange()\\\">\u001b[39m\n\u001b[31m            <option value=\\\"\\\">Select brand</option>\u001b[39m\n\u001b[31m          </select>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span> <span class=\\\"req\\\">*</span></label><input type=\\\"text\\\" id=\\\"f-store\\\" placeholder=\\\"Enter store name\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\">\u001b[39m\n\u001b[31m          <label><span class=\\\"en-txt\\\">Store Address</span><span class=\\\"hi-txt\\\">दुकान का पता</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <textarea id=\\\"f-addr\\\" rows=\\\"2\\\" placeholder=\\\"Full address\\\" onchange=\\\"saveDraft()\\\"></textarea>\u001b[39m\n\u001b[31m          <div class=\\\"gps-row\\\">\u001b[39m\n\u001b[31m            <button class=\\\"gps-btn\\\" onclick=\\\"captureGPS()\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\"/><path d=\\\"M12 2v3M12 19v3M2 12h3M19 12h3\\\"/></svg><span class=\\\"en-txt\\\">Capture GPS</span><span class=\\\"hi-txt\\\">GPS लें</span></button>\u001b[39m\n\u001b[31m            <span id=\\\"gps-status\\\" style=\\\"font-size:12px;color:var(--g500);align-self:center\\\"></span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Mobile No.</span><span class=\\\"hi-txt\\\">मोबाइल नंबर</span></label><input type=\\\"tel\\\" id=\\\"f-mobile\\\" placeholder=\\\"10-digit number\\\" maxlength=\\\"10\\\" inputmode=\\\"numeric\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Client card -->\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Client</span><span class=\\\"hi-txt\\\">क्लाइंट</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\"><span class=\\\"en-txt\\\">Select who this recce is for. Defaults to brand — change if work came via an agency.</span><span class=\\\"hi-txt\\\">यह रेकी किसके लिए है चुनें। ब्रांड से डिफ़ॉल्ट — एजेंसी के ज़रिए हो तो बदलें।</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"cl-chip-grid\\\" id=\\\"client-chips\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"client-other-wrap\\\" style=\\\"display:none;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"f-client-other\\\" placeholder=\\\"Type client name\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" oninput=\\\"onClientOtherInput()\\\">\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-p\\\" onclick=\\\"step2()\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: PHOTOS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-photos\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-store')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Photos</span><span class=\\\"hi-txt\\\">दुकान की फोटो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 2 of 5</span><span class=\\\"hi-txt\\\">चरण 2 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:40%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Front View</span><span class=\\\"hi-txt\\\">आगे का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(min 1, max 3)</span><span class=\\\"cnt-badge gray\\\" id=\\\"front-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"front-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-front\\\" onclick=\\\"addPhoto('front')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Front Photo</span><span class=\\\"hi-txt\\\">आगे की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Inside View</span><span class=\\\"hi-txt\\\">अंदर का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 5)</span><span class=\\\"cnt-badge gray\\\" id=\\\"inside-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"inside-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-inside\\\" onclick=\\\"addPhoto('inside')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Inside Photo</span><span class=\\\"hi-txt\\\">अंदर की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-store')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step3()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: VIDEO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-video\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-photos')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Recce Video</span><span class=\\\"hi-txt\\\">रेकी वीडियो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 3 of 5</span><span class=\\\"hi-txt\\\">चरण 3 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:60%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Video</span><span class=\\\"hi-txt\\\">वीडियो</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Recce video available?</span><span class=\\\"hi-txt\\\">रेकी वीडियो है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"vid-yes\\\" onclick=\\\"setVideo(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"vid-no\\\" onclick=\\\"setVideo(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"vid-sec\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Upload Video</span><span class=\\\"hi-txt\\\">वीडियो अपलोड करें</span></label>\u001b[39m\n\u001b[31m          <div class=\\\"pslot\\\" id=\\\"vid-slot\\\" onclick=\\\"document.getElementById('vid-inp').click()\\\"><div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div></div>\u001b[39m\n\u001b[31m          <input type=\\\"file\\\" id=\\\"vid-inp\\\" accept=\\\"video/*\\\" onchange=\\\"handleVideo(event)\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Video Comments</span><span class=\\\"hi-txt\\\">वीडियो टिप्पणी</span></label><input type=\\\"text\\\" id=\\\"f-vid-cmt\\\" placeholder=\\\"Optional\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-photos')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step4()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: BRANDING -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-branding\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-video')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Branding</span><span class=\\\"hi-txt\\\">ब्रांडिंग</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 4 of 5</span><span class=\\\"hi-txt\\\">चरण 4 / 5</span></div></div></div>\u001b[39m\n\u001b[31m    <span id=\\\"br-hdr-badge\\\" style=\\\"background:rgba(255,255,255,.2);color:#fff;font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px\\\"><span class=\\\"en-txt\\\">0 items</span><span class=\\\"hi-txt\\\">0 आइटम</span></span>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:80%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Branding Space</span><span class=\\\"hi-txt\\\">ब्रांडिंग स्थान</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Space available?</span><span class=\\\"hi-txt\\\">जगह उपलब्ध है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"br-yes\\\" onclick=\\\"setBranding(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"br-no\\\" onclick=\\\"setBranding(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"branding-lock-banner\\\" style=\\\"display:none;background:#fef3c7;border:1.5px solid #f59e0b;border-radius:10px;padding:12px 14px;margin-bottom:10px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:700;color:#92400e\\\">Client approval exists — branding locked</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:#78350f;margin-top:4px\\\"><span class=\\\"en-txt\\\">The client has reviewed this recce. Create a new recce to revise branding items.</span><span class=\\\"hi-txt\\\">क्लाइंट ने रेकी की समीक्षा की है। बदलाव के लिए नई रेकी बनाएं।</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"branding-override-wrap\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m        <button onclick=\\\"unlockBrandingOverride()\\\" style=\\\"background:#f59e0b;color:#000;border:none;border-radius:8px;padding:8px 14px;font-size:12px;font-weight:700;cursor:pointer\\\">Override Edit (H&amp;P only)</button>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:11px;color:#92400e;margin-top:5px\\\">Use only when client has verbally confirmed and app needs correction.</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"br-items\\\"></div>\u001b[39m\n\u001b[31m    <div id=\\\"br-add\\\" style=\\\"display:none;margin-bottom:80px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"addBranding()\\\" style=\\\"width:100%;justify-content:center\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Another Branding Item</span><span class=\\\"hi-txt\\\">एक और ब्रांडिंग जोड़ें</span></button>\u001b[39m\n\u001b[31m      <div style=\\\"text-align:center;font-size:12px;color:var(--g400);margin-top:8px\\\"><span class=\\\"en-txt\\\">Tap Continue below when done adding items</span><span class=\\\"hi-txt\\\">सभी आइटम जोड़ने के बाद आगे दबाएं</span></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-video')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step5()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: ADDITIONAL + SUBMIT -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-additional\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-branding')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Submit</span><span class=\\\"hi-txt\\\">सबमिट</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 5 of 5</span><span class=\\\"hi-txt\\\">चरण 5 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:100%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Mandatory Document</span><span class=\\\"hi-txt\\\">अनिवार्य दस्तावेज़</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"pslot\\\" id=\\\"doc-slot\\\" onclick=\\\"document.getElementById('doc-inp').click()\\\"><div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div></div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"doc-inp\\\" accept=\\\"image/*,.pdf\\\" onchange=\\\"handleDoc(event)\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Additional Photos</span><span class=\\\"hi-txt\\\">अतिरिक्त फोटो</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 8)</span><span class=\\\"cnt-badge gray\\\" id=\\\"addl-badge\\\">0 / 8</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"add-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-addl\\\" onclick=\\\"addAdditional()\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\"><div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Review</span><span class=\\\"hi-txt\\\">समीक्षा</span></div><div id=\\\"rev-body\\\"></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-branding')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"submitRecce()\\\" id=\\\"sub-btn\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Submit Recce ✓</span><span class=\\\"hi-txt\\\">रेकी सबमिट करें ✓</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- ANNOTATION MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"annot-modal\\\" id=\\\"annot-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"annot-bar\\\">\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Draw:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"at-rect\\\"    onclick=\\\"setATool('rect')\\\">▭ Rect</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-ellipse\\\" onclick=\\\"setATool('ellipse')\\\">◯ Ellipse</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-line\\\"    onclick=\\\"setATool('line')\\\">╱ Line</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-arrow\\\"   onclick=\\\"setATool('arrow')\\\">↗ Arrow</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-free\\\"    onclick=\\\"setATool('free')\\\">✏ Free</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool sel-on\\\" id=\\\"at-move\\\" onclick=\\\"setATool('move')\\\" style=\\\"margin-left:4px\\\">⊹ Move</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Color:</span>\u001b[39m\n\u001b[31m      <div class=\\\"acolor on\\\" id=\\\"ac-or\\\" style=\\\"background:#f97316\\\" onclick=\\\"setAColor('#f97316')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-rd\\\" style=\\\"background:#ef4444\\\" onclick=\\\"setAColor('#ef4444')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-wh\\\" style=\\\"background:#ffffff\\\" onclick=\\\"setAColor('#ffffff')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-yw\\\" style=\\\"background:#facc15\\\" onclick=\\\"setAColor('#facc15')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-gn\\\" style=\\\"background:#22c55e\\\" onclick=\\\"setAColor('#22c55e')\\\"></div>\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Width:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-2\\\" onclick=\\\"setAWidth(2)\\\" style=\\\"padding:5px 8px\\\">Thin</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"aw-4\\\" onclick=\\\"setAWidth(4)\\\" style=\\\"padding:5px 8px\\\">Med</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-7\\\" onclick=\\\"setAWidth(7)\\\" style=\\\"padding:5px 8px\\\">Thick</button>\u001b[39m\n\u001b[31m      <div style=\\\"flex:1\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"undoAnnot()\\\">↩</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"clearAnnot()\\\">✕</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"annot-sel-info\\\" style=\\\"display:none;font-size:11px;color:#facc15;padding:4px 0 2px\\\">\u001b[39m\n\u001b[31m      Shape selected — drag to move · drag corners to resize · tap elsewhere to deselect\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-cvs-wrap\\\"><canvas id=\\\"annot-cvs\\\"></canvas></div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-foot\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-s\\\" onclick=\\\"skipAnnot()\\\" style=\\\"flex:1;padding:12px;font-size:14px\\\"><span class=\\\"en-txt\\\">Skip markup</span><span class=\\\"hi-txt\\\">मार्कअप छोड़ें</span></button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" onclick=\\\"saveAnnot()\\\" style=\\\"flex:2;padding:12px\\\"><span class=\\\"en-txt\\\">Done — Save ✓</span><span class=\\\"hi-txt\\\">हो गया — सेव करें ✓</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EXIT DIALOG -->\u001b[39m\n\u001b[31m<!-- MODAL: Link Job to Recce (supervisor only) -->\u001b[39m\n\u001b[31m<div id=\\\"modal-link-job\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m  <div style=\\\"background:#fff;border-radius:14px;padding:20px;width:90%;max-width:380px;display:flex;flex-direction:column;gap:12px;box-shadow:0 8px 32px rgba(0,0,0,.35)\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:15px;font-weight:700;color:#1e293b\\\">&#x1F517; Link Job to Recce</div>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-store\\\" style=\\\"font-size:13px;color:#64748b\\\"></div>\u001b[39m\n\u001b[31m    <select id=\\\"link-job-sel\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m      <option value=\\\"\\\">&#x2014; Select campaign &#x2014;</option>\u001b[39m\n\u001b[31m    </select>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-err\\\" style=\\\"font-size:12px;color:#ef4444;min-height:14px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"closeLinkJobModal()\\\" style=\\\"flex:1;padding:12px;border:1px solid #cbd5e1;border-radius:8px;cursor:pointer;background:#f8fafc;font-size:14px\\\">Cancel</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"saveLinkJob()\\\" style=\\\"flex:2;padding:12px;background:#f59e0b;color:#000;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:700\\\">&#x1F517; Link Job</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"exit-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Exit Recce?</span><span class=\\\"hi-txt\\\">रेकी से बाहर?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Your progress and photos will be saved as a draft. Resume anytime from the home screen.</span><span class=\\\"hi-txt\\\">आपकी प्रगति और फोटो ड्राफ्ट में सेव होंगी। होम स्क्रीन से कभी भी जारी रखें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"exitSaveAndLeave()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">💾 Save Draft & Exit</span><span class=\\\"hi-txt\\\">💾 ड्राफ्ट सेव करें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-d\\\" onclick=\\\"exitDiscard()\\\" style=\\\"flex:1;padding:13px;font-size:13px\\\"><span class=\\\"en-txt\\\">Discard</span><span class=\\\"hi-txt\\\">हटाएं</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"exitCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">← Continue Recce</span><span class=\\\"hi-txt\\\">← रेकी जारी रखें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- PHOTO SOURCE PICKER -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"photo-src-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Camera photos get GPS stamp baked in. Gallery photos are added without stamp.</span><span class=\\\"hi-txt\\\">कैमरा फोटो में GPS स्टैम्प लगती है। गैलरी फोटो में नहीं।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"photoSrcCamera()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">📷 Use Camera</span><span class=\\\"hi-txt\\\">📷 कैमरा</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">GPS stamp applied</span><span class=\\\"hi-txt\\\">GPS स्टैम्प लगेगी</span></span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"photoSrcGallery()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">🖼 Choose from Gallery</span><span class=\\\"hi-txt\\\">🖼 गैलरी से चुनें</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">No stamp</span><span class=\\\"hi-txt\\\">स्टैम्प नहीं</span></span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"photoSrcCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- STORE PREVIEW DIALOG -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"store-preview-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:80vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"store-preview-title\\\"><span class=\\\"en-txt\\\">Preview Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची का प्रीव्यू</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Review before adding to your store list:</span><span class=\\\"hi-txt\\\">जोड़ने से पहले जाँचें:</span></div>\u001b[39m\n\u001b[31m    <div style=\\\"overflow-x:auto;margin-bottom:14px\\\">\u001b[39m\n\u001b[31m      <table style=\\\"width:100%;border-collapse:collapse;font-size:12px\\\">\u001b[39m\n\u001b[31m        <thead><tr style=\\\"background:var(--nv);color:#fff\\\">\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Address</span><span class=\\\"hi-txt\\\">पता</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Mobile</span><span class=\\\"hi-txt\\\">मोबाइल</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span></th>\u001b[39m\n\u001b[31m        </tr></thead>\u001b[39m\n\u001b[31m        <tbody id=\\\"store-preview-body\\\"></tbody>\u001b[39m\n\u001b[31m      </table>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"confirmStorePreview()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">✓ Confirm & Add Stores</span><span class=\\\"hi-txt\\\">✓ स्टोर जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"cancelStorePreview()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BOTTOM DIALOG (branding additional photo prompt) -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"bdialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add reference photos?</span><span class=\\\"hi-txt\\\">संदर्भ फोटो जोड़ें?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Add extra photos for this branding item for future reference.</span><span class=\\\"hi-txt\\\">इस ब्रांडिंग आइटम के लिए अतिरिक्त फोटो जोड़ें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"bdialogYes()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">Yes, add photos</span><span class=\\\"hi-txt\\\">हाँ, जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"bdialogNo()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Skip</span><span class=\\\"hi-txt\\\">छोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- DELETE REASON MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"delete-reason-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"padding-bottom:28px;max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">🗑 Delete Recce</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"del-modal-sub\\\">Select reason for deletion:</div>\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-wrong\\\" onclick=\\\"selectDeleteReason('wrong')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">❌</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Wrong</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Incorrect store / submission error</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-duplicate\\\" onclick=\\\"selectDeleteReason('duplicate')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">📋</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Duplicate</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Same store submitted more than once</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt danger\\\" id=\\\"reason-test\\\" onclick=\\\"selectDeleteReason('test')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">⚠️</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Test Recce</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:#9a3412;margin-top:2px\\\">Permanently deleted — no audit trail</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p no-reason\\\" id=\\\"del-confirm-btn\\\" onclick=\\\"confirmDelete()\\\" style=\\\"flex:2;padding:13px;background:var(--rd)\\\">Delete</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"closeDeleteModal()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EDIT REQUEST MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"edit-req-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Request Edit</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"er-store-name\\\" style=\\\"font-weight:600;color:var(--nv);margin-bottom:4px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:14px\\\">Add a note for the creator (optional)</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m      <textarea id=\\\"er-comment\\\" placeholder=\\\"e.g. Please re-check store address and re-upload front photo\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;color:var(--nv);resize:vertical;min-height:80px;background:#fff\\\"></textarea>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button id=\\\"er-assign-btn\\\" class=\\\"btn-p\\\" onclick=\\\"assignEditToCreator()\\\" style=\\\"padding:14px\\\">👤 Assign to Creator</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"supervisorEditMyself()\\\" style=\\\"padding:14px\\\">✏ Edit Myself</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"closeEditRequestModal()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BRAND EDIT MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"brand-edit-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Edit Brand</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Brand Name <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"text\\\" id=\\\"be-name\\\" placeholder=\\\"e.g. PHILIPS\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:600;text-transform:uppercase\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Logo URL <span style=\\\"font-size:11px;font-weight:400;color:var(--g400)\\\">(optional)</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"url\\\" id=\\\"be-logo\\\" placeholder=\\\"https://…/logo.svg\\\" oninput=\\\"previewBrandLogo()\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px\\\">\u001b[39m\n\u001b[31m      <div id=\\\"be-logo-preview\\\" style=\\\"margin-top:8px;min-height:36px;display:flex;align-items:center;gap:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"be-cascade-info\\\" style=\\\"display:none;font-size:12px;color:var(--g500);padding:8px 12px;background:var(--g50);border-radius:var(--rs);margin-bottom:12px\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"saveBrandEdit()\\\" style=\\\"padding:14px\\\">Save</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"closeBrandEditModal()\\\" style=\\\"width:100%;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FONT SIZE WIDGET -->\u001b[39m\n\u001b[31m<div class=\\\"fs-widget\\\" id=\\\"fs-widget\\\">\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-dec\\\" onclick=\\\"changeFontSize(-1)\\\" title=\\\"Decrease font size\\\" aria-label=\\\"Decrease font size\\\">A<sup style=\\\"font-size:9px\\\">−</sup></button>\u001b[39m\n\u001b[31m  <span class=\\\"fs-label\\\" id=\\\"fs-lbl\\\">A</span>\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-inc\\\" onclick=\\\"changeFontSize(1)\\\" title=\\\"Increase font size\\\" aria-label=\\\"Increase font size\\\"><strong>A</strong><sup style=\\\"font-size:9px\\\">+</sup></button>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"upd-banner\\\" id=\\\"upd-banner\\\">\u001b[39m\n\u001b[31m  <span style=\\\"font-size:13px;font-weight:600;line-height:1.4\\\"><span class=\\\"en-txt\\\">✓ App updated to latest version</span><span class=\\\"hi-txt\\\">✓ ऐप नया संस्करण अपडेट हुआ</span></span>\u001b[39m\n\u001b[31m  <button class=\\\"upd-banner-ok\\\" onclick=\\\"dismissUpdateBanner()\\\"><span class=\\\"en-txt\\\">OK</span><span class=\\\"hi-txt\\\">ठीक है</span></button>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m<div class=\\\"toast\\\" id=\\\"toast\\\"></div>\u001b[39m\n\u001b[31m<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js\\\"></script>\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m// LANGUAGE\u001b[39m\n\u001b[31mlet LANG = localStorage.getItem('recce-lang') || 'en';\u001b[39m\n\u001b[31mfunction setLang(l) {\u001b[39m\n\u001b[31m  LANG = l;\u001b[39m\n\u001b[31m  localStorage.setItem('recce-lang', l);\u001b[39m\n\u001b[31m  document.body.classList.toggle('lang-hi', l === 'hi');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction t(en, hi) { return LANG === 'hi' ? hi : en; }·\u001b[39m\n\u001b[31m// FONT SIZE\u001b[39m\n\u001b[31mlet FS_LEVEL = parseInt(localStorage.getItem('recce-fs') || '0', 10);\u001b[39m\n\u001b[31mconst FS_LABELS = ['A', 'A+', 'A++', 'A+++', 'A++++'];\u001b[39m\n\u001b[31mfunction applyFontSize() {\u001b[39m\n\u001b[31m  document.body.classList.remove('fs-0', 'fs-1', 'fs-2');\u001b[39m\n\u001b[31m  if (FS_LEVEL > 0) document.body.classList.add('fs-' + FS_LEVEL);\u001b[39m\n\u001b[31m  const lbl = document.getElementById('fs-lbl');\u001b[39m\n\u001b[31m  if (lbl) lbl.textContent = FS_LABELS[FS_LEVEL];\u001b[39m\n\u001b[31m  const dec = document.getElementById('fs-dec');\u001b[39m\n\u001b[31m  const inc = document.getElementById('fs-inc');\u001b[39m\n\u001b[31m  if (dec) dec.disabled = FS_LEVEL === 0;\u001b[39m\n\u001b[31m  if (inc) inc.disabled = FS_LEVEL === 4;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction changeFontSize(delta) {\u001b[39m\n\u001b[31m  FS_LEVEL = Math.min(4, Math.max(0, FS_LEVEL + delta));\u001b[39m\n\u001b[31m  localStorage.setItem('recce-fs', FS_LEVEL);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Hub auth gate\u001b[39m\n\u001b[31m(function() {\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (!s || !s.loginAt || Date.now() - new Date(s.loginAt).getTime() > 12 * 3600 * 1000) {\u001b[39m\n\u001b[31m      window.location.replace('/hub/');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) { window.location.replace('/hub/'); }\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31m// STATE\u001b[39m\n\u001b[31mlet F={},frontPhotos=[],insidePhotos=[],addlPhotos=[],brandings=[];\u001b[39m\n\u001b[31mlet videoBlob=null,submissionDoc=null,_docExistingUrl=null,gpsCoords=null;\u001b[39m\n\u001b[31mlet stores=[],selectedStore=null,manualMode=false,DB;\u001b[39m\n\u001b[31mlet imgQuality='compressed'; // 'compressed' | 'hd'\u001b[39m\n\u001b[31mlet geoStampEnabled=true;    // stamp GPS+timestamp on every photo\u001b[39m\n\u001b[31mlet brands=['PHILIPS']; // editable brand list\u001b[39m\n\u001b[31mlet _brandLogos={};   // name → logo_url, loaded from DB\u001b[39m\n\u001b[31mlet _selectedClient=''; // currently selected client chip value\u001b[39m\n\u001b[31mlet _clientOtherMode=false; // true when \\\"Other\\\" chip selected\u001b[39m\n\u001b[31mconst BTYPE=['Glow Sign Board','Inshop Branding','ACP Board','One Way Vision','Fabric Board','Lollypop','Non Lit Flex','Double Side GSB','Clip on Board','Translit','Vinyl Printing','Roll up Standee','Sunboard Standee'];\u001b[39m\n\u001b[31mconst CACHE_VER='recce-v37'; // campaign dropdown + pending job link tab·\u001b[39m\n\u001b[31m// DB\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',3);r.onupgradeneeded=e=>{const d=e.target.result;['subs','cfg','draft'].forEach(s=>{if(!d.objectStoreNames.contains(s))d.createObjectStore(s,{keyPath:'k'||'id'});});if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);});}\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',4);r.onupgradeneeded=e=>{const d=e.target.result;if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);})}\u001b[39m\n\u001b[31mfunction dbGet(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).get(k);r.onsuccess=()=>res(r.result);r.onerror=()=>res(null);}catch{res(null)}})}\u001b[39m\n\u001b[31mfunction dbPut(s,v){return new Promise((res,rej)=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).put(v);r.onsuccess=()=>res();r.onerror=()=>rej();}catch(e){rej(e)}})}\u001b[39m\n\u001b[31mfunction dbAll(s){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).getAll();r.onsuccess=()=>res(r.result);r.onerror=()=>res([]);}catch{res([])}})}\u001b[39m\n\u001b[31mfunction dbDel(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).delete(k);r.onsuccess=()=>res();r.onerror=()=>res();}catch{res()}})}\u001b[39m\n\u001b[31masync function cfg(k,v){if(v===undefined){const r=await dbGet('cfg',k);return r?r.v:null;}await dbPut('cfg',{k,v});}·\u001b[39m\n\u001b[31m// COMPRESS — respects imgQuality setting\u001b[39m\n\u001b[31mfunction compress(file, maxPxOverride, qOverride){\u001b[39m\n\u001b[31m  const maxPx = maxPxOverride || (imgQuality==='hd' ? 1920 : 1280);\u001b[39m\n\u001b[31m  const q     = qOverride     || (imgQuality==='hd' ? 0.90 : 0.78);\u001b[39m\n\u001b[31m  return new Promise(res=>{const img=new Image(),url=URL.createObjectURL(file);img.onload=()=>{const sc=Math.min(1,maxPx/Math.max(img.width,img.height));const c=document.createElement('canvas');c.width=Math.round(img.width*sc);c.height=Math.round(img.height*sc);c.getContext('2d').drawImage(img,0,0,c.width,c.height);URL.revokeObjectURL(url);c.toBlob(b=>res(b),'image/jpeg',q);};img.onerror=()=>{URL.revokeObjectURL(url);res(file)};img.src=url;});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction b64(blob){return new Promise(res=>{const r=new FileReader();r.onload=()=>res(r.result);r.readAsDataURL(blob)})}\u001b[39m\n\u001b[31mfunction fmtSz(b){if(b<1024)return b+'B';if(b<1048576)return(b/1024).toFixed(0)+'KB';return(b/1048576).toFixed(1)+'MB'}·\u001b[39m\n\u001b[31m// STORE LIST\u001b[39m\n\u001b[31mlet _storeFiles=[]; // track uploaded files {name, brand, count}\u001b[39m\n\u001b[31mlet _pendingParse=null; // parsed rows waiting for brand assignment·\u001b[39m\n\u001b[31mfunction parseStoreRow(row, keyFn){\u001b[39m\n\u001b[31m  const v=k=>{\u001b[39m\n\u001b[31m    // Try exact match first, then partial\u001b[39m\n\u001b[31m    const exactKey=Object.keys(row||{}).find(hk=>hk.toLowerCase()===k);\u001b[39m\n\u001b[31m    const partKey=Object.keys(row||{}).find(hk=>hk.toLowerCase().includes(k));\u001b[39m\n\u001b[31m    const useKey=exactKey||partKey;\u001b[39m\n\u001b[31m    if(useKey)return row[useKey]!=null?row[useKey].toString().trim():'';\u001b[39m\n\u001b[31m    // CSV path: keyFn provides value directly\u001b[39m\n\u001b[31m    const col=keyFn(k);return col!=null?col.toString().trim():'';\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const name    = v('sub dealer name')||v('sub dealer')||v('dealer name')||v('store name')||v('store')||v('name');\u001b[39m\n\u001b[31m  const address = v('address')||v('addr')||v('location')||v('area');\u001b[39m\n\u001b[31m  // Contact Detail often stored as a number — toString handles it\u001b[39m\n\u001b[31m  const rawMob  = v('contact detail')||v('contact no.')||v('contact no')||v('mobile no')||v('mobile')||v('phone')||v('mob')||v('contact');\u001b[39m\n\u001b[31m  const mobile  = rawMob.replace(/\\\\D/g,'').slice(-10);\u001b[39m\n\u001b[31m  // Brand: EXACT match only — \\\"Brand\\\" or \\\"Brand Name\\\" columns\u001b[39m\n\u001b[31m  // Partial match is intentionally avoided here because \\\"Inshop Branding\\\" contains \\\"brand\\\"\u001b[39m\n\u001b[31m  const brandKey=Object.keys(row||{}).find(hk=>{\u001b[39m\n\u001b[31m    const lk=hk.toLowerCase().trim();\u001b[39m\n\u001b[31m    return lk==='brand'||lk==='brand name'||lk==='brand_name'||lk==='brandname';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const brand=brandKey?(row[brandKey]||'').toString().trim().toUpperCase():'';\u001b[39m\n\u001b[31m  const distName= v('dist name')||v('distributor name')||v('distributor')||v('dist')||v('territory')||v('tsm')||v('asm');\u001b[39m\n\u001b[31m  const city    = v('city')||v('district')||v('town');\u001b[39m\n\u001b[31m  const sales   = v('2025 full year')||v('2025')||v('full year sales')||v('fy25')||v('sales');\u001b[39m\n\u001b[31m  const proj    = v('2026 projection')||v('2026')||v('projection')||v('fy26')||v('target');\u001b[39m\n\u001b[31m  const glowSign= v('glow sign')||v('glow');\u001b[39m\n\u001b[31m  const inshop  = v('inshop branding')||v('inshop')||v('in-shop')||v('in shop');\u001b[39m\n\u001b[31m  return {name, brand, address, mobile, distName, city, sales, proj, glowSign, inshop};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction dedupeStores(list){\u001b[39m\n\u001b[31m  const seen=new Map();\u001b[39m\n\u001b[31m  list.forEach(s=>{\u001b[39m\n\u001b[31m    // Include address in key — same store name at different locations = different stores\u001b[39m\n\u001b[31m    const key=(s.name.toLowerCase().trim())+'__'+(s.brand||'').toLowerCase()\u001b[39m\n\u001b[31m              +'__'+(s.address||'').toLowerCase().trim().slice(0,30);\u001b[39m\n\u001b[31m    if(!seen.has(key))seen.set(key,s);\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // True duplicate — merge missing fields from second record\u001b[39m\n\u001b[31m      const ex=seen.get(key);\u001b[39m\n\u001b[31m      Object.keys(s).forEach(k=>{ if(!ex[k]&&s[k])ex[k]=s[k]; });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  return Array.from(seen.values());\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderStoreFileList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-file-list');if(!el)return;\u001b[39m\n\u001b[31m  if(!_storeFiles.length){el.innerHTML='';return;}\u001b[39m\n\u001b[31m  el.innerHTML=_storeFiles.map((f,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:5px;font-size:12px\\\">\u001b[39m\n\u001b[31m      <div>\u001b[39m\n\u001b[31m        <span style=\\\"font-weight:600;color:var(--nv)\\\">${f.name}</span>\u001b[39m\n\u001b[31m        <span style=\\\"color:var(--g500);margin-left:6px\\\">${f.count} stores</span>\u001b[39m\n\u001b[31m        ${f.brand?`<span style=\\\"background:var(--nv);color:#fff;font-size:10px;font-weight:700;padding:1px 7px;border-radius:20px;margin-left:5px\\\">${f.brand}</span>`:'<span style=\\\"background:var(--g300);color:var(--g600);font-size:10px;padding:1px 7px;border-radius:20px;margin-left:5px\\\">Mixed brands</span>'}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <button onclick=\\\"removeStoreFile(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:17px;cursor:pointer;padding:0 4px;line-height:1\\\">×</button>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function removeStoreFile(i){\u001b[39m\n\u001b[31m  _storeFiles.splice(i,1);\u001b[39m\n\u001b[31m  // Rebuild stores from remaining files — re-parse from cache not possible, so just reload from DB and remove this file's contribution\u001b[39m\n\u001b[31m  // Simplest approach: clear and ask user to re-upload remaining files\u001b[39m\n\u001b[31m  if(!_storeFiles.length){stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    // Can't re-parse without original files; just note it and keep current store list\u001b[39m\n\u001b[31m    toast('Removed from list. Re-upload the remaining files to refresh store list.','info');\u001b[39m\n\u001b[31m    _storeFiles.splice(0); // clear tracking since we can't reconstruct\u001b[39m\n\u001b[31m    stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderStoreFileList();\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=stores.length?`✓ ${stores.length} stores`:'No stores loaded';\u001b[39m\n\u001b[31m  updAvailTag();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function clearStoreList(){\u001b[39m\n\u001b[31m  if(!confirm('Remove all loaded stores?'))return;\u001b[39m\n\u001b[31m  stores=[];_storeFiles=[];\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent='';\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast('Store list cleared','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function handleStoreUpload(e){\u001b[39m\n\u001b[31m  const file=e.target.files[0];if(!file)return;\u001b[39m\n\u001b[31m  e.target.value=''; // allow same file re-upload\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    let data=[];\u001b[39m\n\u001b[31m    if(file.name.toLowerCase().endsWith('.csv')){\u001b[39m\n\u001b[31m      const txt=await file.text();\u001b[39m\n\u001b[31m      const rows=txt.split('\\\\n').map(r=>r.split(',').map(c=>c.trim().replace(/^\\\"|\\\"$/g,'')));\u001b[39m\n\u001b[31m      if(!rows.length||!rows[0].length){toast('Empty CSV','error');return;}\u001b[39m\n\u001b[31m      const h=rows[0];\u001b[39m\n\u001b[31m      data=rows.slice(1).filter(r=>r.length>1&&r.some(c=>c)).map(r=>{\u001b[39m\n\u001b[31m        const rowObj={};h.forEach((hk,i)=>{rowObj[hk]=r[i]||'';});\u001b[39m\n\u001b[31m        return parseStoreRow(rowObj, ()=>'');\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }else{\u001b[39m\n\u001b[31m      const ab=await file.arrayBuffer();const wb=XLSX.read(ab,{type:'array'});\u001b[39m\n\u001b[31m      const js=XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]],{defval:''});\u001b[39m\n\u001b[31m      data=js.map(row=>parseStoreRow(row,()=>''));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    data=data.filter(d=>d.name.trim());\u001b[39m\n\u001b[31m    if(!data.length){toast('No valid rows found in file','error');return;}\u001b[39m\n\u001b[31m    // Check if any store has a brand\u001b[39m\n\u001b[31m    const hasBrand=data.some(d=>d.brand);\u001b[39m\n\u001b[31m    // Always show preview first before merging\u001b[39m\n\u001b[31m    _pendingParse={file:file.name,data,hasBrand};\u001b[39m\n\u001b[31m    showStorePreview(file.name, data, hasBrand);\u001b[39m\n\u001b[31m  }catch(err){toast('Failed: '+err.message,'error')}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mlet _pendingBrand='';\u001b[39m\n\u001b[31mfunction setPendingBrand(b){\u001b[39m\n\u001b[31m  _pendingBrand=b;\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-assign-chips .chip').forEach(c=>{\u001b[39m\n\u001b[31m    c.classList.toggle('sel',c.textContent===b);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  if(!_pendingBrand){toast('Select a brand first','error');return;}\u001b[39m\n\u001b[31m  // Assign brand to all rows in this file\u001b[39m\n\u001b[31m  const data=_pendingParse.data.map(s=>({...s,brand:_pendingBrand}));\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, data, _pendingBrand);\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function skipBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, _pendingParse.data, '');\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showStorePreview(filename, data, hasBrand){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-preview-dialog');\u001b[39m\n\u001b[31m  const tbody=document.getElementById('store-preview-body');\u001b[39m\n\u001b[31m  document.getElementById('store-preview-title').textContent=`${filename} · ${data.length} ${t('stores found','स्टोर मिले')}`;\u001b[39m\n\u001b[31m  // Show first 8 rows\u001b[39m\n\u001b[31m  const sample=data.slice(0,8);\u001b[39m\n\u001b[31m  tbody.innerHTML=sample.map(s=>`<tr>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;font-weight:500\\\">${s.name||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.address||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.mobile||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px\\\"><span style=\\\"background:${s.brand?'var(--nv)':'var(--rd)'};color:#fff;padding:1px 7px;border-radius:10px;font-size:10px\\\">${s.brand||'?'}</span></td>\u001b[39m\n\u001b[31m  </tr>`).join('');\u001b[39m\n\u001b[31m  if(data.length>8)tbody.innerHTML+=`<tr><td colspan=\\\"4\\\" style=\\\"text-align:center;padding:8px;font-size:12px;color:var(--g400)\\\">…and ${data.length-8} more stores</td></tr>`;\u001b[39m\n\u001b[31m  el.classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function confirmStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  const {file,data,hasBrand}=_pendingParse;\u001b[39m\n\u001b[31m  if(!hasBrand){\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-fname').textContent=`File: ${file} · ${data.length} stores found · No brand column detected`;\u001b[39m\n\u001b[31m    const chips=document.getElementById('brand-assign-chips');\u001b[39m\n\u001b[31m    chips.innerHTML=brands.map(b=>`<div class=\\\"chip\\\" onclick=\\\"setPendingBrand('${b}')\\\" id=\\\"bac-${b}\\\">${b}</div>`).join('');\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').style.display='block';\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    await mergeStores(file, data, '');\u001b[39m\n\u001b[31m    _pendingParse=null;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction cancelStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingParse=null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function mergeStores(filename, newData, assignedBrand){\u001b[39m\n\u001b[31m  const before=stores.length;\u001b[39m\n\u001b[31m  stores=[...stores,...newData];\u001b[39m\n\u001b[31m  stores=dedupeStores(stores);\u001b[39m\n\u001b[31m  const added=stores.length-before;\u001b[39m\n\u001b[31m  const dupes=newData.length-added;\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify(stores));\u001b[39m\n\u001b[31m  // Track file\u001b[39m\n\u001b[31m  _storeFiles.push({name:filename,count:newData.length,brand:assignedBrand||''});\u001b[39m\n\u001b[31m  await cfg('store-files',JSON.stringify(_storeFiles));\u001b[39m\n\u001b[31m  const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m    `✓ ${stores.length} total stores${dupes>0?` · ${dupes} duplicate${dupes>1?'s':''} removed`:''}${noBrand?` · ${noBrand} without brand`:' · All have brand'}`;\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast(`${added} stores added${dupes>0?`, ${dupes} duplicates skipped`:''}${assignedBrand?' as '+assignedBrand:''}`, 'success');\u001b[39m\n\u001b[31m  // Show server-push button for supervisors\u001b[39m\n\u001b[31m  const pb = document.getElementById('store-push-btn');\u001b[39m\n\u001b[31m  if (pb) pb.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function fetchServerStores(){const url=document.getElementById('srv-url').value.trim();if(!url){toast('Enter a URL first','error');return;}try{toast('Fetching…','info');const r=await fetch(url);const j=await r.json();const fetched=Array.isArray(j)?j:j.stores||[];await mergeStores('Server ('+url.split('/').pop()+')',fetched,'');await cfg('srv-url',url);}catch{toast('Fetch failed — check URL','error')}}\u001b[39m\n\u001b[31masync function saveServerUrl(){await cfg('srv-url',document.getElementById('srv-url').value.trim());toast('URL saved','success')}\u001b[39m\n\u001b[31mconst DEFAULT_GAS_URL='https://script.google.com/macros/s/AKfycbwyufC7gQyu1BErCxiDlbQUn0AWiIWv7nEmjk4UcAx3dvlV6bGk7q5fQOiv82CTbokbkA/exec';·\u001b[39m\n\u001b[31mconst DEFAULT_STORES_URL='/recce/stores.json';\u001b[39m\n\u001b[31mconst _RECCE_CFG_URL='/recce/recce-cfg.json';·\u001b[39m\n\u001b[31m// Admin auto-unlock for harish/pramod via hub session\u001b[39m\n\u001b[31mconst _RECCE_ADMIN_IDS = ['harish', 'pramod', 'rakesh'];\u001b[39m\n\u001b[31mconst _RECCE_CFG_ADMINS = ['harish', 'pramod'];\u001b[39m\n\u001b[31mlet _adminRows = [];\u001b[39m\n\u001b[31mlet _myServerRows = [];\u001b[39m\n\u001b[31mlet _adminUnlocked = false;\u001b[39m\n\u001b[31mlet _recceCfg = { version: 1, supervisors: ['harish','pramod','rakesh'], mode: 'public', creators: [], allowed_users: [] };\u001b[39m\n\u001b[31mfunction _isSupervisor() {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  return !!(hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId));\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _showDeletedView = false;\u001b[39m\n\u001b[31mlet _supCreateMode = false;\u001b[39m\n\u001b[31mlet _pendingDeleteId = null;\u001b[39m\n\u001b[31mlet _pendingDeleteReason = null;\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (s?.empId && _RECCE_ADMIN_IDS.includes(s.empId)) _adminUnlocked = true;\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31masync function loadRecceCfg(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(_RECCE_CFG_URL + '?t=' + Date.now());\u001b[39m\n\u001b[31m    if (r.ok) {\u001b[39m\n\u001b[31m      const j = await r.json();\u001b[39m\n\u001b[31m      if (j && j.version) {\u001b[39m\n\u001b[31m        _recceCfg = j;\u001b[39m\n\u001b[31m        if (Array.isArray(j.supervisors) && j.supervisors.length) {\u001b[39m\n\u001b[31m          _recceCfg.supervisors = j.supervisors;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.creators)) _recceCfg.creators = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.allowed_users)) _recceCfg.allowed_users = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.clients)) _recceCfg.clients = [];\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  // Re-check admin status against server supervisor list\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId)) {\u001b[39m\n\u001b[31m    _adminUnlocked = true;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _checkAccessMode(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (_recceCfg.mode !== 'assigned') return;\u001b[39m\n\u001b[31m  const allowed = [\u001b[39m\n\u001b[31m    ...(_recceCfg.supervisors || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.creators || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.allowed_users || []),\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  if (hub?.empId && allowed.includes(hub.empId)) return;\u001b[39m\n\u001b[31m  // Block access — show locked overlay\u001b[39m\n\u001b[31m  document.body.innerHTML = `<div style=\\\"min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0f172a;color:#fff;padding:32px;text-align:center\\\"><div style=\\\"font-size:48px;margin-bottom:16px\\\">🔒</div><div style=\\\"font-size:20px;font-weight:700;margin-bottom:8px\\\">${t('Access Restricted','एक्सेस प्रतिबंधित')}</div><div style=\\\"font-size:14px;color:#94a3b8\\\">${t('You are not authorised to use Branding Recce. Please contact your supervisor.','आप ब्रांडिंग रेक्की उपयोग के लिए अधिकृत नहीं हैं।')}</div></div>`;\u001b[39m\n\u001b[31m  throw new Error('access-restricted');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _recceHubUser() {\u001b[39m\n\u001b[31m  try { return JSON.parse(localStorage.getItem('lm360-session') || '{}'); }\u001b[39m\n\u001b[31m  catch(_) { return {}; }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── Supervisor config management ────────────────────────────────────\u001b[39m\n\u001b[31mfunction renderSupPanel(){\u001b[39m\n\u001b[31m  if (!_adminUnlocked) return;\u001b[39m\n\u001b[31m  const panel = document.getElementById('sup-panel');\u001b[39m\n\u001b[31m  if (panel) panel.style.display = 'block';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const modePublic = document.getElementById('mode-public');\u001b[39m\n\u001b[31m  const modeAssigned = document.getElementById('mode-assigned');\u001b[39m\n\u001b[31m  if (modePublic && modeAssigned) {\u001b[39m\n\u001b[31m    modePublic.classList.toggle('sel', _recceCfg.mode !== 'assigned');\u001b[39m\n\u001b[31m    modeAssigned.classList.toggle('sel', _recceCfg.mode === 'assigned');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  const addRow = document.getElementById('sup-add-row');\u001b[39m\n\u001b[31m  if (addRow) addRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const creatorAddRow = document.getElementById('creator-add-row');\u001b[39m\n\u001b[31m  if (creatorAddRow) creatorAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const clientAddRow = document.getElementById('client-add-row');\u001b[39m\n\u001b[31m  if (clientAddRow) clientAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const modeRow = document.getElementById('mode-row');\u001b[39m\n\u001b[31m  if (modeRow) {\u001b[39m\n\u001b[31m    modeRow.style.display = 'block';\u001b[39m\n\u001b[31m    // Non-cfg-admins see mode as read-only (toggles exist but setRecceMode guards them)\u001b[39m\n\u001b[31m    modeRow.style.opacity = isCfgAdmin ? '1' : '0.65';\u001b[39m\n\u001b[31m    modeRow.style.pointerEvents = isCfgAdmin ? '' : 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const syncBtn = document.getElementById('cfg-sync-btn');\u001b[39m\n\u001b[31m  if (syncBtn) syncBtn.style.display = isCfgAdmin ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('sup-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const sups = _recceCfg.supervisors || [];\u001b[39m\n\u001b[31m  el.innerHTML = sups.map((s,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${s}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin && sups.length > 1 ? `<button onclick=\\\"removeSupervisor(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderCreatorsList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('creator-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const creators = _recceCfg.creators || [];\u001b[39m\n\u001b[31m  el.innerHTML = creators.length ? creators.map((u,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${u}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeCreator(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No creators yet — any Hub user can submit in Public mode.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setRecceMode(mode){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.mode = mode;\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addSupervisor(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('sup-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.supervisors = [...(_recceCfg.supervisors || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeSupervisor(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.supervisors = (_recceCfg.supervisors || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addCreator(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('creator-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.creators || []).includes(val)) { toast(t('Already a creator','पहले से क्रिएटर है'), 'info'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor (includes creation rights)','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.creators = [...(_recceCfg.creators || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeCreator(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.creators = (_recceCfg.creators || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderClientMgmtList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('client-mgmt-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const list = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  el.innerHTML = list.length ? list.map((c,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${esc(c)}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeClientFromList(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No clients yet — add client or agency names to show them as chips in the form.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addClientToList(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('client-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter client name','क्लाइंट नाम दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.clients || []).includes(val)) { toast(t('Already in list','पहले से मौजूद है'), 'info'); return; }\u001b[39m\n\u001b[31m  if (!_recceCfg.clients) _recceCfg.clients = [];\u001b[39m\n\u001b[31m  _recceCfg.clients.push(val);\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeClientFromList(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.clients = (_recceCfg.clients || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncCfgToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast(t('Not authorised','अधिकृत नहीं'), 'error'); return; }\u001b[39m\n\u001b[31m  const st = document.getElementById('cfg-sync-status');\u001b[39m\n\u001b[31m  if (st) st.textContent = t('Syncing…','सिंक हो रहा है…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-cfg', empId: hub.empId, cfg: {\u001b[39m\n\u001b[31m        version: _recceCfg.version || 1,\u001b[39m\n\u001b[31m        supervisors: _recceCfg.supervisors || [],\u001b[39m\n\u001b[31m        mode: _recceCfg.mode || 'public',\u001b[39m\n\u001b[31m        creators: _recceCfg.creators || [],\u001b[39m\n\u001b[31m        allowed_users: _recceCfg.allowed_users || [],\u001b[39m\n\u001b[31m        clients: _recceCfg.clients || [],\u001b[39m\n\u001b[31m      }})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) {\u001b[39m\n\u001b[31m      toast(t('Config synced to server ✓','कॉन्फ़िग सर्वर पर सेव हुआ ✓'), 'success');\u001b[39m\n\u001b[31m      if (st) st.textContent = t('Last synced: just now','अभी सिंक हुआ');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast(j.error || t('Sync failed','सिंक विफल'), 'error');\u001b[39m\n\u001b[31m      if (st) st.textContent = j.error || '';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Network error','नेटवर्क त्रुटि'), 'error');\u001b[39m\n\u001b[31m    if (st) st.textContent = e.message;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function pushStoresToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!hub?.empId || !_adminUnlocked) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-stores', empId: hub.empId, stores })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) toast(`${t('Pushed to server','सर्वर पर पुश हुआ')} · ${j.count} ${t('stores','स्टोर')}`, 'success');\u001b[39m\n\u001b[31m    else toast(j.error || t('Server push failed','सर्वर पुश विफल'), 'error');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Could not reach server','सर्वर से संपर्क नहीं हो सका'), 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── End supervisor config management ────────────────────────────────·\u001b[39m\n\u001b[31m// PostgREST sync constants\u001b[39m\n\u001b[31mconst _RC_BASE      = '/db';\u001b[39m\n\u001b[31mconst _RC_READ      = { 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_WRITE     = { 'Content-Type': 'application/json', 'Content-Profile': 'recce', 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_UPSERT    = { ..._RC_WRITE, 'Prefer': 'resolution=merge-duplicates,return=minimal' };\u001b[39m\n\u001b[31mconst _INSTALL_RD   = { 'Content-Type': 'application/json', 'Accept-Profile': 'installation' };\u001b[39m\n\u001b[31mconst _INSTALL_WR   = { 'Content-Type': 'application/json', 'Content-Profile': 'installation', 'Accept-Profile': 'installation', 'Prefer': 'return=minimal' };·\u001b[39m\n\u001b[31m// ── Campaign selection state ──\u001b[39m\n\u001b[31mlet _selectedCampaignId = null;\u001b[39m\n\u001b[31mlet _notifySupervisor   = false;\u001b[39m\n\u001b[31mlet _campaignList       = [];\u001b[39m\n\u001b[31mlet _pendingJobFilter   = false;\u001b[39m\n\u001b[31mlet _linkJobSubId       = null;\u001b[39m\n\u001b[31mlet _brandingLocked     = false;·\u001b[39m\n\u001b[31mfunction _updateBrandingLock() {\u001b[39m\n\u001b[31m  const hub  = _recceHubUser();\u001b[39m\n\u001b[31m  const isHP = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const banner   = document.getElementById('branding-lock-banner');\u001b[39m\n\u001b[31m  const ovWrap   = document.getElementById('branding-override-wrap');\u001b[39m\n\u001b[31m  const brItems  = document.getElementById('br-items');\u001b[39m\n\u001b[31m  const brAdd    = document.getElementById('br-add');\u001b[39m\n\u001b[31m  const brYes    = document.getElementById('br-yes');\u001b[39m\n\u001b[31m  const brNo     = document.getElementById('br-no');\u001b[39m\n\u001b[31m  if (!banner) return;\u001b[39m\n\u001b[31m  if (_brandingLocked) {\u001b[39m\n\u001b[31m    banner.style.display   = '';\u001b[39m\n\u001b[31m    if (ovWrap)  ovWrap.style.display  = isHP ? '' : 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.pointerEvents = 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.opacity = '0.55';\u001b[39m\n\u001b[31m    if (brAdd)   brAdd.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='none'; brYes.style.opacity='0.5'; }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='none';  brNo.style.opacity='0.5';  }\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    banner.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brItems) { brItems.style.pointerEvents=''; brItems.style.opacity=''; }\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='';  brYes.style.opacity='';   }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='';   brNo.style.opacity='';    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction unlockBrandingOverride() {\u001b[39m\n\u001b[31m  if (!confirm(\u001b[39m\n\u001b[31m    'Client has already reviewed this recce.\\\\n' +\u001b[39m\n\u001b[31m    'Editing brandings will NOT remove their approval.\\\\n' +\u001b[39m\n\u001b[31m    'Continue ONLY if the client has verbally confirmed. Proceed?'\u001b[39m\n\u001b[31m  )) return;\u001b[39m\n\u001b[31m  _brandingLocked = false;\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  renderBrandings();\u001b[39m\n\u001b[31m  toast(t('Branding unlocked for this session', 'ब्रांडिंग इस सत्र के लिए अनलॉक'), 'info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadCampaignsForForm() {\u001b[39m\n\u001b[31m  const sel = document.getElementById('f-campaign-id');\u001b[39m\n\u001b[31m  if (!sel) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m    _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m  } catch(_) { _campaignList = []; }\u001b[39m\n\u001b[31m  sel.innerHTML =\u001b[39m\n\u001b[31m    '<option value=\\\"\\\">— Select job / campaign (optional) —</option>' +\u001b[39m\n\u001b[31m    _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('') +\u001b[39m\n\u001b[31m    '<option value=\\\"__NOTIFY__\\\">⚑ No campaign yet — notify supervisor</option>';\u001b[39m\n\u001b[31m  if (_selectedCampaignId) sel.value = _selectedCampaignId;\u001b[39m\n\u001b[31m  else if (_notifySupervisor) sel.value = '__NOTIFY__';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onCampaignSelect() {\u001b[39m\n\u001b[31m  const val = document.getElementById('f-campaign-id')?.value || '';\u001b[39m\n\u001b[31m  const noticeEl = document.getElementById('campaign-notify-msg');\u001b[39m\n\u001b[31m  if (val === '__NOTIFY__') {\u001b[39m\n\u001b[31m    _selectedCampaignId = null;\u001b[39m\n\u001b[31m    _notifySupervisor   = true;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'block';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    _selectedCampaignId = val || null;\u001b[39m\n\u001b[31m    _notifySupervisor   = false;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction generateRecceReportHtml(entry, photoUrls) {\u001b[39m\n\u001b[31m  const d    = entry.data || {};\u001b[39m\n\u001b[31m  const urls = photoUrls || {};\u001b[39m\n\u001b[31m  const agent = entry.submittedByName || entry.submittedBy || 'Field Agent';\u001b[39m\n\u001b[31m  const _safeId      = (entry.id||'').replace(/\\\\//g,'_').replace(/\\\\.\\\\./g,'');\u001b[39m\n\u001b[31m  const serverPdfUrl = _safeId ? `https://srv1111289.hstgr.cloud/screenshots/recce/views/${_safeId}.pdf` : '';\u001b[39m\n\u001b[31m  const brandLogoUrl = d.brandLogoUrl || _brandLogos[d.brand] || '';\u001b[39m\n\u001b[31m  const tsStr = new Date(entry.timestamp).toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric',hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\u001b[39m\n\u001b[31m  const gpsUrl = d.gpsCoords ? `https://maps.google.com/?q=${d.gpsCoords.lat},${d.gpsCoords.lng}` : null;·\u001b[39m\n\u001b[31m  const frontCount  = (urls.front||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const insideCount = (urls.inside||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const addlCount   = (urls.addl||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const brCount     = (d.brandings||[]).length;·\u001b[39m\n\u001b[31m  // pages: { id, url, bandHtml, cmt, dotLabel, dotColor }\u001b[39m\n\u001b[31m  const pages = [];·\u001b[39m\n\u001b[31m  (urls.front||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Front View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${frontCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.frontPhotos||[])[i]?.cmt||'', dotLabel:`FV${i+1}`, dotColor:'#3b82f6', catLabel:'Front View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.inside||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Inside View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${insideCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.insidePhotos||[])[i]?.cmt||'', dotLabel:`IV${i+1}`, dotColor:'#14b8a6', catLabel:'Inside View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (d.brandings||[]).forEach((b,i)=>{\u001b[39m\n\u001b[31m    const url=(urls.brandings||[])[i]; if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">${esc(b.type||'Branding')}</div><div class=\\\"ph-dims\\\">Width : ${esc(b.w||'?')}&Prime;&nbsp;&times;&nbsp;Height : ${esc(b.h||'?')}&Prime;&nbsp;&mdash;&nbsp;${esc(b.qty||1)} Nos</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${brCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:'', dotLabel:`B${i+1}`, dotColor:'#f97316', catLabel:b.type||'Branding',\u001b[39m\n\u001b[31m      tileDims:`${b.w||'?'}″×${b.h||'?'}″ — ${String(b.qty||1).padStart(2,'0')} Nos` });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.addl||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Additional</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${addlCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.addlPhotos||[])[i]?.desc||'', dotLabel:`A${i+1}`, dotColor:'#94a3b8', catLabel:'Additional', tileDims:'' });\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const sideItems = [\u001b[39m\n\u001b[31m    `<div class=\\\"si-item active\\\" data-tgt=\\\"pg-cover\\\" title=\\\"Cover\\\"><div class=\\\"si-dot\\\" style=\\\"background:#475569\\\">CV</div></div>`\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  pages.forEach(p => {\u001b[39m\n\u001b[31m    sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"${p.id}\\\" title=\\\"${p.dotLabel}\\\"><div class=\\\"si-dot\\\" style=\\\"background:${p.dotColor}\\\">${p.dotLabel}</div></div>`);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(d.hasVideo) sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-vid\\\" title=\\\"Video\\\"><div class=\\\"si-dot\\\" style=\\\"background:#a855f7\\\">VD</div></div>`);\u001b[39m\n\u001b[31m  if(urls.doc)   sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-doc\\\" title=\\\"Document\\\"><div class=\\\"si-dot\\\" style=\\\"background:#64748b\\\">DC</div></div>`);·\u001b[39m\n\u001b[31m  const thumbItems = [\u001b[39m\n\u001b[31m    ...pages,\u001b[39m\n\u001b[31m    ...(d.hasVideo?[{id:'pg-vid',url:null,catLabel:'Video',tileDims:'',dotLabel:'VD',dotColor:'#a855f7'}]:[]),\u001b[39m\n\u001b[31m    ...(urls.doc?[{id:'pg-doc',url:urls.doc,catLabel:'Document',tileDims:'',dotLabel:'DC',dotColor:'#64748b'}]:[])\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  const thumbsHtml = thumbItems.map(p=>`<div class=\\\"cov-thumb\\\" onclick=\\\"document.getElementById('${p.id}').scrollIntoView({behavior:'smooth'})\\\">${p.url?`<img src=\\\"${p.url}\\\" alt=\\\"\\\">`:(`<div class=\\\"cov-thumb-vid\\\">${p.catLabel==='Video'?'&#x25B6;&#xFE0F;':'&#x1F4C4;'}</div>`)}<div class=\\\"cov-thumb-ov\\\" style=\\\"border-top:3px solid ${p.dotColor}\\\"><div class=\\\"cov-thumb-cat\\\">${esc(p.catLabel)}</div>${p.tileDims?`<div class=\\\"cov-thumb-dims\\\">${esc(p.tileDims)}</div>`:''}<div class=\\\"cov-thumb-no\\\">${p.dotLabel}</div></div></div>`).join('');·\u001b[39m\n\u001b[31m  const pagesHtml = pages.map(p => `\u001b[39m\n\u001b[31m<div class=\\\"photo-page\\\" id=\\\"${p.id}\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\">${p.bandHtml}</div>\u001b[39m\n\u001b[31m  <div class=\\\"ph-img\\\"><a href=\\\"${p.url}\\\" target=\\\"_blank\\\"><img src=\\\"${p.url}\\\" loading=\\\"lazy\\\" alt=\\\"\\\"></a>${p.cmt?`<div class=\\\"ph-cmt\\\">${esc(p.cmt)}</div>`:''}</div>\u001b[39m\n\u001b[31m</div>`).join('');·\u001b[39m\n\u001b[31m  return `<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\"><head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m<title>Recce — ${esc(d.storeName||'Unknown')} · ${esc(d.brand||'')}</title>\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--dk:#0f172a;--nv2:#1a2f52;--or:#f97316;--g200:#e2e8f0;--g400:#94a3b8;--g600:#475569;--si:54px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0}\u001b[39m\n\u001b[31mhtml,body{height:100%;overflow:hidden}\u001b[39m\n\u001b[31mbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#111;color:var(--dk);display:flex}\u001b[39m\n\u001b[31ma{color:var(--or);text-decoration:none}\u001b[39m\n\u001b[31mimg{display:block}·\u001b[39m\n\u001b[31m/* ── Side index ── */\u001b[39m\n\u001b[31m.side-idx{width:var(--si);flex-shrink:0;background:var(--dk);overflow-y:auto;display:flex;flex-direction:column;align-items:center;padding:4px 0;scrollbar-width:none;z-index:50}\u001b[39m\n\u001b[31m.side-idx::-webkit-scrollbar{display:none}\u001b[39m\n\u001b[31m.si-item{width:100%;min-height:56px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s}\u001b[39m\n\u001b[31m.si-item:hover{background:rgba(255,255,255,.07)}\u001b[39m\n\u001b[31m.si-dot{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff;opacity:.4;transition:opacity .18s,transform .18s;line-height:1;text-align:center}\u001b[39m\n\u001b[31m.si-item.active .si-dot{opacity:1;transform:scale(1.15)}·\u001b[39m\n\u001b[31m/* ── Main scroll area ── */\u001b[39m\n\u001b[31m.main{flex:1;overflow-y:scroll;scroll-snap-type:y mandatory;scroll-behavior:smooth;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar{width:3px}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15)}·\u001b[39m\n\u001b[31m/* ── Cover ── */\u001b[39m\n\u001b[31m.cover{height:100vh;scroll-snap-align:start;flex-shrink:0;background:linear-gradient(135deg,#0f172a 0%,var(--nv2) 100%);color:#fff;display:flex;flex-direction:column;padding:24px 20px 20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.cover-badge{display:inline-flex;align-items:center;gap:5px;background:var(--or);color:#fff;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:1px;padding:3px 12px;border-radius:20px;margin-bottom:12px;align-self:flex-start}\u001b[39m\n\u001b[31m.cover h1{font-size:20px;font-weight:700;line-height:1.3;margin-bottom:4px}\u001b[39m\n\u001b[31m.cover-addr{color:rgba(255,255,255,.55);font-size:12px;margin-bottom:16px}\u001b[39m\n\u001b[31m.cg{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}\u001b[39m\n\u001b[31m.cm{background:rgba(255,255,255,.08);border-radius:8px;padding:8px 12px}\u001b[39m\n\u001b[31m.cm-l{font-size:9px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}\u001b[39m\n\u001b[31m.cm-v{font-size:13px;font-weight:600;color:#fff}\u001b[39m\n\u001b[31m.cm-v a{color:#fb923c}\u001b[39m\n\u001b[31m.cover-pbar{padding-top:8px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{background:var(--or);color:#fff;border:none;padding:10px 22px;border-radius:22px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}\u001b[39m\n\u001b[31m.btn-p:disabled{opacity:.4;cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-c{background:rgba(255,255,255,.1);color:rgba(255,255,255,.75);border:1px solid rgba(255,255,255,.2);padding:10px 18px;border-radius:22px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit}·\u001b[39m\n\u001b[31m/* ── Cover thumbnail grid ── */\u001b[39m\n\u001b[31m.cov-grid-hdr{font-size:10px;font-weight:700;color:rgba(255,255,255,.35);text-transform:uppercase;letter-spacing:1.2px;padding:10px 0 5px;flex-shrink:0}\u001b[39m\n\u001b[31m.cov-grid{flex:1;min-height:0;display:grid;gap:5px;overflow:hidden;align-content:start}\u001b[39m\n\u001b[31m.cov-thumb{position:relative;overflow:hidden;border-radius:7px;cursor:pointer;background:#1e293b;transition:transform .18s,box-shadow .18s}\u001b[39m\n\u001b[31m.cov-thumb:hover{transform:scale(1.05);box-shadow:0 4px 18px rgba(0,0,0,.55)}\u001b[39m\n\u001b[31m.cov-thumb img{width:100%;height:100%;object-fit:cover;display:block}\u001b[39m\n\u001b[31m.cov-thumb-vid{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:#0f172a}\u001b[39m\n\u001b[31m.cov-thumb-ov{position:absolute;inset:0;background:rgba(0,0,0,.28);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:5px;border-radius:7px}\u001b[39m\n\u001b[31m.cov-thumb-cat{color:rgba(255,255,255,.5);font-weight:900;text-align:center;text-transform:uppercase;letter-spacing:.8px;text-shadow:0 1px 6px rgba(0,0,0,.95);line-height:1.2;word-break:break-word}\u001b[39m\n\u001b[31m.cov-thumb-dims{color:rgba(255,255,255,.5);font-weight:700;text-align:center;text-shadow:0 1px 5px rgba(0,0,0,.95);letter-spacing:.3px;line-height:1.3}\u001b[39m\n\u001b[31m.cov-thumb-no{color:rgba(255,255,255,.5);font-weight:800;text-shadow:0 1px 4px rgba(0,0,0,.95);letter-spacing:.5px}\u001b[39m\n\u001b[31m#cover-btn{position:fixed;bottom:20px;right:16px;display:none;align-items:center;gap:6px;background:rgba(255,255,255,.15);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.25);color:#fff;padding:10px 22px;border-radius:50px;font-size:13px;font-weight:700;cursor:pointer;z-index:200;letter-spacing:.3px;box-shadow:0 2px 12px rgba(0,0,0,.3);font-family:inherit;transition:background .15s,transform .15s}\u001b[39m\n\u001b[31m#cover-btn:hover{background:rgba(255,255,255,.22);transform:scale(1.04)}·\u001b[39m\n\u001b[31m/* ── Print wait overlay ── */\u001b[39m\n\u001b[31m#print-overlay{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m@media print{#print-overlay{display:none!important}}·\u001b[39m\n\u001b[31m/* ── Loading progress bar ── */\u001b[39m\n\u001b[31m.load-bar{position:fixed;bottom:0;left:0;right:0;background:rgba(15,23,42,.95);padding:9px 16px;z-index:9999;display:flex;align-items:center;gap:12px;backdrop-filter:blur(6px)}\u001b[39m\n\u001b[31m.load-track{flex:1;height:5px;background:rgba(255,255,255,.12);border-radius:3px;overflow:hidden}\u001b[39m\n\u001b[31m.load-fill{height:100%;background:var(--or);width:0%;transition:width .35s ease;border-radius:3px}\u001b[39m\n\u001b[31m.load-txt{font-size:11px;color:rgba(255,255,255,.6);white-space:nowrap;min-width:160px}·\u001b[39m\n\u001b[31m/* ── Photo page ── */\u001b[39m\n\u001b[31m.photo-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ph-band{background:var(--dk);padding:16px 26px;flex-shrink:0;display:flex;align-items:center;gap:20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.ph-cat{font-size:35px;font-weight:800;color:#fff;letter-spacing:-.5px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.ph-dims{flex:1;font-size:18px;font-weight:600;color:var(--or);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}\u001b[39m\n\u001b[31m.ph-no{margin-left:auto;flex-shrink:0;font-size:21px;font-weight:700;color:rgba(255,255,255,.85);background:rgba(255,255,255,.1);padding:5px 20px;border-radius:24px;white-space:nowrap}\u001b[39m\n\u001b[31m.ph-of{font-size:18px;font-weight:400;color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.ph-img{flex:1;overflow:hidden;position:relative;background:#111}\u001b[39m\n\u001b[31m.ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m.ph-img img{width:100%;height:100%;object-fit:contain;display:block}\u001b[39m\n\u001b[31m.ph-cmt{position:absolute;bottom:0;left:0;right:0;padding:6px 14px;background:rgba(0,0,0,.62);font-size:11px;color:rgba(255,255,255,.75);font-style:italic;pointer-events:none}·\u001b[39m\n\u001b[31m/* ── Video / Doc pages ── */\u001b[39m\n\u001b[31m.vid-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;background:#fff}\u001b[39m\n\u001b[31m.vid-body{flex:1;padding:20px 24px;font-size:14px;color:var(--g600);border-left:4px solid var(--or)}\u001b[39m\n\u001b[31m.vid-body em{display:block;font-size:12px;color:var(--g400);margin-top:6px}\u001b[39m\n\u001b[31m.doc-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m.doc-wrap{flex:1;display:flex;align-items:center;justify-content:center;background:#111;overflow:hidden}\u001b[39m\n\u001b[31m.doc-img{max-width:100%;max-height:100%;object-fit:contain}·\u001b[39m\n\u001b[31m/* ── Cover header band ── */\u001b[39m\n\u001b[31m.cov-hdr{display:flex;gap:0;margin-bottom:12px;flex-shrink:0;border-radius:10px;overflow:hidden;border:1px solid rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.cov-hdr-l{flex:1;padding:14px 18px;display:flex;flex-direction:column;gap:5px;border-right:1px solid rgba(255,255,255,.1);min-width:0}\u001b[39m\n\u001b[31m.cov-hdr-r{width:170px;flex-shrink:0;padding:14px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:rgba(255,255,255,.04)}\u001b[39m\n\u001b[31m.cov-store{font-size:18px;font-weight:800;color:#fff;line-height:1.25;margin-bottom:2px}\u001b[39m\n\u001b[31m.cov-meta{font-size:12px;color:rgba(255,255,255,.55);display:flex;align-items:center;gap:5px;line-height:1.5}\u001b[39m\n\u001b[31m.cov-brand{background:var(--or);color:#fff;font-size:13px;font-weight:800;padding:5px 16px;border-radius:20px;text-align:center;letter-spacing:.3px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\u001b[39m\n\u001b[31m.cov-date-l{font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.8px;margin-bottom:2px;text-align:center}\u001b[39m\n\u001b[31m.cov-date-v{font-size:13px;font-weight:700;color:#fff;text-align:center}\u001b[39m\n\u001b[31m.cov-logo-box{background:#fff;border-radius:8px;padding:8px 14px;display:flex;align-items:center;justify-content:center;width:100%;max-width:138px}\u001b[39m\n\u001b[31m.cov-logo-box img{max-width:110px;max-height:44px;object-fit:contain;display:block}·\u001b[39m\n\u001b[31m/* ── Print ── */\u001b[39m\n\u001b[31m@page{size:A4 landscape;margin:12mm}\u001b[39m\n\u001b[31m@media print{\u001b[39m\n\u001b[31m  html,body{height:auto;overflow:visible;display:block}\u001b[39m\n\u001b[31m  .side-idx{display:none}\u001b[39m\n\u001b[31m  .main{overflow:visible;display:block;height:auto;scroll-snap-type:none}\u001b[39m\n\u001b[31m  .cover,.vid-page,.doc-page{height:auto;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m  .photo-page{height:186mm;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m  .cover{padding:20px 24px}\u001b[39m\n\u001b[31m  .cover-pbar{display:none}\u001b[39m\n\u001b[31m  .cov-hdr{margin-bottom:8px;border-radius:7px}\u001b[39m\n\u001b[31m  .cov-hdr-l{padding:10px 14px}\u001b[39m\n\u001b[31m  .cov-hdr-r{padding:10px 12px;width:150px}\u001b[39m\n\u001b[31m  .cov-store{font-size:15px}\u001b[39m\n\u001b[31m  .cov-meta{font-size:10px}\u001b[39m\n\u001b[31m  .cov-brand{font-size:11px;padding:3px 12px}\u001b[39m\n\u001b[31m  .cov-date-v{font-size:11px}\u001b[39m\n\u001b[31m  .ph-band{padding:5mm 13mm;gap:10mm}\u001b[39m\n\u001b[31m  .ph-cat{font-size:15mm}\u001b[39m\n\u001b[31m  .ph-dims{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-no{font-size:12mm;padding:2mm 8mm}\u001b[39m\n\u001b[31m  .ph-of{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-img{flex:1;display:flex;align-items:center;justify-content:center;background:#fff;overflow:hidden}\u001b[39m\n\u001b[31m  .ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m  .ph-img img{width:100%;height:100%;object-fit:contain}\u001b[39m\n\u001b[31m  .ph-cmt{position:static;background:transparent;color:#475569;padding:2mm 8mm;font-size:6mm}\u001b[39m\n\u001b[31m  .main>*:last-child{page-break-after:avoid;break-after:avoid}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m</style></head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<div class=\\\"side-idx\\\" id=\\\"side-idx\\\">${sideItems.join('')}</div>·\u001b[39m\n\u001b[31m<div class=\\\"main\\\" id=\\\"main\\\">·\u001b[39m\n\u001b[31m<div class=\\\"cover\\\" id=\\\"pg-cover\\\">\u001b[39m\n\u001b[31m  <div class=\\\"cov-hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-l\\\">\u001b[39m\n\u001b[31m      <div class=\\\"cov-store\\\">${esc(d.storeName||'Unknown Store')}</div>\u001b[39m\n\u001b[31m      ${(d.address||d.city)?`<div class=\\\"cov-meta\\\">&#x1F4CD; ${esc(d.address||'')}${d.city&&!(d.address||'').includes(d.city)?', '+esc(d.city):''}</div>`:''}\u001b[39m\n\u001b[31m      ${d.mobile?`<div class=\\\"cov-meta\\\">&#x1F4DE; ${esc(d.mobile)}</div>`:''}\u001b[39m\n\u001b[31m      ${d.email?`<div class=\\\"cov-meta\\\">&#x2709; ${esc(d.email)}</div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-r\\\">\u001b[39m\n\u001b[31m      ${brandLogoUrl\u001b[39m\n\u001b[31m        ? `<div class=\\\"cov-logo-box\\\"><img src=\\\"${brandLogoUrl}\\\" alt=\\\"${esc(d.brand||'')}\\\"></div>`\u001b[39m\n\u001b[31m        : (d.brand?`<div class=\\\"cov-brand\\\">${esc(d.brand)}</div>`:'')}\u001b[39m\n\u001b[31m      ${d.date?`<div><div class=\\\"cov-date-l\\\">Recce Date</div><div class=\\\"cov-date-v\\\">${esc(d.date)}</div></div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${thumbItems.length ? `<div class=\\\"cov-grid-hdr\\\">&#x1F4F7; ${thumbItems.length} page${thumbItems.length!==1?'s':''} &mdash; tap any to jump</div><div class=\\\"cov-grid\\\" id=\\\"cov-grid\\\">${thumbsHtml}</div>` : ''}\u001b[39m\n\u001b[31m  <div class=\\\"cover-pbar\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" id=\\\"btn-print\\\" onclick=\\\"doPDF()\\\">&#x1F4C4;&nbsp;PDF</button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-c\\\" onclick=\\\"window.close()\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m${pagesHtml}·\u001b[39m\n\u001b[31m${d.hasVideo?`\u001b[39m\n\u001b[31m<div class=\\\"vid-page\\\" id=\\\"pg-vid\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Video</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"vid-body\\\">${esc(d.videoNote||'Video recorded during visit')}${d.videoCmt?`<em>${esc(d.videoCmt)}</em>`:''}</div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m${urls.doc?`\u001b[39m\n\u001b[31m<div class=\\\"doc-page\\\" id=\\\"pg-doc\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Document</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"doc-wrap\\\"><a href=\\\"${urls.doc}\\\" target=\\\"_blank\\\"><img class=\\\"doc-img\\\" src=\\\"${urls.doc}\\\" loading=\\\"lazy\\\" alt=\\\"Document\\\"></a></div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"print-overlay\\\"><div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Preparing print&hellip;</div><div class=\\\"po-sub\\\" id=\\\"po-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"po-pfill\\\"></div></div></div>\u001b[39m\n\u001b[31m${pages.length ? `<div class=\\\"load-bar\\\" id=\\\"load-bar\\\"><div class=\\\"load-track\\\"><div class=\\\"load-fill\\\" id=\\\"load-fill\\\"></div></div><div class=\\\"load-txt\\\" id=\\\"load-txt\\\">Loading photos&#x2026;</div></div>` : ''}\u001b[39m\n\u001b[31m${thumbItems.length ? `<button id=\\\"cover-btn\\\" onclick=\\\"document.getElementById('pg-cover').scrollIntoView({behavior:'smooth'})\\\">&#x1F3E0;&nbsp;Cover Page</button>` : ''}·\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var main=document.getElementById('main');\u001b[39m\n\u001b[31m  var items=document.querySelectorAll('.si-item');\u001b[39m\n\u001b[31m  var covBtn=document.getElementById('cover-btn');\u001b[39m\n\u001b[31m  function setActive(id){\u001b[39m\n\u001b[31m    items.forEach(function(el){el.classList.toggle('active',el.dataset.tgt===id);});\u001b[39m\n\u001b[31m    var a=document.querySelector('.si-item[data-tgt=\\\"'+id+'\\\"]');\u001b[39m\n\u001b[31m    if(a) a.scrollIntoView({block:'nearest'});\u001b[39m\n\u001b[31m    if(covBtn) covBtn.style.display=id==='pg-cover'?'none':'flex';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  items.forEach(function(el){\u001b[39m\n\u001b[31m    el.addEventListener('click',function(){\u001b[39m\n\u001b[31m      var t=document.getElementById(el.dataset.tgt);\u001b[39m\n\u001b[31m      if(t) t.scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if('IntersectionObserver' in window){\u001b[39m\n\u001b[31m    var obs=new IntersectionObserver(function(entries){\u001b[39m\n\u001b[31m      entries.forEach(function(e){if(e.isIntersecting&&e.intersectionRatio>=0.45) setActive(e.target.id);});\u001b[39m\n\u001b[31m    },{root:main,threshold:0.45});\u001b[39m\n\u001b[31m    document.querySelectorAll('[id^=\\\"pg-\\\"]').forEach(function(p){obs.observe(p);});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  setActive('pg-cover');\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var imgs=Array.from(document.querySelectorAll('img'));\u001b[39m\n\u001b[31m  var total=imgs.length,loaded=0;\u001b[39m\n\u001b[31m  var bar=document.getElementById('load-bar');\u001b[39m\n\u001b[31m  var fill=document.getElementById('load-fill');\u001b[39m\n\u001b[31m  var txt=document.getElementById('load-txt');\u001b[39m\n\u001b[31m  var printPending=false,printShowTime=0;\u001b[39m\n\u001b[31m  var mm=96/25.4;\u001b[39m\n\u001b[31m  var SERVER_PDF='${serverPdfUrl}';\u001b[39m\n\u001b[31m  function updatePoBar(){\u001b[39m\n\u001b[31m    var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m    var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(poFill) poFill.style.width=(total?Math.round(loaded/total*100):100)+'%';\u001b[39m\n\u001b[31m    if(poSub) poSub.textContent=loaded+' / '+total+' photos ready';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function done(){\u001b[39m\n\u001b[31m    if(fill) fill.style.width='100%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='✓ All '+total+' photos ready';\u001b[39m\n\u001b[31m    setTimeout(function(){\u001b[39m\n\u001b[31m      if(bar){bar.style.transition='opacity .6s';bar.style.opacity='0';}\u001b[39m\n\u001b[31m      setTimeout(function(){if(bar)bar.style.display='none';},650);\u001b[39m\n\u001b[31m    },2000);\u001b[39m\n\u001b[31m    if(printPending){\u001b[39m\n\u001b[31m      printPending=false;\u001b[39m\n\u001b[31m      var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m      var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m      var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(poFill) poFill.style.width='100%';\u001b[39m\n\u001b[31m      if(poSub) poSub.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},Math.max(400,2000-(Date.now()-printShowTime)));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function onImg(){\u001b[39m\n\u001b[31m    loaded++;\u001b[39m\n\u001b[31m    if(fill) fill.style.width=Math.round(loaded/total*100)+'%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… '+loaded+' / '+total;\u001b[39m\n\u001b[31m    if(printPending) updatePoBar();\u001b[39m\n\u001b[31m    if(loaded>=total) done();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  /* ── PDF layout helpers ── */\u001b[39m\n\u001b[31m  function fitBandFonts(pageW){\u001b[39m\n\u001b[31m    var padH=2*13*mm,gapH=2*10*mm,noPadH=2*8*mm;\u001b[39m\n\u001b[31m    var avail=pageW-padH-gapH;\u001b[39m\n\u001b[31m    var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-band').forEach(function(band){\u001b[39m\n\u001b[31m      var cat=band.querySelector('.ph-cat');\u001b[39m\n\u001b[31m      var dims=band.querySelector('.ph-dims');\u001b[39m\n\u001b[31m      var no=band.querySelector('.ph-no');\u001b[39m\n\u001b[31m      if(!cat) return;\u001b[39m\n\u001b[31m      var catTxt=cat.textContent.trim();\u001b[39m\n\u001b[31m      var dimsTxt=dims?dims.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      var noTxt=no?no.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      function tw(sc){\u001b[39m\n\u001b[31m        var cf=15*sc*mm,df=10*sc*mm,nf=12*sc*mm;\u001b[39m\n\u001b[31m        ctx.font='800 '+cf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var cw=ctx.measureText(catTxt).width;\u001b[39m\n\u001b[31m        ctx.font='600 '+df+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var dw=dims?ctx.measureText(dimsTxt).width:0;\u001b[39m\n\u001b[31m        ctx.font='700 '+nf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var nw=no?ctx.measureText(noTxt).width+noPadH:0;\u001b[39m\n\u001b[31m        return cw+dw+nw;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      var scale=1.0;\u001b[39m\n\u001b[31m      if(tw(scale)>avail){\u001b[39m\n\u001b[31m        var lo=0.3,hi=1.0;\u001b[39m\n\u001b[31m        for(var i=0;i<10;i++){var mid=(lo+hi)/2;if(tw(mid)<=avail)lo=mid;else hi=mid;}\u001b[39m\n\u001b[31m        scale=lo*0.93;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      cat.style.setProperty('font-size',Math.round(15*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(dims) dims.style.setProperty('font-size',Math.round(10*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(no) no.style.setProperty('font-size',Math.round(12*scale*mm)+'px','important');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function sizePdfThumbs(pageW,pageH){\u001b[39m\n\u001b[31m    var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m    if(!grid||!grid.children.length) return;\u001b[39m\n\u001b[31m    var coverPage=document.getElementById('pg-cover');\u001b[39m\n\u001b[31m    var usedH=56;\u001b[39m\n\u001b[31m    if(coverPage){\u001b[39m\n\u001b[31m      Array.from(coverPage.children).forEach(function(el){\u001b[39m\n\u001b[31m        if(el!==grid) usedH+=el.offsetHeight||0;\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    var gridH=Math.max(80,pageH-usedH);\u001b[39m\n\u001b[31m    var n=grid.children.length,gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m    for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m      var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m      var w=(pageW-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m      var h=w*asp;\u001b[39m\n\u001b[31m      if(rows*h+(rows-1)*gap<=gridH&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m    grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m    grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m    var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m    var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m    var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function preparePdfLayout(){\u001b[39m\n\u001b[31m    var pageW=Math.round((297-24)*mm);\u001b[39m\n\u001b[31m    var pageH=Math.round((210-24)*mm);\u001b[39m\n\u001b[31m    fitBandFonts(pageW);\u001b[39m\n\u001b[31m    sizePdfThumbs(pageW,pageH);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.preparePdfLayout=preparePdfLayout;\u001b[39m\n\u001b[31m  function restorePdfLayout(){\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-cat,.ph-dims,.ph-no').forEach(function(el){\u001b[39m\n\u001b[31m      el.style.removeProperty('font-size');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(window._screenSizeThumbs) window._screenSizeThumbs();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.addEventListener('afterprint',restorePdfLayout);\u001b[39m\n\u001b[31m  function _doBrowserPrint(){\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    printShowTime=Date.now();\u001b[39m\n\u001b[31m    preparePdfLayout();\u001b[39m\n\u001b[31m    if(total===0||loaded>=total){\u001b[39m\n\u001b[31m      var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m      if(ps) ps.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},2000);\u001b[39m\n\u001b[31m      return;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    printPending=true;\u001b[39m\n\u001b[31m    updatePoBar();\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if((!img.complete||img.naturalWidth===0)&&img.getAttribute('loading')==='lazy'){\u001b[39m\n\u001b[31m        img.loading='eager';var s=img.src;img.src='';img.src=s;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.doPDF=async function(){\u001b[39m\n\u001b[31m    if(!SERVER_PDF){_doBrowserPrint();return;}\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      var r=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m      if(r.ok){window.open(SERVER_PDF,'_blank');return;}\u001b[39m\n\u001b[31m    }catch(_){}\u001b[39m\n\u001b[31m    // PDF not ready yet — show overlay and poll\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    if(pf) pf.style.width='0%';\u001b[39m\n\u001b[31m    if(ps) ps.textContent='Waiting for server PDF…';\u001b[39m\n\u001b[31m    var tries=0;\u001b[39m\n\u001b[31m    (async function poll(){\u001b[39m\n\u001b[31m      tries++;\u001b[39m\n\u001b[31m      if(pf) pf.style.width=Math.min(88,tries*8)+'%';\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        var r2=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m        if(r2.ok){\u001b[39m\n\u001b[31m          if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m          setTimeout(function(){if(ov)ov.style.display='none';window.open(SERVER_PDF,'_blank');},400);\u001b[39m\n\u001b[31m          return;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      }catch(_){}\u001b[39m\n\u001b[31m      if(tries>=12){if(ov)ov.style.display='none';_doBrowserPrint();return;}\u001b[39m\n\u001b[31m      setTimeout(poll,5000);\u001b[39m\n\u001b[31m    })();\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  if(total===0){if(bar)bar.style.display='none';}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… 0 / '+total;\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if(img.complete&&img.naturalWidth>0) onImg();\u001b[39m\n\u001b[31m      else{img.addEventListener('load',onImg);img.addEventListener('error',onImg);}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m  if(grid&&grid.children.length>0){\u001b[39m\n\u001b[31m    function sizeThumbs(){\u001b[39m\n\u001b[31m      var n=grid.children.length;\u001b[39m\n\u001b[31m      var gw=grid.clientWidth,gh=grid.clientHeight;\u001b[39m\n\u001b[31m      if(!gw||!gh) return;\u001b[39m\n\u001b[31m      var gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m      for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m        var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m        var w=(gw-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m        var h=w*asp;\u001b[39m\n\u001b[31m        if(rows*h+(rows-1)*gap<=gh&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m      grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m      grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m      var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m      var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m      var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    window._screenSizeThumbs=sizeThumbs;\u001b[39m\n\u001b[31m    requestAnimationFrame(function(){requestAnimationFrame(sizeThumbs);});\u001b[39m\n\u001b[31m    window.addEventListener('resize',sizeThumbs);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m</scr`+'ipt>'+`\u001b[39m\n\u001b[31m</body></html>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncToPostgres(entry) {\u001b[39m\n\u001b[31m  const d   = entry.data || {};\u001b[39m\n\u001b[31m  const hub = _recceHubUser();·\u001b[39m\n\u001b[31m  // Step 1 — upload all photos to VPS, get permanent server URLs\u001b[39m\n\u001b[31m  let photoUrls = { front:[], inside:[], brandings:[], addl:[], doc:null };\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const pResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type: 'save-photos', subId: entry.id,\u001b[39m\n\u001b[31m        photos: {\u001b[39m\n\u001b[31m          front:    (d.frontPhotos||[]).map(p=>({b64:p.b64,   cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64,  cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||null})),\u001b[39m\n\u001b[31m          addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64,   desc:p.desc||''})),\u001b[39m\n\u001b[31m          doc:      d.docB64 || null,\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (pResp.ok) { const r=await pResp.json(); if(r.success) {\u001b[39m\n\u001b[31m      photoUrls=r.photoUrls;\u001b[39m\n\u001b[31m      // Merge retained existing URLs for edit re-submits\u001b[39m\n\u001b[31m      if (entry.editedAt) {\u001b[39m\n\u001b[31m        photoUrls.front    =(photoUrls.front   ||[]).map((u,i)=>u||(d.frontPhotos  ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.inside   =(photoUrls.inside  ||[]).map((u,i)=>u||(d.insidePhotos ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.addl     =(photoUrls.addl    ||[]).map((u,i)=>u||(d.addlPhotos   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.brandings=(photoUrls.brandings||[]).map((u,i)=>u||(d.brandings   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        if(!photoUrls.doc) photoUrls.doc=d._docExistingUrl||null;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }}\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-photos] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 1.5 — trigger Google Slides via proxy using permanent photo URLs (fire-and-forget)\u001b[39m\n\u001b[31m  (async()=>{try{\u001b[39m\n\u001b[31m    const _hasPh=(photoUrls.front||[]).some(Boolean)||(photoUrls.inside||[]).some(Boolean)||(photoUrls.brandings||[]).some(Boolean);\u001b[39m\n\u001b[31m    if(!_hasPh)return;\u001b[39m\n\u001b[31m    const _gu=(await cfg('slides-gas-url'))||(await cfg('gas-url'))||DEFAULT_GAS_URL;if(!_gu)return;\u001b[39m\n\u001b[31m    await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({\u001b[39m\n\u001b[31m      type:'make-slides',gasUrl:_gu,subId:entry.id,\u001b[39m\n\u001b[31m      storeInfo:{storeName:d.storeName||'',brand:d.brand||'',address:d.address||'',mobile:d.mobile||'',date:d.date||'',city:d.city||'',gpsCoords:d.gpsCoords||null},\u001b[39m\n\u001b[31m      photoGroups:{\u001b[39m\n\u001b[31m        front:    (photoUrls.front   ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.frontPhotos  ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        inside:   (photoUrls.inside  ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.insidePhotos ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        brandings:(photoUrls.brandings||[]).filter(Boolean).map((url,i)=>({url,meta:{type:(d.brandings||[])[i]?.type,w:(d.brandings||[])[i]?.w,h:(d.brandings||[])[i]?.h,qty:(d.brandings||[])[i]?.qty,sqft:(d.brandings||[])[i]?.sqft}})),\u001b[39m\n\u001b[31m        addl:    (photoUrls.addl    ||[]).filter(Boolean).map((url,i)=>({url,desc:(d.addlPhotos  ||[])[i]?.desc||''})),\u001b[39m\n\u001b[31m      },\u001b[39m\n\u001b[31m    })});\u001b[39m\n\u001b[31m    entry.gasAt=new Date().toISOString();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[recce-slides]',e.message);}}\u001b[39m\n\u001b[31m  )();·\u001b[39m\n\u001b[31m  // Step 2 — generate rich HTML report using server URLs, save to VPS\u001b[39m\n\u001b[31m  let view_url = null;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const html  = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m    const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-view', subId: entry.id, html })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (vResp.ok) { const r=await vResp.json(); if(r.success) view_url=r.url; }\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-view] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 3 — upsert to PostgreSQL with photo URLs + view URL\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch(`${_RC_BASE}/submissions`, {\u001b[39m\n\u001b[31m      method: 'POST', headers: _RC_UPSERT,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        sub_id:         entry.id,\u001b[39m\n\u001b[31m        store_name:     d.storeName    || 'Unknown',\u001b[39m\n\u001b[31m        brand:          d.brand        || null,\u001b[39m\n\u001b[31m        client_name:    d.clientName   || null,\u001b[39m\n\u001b[31m        visit_date:     d.date         || new Date().toISOString().slice(0,10),\u001b[39m\n\u001b[31m        address:        d.address      || null,\u001b[39m\n\u001b[31m        mobile:         d.mobile       || null,\u001b[39m\n\u001b[31m        city:           d.city         || null,\u001b[39m\n\u001b[31m        has_branding:   !!(d.brandings?.length),\u001b[39m\n\u001b[31m        branding_count: d.brandings?.length || 0,\u001b[39m\n\u001b[31m        has_video:      !!d.hasVideo,\u001b[39m\n\u001b[31m        front_photos:   d.frontPhotos?.length  || 0,\u001b[39m\n\u001b[31m        inside_photos:  d.insidePhotos?.length || 0,\u001b[39m\n\u001b[31m        addl_photos:    d.addlPhotos?.length   || 0,\u001b[39m\n\u001b[31m        gps_lat:        d.gpsCoords?.lat       || null,\u001b[39m\n\u001b[31m        gps_lng:        d.gpsCoords?.lng       || null,\u001b[39m\n\u001b[31m        submitted_by:   hub.empId              || null,\u001b[39m\n\u001b[31m        submitted_at:   entry.timestamp,\u001b[39m\n\u001b[31m        campaign_id:    entry.campaignId       || null,\u001b[39m\n\u001b[31m        photo_urls:     photoUrls,\u001b[39m\n\u001b[31m        view_url,\u001b[39m\n\u001b[31m        meta: {\u001b[39m\n\u001b[31m          brandings: (d.brandings||[]).map(b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft})),\u001b[39m\n\u001b[31m          videoNote: d.videoNote || null,\u001b[39m\n\u001b[31m          videoCmt:  d.videoCmt  || null,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        status: 'submitted',\u001b[39m\n\u001b[31m        edit_assigned_to: null,\u001b[39m\n\u001b[31m        edit_comment: null,\u001b[39m\n\u001b[31m        edited_at: entry.editedAt || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    return { ok: true, viewUrl: view_url };\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    console.warn('[recce-db] sync error:', e.message);\u001b[39m\n\u001b[31m    return { ok: false, viewUrl: null };\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mconst DEFAULT_ADMIN_HASH='42d372e6110bee134990ac6881c3d5eb568482008add9a859f37f10d759430e8';·\u001b[39m\n\u001b[31masync function saveGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('gas-url',url||DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  toast('Endpoint saved','success');\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function testEndpoint(){\u001b[39m\n\u001b[31m  const url=(await cfg('gas-url'))||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  try{await fetch(url,{method:'POST',mode:'no-cors',body:JSON.stringify({test:true})});toast('Endpoint reachable ✓','success');}\u001b[39m\n\u001b[31m  catch{toast('Cannot reach endpoint','error')}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  cfg('gas-url').then(url=>{\u001b[39m\n\u001b[31m    const u=url||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    // Show last 30 chars only for privacy\u001b[39m\n\u001b[31m    el.textContent='Endpoint: …'+u.slice(-30);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── SLIDES GAS URL ────────────────────────────────────────────\u001b[39m\n\u001b[31masync function saveSlidesGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('slides-gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('slides-gas-url', url);\u001b[39m\n\u001b[31m  toast('Slides GAS URL saved','success');\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function updateSlidesGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('slides-gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  const u=await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  el.textContent=u?'Configured: …'+u.slice(-30):'Not configured';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── MAKE SLIDES ───────────────────────────────────────────────\u001b[39m\n\u001b[31masync function makeSlides(id){\u001b[39m\n\u001b[31m  const gasUrl = await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  if(!gasUrl){\u001b[39m\n\u001b[31m    toast('Configure Slides GAS URL in Settings first','error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const entry = await dbGet('subs', id);\u001b[39m\n\u001b[31m  if(!entry){ toast('Entry not found','error'); return; }\u001b[39m\n\u001b[31m  const d = entry.data;·\u001b[39m\n\u001b[31m  toast('Uploading photos & generating slides…','info');·\u001b[39m\n\u001b[31m  // Build photo groups payload\u001b[39m\n\u001b[31m  const photoGroups = {\u001b[39m\n\u001b[31m    front:    (d.frontPhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64, cmt:p.desc||''})),\u001b[39m\n\u001b[31m    brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||'', meta:{type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft}})),\u001b[39m\n\u001b[31m  };·\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type:       'recce',\u001b[39m\n\u001b[31m        subId:      id,\u001b[39m\n\u001b[31m        gasUrl:     gasUrl,\u001b[39m\n\u001b[31m        storeInfo:  {\u001b[39m\n\u001b[31m          storeName: d.storeName, brand: d.brand,\u001b[39m\n\u001b[31m          date: d.date, address: d.address,\u001b[39m\n\u001b[31m          mobile: d.mobile, gpsCoords: d.gpsCoords,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        photoGroups,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const result = await resp.json();\u001b[39m\n\u001b[31m    if(result.success && result.slideUrl){\u001b[39m\n\u001b[31m      // Store slide URL on the entry\u001b[39m\n\u001b[31m      entry.slideUrl = result.slideUrl;\u001b[39m\n\u001b[31m      await dbPut('subs', entry);\u001b[39m\n\u001b[31m      toast('✅ Slides ready!','success');\u001b[39m\n\u001b[31m      window.open(result.slideUrl, '_blank');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast('Slides error: '+(result.error||'Unknown'),'error');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e){\u001b[39m\n\u001b[31m    toast('Network error: '+e.message,'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN LOGIN ──────────────────────────────────────────────\u001b[39m\n\u001b[31mfunction showAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-error').style.display='none';\u001b[39m\n\u001b[31m  // Restore saved config URL\u001b[39m\n\u001b[31m  cfg('admin-cfg-url').then(u=>{if(u&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=u;});\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('admin-pwd').focus(),100);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveAdminCfgUrl(){\u001b[39m\n\u001b[31m  // Admin cfg URL can be saved without login (needed to set up auth itself)\u001b[39m\n\u001b[31m  // But we warn if saving while unlocked only\u001b[39m\n\u001b[31m  const url=document.getElementById('admin-cfg-url').value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  await cfg('admin-cfg-url',url);\u001b[39m\n\u001b[31m  toast('Config URL saved — will use on next login attempt','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function verifyAdmin(){\u001b[39m\n\u001b[31m  // Hub admins (harish/pramod) are auto-unlocked — no password needed\u001b[39m\n\u001b[31m  if (_adminUnlocked) { adminLoginSuccess(); return; }\u001b[39m\n\u001b[31m  const pwd=document.getElementById('admin-pwd').value;\u001b[39m\n\u001b[31m  if(!pwd){document.getElementById('admin-error').style.display='block';document.getElementById('admin-error').textContent='Enter password';return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('admin-login-btn');btn.disabled=true;btn.textContent='Verifying…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // Try server verification first\u001b[39m\n\u001b[31m    const cfgUrl=(await cfg('admin-cfg-url'))||'';\u001b[39m\n\u001b[31m    if(cfgUrl){\u001b[39m\n\u001b[31m      const r=await fetch(cfgUrl,{cache:'no-store'});\u001b[39m\n\u001b[31m      const j=await r.json();\u001b[39m\n\u001b[31m      // Server JSON format: {\\\"password\\\":\\\"plaintext\\\"} or {\\\"hash\\\":\\\"sha256hash\\\"}\u001b[39m\n\u001b[31m      let match=false;\u001b[39m\n\u001b[31m      if(j.password){match=(j.password===pwd);}\u001b[39m\n\u001b[31m      else if(j.hash){\u001b[39m\n\u001b[31m        // SHA-256 comparison\u001b[39m\n\u001b[31m        const enc=new TextEncoder();\u001b[39m\n\u001b[31m        const data=enc.encode(pwd);\u001b[39m\n\u001b[31m        const hashBuf=await crypto.subtle.digest('SHA-256',data);\u001b[39m\n\u001b[31m        const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m        match=(hashHex===j.hash);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      if(match){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m      else{showAdminError('Incorrect password');return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Fallback: local password stored in settings\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if(localHash){\u001b[39m\n\u001b[31m      const enc=new TextEncoder();\u001b[39m\n\u001b[31m      const hashBuf=await crypto.subtle.digest('SHA-256',enc.encode(pwd));\u001b[39m\n\u001b[31m      const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m      if(hashHex===localHash){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Final fallback: check against hardcoded default hash\u001b[39m\n\u001b[31m    const enc2=new TextEncoder();\u001b[39m\n\u001b[31m    const hb2=await crypto.subtle.digest('SHA-256',enc2.encode(pwd));\u001b[39m\n\u001b[31m    const hh2=Array.from(new Uint8Array(hb2)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    if(hh2===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }catch(err){\u001b[39m\n\u001b[31m    // Network error — try all local fallbacks\u001b[39m\n\u001b[31m    const enc3=new TextEncoder();\u001b[39m\n\u001b[31m    const hb3=await crypto.subtle.digest('SHA-256',enc3.encode(pwd));\u001b[39m\n\u001b[31m    const hh3=Array.from(new Uint8Array(hb3)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if((localHash&&hh3===localHash)||hh3===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }finally{btn.disabled=false;btn.textContent='Login';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showAdminError(msg){\u001b[39m\n\u001b[31m  const el=document.getElementById('admin-error');\u001b[39m\n\u001b[31m  el.textContent=msg;el.style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminLoginSuccess(){\u001b[39m\n\u001b[31m  _adminUnlocked=true;\u001b[39m\n\u001b[31m  closeAdminLogin();\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  cfg('gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  cfg('slides-gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('slides-gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||'';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  toast('Admin mode unlocked','success');\u001b[39m\n\u001b[31m  setTimeout(lockAdmin,10*60*1000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction lockAdmin(){\u001b[39m\n\u001b[31m  _adminUnlocked=false;\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  toast('Admin session ended','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updAvailTag(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-avail-tag');\u001b[39m\n\u001b[31m  const ct=document.getElementById('store-avail-count');\u001b[39m\n\u001b[31m  const txt=stores.length?`${stores.length} stores`:'No store list';\u001b[39m\n\u001b[31m  if(el)el.textContent=txt;\u001b[39m\n\u001b[31m  if(ct)ct.textContent=stores.length?t(`${stores.length} stores available — tap to browse`,`${stores.length} स्टोर उपलब्ध — दबाएं`):t('No store list loaded yet','कोई स्टोर सूची नहीं');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PICKER\u001b[39m\n\u001b[31mfunction openPicker(){\u001b[39m\n\u001b[31m  if(!stores.length){toast('Load a store list in Settings first','error');return;}\u001b[39m\n\u001b[31m  document.getElementById('povl').classList.add('open');\u001b[39m\n\u001b[31m  document.getElementById('psearch').value='';\u001b[39m\n\u001b[31m  filterPicker('');\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('psearch').focus(),150);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closePicker(){document.getElementById('povl').classList.remove('open');}\u001b[39m\n\u001b[31masync function filterPicker(q){\u001b[39m\n\u001b[31m  const list=document.getElementById('plist');\u001b[39m\n\u001b[31m  const words=q.toLowerCase().trim().split(/\\\\s+/).filter(Boolean);\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const lastVisit={};\u001b[39m\n\u001b[31m  subs.forEach(s=>{const nm=s.data?.storeName;if(nm&&(!lastVisit[nm]||s.timestamp>lastVisit[nm]))lastVisit[nm]=s.timestamp;});·\u001b[39m\n\u001b[31m  // Multi-word: ALL words must match somewhere in any field (search across both English and Hindi)\u001b[39m\n\u001b[31m  let fl=stores.filter(s=>{\u001b[39m\n\u001b[31m    if(!words.length)return true;\u001b[39m\n\u001b[31m    const hay=[s.name,s.nameHi,s.address,s.addressHi,s.mobile,s.city,s.cityHi,s.distName,s.distNameHi,s.brand,s.sales,s.proj,s.glowSign,s.inshop]\u001b[39m\n\u001b[31m               .map(x=>(x||'').toLowerCase()).join(' ');\u001b[39m\n\u001b[31m    return words.every(w=>hay.includes(w));\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(fl.length>100)fl=fl.slice(0,100);·\u001b[39m\n\u001b[31m  if(!fl.length){\u001b[39m\n\u001b[31m    const esc=q.replace(/'/g,\\\"\\\\\\\\'\\\");\u001b[39m\n\u001b[31m    list.innerHTML=`<div style=\\\"text-align:center;padding:32px 16px;color:var(--g400);font-size:14px\\\">No stores match \\\"${q}\\\"<br><span style=\\\"font-size:12px\\\">Try fewer or different words</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('${esc}')\\\">+ Add \\\"${q}\\\" as new store</div>`;\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Group by brand (including empty brand)\u001b[39m\n\u001b[31m  const g={};\u001b[39m\n\u001b[31m  fl.forEach(s=>{\u001b[39m\n\u001b[31m    const b=s.brand||'(No Brand — will ask)';\u001b[39m\n\u001b[31m    if(!g[b])g[b]=[];\u001b[39m\n\u001b[31m    g[b].push(s);\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html='';\u001b[39m\n\u001b[31m  Object.keys(g).sort().forEach(br=>{\u001b[39m\n\u001b[31m    html+=`<div class=\\\"psec\\\">${br}</div>`;\u001b[39m\n\u001b[31m    g[br].forEach(s=>{\u001b[39m\n\u001b[31m      const lv=lastVisit[s.name];\u001b[39m\n\u001b[31m      const lvStr=lv?`🕐 Last: ${new Date(lv).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'2-digit'})}`:'';\u001b[39m\n\u001b[31m      const chips=[];\u001b[39m\n\u001b[31m      if(s.glowSign&&s.glowSign.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dcfce7;color:#14532d;padding:2px 6px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m      if(s.inshop&&s.inshop.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dbeafe;color:#1e40af;padding:2px 6px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m      if(s.proj)chips.push(`<span style=\\\"font-size:10px;background:var(--g100);color:var(--g600);padding:2px 6px;border-radius:10px\\\">Target: ${s.proj}</span>`);\u001b[39m\n\u001b[31m      const enc=JSON.stringify(s).replace(/\\\"/g,'&quot;');\u001b[39m\n\u001b[31m      const mapsUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m      const waUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const telUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const dispName=LANG==='hi'&&s.nameHi?s.nameHi:s.name;\u001b[39m\n\u001b[31m      const dispAddr=LANG==='hi'&&s.addressHi?s.addressHi:s.address;\u001b[39m\n\u001b[31m      const dispDist=LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m      html+=`<div class=\\\"pitem\\\" onclick=\\\"pickStore(${enc})\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"pi-name\\\">${dispName}</div>\u001b[39m\n\u001b[31m          ${dispAddr?`<div class=\\\"pi-addr\\\">📍 ${dispAddr}</div>`:''}\u001b[39m\n\u001b[31m          ${s.mobile?`<div class=\\\"pi-addr\\\">📞 ${s.mobile}</div>`:''}\u001b[39m\n\u001b[31m          ${dispDist?`<div class=\\\"pi-addr\\\" style=\\\"color:var(--am)\\\">👤 ${dispDist}</div>`:''}\u001b[39m\n\u001b[31m          ${lvStr?`<div class=\\\"pi-last\\\">${lvStr}</div>`:''}\u001b[39m\n\u001b[31m          ${chips.length?`<div style=\\\"display:flex;gap:4px;flex-wrap:wrap;margin-top:4px\\\">${chips.join('')}</div>`:''}\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;gap:6px;margin-top:7px\\\" onclick=\\\"event.stopPropagation()\\\">\u001b[39m\n\u001b[31m            ${mapsUrl?`<a href=\\\"${mapsUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#e0f2fe;color:#0369a1;border-radius:20px;text-decoration:none;font-weight:600\\\">🗺 Maps</a>`:''}\u001b[39m\n\u001b[31m            ${waUrl?`<a href=\\\"${waUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#dcfce7;color:#15803d;border-radius:20px;text-decoration:none;font-weight:600\\\">💬 WhatsApp</a>`:''}\u001b[39m\n\u001b[31m            ${telUrl?`<a href=\\\"${telUrl}\\\" style=\\\"font-size:11px;padding:4px 10px;background:#f0fdf4;color:#166534;border-radius:20px;text-decoration:none;font-weight:600\\\">📞 Call</a>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        ${s.brand?`<div class=\\\"pi-brand\\\">${s.brand}</div>`:'<div class=\\\"pi-brand\\\" style=\\\"background:var(--rd)\\\">?</div>'}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html+=`<div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('')\\\">+ Not in list? Add new store</div>`;\u001b[39m\n\u001b[31m  list.innerHTML=html;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function pickStore(s){\u001b[39m\n\u001b[31m  selectedStore=s;manualMode=false;closePicker();\u001b[39m\n\u001b[31m  const _dn =LANG==='hi'&&s.nameHi    ?s.nameHi    :s.name;\u001b[39m\n\u001b[31m  const _da =LANG==='hi'&&s.addressHi ?s.addressHi :s.address;\u001b[39m\n\u001b[31m  const _dd =LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m  const _dc =LANG==='hi'&&s.cityHi    ?s.cityHi    :s.city;\u001b[39m\n\u001b[31m  document.getElementById('sc-name').textContent=_dn;\u001b[39m\n\u001b[31m  const brandEl=document.getElementById('sc-brand');\u001b[39m\n\u001b[31m  brandEl.textContent=s.brand||'No Brand';brandEl.style.background=s.brand?'var(--nv)':'var(--rd)';\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const prev=subs.filter(x=>x.data?.storeName===s.name).sort((a,b)=>new Date(b.timestamp)-new Date(a.timestamp))[0];\u001b[39m\n\u001b[31m  const lc=document.getElementById('sc-last');\u001b[39m\n\u001b[31m  if(prev){const d=new Date(prev.timestamp);lc.textContent='Last: '+d.toLocaleDateString('en-IN',{day:'numeric',month:'short'});lc.style.display='inline-flex';}\u001b[39m\n\u001b[31m  else lc.style.display='none';\u001b[39m\n\u001b[31m  // All Excel fields — display in active language\u001b[39m\n\u001b[31m  const mUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m  const wUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const tUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const details=[];\u001b[39m\n\u001b[31m  if(_da)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📍 ${_da}${mUrl?` <a href=\\\"${mUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#0369a1;margin-left:6px\\\">🗺 Navigate</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(s.mobile)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📞 ${s.mobile}${tUrl?` <a href=\\\"${tUrl}\\\" style=\\\"font-size:11px;color:#166534;margin-left:6px\\\">Call</a>`:''}${wUrl?` <a href=\\\"${wUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#15803d;margin-left:6px\\\">WhatsApp</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(_dd)details.push(`<div style=\\\"font-size:12px;color:var(--am)\\\">👤 ${_dd}</div>`);\u001b[39m\n\u001b[31m  if(_dc)details.push(`<div style=\\\"font-size:12px;color:var(--g500)\\\">🏙 ${_dc}</div>`);\u001b[39m\n\u001b[31m  const opp=[];\u001b[39m\n\u001b[31m  if(s.glowSign&&s.glowSign.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dcfce7;color:#14532d;padding:2px 7px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m  if(s.inshop&&s.inshop.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dbeafe;color:#1e40af;padding:2px 7px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m  if(s.proj)opp.push(`<span style=\\\"font-size:11px;background:var(--g100);color:var(--g600);padding:2px 7px;border-radius:10px\\\">Target 2026: ${s.proj}</span>`);\u001b[39m\n\u001b[31m  if(opp.length)details.push(`<div style=\\\"display:flex;gap:5px;flex-wrap:wrap;margin-top:3px\\\">${opp.join('')}</div>`);\u001b[39m\n\u001b[31m  document.getElementById('sc-details').innerHTML=details.join('');\u001b[39m\n\u001b[31m  // Missing fields\u001b[39m\n\u001b[31m  const missing=[];\u001b[39m\n\u001b[31m  if(!s.address)missing.push({key:'address',label:'Store Address',type:'textarea',placeholder:'Full address'});\u001b[39m\n\u001b[31m  if(!s.mobile)missing.push({key:'mobile',label:'Mobile No.',type:'tel',placeholder:'10-digit number',maxlen:'10'});\u001b[39m\n\u001b[31m  const mw=document.getElementById('sc-missing'),mf=document.getElementById('sc-missing-fields');\u001b[39m\n\u001b[31m  if(missing.length){\u001b[39m\n\u001b[31m    mf.innerHTML=missing.map(m=>`<div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\"><label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">${m.label} <span class=\\\"req\\\">*</span></label>${m.type==='textarea'?`<textarea id=\\\"sc-miss-${m.key}\\\" rows=\\\"2\\\" placeholder=\\\"${m.placeholder}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></textarea>`:`<input type=\\\"${m.type}\\\" id=\\\"sc-miss-${m.key}\\\" placeholder=\\\"${m.placeholder}\\\" ${m.maxlen?`maxlength=\\\"${m.maxlen}\\\"`:''}  inputmode=\\\"${m.type==='tel'?'numeric':'text'}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\">`}</div>`).join('');\u001b[39m\n\u001b[31m    mw.style.display='block';\u001b[39m\n\u001b[31m  } else {mw.style.display='none';}\u001b[39m\n\u001b[31m  // Brand selector\u001b[39m\n\u001b[31m  const bSel=document.getElementById('brand-selector'),bChips=document.getElementById('brand-chips');\u001b[39m\n\u001b[31m  if(!s.brand){\u001b[39m\n\u001b[31m    renderBrandChips();\u001b[39m\n\u001b[31m    bSel.style.display='block';\u001b[39m\n\u001b[31m  } else {bSel.style.display='none';}\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  F.storeName=s.name;F.brand=s.brand||'';F.address=s.address||'';F.mobile=s.mobile||'';\u001b[39m\n\u001b[31m  if(s.brand&&!_selectedClient&&!_clientOtherMode) autoSetClient(s.brand);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateMissingField(key,val){if(!selectedStore)return;selectedStore[key]=val.trim();F[key]=val.trim();saveDraft();}\u001b[39m\n\u001b[31mfunction selectStoreBrand(b){\u001b[39m\n\u001b[31m  F.brand=b;F.brandLogoUrl=_brandLogos[b]||'';\u001b[39m\n\u001b[31m  if(selectedStore)selectedStore.brand=b;\u001b[39m\n\u001b[31m  const el=document.getElementById('sc-brand');if(el){el.textContent=b;el.style.background='var(--nv)';}\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-chips .chip').forEach(c=>{c.classList.toggle('sel',c.querySelector('span')?.textContent===b||c.textContent.trim()===b);});\u001b[39m\n\u001b[31m  if(!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction onManualBrandChange(){\u001b[39m\n\u001b[31m  const b=document.getElementById('f-brand')?.value||'';\u001b[39m\n\u001b[31m  F.brandLogoUrl=b?(_brandLogos[b]||''):'';\u001b[39m\n\u001b[31m  if(b&&!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction openManual(prefill){\u001b[39m\n\u001b[31m  manualMode=true;\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').classList.add('on');\u001b[39m\n\u001b[31m  document.getElementById('mt-label').innerHTML='← Back to store list';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='block';\u001b[39m\n\u001b[31m  // Pre-fill from selectedStore if available (e.g. when toggling after picker selection)\u001b[39m\n\u001b[31m  const s=selectedStore;\u001b[39m\n\u001b[31m  if(s){\u001b[39m\n\u001b[31m    if(document.getElementById('f-brand'))document.getElementById('f-brand').value=s.brand||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-store'))document.getElementById('f-store').value=s.name||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-addr'))document.getElementById('f-addr').value=s.address||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-mobile'))document.getElementById('f-mobile').value=s.mobile||'';\u001b[39m\n\u001b[31m  } else if(prefill){\u001b[39m\n\u001b[31m    document.getElementById('f-store').value=prefill;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  selectedStore=null;\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction toggleManual(){\u001b[39m\n\u001b[31m  if(manualMode){\u001b[39m\n\u001b[31m    manualMode=false;\u001b[39m\n\u001b[31m    document.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31m    document.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31m    document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    openManual('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// GPS\u001b[39m\n\u001b[31mfunction captureGPS(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gps-status');el.textContent='Getting location…';el.style.color='var(--g500)';\u001b[39m\n\u001b[31m  if(!navigator.geolocation){el.textContent='GPS not available';return;}\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(pos=>{\u001b[39m\n\u001b[31m    gpsCoords={lat:pos.coords.latitude.toFixed(6),lng:pos.coords.longitude.toFixed(6),acc:Math.round(pos.coords.accuracy)};\u001b[39m\n\u001b[31m    el.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${gpsCoords.acc}m)`;el.style.color='var(--gn)';saveDraft();\u001b[39m\n\u001b[31m  },()=>{el.textContent='GPS failed — enter address manually';el.style.color='var(--rd)';},{enableHighAccuracy:true,timeout:10000});\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// DRAFT\u001b[39m\n\u001b[31mlet draftT;\u001b[39m\n\u001b[31mfunction saveDraft(){\u001b[39m\n\u001b[31m  clearTimeout(draftT);\u001b[39m\n\u001b[31m  draftT=setTimeout(async()=>{\u001b[39m\n\u001b[31m    const draft={k:'current',ts:Date.now(),F:{...F,date:document.getElementById('f-date')?.value||'',brand:manualMode?(document.getElementById('f-brand')?.value||''):(selectedStore?.brand||F.brand||''),storeName:selectedStore?selectedStore.name:(document.getElementById('f-store')?.value||''),address:manualMode?(document.getElementById('f-addr')?.value||''):(selectedStore?.address||F.address||''),mobile:manualMode?(document.getElementById('f-mobile')?.value||''):(selectedStore?.mobile||F.mobile||''),clientName:getClientName()},selectedStore,manualMode,gpsCoords,_selectedClient,_clientOtherMode,fCnt:frontPhotos.length,iCnt:insidePhotos.length,bCnt:brandings.length};\u001b[39m\n\u001b[31m    await dbPut('draft',draft);\u001b[39m\n\u001b[31m    // Also save photos as b64 blobs to draft so they survive exit\u001b[39m\n\u001b[31m    await saveDraftPhotos();\u001b[39m\n\u001b[31m  },500);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveDraftPhotos(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const photoData={\u001b[39m\n\u001b[31m      front:await Promise.all(frontPhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      inside:await Promise.all(insidePhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      addl:await Promise.all(addlPhotos.map(async p=>({b64:await b64(p.blob),desc:p.desc||''}))),\u001b[39m\n\u001b[31m      brand:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,b64:b.blob?await b64(b.blob):null})))\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    await dbPut('draft',{k:'photos',...photoData});\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function checkDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');const wrap=document.getElementById('resume-wrap');\u001b[39m\n\u001b[31m  if(!d||!d.F?.storeName){wrap.innerHTML='';return;}\u001b[39m\n\u001b[31m  const ago=Math.round((Date.now()-d.ts)/60000);\u001b[39m\n\u001b[31m  const agoStr=ago<1?'just now':ago<60?`${ago}m ago`:`${Math.round(ago/60)}h ago`;\u001b[39m\n\u001b[31m  wrap.innerHTML=`<button class=\\\"resume-btn\\\" onclick=\\\"resumeDraft()\\\">\u001b[39m\n\u001b[31m    <div><div style=\\\"font-size:12px;color:rgba(255,255,255,.5);margin-bottom:3px\\\">Resume draft · ${agoStr}</div><div>${d.F.storeName} · ${d.F.brand||'No brand'}</div></div>\u001b[39m\n\u001b[31m    <div style=\\\"text-align:right\\\"><div style=\\\"font-size:13px;color:var(--or)\\\">${d.fCnt||0} photos · ${d.bCnt||0} brandings →</div></div>\u001b[39m\n\u001b[31m  </button>`;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function resumeDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');if(!d)return;\u001b[39m\n\u001b[31m  F=d.F||{};gpsCoords=d.gpsCoords||null;\u001b[39m\n\u001b[31m  if(d.selectedStore){await pickStore(d.selectedStore);}\u001b[39m\n\u001b[31m  else if(d.manualMode){openManual('');if(F.brand)document.getElementById('f-brand').value=F.brand;if(F.storeName)document.getElementById('f-store').value=F.storeName;if(F.address)document.getElementById('f-addr').value=F.address;if(F.mobile)document.getElementById('f-mobile').value=F.mobile;}\u001b[39m\n\u001b[31m  if(F.date)document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  // Restore client chip state\u001b[39m\n\u001b[31m  if(d._clientOtherMode){_clientOtherMode=true;_selectedClient='';const inp=document.getElementById('f-client-other');if(inp&&F.clientName)inp.value=F.clientName;}\u001b[39m\n\u001b[31m  else if(d._selectedClient){_selectedClient=d._selectedClient;_clientOtherMode=false;}\u001b[39m\n\u001b[31m  else if(F.clientName){autoSetClient(F.clientName);}\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  // Restore photos from draft\u001b[39m\n\u001b[31m  const pd=await dbGet('draft','photos');\u001b[39m\n\u001b[31m  if(pd){\u001b[39m\n\u001b[31m    async function b64ToBlob(b64str){if(!b64str)return null;try{const r=await fetch(b64str);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m    for(const p of(pd.front||[])){const bl=await b64ToBlob(p.b64);if(bl)frontPhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.inside||[])){const bl=await b64ToBlob(p.b64);if(bl)insidePhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.addl||[])){const bl=await b64ToBlob(p.b64);if(bl)addlPhotos.push({blob:bl,prev:URL.createObjectURL(bl),desc:p.desc||''});}\u001b[39m\n\u001b[31m    for(const b of(pd.brand||[])){const bl=await b64ToBlob(b.b64);brandings.push({type:b.type,w:b.w,h:b.h,qty:b.qty,blob:bl,prev:bl?URL.createObjectURL(bl):null});}\u001b[39m\n\u001b[31m    toast('Draft restored with '+frontPhotos.length+' photos ✓','success');\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    toast('Draft restored — photos could not be recovered','info');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PHOTOS\u001b[39m\n\u001b[31mfunction updPhotoBadge(type){const arr=type==='front'?frontPhotos:insidePhotos;const el=document.getElementById(type+'-badge');if(el){el.textContent=arr.length;el.className='cnt-badge '+(arr.length?'':'gray');}}\u001b[39m\n\u001b[31mfunction renderPhotos(type){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  const cont=document.getElementById(type+'-cont');const addBtn=document.getElementById('add-'+type);\u001b[39m\n\u001b[31m  updPhotoBadge(type);\u001b[39m\n\u001b[31m  if(arr.length===0){cont.innerHTML=`<div class=\\\"pslot\\\" onclick=\\\"addPhoto('${type}')\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to capture or upload</span><span class=\\\"hi-txt\\\">फोटो खींचें या अपलोड करें</span></div></div>`;addBtn.style.display='none';return;}\u001b[39m\n\u001b[31m  cont.innerHTML=arr.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const badge=isRetained?`<span class=\\\"pbadge\\\" style=\\\"background:#475569\\\">Existing</span>`:`<span class=\\\"pbadge\\\">${fmtSz(p.blob.size)}</span>`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replacePhoto('${type}',${i})\\\" style=\\\"right:36px;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"margin-bottom:12px\\\"><div class=\\\"pslot filled\\\" style=\\\"margin-bottom:8px\\\"><img src=\\\"${p.prev}\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmPhoto('${type}',${i})\\\">×</button>${badge}</div><input type=\\\"text\\\" placeholder=\\\"Comments (optional)\\\" value=\\\"${p.cmt||''}\\\" onchange=\\\"${type==='front'?'frontPhotos':'insidePhotos'}[${i}].cmt=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  addBtn.style.display=arr.length<(type==='inside'?5:3)?'inline-flex':'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// Photo source: 'camera' stamps geo, 'gallery' does not\u001b[39m\n\u001b[31mlet _photoSourceCb=null,_photoSourceQuality=null;·\u001b[39m\n\u001b[31mfunction capPhoto(cb,forceSource,quality){\u001b[39m\n\u001b[31m  // quality override: null=use setting, 'hd', 'compressed'\u001b[39m\n\u001b[31m  _photoSourceCb=cb;_photoSourceQuality=quality||null;\u001b[39m\n\u001b[31m  if(forceSource==='camera'){_doCapture(cb,'camera',quality);return;}\u001b[39m\n\u001b[31m  if(forceSource==='gallery'){_doCapture(cb,'gallery',quality);return;}\u001b[39m\n\u001b[31m  // Show picker\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _doCapture(cb,src,quality){\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  const i=document.createElement('input');\u001b[39m\n\u001b[31m  i.type='file';i.accept='image/*';\u001b[39m\n\u001b[31m  if(src==='camera')i.setAttribute('capture','environment');\u001b[39m\n\u001b[31m  i.style.display='none';\u001b[39m\n\u001b[31m  i.onchange=async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f)return;\u001b[39m\n\u001b[31m    const q=quality||_photoSourceQuality||null;\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      const blob=await compress(f,q==='hd'?1920:q==='compressed'?1280:null,q==='hd'?0.90:q==='compressed'?0.78:null);\u001b[39m\n\u001b[31m      // Only stamp if from camera (live photo)\u001b[39m\n\u001b[31m      const stamped=(src==='camera')?await stampPhoto(blob):blob;\u001b[39m\n\u001b[31m      // Save to device (auto-download trigger)\u001b[39m\n\u001b[31m      savePhotoToDevice(stamped);\u001b[39m\n\u001b[31m      cb({target:{files:[f]},_blob:stamped,_src:src});\u001b[39m\n\u001b[31m    }catch(err){toast('Photo processing failed — try again','error');console.error('_doCapture error:',err);}\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  document.body.appendChild(i);i.click();setTimeout(()=>i.remove(),8000);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction photoSrcCamera(){_doCapture(_photoSourceCb,'camera',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcGallery(){_doCapture(_photoSourceCb,'gallery',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcCancel(){document.getElementById('photo-src-dialog').classList.remove('open');_photoSourceCb=null;}·\u001b[39m\n\u001b[31m// Save photo to device gallery/downloads\u001b[39m\n\u001b[31mfunction savePhotoToDevice(blob){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    const a=document.createElement('a');\u001b[39m\n\u001b[31m    a.href=url;\u001b[39m\n\u001b[31m    a.download='Recce_'+Date.now()+'.jpg';\u001b[39m\n\u001b[31m    a.style.display='none';\u001b[39m\n\u001b[31m    document.body.appendChild(a);a.click();\u001b[39m\n\u001b[31m    setTimeout(()=>{URL.revokeObjectURL(url);a.remove();},1000);\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addPhoto(type){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}${e._src==='camera'&&geoStampEnabled?' · Stamped':''}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31masync function handleCapture(e,type){\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmPhoto(type,i){(type==='front'?frontPhotos:insidePhotos).splice(i,1);renderPhotos(type);saveDraft();}\u001b[39m\n\u001b[31mfunction replacePhoto(type,idx){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m    arr[idx]={...arr[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAddl(){\u001b[39m\n\u001b[31m  const cont=document.getElementById('add-cont');const btn=document.getElementById('add-addl');\u001b[39m\n\u001b[31m  const badge=document.getElementById('addl-badge');if(badge){badge.textContent=`${addlPhotos.length} / 8`;badge.className='cnt-badge '+(addlPhotos.length?'':'gray');}\u001b[39m\n\u001b[31m  cont.innerHTML=addlPhotos.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const sizeInfo=isRetained?'<span style=\\\"color:#475569\\\">Existing</span>':`${fmtSz(p.blob.size)}`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replaceAddl(${i})\\\" style=\\\"top:3px;left:3px;right:auto;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;gap:10px;align-items:start;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--g100)\\\"><div style=\\\"position:relative;flex-shrink:0\\\"><img src=\\\"${p.prev}\\\" style=\\\"width:80px;height:80px;object-fit:cover;border-radius:var(--rs)\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmAddl(${i})\\\" style=\\\"top:3px;right:3px\\\">×</button></div><div style=\\\"flex:1\\\"><input type=\\\"text\\\" placeholder=\\\"Description (optional)\\\" value=\\\"${p.desc||''}\\\" onchange=\\\"addlPhotos[${i}].desc=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"><div style=\\\"font-size:11px;color:var(--g400);margin-top:4px\\\">${sizeInfo}</div></div></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  btn.style.display=addlPhotos.length>=8?'none':'inline-flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction addAdditional(){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  addlPhotos.push({blob:bs,prev:URL.createObjectURL(bs),desc:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderAddl();saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31mfunction rmAddl(i){addlPhotos.splice(i,1);renderAddl();saveDraft();}\u001b[39m\n\u001b[31mfunction replaceAddl(idx){\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m    addlPhotos[idx]={...addlPhotos[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderAddl();saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// BRANDING\u001b[39m\n\u001b[31mfunction calcSqft(w,h){const wf=parseFloat(w),hf=parseFloat(h);if(!wf||!hf)return '';return `${(wf*hf).toFixed(0)} sq.in = ${(wf*hf/144).toFixed(2)} sq.ft`;}\u001b[39m\n\u001b[31mfunction renderBrandings(){\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  const cont=document.getElementById('br-items');\u001b[39m\n\u001b[31m  const hb=document.getElementById('br-hdr-badge');if(hb)hb.textContent=`${brandings.length} ${t(brandings.length!==1?'items':'item',brandings.length!==1?'आइटम':'आइटम')}`;\u001b[39m\n\u001b[31m  cont.innerHTML=brandings.map((b,i)=>`<div class=\\\"bitem\\\"><div class=\\\"bitem-hdr\\\"><div class=\\\"bitem-title\\\">${t('Branding','ब्रांडिंग')} ${i+1}${b.type?' — '+b.type:''}</div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:6px\\\">${i>0?`<button class=\\\"btn-d\\\" onclick=\\\"dupBr(${i})\\\" style=\\\"color:var(--or);border-color:var(--orl)\\\">${t('Dup ↑','डुप ↑')}</button>`:''}<button class=\\\"btn-d\\\" onclick=\\\"rmBr(${i})\\\">${t('Remove','हटाएं')}</button></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\"><label>${t('Type','प्रकार')} <span class=\\\"req\\\">*</span></label><div class=\\\"chip-grid\\\">${BTYPE.map(tp=>`<div class=\\\"chip${b.type===tp?' sel':''}\\\" onclick=\\\"setBType(${i},'${tp.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\"> ${tp}</div>`).join('')}</div></div>\u001b[39m\n\u001b[31m    <div class=\\\"dim-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Width (in)','चौड़ाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.w||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].w=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Height (in)','ऊंचाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.h||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].h=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"max-width:74px\\\"><label>${t('Qty','मात्रा')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.qty||''}\\\" placeholder=\\\"1\\\" inputmode=\\\"numeric\\\" onchange=\\\"brandings[${i}].qty=this.value;saveDraft()\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <span class=\\\"sqft\\\" id=\\\"sf${i}\\\">${calcSqft(b.w,b.h)||t('Enter W × H','W × H दर्ज करें')}</span>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-top:12px\\\"><label>${t('Photo','फोटो')} <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      ${b.prev?`<div class=\\\"pslot filled\\\" onclick=\\\"capBr(${i})\\\"><img src=\\\"${b.prev}\\\"><button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();rmBrPh(${i})\\\">×</button><span class=\\\"pbadge\\\">${b.blob?fmtSz(b.blob.size):'Existing'}</span></div>`:`<div><div class=\\\"pslot\\\" onclick=\\\"capBr(${i})\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\">${t('Tap to capture','दबाकर कैप्चर करें')}</div></div><div style=\\\"display:flex;gap:6px;margin-top:6px\\\"><button class=\\\"atool${(b.quality||imgQuality)==='compressed'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'compressed');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">${t('Compressed','कम्प्रेस्ड')}</button><button class=\\\"atool${(b.quality||imgQuality)==='hd'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'hd');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">HD</button></div></div>`}\u001b[39m\n\u001b[31m    </div></div>`).join('');\u001b[39m\n\u001b[31m  // Only show \\\"Add Another\\\" when last item is fully complete\u001b[39m\n\u001b[31m  const addDiv=document.getElementById('br-add');\u001b[39m\n\u001b[31m  if(addDiv&&brandings.length>0){\u001b[39m\n\u001b[31m    const last=brandings[brandings.length-1];\u001b[39m\n\u001b[31m    const lastComplete=last.type&&last.w&&last.h&&last.qty&&last.prev;\u001b[39m\n\u001b[31m    addDiv.style.display=(lastComplete&&brandings.length<15)?'block':'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updSqft(i){const el=document.getElementById('sf'+i);if(el)el.textContent=calcSqft(brandings[i].w,brandings[i].h)||t('Enter W × H','W × H दर्ज करें');saveDraft();}\u001b[39m\n\u001b[31mfunction setBType(i,tp){brandings[i].type=tp;renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction addBranding(){if(brandings.length>=15){toast(t('Max 15 items','अधिकतम 15 आइटम'),'error');return;}brandings.push({type:'',w:'',h:'',qty:'1',blob:null,prev:null});renderBrandings();}\u001b[39m\n\u001b[31mfunction dupBr(i){if(brandings.length>=10){toast(t('Max 10 items','अधिकतम 10 आइटम'),'error');return;}const s=brandings[i-1];brandings.splice(i,0,{type:s.type,w:s.w,h:s.h,qty:s.qty,blob:null,prev:null});renderBrandings();toast(t('Duplicated — add photo','डुप्लीकेट — फोटो जोड़ें'),'info');}\u001b[39m\n\u001b[31mfunction rmBr(i){brandings.splice(i,1);renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction capBr(i){\u001b[39m\n\u001b[31m  const q=brandings[i]?.quality||imgQuality;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f,q==='hd'?1920:1280,q==='hd'?0.90:0.78));\u001b[39m\n\u001b[31m    brandings[i].blob=bs;brandings[i].prev=URL.createObjectURL(bs);\u001b[39m\n\u001b[31m    brandings[i].fromCamera=(e._src==='camera');\u001b[39m\n\u001b[31m    openAnnot(i);\u001b[39m\n\u001b[31m  },null,q);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmBrPh(i){brandings[i].blob=null;brandings[i].prev=null;renderBrandings();}\u001b[39m\n\u001b[31mfunction setBrQuality(i,q){brandings[i].quality=q;renderBrandings();}·\u001b[39m\n\u001b[31m// VIDEO / DOC\u001b[39m\n\u001b[31mfunction setVideo(v){F.hasVideo=v;document.getElementById('vid-yes').classList.toggle('sel',v);document.getElementById('vid-no').classList.toggle('sel',!v);document.getElementById('vid-sec').style.display=v?'block':'none';saveDraft();}\u001b[39m\n\u001b[31masync function handleVideo(e){videoBlob=e.target.files[0];if(!videoBlob)return;document.getElementById('vid-slot').innerHTML=`<div style=\\\"padding:14px;font-size:13px;color:var(--gn)\\\">✓ ${videoBlob.name} (${fmtSz(videoBlob.size)})</div>`;}\u001b[39m\n\u001b[31mfunction setBranding(v){F.hasBranding=v;document.getElementById('br-yes').classList.toggle('sel',v);document.getElementById('br-no').classList.toggle('sel',!v);document.getElementById('br-add').style.display=v?'block':'none';if(v&&brandings.length===0)addBranding();saveDraft();}\u001b[39m\n\u001b[31masync function handleDoc(e){const f=e.target.files[0];if(!f)return;submissionDoc=f.type.startsWith('image/')?await compress(f,1600,.85):f;const slot=document.getElementById('doc-slot');if(f.type.startsWith('image/')){slot.classList.add('filled');slot.innerHTML=`<img src=\\\"${URL.createObjectURL(submissionDoc)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}else{slot.innerHTML=`<div style=\\\"padding:16px;font-size:13px;color:var(--gn)\\\">✓ ${f.name} (${fmtSz(f.size)})</div>`;}buildReview();}·\u001b[39m\n\u001b[31m// CLIENT CHIPS\u001b[39m\n\u001b[31mfunction renderClientChips(){\u001b[39m\n\u001b[31m  const grid = document.getElementById('client-chips'); if (!grid) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  clientList.forEach(c => {\u001b[39m\n\u001b[31m    const sel = !_clientOtherMode && _selectedClient === c;\u001b[39m\n\u001b[31m    html += `<div class=\\\"cl-chip${sel?' sel':''}\\\" onclick=\\\"selectClientChip('${esc(c)}')\\\">${esc(c)}</div>`;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html += `<div class=\\\"cl-chip cl-chip-other${_clientOtherMode?' sel':''}\\\" onclick=\\\"selectClientOther()\\\"><span class=\\\"en-txt\\\">Other…</span><span class=\\\"hi-txt\\\">अन्य…</span></div>`;\u001b[39m\n\u001b[31m  grid.innerHTML = html;\u001b[39m\n\u001b[31m  document.getElementById('client-other-wrap').style.display = _clientOtherMode ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientChip(name){\u001b[39m\n\u001b[31m  _selectedClient = name; _clientOtherMode = false;\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').value = '';\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientOther(){\u001b[39m\n\u001b[31m  _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onClientOtherInput(){\u001b[39m\n\u001b[31m  _selectedClient = document.getElementById('f-client-other').value.trim();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction getClientName(){\u001b[39m\n\u001b[31m  if (_clientOtherMode) return (document.getElementById('f-client-other')?.value||'').trim();\u001b[39m\n\u001b[31m  return _selectedClient;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction autoSetClient(brandName){\u001b[39m\n\u001b[31m  if (!brandName) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  if (clientList.includes(brandName)){\u001b[39m\n\u001b[31m    _selectedClient = brandName; _clientOtherMode = false;\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    // Not in list — pre-fill the Other field\u001b[39m\n\u001b[31m    _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m    const inp = document.getElementById('f-client-other');\u001b[39m\n\u001b[31m    if (inp && !inp.value) inp.value = brandName;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// STEP VALIDATION\u001b[39m\n\u001b[31mfunction getSD(){if(selectedStore&&!manualMode)return{storeName:selectedStore.name,brand:selectedStore.brand||'',address:selectedStore.address||'',mobile:selectedStore.mobile||''};return{storeName:(document.getElementById('f-store')?.value||'').trim(),brand:document.getElementById('f-brand')?.value||'',address:(document.getElementById('f-addr')?.value||'').trim(),mobile:(document.getElementById('f-mobile')?.value||'').trim()};}\u001b[39m\n\u001b[31mfunction step2(){\u001b[39m\n\u001b[31m  const d=document.getElementById('f-date').value;\u001b[39m\n\u001b[31m  if(!d){toast('Select date','error');return;}\u001b[39m\n\u001b[31m  const sd=getSD();\u001b[39m\n\u001b[31m  if(!sd.storeName){toast('Select or enter store name','error');return;}\u001b[39m\n\u001b[31m  if(!sd.brand){toast('Select a brand','error');document.getElementById('brand-selector').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  if(!sd.address){toast('Enter store address','error');return;}\u001b[39m\n\u001b[31m  const clientName=getClientName();\u001b[39m\n\u001b[31m  if(!clientName){toast(t('Select a client','क्लाइंट चुनें'),'error');document.getElementById('client-chips').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  // Check missing fields filled\u001b[39m\n\u001b[31m  const missAddr=document.getElementById('sc-miss-address');\u001b[39m\n\u001b[31m  if(missAddr&&!missAddr.value.trim()){toast('Enter store address in the highlighted field','error');missAddr.focus();return;}\u001b[39m\n\u001b[31m  const missMob=document.getElementById('sc-miss-mobile');\u001b[39m\n\u001b[31m  // mobile not required — just copy if filled\u001b[39m\n\u001b[31m  if(missMob&&missMob.value.trim()&&!F.mobile)F.mobile=missMob.value.trim();\u001b[39m\n\u001b[31m  Object.assign(F,{date:d,...sd,clientName});saveDraft();\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');showView('form-photos');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction step3(){if(!frontPhotos.length){toast('Add at least 1 front view photo','error');return;}showView('form-video');}\u001b[39m\n\u001b[31mfunction step4(){if(F.hasVideo===undefined||F.hasVideo===null){toast('Select Yes or No for video','error');return;}renderBrandings();showView('form-branding');}\u001b[39m\n\u001b[31mfunction step5(){if(F.hasBranding===undefined||F.hasBranding===null){toast('Select Yes or No for branding space','error');return;}if(F.hasBranding){for(let i=0;i<brandings.length;i++){const b=brandings[i];if(!b.type){toast(`Select branding type for item ${i+1}`,'error');return;}if(!b.w||!b.h){toast(`Enter W and H dimensions for item ${i+1}`,'error');return;}if(!b.qty){toast(`Enter qty for item ${i+1}`,'error');return;}if(!b.blob&&!b.prev){toast(`Add photo for item ${i+1}`,'error');return;}}}renderAddl();buildReview();showView('form-additional');}·\u001b[39m\n\u001b[31m// REVIEW\u001b[39m\n\u001b[31mfunction buildReview(){const el=document.getElementById('rev-body');if(!el)return;const sd=getSD();const cn=getClientName();el.innerHTML=`<div><div class=\\\"rev-lbl\\\">Store</div><div class=\\\"rev-val\\\">${sd.storeName||'—'} · ${sd.brand||'—'}</div><div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">${sd.address||'—'}${sd.mobile?' · '+sd.mobile:''}</div>${gpsCoords?`<div style=\\\"font-size:11px;color:var(--gn);margin-top:3px\\\">📍 ${gpsCoords.lat}, ${gpsCoords.lng} ±${gpsCoords.acc}m</div>`:''}</div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Client</div><div class=\\\"rev-val\\\" style=\\\"color:${cn?'var(--nv)':'var(--rd)'}\\\">${cn||'⚠ Not selected — required'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Photos — Front · Inside · Additional</div><div class=\\\"rev-val\\\">${frontPhotos.length} · ${insidePhotos.length} · ${addlPhotos.length}</div><div class=\\\"rev-photos\\\">${[...frontPhotos,...insidePhotos].slice(0,6).map(p=>`<img class=\\\"rev-thumb\\\" src=\\\"${p.prev}\\\">`).join('')}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Video · Branding items</div><div class=\\\"rev-val\\\">${F.hasVideo?'Yes':'No'} · ${brandings.length} item(s)</div></div>${F.hasBranding&&brandings.length?`<div style=\\\"margin-top:8px\\\">${brandings.map((b,i)=>`<div style=\\\"font-size:12px;color:var(--g600);padding:4px 0;border-bottom:1px solid var(--g100)\\\">${i+1}. ${b.type||'No type'} — ${b.w||'?'}×${b.h||'?'}\\\" × ${b.qty||'?'} — ${calcSqft(b.w,b.h)||'?'}</div>`).join('')}</div>`:''}<div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Additional photos <span style=\\\"font-size:11px;color:var(--g400)\\\">(optional)</span></div><div class=\\\"rev-val\\\" style=\\\"color:${addlPhotos.length?'var(--gn)':'var(--g500)'}\\\">${addlPhotos.length?`✓ ${addlPhotos.length} photo(s) added`:'None added'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Mandatory document</div><div class=\\\"rev-val\\\" style=\\\"color:${(submissionDoc||_docExistingUrl)?'var(--gn)':'var(--rd)'}\\\">${(submissionDoc||_docExistingUrl)?'✓ Uploaded':'⚠ Missing — required'}</div></div>`;}·\u001b[39m\n\u001b[31m// SUBMIT\u001b[39m\n\u001b[31masync function submitRecce(){\u001b[39m\n\u001b[31m  if(!submissionDoc&&!_docExistingUrl){toast('Upload mandatory doc first','error');return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('sub-btn');btn.disabled=true;btn.textContent='Saving…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const isEdit=!!(F.editingId);\u001b[39m\n\u001b[31m    const id=isEdit?F.editingId:('RC_'+Date.now()+'_'+Math.random().toString(36).slice(2,6).toUpperCase());\u001b[39m\n\u001b[31m    const sd=getSD();\u001b[39m\n\u001b[31m    const _hub=_recceHubUser();\u001b[39m\n\u001b[31m    const entry={id,timestamp:isEdit?(await dbGet('subs',id))?.timestamp||new Date().toISOString():new Date().toISOString(),editedAt:isEdit?new Date().toISOString():undefined,status:'pending',submittedBy:_hub.empId||null,submittedByName:_hub.name||null,data:{...F,...sd,gpsCoords,frontPhotos:await Promise.all(frontPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),insidePhotos:await Promise.all(insidePhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),videoNote:F.hasVideo&&videoBlob?`Video local (${fmtSz(videoBlob.size)}) — share via WhatsApp`:null,videoCmt:document.getElementById('f-vid-cmt')?.value||'',brandings:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:calcSqft(b.w,b.h),photoB64:b.blob?await b64(b.blob):null,existingUrl:b.existingUrl||null}))),addlPhotos:await Promise.all(addlPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,desc:p.desc,existingUrl:p.existingUrl||null}))),docB64:submissionDoc?await b64(submissionDoc):null,_docExistingUrl:_docExistingUrl||null}};\u001b[39m\n\u001b[31m    entry.campaignId       = _selectedCampaignId || null;\u001b[39m\n\u001b[31m    entry.notifySupervisor = _notifySupervisor   || false;\u001b[39m\n\u001b[31m    await dbPut('subs',entry);\u001b[39m\n\u001b[31m    await dbDel('draft','current');\u001b[39m\n\u001b[31m    toast(isEdit?'Recce updated ✓':'Recce saved ✓','success');\u001b[39m\n\u001b[31m    if(navigator.onLine)syncNow();\u001b[39m\n\u001b[31m    showView('home');loadHome();checkDraft();\u001b[39m\n\u001b[31m  }catch(err){toast('Error: '+err.message,'error');}\u001b[39m\n\u001b[31m  finally{btn.disabled=false;btn.textContent='Submit Recce ✓';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// SYNC\u001b[39m\n\u001b[31masync function syncNow() {\u001b[39m\n\u001b[31m  if (!navigator.onLine) { toast('Offline — sync when back online', 'info'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('sync-btn');\u001b[39m\n\u001b[31m  const SYNC_ICON = '<svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg>Sync';\u001b[39m\n\u001b[31m  if (btn) { btn.innerHTML = '<span class=\\\"spin\\\">↻</span> Syncing'; btn.disabled = true; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const all      = await dbAll('subs');\u001b[39m\n\u001b[31m    const pend     = all.filter(s => s.status === 'pending' || s.status === 'failed');\u001b[39m\n\u001b[31m    const backfill = all.filter(s => s.status === 'synced' && !s.gasAt);\u001b[39m\n\u001b[31m    if (!pend.length && !backfill.length) { toast('All synced ✓', 'success'); return; }·\u001b[39m\n\u001b[31m    const gasUrl = (await cfg('gas-url')) || DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    function fireGas(s) {\u001b[39m\n\u001b[31m      if (!gasUrl) return;\u001b[39m\n\u001b[31m      fetch(gasUrl, { method:'POST', mode:'no-cors',\u001b[39m\n\u001b[31m        body: JSON.stringify({ action:'syncSheet', submission: s }) })\u001b[39m\n\u001b[31m        .catch(() => {});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    let ok = 0;\u001b[39m\n\u001b[31m    for (const s of pend) {\u001b[39m\n\u001b[31m      // Fire Sheet sync (no-cors fire-and-forget — writes row to Google Sheet)\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      // Primary: upload photos → auto-trigger slides → generate report → store in PostgreSQL\u001b[39m\n\u001b[31m      const { ok: pgOk, viewUrl } = await syncToPostgres(s);\u001b[39m\n\u001b[31m      if (pgOk) {\u001b[39m\n\u001b[31m        s.status = 'synced'; s.syncedAt = new Date().toISOString();\u001b[39m\n\u001b[31m        if (viewUrl) s.viewUrl = viewUrl;\u001b[39m\n\u001b[31m        await dbPut('subs', s); ok++;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        s.status = 'failed'; await dbPut('subs', s);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Backfill: entries synced to Postgres but never reached Sheet GAS\u001b[39m\n\u001b[31m    for (const s of backfill) {\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      await dbPut('subs', s);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if (backfill.length) toast(`Sent ${backfill.length} older entries to Sheet`, 'info');·\u001b[39m\n\u001b[31m    await cfg('last-sync', new Date().toISOString());\u001b[39m\n\u001b[31m    if (pend.length) toast(`Synced ${ok}/${pend.length}`, ok === pend.length ? 'success' : 'error');\u001b[39m\n\u001b[31m    loadHome();\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.innerHTML = SYNC_ICON; btn.disabled = false; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN HOME ──────────────────────────────────────────────\u001b[39m\n\u001b[31masync function loadHomeAdmin() {\u001b[39m\n\u001b[31m  // Adapt UI for admin view\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const _sh = document.querySelector('.sh'); if (_sh) _sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = 'All Submissions';\u001b[39m\n\u001b[31m  const slbls = document.querySelectorAll('.slbl');\u001b[39m\n\u001b[31m  if (slbls[0]) slbls[0].textContent = 'Showing';\u001b[39m\n\u001b[31m  if (slbls[1]) slbls[1].textContent = 'Agents';·\u001b[39m\n\u001b[31m  // Back-to-menu button for supervisors\u001b[39m\n\u001b[31m  if (_isSupervisor() && !document.getElementById('sup-back-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => { document.getElementById('sup-back-btn').remove(); renderSupLanding(); };\u001b[39m\n\u001b[31m    const content = document.querySelector('#view-home .content');\u001b[39m\n\u001b[31m    content.prepend(bb);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Show filter bar — restore if hidden by renderSupLanding, else inject fresh\u001b[39m\n\u001b[31m  const _existingFb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (_existingFb) { _existingFb.style.display = ''; }\u001b[39m\n\u001b[31m  if (!_existingFb) {\u001b[39m\n\u001b[31m    const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m    const fb = document.createElement('div');\u001b[39m\n\u001b[31m    fb.id = 'admin-filter-bar';\u001b[39m\n\u001b[31m    fb.className = 'af-bar';\u001b[39m\n\u001b[31m    fb.innerHTML =\u001b[39m\n\u001b[31m      `<div class=\\\"af-grid\\\">\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-agent\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Agents</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-brand\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Brands</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-client\\\" onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Clients</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-period\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">All Time</option>\u001b[39m\n\u001b[31m          <option value=\\\"7\\\">Last 7 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"30\\\">Last 30 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"90\\\">Last 3 months</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-group\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"date\\\">Sort: Recent</option>\u001b[39m\n\u001b[31m          <option value=\\\"agent\\\">Group: Agent</option>\u001b[39m\n\u001b[31m          <option value=\\\"brand\\\">Group: Brand</option>\u001b[39m\n\u001b[31m          <option value=\\\"client\\\">Group: Client</option>\u001b[39m\n\u001b[31m          <option value=\\\"city\\\">Group: City</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m        <input class=\\\"af-inp\\\" id=\\\"af-search\\\" type=\\\"text\\\" placeholder=\\\"🔍 Search store or city…\\\" oninput=\\\"renderAdminList()\\\" style=\\\"flex:1;min-width:120px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"del-toggle-btn\\\" id=\\\"del-toggle-btn\\\" onclick=\\\"toggleDeletedView()\\\" style=\\\"flex-shrink:0\\\">📋 View Deleted</button>\u001b[39m\n\u001b[31m        ${_isSupervisor() ? `<button class=\\\"del-toggle-btn\\\" id=\\\"pending-job-btn\\\" onclick=\\\"togglePendingJobView()\\\" style=\\\"flex-shrink:0;background:#fef3c7;color:#92400e;border-color:#f59e0b\\\">⚑ Unlinked <span id=\\\"pending-job-count\\\" style=\\\"font-weight:900\\\"></span></button>` : ''}\u001b[39m\n\u001b[31m        ${_adminUnlocked ? `<button class=\\\"del-toggle-btn\\\" id=\\\"regen-rpt-btn\\\" onclick=\\\"regenAllReports()\\\" style=\\\"flex-shrink:0\\\">&#x21BB; Regen Reports</button>` : ''}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    sh.parentNode.insertBefore(fb, sh);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Fetch\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  list.innerHTML = '<div style=\\\"text-align:center;padding:40px\\\"><div class=\\\"spinner\\\"></div></div>';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?order=submitted_at.desc&limit=500`, { headers: _RC_READ });\u001b[39m\n\u001b[31m    _adminRows = resp.ok ? await resp.json() : [];\u001b[39m\n\u001b[31m    document.getElementById('stat-total').textContent = _adminRows.length;\u001b[39m\n\u001b[31m    if (resp.ok) {\u001b[39m\n\u001b[31m      const now = new Date();\u001b[39m\n\u001b[31m      document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m        'Loaded ' + now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Populate agent dropdown\u001b[39m\n\u001b[31m    const agents = [...new Set(_adminRows.map(r => r.submitted_by).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-agent').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Agents (${agents.length})</option>` +\u001b[39m\n\u001b[31m      agents.map(a => `<option value=\\\"${a}\\\">${a}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate brand dropdown\u001b[39m\n\u001b[31m    const brands = [...new Set(_adminRows.map(r => r.brand).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-brand').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Brands (${brands.length})</option>` +\u001b[39m\n\u001b[31m      brands.map(b => `<option value=\\\"${b}\\\">${b}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate client dropdown\u001b[39m\n\u001b[31m    const clients = [...new Set(_adminRows.map(r => r.client_name).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-client').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Clients (${clients.length})</option>` +\u001b[39m\n\u001b[31m      clients.map(c => `<option value=\\\"${c}\\\">${c}</option>`).join('');·\u001b[39m\n\u001b[31m    // Update pending-job count badge\u001b[39m\n\u001b[31m    const unlinkedCount = _adminRows.filter(r => !r.deleted_at && !r.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinkedCount ? `(${unlinkedCount})` : '';·\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">⚠️</div><div class=\\\"empty-txt\\\">Could not load — check connection</div></div>';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction togglePendingJobView() {\u001b[39m\n\u001b[31m  _pendingJobFilter = !_pendingJobFilter;\u001b[39m\n\u001b[31m  _showDeletedView  = false;\u001b[39m\n\u001b[31m  const btn = document.getElementById('pending-job-btn');\u001b[39m\n\u001b[31m  if (btn) btn.style.background = _pendingJobFilter ? '#f59e0b' : '#fef3c7';\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function openLinkJobModal(subId, storeName) {\u001b[39m\n\u001b[31m  _linkJobSubId = subId;\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  const storeEl = document.getElementById('link-job-store');\u001b[39m\n\u001b[31m  const sel = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  if (!modal) return;\u001b[39m\n\u001b[31m  if (storeEl) storeEl.textContent = storeName || subId;\u001b[39m\n\u001b[31m  if (errEl) errEl.textContent = '';\u001b[39m\n\u001b[31m  // Load campaigns into dropdown\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (!_campaignList.length) {\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m      _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  if (sel) {\u001b[39m\n\u001b[31m    sel.innerHTML = '<option value=\\\"\\\">— Select campaign —</option>' +\u001b[39m\n\u001b[31m      _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  modal.style.display = 'flex';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeLinkJobModal() {\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  if (modal) modal.style.display = 'none';\u001b[39m\n\u001b[31m  _linkJobSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function saveLinkJob() {\u001b[39m\n\u001b[31m  const sel    = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl  = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  const campId = sel?.value || '';\u001b[39m\n\u001b[31m  if (!campId) { if (errEl) errEl.textContent = 'Select a campaign'; return; }\u001b[39m\n\u001b[31m  if (!_linkJobSubId) return;\u001b[39m\n\u001b[31m  const btn = document.querySelector('#modal-link-job button[onclick=\\\"saveLinkJob()\\\"]');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Linking…'; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(_linkJobSubId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ campaign_id: campId }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Patch failed');\u001b[39m\n\u001b[31m    // Update local cache\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === _linkJobSubId);\u001b[39m\n\u001b[31m    if (idx >= 0) _adminRows[idx].campaign_id = campId;\u001b[39m\n\u001b[31m    // Update pending count badge\u001b[39m\n\u001b[31m    const unlinked = _adminRows.filter(x => !x.deleted_at && !x.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinked ? `(${unlinked})` : '';\u001b[39m\n\u001b[31m    closeLinkJobModal();\u001b[39m\n\u001b[31m    toast('Job linked ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    if (errEl) errEl.textContent = 'Failed to link — try again';\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.disabled = false; btn.textContent = '🔗 Link Job'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAdminList() {\u001b[39m\n\u001b[31m  const agent  = document.getElementById('af-agent')?.value  || '';\u001b[39m\n\u001b[31m  const brand  = document.getElementById('af-brand')?.value  || '';\u001b[39m\n\u001b[31m  const period = document.getElementById('af-period')?.value || '';\u001b[39m\n\u001b[31m  const search = (document.getElementById('af-search')?.value || '').toLowerCase().trim();\u001b[39m\n\u001b[31m  const group  = document.getElementById('af-group')?.value  || 'date';·\u001b[39m\n\u001b[31m  // Pending-job filter overrides deleted/normal modes\u001b[39m\n\u001b[31m  let rows;\u001b[39m\n\u001b[31m  if (_pendingJobFilter) {\u001b[39m\n\u001b[31m    rows = _adminRows.filter(r => !r.deleted_at && !r.campaign_id);\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows = _showDeletedView\u001b[39m\n\u001b[31m      ? _adminRows.filter(r => r.deleted_at)\u001b[39m\n\u001b[31m      : _adminRows.filter(r => !r.deleted_at);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const client = document.getElementById('af-client')?.value || '';\u001b[39m\n\u001b[31m  if (agent)  rows = rows.filter(r => r.submitted_by === agent);\u001b[39m\n\u001b[31m  if (brand)  rows = rows.filter(r => r.brand === brand);\u001b[39m\n\u001b[31m  if (client) rows = rows.filter(r => r.client_name === client);\u001b[39m\n\u001b[31m  if (search) rows = rows.filter(r => (r.store_name||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.city||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.client_name||'').toLowerCase().includes(search));\u001b[39m\n\u001b[31m  if (period && !_showDeletedView) {\u001b[39m\n\u001b[31m    const cut = new Date(); cut.setDate(cut.getDate() - parseInt(period));\u001b[39m\n\u001b[31m    rows = rows.filter(r => new Date(r.submitted_at) >= cut);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const uniqueAgents = new Set(rows.map(r => r.submitted_by).filter(Boolean)).size;\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = rows.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = uniqueAgents;\u001b[39m\n\u001b[31m  const deletedCount = _adminRows.filter(r => r.deleted_at).length;\u001b[39m\n\u001b[31m  const delBtn = document.getElementById('del-toggle-btn');\u001b[39m\n\u001b[31m  if (delBtn) {\u001b[39m\n\u001b[31m    if (_showDeletedView) {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 Hide Deleted (${deletedCount})` : '📋 Hide Deleted';\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 View Deleted (${deletedCount})` : '📋 View Deleted';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    delBtn.classList.toggle('active', _showDeletedView);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!rows.length) {\u001b[39m\n\u001b[31m    list.innerHTML = _showDeletedView\u001b[39m\n\u001b[31m      ? '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">✅</div><div class=\\\"empty-txt\\\">No deleted recces</div></div>'\u001b[39m\n\u001b[31m      : '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">🔍</div><div class=\\\"empty-txt\\\">No matching submissions</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (group === 'agent') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.submitted_by||'').localeCompare(b.submitted_by||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.submitted_by || 'Unknown';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">👤 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'brand') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.brand||'').localeCompare(b.brand||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.brand || 'No Brand';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🏷 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'client') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.client_name||'').localeCompare(b.client_name||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.client_name || 'No Client';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🤝 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'city') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.city||'').localeCompare(b.city||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.city || 'No City';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">📍 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows.sort((a,b) => new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    rows.forEach(r => { html += adminCard(r); });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminCard(r) {\u001b[39m\n\u001b[31m  const dt    = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds    = dt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m  const tm    = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const photos = (r.front_photos||0) + (r.inside_photos||0) + (r.addl_photos||0);\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const canDelete  = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const canArchive = _RECCE_CFG_ADMINS.includes(hub?.empId) && !r.client_archived;·\u001b[39m\n\u001b[31m  // Client status badge\u001b[39m\n\u001b[31m  const clientStatusMap = {\u001b[39m\n\u001b[31m    approved:              {t:'✓ Approved',    s:'color:#166534;background:#dcfce7;border:1px solid #86efac'},\u001b[39m\n\u001b[31m    rejected:              {t:'✕ Rejected',    s:'color:#991b1b;background:#fee2e2;border:1px solid #fca5a5'},\u001b[39m\n\u001b[31m    approved_with_changes: {t:'✎ Approved w/ Comments', s:'color:#92400e;background:#fef3c7;border:1px solid #fcd34d'},\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const csCfg = clientStatusMap[r.client_status];\u001b[39m\n\u001b[31m  const clientStatusBadge = csCfg\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;${csCfg.s}\\\">${csCfg.t}</span>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const archiveBadge = r.client_archived\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;color:#475569;background:#f1f5f9;border:1px solid #cbd5e1\\\">⬚ Client hidden</span>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  if (r.deleted_at) {\u001b[39m\n\u001b[31m    const delDt = new Date(r.deleted_at);\u001b[39m\n\u001b[31m    const delDs = delDt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m    const reasonLabel = r.deletion_reason === 'wrong' ? 'Wrong' : r.deletion_reason === 'duplicate' ? 'Duplicate' : 'Test';\u001b[39m\n\u001b[31m    return `<div class=\\\"asc deleted-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m        <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m            <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds}</span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m          <span class=\\\"del-reason-tag\\\">❌ ${reasonLabel}</span>\u001b[39m\n\u001b[31m          <div class=\\\"del-by-txt\\\">by ${r.deleted_by||'?'} · ${delDs}</div>\u001b[39m\n\u001b[31m          ${canDelete ? `<button class=\\\"restore-btn\\\" onclick=\\\"event.stopPropagation();restoreRecce('${r.sub_id}')\\\">↩ Restore</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Submitted by ${r.submitted_by||'?'}</div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const chips = [\u001b[39m\n\u001b[31m    photos > 0   ? `📷 ${photos} photo${photos!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.has_video  ? '🎥 Video' : null,\u001b[39m\n\u001b[31m    r.has_branding ? `🪧 ${r.branding_count} branding${r.branding_count!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.city       ? `📍 ${r.city}` : (r.address ? `📍 ${r.address}` : null),\u001b[39m\n\u001b[31m    r.view_url   ? '👁 View available' : null,\u001b[39m\n\u001b[31m  ].filter(Boolean);·\u001b[39m\n\u001b[31m  const delBtnHtml = canDelete\u001b[39m\n\u001b[31m    ? `<button class=\\\"del-btn\\\" onclick=\\\"event.stopPropagation();openDeleteModal('${r.sub_id}')\\\" title=\\\"Delete recce\\\">🗑</button>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const editReqHtml = r.edit_assigned_to\u001b[39m\n\u001b[31m    ? `<span class=\\\"edit-req-badge\\\">✏ Edit sent to ${r.edit_assigned_to}</span>`\u001b[39m\n\u001b[31m    : (_isSupervisor()\u001b[39m\n\u001b[31m        ? `<button class=\\\"req-edit-btn\\\" onclick=\\\"event.stopPropagation();openEditRequestModal('${r.sub_id}')\\\">✏ Request Edit</button>`\u001b[39m\n\u001b[31m        : '');·\u001b[39m\n\u001b[31m  const editRow = editReqHtml\u001b[39m\n\u001b[31m    ? `<div style=\\\"margin-top:6px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">${editReqHtml}</div>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const showPdfBtn = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m  const pdfClass = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m  const pdfLabel = '📄 PDF';\u001b[39m\n\u001b[31m  const linkJobBtn = (_pendingJobFilter && _isSupervisor() && !r.campaign_id)\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:#f59e0b;color:#000;border-color:#f59e0b;font-weight:700\\\" onclick=\\\"event.stopPropagation();openLinkJobModal('${r.sub_id}','${(r.store_name||'Unknown').replace(/'/g,'\\\\\\\\\\\\'')}')\\\">🔗 Link Job</button>`\u001b[39m\n\u001b[31m    : (r.campaign_id ? `<span style=\\\"font-size:10px;color:var(--g400);align-self:center\\\">🔗 ${r.campaign_id}</span>` : '');\u001b[39m\n\u001b[31m  const archiveBtn = canArchive\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:rgba(99,102,241,.08);border-color:var(--nv);color:var(--nv)\\\" onclick=\\\"event.stopPropagation();archiveRecce('${r.sub_id}')\\\">⛚ Archive</button>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const btnsRow = `<div class=\\\"rpt-btns\\\">\u001b[39m\n\u001b[31m    <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openAdminRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m    ${showPdfBtn ? `<button class=\\\"${pdfClass}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">${pdfLabel}</button>` : ''}\u001b[39m\n\u001b[31m    ${linkJobBtn}\u001b[39m\n\u001b[31m    ${archiveBtn}\u001b[39m\n\u001b[31m  </div>`;·\u001b[39m\n\u001b[31m  return `<div class=\\\"asc\\\">\u001b[39m\n\u001b[31m    <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m      <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m          ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          ${r.client_name&&r.client_name!==r.brand?`<span class=\\\"client-tag\\\">🤝 ${r.client_name}</span>`:''}\u001b[39m\n\u001b[31m          <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds} · ${tm}</span>\u001b[39m\n\u001b[31m          ${clientStatusBadge}\u001b[39m\n\u001b[31m          ${archiveBadge}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <span class=\\\"asc-agent\\\">👤 ${r.submitted_by||'?'}</span>\u001b[39m\n\u001b[31m        ${delBtnHtml}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    ${chips.length?`<div class=\\\"asc-chips\\\">${chips.map(c=>`<span class=\\\"asc-chip\\\">${c}</span>`).join('')}</div>`:''}\u001b[39m\n\u001b[31m    ${editRow}\u001b[39m\n\u001b[31m    ${btnsRow}\u001b[39m\n\u001b[31m  </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _ensurePdfOverlay() {\u001b[39m\n\u001b[31m  if (document.getElementById('pdf-wait-ov')) return;\u001b[39m\n\u001b[31m  const ov = document.createElement('div');\u001b[39m\n\u001b[31m  ov.id = 'pdf-wait-ov';\u001b[39m\n\u001b[31m  ov.innerHTML = '<div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Generating PDF…</div><div class=\\\"po-sub\\\" id=\\\"pw-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"pw-pfill\\\"></div></div>';\u001b[39m\n\u001b[31m  document.body.appendChild(ov);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _showPdfOverlay(msg) {\u001b[39m\n\u001b[31m  _ensurePdfOverlay();\u001b[39m\n\u001b[31m  document.getElementById('pw-sub').textContent = msg || '';\u001b[39m\n\u001b[31m  document.getElementById('pw-pfill').style.width = '0%';\u001b[39m\n\u001b[31m  document.getElementById('pdf-wait-ov').style.display = 'flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _hidePdfOverlay() {\u001b[39m\n\u001b[31m  const ov = document.getElementById('pdf-wait-ov');\u001b[39m\n\u001b[31m  if (ov) ov.style.display = 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function openPdf(subId, pdfUrl, viewUrl) {\u001b[39m\n\u001b[31m  if (pdfUrl) { window.open(pdfUrl, '_blank'); return; }\u001b[39m\n\u001b[31m  if (!viewUrl) {\u001b[39m\n\u001b[31m    toast('Report view not available yet — please try after the report is generated.', 'info');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _showPdfOverlay('Requesting PDF generation…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type': 'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({type: 'regen-pdf', subId, viewUrl})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  let attempts = 0;\u001b[39m\n\u001b[31m  const MAX = 24;\u001b[39m\n\u001b[31m  const poll = async () => {\u001b[39m\n\u001b[31m    attempts++;\u001b[39m\n\u001b[31m    const pct = Math.min(88, Math.round(attempts / MAX * 88));\u001b[39m\n\u001b[31m    document.getElementById('pw-pfill').style.width = pct + '%';\u001b[39m\n\u001b[31m    const left = Math.ceil((MAX - attempts) * 5);\u001b[39m\n\u001b[31m    document.getElementById('pw-sub').textContent = 'Checking… (' + left + 's remaining)';\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const res = await fetch('/db/submissions?sub_id=eq.' + subId + '&select=pdf_url', {\u001b[39m\n\u001b[31m        headers: {'Content-Profile': 'recce', 'Accept-Profile': 'recce'}\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      const rows = await res.json();\u001b[39m\n\u001b[31m      if (rows && rows[0] && rows[0].pdf_url) {\u001b[39m\n\u001b[31m        document.getElementById('pw-pfill').style.width = '100%';\u001b[39m\n\u001b[31m        setTimeout(() => { _hidePdfOverlay(); window.open(rows[0].pdf_url, '_blank'); }, 400);\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(_) {}\u001b[39m\n\u001b[31m    if (attempts >= MAX) { _hidePdfOverlay(); toast('PDF generation timed out. Please try again later.', 'error'); return; }\u001b[39m\n\u001b[31m    setTimeout(poll, 5000);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  setTimeout(poll, 4000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openAdminRecce(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];·\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">\u001b[39m\n\u001b[31m         📍 View on Google Maps (${Number(r.gps_lat).toFixed(4)}, ${Number(r.gps_lng).toFixed(4)})\u001b[39m\n\u001b[31m       </a>` : '';·\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} ft × ${b.h||'?'} ft · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos not yet available — field agent must re-sync from their device to upload view\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Submission Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">👤 ${r.submitted_by||'Unknown'}</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            ${meta.videoCmt?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500);font-size:12px\\\">${meta.videoCmt}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m          ${(()=>{\u001b[39m\n\u001b[31m            const hub2 = _recceHubUser();\u001b[39m\n\u001b[31m            const isHP = _RECCE_CFG_ADMINS.includes(hub2?.empId);\u001b[39m\n\u001b[31m            const csMap = {\u001b[39m\n\u001b[31m              approved:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#166534;background:#dcfce7\\\">✓ Approved</span>',\u001b[39m\n\u001b[31m              rejected:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#991b1b;background:#fee2e2\\\">✕ Rejected</span>',\u001b[39m\n\u001b[31m              approved_with_changes: '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#92400e;background:#fef3c7\\\">✎ Approved w/ Comments</span>',\u001b[39m\n\u001b[31m            };\u001b[39m\n\u001b[31m            const csBadge = csMap[r.client_status] || '';\u001b[39m\n\u001b[31m            const approvedAt = r.client_approved_at\u001b[39m\n\u001b[31m              ? new Date(r.client_approved_at).toLocaleString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit',timeZone:'Asia/Kolkata'})\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const pdfLink = r.client_approval_pdf_url\u001b[39m\n\u001b[31m              ? `<a href=\\\"${r.client_approval_pdf_url}\\\" target=\\\"_blank\\\" style=\\\"font-size:12px;color:var(--or);text-decoration:none\\\">⬇ Approval PDF</a>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const archAct = isHP && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveRecce('${r.sub_id}')\\\" style=\\\"font-size:12px;color:var(--nv);background:none;border:1px solid var(--nv);border-radius:6px;padding:4px 10px;cursor:pointer\\\">⦽ Archive from client</button>`\u001b[39m\n\u001b[31m              : (r.client_archived ? '<span style=\\\"font-size:11px;color:var(--g400)\\\">⦽ Hidden from client</span>' : '');\u001b[39m\n\u001b[31m            const campAct = isHP && r.campaign_id && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveAllForCampaign('${r.campaign_id}')\\\" style=\\\"font-size:11px;color:#991b1b;background:none;border:1px solid #fca5a5;border-radius:6px;padding:3px 8px;cursor:pointer\\\">Archive ALL for ${r.campaign_id}</button>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            if (!csBadge && !pdfLink && !archAct) return '';\u001b[39m\n\u001b[31m            return `<div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m              <div class=\\\"ardl-lbl\\\">Client Approval</div>\u001b[39m\n\u001b[31m              ${csBadge ? `<div style=\\\"margin-bottom:5px\\\">${csBadge}${approvedAt ? ' <span style=\\\"font-size:11px;color:var(--g400)\\\">' + approvedAt + '</span>' : ''}</div>` : ''}\u001b[39m\n\u001b[31m              ${r.client_comment ? `<div style=\\\"font-size:12px;color:var(--g600);background:var(--g50);border-radius:6px;padding:7px 10px;margin-bottom:5px\\\">\\\"${r.client_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m              ${pdfLink ? `<div style=\\\"margin-bottom:4px\\\">${pdfLink}</div>` : ''}\u001b[39m\n\u001b[31m              ${archAct ? `<div style=\\\"margin-bottom:4px\\\">${archAct}</div>` : ''}\u001b[39m\n\u001b[31m              ${campAct ? `<div>${campAct}</div>` : ''}\u001b[39m\n\u001b[31m            </div>`;\u001b[39m\n\u001b[31m          })()}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeAdminDetail() {\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveRecce(subId) {\u001b[39m\n\u001b[31m  if (!confirm('Archive this recce from client view? The client will no longer see it.')) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(subId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) Object.assign(_adminRows[idx], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    toast('Archived from client view ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveAllForCampaign(campaignId) {\u001b[39m\n\u001b[31m  if (!confirm(`Archive ALL recces for campaign \\\"${campaignId}\\\" from client view?\\\\nClients will no longer see any recce from this campaign.`)) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?campaign_id=eq.${encodeURIComponent(campaignId)}&client_archived=eq.false`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    _adminRows.forEach((row, i) => {\u001b[39m\n\u001b[31m      if (row.campaign_id === campaignId) Object.assign(_adminRows[i], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    toast(`All recces for ${campaignId} archived ✓`, 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function regenAllReports() {\u001b[39m\n\u001b[31m  if (!_adminUnlocked) { toast('Admin access required', 'error'); return; }\u001b[39m\n\u001b[31m  const rows = _adminRows.filter(r => !r.deleted_at && r.photo_urls);\u001b[39m\n\u001b[31m  if (!rows.length) { toast('No synced rows with photos found', 'error'); return; }·\u001b[39m\n\u001b[31m  const btn = document.getElementById('regen-rpt-btn');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Regenerating…'; }\u001b[39m\n\u001b[31m  toast(`Regenerating ${rows.length} reports…`, 'info');·\u001b[39m\n\u001b[31m  let done = 0, failed = 0;\u001b[39m\n\u001b[31m  for (const r of rows) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const photoUrls = typeof r.photo_urls === 'string' ? JSON.parse(r.photo_urls) : (r.photo_urls || {});\u001b[39m\n\u001b[31m      let meta = {};\u001b[39m\n\u001b[31m      try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m      const entry = {\u001b[39m\n\u001b[31m        id: r.sub_id,\u001b[39m\n\u001b[31m        timestamp: r.submitted_at,\u001b[39m\n\u001b[31m        submittedBy: r.submitted_by,\u001b[39m\n\u001b[31m        data: {\u001b[39m\n\u001b[31m          storeName:    r.store_name,\u001b[39m\n\u001b[31m          brand:        r.brand,\u001b[39m\n\u001b[31m          clientName:   r.client_name,\u001b[39m\n\u001b[31m          date:         r.visit_date,\u001b[39m\n\u001b[31m          address:      r.address,\u001b[39m\n\u001b[31m          city:         r.city,\u001b[39m\n\u001b[31m          mobile:       r.mobile,\u001b[39m\n\u001b[31m          gpsCoords:    (r.gps_lat && r.gps_lng) ? { lat: r.gps_lat, lng: r.gps_lng } : null,\u001b[39m\n\u001b[31m          hasVideo:     r.has_video,\u001b[39m\n\u001b[31m          videoNote:    meta.videoNote || '',\u001b[39m\n\u001b[31m          videoCmt:     meta.videoCmt  || '',\u001b[39m\n\u001b[31m          frontPhotos:  (photoUrls.front   || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          insidePhotos: (photoUrls.inside  || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          addlPhotos:   (photoUrls.addl    || []).map(() => ({ desc: '' })),\u001b[39m\n\u001b[31m          brandings:    (meta.brandings    || []),\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      };·\u001b[39m\n\u001b[31m      const html = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m      const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m        method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m        body: JSON.stringify({ type: 'save-view', subId: r.sub_id, html })\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!vResp.ok) { failed++; continue; }\u001b[39m\n\u001b[31m      const vr = await vResp.json();\u001b[39m\n\u001b[31m      if (!vr.success) { failed++; continue; }·\u001b[39m\n\u001b[31m      if (vr.url && vr.url !== r.view_url) {\u001b[39m\n\u001b[31m        await fetch(`${_RC_BASE}/submissions?sub_id=eq.${r.sub_id}`, {\u001b[39m\n\u001b[31m          method: 'PATCH', headers: _RC_WRITE,\u001b[39m\n\u001b[31m          body: JSON.stringify({ view_url: vr.url })\u001b[39m\n\u001b[31m        });\u001b[39m\n\u001b[31m        const idx = _adminRows.findIndex(x => x.sub_id === r.sub_id);\u001b[39m\n\u001b[31m        if (idx >= 0) _adminRows[idx].view_url = vr.url;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      done++;\u001b[39m\n\u001b[31m    } catch(e) { failed++; }\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = false; btn.textContent = '↻ Regen Reports'; }\u001b[39m\n\u001b[31m  toast(`Done: ${done} regenerated${failed ? `, ${failed} failed` : ''}`, done > 0 ? 'success' : 'error');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction toggleDeletedView() {\u001b[39m\n\u001b[31m  _showDeletedView = !_showDeletedView;\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openDeleteModal(subId) {\u001b[39m\n\u001b[31m  _pendingDeleteId = subId;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  const sub = document.getElementById('del-modal-sub');\u001b[39m\n\u001b[31m  if (sub) sub.textContent = r ? `Delete: \\\"${r.store_name||'Unknown'}\\\"` : 'Select reason for deletion:';\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectDeleteReason(reason) {\u001b[39m\n\u001b[31m  _pendingDeleteReason = reason;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  document.getElementById('reason-' + reason)?.classList.add('sel');\u001b[39m\n\u001b[31m  document.getElementById('del-confirm-btn').classList.remove('no-reason');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeDeleteModal() {\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingDeleteId = null;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  clearTimeout(_tt);\u001b[39m\n\u001b[31m  document.getElementById('toast').classList.remove('show');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function restoreRecce(subId) {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({ deleted_at: null, deleted_by: null, deletion_reason: null }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Restore failed: ' + r.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_at = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_by = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deletion_reason = null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    toast('Recce restored ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Restore failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmDelete() {\u001b[39m\n\u001b[31m  if (!_pendingDeleteReason) {\u001b[39m\n\u001b[31m    const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m    btn.style.animation = 'none';\u001b[39m\n\u001b[31m    btn.offsetHeight; // reflow\u001b[39m\n\u001b[31m    btn.style.animation = 'shake .35s ease';\u001b[39m\n\u001b[31m    toast('Select a reason first', 'error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if (!_pendingDeleteId) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Deleting…';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      // Hard delete — no audit trail\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'DELETE',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Delete failed: ' + r.status);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Soft delete — stamp deleted_at, deleted_by, deletion_reason\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'PATCH',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m        body: JSON.stringify({\u001b[39m\n\u001b[31m          deleted_at: new Date().toISOString(),\u001b[39m\n\u001b[31m          deleted_by: hub.empId,\u001b[39m\n\u001b[31m          deletion_reason: _pendingDeleteReason,\u001b[39m\n\u001b[31m        }),\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Update failed: ' + r.status);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Remove or update in local cache\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      _adminRows = _adminRows.filter(x => x.sub_id !== _pendingDeleteId);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      const idx = _adminRows.findIndex(x => x.sub_id === _pendingDeleteId);\u001b[39m\n\u001b[31m      if (idx >= 0) {\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_at = new Date().toISOString();\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_by = hub.empId;\u001b[39m\n\u001b[31m        _adminRows[idx].deletion_reason = _pendingDeleteReason;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeDeleteModal();\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast('Recce deleted', 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Delete failed', 'error');\u001b[39m\n\u001b[31m    btn.classList.remove('no-reason');\u001b[39m\n\u001b[31m    btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openMyServerRecce(subId) {\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  // No view yet — show metadata modal (same layout as admin detail)\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta==='string' ? JSON.parse(r.meta) : (r.meta||{}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">📍 View on Google Maps</a>` : '';\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} × ${b.h||'?'} in · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos will appear after next sync from original device\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Visit Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupLanding() {\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = 'none';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = 'none';\u001b[39m\n\u001b[31m  // Clean up admin + create-mode UI\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('sup-back-btn')?.remove();\u001b[39m\n\u001b[31m  document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m  _supCreateMode = false;\u001b[39m\n\u001b[31m  // Resume-wrap may have been hidden by loadHomeAdmin() — restore it so draft banner shows\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = '';\u001b[39m\n\u001b[31m  document.getElementById('sub-list').innerHTML = `\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorViewAll()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0f9ff\\\">📋</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">View All Recces</span><span class=\\\"hi-txt\\\">सभी रेकी देखें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">Browse & review submissions from all agents</span><span class=\\\"hi-txt\\\">सभी एजेंट की सबमिशन देखें</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorCreateView()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0fdf4\\\">✍️</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">Create Recce</span><span class=\\\"hi-txt\\\">नई रेकी बनाएं</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">My submissions + New Recce button</span><span class=\\\"hi-txt\\\">मेरी सबमिशन + नई रेकी</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorViewAll() {\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  await loadHomeAdmin();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorCreateView() {\u001b[39m\n\u001b[31m  _supCreateMode = true;\u001b[39m\n\u001b[31m  // Restore field-agent UI\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh'); if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = t('My Submissions','मेरी सबमिशन');\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar'); if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  // Add Back to Menu button (once)\u001b[39m\n\u001b[31m  if (!document.getElementById('sup-back-create-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-create-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => {\u001b[39m\n\u001b[31m      _supCreateMode = false;\u001b[39m\n\u001b[31m      document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m      renderSupLanding();\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    document.querySelector('#view-home .content').prepend(bb);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  await loadHome();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadHome() {\u001b[39m\n\u001b[31m  if (_isSupervisor() && !_supCreateMode) { renderSupLanding(); return; }\u001b[39m\n\u001b[31m  if (_adminUnlocked && !_supCreateMode) { await loadHomeAdmin(); return; }·\u001b[39m\n\u001b[31m  const all  = await dbAll('subs');\u001b[39m\n\u001b[31m  const sy   = all.filter(s => s.status === 'synced').length;\u001b[39m\n\u001b[31m  const pe   = all.filter(s => s.status !== 'synced').length;·\u001b[39m\n\u001b[31m  // Fetch this agent's submissions from server — works on any device\u001b[39m\n\u001b[31m  let serverOnly = [];\u001b[39m\n\u001b[31m  let editAssigned = [];\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (navigator.onLine && hub?.empId) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?submitted_by=eq.${encodeURIComponent(hub.empId)}&order=submitted_at.desc&limit=200`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp.ok) {\u001b[39m\n\u001b[31m        const rows = await resp.json();\u001b[39m\n\u001b[31m        const localIds = new Set(all.map(s => s.id));\u001b[39m\n\u001b[31m        serverOnly = rows.filter(r => !localIds.has(r.sub_id));\u001b[39m\n\u001b[31m        _myServerRows = serverOnly;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m    // Fetch edit-assigned recces (supervisor assigned this creator to edit)\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp2 = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?edit_assigned_to=eq.${encodeURIComponent(hub.empId)}&deleted_at=is.null&order=submitted_at.desc`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp2.ok) editAssigned = await resp2.json();\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = sy + serverOnly.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = pe;\u001b[39m\n\u001b[31m  document.getElementById('stat-total').textContent   = all.length + serverOnly.length;·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!all.length && !serverOnly.length && !editAssigned.length) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">📋</div><div class=\\\"empty-txt\\\">No submissions yet</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const icos   = { synced:'✅', pending:'⏳', failed:'❌' };\u001b[39m\n\u001b[31m  const sorted = [...all].sort((a,b) => new Date(b.timestamp) - new Date(a.timestamp)).slice(0, 50);·\u001b[39m\n\u001b[31m  const localCards = sorted.map(s => {\u001b[39m\n\u001b[31m    const dt = new Date(s.timestamp);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const viewBtn = s.viewUrl\u001b[39m\n\u001b[31m      ? `<button class=\\\"edit-btn-sm\\\" onclick=\\\"window.open('${s.viewUrl}','_blank')\\\">👁 View</button>`\u001b[39m\n\u001b[31m      : `<button class=\\\"edit-btn-sm\\\" onclick=\\\"viewRecce('${s.id}')\\\">👁 View</button>`;\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico ${s.status}\\\">${icos[s.status]||'📋'}</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${s.data.storeName||'Unknown'} · ${s.data.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${s.data.address||''}</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge ${s.status}\\\">${s.status}</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          ${viewBtn}\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"editRecce('${s.id}')\\\" style=\\\"background:#fff7ed;border-color:var(--or);color:var(--or)\\\">✏ Edit</button>\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"makeSlides('${s.id}')\\\" style=\\\"background:#eff6ff;border-color:#3b82f6;color:#1d4ed8\\\">📊 Slides</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const serverCards = serverOnly.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const showPdf = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m    const pdfCls = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico synced\\\">✅</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\" style=\\\"min-width:0;flex:1\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"rpt-btns\\\" style=\\\"margin-top:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openMyServerRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m          ${showPdf ? `<button class=\\\"${pdfCls}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">📄 PDF</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge synced\\\">synced</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const editAssignedCards = editAssigned.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    return `<div class=\\\"edit-req-card\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:26px;flex-shrink:0\\\">✏</div>\u001b[39m\n\u001b[31m      <div class=\\\"edit-req-card-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-meta\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        ${r.edit_comment ? `<div class=\\\"edit-req-cmt\\\">\\\"${r.edit_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:10px;display:flex;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"startCreatorEdit('${r.sub_id}')\\\" style=\\\"padding:9px 16px;font-size:13px;font-weight:600\\\">✏ Edit this Recce</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (editAssignedCards.length) {\u001b[39m\n\u001b[31m    html += `<div class=\\\"edit-req-section-hdr\\\">✏ Edit Requested (${editAssignedCards.length})</div>`;\u001b[39m\n\u001b[31m    html += editAssignedCards.join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  html += localCards.join('') + serverCards.join('');\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m  const ls = await cfg('last-sync');\u001b[39m\n\u001b[31m  if (ls) {\u001b[39m\n\u001b[31m    const d = new Date(ls);\u001b[39m\n\u001b[31m    document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m      'Synced ' + d.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// RESET\u001b[39m\n\u001b[31mfunction startNewRecce(){F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  if(geoStampEnabled)autoRequestGPS();\u001b[39m\n\u001b[31m['f-date','f-brand','f-store','f-addr','f-mobile','f-client-other'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';});\u001b[39m\n\u001b[31m_selectedClient='';_clientOtherMode=false;\u001b[39m\n\u001b[31m_selectedCampaignId=null;_notifySupervisor=false;_brandingLocked=false;\u001b[39m\n\u001b[31mconst _camSel=document.getElementById('f-campaign-id');if(_camSel)_camSel.value='';\u001b[39m\n\u001b[31mconst _camNotice=document.getElementById('campaign-notify-msg');if(_camNotice)_camNotice.style.display='none';\u001b[39m\n\u001b[31mloadCampaignsForForm();\u001b[39m\n\u001b[31mrenderClientChips();\u001b[39m\n\u001b[31mdocument.getElementById('f-date').value=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31m// Block future dates\u001b[39m\n\u001b[31mdocument.getElementById('f-date').max=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31mdocument.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('pick-trigger-wrap').style.display=stores.length?'block':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').style.display=stores.length?'flex':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31mdocument.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31mdocument.getElementById('manual-fields').style.display=stores.length?'none':'block';\u001b[39m\n\u001b[31mdocument.getElementById('gps-status').textContent='';\u001b[39m\n\u001b[31m['vid-yes','vid-no','br-yes','br-no'].forEach(id=>document.getElementById(id).classList.remove('sel'));\u001b[39m\n\u001b[31mdocument.getElementById('vid-sec').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('vid-slot').innerHTML=`<div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('br-add').style.display='none';document.getElementById('br-items').innerHTML='';\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').classList.remove('filled');\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').innerHTML=`<div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('brand-selector').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('sc-missing').style.display='none';\u001b[39m\n\u001b[31mpopulateBrandDropdown();\u001b[39m\n\u001b[31mrenderPhotos('front');renderPhotos('inside');renderAddl();updAvailTag();showView('form-store');}\u001b[39m\n\u001b[31mfunction exitForm(){\u001b[39m\n\u001b[31m  // Show safe exit dialog instead of confirm\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitSaveAndLeave(){\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m  checkDraft();\u001b[39m\n\u001b[31m  toast('Draft saved — tap Resume to continue','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitDiscard(){\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];\u001b[39m\n\u001b[31m  videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  dbDel('draft','current');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitCancel(){document.getElementById('exit-dialog').classList.remove('open');}\u001b[39m\n\u001b[31mfunction showView(n){document.querySelectorAll('.view').forEach(v=>v.classList.remove('active'));const t=document.getElementById('view-'+n);if(t){t.classList.add('active');window.scrollTo(0,0);}}\u001b[39m\n\u001b[31mlet _tt;\u001b[39m\n\u001b[31mfunction toast(msg,type='info'){const el=document.getElementById('toast');el.textContent=msg;el.className='toast show '+type;clearTimeout(_tt);_tt=setTimeout(()=>el.classList.remove('show'),3000);}\u001b[39m\n\u001b[31mfunction netStatus(){const on=navigator.onLine;const dot=document.getElementById('net-dot');const txt=document.getElementById('net-txt');if(dot)dot.className='sdot '+(on?'on':'off');if(txt)txt.textContent=on?t('Online','ऑनलाइन'):t('Offline — saves locally','ऑफलाइन — स्थानीय रूप से सेव');}\u001b[39m\n\u001b[31masync function loadSettings(){\u001b[39m\n\u001b[31m  // Gas URL: pre-load default if none saved, update preview\u001b[39m\n\u001b[31m  const gu=await cfg('gas-url');\u001b[39m\n\u001b[31m  if(!gu)await cfg('gas-url',DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m  // Admin cfg url\u001b[39m\n\u001b[31m  const acu=await cfg('admin-cfg-url');if(acu&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=acu;\u001b[39m\n\u001b[31m  const su=await cfg('srv-url')||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su)document.getElementById('srv-url').value=su;\u001b[39m\n\u001b[31m  const sc=await cfg('stores');\u001b[39m\n\u001b[31m  if(sc){\u001b[39m\n\u001b[31m    stores=JSON.parse(sc);\u001b[39m\n\u001b[31m    const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m    document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m      `✓ ${stores.length} stores in cache${noBrand?` · ${noBrand} without brand`:''}`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const sf=await cfg('store-files');if(sf){_storeFiles=JSON.parse(sf);renderStoreFileList();}\u001b[39m\n\u001b[31m  const iq=await cfg('img-quality');imgQuality=iq||'compressed';applyQualityUI(imgQuality);\u001b[39m\n\u001b[31m  const gs=await cfg('geo-stamp');geoStampEnabled=(gs===null||gs==='1');applyGeoStampUI();\u001b[39m\n\u001b[31m  const bl=await cfg('brands');if(bl)brands=JSON.parse(bl);\u001b[39m\n\u001b[31m  loadBrandsFromDb();  // async — updates brands + logos from DB in background\u001b[39m\n\u001b[31m  renderBrandManageList();\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m  // Show store upload row + brand add row to supervisors only\u001b[39m\n\u001b[31m  const sur = document.getElementById('store-upload-row');\u001b[39m\n\u001b[31m  if (sur) sur.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const bar = document.getElementById('brand-add-row');\u001b[39m\n\u001b[31m  if (bar) bar.style.display = _isSupervisor() ? 'flex' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction populateBrandDropdown(){\u001b[39m\n\u001b[31m  const sel=document.getElementById('f-brand');if(!sel)return;\u001b[39m\n\u001b[31m  const cur=sel.value;\u001b[39m\n\u001b[31m  sel.innerHTML='<option value=\\\"\\\">Select brand</option>'+brands.map(b=>`<option${cur===b?' selected':''}>${b}</option>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderBrandManageList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('brand-manage-list');if(!el)return;\u001b[39m\n\u001b[31m  const isSup=_isSupervisor();\u001b[39m\n\u001b[31m  el.innerHTML=brands.map((b,i)=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    const logoHtml=logo?`<img src=\\\"${logo}\\\" style=\\\"height:20px;max-width:48px;object-fit:contain;flex-shrink:0;border-radius:3px\\\">`:'';\u001b[39m\n\u001b[31m    const ctrlHtml=isSup?`<div style=\\\"display:flex;gap:2px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"openEditBrandDialog(${i})\\\" style=\\\"background:none;border:none;color:var(--nv);font-size:15px;cursor:pointer;padding:2px 6px\\\" title=\\\"Edit\\\">✏</button>\u001b[39m\n\u001b[31m      ${brands.length>1?`<button onclick=\\\"confirmRemoveBrand(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:2px 4px\\\">×</button>`:'<span style=\\\"font-size:11px;color:var(--g400);padding:0 6px\\\">Last</span>'}\u001b[39m\n\u001b[31m    </div>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;min-width:0\\\">${logoHtml}<span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${b}</span></div>\u001b[39m\n\u001b[31m      ${ctrlHtml}\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function addBrandToList(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const inp=document.getElementById('brand-add-inp');\u001b[39m\n\u001b[31m  const val=(inp.value.trim()||'').toUpperCase();\u001b[39m\n\u001b[31m  if(!val){toast('Enter a brand name','error');return;}\u001b[39m\n\u001b[31m  if(brands.some(b=>b.toLowerCase()===val.toLowerCase())){toast(`${val} already in list`,'error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands`,{method:'POST',headers:{..._RC_WRITE,'Prefer':'return=minimal'},body:JSON.stringify({name:val,sort_order:99})});\u001b[39m\n\u001b[31m    if(resp.status===409){toast(`${val} already exists in DB`,'error');return;}\u001b[39m\n\u001b[31m    if(!resp.ok){const e=await resp.json().catch(()=>({}));throw new Error(e.message||resp.status);}\u001b[39m\n\u001b[31m    inp.value='';\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${val} added ✓`,'success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Add failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmRemoveBrand(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const name=brands[idx];\u001b[39m\n\u001b[31m  if(brands.length<=1){toast('Need at least one brand','error');return;}\u001b[39m\n\u001b[31m  let count=0;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(name)}&select=sub_id`,{headers:_RC_READ});\u001b[39m\n\u001b[31m    if(r.ok){const rows=await r.json();count=rows.length;}\u001b[39m\n\u001b[31m  }catch(_){}\u001b[39m\n\u001b[31m  const msg=count>0?`Delete \\\"${name}\\\" from brand list?\\\\n(${count} submission${count!==1?'s':''} reference this brand — they keep the name as text.)`:`Delete \\\"${name}\\\" from brand list?`;\u001b[39m\n\u001b[31m  if(!confirm(msg))return;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(name)}`,{method:'DELETE',headers:{'Content-Profile':'recce','Accept-Profile':'recce'}});\u001b[39m\n\u001b[31m    if(!resp.ok&&resp.status!==204){throw new Error(resp.status);}\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${name} removed ✓`,'info');\u001b[39m\n\u001b[31m  }catch(e){toast(`Remove failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadBrandsFromDb(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch('/db/brands?select=name,logo_url&order=sort_order',{\u001b[39m\n\u001b[31m      headers:{'Content-Profile':'recce','Accept-Profile':'recce'}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(!r.ok) return;\u001b[39m\n\u001b[31m    const rows=await r.json();\u001b[39m\n\u001b[31m    if(!rows||!rows.length) return;\u001b[39m\n\u001b[31m    const dbNames=rows.map(r=>r.name);\u001b[39m\n\u001b[31m    const logos={};rows.forEach(r=>{if(r.logo_url)logos[r.name]=r.logo_url;});\u001b[39m\n\u001b[31m    // Merge: DB brands canonical, keep locally-added extras\u001b[39m\n\u001b[31m    const extras=brands.filter(b=>!dbNames.some(n=>n.toLowerCase()===b.toLowerCase()));\u001b[39m\n\u001b[31m    brands=[...dbNames,...extras];\u001b[39m\n\u001b[31m    _brandLogos=logos;\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    // Refresh brand chips if brand-selector is visible\u001b[39m\n\u001b[31m    const bSel=document.getElementById('brand-selector');\u001b[39m\n\u001b[31m    if(bSel&&bSel.style.display!=='none') renderBrandChips();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[brands-db]',e.message);}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction renderBrandChips(){\u001b[39m\n\u001b[31m  const bChips=document.getElementById('brand-chips');if(!bChips)return;\u001b[39m\n\u001b[31m  bChips.innerHTML=brands.map(b=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    return `<div class=\\\"chip brand-chip${F.brand===b?' sel':''}\\\" onclick=\\\"selectStoreBrand('${b.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\">` +\u001b[39m\n\u001b[31m      (logo?`<img src=\\\"${logo}\\\" class=\\\"brand-chip-logo\\\" alt=\\\"\\\">`:'') +\u001b[39m\n\u001b[31m      `<span>${b}</span></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _editBrandIdx=null,_editBrandOld=null;\u001b[39m\n\u001b[31mfunction openEditBrandDialog(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor())return;\u001b[39m\n\u001b[31m  _editBrandIdx=idx;_editBrandOld=brands[idx];\u001b[39m\n\u001b[31m  document.getElementById('be-name').value=brands[idx];\u001b[39m\n\u001b[31m  const logo=_brandLogos[brands[idx]]||'';\u001b[39m\n\u001b[31m  document.getElementById('be-logo').value=logo;\u001b[39m\n\u001b[31m  document.getElementById('be-logo-preview').innerHTML=logo?`<img src=\\\"${logo}\\\" style=\\\"height:28px;object-fit:contain\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Current logo</span>`:'';\u001b[39m\n\u001b[31m  document.getElementById('be-cascade-info').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('brand-edit-modal').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeBrandEditModal(){document.getElementById('brand-edit-modal').classList.remove('open');_editBrandIdx=null;_editBrandOld=null;}\u001b[39m\n\u001b[31mfunction previewBrandLogo(){\u001b[39m\n\u001b[31m  const url=(document.getElementById('be-logo')?.value||'').trim();\u001b[39m\n\u001b[31m  const prev=document.getElementById('be-logo-preview');\u001b[39m\n\u001b[31m  if(prev)prev.innerHTML=url?`<img src=\\\"${url}\\\" style=\\\"height:28px;object-fit:contain\\\" onerror=\\\"this.style.display='none'\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Preview</span>`:'';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveBrandEdit(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const oldName=_editBrandOld;\u001b[39m\n\u001b[31m  const newName=(document.getElementById('be-name').value||'').trim().toUpperCase();\u001b[39m\n\u001b[31m  const newLogo=(document.getElementById('be-logo').value||'').trim();\u001b[39m\n\u001b[31m  if(!newName){toast('Brand name required','error');return;}\u001b[39m\n\u001b[31m  const isRename=newName!==oldName;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // 1. Update recce.brands\u001b[39m\n\u001b[31m    const pResp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m      method:'PATCH',headers:{..._RC_WRITE,'Prefer':'return=minimal'},\u001b[39m\n\u001b[31m      body:JSON.stringify({name:newName,logo_url:newLogo||null})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(pResp.status===409){toast(`\\\"${newName}\\\" already exists`,'error');return;}\u001b[39m\n\u001b[31m    if(!pResp.ok&&pResp.status!==204){const e=await pResp.json().catch(()=>({}));throw new Error(e.message||pResp.status);}\u001b[39m\n\u001b[31m    if(isRename){\u001b[39m\n\u001b[31m      const hub=_recceHubUser();\u001b[39m\n\u001b[31m      // 2. Cascade to submissions\u001b[39m\n\u001b[31m      await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m        method:'PATCH',headers:_RC_WRITE,body:JSON.stringify({brand:newName})\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      // 3. Cascade to stores.json + view HTML files + PDFs\u001b[39m\n\u001b[31m      toast('Cascading rename to reports…','info');\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        const cResp=await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},\u001b[39m\n\u001b[31m          body:JSON.stringify({type:'cascade-rename-brand',oldName,newName,empId:hub?.empId||''})});\u001b[39m\n\u001b[31m        const cRes=cResp.ok?await cResp.json():{};\u001b[39m\n\u001b[31m        const msg=`Brand renamed ✓${cRes.viewsUpdated?` · ${cRes.viewsUpdated} reports re-queued`:''}`;\u001b[39m\n\u001b[31m        closeBrandEditModal();\u001b[39m\n\u001b[31m        await loadBrandsFromDb();\u001b[39m\n\u001b[31m        toast(msg,'success');\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }catch(e){console.warn('[cascade-rename]',e.message);}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeBrandEditModal();\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast('Brand updated ✓','success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Save failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function fetchServerBrands(){\u001b[39m\n\u001b[31m  const url=document.getElementById('brands-url')?.value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    toast('Fetching brands…','info');\u001b[39m\n\u001b[31m    const r=await fetch(url);const j=await r.json();\u001b[39m\n\u001b[31m    const list=Array.isArray(j)?j:j.brands||[];\u001b[39m\n\u001b[31m    if(!list.length){toast('No brands found in response','error');return;}\u001b[39m\n\u001b[31m    brands=list.map(b=>b.toString().toUpperCase());\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    toast(`${brands.length} brands loaded from server`,'success');\u001b[39m\n\u001b[31m  }catch{toast('Failed to fetch — check URL','error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setImgQuality(q){\u001b[39m\n\u001b[31m  imgQuality=q;\u001b[39m\n\u001b[31m  cfg('img-quality',q);\u001b[39m\n\u001b[31m  applyQualityUI(q);\u001b[39m\n\u001b[31m  toast(q==='hd'?'HD Quality selected (~400–600 KB per photo)':'Full Compression selected (~150–200 KB per photo)','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction applyQualityUI(q){\u001b[39m\n\u001b[31m  ['compressed','hd'].forEach(opt=>{\u001b[39m\n\u001b[31m    const label=document.getElementById('q-opt-'+opt);\u001b[39m\n\u001b[31m    const radio=document.getElementById('q-radio-'+opt);\u001b[39m\n\u001b[31m    const dot  =document.getElementById('q-dot-'+opt);\u001b[39m\n\u001b[31m    if(!label)return;\u001b[39m\n\u001b[31m    const active=opt===q;\u001b[39m\n\u001b[31m    label.style.borderColor=active?'var(--or)':'var(--g200)';\u001b[39m\n\u001b[31m    label.style.background=active?'#fff7ed':'var(--g50)';\u001b[39m\n\u001b[31m    if(radio)radio.style.borderColor=active?'var(--or)':'var(--g300)';\u001b[39m\n\u001b[31m    if(dot)dot.style.display=active?'block':'none';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const badge=document.getElementById('q-current-badge');\u001b[39m\n\u001b[31m  if(badge){\u001b[39m\n\u001b[31m    const label=q==='hd'?'HD Quality (~400–600 KB)':'Full Compression (~150–200 KB)';\u001b[39m\n\u001b[31m    badge.innerHTML=`Active: <strong>${label}</strong>`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function clearData(){if(!confirm('Delete ALL local data?'))return;const all=await dbAll('subs');for(const s of all)await dbDel('subs',s.id);stores=[];await cfg('stores',null);toast('All cleared','success');loadHome();}\u001b[39m\n\u001b[31mif('serviceWorker' in navigator){const sw=`const C='recce-v37';self.addEventListener('install',e=>{e.waitUntil(caches.open(C).then(c=>c.add('/')));self.skipWaiting();});self.addEventListener('activate',e=>e.waitUntil(clients.claim()));self.addEventListener('fetch',e=>{if(e.request.method!=='GET')return;e.respondWith(caches.match(e.request).then(r=>{if(r)return r;return fetch(e.request).then(res=>{if(res&&res.status===200&&res.type==='basic'){const cl=res.clone();caches.open(C).then(c=>c.put(e.request,cl));}return res;}).catch(()=>caches.match('/'));}))}); `;const blob=new Blob([sw],{type:'application/javascript'});navigator.serviceWorker.register(URL.createObjectURL(blob),{scope:'/'}).catch(()=>{});}·\u001b[39m\n\u001b[31m// ── GEOLOCATION STAMP ────────────────────────────────────────\u001b[39m\n\u001b[31mfunction applyGeoStampUI(){\u001b[39m\n\u001b[31m  const tog=document.getElementById('geo-tog');\u001b[39m\n\u001b[31m  if(tog)tog.classList.toggle('on',geoStampEnabled);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function toggleGeoStamp(){\u001b[39m\n\u001b[31m  geoStampEnabled=!geoStampEnabled;\u001b[39m\n\u001b[31m  await cfg('geo-stamp',geoStampEnabled?'1':'0');\u001b[39m\n\u001b[31m  applyGeoStampUI();\u001b[39m\n\u001b[31m  toast(geoStampEnabled?'Geolocation stamp enabled':'Geolocation stamp disabled','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Auto-request GPS silently when a new recce starts\u001b[39m\n\u001b[31mfunction autoRequestGPS(){\u001b[39m\n\u001b[31m  if(!navigator.geolocation)return;\u001b[39m\n\u001b[31m  const statusEl=document.getElementById('geo-status');\u001b[39m\n\u001b[31m  if(statusEl)statusEl.textContent='Acquiring GPS…';\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(\u001b[39m\n\u001b[31m    pos=>{\u001b[39m\n\u001b[31m      gpsCoords={\u001b[39m\n\u001b[31m        lat:pos.coords.latitude.toFixed(6),\u001b[39m\n\u001b[31m        lng:pos.coords.longitude.toFixed(6),\u001b[39m\n\u001b[31m        acc:Math.round(pos.coords.accuracy)\u001b[39m\n\u001b[31m      };\u001b[39m\n\u001b[31m      const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m      const quality=acc<=15?'Excellent':acc<=50?'Good':acc<=200?'Fair':'Poor (cell tower)';\u001b[39m\n\u001b[31m      const color=acc<=15?'var(--gn)':acc<=50?'#16a34a':acc<=200?'var(--am)':'var(--rd)';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.innerHTML=`GPS: ${gpsCoords.lat}, ${gpsCoords.lng} · ±${acc}m · <span style=\\\"color:${color};font-weight:600\\\">${quality}</span>`;\u001b[39m\n\u001b[31m      // Update form GPS status too\u001b[39m\n\u001b[31m      const fs=document.getElementById('gps-status');\u001b[39m\n\u001b[31m      if(fs){fs.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${acc}m)`;fs.style.color='var(--gn)';}\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    err=>{\u001b[39m\n\u001b[31m      const msgs={1:'Location permission denied in Chrome',2:'GPS signal unavailable',3:'GPS timed out'};\u001b[39m\n\u001b[31m      const msg=msgs[err.code]||'GPS unavailable';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.textContent=msg+' — stamp will use store address';\u001b[39m\n\u001b[31m      if(err.code===1)toast('Tap the lock icon in Chrome address bar → allow Location','info');\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    {enableHighAccuracy:true,timeout:20000,maximumAge:60000}\u001b[39m\n\u001b[31m  );\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Draw stamp on a photo blob — returns new blob with stamp baked in\u001b[39m\n\u001b[31mfunction roundRectPath(ctx,x,y,w,h,r){\u001b[39m\n\u001b[31m  ctx.beginPath();ctx.moveTo(x+r,y);ctx.lineTo(x+w-r,y);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y,x+w,y+r);ctx.lineTo(x+w,y+h-r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);ctx.lineTo(x+r,y+h);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y+h,x,y+h-r);ctx.lineTo(x,y+r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y,x+r,y);ctx.closePath();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction fitText(ctx,text,maxW){\u001b[39m\n\u001b[31m  if(ctx.measureText(text).width<=maxW)return text;\u001b[39m\n\u001b[31m  while(text.length>1&&ctx.measureText(text+'…').width>maxW)text=text.slice(0,-1);\u001b[39m\n\u001b[31m  return text+'…';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction stampPhoto(blob){\u001b[39m\n\u001b[31m  if(!geoStampEnabled)return Promise.resolve(blob);\u001b[39m\n\u001b[31m  return new Promise(res=>{\u001b[39m\n\u001b[31m    const img=new Image(),url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    img.onload=()=>{\u001b[39m\n\u001b[31m      URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m      const W=img.width,H=img.height;\u001b[39m\n\u001b[31m      const c=document.createElement('canvas');c.width=W;c.height=H;\u001b[39m\n\u001b[31m      const ctx=c.getContext('2d');\u001b[39m\n\u001b[31m      ctx.drawImage(img,0,0);·\u001b[39m\n\u001b[31m      // Stamp dimensions — 18% of image height\u001b[39m\n\u001b[31m      const SH=Math.round(H*0.18);\u001b[39m\n\u001b[31m      const pad=Math.round(W*0.03);\u001b[39m\n\u001b[31m      const SY=H-SH;·\u001b[39m\n\u001b[31m      // Semi-transparent background\u001b[39m\n\u001b[31m      ctx.fillStyle='rgba(10,18,35,0.78)';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,SH);·\u001b[39m\n\u001b[31m      // Orange top accent line\u001b[39m\n\u001b[31m      ctx.fillStyle='#f97316';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,Math.max(3,Math.round(H*0.004)));·\u001b[39m\n\u001b[31m      // Font sizes scaled to image\u001b[39m\n\u001b[31m      const f1=Math.round(SH*0.26); // store name\u001b[39m\n\u001b[31m      const f2=Math.round(SH*0.22); // coords / address\u001b[39m\n\u001b[31m      const f3=Math.round(SH*0.20); // timestamp·\u001b[39m\n\u001b[31m      // Row Y centres\u001b[39m\n\u001b[31m      const r1=SY+SH*0.26;\u001b[39m\n\u001b[31m      const r2=SY+SH*0.55;\u001b[39m\n\u001b[31m      const r3=SY+SH*0.82;·\u001b[39m\n\u001b[31m      // Get stamp data\u001b[39m\n\u001b[31m      const storeName=F.storeName||selectedStore?.name||'';\u001b[39m\n\u001b[31m      const brand=F.brand||selectedStore?.brand||'';\u001b[39m\n\u001b[31m      const addr=F.address||selectedStore?.address||'';\u001b[39m\n\u001b[31m      const now=new Date();\u001b[39m\n\u001b[31m      const dateStr=now.toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m      const timeStr=now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit',hour12:true});·\u001b[39m\n\u001b[31m      // Badge (right side — GPS quality)\u001b[39m\n\u001b[31m      let badgeLabel='',badgeColor='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m        if(acc<=15){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=50){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=200){badgeLabel='~'+acc+'m';badgeColor='#d97706';}\u001b[39m\n\u001b[31m        else{badgeLabel='Cell ~'+acc+'m';badgeColor='#dc2626';}\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        badgeLabel='No GPS';badgeColor='#64748b';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      const bFontSz=Math.round(SH*0.18);\u001b[39m\n\u001b[31m      ctx.font=`bold ${bFontSz}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      const bW=Math.round(ctx.measureText(badgeLabel).width+pad);\u001b[39m\n\u001b[31m      const bH=Math.round(SH*0.32);\u001b[39m\n\u001b[31m      const bX=W-bW-pad;const bY=SY+(SH-bH)/2;\u001b[39m\n\u001b[31m      ctx.fillStyle=badgeColor+'cc';\u001b[39m\n\u001b[31m      roundRectPath(ctx,bX,bY,bW,bH,4);ctx.fill();\u001b[39m\n\u001b[31m      ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';\u001b[39m\n\u001b[31m      ctx.fillText(badgeLabel,bX+bW/2,bY+bH/2);\u001b[39m\n\u001b[31m      ctx.textAlign='left';ctx.textBaseline='alphabetic';·\u001b[39m\n\u001b[31m      const textMaxW=bX-pad*2;·\u001b[39m\n\u001b[31m      // Row 1 — store name + brand\u001b[39m\n\u001b[31m      ctx.font=`bold ${f1}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#ffffff';\u001b[39m\n\u001b[31m      const nameText=storeName+(brand?' · '+brand:'');\u001b[39m\n\u001b[31m      ctx.fillText('📍 '+fitText(ctx,nameText,textMaxW-f1*1.4),pad,r1);·\u001b[39m\n\u001b[31m      // Row 2 — GPS coords OR address\u001b[39m\n\u001b[31m      ctx.font=`${f2}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#cbd5e1';\u001b[39m\n\u001b[31m      let row2='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        row2=`Lat ${gpsCoords.lat}°   Long ${gpsCoords.lng}°`;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        row2=addr?fitText(ctx,addr,textMaxW):'GPS coordinates unavailable';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      ctx.fillText(row2,pad,r2);·\u001b[39m\n\u001b[31m      // Row 3 — date and time\u001b[39m\n\u001b[31m      ctx.font=`${f3}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#94a3b8';\u001b[39m\n\u001b[31m      ctx.fillText(`${dateStr}   ${timeStr}`,pad,r3);·\u001b[39m\n\u001b[31m      c.toBlob(b=>res(b||blob),'image/jpeg',imgQuality==='hd'?0.88:0.82);\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    img.onerror=()=>{URL.revokeObjectURL(url);res(blob);};\u001b[39m\n\u001b[31m    img.src=url;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _aTool='rect',_aColor='#f97316',_aWidth=4,_aTarget=-1;\u001b[39m\n\u001b[31mlet _aImg=null,_aHistory=[],_aDrawing=false,_aStart={},_aPts=[];\u001b[39m\n\u001b[31mlet _aSel=-1,_aDragMode=null,_aDragOff={x:0,y:0};\u001b[39m\n\u001b[31m// Larger hit radius on touch devices for easier finger selection\u001b[39m\n\u001b[31mconst HIT_R=()=>('ontouchstart' in window)?32:16;·\u001b[39m\n\u001b[31mfunction setATool(t){\u001b[39m\n\u001b[31m  _aTool=t;\u001b[39m\n\u001b[31m  ['rect','ellipse','line','arrow','free'].forEach(id=>{const el=document.getElementById('at-'+id);if(el)el.classList.toggle('on',id===t&&t!=='move');});\u001b[39m\n\u001b[31m  const mv=document.getElementById('at-move');if(mv)mv.classList.toggle('sel-on',t==='move');\u001b[39m\n\u001b[31m  const info=document.getElementById('annot-sel-info');if(info)info.style.display=t==='move'?'block':'none';\u001b[39m\n\u001b[31m  if(t!=='move'){_aSel=-1;redrawAnnot();}\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(cvs)cvs.style.cursor=t==='move'?'default':'crosshair';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAColor(c){\u001b[39m\n\u001b[31m  _aColor=c;\u001b[39m\n\u001b[31m  const m={'#f97316':'or','#ef4444':'rd','#ffffff':'wh','#facc15':'yw','#22c55e':'gn'};\u001b[39m\n\u001b[31m  Object.entries(m).forEach(([col,id])=>{const el=document.getElementById('ac-'+id);if(el)el.classList.toggle('on',col===c);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAWidth(w){_aWidth=w;[2,4,7].forEach(v=>{const el=document.getElementById('aw-'+v);if(el)el.classList.toggle('on',v===w);});}·\u001b[39m\n\u001b[31mfunction openAnnot(idx){\u001b[39m\n\u001b[31m  _aTarget=idx;_aHistory=[];_aDrawing=false;_aPts=[];_aSel=-1;_aDragMode=null;\u001b[39m\n\u001b[31m  document.getElementById('annot-modal').classList.add('open');\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');\u001b[39m\n\u001b[31m  const img=new Image(),url=URL.createObjectURL(brandings[idx].blob);\u001b[39m\n\u001b[31m  img.onload=()=>{\u001b[39m\n\u001b[31m    const sc=Math.min(1,window.innerWidth/img.width,(window.innerHeight-185)/img.height);\u001b[39m\n\u001b[31m    cvs.width=Math.round(img.width*sc);cvs.height=Math.round(img.height*sc);\u001b[39m\n\u001b[31m    _aImg=img;redrawAnnot();URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  img.src=url;\u001b[39m\n\u001b[31m  cvs.ontouchstart=aDown;cvs.ontouchmove=aMove;cvs.ontouchend=aUp;\u001b[39m\n\u001b[31m  cvs.onmousedown=aDown;cvs.onmousemove=aMove;cvs.onmouseup=aUp;\u001b[39m\n\u001b[31m  setATool('rect');setAColor('#f97316');setAWidth(4);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aPos(e){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const r=cvs.getBoundingClientRect();\u001b[39m\n\u001b[31m  const src=e.touches?e.touches[0]:e;\u001b[39m\n\u001b[31m  return{x:(src.clientX-r.left)*(cvs.width/r.width),y:(src.clientY-r.top)*(cvs.height/r.height)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Always return normalised (positive w,h) bounds\u001b[39m\n\u001b[31mfunction sBounds(s){\u001b[39m\n\u001b[31m  if(s.type==='free'){\u001b[39m\n\u001b[31m    if(!s.pts||!s.pts.length)return null;\u001b[39m\n\u001b[31m    const xs=s.pts.map(p=>p.x),ys=s.pts.map(p=>p.y);\u001b[39m\n\u001b[31m    const x=Math.min(...xs),y=Math.min(...ys);\u001b[39m\n\u001b[31m    return{x,y,w:Math.max(...xs)-x,h:Math.max(...ys)-y};\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  return{x:Math.min(s.x,s.x+s.w),y:Math.min(s.y,s.y+s.h),w:Math.abs(s.w),h:Math.abs(s.h)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction hitHandle(px,py,s){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return null;\u001b[39m\n\u001b[31m  const b=sBounds(s);const hr=HIT_R();\u001b[39m\n\u001b[31m  for(const[n,x,y]of[['tl',b.x,b.y],['tr',b.x+b.w,b.y],['bl',b.x,b.y+b.h],['br',b.x+b.w,b.y+b.h]])\u001b[39m\n\u001b[31m    if(Math.hypot(px-x,py-y)<hr)return n;\u001b[39m\n\u001b[31m  return null;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction hitShape(px,py,s){\u001b[39m\n\u001b[31m  const b=sBounds(s);if(!b)return false;\u001b[39m\n\u001b[31m  const pad=HIT_R();\u001b[39m\n\u001b[31m  return px>=b.x-pad&&px<=b.x+b.w+pad&&py>=b.y-pad&&py<=b.y+b.h+pad;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aDown(e){\u001b[39m\n\u001b[31m  e.preventDefault();const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'){\u001b[39m\n\u001b[31m    // Check handles of selected shape first\u001b[39m\n\u001b[31m    if(_aSel>=0&&_aSel<_aHistory.length){\u001b[39m\n\u001b[31m      const h=hitHandle(p.x,p.y,_aHistory[_aSel]);\u001b[39m\n\u001b[31m      if(h){_aDragMode='r-'+h;_aDragOff={x:p.x,y:p.y};_aDrawing=true;return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Hit test all shapes topmost first\u001b[39m\n\u001b[31m    for(let i=_aHistory.length-1;i>=0;i--){\u001b[39m\n\u001b[31m      if(hitShape(p.x,p.y,_aHistory[i])){\u001b[39m\n\u001b[31m        _aSel=i;_aDragMode='move';\u001b[39m\n\u001b[31m        const s=_aHistory[i];\u001b[39m\n\u001b[31m        const b=sBounds(s);\u001b[39m\n\u001b[31m        // Store offset from shape top-left corner (normalised)\u001b[39m\n\u001b[31m        _aDragOff={x:p.x-b.x,y:p.y-b.y};\u001b[39m\n\u001b[31m        _aDrawing=true;redrawAnnot();return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    _aSel=-1;redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _aDrawing=true;_aStart={x:p.x,y:p.y};if(_aTool==='free')_aPts=[{x:p.x,y:p.y}];\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aMove(e){\u001b[39m\n\u001b[31m  e.preventDefault();if(!_aDrawing)return;const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'&&_aDragMode){\u001b[39m\n\u001b[31m    const s=_aHistory[_aSel];if(!s)return;\u001b[39m\n\u001b[31m    if(_aDragMode==='move'){\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      // New top-left position\u001b[39m\n\u001b[31m      const nx=p.x-_aDragOff.x;\u001b[39m\n\u001b[31m      const ny=p.y-_aDragOff.y;\u001b[39m\n\u001b[31m      const dx=nx-b.x,dy=ny-b.y;\u001b[39m\n\u001b[31m      if(s.type==='free'){\u001b[39m\n\u001b[31m        s.pts=s.pts.map(pt=>({x:pt.x+dx,y:pt.y+dy}));\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        // Move preserving w/h sign (don't normalise — keep original drawing direction)\u001b[39m\n\u001b[31m        s.x+=dx;s.y+=dy;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Resize from corner — always work on normalised bounds then re-apply\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      const n=_aDragMode.slice(2);\u001b[39m\n\u001b[31m      let nx=b.x,ny=b.y,nw=b.w,nh=b.h;\u001b[39m\n\u001b[31m      if(n==='br'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,p.y-b.y);}\u001b[39m\n\u001b[31m      else if(n==='tl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,b.y+b.h-p.y);nx=p.x;ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='tr'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,b.y+b.h-p.y);ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='bl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,p.y-b.y);nx=p.x;}\u001b[39m\n\u001b[31m      s.x=nx;s.y=ny;s.w=nw;s.h=nh; // store as normalised going forward\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if(_aTool==='free'){_aPts.push({x:p.x,y:p.y});redrawAnnot();drawSh({type:'free',pts:[..._aPts],color:_aColor,lw:_aWidth},true);return;}\u001b[39m\n\u001b[31m  redrawAnnot();drawSh({type:_aTool,x:_aStart.x,y:_aStart.y,w:p.x-_aStart.x,h:p.y-_aStart.y,color:_aColor,lw:_aWidth},true);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction aUp(e){\u001b[39m\n\u001b[31m  if(!_aDrawing)return;_aDrawing=false;\u001b[39m\n\u001b[31m  if(_aTool==='move'){_aDragMode=null;return;}\u001b[39m\n\u001b[31m  const p=aPos(e||{touches:[{clientX:0,clientY:0}]});\u001b[39m\n\u001b[31m  if(_aTool==='free'){if(_aPts.length>2){_aHistory.push({type:'free',pts:[..._aPts],x:_aPts[0].x,y:_aPts[0].y,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  else{const w=p.x-_aStart.x,h=p.y-_aStart.y;if(Math.abs(w)>4||Math.abs(h)>4){_aHistory.push({type:_aTool,x:_aStart.x,y:_aStart.y,w,h,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  _aPts=[];redrawAnnot();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction redrawAnnot(){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.clearRect(0,0,cvs.width,cvs.height);if(_aImg)ctx.drawImage(_aImg,0,0,cvs.width,cvs.height);\u001b[39m\n\u001b[31m  _aHistory.forEach((s,i)=>{drawSh(s,false,ctx);if(_aTool==='move'&&i===_aSel)drawHandles(s,ctx);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawHandles(s,ctx){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return;const b=sBounds(s);ctx.save();\u001b[39m\n\u001b[31m  ctx.setLineDash([5,3]);ctx.strokeStyle='#facc15';ctx.lineWidth=1.5;ctx.strokeRect(b.x-2,b.y-2,b.w+4,b.h+4);ctx.setLineDash([]);\u001b[39m\n\u001b[31m  [[b.x,b.y],[b.x+b.w,b.y],[b.x,b.y+b.h],[b.x+b.w,b.y+b.h]].forEach(([x,y])=>{ctx.beginPath();ctx.arc(x,y,7,0,2*Math.PI);ctx.fillStyle='#f97316';ctx.fill();ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();});\u001b[39m\n\u001b[31m  ctx.restore();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawSh(s,preview=false,ctx){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(!ctx)ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.save();ctx.strokeStyle=s.color;ctx.lineWidth=preview?Math.max(s.lw||4,2):s.lw||4;\u001b[39m\n\u001b[31m  ctx.lineCap='round';ctx.lineJoin='round';ctx.setLineDash(preview?[6,3]:[]);\u001b[39m\n\u001b[31m  if(s.type==='rect'){ctx.strokeRect(s.x,s.y,s.w,s.h);ctx.fillStyle=s.color+'28';ctx.fillRect(s.x,s.y,s.w,s.h);}\u001b[39m\n\u001b[31m  else if(s.type==='ellipse'){const cx=s.x+s.w/2,cy=s.y+s.h/2;ctx.beginPath();ctx.ellipse(cx,cy,Math.abs(s.w/2),Math.abs(s.h/2),0,0,2*Math.PI);ctx.stroke();ctx.fillStyle=s.color+'28';ctx.fill();}\u001b[39m\n\u001b[31m  else if(s.type==='line'){ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(s.x+s.w,s.y+s.h);ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='arrow'){const ex=s.x+s.w,ey=s.y+s.h;ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(ex,ey);ctx.stroke();const a=Math.atan2(s.h,s.w),al=20,aa=0.4;ctx.setLineDash([]);ctx.beginPath();ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a-aa),ey-al*Math.sin(a-aa));ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a+aa),ey-al*Math.sin(a+aa));ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='free'){if(s.pts.length<2){ctx.restore();return;}ctx.beginPath();s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));ctx.stroke();}\u001b[39m\n\u001b[31m  ctx.setLineDash([]);ctx.restore();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction undoAnnot(){if(_aHistory.length){_aHistory.pop();_aSel=Math.min(_aSel,_aHistory.length-1);redrawAnnot();}}\u001b[39m\n\u001b[31mfunction clearAnnot(){_aHistory=[];_aSel=-1;redrawAnnot();}·\u001b[39m\n\u001b[31m// Bottom dialog\u001b[39m\n\u001b[31mlet _bdCb=null;\u001b[39m\n\u001b[31mfunction showBDialog(title,sub,onYes){\u001b[39m\n\u001b[31m  document.getElementById('bdialog-title').textContent=title;\u001b[39m\n\u001b[31m  document.getElementById('bdialog-sub').textContent=sub;\u001b[39m\n\u001b[31m  _bdCb=onYes;document.getElementById('bdialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction bdialogYes(){document.getElementById('bdialog').classList.remove('open');if(_bdCb)_bdCb();_bdCb=null;}\u001b[39m\n\u001b[31mfunction bdialogNo(){document.getElementById('bdialog').classList.remove('open');_bdCb=null;}·\u001b[39m\n\u001b[31mfunction _afterBrandingPhoto(){\u001b[39m\n\u001b[31m  const idx=_aTarget;\u001b[39m\n\u001b[31m  showBDialog(t(`Add reference photos for Branding ${idx+1}?`,`ब्रांडिंग ${idx+1} के लिए अतिरिक्त फोटो?`),t('Optional extra photos for future reference.','वैकल्पिक — भविष्य के लिए अतिरिक्त फोटो।'),()=>{showView('form-additional');setTimeout(()=>addAdditional(),200);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction skipAnnot(){document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo added (${fmtSz(brandings[_aTarget].blob.size)})`,'success');_afterBrandingPhoto();}\u001b[39m\n\u001b[31mfunction saveAnnot(){const cvs=document.getElementById('annot-cvs');cvs.toBlob(blob=>{brandings[_aTarget].blob=blob;brandings[_aTarget].prev=URL.createObjectURL(blob);document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo + markup saved (${fmtSz(blob.size)})`,'success');_afterBrandingPhoto();},'image/jpeg',0.88);}·\u001b[39m\n\u001b[31m// ── VIEW RECCE (read-only) ──────────────────────────────────\u001b[39m\n\u001b[31masync function viewRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  // Synced entries have a server-side rich report — open it directly\u001b[39m\n\u001b[31m  if(entry.viewUrl){window.open(entry.viewUrl,'_blank');return;}\u001b[39m\n\u001b[31m  // Offline / not-yet-synced fallback: generate from local base64 data\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  const ts=new Date(entry.timestamp).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'});·\u001b[39m\n\u001b[31m  async function b64ToUrl(b64){if(!b64)return'';try{const r=await fetch(b64);const bl=await r.blob();return URL.createObjectURL(bl);}catch{return'';}}·\u001b[39m\n\u001b[31m  const fvUrls=await Promise.all((d.frontPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const ivUrls=await Promise.all((d.insidePhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const brUrls=await Promise.all((d.brandings||[]).map(b=>b64ToUrl(b.photoB64)));\u001b[39m\n\u001b[31m  const adUrls=await Promise.all((d.addlPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const docUrl=await b64ToUrl(d.docB64);·\u001b[39m\n\u001b[31m  const brRows=(d.brandings||[]).map((b,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:16px;padding:12px;background:#f8fafc;border-radius:8px;border-left:3px solid #f97316\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-weight:600;font-size:14px;color:#0f172a;margin-bottom:6px\\\">${i+1}. ${b.type||'—'}: ${b.w||'?'}\\\"×${b.h||'?'}\\\" · Qty: ${b.qty||'?'} · ${b.sqft||'?'}</div>\u001b[39m\n\u001b[31m      ${brUrls[i]?`<img src=\\\"${brUrls[i]}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:6px\\\">`:'<div style=\\\"color:#94a3b8;font-size:12px\\\">No photo</div>'}\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  const html=`<!DOCTYPE html><html><head><meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m  <title>Recce — ${d.storeName||'Unknown'}</title>\u001b[39m\n\u001b[31m  <style>body{font-family:Arial,sans-serif;margin:0;padding:16px;background:#f1f5f9}\u001b[39m\n\u001b[31m  .card{background:#fff;border-radius:12px;padding:16px;margin-bottom:14px;box-shadow:0 1px 4px rgba(0,0,0,.08)}\u001b[39m\n\u001b[31m  h1{font-size:18px;color:#0f172a;margin:0 0 4px}h2{font-size:14px;color:#f97316;text-transform:uppercase;letter-spacing:.5px;margin:0 0 10px}\u001b[39m\n\u001b[31m  .meta{font-size:12px;color:#64748b;margin-bottom:12px}.photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}\u001b[39m\n\u001b[31m  img{width:100%;border-radius:8px;object-fit:cover}\u001b[39m\n\u001b[31m  .tag{display:inline-block;background:#0f172a;color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-right:4px}\u001b[39m\n\u001b[31m  @media print{body{background:#fff}.card{box-shadow:none}}</style></head><body>\u001b[39m\n\u001b[31m  <div class=\\\"card\\\">\u001b[39m\n\u001b[31m    <h1>${d.storeName||'Unknown Store'}</h1>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\"><span class=\\\"tag\\\">${d.brand||'No Brand'}</span>${d.address||''}</div>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\">📞 ${d.mobile||'—'} &nbsp;|&nbsp; 📅 ${d.date||'—'} &nbsp;|&nbsp; Submitted: ${ts}</div>\u001b[39m\n\u001b[31m    ${d.gpsCoords?`<div class=\\\"meta\\\">📍 ${d.gpsCoords.lat}, ${d.gpsCoords.lng} ±${d.gpsCoords.acc}m</div>`:''}\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${fvUrls.length?`<div class=\\\"card\\\"><h2>Front View Photos</h2><div class=\\\"photos\\\">${fvUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${ivUrls.length?`<div class=\\\"card\\\"><h2>Inside View Photos</h2><div class=\\\"photos\\\">${ivUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${d.hasVideo?`<div class=\\\"card\\\"><h2>Video</h2><div>${d.videoNote||'Video recorded'}</div></div>`:''}\u001b[39m\n\u001b[31m  ${(d.brandings||[]).length?`<div class=\\\"card\\\"><h2>Branding Items (${(d.brandings||[]).length})</h2>${brRows}</div>`:''}\u001b[39m\n\u001b[31m  ${adUrls.length?`<div class=\\\"card\\\"><h2>Additional Photos</h2><div class=\\\"photos\\\">${adUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${docUrl?`<div class=\\\"card\\\"><h2>Submission Document</h2><img src=\\\"${docUrl}\\\" style=\\\"width:100%;max-height:300px;object-fit:contain\\\"></div>`:''}\u001b[39m\n\u001b[31m  <div style=\\\"text-align:center;margin:16px 0\\\">\u001b[39m\n\u001b[31m    <button onclick=\\\"window.print()\\\" style=\\\"background:#f97316;color:#fff;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer\\\">🖨 Print / Save as PDF</button>\u001b[39m\n\u001b[31m    <button onclick=\\\"window.close()\\\" style=\\\"background:#e2e8f0;color:#475569;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer;margin-left:10px\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  </body></html>`;\u001b[39m\n\u001b[31m  const blob=new Blob([html],{type:'text/html'});\u001b[39m\n\u001b[31m  const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m  window.open(url,'_blank');\u001b[39m\n\u001b[31m  setTimeout(()=>URL.revokeObjectURL(url),30000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── EDIT OLD RECCE ───────────────────────────────────────────\u001b[39m\n\u001b[31masync function editRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=d.gpsCoords||null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  F.editingId=id;F.date=d.date||'';F.brand=d.brand||'';F.storeName=d.storeName||'';F.address=d.address||'';F.mobile=d.mobile||'';F.hasVideo=d.hasVideo;F.hasBranding=d.hasBranding;\u001b[39m\n\u001b[31m  async function b64ToBlob(b64){if(!b64)return null;try{const r=await fetch(b64);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m  toast('Loading recce data…','info');\u001b[39m\n\u001b[31m  for(const p of(d.frontPhotos||[])){const b=await b64ToBlob(p.b64);if(b)frontPhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const p of(d.insidePhotos||[])){const b=await b64ToBlob(p.b64);if(b)insidePhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const br of(d.brandings||[])){const b=await b64ToBlob(br.photoB64);brandings.push({type:br.type,w:br.w,h:br.h,qty:br.qty,blob:b,prev:b?URL.createObjectURL(b):null});}\u001b[39m\n\u001b[31m  for(const p of(d.addlPhotos||[])){const b=await b64ToBlob(p.b64);if(b)addlPhotos.push({blob:b,prev:URL.createObjectURL(b),desc:p.desc||''});}\u001b[39m\n\u001b[31m  if(d.docB64){const b=await b64ToBlob(d.docB64);if(b){submissionDoc=b;const sl=document.getElementById('doc-slot');sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${URL.createObjectURL(b)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}}\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  if(F.brand)document.getElementById('f-brand').value=F.brand;\u001b[39m\n\u001b[31m  if(F.storeName)document.getElementById('f-store').value=F.storeName;\u001b[39m\n\u001b[31m  if(F.address)document.getElementById('f-addr').value=F.address;\u001b[39m\n\u001b[31m  if(F.mobile)document.getElementById('f-mobile').value=F.mobile;\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();updAvailTag();\u001b[39m\n\u001b[31m  toast('Recce loaded — make changes and re-submit','success');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── EDIT REQUEST ────────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mlet _editReqSubId = null;·\u001b[39m\n\u001b[31mfunction _hydratePhotosFromRow(r) {\u001b[39m\n\u001b[31m  let pu={};\u001b[39m\n\u001b[31m  try{pu=typeof r.photo_urls==='string'?JSON.parse(r.photo_urls):(r.photo_urls||{});}catch(_){}\u001b[39m\n\u001b[31m  let meta={};\u001b[39m\n\u001b[31m  try{meta=typeof r.meta==='string'?JSON.parse(r.meta):(r.meta||{});}catch(_){}\u001b[39m\n\u001b[31m  frontPhotos =(pu.front   ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  insidePhotos=(pu.inside  ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  addlPhotos  =(pu.addl    ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,desc:''}));\u001b[39m\n\u001b[31m  brandings   =(meta.brandings||[]).map((b,i)=>({type:b.type,w:b.w,h:b.h,qty:b.qty,existingUrl:(pu.brandings||[])[i]||null,blob:null,prev:(pu.brandings||[])[i]||null}));\u001b[39m\n\u001b[31m  _docExistingUrl=pu.doc||null;\u001b[39m\n\u001b[31m  // Show retained doc in slot\u001b[39m\n\u001b[31m  const sl=document.getElementById('doc-slot');\u001b[39m\n\u001b[31m  if(sl&&_docExistingUrl){sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${_docExistingUrl}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openEditRequestModal(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  _editReqSubId = subId;\u001b[39m\n\u001b[31m  document.getElementById('er-store-name').textContent = r.store_name || 'Unknown';\u001b[39m\n\u001b[31m  document.getElementById('er-comment').value = '';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const assignBtn = document.getElementById('er-assign-btn');\u001b[39m\n\u001b[31m  if (r.submitted_by && r.submitted_by !== hub?.empId) {\u001b[39m\n\u001b[31m    assignBtn.textContent = `👤 Assign to ${r.submitted_by}`;\u001b[39m\n\u001b[31m    assignBtn.style.display = '';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    assignBtn.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeEditRequestModal() {\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _editReqSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorEditMyself() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  // Lock branding if client has reviewed (preserve their approval)\u001b[39m\n\u001b[31m  _brandingLocked = !!(r.client_status && r.client_status !== 'pending');\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function assignEditToCreator() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r || !r.submitted_by) { toast('No creator found for this recce', 'error'); return; }\u001b[39m\n\u001b[31m  const comment = (document.getElementById('er-comment').value || '').trim();\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        status: 'edit_requested',\u001b[39m\n\u001b[31m        edit_assigned_to: r.submitted_by,\u001b[39m\n\u001b[31m        edit_comment: comment || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!resp.ok) throw new Error('Update failed: ' + resp.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].status = 'edit_requested';\u001b[39m\n\u001b[31m      _adminRows[idx].edit_assigned_to = r.submitted_by;\u001b[39m\n\u001b[31m      _adminRows[idx].edit_comment = comment || null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Push notification to creator\u001b[39m\n\u001b[31m    const notifBody = comment || `Please review and re-submit: ${r.store_name || 'your recce'}`;\u001b[39m\n\u001b[31m    fetch('/push-server/notify', {\u001b[39m\n\u001b[31m      method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        user_id: r.submitted_by, title: '✏ Edit Requested',\u001b[39m\n\u001b[31m        body: notifBody, tag: `recce-edit-${subId}`, url: '/recce/',\u001b[39m\n\u001b[31m        icon: '/hub/icons/icon-192.png', badge: '/hub/icons/icon-192.png',\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    }).catch(() => {});\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast(`Edit assigned to ${r.submitted_by} ✓`, 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Assign failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function startCreatorEdit(subId) {\u001b[39m\n\u001b[31m  // Try local IndexedDB first (has photos)\u001b[39m\n\u001b[31m  const local = await dbGet('subs', subId);\u001b[39m\n\u001b[31m  if (local) { await editRecce(subId); return; }\u001b[39m\n\u001b[31m  // Fallback: load text fields from server row\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId)\u001b[39m\n\u001b[31m         || (await (async () => {\u001b[39m\n\u001b[31m              try {\u001b[39m\n\u001b[31m                const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, { headers: _RC_READ });\u001b[39m\n\u001b[31m                if (resp.ok) { const arr = await resp.json(); return arr[0]; }\u001b[39m\n\u001b[31m              } catch(_) {} return null;\u001b[39m\n\u001b[31m            })());\u001b[39m\n\u001b[31m  if (!r) { toast('Record not found', 'error'); return; }\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── End edit request ─────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mfunction goToHub() { window.location.href = '/hub/'; }\u001b[39m\n\u001b[31mfunction recceLogout() {\u001b[39m\n\u001b[31m  if (!confirm('Log out?')) return;\u001b[39m\n\u001b[31m  localStorage.removeItem('lm360-session');\u001b[39m\n\u001b[31m  localStorage.removeItem('360exp-session');\u001b[39m\n\u001b[31m  window.location.href = '/hub/';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction injectHubButtons() {\u001b[39m\n\u001b[31m  const u = _recceHubUser();\u001b[39m\n\u001b[31m  const name = u ? (u.name || '') : '';\u001b[39m\n\u001b[31m  if (name) {\u001b[39m\n\u001b[31m    const bar = document.getElementById('recce-hero-ubar');\u001b[39m\n\u001b[31m    const nm  = document.getElementById('recce-hero-name');\u001b[39m\n\u001b[31m    if (bar) { nm.textContent = name; bar.style.display = 'flex'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.querySelectorAll('.hdr').forEach(hdr => {\u001b[39m\n\u001b[31m    const r = document.createElement('div');\u001b[39m\n\u001b[31m    r.className = 'hdr-r';\u001b[39m\n\u001b[31m    if (name) {\u001b[39m\n\u001b[31m      const un = document.createElement('span');\u001b[39m\n\u001b[31m      un.className = 'hdr-user';\u001b[39m\n\u001b[31m      un.textContent = name;\u001b[39m\n\u001b[31m      r.appendChild(un);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    const hub = document.createElement('button');\u001b[39m\n\u001b[31m    hub.className = 'btn-hub';\u001b[39m\n\u001b[31m    hub.innerHTML = '🏡 Hub';\u001b[39m\n\u001b[31m    hub.addEventListener('click', goToHub);\u001b[39m\n\u001b[31m    r.appendChild(hub);\u001b[39m\n\u001b[31m    const lo = document.createElement('button');\u001b[39m\n\u001b[31m    lo.className = 'btn-logout';\u001b[39m\n\u001b[31m    lo.textContent = 'Logout';\u001b[39m\n\u001b[31m    lo.addEventListener('click', recceLogout);\u001b[39m\n\u001b[31m    r.appendChild(lo);\u001b[39m\n\u001b[31m    hdr.appendChild(r);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction checkAppUpdate(){\u001b[39m\n\u001b[31m  const seen=localStorage.getItem('recce-ver-seen');\u001b[39m\n\u001b[31m  localStorage.setItem('recce-ver-seen',CACHE_VER);\u001b[39m\n\u001b[31m  if(seen&&seen!==CACHE_VER){\u001b[39m\n\u001b[31m    const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m    if(b){b.classList.add('show');setTimeout(()=>b.classList.remove('show'),5000);}\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction dismissUpdateBanner(){\u001b[39m\n\u001b[31m  const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m  if(b)b.classList.remove('show');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function init(){\u001b[39m\n\u001b[31m  // Detect host banners (tiiny.host, etc) and raise bnav above them\u001b[39m\n\u001b[31m  (function detectHostBar(){\u001b[39m\n\u001b[31m    const h=window.location.hostname;\u001b[39m\n\u001b[31m    let extra=0;\u001b[39m\n\u001b[31m    if(h.includes('tiiny'))extra=58;\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // Generic detection: check if window is shorter than expected (host injected a bar)\u001b[39m\n\u001b[31m      const gap=screen.height - window.innerHeight;\u001b[39m\n\u001b[31m      if(gap>100&&gap<200)extra=58; // a fixed bar is roughly 56-60px\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if(extra>0){\u001b[39m\n\u001b[31m      document.documentElement.style.setProperty('--host-bar',extra+'px');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  })();\u001b[39m\n\u001b[31m  setLang(LANG);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m  checkAppUpdate();\u001b[39m\n\u001b[31m  await loadRecceCfg();\u001b[39m\n\u001b[31m  _checkAccessMode();\u001b[39m\n\u001b[31m  await initDB();await loadSettings();await loadHome();await checkDraft();netStatus();window.addEventListener('online',()=>{netStatus();syncNow();});window.addEventListener('offline',netStatus);injectHubButtons();document.getElementById('today-date').textContent=new Date().toLocaleDateString('en-IN',{weekday:'long',day:'numeric',month:'long',year:'numeric'});updAvailTag();\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m  // Auto-fetch stores from server on every startup (uses default Netlify URL if none saved)\u001b[39m\n\u001b[31m  const su=(await cfg('srv-url'))||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su&&navigator.onLine){\u001b[39m\n\u001b[31m    fetch(su).then(r=>r.json()).then(async j=>{\u001b[39m\n\u001b[31m      const d=Array.isArray(j)?j:j.stores||[];\u001b[39m\n\u001b[31m      if(d.length){stores=d;await cfg('stores',JSON.stringify(d));await cfg('srv-url',su);updAvailTag();\u001b[39m\n\u001b[31m        document.getElementById('srv-url').value=su;}\u001b[39m\n\u001b[31m    }).catch(()=>{});\u001b[39m\n\u001b[31m  }}init();\u001b[39m\n\u001b[31m</script>\u001b[39m\n\u001b[31m</body>\u001b[39m\n\u001b[31m</html>\u001b[39m\n\u001b[31m\"\u001b[39m\n\n  335 |     const resp = await page.request.get(BASE_URL);\n  336 |     const src = await resp.text();\n> 337 |     expect(src).toContain('recce-v15');\n      |                 ^\n  338 |     expect(src).not.toContain('recce-v14');\n  339 |   });\n  340 | });\n    at /var/www/360lm/tests/recce.spec.js:337:17"
                        }
                      ],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:44:28.126Z",
                      "annotations": [],
                      "attachments": [
                        {
                          "name": "screenshot",
                          "contentType": "image/png",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v10-dbf60-tos-SW-version-is-recce-v15-android-chrome/test-failed-1.png"
                        },
                        {
                          "name": "error-context",
                          "contentType": "text/markdown",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v10-dbf60-tos-SW-version-is-recce-v15-android-chrome/error-context.md"
                        }
                      ],
                      "errorLocation": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "column": 17,
                        "line": 337
                      }
                    },
                    {
                      "workerIndex": 1,
                      "parallelIndex": 0,
                      "status": "failed",
                      "duration": 474,
                      "error": {
                        "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoContain\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // indexOf\u001b[22m\n\nExpected substring: \u001b[32m\"recce-v15\"\u001b[39m\nReceived string:    \u001b[31m\"<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\">\u001b[39m\n\u001b[31m<head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\">\u001b[39m\n\u001b[31m<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\\\">\u001b[39m\n\u001b[31m<meta name=\\\"theme-color\\\" content=\\\"#0f172a\\\">\u001b[39m\n\u001b[31m<meta name=\\\"apple-mobile-web-app-capable\\\" content=\\\"yes\\\">\u001b[39m\n\u001b[31m<title>Branding Recce</title>\u001b[39m\n\u001b[31m<link rel=\\\"manifest\\\" href=\\\"manifest.json\\\">\u001b[39m\n\u001b[31m<link rel=\\\"preconnect\\\" href=\\\"https://fonts.googleapis.com\\\">\u001b[39m\n\u001b[31m<link href=\\\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap\\\" rel=\\\"stylesheet\\\">\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--nv:#0f172a;--nv2:#1e293b;--or:#f97316;--orl:#fed7aa;--gn:#16a34a;--rd:#dc2626;--am:#d97706;--g50:#f8fafc;--g100:#f1f5f9;--g200:#e2e8f0;--g300:#cbd5e1;--g400:#94a3b8;--g500:#64748b;--g600:#475569;--r:12px;--rs:8px;--sh:0 1px 3px rgba(0,0,0,.1),0 1px 2px rgba(0,0,0,.06);--bnav-h:72px;--host-bar:0px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}\u001b[39m\n\u001b[31mbody{font-family:'DM Sans',sans-serif;background:var(--g50);color:var(--nv);min-height:100vh;overflow-x:hidden}\u001b[39m\n\u001b[31m.hdr{background:var(--nv);color:#fff;padding:0 16px;height:56px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}\u001b[39m\n\u001b[31m.hdr-l{display:flex;align-items:center;gap:10px}\u001b[39m\n\u001b[31m.hdr-title{font-size:16px;font-weight:600}.hdr-sub{font-size:11px;color:var(--g400)}\u001b[39m\n\u001b[31m.back-btn,.icon-btn{background:none;border:none;color:#fff;padding:8px;cursor:pointer;display:flex;align-items:center}\u001b[39m\n\u001b[31m.back-btn{margin-left:-8px}\u001b[39m\n\u001b[31m.pgbar{height:3px;background:var(--g200)}.pgfill{height:100%;background:var(--or);transition:width .3s}\u001b[39m\n\u001b[31m.view{display:none;min-height:calc(100vh - 56px);padding-bottom:calc(var(--bnav-h) + var(--host-bar) + 24px)}.view.active{display:block}\u001b[39m\n\u001b[31m.content{padding:16px}\u001b[39m\n\u001b[31m.card{background:#fff;border-radius:var(--r);padding:16px;box-shadow:var(--sh);margin-bottom:12px}\u001b[39m\n\u001b[31m.card-title{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;letter-spacing:.6px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between}\u001b[39m\n\u001b[31m.cnt-badge{background:var(--or);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;min-width:22px;text-align:center}\u001b[39m\n\u001b[31m.cnt-badge.gray{background:var(--g400)}\u001b[39m\n\u001b[31m.field{margin-bottom:16px}.field:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.field label{display:block;font-size:13px;font-weight:500;color:var(--g600);margin-bottom:6px}\u001b[39m\n\u001b[31m.req{color:var(--or);margin-left:2px}\u001b[39m\n\u001b[31m.field input,.field select,.field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;color:var(--nv);background:#fff;transition:border-color .15s;-webkit-appearance:none;appearance:none}\u001b[39m\n\u001b[31m.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--or)}\u001b[39m\n\u001b[31m.field input:read-only{background:var(--g50);color:var(--g600)}\u001b[39m\n\u001b[31m.field textarea{resize:vertical;min-height:68px}\u001b[39m\n\u001b[31m.field select{background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}\u001b[39m\n\u001b[31m.pslot{border:2px dashed var(--g300);border-radius:var(--r);min-height:110px;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all .15s;position:relative;overflow:hidden;text-align:center;padding:16px}\u001b[39m\n\u001b[31m.pslot:active{border-color:var(--or);background:var(--g50)}\u001b[39m\n\u001b[31m.pslot.filled{border-style:solid;border-color:var(--or);padding:0;min-height:0}\u001b[39m\n\u001b[31m.pslot img{width:100%;height:150px;object-fit:cover;border-radius:calc(var(--r) - 2px);display:block}\u001b[39m\n\u001b[31m.pslot-lbl{font-size:13px;color:var(--g400);margin-top:6px}.pslot-ico{font-size:28px;color:var(--g300)}\u001b[39m\n\u001b[31m.pbadge{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.premove{position:absolute;top:6px;right:6px;background:var(--rd);color:#fff;border:none;border-radius:50%;width:26px;height:26px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;z-index:5}\u001b[39m\n\u001b[31minput[type=file]{display:none}\u001b[39m\n\u001b[31m.rgroup{display:flex;gap:10px}\u001b[39m\n\u001b[31m.rbtn{flex:1;padding:13px;border:1.5px solid var(--g200);border-radius:var(--rs);text-align:center;cursor:pointer;font-size:14px;font-weight:500;color:var(--g500);transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.rbtn.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.chip-grid{display:flex;flex-wrap:wrap;gap:8px}\u001b[39m\n\u001b[31m.chip{padding:7px 12px;border:1.5px solid var(--g200);border-radius:20px;font-size:13px;color:var(--g600);cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.chip.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.brand-chip{display:flex;align-items:center;gap:6px;padding:5px 12px}\u001b[39m\n\u001b[31m.brand-chip-logo{width:28px;height:18px;object-fit:contain;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{display:block;width:100%;padding:15px;background:var(--or);color:#fff;border:none;border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:700;cursor:pointer;text-align:center;transition:background .15s}\u001b[39m\n\u001b[31m.btn-p:active{background:#ea6c05}.btn-p:disabled{background:var(--g300);cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-s{display:block;width:100%;padding:14px;background:#fff;color:var(--nv);border:1.5px solid var(--g200);border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:500;cursor:pointer;text-align:center}\u001b[39m\n\u001b[31m.btn-s:active{background:var(--g100)}\u001b[39m\n\u001b[31m.btn-o{display:inline-flex;align-items:center;gap:6px;padding:10px 16px;background:#fff;color:var(--or);border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer}\u001b[39m\n\u001b[31m.btn-o:active{background:var(--orl)}\u001b[39m\n\u001b[31m.btn-d{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;background:#fff;color:var(--rd);border:1.5px solid #fecaca;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:12px;cursor:pointer}\u001b[39m\n\u001b[31m.bnav{position:fixed;bottom:var(--host-bar);left:0;right:0;background:#fff;border-top:1px solid var(--g200);display:flex;padding:10px 16px;gap:10px;z-index:100}\u001b[39m\n\u001b[31m.hero{background:var(--nv);color:#fff;padding:20px 16px 24px}\u001b[39m\n\u001b[31m.hero-title{font-size:22px;font-weight:700;margin-bottom:2px}.hero-sub{font-size:13px;color:var(--g400)}\u001b[39m\n\u001b[31m.stats{display:flex;gap:10px;margin-top:16px}\u001b[39m\n\u001b[31m.scard{flex:1;background:rgba(255,255,255,.08);border-radius:var(--rs);padding:12px;text-align:center}\u001b[39m\n\u001b[31m.snum{font-size:22px;font-weight:700}.slbl{font-size:11px;color:var(--g400);margin-top:2px}\u001b[39m\n\u001b[31m.scard.g .snum{color:#4ade80}.scard.a .snum{color:#fbbf24}\u001b[39m\n\u001b[31m.new-btn{background:var(--or);color:#fff;border:none;border-radius:var(--r);padding:16px;font-family:'DM Sans',sans-serif;font-size:16px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:10px;cursor:pointer;width:100%;margin-bottom:10px}\u001b[39m\n\u001b[31m.new-btn:active{background:#ea6c05}\u001b[39m\n\u001b[31m.resume-btn{background:var(--nv2);color:#fff;border:none;border-radius:var(--r);padding:13px 16px;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;display:flex;align-items:center;justify-content:space-between;cursor:pointer;width:100%;margin-bottom:18px}\u001b[39m\n\u001b[31m.sub-card{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:10px;display:flex;align-items:center;gap:12px}\u001b[39m\n\u001b[31m.sub-ico{width:40px;height:40px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}\u001b[39m\n\u001b[31m.sub-ico.pending{background:#fef3c7}.sub-ico.synced{background:#dcfce7}.sub-ico.failed{background:#fee2e2}\u001b[39m\n\u001b[31m.sub-meta{flex:1;min-width:0}.sub-name{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.sub-dtl{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.sbadge{font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;flex-shrink:0}\u001b[39m\n\u001b[31m.sbadge.pending{background:#fef3c7;color:#92400e}.sbadge.synced{background:#dcfce7;color:#14532d}.sbadge.failed{background:#fee2e2;color:#991b1b}\u001b[39m\n\u001b[31m.sh{display:flex;align-items:center;justify-content:space-between;margin:20px 0 12px}\u001b[39m\n\u001b[31m.st{font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.toast{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 8px);left:16px;right:16px;background:var(--nv);color:#fff;padding:12px 16px;border-radius:var(--r);font-size:14px;z-index:1000;transform:translateY(120px);opacity:0;transition:all .3s;pointer-events:none}\u001b[39m\n\u001b[31m.toast.show{transform:translateY(0);opacity:1}.toast.success{background:#16a34a}.toast.error{background:var(--rd)}.toast.info{background:var(--nv2)}\u001b[39m\n\u001b[31m.srow{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:#fff;border-top:1px solid var(--g100);font-size:12px;color:var(--g500)}\u001b[39m\n\u001b[31m.sdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px}.sdot.on{background:var(--gn)}.sdot.off{background:var(--g300)}\u001b[39m\n\u001b[31m.set-item{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:8px}\u001b[39m\n\u001b[31m.set-lbl{font-size:14px;font-weight:600;color:var(--nv);margin-bottom:4px}\u001b[39m\n\u001b[31m.set-sub{font-size:12px;color:var(--g500);margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem{background:#fff;border-radius:var(--r);border:1.5px solid var(--g200);padding:14px;margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\u001b[39m\n\u001b[31m.bitem-title{font-size:14px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.dim-row{display:flex;gap:8px}.dim-row .field{flex:1}\u001b[39m\n\u001b[31m.sqft{display:inline-block;background:var(--g100);color:var(--g600);font-size:12px;padding:4px 10px;border-radius:20px;margin-top:6px}\u001b[39m\n\u001b[31m.divider{height:1px;background:var(--g100);margin:12px 0}\u001b[39m\n\u001b[31m.rev-lbl{font-size:12px;color:var(--g500);margin-bottom:2px}\u001b[39m\n\u001b[31m.rev-val{font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.rev-photos{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}\u001b[39m\n\u001b[31m.rev-thumb{width:56px;height:56px;object-fit:cover;border-radius:var(--rs)}\u001b[39m\n\u001b[31m.empty{text-align:center;padding:40px 20px;color:var(--g400)}.empty-ico{font-size:40px;margin-bottom:12px}.empty-txt{font-size:14px}\u001b[39m\n\u001b[31m/* store picker */\u001b[39m\n\u001b[31m.store-card{border:1.5px solid var(--g200);border-radius:var(--rs);padding:13px 14px;background:#fff;position:relative;cursor:pointer}\u001b[39m\n\u001b[31m.store-card:active{background:var(--g50)}\u001b[39m\n\u001b[31m.store-card-name{font-size:15px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.store-card-meta{font-size:13px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.store-card-change{position:absolute;top:11px;right:12px;background:none;border:none;color:var(--or);font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer}\u001b[39m\n\u001b[31m.brand-tag{display:inline-block;background:var(--nv);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-top:4px}\u001b[39m\n\u001b[31m.last-chip{display:inline-flex;align-items:center;gap:4px;background:#fef3c7;color:#92400e;font-size:11px;font-weight:500;padding:3px 9px;border-radius:20px;margin-left:6px}\u001b[39m\n\u001b[31m.pick-trigger{border:2px solid var(--or);border-radius:var(--rs);padding:14px 16px;background:#fff7ed;display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-size:15px;font-weight:600;color:var(--or)}\u001b[39m\n\u001b[31m.pick-trigger:active{background:#ffedd5;border-color:#ea6800}\u001b[39m\n\u001b[31m.manual-toggle{display:flex;align-items:center;gap:8px;padding:10px 14px;border:1.5px dashed var(--g300);border-radius:var(--rs);cursor:pointer;font-size:13px;color:var(--g600);margin-top:8px;user-select:none}\u001b[39m\n\u001b[31m/* client chip grid */\u001b[39m\n\u001b[31m.cl-chip-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}\u001b[39m\n\u001b[31m.cl-chip{padding:8px 14px;border-radius:20px;border:1.5px solid var(--g200);font-size:13px;font-weight:500;color:var(--g600);background:#fff;cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.cl-chip:active,.cl-chip.sel{background:var(--or);border-color:var(--or);color:#fff;font-weight:600}\u001b[39m\n\u001b[31m.cl-chip-other{border-style:dashed}\u001b[39m\n\u001b[31m.client-tag{display:inline-block;background:#e0f2fe;color:#0369a1;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-left:4px}\u001b[39m\n\u001b[31m.manual-toggle.on{border-color:var(--or);background:#fff7ed;color:var(--or)}\u001b[39m\n\u001b[31m/* picker overlay */\u001b[39m\n\u001b[31m.povl{display:none;position:fixed;inset:0;background:var(--g50);z-index:200;flex-direction:column}\u001b[39m\n\u001b[31m.povl.open{display:flex}\u001b[39m\n\u001b[31m.povl-hdr{background:var(--nv);padding:12px 16px;display:flex;align-items:center;gap:12px;flex-shrink:0}\u001b[39m\n\u001b[31m.psearch{flex:1;padding:10px 14px;border:none;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;background:rgba(255,255,255,.12);color:#fff;outline:none}\u001b[39m\n\u001b[31m.psearch::placeholder{color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.pcancel{background:none;border:none;color:rgba(255,255,255,.7);font-family:'DM Sans',sans-serif;font-size:14px;cursor:pointer;padding:4px;white-space:nowrap}\u001b[39m\n\u001b[31m.plist{overflow-y:auto;flex:1}\u001b[39m\n\u001b[31m.pitem{padding:14px 16px;border-bottom:.5px solid var(--g100);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px}\u001b[39m\n\u001b[31m.pitem:active{background:var(--g100)}\u001b[39m\n\u001b[31m.pi-name{font-size:15px;font-weight:600;color:var(--nv)}.pi-addr{font-size:12px;color:var(--g500);margin-top:2px}.pi-last{font-size:11px;color:var(--am);margin-top:2px}\u001b[39m\n\u001b[31m.pi-brand{font-size:11px;font-weight:700;padding:3px 8px;border-radius:20px;background:var(--nv);color:#fff;flex-shrink:0}\u001b[39m\n\u001b[31m.psec{padding:8px 16px 4px;font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;background:var(--g50)}\u001b[39m\n\u001b[31m.padd{padding:16px;text-align:center;font-size:14px;color:var(--or);font-weight:600;cursor:pointer;background:#fff7ed;border-top:1.5px dashed var(--or)}\u001b[39m\n\u001b[31m.gps-row{display:flex;gap:8px;margin-top:8px}\u001b[39m\n\u001b[31m.gps-btn{flex-shrink:0;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;color:var(--g500);display:flex;align-items:center;gap:6px}\u001b[39m\n\u001b[31m.gps-btn:active{background:var(--orl);border-color:var(--or);color:var(--or)}\u001b[39m\n\u001b[31m@keyframes spin{to{transform:rotate(360deg)}}.spin{animation:spin .7s linear infinite;display:inline-block}\u001b[39m\n\u001b[31m/* ANNOTATION TOOL */\u001b[39m\n\u001b[31m.annot-modal{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column}\u001b[39m\n\u001b[31m.annot-modal.open{display:flex}\u001b[39m\n\u001b[31m.annot-bar{background:var(--nv);padding:8px 12px;flex-shrink:0}\u001b[39m\n\u001b[31m.annot-row{display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap}\u001b[39m\n\u001b[31m.annot-row:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.atool{padding:6px 10px;background:rgba(255,255,255,.1);border:1.5px solid rgba(255,255,255,.2);border-radius:var(--rs);color:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:500;cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.atool.on{background:var(--or);border-color:var(--or)}\u001b[39m\n\u001b[31m.atool.sel-on{background:#7c3aed;border-color:#7c3aed}\u001b[39m\n\u001b[31m.acolor{width:24px;height:24px;border-radius:50%;border:2px solid rgba(255,255,255,.3);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.acolor.on{border-color:#fff;border-width:3px;transform:scale(1.15)}\u001b[39m\n\u001b[31m.annot-cvs-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#111;position:relative}\u001b[39m\n\u001b[31m#annot-cvs{max-width:100%;max-height:100%;display:block;touch-action:none;cursor:crosshair}\u001b[39m\n\u001b[31m.annot-foot{background:var(--nv);padding:10px 16px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.req-note{font-size:12px;color:var(--rd);margin-top:6px;font-weight:500}\u001b[39m\n\u001b[31m/* Bottom dialog */\u001b[39m\n\u001b[31m.bdialog-wrap{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:400;align-items:flex-end}\u001b[39m\n\u001b[31m.bdialog-wrap.open{display:flex}\u001b[39m\n\u001b[31m.bdialog{background:#fff;border-radius:var(--r) var(--r) 0 0;padding:20px 16px 32px;width:100%}\u001b[39m\n\u001b[31m.bdialog-title{font-size:16px;font-weight:700;color:var(--nv);margin-bottom:6px}\u001b[39m\n\u001b[31m.bdialog-sub{font-size:13px;color:var(--g500);margin-bottom:16px}\u001b[39m\n\u001b[31m.bdialog-btns{display:flex;gap:10px}\u001b[39m\n\u001b[31m/* Edit badge on sub-card */\u001b[39m\n\u001b[31m.edit-btn-sm{padding:5px 12px;background:var(--g50);border:1px solid var(--g200);border-radius:20px;font-family:'DM Sans',sans-serif;font-size:12px;color:var(--g600);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m/* Toggle switch */\u001b[39m\n\u001b[31m.tog{width:48px;height:26px;background:var(--g300);border-radius:13px;cursor:pointer;transition:background .2s;flex-shrink:0;position:relative;display:inline-block}\u001b[39m\n\u001b[31m.tog.on{background:var(--or)}\u001b[39m\n\u001b[31m.tog-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2);pointer-events:none}\u001b[39m\n\u001b[31m.tog.on .tog-knob{transform:translateX(22px)}\u001b[39m\n\u001b[31m/* ── ADMIN RECCE VIEW ── */\u001b[39m\n\u001b[31m.af-bar{background:var(--g100);padding:10px 16px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--g200);overflow:hidden}\u001b[39m\n\u001b[31m.af-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}\u001b[39m\n\u001b[31m.af-sel{width:100%;padding:8px 10px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv);cursor:pointer;\u001b[39m\n\u001b[31m  white-space:normal;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.af-sel:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.af-inp{width:100%;padding:8px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv)}\u001b[39m\n\u001b[31m.af-inp:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.grp-hdr{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;\u001b[39m\n\u001b[31m  letter-spacing:.5px;padding:14px 0 6px;border-bottom:1px solid var(--g200);margin-bottom:6px}\u001b[39m\n\u001b[31m.grp-hdr:first-child{padding-top:0}\u001b[39m\n\u001b[31m.asc{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:12px 14px;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;gap:6px;margin-bottom:8px;cursor:pointer;\u001b[39m\n\u001b[31m  transition:box-shadow .15s}\u001b[39m\n\u001b[31m.asc:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.asc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}\u001b[39m\n\u001b[31m.asc-name{font-size:14px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.asc-brand{display:inline-block;background:#fff7ed;color:var(--or);font-size:11px;\u001b[39m\n\u001b[31m  font-weight:600;padding:2px 8px;border-radius:20px;border:1px solid #fed7aa;white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chip{background:var(--g100);border-radius:20px;padding:2px 8px;font-size:11px;color:var(--g600);white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chips{display:flex;flex-wrap:wrap;gap:5px}\u001b[39m\n\u001b[31m.asc-agent{background:var(--nv);color:#fff;font-size:11px;font-weight:600;\u001b[39m\n\u001b[31m  padding:2px 8px;border-radius:20px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m/* Admin detail modal */\u001b[39m\n\u001b[31m.ardl-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:600;\u001b[39m\n\u001b[31m  display:flex;align-items:flex-end;justify-content:center}\u001b[39m\n\u001b[31m.ardl-box{background:#fff;border-radius:var(--r) var(--r) 0 0;width:100%;max-height:80vh;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ardl-hdr{display:flex;align-items:flex-start;justify-content:space-between;\u001b[39m\n\u001b[31m  padding:16px 16px 10px;border-bottom:1px solid var(--g200);gap:10px}\u001b[39m\n\u001b[31m.ardl-title{font-size:17px;font-weight:700;color:var(--nv);line-height:1.3}\u001b[39m\n\u001b[31m.ardl-body{flex:1;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:14px}\u001b[39m\n\u001b[31m.ardl-sec{display:flex;flex-direction:column;gap:6px}\u001b[39m\n\u001b[31m.ardl-lbl{font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.ardl-val{font-size:13px;color:var(--nv);line-height:1.5}\u001b[39m\n\u001b[31m.ardl-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\u001b[39m\n\u001b[31m/* Hub home button */\u001b[39m\n\u001b[31m.btn-hub{background:none;border:1px solid rgba(255,255,255,.25);color:rgba(255,255,255,.85);\u001b[39m\n\u001b[31m  font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;cursor:pointer;\u001b[39m\n\u001b[31m  display:flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-hub:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hdr-r{display:flex;align-items:center;gap:6px;margin-left:auto;flex-shrink:0}\u001b[39m\n\u001b[31m.hdr-user{font-size:11px;color:rgba(255,255,255,.7);white-space:nowrap;max-width:80px;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.btn-logout{background:none;border:1px solid rgba(255,255,255,.2);color:rgba(255,255,255,.7);font-size:11px;font-weight:600;padding:4px 8px;border-radius:20px;cursor:pointer;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-logout:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hero-ubar{display:flex;align-items:center;justify-content:space-between;padding-top:6px;margin-top:2px}\u001b[39m\n\u001b[31m.hero-uname{font-size:12px;color:rgba(255,255,255,.65)}\u001b[39m\n\u001b[31m.hi-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .en-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .hi-txt{display:inline}\u001b[39m\n\u001b[31m.lang-btn{background:none;border:1px solid rgba(255,255,255,.3);color:rgba(255,255,255,.8);font-size:12px;font-weight:700;padding:4px 10px;border-radius:20px;cursor:pointer;display:flex;align-items:center;gap:3px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.lang-btn:active{background:rgba(255,255,255,.15)}\u001b[39m\n\u001b[31m/* ── DELETE / AUDIT ── */\u001b[39m\n\u001b[31m.del-btn{background:none;border:none;padding:6px 8px;cursor:pointer;color:var(--g400);font-size:16px;flex-shrink:0;border-radius:var(--rs);transition:color .15s,background .15s}\u001b[39m\n\u001b[31m.del-btn:active{color:var(--rd);background:#fee2e2}\u001b[39m\n\u001b[31m.asc.deleted-row{background:#fff5f5;border:1px solid #fecaca;opacity:.85}\u001b[39m\n\u001b[31m.asc.deleted-row .asc-name{text-decoration:line-through;color:var(--g500)}\u001b[39m\n\u001b[31m.del-reason-tag{display:inline-block;background:#fee2e2;color:var(--rd);font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.del-by-txt{font-size:11px;color:var(--g400);margin-top:3px}\u001b[39m\n\u001b[31m.restore-btn{background:none;border:1.5px solid #bbf7d0;border-radius:20px;color:#16a34a;font-size:11px;font-weight:700;padding:3px 10px;cursor:pointer;white-space:nowrap;margin-top:5px}\u001b[39m\n\u001b[31m.restore-btn:active{background:#dcfce7}\u001b[39m\n\u001b[31m.sup-tile{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:20px 16px;cursor:pointer;display:flex;align-items:center;gap:14px;margin-bottom:12px;transition:box-shadow .15s}\u001b[39m\n\u001b[31m.sup-tile:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.sup-tile-ico{width:48px;height:48px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:26px;flex-shrink:0}\u001b[39m\n\u001b[31m.sup-tile-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.sup-tile-title{font-size:15px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.sup-tile-sub{font-size:12px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.del-toggle-btn{padding:6px 14px;border:1.5px solid var(--g200);border-radius:20px;background:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:600;color:var(--g500);cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.del-toggle-btn.active{background:#fee2e2;border-color:#fecaca;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1.5px solid var(--g200);border-radius:var(--r);margin-bottom:10px;cursor:pointer;transition:all .15s;font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.reason-opt:active{background:var(--g50)}\u001b[39m\n\u001b[31m.reason-opt.sel{border-color:var(--rd);background:#fff5f5;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt.danger{border-color:#fdba74;background:#fff7ed;color:#9a3412}\u001b[39m\n\u001b[31m.reason-opt.danger.sel{border-color:#c2410c;background:#fff1e6;color:#9a3412}\u001b[39m\n\u001b[31m#del-confirm-btn.no-reason{background:var(--g300)!important;cursor:default}\u001b[39m\n\u001b[31m@keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}\u001b[39m\n\u001b[31m.reason-opt-ico{font-size:22px;flex-shrink:0}\u001b[39m\n\u001b[31m/* ── APP UPDATE BANNER ── */\u001b[39m\n\u001b[31m.upd-banner{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);left:12px;right:12px;background:#16a34a;color:#fff;padding:11px 14px;border-radius:var(--r);display:flex;align-items:center;justify-content:space-between;gap:10px;z-index:550;box-shadow:0 4px 16px rgba(0,0,0,.18);transform:translateY(120px);opacity:0;transition:transform .35s ease,opacity .35s ease;pointer-events:none}\u001b[39m\n\u001b[31m.upd-banner.show{transform:translateY(0);opacity:1;pointer-events:auto}\u001b[39m\n\u001b[31m/* ── EDIT REQUEST ── */\u001b[39m\n\u001b[31m.req-edit-btn{padding:4px 10px;background:#fffbeb;border:1px solid #fde68a;border-radius:20px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:600;color:#92400e;cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.req-edit-btn:active{background:#fef3c7}\u001b[39m\n\u001b[31m.edit-req-badge{display:inline-block;background:#fef3c7;color:#92400e;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;white-space:nowrap}\u001b[39m\n\u001b[31m.edit-req-card{background:#fffbeb;border:1.5px solid #fde68a;border-radius:var(--r);padding:14px 16px;margin-bottom:10px;display:flex;align-items:flex-start;gap:12px}\u001b[39m\n\u001b[31m.edit-req-card-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.edit-req-card-name{font-size:14px;font-weight:600;color:var(--nv);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.edit-req-card-meta{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.edit-req-cmt{font-size:12px;color:#78350f;background:#fff;border:1px solid #fde68a;border-radius:var(--rs);padding:8px 10px;margin-top:8px;line-height:1.5}\u001b[39m\n\u001b[31m.edit-req-section-hdr{font-size:11px;font-weight:700;color:#92400e;text-transform:uppercase;letter-spacing:.5px;padding:10px 0 6px;border-bottom:1px solid #fde68a;margin-bottom:8px}\u001b[39m\n\u001b[31m.upd-banner-ok{background:rgba(255,255,255,.2);border:none;color:#fff;border-radius:20px;padding:5px 13px;font-size:12px;font-weight:600;cursor:pointer;font-family:'DM Sans',sans-serif;white-space:nowrap}\u001b[39m\n\u001b[31m.upd-banner-ok:active{background:rgba(255,255,255,.35)}\u001b[39m\n\u001b[31m/* ── FONT SIZE WIDGET ── */\u001b[39m\n\u001b[31m.fs-widget{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);right:12px;display:flex;align-items:center;gap:0;background:#fff;border:1.5px solid var(--g200);border-radius:24px;box-shadow:0 2px 8px rgba(0,0,0,.12);z-index:500;overflow:hidden;user-select:none}\u001b[39m\n\u001b[31m.fs-btn{background:none;border:none;cursor:pointer;padding:7px 11px;color:var(--g500);line-height:1;transition:background .15s}\u001b[39m\n\u001b[31m.fs-btn:active{background:var(--g100)}\u001b[39m\n\u001b[31m.fs-btn:disabled{color:var(--g300);cursor:default}\u001b[39m\n\u001b[31m.fs-label{font-size:11px;font-weight:700;color:var(--g500);padding:0 4px;pointer-events:none}\u001b[39m\n\u001b[31m/* Level 1 — Large (+15%) */\u001b[39m\n\u001b[31mbody.fs-1 .field label,body.fs-1 .card-title,body.fs-1 .set-lbl,body.fs-1 .set-sub,\u001b[39m\n\u001b[31mbody.fs-1 .hdr-title,body.fs-1 .hdr-sub,body.fs-1 .slbl,body.fs-1 .rev-lbl,body.fs-1 .rev-val,\u001b[39m\n\u001b[31mbody.fs-1 .rbtn,body.fs-1 .chip,body.fs-1 .btn-p,body.fs-1 .btn-s,body.fs-1 .btn-o,\u001b[39m\n\u001b[31mbody.fs-1 .bdialog-title,body.fs-1 .bdialog-sub,body.fs-1 .sub-name,body.fs-1 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-1 .pslot-lbl,body.fs-1 .bitem-title,body.fs-1 .pi-name,body.fs-1 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-1 .asc-name,body.fs-1 .new-btn,body.fs-1 .resume-btn,body.fs-1 .ardl-lbl,body.fs-1 .ardl-val{font-size:calc(1em * 1.15) !important}\u001b[39m\n\u001b[31m/* Level 2 — X-Large (+30%) */\u001b[39m\n\u001b[31mbody.fs-2 .field label,body.fs-2 .card-title,body.fs-2 .set-lbl,body.fs-2 .set-sub,\u001b[39m\n\u001b[31mbody.fs-2 .hdr-title,body.fs-2 .hdr-sub,body.fs-2 .slbl,body.fs-2 .rev-lbl,body.fs-2 .rev-val,\u001b[39m\n\u001b[31mbody.fs-2 .rbtn,body.fs-2 .chip,body.fs-2 .btn-p,body.fs-2 .btn-s,body.fs-2 .btn-o,\u001b[39m\n\u001b[31mbody.fs-2 .bdialog-title,body.fs-2 .bdialog-sub,body.fs-2 .sub-name,body.fs-2 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-2 .pslot-lbl,body.fs-2 .bitem-title,body.fs-2 .pi-name,body.fs-2 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-2 .asc-name,body.fs-2 .new-btn,body.fs-2 .resume-btn,body.fs-2 .ardl-lbl,body.fs-2 .ardl-val{font-size:calc(1em * 1.30) !important}\u001b[39m\n\u001b[31m/* Level 3 — XX-Large (+50%) */\u001b[39m\n\u001b[31mbody.fs-3 .field label,body.fs-3 .card-title,body.fs-3 .set-lbl,body.fs-3 .set-sub,\u001b[39m\n\u001b[31mbody.fs-3 .hdr-title,body.fs-3 .hdr-sub,body.fs-3 .slbl,body.fs-3 .rev-lbl,body.fs-3 .rev-val,\u001b[39m\n\u001b[31mbody.fs-3 .rbtn,body.fs-3 .chip,body.fs-3 .btn-p,body.fs-3 .btn-s,body.fs-3 .btn-o,\u001b[39m\n\u001b[31mbody.fs-3 .bdialog-title,body.fs-3 .bdialog-sub,body.fs-3 .sub-name,body.fs-3 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-3 .pslot-lbl,body.fs-3 .bitem-title,body.fs-3 .pi-name,body.fs-3 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-3 .asc-name,body.fs-3 .new-btn,body.fs-3 .resume-btn,body.fs-3 .ardl-lbl,body.fs-3 .ardl-val{font-size:calc(1em * 1.50) !important}\u001b[39m\n\u001b[31m/* Level 4 — Max (+70%) */\u001b[39m\n\u001b[31mbody.fs-4 .field label,body.fs-4 .card-title,body.fs-4 .set-lbl,body.fs-4 .set-sub,\u001b[39m\n\u001b[31mbody.fs-4 .hdr-title,body.fs-4 .hdr-sub,body.fs-4 .slbl,body.fs-4 .rev-lbl,body.fs-4 .rev-val,\u001b[39m\n\u001b[31mbody.fs-4 .rbtn,body.fs-4 .chip,body.fs-4 .btn-p,body.fs-4 .btn-s,body.fs-4 .btn-o,\u001b[39m\n\u001b[31mbody.fs-4 .bdialog-title,body.fs-4 .bdialog-sub,body.fs-4 .sub-name,body.fs-4 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-4 .pslot-lbl,body.fs-4 .bitem-title,body.fs-4 .pi-name,body.fs-4 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-4 .asc-name,body.fs-4 .new-btn,body.fs-4 .resume-btn,body.fs-4 .ardl-lbl,body.fs-4 .ardl-val{font-size:calc(1em * 1.70) !important}\u001b[39m\n\u001b[31m/* ── RECCE TILE ACTION BUTTONS ── */\u001b[39m\n\u001b[31m.rpt-btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid rgba(0,0,0,.06)}\u001b[39m\n\u001b[31m.rpt-btn{display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 14px;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;border:none;font-family:inherit;transition:background .15s,opacity .15s;flex:1;min-width:110px;letter-spacing:.1px;white-space:nowrap}\u001b[39m\n\u001b[31m.rpt-btn-report{background:#fff7ed;color:var(--or);border:1.5px solid var(--or)}\u001b[39m\n\u001b[31m.rpt-btn-report:active{background:#fed7aa}\u001b[39m\n\u001b[31m.rpt-btn-pdf{background:var(--g100);color:var(--g400);border:1.5px solid var(--g200)}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready{background:var(--or);color:#fff;border-color:transparent}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready:active{background:#ea6c00}\u001b[39m\n\u001b[31m/* PDF wait overlay */\u001b[39m\n\u001b[31m#pdf-wait-ov{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m</style>\u001b[39m\n\u001b[31m</head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<!-- PICKER OVERLAY -->\u001b[39m\n\u001b[31m<div class=\\\"povl\\\" id=\\\"povl\\\">\u001b[39m\n\u001b[31m  <div class=\\\"povl-hdr\\\">\u001b[39m\n\u001b[31m    <input class=\\\"psearch\\\" id=\\\"psearch\\\" type=\\\"text\\\" placeholder=\\\"Search store / दुकान खोजें…\\\" oninput=\\\"filterPicker(this.value)\\\" autocomplete=\\\"off\\\">\u001b[39m\n\u001b[31m    <button class=\\\"pcancel\\\" onclick=\\\"closePicker()\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"plist\\\" id=\\\"plist\\\"></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"app\\\">·\u001b[39m\n\u001b[31m<!-- HOME -->\u001b[39m\n\u001b[31m<div class=\\\"view active\\\" id=\\\"view-home\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hero\\\">\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;justify-content:space-between;align-items:center\\\">\u001b[39m\n\u001b[31m      <div><div class=\\\"hero-title\\\"><span class=\\\"en-txt\\\">Branding Recce</span><span class=\\\"hi-txt\\\">ब्रांडिंग रेकी</span></div><div class=\\\"hero-sub\\\" id=\\\"today-date\\\">—</div></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:6px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"lang-btn\\\" onclick=\\\"setLang(LANG==='en'?'hi':'en')\\\" id=\\\"lang-btn\\\" title=\\\"Switch language / भाषा बदलें\\\">EN | हि</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-hub\\\" onclick=\\\"goToHub()\\\">🏡 Hub</button>\u001b[39m\n\u001b[31m      <button class=\\\"icon-btn\\\" onclick=\\\"showView('settings')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12 15a3 3 0 100-6 3 3 0 000 6z\\\"/><path d=\\\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\\\"/></svg></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"hero-ubar\\\" id=\\\"recce-hero-ubar\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <span class=\\\"hero-uname\\\" id=\\\"recce-hero-name\\\"></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-logout\\\" onclick=\\\"recceLogout()\\\">Logout</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"stats\\\">\u001b[39m\n\u001b[31m      <div class=\\\"scard g\\\"><div class=\\\"snum\\\" id=\\\"stat-synced\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Synced</span><span class=\\\"hi-txt\\\">सिंक्ड</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard a\\\"><div class=\\\"snum\\\" id=\\\"stat-pending\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Pending</span><span class=\\\"hi-txt\\\">बाकी</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard\\\"><div class=\\\"snum\\\" id=\\\"stat-total\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Total</span><span class=\\\"hi-txt\\\">कुल</span></div></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <button class=\\\"new-btn\\\" onclick=\\\"startNewRecce()\\\"><svg width=\\\"20\\\" height=\\\"20\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">New Recce</span><span class=\\\"hi-txt\\\">नई रेकी</span></button>\u001b[39m\n\u001b[31m    <div id=\\\"resume-wrap\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"sh\\\"><span class=\\\"st\\\"><span class=\\\"en-txt\\\">Recent Submissions</span><span class=\\\"hi-txt\\\">हाल की सबमिशन</span></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"syncNow()\\\" id=\\\"sync-btn\\\" style=\\\"padding:7px 12px;font-size:12px\\\"><svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg><span class=\\\"en-txt\\\">Sync</span><span class=\\\"hi-txt\\\">सिंक</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"sub-list\\\"></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"srow\\\"><div><span class=\\\"sdot\\\" id=\\\"net-dot\\\"></span><span id=\\\"net-txt\\\"><span class=\\\"en-txt\\\">Checking…</span><span class=\\\"hi-txt\\\">जाँच…</span></span></div><span id=\\\"last-sync-txt\\\" style=\\\"font-size:11px\\\"><span class=\\\"en-txt\\\">Never synced</span><span class=\\\"hi-txt\\\">कभी सिंक नहीं</span></span></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- SETTINGS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-settings\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('home')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Settings</span><span class=\\\"hi-txt\\\">सेटिंग</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Brand List</span><span class=\\\"hi-txt\\\">ब्रांड सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Manage Brands</span><span class=\\\"hi-txt\\\">ब्रांड प्रबंधन</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">These appear in the brand dropdown and store picker. Add client brands as needed.</div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-manage-list\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-add-row\\\" style=\\\"display:none;gap:8px;align-items:center\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"brand-add-inp\\\" placeholder=\\\"Type brand name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addBrandToList()\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"addBrandToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Store Lists</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Supervisors can upload XLS/CSV store lists here. Updates sync to all devices via server.</span><span class=\\\"hi-txt\\\">सुपरवाइजर यहाँ XLS/CSV स्टोर सूची अपलोड कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m      <!-- Upload/Clear row — supervisor only -->\u001b[39m\n\u001b[31m      <div id=\\\"store-upload-row\\\" style=\\\"display:none;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;margin-top:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"document.getElementById('store-xl').click()\\\"><svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Add File</span><span class=\\\"hi-txt\\\">फ़ाइल जोड़ें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-d\\\" onclick=\\\"clearStoreList()\\\" style=\\\"font-size:12px\\\"><span class=\\\"en-txt\\\">Clear All Stores</span><span class=\\\"hi-txt\\\">सभी स्टोर हटाएं</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" id=\\\"store-push-btn\\\" onclick=\\\"pushStoresToServer()\\\" style=\\\"font-size:12px;display:none\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Push to Server</span><span class=\\\"hi-txt\\\">सर्वर पर पुश करें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"store-xl\\\" accept=\\\".xlsx,.xls,.csv\\\" onchange=\\\"handleStoreUpload(event)\\\">\u001b[39m\n\u001b[31m      <div id=\\\"store-count\\\" style=\\\"font-size:13px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"store-file-list\\\" style=\\\"margin-top:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Brand assignment dialog for files with no brand column -->\u001b[39m\n\u001b[31m    <div id=\\\"brand-assign-dialog\\\" style=\\\"display:none;margin-top:10px;padding:14px;background:#fff7ed;border:1.5px solid var(--or);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\">Which brand is this store list for?</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\" id=\\\"brand-assign-fname\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-assign-chips\\\" class=\\\"chip-grid\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"confirmBrandAssign()\\\" style=\\\"flex:2;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">Assign Brand</span><span class=\\\"hi-txt\\\">ब्रांड असाइन करें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"skipBrandAssign()\\\" style=\\\"flex:1;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">No Brand</span><span class=\\\"hi-txt\\\">कोई ब्रांड नहीं</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Server Store List URL (Admin)</span><span class=\\\"hi-txt\\\">सर्वर स्टोर सूची URL</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Admin pushes stores.json to any public URL. App auto-fetches on open and caches offline.</div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"srv-url\\\" placeholder=\\\"https://yourserver.com/stores.json\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"fetchServerStores()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Fetch Now</button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"saveServerUrl()\\\" style=\\\"padding:9px 14px;font-size:13px;width:auto\\\">Save URL</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Sync Endpoint</span><span class=\\\"hi-txt\\\">सिंक एंडपॉइंट</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Slides Generator</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Managed by admin. Deploy gas_slides.gs from /opt/slides-proxy/ to Google Apps Script and paste the URL here.</div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"slides-gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Not configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"slides-gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"saveSlidesGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Sheet Sync</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Legacy sync endpoint. Writes recce data to Google Sheet.</div>·\u001b[39m\n\u001b[31m      <!-- Locked state (default) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Endpoint configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Unlocked state (after admin login) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;align-items:center;gap:8px;margin-bottom:10px;padding:7px 12px;background:#dcfce7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          <span style=\\\"font-size:12px;color:#14532d;font-weight:600\\\">🔓 Admin mode active</span>\u001b[39m\n\u001b[31m          <button onclick=\\\"lockAdmin()\\\" style=\\\"margin-left:auto;background:none;border:none;color:#14532d;font-size:12px;cursor:pointer;font-weight:600\\\">Lock ×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"testEndpoint()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Test</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>·\u001b[39m\n\u001b[31m    <!-- Admin Login Modal -->\u001b[39m\n\u001b[31m    <div id=\\\"admin-login-modal\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m      <div style=\\\"background:#fff;border-radius:var(--r);padding:24px 20px;margin:20px;max-width:380px;width:100%;box-shadow:0 8px 32px rgba(0,0,0,.2)\\\">\u001b[39m\n\u001b[31m        <div style=\\\"font-size:17px;font-weight:700;color:var(--nv);margin-bottom:4px\\\">Admin Login</div>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:18px\\\">Enter admin password to unlock settings</div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m          <label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">Password</label>\u001b[39m\n\u001b[31m          <input type=\\\"password\\\" id=\\\"admin-pwd\\\" placeholder=\\\"Enter admin password\\\" style=\\\"width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px\\\" onkeydown=\\\"if(event.key==='Enter')verifyAdmin()\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div id=\\\"admin-error\\\" style=\\\"display:none;font-size:12px;color:var(--rd);margin-bottom:12px;padding:8px 12px;background:#fee2e2;border-radius:var(--rs)\\\">Incorrect password</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"verifyAdmin()\\\" style=\\\"flex:2;padding:13px\\\" id=\\\"admin-login-btn\\\">Login</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-s\\\" onclick=\\\"closeAdminLogin()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:14px;padding-top:14px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.4px;margin-bottom:8px\\\">Admin Password Config URL</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:8px\\\">URL to your admin.json file on server (contains hashed password)</div>\u001b[39m\n\u001b[31m          <input type=\\\"url\\\" id=\\\"admin-cfg-url\\\" placeholder=\\\"https://yourserver.com/admin.json\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px;margin-bottom:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveAdminCfgUrl()\\\" style=\\\"font-size:12px;padding:7px 12px;width:100%;justify-content:center\\\">Save Config URL</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Geolocation Stamp</span><span class=\\\"hi-txt\\\">जियोलोकेशन स्टैम्प</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;justify-content:space-between;gap:16px\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1\\\">\u001b[39m\n\u001b[31m          <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Stamp on Photos</span><span class=\\\"hi-txt\\\">फोटो पर स्टैम्प</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"set-sub\\\" style=\\\"margin-bottom:0\\\">Bakes GPS coordinates, store name and timestamp into every photo — visible in the image itself. Same as GPS Map Camera app. Default: On.</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"tog on\\\" id=\\\"geo-tog\\\" onclick=\\\"toggleGeoStamp()\\\"><div class=\\\"tog-knob\\\"></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"geo-status\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\">GPS not yet captured</div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Image Quality</span><span class=\\\"hi-txt\\\">फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Default Photo Quality</span><span class=\\\"hi-txt\\\">डिफ़ॉल्ट फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Applies to all photos — front view, inside view, branding, and additional. HD uses more storage and takes longer to sync on poor networks.</div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;gap:10px;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-compressed\\\" onclick=\\\"setImgQuality('compressed')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-compressed\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-compressed\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">Full Compression</span><span class=\\\"hi-txt\\\">पूर्ण कम्प्रेशन</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~150–200 KB · Max 1280px · Best for poor network</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-left:auto;font-size:11px;font-weight:700;color:var(--gn);background:#dcfce7;padding:3px 8px;border-radius:20px\\\"><span class=\\\"en-txt\\\">Recommended</span><span class=\\\"hi-txt\\\">अनुशंसित</span></div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-hd\\\" onclick=\\\"setImgQuality('hd')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-hd\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-hd\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">HD Quality</span><span class=\\\"hi-txt\\\">HD क्वालिटी</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~400–600 KB · Max 1920px · Better detail for print</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"q-current-badge\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Supervisor Config panel — shown only to supervisors via renderSupPanel() -->\u001b[39m\n\u001b[31m    <div id=\\\"sup-panel\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">🔐 Recce Access Config</span><span class=\\\"hi-txt\\\">🔐 रेकी एक्सेस कॉन्फ़िग</span></div>\u001b[39m\n\u001b[31m      <!-- Access mode — only H/P can change -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"mode-row\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Access Mode</span><span class=\\\"hi-txt\\\">एक्सेस मोड</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Public: any Hub user can submit Recces. Assigned: only Supervisors and Creators can access.</span><span class=\\\"hi-txt\\\">सार्वजनिक: कोई भी Hub यूजर। नियत: सिर्फ़ Supervisors और Creators।</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\" style=\\\"margin-bottom:8px;margin-top:8px\\\">\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-public\\\" onclick=\\\"setRecceMode('public')\\\"><span class=\\\"en-txt\\\">Public</span><span class=\\\"hi-txt\\\">सार्वजनिक</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-assigned\\\" onclick=\\\"setRecceMode('assigned')\\\"><span class=\\\"en-txt\\\">Assigned</span><span class=\\\"hi-txt\\\">नियत</span></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Supervisor list — view all + delete + create -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Supervisors</span><span class=\\\"hi-txt\\\">सुपरवाइजर</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can view all recces, delete with reason, and submit. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">सभी रेकी देख सकते हैं, कारण से हटा सकते हैं, और सबमिट कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"sup-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addSupervisor()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addSupervisor()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Creator list — creation only -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Creators</span><span class=\\\"hi-txt\\\">क्रिएटर्स</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can submit Recces only — no admin view or deletion rights. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">केवल रेकी सबमिट कर सकते हैं — एडमिन व्यू या डिलीट नहीं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"creator-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addCreator()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addCreator()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Client list — used for client portal scoping -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clients</span><span class=\\\"hi-txt\\\">क्लाइंट</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Names that appear as chips when submitting a recce. Add the brand or agency name (e.g. \\\"Marketing Vibe\\\"). These are used to scope what clients see in the Client Portal.</span><span class=\\\"hi-txt\\\">रेकी सबमिट करते समय दिखने वाले क्लाइंट नाम। ब्रांड या एजेंसी नाम जोड़ें।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-mgmt-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"client-add-inp\\\" placeholder=\\\"Client name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addClientToList()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addClientToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Sync to server — only H/P -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"cfg-sync-btn\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Sync Config to Server</span><span class=\\\"hi-txt\\\">सर्वर पर कॉन्फ़िग सिंक करें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Apply supervisor/creator/client lists and access mode to all devices.</span><span class=\\\"hi-txt\\\">सभी डिवाइस पर कॉन्फ़िग लागू करें।</span></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"syncCfgToServer()\\\" style=\\\"max-width:220px;font-size:14px;padding:12px;margin-top:8px\\\"><span class=\\\"en-txt\\\">Sync to Server</span><span class=\\\"hi-txt\\\">सर्वर पर सिंक करें</span></button>\u001b[39m\n\u001b[31m        <div id=\\\"cfg-sync-status\\\" style=\\\"margin-top:8px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Danger Zone</span><span class=\\\"hi-txt\\\">खतरनाक ज़ोन</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\"><div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clear All Local Data</span><span class=\\\"hi-txt\\\">सभी डेटा हटाएं</span></div><div class=\\\"set-sub\\\">Removes all submissions from this device.</div><button class=\\\"btn-d\\\" onclick=\\\"clearData()\\\" style=\\\"padding:9px 14px;font-size:13px\\\">Clear All</button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: STORE INFO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-store\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"exitForm()\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Details</span><span class=\\\"hi-txt\\\">दुकान विवरण</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 1 of 5</span><span class=\\\"hi-txt\\\">चरण 1 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:20%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Recce Info</span><span class=\\\"hi-txt\\\">रेकी जानकारी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Date of Recce</span><span class=\\\"hi-txt\\\">रेकी की तारीख</span> <span class=\\\"req\\\">*</span></label><input type=\\\"date\\\" id=\\\"f-date\\\" onchange=\\\"saveDraft()\\\" max=\\\"\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" id=\\\"campaign-field\\\">\u001b[39m\n\u001b[31m        <label><span class=\\\"en-txt\\\">Job / Campaign</span><span class=\\\"hi-txt\\\">जॉब / कैंपेन</span></label>\u001b[39m\n\u001b[31m        <select id=\\\"f-campaign-id\\\" onchange=\\\"onCampaignSelect()\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">Loading campaigns…</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <div id=\\\"campaign-notify-msg\\\" style=\\\"display:none;font-size:12px;color:#92400e;margin-top:6px;padding:8px 10px;background:#fef3c7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          ⚑ <span class=\\\"en-txt\\\">Recce will submit without a job ID. A notification will flag this for your supervisor to link it later.</span><span class=\\\"hi-txt\\\">रेकी बिना जॉब ID के सबमिट होगी। सुपरवाइजर बाद में लिंक करेगा।</span>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Store</span><span class=\\\"hi-txt\\\">दुकान</span> <span id=\\\"store-avail-tag\\\" style=\\\"font-size:11px;color:var(--g400);font-weight:400;text-transform:none;letter-spacing:0\\\"></span></div>·\u001b[39m\n\u001b[31m      <!-- When store is selected -->\u001b[39m\n\u001b[31m      <div id=\\\"store-selected\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"store-card\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:start;justify-content:space-between;gap:8px\\\">\u001b[39m\n\u001b[31m            <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m              <div class=\\\"store-card-name\\\" id=\\\"sc-name\\\">—</div>\u001b[39m\n\u001b[31m              <div style=\\\"display:flex;align-items:center;gap:6px;margin-top:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m                <span class=\\\"brand-tag\\\" id=\\\"sc-brand\\\">—</span>\u001b[39m\n\u001b[31m                <span class=\\\"last-chip\\\" id=\\\"sc-last\\\" style=\\\"display:none\\\">—</span>\u001b[39m\n\u001b[31m              </div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            <button class=\\\"store-card-change\\\" onclick=\\\"openPicker()\\\"><span class=\\\"en-txt\\\">Change ›</span><span class=\\\"hi-txt\\\">बदलें ›</span></button>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <!-- All fields from Excel shown here -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-details\\\" style=\\\"margin-top:10px;display:flex;flex-direction:column;gap:4px\\\"></div>\u001b[39m\n\u001b[31m          <!-- Missing required fields — editable inline -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-missing\\\" style=\\\"display:none;margin-top:12px;padding-top:12px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m            <div style=\\\"font-size:11px;font-weight:700;color:var(--rd);text-transform:uppercase;letter-spacing:.4px;margin-bottom:10px\\\">⚠ Please complete missing fields</div>\u001b[39m\n\u001b[31m            <div id=\\\"sc-missing-fields\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <!-- Brand selector — shown when store has no brand -->\u001b[39m\n\u001b[31m        <div id=\\\"brand-selector\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\"><span class=\\\"en-txt\\\">Select Brand</span><span class=\\\"hi-txt\\\">ब्रांड चुनें</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\">This store has no brand in the list — select one:</div>\u001b[39m\n\u001b[31m          <div id=\\\"brand-chips\\\" class=\\\"chip-grid\\\"></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Picker trigger (shown when stores loaded) -->\u001b[39m\n\u001b[31m      <div id=\\\"pick-trigger-wrap\\\">\u001b[39m\n\u001b[31m        <div class=\\\"pick-trigger\\\" onclick=\\\"openPicker()\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:center;gap:10px\\\">\u001b[39m\n\u001b[31m            <span style=\\\"font-size:20px\\\">🏪</span>\u001b[39m\n\u001b[31m            <div>\u001b[39m\n\u001b[31m              <div style=\\\"font-size:15px;font-weight:700;color:var(--or)\\\"><span class=\\\"en-txt\\\">Select Store from List</span><span class=\\\"hi-txt\\\">सूची से दुकान चुनें</span></div>\u001b[39m\n\u001b[31m              <div id=\\\"store-avail-count\\\" style=\\\"font-size:12px;font-weight:400;color:var(--am);margin-top:1px\\\"><span class=\\\"en-txt\\\">Tap to browse stores</span><span class=\\\"hi-txt\\\">दुकान खोजने के लिए दबाएं</span></div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual / new store toggle -->\u001b[39m\n\u001b[31m      <div class=\\\"manual-toggle\\\" id=\\\"manual-toggle\\\" onclick=\\\"toggleManual()\\\">\u001b[39m\n\u001b[31m        <svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\" id=\\\"mt-icon\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg>\u001b[39m\n\u001b[31m        <span id=\\\"mt-label\\\"><span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span></span>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual fields -->\u001b[39m\n\u001b[31m      <div id=\\\"manual-fields\\\" style=\\\"display:none;margin-top:14px\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\" style=\\\"margin-bottom:14px\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <select id=\\\"f-brand\\\" onchange=\\\"onManualBrandChange()\\\">\u001b[39m\n\u001b[31m            <option value=\\\"\\\">Select brand</option>\u001b[39m\n\u001b[31m          </select>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span> <span class=\\\"req\\\">*</span></label><input type=\\\"text\\\" id=\\\"f-store\\\" placeholder=\\\"Enter store name\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\">\u001b[39m\n\u001b[31m          <label><span class=\\\"en-txt\\\">Store Address</span><span class=\\\"hi-txt\\\">दुकान का पता</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <textarea id=\\\"f-addr\\\" rows=\\\"2\\\" placeholder=\\\"Full address\\\" onchange=\\\"saveDraft()\\\"></textarea>\u001b[39m\n\u001b[31m          <div class=\\\"gps-row\\\">\u001b[39m\n\u001b[31m            <button class=\\\"gps-btn\\\" onclick=\\\"captureGPS()\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\"/><path d=\\\"M12 2v3M12 19v3M2 12h3M19 12h3\\\"/></svg><span class=\\\"en-txt\\\">Capture GPS</span><span class=\\\"hi-txt\\\">GPS लें</span></button>\u001b[39m\n\u001b[31m            <span id=\\\"gps-status\\\" style=\\\"font-size:12px;color:var(--g500);align-self:center\\\"></span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Mobile No.</span><span class=\\\"hi-txt\\\">मोबाइल नंबर</span></label><input type=\\\"tel\\\" id=\\\"f-mobile\\\" placeholder=\\\"10-digit number\\\" maxlength=\\\"10\\\" inputmode=\\\"numeric\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Client card -->\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Client</span><span class=\\\"hi-txt\\\">क्लाइंट</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\"><span class=\\\"en-txt\\\">Select who this recce is for. Defaults to brand — change if work came via an agency.</span><span class=\\\"hi-txt\\\">यह रेकी किसके लिए है चुनें। ब्रांड से डिफ़ॉल्ट — एजेंसी के ज़रिए हो तो बदलें।</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"cl-chip-grid\\\" id=\\\"client-chips\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"client-other-wrap\\\" style=\\\"display:none;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"f-client-other\\\" placeholder=\\\"Type client name\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" oninput=\\\"onClientOtherInput()\\\">\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-p\\\" onclick=\\\"step2()\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: PHOTOS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-photos\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-store')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Photos</span><span class=\\\"hi-txt\\\">दुकान की फोटो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 2 of 5</span><span class=\\\"hi-txt\\\">चरण 2 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:40%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Front View</span><span class=\\\"hi-txt\\\">आगे का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(min 1, max 3)</span><span class=\\\"cnt-badge gray\\\" id=\\\"front-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"front-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-front\\\" onclick=\\\"addPhoto('front')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Front Photo</span><span class=\\\"hi-txt\\\">आगे की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Inside View</span><span class=\\\"hi-txt\\\">अंदर का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 5)</span><span class=\\\"cnt-badge gray\\\" id=\\\"inside-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"inside-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-inside\\\" onclick=\\\"addPhoto('inside')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Inside Photo</span><span class=\\\"hi-txt\\\">अंदर की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-store')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step3()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: VIDEO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-video\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-photos')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Recce Video</span><span class=\\\"hi-txt\\\">रेकी वीडियो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 3 of 5</span><span class=\\\"hi-txt\\\">चरण 3 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:60%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Video</span><span class=\\\"hi-txt\\\">वीडियो</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Recce video available?</span><span class=\\\"hi-txt\\\">रेकी वीडियो है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"vid-yes\\\" onclick=\\\"setVideo(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"vid-no\\\" onclick=\\\"setVideo(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"vid-sec\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Upload Video</span><span class=\\\"hi-txt\\\">वीडियो अपलोड करें</span></label>\u001b[39m\n\u001b[31m          <div class=\\\"pslot\\\" id=\\\"vid-slot\\\" onclick=\\\"document.getElementById('vid-inp').click()\\\"><div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div></div>\u001b[39m\n\u001b[31m          <input type=\\\"file\\\" id=\\\"vid-inp\\\" accept=\\\"video/*\\\" onchange=\\\"handleVideo(event)\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Video Comments</span><span class=\\\"hi-txt\\\">वीडियो टिप्पणी</span></label><input type=\\\"text\\\" id=\\\"f-vid-cmt\\\" placeholder=\\\"Optional\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-photos')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step4()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: BRANDING -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-branding\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-video')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Branding</span><span class=\\\"hi-txt\\\">ब्रांडिंग</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 4 of 5</span><span class=\\\"hi-txt\\\">चरण 4 / 5</span></div></div></div>\u001b[39m\n\u001b[31m    <span id=\\\"br-hdr-badge\\\" style=\\\"background:rgba(255,255,255,.2);color:#fff;font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px\\\"><span class=\\\"en-txt\\\">0 items</span><span class=\\\"hi-txt\\\">0 आइटम</span></span>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:80%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Branding Space</span><span class=\\\"hi-txt\\\">ब्रांडिंग स्थान</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Space available?</span><span class=\\\"hi-txt\\\">जगह उपलब्ध है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"br-yes\\\" onclick=\\\"setBranding(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"br-no\\\" onclick=\\\"setBranding(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"branding-lock-banner\\\" style=\\\"display:none;background:#fef3c7;border:1.5px solid #f59e0b;border-radius:10px;padding:12px 14px;margin-bottom:10px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:700;color:#92400e\\\">Client approval exists — branding locked</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:#78350f;margin-top:4px\\\"><span class=\\\"en-txt\\\">The client has reviewed this recce. Create a new recce to revise branding items.</span><span class=\\\"hi-txt\\\">क्लाइंट ने रेकी की समीक्षा की है। बदलाव के लिए नई रेकी बनाएं।</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"branding-override-wrap\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m        <button onclick=\\\"unlockBrandingOverride()\\\" style=\\\"background:#f59e0b;color:#000;border:none;border-radius:8px;padding:8px 14px;font-size:12px;font-weight:700;cursor:pointer\\\">Override Edit (H&amp;P only)</button>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:11px;color:#92400e;margin-top:5px\\\">Use only when client has verbally confirmed and app needs correction.</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"br-items\\\"></div>\u001b[39m\n\u001b[31m    <div id=\\\"br-add\\\" style=\\\"display:none;margin-bottom:80px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"addBranding()\\\" style=\\\"width:100%;justify-content:center\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Another Branding Item</span><span class=\\\"hi-txt\\\">एक और ब्रांडिंग जोड़ें</span></button>\u001b[39m\n\u001b[31m      <div style=\\\"text-align:center;font-size:12px;color:var(--g400);margin-top:8px\\\"><span class=\\\"en-txt\\\">Tap Continue below when done adding items</span><span class=\\\"hi-txt\\\">सभी आइटम जोड़ने के बाद आगे दबाएं</span></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-video')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step5()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: ADDITIONAL + SUBMIT -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-additional\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-branding')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Submit</span><span class=\\\"hi-txt\\\">सबमिट</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 5 of 5</span><span class=\\\"hi-txt\\\">चरण 5 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:100%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Mandatory Document</span><span class=\\\"hi-txt\\\">अनिवार्य दस्तावेज़</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"pslot\\\" id=\\\"doc-slot\\\" onclick=\\\"document.getElementById('doc-inp').click()\\\"><div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div></div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"doc-inp\\\" accept=\\\"image/*,.pdf\\\" onchange=\\\"handleDoc(event)\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Additional Photos</span><span class=\\\"hi-txt\\\">अतिरिक्त फोटो</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 8)</span><span class=\\\"cnt-badge gray\\\" id=\\\"addl-badge\\\">0 / 8</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"add-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-addl\\\" onclick=\\\"addAdditional()\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\"><div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Review</span><span class=\\\"hi-txt\\\">समीक्षा</span></div><div id=\\\"rev-body\\\"></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-branding')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"submitRecce()\\\" id=\\\"sub-btn\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Submit Recce ✓</span><span class=\\\"hi-txt\\\">रेकी सबमिट करें ✓</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- ANNOTATION MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"annot-modal\\\" id=\\\"annot-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"annot-bar\\\">\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Draw:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"at-rect\\\"    onclick=\\\"setATool('rect')\\\">▭ Rect</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-ellipse\\\" onclick=\\\"setATool('ellipse')\\\">◯ Ellipse</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-line\\\"    onclick=\\\"setATool('line')\\\">╱ Line</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-arrow\\\"   onclick=\\\"setATool('arrow')\\\">↗ Arrow</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-free\\\"    onclick=\\\"setATool('free')\\\">✏ Free</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool sel-on\\\" id=\\\"at-move\\\" onclick=\\\"setATool('move')\\\" style=\\\"margin-left:4px\\\">⊹ Move</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Color:</span>\u001b[39m\n\u001b[31m      <div class=\\\"acolor on\\\" id=\\\"ac-or\\\" style=\\\"background:#f97316\\\" onclick=\\\"setAColor('#f97316')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-rd\\\" style=\\\"background:#ef4444\\\" onclick=\\\"setAColor('#ef4444')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-wh\\\" style=\\\"background:#ffffff\\\" onclick=\\\"setAColor('#ffffff')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-yw\\\" style=\\\"background:#facc15\\\" onclick=\\\"setAColor('#facc15')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-gn\\\" style=\\\"background:#22c55e\\\" onclick=\\\"setAColor('#22c55e')\\\"></div>\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Width:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-2\\\" onclick=\\\"setAWidth(2)\\\" style=\\\"padding:5px 8px\\\">Thin</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"aw-4\\\" onclick=\\\"setAWidth(4)\\\" style=\\\"padding:5px 8px\\\">Med</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-7\\\" onclick=\\\"setAWidth(7)\\\" style=\\\"padding:5px 8px\\\">Thick</button>\u001b[39m\n\u001b[31m      <div style=\\\"flex:1\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"undoAnnot()\\\">↩</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"clearAnnot()\\\">✕</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"annot-sel-info\\\" style=\\\"display:none;font-size:11px;color:#facc15;padding:4px 0 2px\\\">\u001b[39m\n\u001b[31m      Shape selected — drag to move · drag corners to resize · tap elsewhere to deselect\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-cvs-wrap\\\"><canvas id=\\\"annot-cvs\\\"></canvas></div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-foot\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-s\\\" onclick=\\\"skipAnnot()\\\" style=\\\"flex:1;padding:12px;font-size:14px\\\"><span class=\\\"en-txt\\\">Skip markup</span><span class=\\\"hi-txt\\\">मार्कअप छोड़ें</span></button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" onclick=\\\"saveAnnot()\\\" style=\\\"flex:2;padding:12px\\\"><span class=\\\"en-txt\\\">Done — Save ✓</span><span class=\\\"hi-txt\\\">हो गया — सेव करें ✓</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EXIT DIALOG -->\u001b[39m\n\u001b[31m<!-- MODAL: Link Job to Recce (supervisor only) -->\u001b[39m\n\u001b[31m<div id=\\\"modal-link-job\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m  <div style=\\\"background:#fff;border-radius:14px;padding:20px;width:90%;max-width:380px;display:flex;flex-direction:column;gap:12px;box-shadow:0 8px 32px rgba(0,0,0,.35)\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:15px;font-weight:700;color:#1e293b\\\">&#x1F517; Link Job to Recce</div>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-store\\\" style=\\\"font-size:13px;color:#64748b\\\"></div>\u001b[39m\n\u001b[31m    <select id=\\\"link-job-sel\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m      <option value=\\\"\\\">&#x2014; Select campaign &#x2014;</option>\u001b[39m\n\u001b[31m    </select>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-err\\\" style=\\\"font-size:12px;color:#ef4444;min-height:14px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"closeLinkJobModal()\\\" style=\\\"flex:1;padding:12px;border:1px solid #cbd5e1;border-radius:8px;cursor:pointer;background:#f8fafc;font-size:14px\\\">Cancel</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"saveLinkJob()\\\" style=\\\"flex:2;padding:12px;background:#f59e0b;color:#000;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:700\\\">&#x1F517; Link Job</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"exit-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Exit Recce?</span><span class=\\\"hi-txt\\\">रेकी से बाहर?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Your progress and photos will be saved as a draft. Resume anytime from the home screen.</span><span class=\\\"hi-txt\\\">आपकी प्रगति और फोटो ड्राफ्ट में सेव होंगी। होम स्क्रीन से कभी भी जारी रखें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"exitSaveAndLeave()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">💾 Save Draft & Exit</span><span class=\\\"hi-txt\\\">💾 ड्राफ्ट सेव करें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-d\\\" onclick=\\\"exitDiscard()\\\" style=\\\"flex:1;padding:13px;font-size:13px\\\"><span class=\\\"en-txt\\\">Discard</span><span class=\\\"hi-txt\\\">हटाएं</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"exitCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">← Continue Recce</span><span class=\\\"hi-txt\\\">← रेकी जारी रखें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- PHOTO SOURCE PICKER -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"photo-src-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Camera photos get GPS stamp baked in. Gallery photos are added without stamp.</span><span class=\\\"hi-txt\\\">कैमरा फोटो में GPS स्टैम्प लगती है। गैलरी फोटो में नहीं।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"photoSrcCamera()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">📷 Use Camera</span><span class=\\\"hi-txt\\\">📷 कैमरा</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">GPS stamp applied</span><span class=\\\"hi-txt\\\">GPS स्टैम्प लगेगी</span></span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"photoSrcGallery()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">🖼 Choose from Gallery</span><span class=\\\"hi-txt\\\">🖼 गैलरी से चुनें</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">No stamp</span><span class=\\\"hi-txt\\\">स्टैम्प नहीं</span></span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"photoSrcCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- STORE PREVIEW DIALOG -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"store-preview-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:80vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"store-preview-title\\\"><span class=\\\"en-txt\\\">Preview Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची का प्रीव्यू</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Review before adding to your store list:</span><span class=\\\"hi-txt\\\">जोड़ने से पहले जाँचें:</span></div>\u001b[39m\n\u001b[31m    <div style=\\\"overflow-x:auto;margin-bottom:14px\\\">\u001b[39m\n\u001b[31m      <table style=\\\"width:100%;border-collapse:collapse;font-size:12px\\\">\u001b[39m\n\u001b[31m        <thead><tr style=\\\"background:var(--nv);color:#fff\\\">\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Address</span><span class=\\\"hi-txt\\\">पता</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Mobile</span><span class=\\\"hi-txt\\\">मोबाइल</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span></th>\u001b[39m\n\u001b[31m        </tr></thead>\u001b[39m\n\u001b[31m        <tbody id=\\\"store-preview-body\\\"></tbody>\u001b[39m\n\u001b[31m      </table>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"confirmStorePreview()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">✓ Confirm & Add Stores</span><span class=\\\"hi-txt\\\">✓ स्टोर जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"cancelStorePreview()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BOTTOM DIALOG (branding additional photo prompt) -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"bdialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add reference photos?</span><span class=\\\"hi-txt\\\">संदर्भ फोटो जोड़ें?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Add extra photos for this branding item for future reference.</span><span class=\\\"hi-txt\\\">इस ब्रांडिंग आइटम के लिए अतिरिक्त फोटो जोड़ें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"bdialogYes()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">Yes, add photos</span><span class=\\\"hi-txt\\\">हाँ, जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"bdialogNo()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Skip</span><span class=\\\"hi-txt\\\">छोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- DELETE REASON MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"delete-reason-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"padding-bottom:28px;max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">🗑 Delete Recce</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"del-modal-sub\\\">Select reason for deletion:</div>\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-wrong\\\" onclick=\\\"selectDeleteReason('wrong')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">❌</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Wrong</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Incorrect store / submission error</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-duplicate\\\" onclick=\\\"selectDeleteReason('duplicate')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">📋</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Duplicate</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Same store submitted more than once</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt danger\\\" id=\\\"reason-test\\\" onclick=\\\"selectDeleteReason('test')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">⚠️</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Test Recce</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:#9a3412;margin-top:2px\\\">Permanently deleted — no audit trail</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p no-reason\\\" id=\\\"del-confirm-btn\\\" onclick=\\\"confirmDelete()\\\" style=\\\"flex:2;padding:13px;background:var(--rd)\\\">Delete</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"closeDeleteModal()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EDIT REQUEST MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"edit-req-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Request Edit</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"er-store-name\\\" style=\\\"font-weight:600;color:var(--nv);margin-bottom:4px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:14px\\\">Add a note for the creator (optional)</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m      <textarea id=\\\"er-comment\\\" placeholder=\\\"e.g. Please re-check store address and re-upload front photo\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;color:var(--nv);resize:vertical;min-height:80px;background:#fff\\\"></textarea>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button id=\\\"er-assign-btn\\\" class=\\\"btn-p\\\" onclick=\\\"assignEditToCreator()\\\" style=\\\"padding:14px\\\">👤 Assign to Creator</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"supervisorEditMyself()\\\" style=\\\"padding:14px\\\">✏ Edit Myself</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"closeEditRequestModal()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BRAND EDIT MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"brand-edit-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Edit Brand</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Brand Name <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"text\\\" id=\\\"be-name\\\" placeholder=\\\"e.g. PHILIPS\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:600;text-transform:uppercase\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Logo URL <span style=\\\"font-size:11px;font-weight:400;color:var(--g400)\\\">(optional)</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"url\\\" id=\\\"be-logo\\\" placeholder=\\\"https://…/logo.svg\\\" oninput=\\\"previewBrandLogo()\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px\\\">\u001b[39m\n\u001b[31m      <div id=\\\"be-logo-preview\\\" style=\\\"margin-top:8px;min-height:36px;display:flex;align-items:center;gap:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"be-cascade-info\\\" style=\\\"display:none;font-size:12px;color:var(--g500);padding:8px 12px;background:var(--g50);border-radius:var(--rs);margin-bottom:12px\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"saveBrandEdit()\\\" style=\\\"padding:14px\\\">Save</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"closeBrandEditModal()\\\" style=\\\"width:100%;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FONT SIZE WIDGET -->\u001b[39m\n\u001b[31m<div class=\\\"fs-widget\\\" id=\\\"fs-widget\\\">\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-dec\\\" onclick=\\\"changeFontSize(-1)\\\" title=\\\"Decrease font size\\\" aria-label=\\\"Decrease font size\\\">A<sup style=\\\"font-size:9px\\\">−</sup></button>\u001b[39m\n\u001b[31m  <span class=\\\"fs-label\\\" id=\\\"fs-lbl\\\">A</span>\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-inc\\\" onclick=\\\"changeFontSize(1)\\\" title=\\\"Increase font size\\\" aria-label=\\\"Increase font size\\\"><strong>A</strong><sup style=\\\"font-size:9px\\\">+</sup></button>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"upd-banner\\\" id=\\\"upd-banner\\\">\u001b[39m\n\u001b[31m  <span style=\\\"font-size:13px;font-weight:600;line-height:1.4\\\"><span class=\\\"en-txt\\\">✓ App updated to latest version</span><span class=\\\"hi-txt\\\">✓ ऐप नया संस्करण अपडेट हुआ</span></span>\u001b[39m\n\u001b[31m  <button class=\\\"upd-banner-ok\\\" onclick=\\\"dismissUpdateBanner()\\\"><span class=\\\"en-txt\\\">OK</span><span class=\\\"hi-txt\\\">ठीक है</span></button>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m<div class=\\\"toast\\\" id=\\\"toast\\\"></div>\u001b[39m\n\u001b[31m<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js\\\"></script>\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m// LANGUAGE\u001b[39m\n\u001b[31mlet LANG = localStorage.getItem('recce-lang') || 'en';\u001b[39m\n\u001b[31mfunction setLang(l) {\u001b[39m\n\u001b[31m  LANG = l;\u001b[39m\n\u001b[31m  localStorage.setItem('recce-lang', l);\u001b[39m\n\u001b[31m  document.body.classList.toggle('lang-hi', l === 'hi');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction t(en, hi) { return LANG === 'hi' ? hi : en; }·\u001b[39m\n\u001b[31m// FONT SIZE\u001b[39m\n\u001b[31mlet FS_LEVEL = parseInt(localStorage.getItem('recce-fs') || '0', 10);\u001b[39m\n\u001b[31mconst FS_LABELS = ['A', 'A+', 'A++', 'A+++', 'A++++'];\u001b[39m\n\u001b[31mfunction applyFontSize() {\u001b[39m\n\u001b[31m  document.body.classList.remove('fs-0', 'fs-1', 'fs-2');\u001b[39m\n\u001b[31m  if (FS_LEVEL > 0) document.body.classList.add('fs-' + FS_LEVEL);\u001b[39m\n\u001b[31m  const lbl = document.getElementById('fs-lbl');\u001b[39m\n\u001b[31m  if (lbl) lbl.textContent = FS_LABELS[FS_LEVEL];\u001b[39m\n\u001b[31m  const dec = document.getElementById('fs-dec');\u001b[39m\n\u001b[31m  const inc = document.getElementById('fs-inc');\u001b[39m\n\u001b[31m  if (dec) dec.disabled = FS_LEVEL === 0;\u001b[39m\n\u001b[31m  if (inc) inc.disabled = FS_LEVEL === 4;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction changeFontSize(delta) {\u001b[39m\n\u001b[31m  FS_LEVEL = Math.min(4, Math.max(0, FS_LEVEL + delta));\u001b[39m\n\u001b[31m  localStorage.setItem('recce-fs', FS_LEVEL);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Hub auth gate\u001b[39m\n\u001b[31m(function() {\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (!s || !s.loginAt || Date.now() - new Date(s.loginAt).getTime() > 12 * 3600 * 1000) {\u001b[39m\n\u001b[31m      window.location.replace('/hub/');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) { window.location.replace('/hub/'); }\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31m// STATE\u001b[39m\n\u001b[31mlet F={},frontPhotos=[],insidePhotos=[],addlPhotos=[],brandings=[];\u001b[39m\n\u001b[31mlet videoBlob=null,submissionDoc=null,_docExistingUrl=null,gpsCoords=null;\u001b[39m\n\u001b[31mlet stores=[],selectedStore=null,manualMode=false,DB;\u001b[39m\n\u001b[31mlet imgQuality='compressed'; // 'compressed' | 'hd'\u001b[39m\n\u001b[31mlet geoStampEnabled=true;    // stamp GPS+timestamp on every photo\u001b[39m\n\u001b[31mlet brands=['PHILIPS']; // editable brand list\u001b[39m\n\u001b[31mlet _brandLogos={};   // name → logo_url, loaded from DB\u001b[39m\n\u001b[31mlet _selectedClient=''; // currently selected client chip value\u001b[39m\n\u001b[31mlet _clientOtherMode=false; // true when \\\"Other\\\" chip selected\u001b[39m\n\u001b[31mconst BTYPE=['Glow Sign Board','Inshop Branding','ACP Board','One Way Vision','Fabric Board','Lollypop','Non Lit Flex','Double Side GSB','Clip on Board','Translit','Vinyl Printing','Roll up Standee','Sunboard Standee'];\u001b[39m\n\u001b[31mconst CACHE_VER='recce-v37'; // campaign dropdown + pending job link tab·\u001b[39m\n\u001b[31m// DB\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',3);r.onupgradeneeded=e=>{const d=e.target.result;['subs','cfg','draft'].forEach(s=>{if(!d.objectStoreNames.contains(s))d.createObjectStore(s,{keyPath:'k'||'id'});});if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);});}\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',4);r.onupgradeneeded=e=>{const d=e.target.result;if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);})}\u001b[39m\n\u001b[31mfunction dbGet(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).get(k);r.onsuccess=()=>res(r.result);r.onerror=()=>res(null);}catch{res(null)}})}\u001b[39m\n\u001b[31mfunction dbPut(s,v){return new Promise((res,rej)=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).put(v);r.onsuccess=()=>res();r.onerror=()=>rej();}catch(e){rej(e)}})}\u001b[39m\n\u001b[31mfunction dbAll(s){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).getAll();r.onsuccess=()=>res(r.result);r.onerror=()=>res([]);}catch{res([])}})}\u001b[39m\n\u001b[31mfunction dbDel(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).delete(k);r.onsuccess=()=>res();r.onerror=()=>res();}catch{res()}})}\u001b[39m\n\u001b[31masync function cfg(k,v){if(v===undefined){const r=await dbGet('cfg',k);return r?r.v:null;}await dbPut('cfg',{k,v});}·\u001b[39m\n\u001b[31m// COMPRESS — respects imgQuality setting\u001b[39m\n\u001b[31mfunction compress(file, maxPxOverride, qOverride){\u001b[39m\n\u001b[31m  const maxPx = maxPxOverride || (imgQuality==='hd' ? 1920 : 1280);\u001b[39m\n\u001b[31m  const q     = qOverride     || (imgQuality==='hd' ? 0.90 : 0.78);\u001b[39m\n\u001b[31m  return new Promise(res=>{const img=new Image(),url=URL.createObjectURL(file);img.onload=()=>{const sc=Math.min(1,maxPx/Math.max(img.width,img.height));const c=document.createElement('canvas');c.width=Math.round(img.width*sc);c.height=Math.round(img.height*sc);c.getContext('2d').drawImage(img,0,0,c.width,c.height);URL.revokeObjectURL(url);c.toBlob(b=>res(b),'image/jpeg',q);};img.onerror=()=>{URL.revokeObjectURL(url);res(file)};img.src=url;});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction b64(blob){return new Promise(res=>{const r=new FileReader();r.onload=()=>res(r.result);r.readAsDataURL(blob)})}\u001b[39m\n\u001b[31mfunction fmtSz(b){if(b<1024)return b+'B';if(b<1048576)return(b/1024).toFixed(0)+'KB';return(b/1048576).toFixed(1)+'MB'}·\u001b[39m\n\u001b[31m// STORE LIST\u001b[39m\n\u001b[31mlet _storeFiles=[]; // track uploaded files {name, brand, count}\u001b[39m\n\u001b[31mlet _pendingParse=null; // parsed rows waiting for brand assignment·\u001b[39m\n\u001b[31mfunction parseStoreRow(row, keyFn){\u001b[39m\n\u001b[31m  const v=k=>{\u001b[39m\n\u001b[31m    // Try exact match first, then partial\u001b[39m\n\u001b[31m    const exactKey=Object.keys(row||{}).find(hk=>hk.toLowerCase()===k);\u001b[39m\n\u001b[31m    const partKey=Object.keys(row||{}).find(hk=>hk.toLowerCase().includes(k));\u001b[39m\n\u001b[31m    const useKey=exactKey||partKey;\u001b[39m\n\u001b[31m    if(useKey)return row[useKey]!=null?row[useKey].toString().trim():'';\u001b[39m\n\u001b[31m    // CSV path: keyFn provides value directly\u001b[39m\n\u001b[31m    const col=keyFn(k);return col!=null?col.toString().trim():'';\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const name    = v('sub dealer name')||v('sub dealer')||v('dealer name')||v('store name')||v('store')||v('name');\u001b[39m\n\u001b[31m  const address = v('address')||v('addr')||v('location')||v('area');\u001b[39m\n\u001b[31m  // Contact Detail often stored as a number — toString handles it\u001b[39m\n\u001b[31m  const rawMob  = v('contact detail')||v('contact no.')||v('contact no')||v('mobile no')||v('mobile')||v('phone')||v('mob')||v('contact');\u001b[39m\n\u001b[31m  const mobile  = rawMob.replace(/\\\\D/g,'').slice(-10);\u001b[39m\n\u001b[31m  // Brand: EXACT match only — \\\"Brand\\\" or \\\"Brand Name\\\" columns\u001b[39m\n\u001b[31m  // Partial match is intentionally avoided here because \\\"Inshop Branding\\\" contains \\\"brand\\\"\u001b[39m\n\u001b[31m  const brandKey=Object.keys(row||{}).find(hk=>{\u001b[39m\n\u001b[31m    const lk=hk.toLowerCase().trim();\u001b[39m\n\u001b[31m    return lk==='brand'||lk==='brand name'||lk==='brand_name'||lk==='brandname';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const brand=brandKey?(row[brandKey]||'').toString().trim().toUpperCase():'';\u001b[39m\n\u001b[31m  const distName= v('dist name')||v('distributor name')||v('distributor')||v('dist')||v('territory')||v('tsm')||v('asm');\u001b[39m\n\u001b[31m  const city    = v('city')||v('district')||v('town');\u001b[39m\n\u001b[31m  const sales   = v('2025 full year')||v('2025')||v('full year sales')||v('fy25')||v('sales');\u001b[39m\n\u001b[31m  const proj    = v('2026 projection')||v('2026')||v('projection')||v('fy26')||v('target');\u001b[39m\n\u001b[31m  const glowSign= v('glow sign')||v('glow');\u001b[39m\n\u001b[31m  const inshop  = v('inshop branding')||v('inshop')||v('in-shop')||v('in shop');\u001b[39m\n\u001b[31m  return {name, brand, address, mobile, distName, city, sales, proj, glowSign, inshop};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction dedupeStores(list){\u001b[39m\n\u001b[31m  const seen=new Map();\u001b[39m\n\u001b[31m  list.forEach(s=>{\u001b[39m\n\u001b[31m    // Include address in key — same store name at different locations = different stores\u001b[39m\n\u001b[31m    const key=(s.name.toLowerCase().trim())+'__'+(s.brand||'').toLowerCase()\u001b[39m\n\u001b[31m              +'__'+(s.address||'').toLowerCase().trim().slice(0,30);\u001b[39m\n\u001b[31m    if(!seen.has(key))seen.set(key,s);\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // True duplicate — merge missing fields from second record\u001b[39m\n\u001b[31m      const ex=seen.get(key);\u001b[39m\n\u001b[31m      Object.keys(s).forEach(k=>{ if(!ex[k]&&s[k])ex[k]=s[k]; });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  return Array.from(seen.values());\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderStoreFileList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-file-list');if(!el)return;\u001b[39m\n\u001b[31m  if(!_storeFiles.length){el.innerHTML='';return;}\u001b[39m\n\u001b[31m  el.innerHTML=_storeFiles.map((f,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:5px;font-size:12px\\\">\u001b[39m\n\u001b[31m      <div>\u001b[39m\n\u001b[31m        <span style=\\\"font-weight:600;color:var(--nv)\\\">${f.name}</span>\u001b[39m\n\u001b[31m        <span style=\\\"color:var(--g500);margin-left:6px\\\">${f.count} stores</span>\u001b[39m\n\u001b[31m        ${f.brand?`<span style=\\\"background:var(--nv);color:#fff;font-size:10px;font-weight:700;padding:1px 7px;border-radius:20px;margin-left:5px\\\">${f.brand}</span>`:'<span style=\\\"background:var(--g300);color:var(--g600);font-size:10px;padding:1px 7px;border-radius:20px;margin-left:5px\\\">Mixed brands</span>'}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <button onclick=\\\"removeStoreFile(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:17px;cursor:pointer;padding:0 4px;line-height:1\\\">×</button>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function removeStoreFile(i){\u001b[39m\n\u001b[31m  _storeFiles.splice(i,1);\u001b[39m\n\u001b[31m  // Rebuild stores from remaining files — re-parse from cache not possible, so just reload from DB and remove this file's contribution\u001b[39m\n\u001b[31m  // Simplest approach: clear and ask user to re-upload remaining files\u001b[39m\n\u001b[31m  if(!_storeFiles.length){stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    // Can't re-parse without original files; just note it and keep current store list\u001b[39m\n\u001b[31m    toast('Removed from list. Re-upload the remaining files to refresh store list.','info');\u001b[39m\n\u001b[31m    _storeFiles.splice(0); // clear tracking since we can't reconstruct\u001b[39m\n\u001b[31m    stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderStoreFileList();\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=stores.length?`✓ ${stores.length} stores`:'No stores loaded';\u001b[39m\n\u001b[31m  updAvailTag();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function clearStoreList(){\u001b[39m\n\u001b[31m  if(!confirm('Remove all loaded stores?'))return;\u001b[39m\n\u001b[31m  stores=[];_storeFiles=[];\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent='';\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast('Store list cleared','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function handleStoreUpload(e){\u001b[39m\n\u001b[31m  const file=e.target.files[0];if(!file)return;\u001b[39m\n\u001b[31m  e.target.value=''; // allow same file re-upload\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    let data=[];\u001b[39m\n\u001b[31m    if(file.name.toLowerCase().endsWith('.csv')){\u001b[39m\n\u001b[31m      const txt=await file.text();\u001b[39m\n\u001b[31m      const rows=txt.split('\\\\n').map(r=>r.split(',').map(c=>c.trim().replace(/^\\\"|\\\"$/g,'')));\u001b[39m\n\u001b[31m      if(!rows.length||!rows[0].length){toast('Empty CSV','error');return;}\u001b[39m\n\u001b[31m      const h=rows[0];\u001b[39m\n\u001b[31m      data=rows.slice(1).filter(r=>r.length>1&&r.some(c=>c)).map(r=>{\u001b[39m\n\u001b[31m        const rowObj={};h.forEach((hk,i)=>{rowObj[hk]=r[i]||'';});\u001b[39m\n\u001b[31m        return parseStoreRow(rowObj, ()=>'');\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }else{\u001b[39m\n\u001b[31m      const ab=await file.arrayBuffer();const wb=XLSX.read(ab,{type:'array'});\u001b[39m\n\u001b[31m      const js=XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]],{defval:''});\u001b[39m\n\u001b[31m      data=js.map(row=>parseStoreRow(row,()=>''));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    data=data.filter(d=>d.name.trim());\u001b[39m\n\u001b[31m    if(!data.length){toast('No valid rows found in file','error');return;}\u001b[39m\n\u001b[31m    // Check if any store has a brand\u001b[39m\n\u001b[31m    const hasBrand=data.some(d=>d.brand);\u001b[39m\n\u001b[31m    // Always show preview first before merging\u001b[39m\n\u001b[31m    _pendingParse={file:file.name,data,hasBrand};\u001b[39m\n\u001b[31m    showStorePreview(file.name, data, hasBrand);\u001b[39m\n\u001b[31m  }catch(err){toast('Failed: '+err.message,'error')}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mlet _pendingBrand='';\u001b[39m\n\u001b[31mfunction setPendingBrand(b){\u001b[39m\n\u001b[31m  _pendingBrand=b;\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-assign-chips .chip').forEach(c=>{\u001b[39m\n\u001b[31m    c.classList.toggle('sel',c.textContent===b);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  if(!_pendingBrand){toast('Select a brand first','error');return;}\u001b[39m\n\u001b[31m  // Assign brand to all rows in this file\u001b[39m\n\u001b[31m  const data=_pendingParse.data.map(s=>({...s,brand:_pendingBrand}));\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, data, _pendingBrand);\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function skipBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, _pendingParse.data, '');\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showStorePreview(filename, data, hasBrand){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-preview-dialog');\u001b[39m\n\u001b[31m  const tbody=document.getElementById('store-preview-body');\u001b[39m\n\u001b[31m  document.getElementById('store-preview-title').textContent=`${filename} · ${data.length} ${t('stores found','स्टोर मिले')}`;\u001b[39m\n\u001b[31m  // Show first 8 rows\u001b[39m\n\u001b[31m  const sample=data.slice(0,8);\u001b[39m\n\u001b[31m  tbody.innerHTML=sample.map(s=>`<tr>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;font-weight:500\\\">${s.name||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.address||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.mobile||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px\\\"><span style=\\\"background:${s.brand?'var(--nv)':'var(--rd)'};color:#fff;padding:1px 7px;border-radius:10px;font-size:10px\\\">${s.brand||'?'}</span></td>\u001b[39m\n\u001b[31m  </tr>`).join('');\u001b[39m\n\u001b[31m  if(data.length>8)tbody.innerHTML+=`<tr><td colspan=\\\"4\\\" style=\\\"text-align:center;padding:8px;font-size:12px;color:var(--g400)\\\">…and ${data.length-8} more stores</td></tr>`;\u001b[39m\n\u001b[31m  el.classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function confirmStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  const {file,data,hasBrand}=_pendingParse;\u001b[39m\n\u001b[31m  if(!hasBrand){\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-fname').textContent=`File: ${file} · ${data.length} stores found · No brand column detected`;\u001b[39m\n\u001b[31m    const chips=document.getElementById('brand-assign-chips');\u001b[39m\n\u001b[31m    chips.innerHTML=brands.map(b=>`<div class=\\\"chip\\\" onclick=\\\"setPendingBrand('${b}')\\\" id=\\\"bac-${b}\\\">${b}</div>`).join('');\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').style.display='block';\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    await mergeStores(file, data, '');\u001b[39m\n\u001b[31m    _pendingParse=null;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction cancelStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingParse=null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function mergeStores(filename, newData, assignedBrand){\u001b[39m\n\u001b[31m  const before=stores.length;\u001b[39m\n\u001b[31m  stores=[...stores,...newData];\u001b[39m\n\u001b[31m  stores=dedupeStores(stores);\u001b[39m\n\u001b[31m  const added=stores.length-before;\u001b[39m\n\u001b[31m  const dupes=newData.length-added;\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify(stores));\u001b[39m\n\u001b[31m  // Track file\u001b[39m\n\u001b[31m  _storeFiles.push({name:filename,count:newData.length,brand:assignedBrand||''});\u001b[39m\n\u001b[31m  await cfg('store-files',JSON.stringify(_storeFiles));\u001b[39m\n\u001b[31m  const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m    `✓ ${stores.length} total stores${dupes>0?` · ${dupes} duplicate${dupes>1?'s':''} removed`:''}${noBrand?` · ${noBrand} without brand`:' · All have brand'}`;\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast(`${added} stores added${dupes>0?`, ${dupes} duplicates skipped`:''}${assignedBrand?' as '+assignedBrand:''}`, 'success');\u001b[39m\n\u001b[31m  // Show server-push button for supervisors\u001b[39m\n\u001b[31m  const pb = document.getElementById('store-push-btn');\u001b[39m\n\u001b[31m  if (pb) pb.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function fetchServerStores(){const url=document.getElementById('srv-url').value.trim();if(!url){toast('Enter a URL first','error');return;}try{toast('Fetching…','info');const r=await fetch(url);const j=await r.json();const fetched=Array.isArray(j)?j:j.stores||[];await mergeStores('Server ('+url.split('/').pop()+')',fetched,'');await cfg('srv-url',url);}catch{toast('Fetch failed — check URL','error')}}\u001b[39m\n\u001b[31masync function saveServerUrl(){await cfg('srv-url',document.getElementById('srv-url').value.trim());toast('URL saved','success')}\u001b[39m\n\u001b[31mconst DEFAULT_GAS_URL='https://script.google.com/macros/s/AKfycbwyufC7gQyu1BErCxiDlbQUn0AWiIWv7nEmjk4UcAx3dvlV6bGk7q5fQOiv82CTbokbkA/exec';·\u001b[39m\n\u001b[31mconst DEFAULT_STORES_URL='/recce/stores.json';\u001b[39m\n\u001b[31mconst _RECCE_CFG_URL='/recce/recce-cfg.json';·\u001b[39m\n\u001b[31m// Admin auto-unlock for harish/pramod via hub session\u001b[39m\n\u001b[31mconst _RECCE_ADMIN_IDS = ['harish', 'pramod', 'rakesh'];\u001b[39m\n\u001b[31mconst _RECCE_CFG_ADMINS = ['harish', 'pramod'];\u001b[39m\n\u001b[31mlet _adminRows = [];\u001b[39m\n\u001b[31mlet _myServerRows = [];\u001b[39m\n\u001b[31mlet _adminUnlocked = false;\u001b[39m\n\u001b[31mlet _recceCfg = { version: 1, supervisors: ['harish','pramod','rakesh'], mode: 'public', creators: [], allowed_users: [] };\u001b[39m\n\u001b[31mfunction _isSupervisor() {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  return !!(hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId));\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _showDeletedView = false;\u001b[39m\n\u001b[31mlet _supCreateMode = false;\u001b[39m\n\u001b[31mlet _pendingDeleteId = null;\u001b[39m\n\u001b[31mlet _pendingDeleteReason = null;\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (s?.empId && _RECCE_ADMIN_IDS.includes(s.empId)) _adminUnlocked = true;\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31masync function loadRecceCfg(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(_RECCE_CFG_URL + '?t=' + Date.now());\u001b[39m\n\u001b[31m    if (r.ok) {\u001b[39m\n\u001b[31m      const j = await r.json();\u001b[39m\n\u001b[31m      if (j && j.version) {\u001b[39m\n\u001b[31m        _recceCfg = j;\u001b[39m\n\u001b[31m        if (Array.isArray(j.supervisors) && j.supervisors.length) {\u001b[39m\n\u001b[31m          _recceCfg.supervisors = j.supervisors;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.creators)) _recceCfg.creators = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.allowed_users)) _recceCfg.allowed_users = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.clients)) _recceCfg.clients = [];\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  // Re-check admin status against server supervisor list\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId)) {\u001b[39m\n\u001b[31m    _adminUnlocked = true;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _checkAccessMode(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (_recceCfg.mode !== 'assigned') return;\u001b[39m\n\u001b[31m  const allowed = [\u001b[39m\n\u001b[31m    ...(_recceCfg.supervisors || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.creators || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.allowed_users || []),\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  if (hub?.empId && allowed.includes(hub.empId)) return;\u001b[39m\n\u001b[31m  // Block access — show locked overlay\u001b[39m\n\u001b[31m  document.body.innerHTML = `<div style=\\\"min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0f172a;color:#fff;padding:32px;text-align:center\\\"><div style=\\\"font-size:48px;margin-bottom:16px\\\">🔒</div><div style=\\\"font-size:20px;font-weight:700;margin-bottom:8px\\\">${t('Access Restricted','एक्सेस प्रतिबंधित')}</div><div style=\\\"font-size:14px;color:#94a3b8\\\">${t('You are not authorised to use Branding Recce. Please contact your supervisor.','आप ब्रांडिंग रेक्की उपयोग के लिए अधिकृत नहीं हैं।')}</div></div>`;\u001b[39m\n\u001b[31m  throw new Error('access-restricted');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _recceHubUser() {\u001b[39m\n\u001b[31m  try { return JSON.parse(localStorage.getItem('lm360-session') || '{}'); }\u001b[39m\n\u001b[31m  catch(_) { return {}; }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── Supervisor config management ────────────────────────────────────\u001b[39m\n\u001b[31mfunction renderSupPanel(){\u001b[39m\n\u001b[31m  if (!_adminUnlocked) return;\u001b[39m\n\u001b[31m  const panel = document.getElementById('sup-panel');\u001b[39m\n\u001b[31m  if (panel) panel.style.display = 'block';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const modePublic = document.getElementById('mode-public');\u001b[39m\n\u001b[31m  const modeAssigned = document.getElementById('mode-assigned');\u001b[39m\n\u001b[31m  if (modePublic && modeAssigned) {\u001b[39m\n\u001b[31m    modePublic.classList.toggle('sel', _recceCfg.mode !== 'assigned');\u001b[39m\n\u001b[31m    modeAssigned.classList.toggle('sel', _recceCfg.mode === 'assigned');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  const addRow = document.getElementById('sup-add-row');\u001b[39m\n\u001b[31m  if (addRow) addRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const creatorAddRow = document.getElementById('creator-add-row');\u001b[39m\n\u001b[31m  if (creatorAddRow) creatorAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const clientAddRow = document.getElementById('client-add-row');\u001b[39m\n\u001b[31m  if (clientAddRow) clientAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const modeRow = document.getElementById('mode-row');\u001b[39m\n\u001b[31m  if (modeRow) {\u001b[39m\n\u001b[31m    modeRow.style.display = 'block';\u001b[39m\n\u001b[31m    // Non-cfg-admins see mode as read-only (toggles exist but setRecceMode guards them)\u001b[39m\n\u001b[31m    modeRow.style.opacity = isCfgAdmin ? '1' : '0.65';\u001b[39m\n\u001b[31m    modeRow.style.pointerEvents = isCfgAdmin ? '' : 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const syncBtn = document.getElementById('cfg-sync-btn');\u001b[39m\n\u001b[31m  if (syncBtn) syncBtn.style.display = isCfgAdmin ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('sup-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const sups = _recceCfg.supervisors || [];\u001b[39m\n\u001b[31m  el.innerHTML = sups.map((s,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${s}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin && sups.length > 1 ? `<button onclick=\\\"removeSupervisor(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderCreatorsList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('creator-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const creators = _recceCfg.creators || [];\u001b[39m\n\u001b[31m  el.innerHTML = creators.length ? creators.map((u,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${u}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeCreator(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No creators yet — any Hub user can submit in Public mode.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setRecceMode(mode){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.mode = mode;\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addSupervisor(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('sup-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.supervisors = [...(_recceCfg.supervisors || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeSupervisor(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.supervisors = (_recceCfg.supervisors || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addCreator(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('creator-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.creators || []).includes(val)) { toast(t('Already a creator','पहले से क्रिएटर है'), 'info'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor (includes creation rights)','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.creators = [...(_recceCfg.creators || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeCreator(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.creators = (_recceCfg.creators || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderClientMgmtList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('client-mgmt-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const list = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  el.innerHTML = list.length ? list.map((c,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${esc(c)}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeClientFromList(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No clients yet — add client or agency names to show them as chips in the form.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addClientToList(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('client-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter client name','क्लाइंट नाम दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.clients || []).includes(val)) { toast(t('Already in list','पहले से मौजूद है'), 'info'); return; }\u001b[39m\n\u001b[31m  if (!_recceCfg.clients) _recceCfg.clients = [];\u001b[39m\n\u001b[31m  _recceCfg.clients.push(val);\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeClientFromList(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.clients = (_recceCfg.clients || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncCfgToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast(t('Not authorised','अधिकृत नहीं'), 'error'); return; }\u001b[39m\n\u001b[31m  const st = document.getElementById('cfg-sync-status');\u001b[39m\n\u001b[31m  if (st) st.textContent = t('Syncing…','सिंक हो रहा है…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-cfg', empId: hub.empId, cfg: {\u001b[39m\n\u001b[31m        version: _recceCfg.version || 1,\u001b[39m\n\u001b[31m        supervisors: _recceCfg.supervisors || [],\u001b[39m\n\u001b[31m        mode: _recceCfg.mode || 'public',\u001b[39m\n\u001b[31m        creators: _recceCfg.creators || [],\u001b[39m\n\u001b[31m        allowed_users: _recceCfg.allowed_users || [],\u001b[39m\n\u001b[31m        clients: _recceCfg.clients || [],\u001b[39m\n\u001b[31m      }})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) {\u001b[39m\n\u001b[31m      toast(t('Config synced to server ✓','कॉन्फ़िग सर्वर पर सेव हुआ ✓'), 'success');\u001b[39m\n\u001b[31m      if (st) st.textContent = t('Last synced: just now','अभी सिंक हुआ');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast(j.error || t('Sync failed','सिंक विफल'), 'error');\u001b[39m\n\u001b[31m      if (st) st.textContent = j.error || '';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Network error','नेटवर्क त्रुटि'), 'error');\u001b[39m\n\u001b[31m    if (st) st.textContent = e.message;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function pushStoresToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!hub?.empId || !_adminUnlocked) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-stores', empId: hub.empId, stores })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) toast(`${t('Pushed to server','सर्वर पर पुश हुआ')} · ${j.count} ${t('stores','स्टोर')}`, 'success');\u001b[39m\n\u001b[31m    else toast(j.error || t('Server push failed','सर्वर पुश विफल'), 'error');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Could not reach server','सर्वर से संपर्क नहीं हो सका'), 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── End supervisor config management ────────────────────────────────·\u001b[39m\n\u001b[31m// PostgREST sync constants\u001b[39m\n\u001b[31mconst _RC_BASE      = '/db';\u001b[39m\n\u001b[31mconst _RC_READ      = { 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_WRITE     = { 'Content-Type': 'application/json', 'Content-Profile': 'recce', 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_UPSERT    = { ..._RC_WRITE, 'Prefer': 'resolution=merge-duplicates,return=minimal' };\u001b[39m\n\u001b[31mconst _INSTALL_RD   = { 'Content-Type': 'application/json', 'Accept-Profile': 'installation' };\u001b[39m\n\u001b[31mconst _INSTALL_WR   = { 'Content-Type': 'application/json', 'Content-Profile': 'installation', 'Accept-Profile': 'installation', 'Prefer': 'return=minimal' };·\u001b[39m\n\u001b[31m// ── Campaign selection state ──\u001b[39m\n\u001b[31mlet _selectedCampaignId = null;\u001b[39m\n\u001b[31mlet _notifySupervisor   = false;\u001b[39m\n\u001b[31mlet _campaignList       = [];\u001b[39m\n\u001b[31mlet _pendingJobFilter   = false;\u001b[39m\n\u001b[31mlet _linkJobSubId       = null;\u001b[39m\n\u001b[31mlet _brandingLocked     = false;·\u001b[39m\n\u001b[31mfunction _updateBrandingLock() {\u001b[39m\n\u001b[31m  const hub  = _recceHubUser();\u001b[39m\n\u001b[31m  const isHP = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const banner   = document.getElementById('branding-lock-banner');\u001b[39m\n\u001b[31m  const ovWrap   = document.getElementById('branding-override-wrap');\u001b[39m\n\u001b[31m  const brItems  = document.getElementById('br-items');\u001b[39m\n\u001b[31m  const brAdd    = document.getElementById('br-add');\u001b[39m\n\u001b[31m  const brYes    = document.getElementById('br-yes');\u001b[39m\n\u001b[31m  const brNo     = document.getElementById('br-no');\u001b[39m\n\u001b[31m  if (!banner) return;\u001b[39m\n\u001b[31m  if (_brandingLocked) {\u001b[39m\n\u001b[31m    banner.style.display   = '';\u001b[39m\n\u001b[31m    if (ovWrap)  ovWrap.style.display  = isHP ? '' : 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.pointerEvents = 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.opacity = '0.55';\u001b[39m\n\u001b[31m    if (brAdd)   brAdd.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='none'; brYes.style.opacity='0.5'; }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='none';  brNo.style.opacity='0.5';  }\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    banner.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brItems) { brItems.style.pointerEvents=''; brItems.style.opacity=''; }\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='';  brYes.style.opacity='';   }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='';   brNo.style.opacity='';    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction unlockBrandingOverride() {\u001b[39m\n\u001b[31m  if (!confirm(\u001b[39m\n\u001b[31m    'Client has already reviewed this recce.\\\\n' +\u001b[39m\n\u001b[31m    'Editing brandings will NOT remove their approval.\\\\n' +\u001b[39m\n\u001b[31m    'Continue ONLY if the client has verbally confirmed. Proceed?'\u001b[39m\n\u001b[31m  )) return;\u001b[39m\n\u001b[31m  _brandingLocked = false;\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  renderBrandings();\u001b[39m\n\u001b[31m  toast(t('Branding unlocked for this session', 'ब्रांडिंग इस सत्र के लिए अनलॉक'), 'info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadCampaignsForForm() {\u001b[39m\n\u001b[31m  const sel = document.getElementById('f-campaign-id');\u001b[39m\n\u001b[31m  if (!sel) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m    _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m  } catch(_) { _campaignList = []; }\u001b[39m\n\u001b[31m  sel.innerHTML =\u001b[39m\n\u001b[31m    '<option value=\\\"\\\">— Select job / campaign (optional) —</option>' +\u001b[39m\n\u001b[31m    _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('') +\u001b[39m\n\u001b[31m    '<option value=\\\"__NOTIFY__\\\">⚑ No campaign yet — notify supervisor</option>';\u001b[39m\n\u001b[31m  if (_selectedCampaignId) sel.value = _selectedCampaignId;\u001b[39m\n\u001b[31m  else if (_notifySupervisor) sel.value = '__NOTIFY__';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onCampaignSelect() {\u001b[39m\n\u001b[31m  const val = document.getElementById('f-campaign-id')?.value || '';\u001b[39m\n\u001b[31m  const noticeEl = document.getElementById('campaign-notify-msg');\u001b[39m\n\u001b[31m  if (val === '__NOTIFY__') {\u001b[39m\n\u001b[31m    _selectedCampaignId = null;\u001b[39m\n\u001b[31m    _notifySupervisor   = true;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'block';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    _selectedCampaignId = val || null;\u001b[39m\n\u001b[31m    _notifySupervisor   = false;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction generateRecceReportHtml(entry, photoUrls) {\u001b[39m\n\u001b[31m  const d    = entry.data || {};\u001b[39m\n\u001b[31m  const urls = photoUrls || {};\u001b[39m\n\u001b[31m  const agent = entry.submittedByName || entry.submittedBy || 'Field Agent';\u001b[39m\n\u001b[31m  const _safeId      = (entry.id||'').replace(/\\\\//g,'_').replace(/\\\\.\\\\./g,'');\u001b[39m\n\u001b[31m  const serverPdfUrl = _safeId ? `https://srv1111289.hstgr.cloud/screenshots/recce/views/${_safeId}.pdf` : '';\u001b[39m\n\u001b[31m  const brandLogoUrl = d.brandLogoUrl || _brandLogos[d.brand] || '';\u001b[39m\n\u001b[31m  const tsStr = new Date(entry.timestamp).toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric',hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\u001b[39m\n\u001b[31m  const gpsUrl = d.gpsCoords ? `https://maps.google.com/?q=${d.gpsCoords.lat},${d.gpsCoords.lng}` : null;·\u001b[39m\n\u001b[31m  const frontCount  = (urls.front||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const insideCount = (urls.inside||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const addlCount   = (urls.addl||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const brCount     = (d.brandings||[]).length;·\u001b[39m\n\u001b[31m  // pages: { id, url, bandHtml, cmt, dotLabel, dotColor }\u001b[39m\n\u001b[31m  const pages = [];·\u001b[39m\n\u001b[31m  (urls.front||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Front View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${frontCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.frontPhotos||[])[i]?.cmt||'', dotLabel:`FV${i+1}`, dotColor:'#3b82f6', catLabel:'Front View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.inside||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Inside View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${insideCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.insidePhotos||[])[i]?.cmt||'', dotLabel:`IV${i+1}`, dotColor:'#14b8a6', catLabel:'Inside View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (d.brandings||[]).forEach((b,i)=>{\u001b[39m\n\u001b[31m    const url=(urls.brandings||[])[i]; if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">${esc(b.type||'Branding')}</div><div class=\\\"ph-dims\\\">Width : ${esc(b.w||'?')}&Prime;&nbsp;&times;&nbsp;Height : ${esc(b.h||'?')}&Prime;&nbsp;&mdash;&nbsp;${esc(b.qty||1)} Nos</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${brCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:'', dotLabel:`B${i+1}`, dotColor:'#f97316', catLabel:b.type||'Branding',\u001b[39m\n\u001b[31m      tileDims:`${b.w||'?'}″×${b.h||'?'}″ — ${String(b.qty||1).padStart(2,'0')} Nos` });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.addl||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Additional</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${addlCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.addlPhotos||[])[i]?.desc||'', dotLabel:`A${i+1}`, dotColor:'#94a3b8', catLabel:'Additional', tileDims:'' });\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const sideItems = [\u001b[39m\n\u001b[31m    `<div class=\\\"si-item active\\\" data-tgt=\\\"pg-cover\\\" title=\\\"Cover\\\"><div class=\\\"si-dot\\\" style=\\\"background:#475569\\\">CV</div></div>`\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  pages.forEach(p => {\u001b[39m\n\u001b[31m    sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"${p.id}\\\" title=\\\"${p.dotLabel}\\\"><div class=\\\"si-dot\\\" style=\\\"background:${p.dotColor}\\\">${p.dotLabel}</div></div>`);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(d.hasVideo) sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-vid\\\" title=\\\"Video\\\"><div class=\\\"si-dot\\\" style=\\\"background:#a855f7\\\">VD</div></div>`);\u001b[39m\n\u001b[31m  if(urls.doc)   sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-doc\\\" title=\\\"Document\\\"><div class=\\\"si-dot\\\" style=\\\"background:#64748b\\\">DC</div></div>`);·\u001b[39m\n\u001b[31m  const thumbItems = [\u001b[39m\n\u001b[31m    ...pages,\u001b[39m\n\u001b[31m    ...(d.hasVideo?[{id:'pg-vid',url:null,catLabel:'Video',tileDims:'',dotLabel:'VD',dotColor:'#a855f7'}]:[]),\u001b[39m\n\u001b[31m    ...(urls.doc?[{id:'pg-doc',url:urls.doc,catLabel:'Document',tileDims:'',dotLabel:'DC',dotColor:'#64748b'}]:[])\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  const thumbsHtml = thumbItems.map(p=>`<div class=\\\"cov-thumb\\\" onclick=\\\"document.getElementById('${p.id}').scrollIntoView({behavior:'smooth'})\\\">${p.url?`<img src=\\\"${p.url}\\\" alt=\\\"\\\">`:(`<div class=\\\"cov-thumb-vid\\\">${p.catLabel==='Video'?'&#x25B6;&#xFE0F;':'&#x1F4C4;'}</div>`)}<div class=\\\"cov-thumb-ov\\\" style=\\\"border-top:3px solid ${p.dotColor}\\\"><div class=\\\"cov-thumb-cat\\\">${esc(p.catLabel)}</div>${p.tileDims?`<div class=\\\"cov-thumb-dims\\\">${esc(p.tileDims)}</div>`:''}<div class=\\\"cov-thumb-no\\\">${p.dotLabel}</div></div></div>`).join('');·\u001b[39m\n\u001b[31m  const pagesHtml = pages.map(p => `\u001b[39m\n\u001b[31m<div class=\\\"photo-page\\\" id=\\\"${p.id}\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\">${p.bandHtml}</div>\u001b[39m\n\u001b[31m  <div class=\\\"ph-img\\\"><a href=\\\"${p.url}\\\" target=\\\"_blank\\\"><img src=\\\"${p.url}\\\" loading=\\\"lazy\\\" alt=\\\"\\\"></a>${p.cmt?`<div class=\\\"ph-cmt\\\">${esc(p.cmt)}</div>`:''}</div>\u001b[39m\n\u001b[31m</div>`).join('');·\u001b[39m\n\u001b[31m  return `<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\"><head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m<title>Recce — ${esc(d.storeName||'Unknown')} · ${esc(d.brand||'')}</title>\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--dk:#0f172a;--nv2:#1a2f52;--or:#f97316;--g200:#e2e8f0;--g400:#94a3b8;--g600:#475569;--si:54px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0}\u001b[39m\n\u001b[31mhtml,body{height:100%;overflow:hidden}\u001b[39m\n\u001b[31mbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#111;color:var(--dk);display:flex}\u001b[39m\n\u001b[31ma{color:var(--or);text-decoration:none}\u001b[39m\n\u001b[31mimg{display:block}·\u001b[39m\n\u001b[31m/* ── Side index ── */\u001b[39m\n\u001b[31m.side-idx{width:var(--si);flex-shrink:0;background:var(--dk);overflow-y:auto;display:flex;flex-direction:column;align-items:center;padding:4px 0;scrollbar-width:none;z-index:50}\u001b[39m\n\u001b[31m.side-idx::-webkit-scrollbar{display:none}\u001b[39m\n\u001b[31m.si-item{width:100%;min-height:56px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s}\u001b[39m\n\u001b[31m.si-item:hover{background:rgba(255,255,255,.07)}\u001b[39m\n\u001b[31m.si-dot{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff;opacity:.4;transition:opacity .18s,transform .18s;line-height:1;text-align:center}\u001b[39m\n\u001b[31m.si-item.active .si-dot{opacity:1;transform:scale(1.15)}·\u001b[39m\n\u001b[31m/* ── Main scroll area ── */\u001b[39m\n\u001b[31m.main{flex:1;overflow-y:scroll;scroll-snap-type:y mandatory;scroll-behavior:smooth;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar{width:3px}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15)}·\u001b[39m\n\u001b[31m/* ── Cover ── */\u001b[39m\n\u001b[31m.cover{height:100vh;scroll-snap-align:start;flex-shrink:0;background:linear-gradient(135deg,#0f172a 0%,var(--nv2) 100%);color:#fff;display:flex;flex-direction:column;padding:24px 20px 20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.cover-badge{display:inline-flex;align-items:center;gap:5px;background:var(--or);color:#fff;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:1px;padding:3px 12px;border-radius:20px;margin-bottom:12px;align-self:flex-start}\u001b[39m\n\u001b[31m.cover h1{font-size:20px;font-weight:700;line-height:1.3;margin-bottom:4px}\u001b[39m\n\u001b[31m.cover-addr{color:rgba(255,255,255,.55);font-size:12px;margin-bottom:16px}\u001b[39m\n\u001b[31m.cg{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}\u001b[39m\n\u001b[31m.cm{background:rgba(255,255,255,.08);border-radius:8px;padding:8px 12px}\u001b[39m\n\u001b[31m.cm-l{font-size:9px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}\u001b[39m\n\u001b[31m.cm-v{font-size:13px;font-weight:600;color:#fff}\u001b[39m\n\u001b[31m.cm-v a{color:#fb923c}\u001b[39m\n\u001b[31m.cover-pbar{padding-top:8px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{background:var(--or);color:#fff;border:none;padding:10px 22px;border-radius:22px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}\u001b[39m\n\u001b[31m.btn-p:disabled{opacity:.4;cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-c{background:rgba(255,255,255,.1);color:rgba(255,255,255,.75);border:1px solid rgba(255,255,255,.2);padding:10px 18px;border-radius:22px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit}·\u001b[39m\n\u001b[31m/* ── Cover thumbnail grid ── */\u001b[39m\n\u001b[31m.cov-grid-hdr{font-size:10px;font-weight:700;color:rgba(255,255,255,.35);text-transform:uppercase;letter-spacing:1.2px;padding:10px 0 5px;flex-shrink:0}\u001b[39m\n\u001b[31m.cov-grid{flex:1;min-height:0;display:grid;gap:5px;overflow:hidden;align-content:start}\u001b[39m\n\u001b[31m.cov-thumb{position:relative;overflow:hidden;border-radius:7px;cursor:pointer;background:#1e293b;transition:transform .18s,box-shadow .18s}\u001b[39m\n\u001b[31m.cov-thumb:hover{transform:scale(1.05);box-shadow:0 4px 18px rgba(0,0,0,.55)}\u001b[39m\n\u001b[31m.cov-thumb img{width:100%;height:100%;object-fit:cover;display:block}\u001b[39m\n\u001b[31m.cov-thumb-vid{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:#0f172a}\u001b[39m\n\u001b[31m.cov-thumb-ov{position:absolute;inset:0;background:rgba(0,0,0,.28);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:5px;border-radius:7px}\u001b[39m\n\u001b[31m.cov-thumb-cat{color:rgba(255,255,255,.5);font-weight:900;text-align:center;text-transform:uppercase;letter-spacing:.8px;text-shadow:0 1px 6px rgba(0,0,0,.95);line-height:1.2;word-break:break-word}\u001b[39m\n\u001b[31m.cov-thumb-dims{color:rgba(255,255,255,.5);font-weight:700;text-align:center;text-shadow:0 1px 5px rgba(0,0,0,.95);letter-spacing:.3px;line-height:1.3}\u001b[39m\n\u001b[31m.cov-thumb-no{color:rgba(255,255,255,.5);font-weight:800;text-shadow:0 1px 4px rgba(0,0,0,.95);letter-spacing:.5px}\u001b[39m\n\u001b[31m#cover-btn{position:fixed;bottom:20px;right:16px;display:none;align-items:center;gap:6px;background:rgba(255,255,255,.15);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.25);color:#fff;padding:10px 22px;border-radius:50px;font-size:13px;font-weight:700;cursor:pointer;z-index:200;letter-spacing:.3px;box-shadow:0 2px 12px rgba(0,0,0,.3);font-family:inherit;transition:background .15s,transform .15s}\u001b[39m\n\u001b[31m#cover-btn:hover{background:rgba(255,255,255,.22);transform:scale(1.04)}·\u001b[39m\n\u001b[31m/* ── Print wait overlay ── */\u001b[39m\n\u001b[31m#print-overlay{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m@media print{#print-overlay{display:none!important}}·\u001b[39m\n\u001b[31m/* ── Loading progress bar ── */\u001b[39m\n\u001b[31m.load-bar{position:fixed;bottom:0;left:0;right:0;background:rgba(15,23,42,.95);padding:9px 16px;z-index:9999;display:flex;align-items:center;gap:12px;backdrop-filter:blur(6px)}\u001b[39m\n\u001b[31m.load-track{flex:1;height:5px;background:rgba(255,255,255,.12);border-radius:3px;overflow:hidden}\u001b[39m\n\u001b[31m.load-fill{height:100%;background:var(--or);width:0%;transition:width .35s ease;border-radius:3px}\u001b[39m\n\u001b[31m.load-txt{font-size:11px;color:rgba(255,255,255,.6);white-space:nowrap;min-width:160px}·\u001b[39m\n\u001b[31m/* ── Photo page ── */\u001b[39m\n\u001b[31m.photo-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ph-band{background:var(--dk);padding:16px 26px;flex-shrink:0;display:flex;align-items:center;gap:20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.ph-cat{font-size:35px;font-weight:800;color:#fff;letter-spacing:-.5px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.ph-dims{flex:1;font-size:18px;font-weight:600;color:var(--or);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}\u001b[39m\n\u001b[31m.ph-no{margin-left:auto;flex-shrink:0;font-size:21px;font-weight:700;color:rgba(255,255,255,.85);background:rgba(255,255,255,.1);padding:5px 20px;border-radius:24px;white-space:nowrap}\u001b[39m\n\u001b[31m.ph-of{font-size:18px;font-weight:400;color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.ph-img{flex:1;overflow:hidden;position:relative;background:#111}\u001b[39m\n\u001b[31m.ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m.ph-img img{width:100%;height:100%;object-fit:contain;display:block}\u001b[39m\n\u001b[31m.ph-cmt{position:absolute;bottom:0;left:0;right:0;padding:6px 14px;background:rgba(0,0,0,.62);font-size:11px;color:rgba(255,255,255,.75);font-style:italic;pointer-events:none}·\u001b[39m\n\u001b[31m/* ── Video / Doc pages ── */\u001b[39m\n\u001b[31m.vid-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;background:#fff}\u001b[39m\n\u001b[31m.vid-body{flex:1;padding:20px 24px;font-size:14px;color:var(--g600);border-left:4px solid var(--or)}\u001b[39m\n\u001b[31m.vid-body em{display:block;font-size:12px;color:var(--g400);margin-top:6px}\u001b[39m\n\u001b[31m.doc-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m.doc-wrap{flex:1;display:flex;align-items:center;justify-content:center;background:#111;overflow:hidden}\u001b[39m\n\u001b[31m.doc-img{max-width:100%;max-height:100%;object-fit:contain}·\u001b[39m\n\u001b[31m/* ── Cover header band ── */\u001b[39m\n\u001b[31m.cov-hdr{display:flex;gap:0;margin-bottom:12px;flex-shrink:0;border-radius:10px;overflow:hidden;border:1px solid rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.cov-hdr-l{flex:1;padding:14px 18px;display:flex;flex-direction:column;gap:5px;border-right:1px solid rgba(255,255,255,.1);min-width:0}\u001b[39m\n\u001b[31m.cov-hdr-r{width:170px;flex-shrink:0;padding:14px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:rgba(255,255,255,.04)}\u001b[39m\n\u001b[31m.cov-store{font-size:18px;font-weight:800;color:#fff;line-height:1.25;margin-bottom:2px}\u001b[39m\n\u001b[31m.cov-meta{font-size:12px;color:rgba(255,255,255,.55);display:flex;align-items:center;gap:5px;line-height:1.5}\u001b[39m\n\u001b[31m.cov-brand{background:var(--or);color:#fff;font-size:13px;font-weight:800;padding:5px 16px;border-radius:20px;text-align:center;letter-spacing:.3px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\u001b[39m\n\u001b[31m.cov-date-l{font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.8px;margin-bottom:2px;text-align:center}\u001b[39m\n\u001b[31m.cov-date-v{font-size:13px;font-weight:700;color:#fff;text-align:center}\u001b[39m\n\u001b[31m.cov-logo-box{background:#fff;border-radius:8px;padding:8px 14px;display:flex;align-items:center;justify-content:center;width:100%;max-width:138px}\u001b[39m\n\u001b[31m.cov-logo-box img{max-width:110px;max-height:44px;object-fit:contain;display:block}·\u001b[39m\n\u001b[31m/* ── Print ── */\u001b[39m\n\u001b[31m@page{size:A4 landscape;margin:12mm}\u001b[39m\n\u001b[31m@media print{\u001b[39m\n\u001b[31m  html,body{height:auto;overflow:visible;display:block}\u001b[39m\n\u001b[31m  .side-idx{display:none}\u001b[39m\n\u001b[31m  .main{overflow:visible;display:block;height:auto;scroll-snap-type:none}\u001b[39m\n\u001b[31m  .cover,.vid-page,.doc-page{height:auto;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m  .photo-page{height:186mm;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m  .cover{padding:20px 24px}\u001b[39m\n\u001b[31m  .cover-pbar{display:none}\u001b[39m\n\u001b[31m  .cov-hdr{margin-bottom:8px;border-radius:7px}\u001b[39m\n\u001b[31m  .cov-hdr-l{padding:10px 14px}\u001b[39m\n\u001b[31m  .cov-hdr-r{padding:10px 12px;width:150px}\u001b[39m\n\u001b[31m  .cov-store{font-size:15px}\u001b[39m\n\u001b[31m  .cov-meta{font-size:10px}\u001b[39m\n\u001b[31m  .cov-brand{font-size:11px;padding:3px 12px}\u001b[39m\n\u001b[31m  .cov-date-v{font-size:11px}\u001b[39m\n\u001b[31m  .ph-band{padding:5mm 13mm;gap:10mm}\u001b[39m\n\u001b[31m  .ph-cat{font-size:15mm}\u001b[39m\n\u001b[31m  .ph-dims{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-no{font-size:12mm;padding:2mm 8mm}\u001b[39m\n\u001b[31m  .ph-of{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-img{flex:1;display:flex;align-items:center;justify-content:center;background:#fff;overflow:hidden}\u001b[39m\n\u001b[31m  .ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m  .ph-img img{width:100%;height:100%;object-fit:contain}\u001b[39m\n\u001b[31m  .ph-cmt{position:static;background:transparent;color:#475569;padding:2mm 8mm;font-size:6mm}\u001b[39m\n\u001b[31m  .main>*:last-child{page-break-after:avoid;break-after:avoid}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m</style></head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<div class=\\\"side-idx\\\" id=\\\"side-idx\\\">${sideItems.join('')}</div>·\u001b[39m\n\u001b[31m<div class=\\\"main\\\" id=\\\"main\\\">·\u001b[39m\n\u001b[31m<div class=\\\"cover\\\" id=\\\"pg-cover\\\">\u001b[39m\n\u001b[31m  <div class=\\\"cov-hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-l\\\">\u001b[39m\n\u001b[31m      <div class=\\\"cov-store\\\">${esc(d.storeName||'Unknown Store')}</div>\u001b[39m\n\u001b[31m      ${(d.address||d.city)?`<div class=\\\"cov-meta\\\">&#x1F4CD; ${esc(d.address||'')}${d.city&&!(d.address||'').includes(d.city)?', '+esc(d.city):''}</div>`:''}\u001b[39m\n\u001b[31m      ${d.mobile?`<div class=\\\"cov-meta\\\">&#x1F4DE; ${esc(d.mobile)}</div>`:''}\u001b[39m\n\u001b[31m      ${d.email?`<div class=\\\"cov-meta\\\">&#x2709; ${esc(d.email)}</div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-r\\\">\u001b[39m\n\u001b[31m      ${brandLogoUrl\u001b[39m\n\u001b[31m        ? `<div class=\\\"cov-logo-box\\\"><img src=\\\"${brandLogoUrl}\\\" alt=\\\"${esc(d.brand||'')}\\\"></div>`\u001b[39m\n\u001b[31m        : (d.brand?`<div class=\\\"cov-brand\\\">${esc(d.brand)}</div>`:'')}\u001b[39m\n\u001b[31m      ${d.date?`<div><div class=\\\"cov-date-l\\\">Recce Date</div><div class=\\\"cov-date-v\\\">${esc(d.date)}</div></div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${thumbItems.length ? `<div class=\\\"cov-grid-hdr\\\">&#x1F4F7; ${thumbItems.length} page${thumbItems.length!==1?'s':''} &mdash; tap any to jump</div><div class=\\\"cov-grid\\\" id=\\\"cov-grid\\\">${thumbsHtml}</div>` : ''}\u001b[39m\n\u001b[31m  <div class=\\\"cover-pbar\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" id=\\\"btn-print\\\" onclick=\\\"doPDF()\\\">&#x1F4C4;&nbsp;PDF</button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-c\\\" onclick=\\\"window.close()\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m${pagesHtml}·\u001b[39m\n\u001b[31m${d.hasVideo?`\u001b[39m\n\u001b[31m<div class=\\\"vid-page\\\" id=\\\"pg-vid\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Video</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"vid-body\\\">${esc(d.videoNote||'Video recorded during visit')}${d.videoCmt?`<em>${esc(d.videoCmt)}</em>`:''}</div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m${urls.doc?`\u001b[39m\n\u001b[31m<div class=\\\"doc-page\\\" id=\\\"pg-doc\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Document</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"doc-wrap\\\"><a href=\\\"${urls.doc}\\\" target=\\\"_blank\\\"><img class=\\\"doc-img\\\" src=\\\"${urls.doc}\\\" loading=\\\"lazy\\\" alt=\\\"Document\\\"></a></div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"print-overlay\\\"><div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Preparing print&hellip;</div><div class=\\\"po-sub\\\" id=\\\"po-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"po-pfill\\\"></div></div></div>\u001b[39m\n\u001b[31m${pages.length ? `<div class=\\\"load-bar\\\" id=\\\"load-bar\\\"><div class=\\\"load-track\\\"><div class=\\\"load-fill\\\" id=\\\"load-fill\\\"></div></div><div class=\\\"load-txt\\\" id=\\\"load-txt\\\">Loading photos&#x2026;</div></div>` : ''}\u001b[39m\n\u001b[31m${thumbItems.length ? `<button id=\\\"cover-btn\\\" onclick=\\\"document.getElementById('pg-cover').scrollIntoView({behavior:'smooth'})\\\">&#x1F3E0;&nbsp;Cover Page</button>` : ''}·\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var main=document.getElementById('main');\u001b[39m\n\u001b[31m  var items=document.querySelectorAll('.si-item');\u001b[39m\n\u001b[31m  var covBtn=document.getElementById('cover-btn');\u001b[39m\n\u001b[31m  function setActive(id){\u001b[39m\n\u001b[31m    items.forEach(function(el){el.classList.toggle('active',el.dataset.tgt===id);});\u001b[39m\n\u001b[31m    var a=document.querySelector('.si-item[data-tgt=\\\"'+id+'\\\"]');\u001b[39m\n\u001b[31m    if(a) a.scrollIntoView({block:'nearest'});\u001b[39m\n\u001b[31m    if(covBtn) covBtn.style.display=id==='pg-cover'?'none':'flex';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  items.forEach(function(el){\u001b[39m\n\u001b[31m    el.addEventListener('click',function(){\u001b[39m\n\u001b[31m      var t=document.getElementById(el.dataset.tgt);\u001b[39m\n\u001b[31m      if(t) t.scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if('IntersectionObserver' in window){\u001b[39m\n\u001b[31m    var obs=new IntersectionObserver(function(entries){\u001b[39m\n\u001b[31m      entries.forEach(function(e){if(e.isIntersecting&&e.intersectionRatio>=0.45) setActive(e.target.id);});\u001b[39m\n\u001b[31m    },{root:main,threshold:0.45});\u001b[39m\n\u001b[31m    document.querySelectorAll('[id^=\\\"pg-\\\"]').forEach(function(p){obs.observe(p);});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  setActive('pg-cover');\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var imgs=Array.from(document.querySelectorAll('img'));\u001b[39m\n\u001b[31m  var total=imgs.length,loaded=0;\u001b[39m\n\u001b[31m  var bar=document.getElementById('load-bar');\u001b[39m\n\u001b[31m  var fill=document.getElementById('load-fill');\u001b[39m\n\u001b[31m  var txt=document.getElementById('load-txt');\u001b[39m\n\u001b[31m  var printPending=false,printShowTime=0;\u001b[39m\n\u001b[31m  var mm=96/25.4;\u001b[39m\n\u001b[31m  var SERVER_PDF='${serverPdfUrl}';\u001b[39m\n\u001b[31m  function updatePoBar(){\u001b[39m\n\u001b[31m    var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m    var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(poFill) poFill.style.width=(total?Math.round(loaded/total*100):100)+'%';\u001b[39m\n\u001b[31m    if(poSub) poSub.textContent=loaded+' / '+total+' photos ready';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function done(){\u001b[39m\n\u001b[31m    if(fill) fill.style.width='100%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='✓ All '+total+' photos ready';\u001b[39m\n\u001b[31m    setTimeout(function(){\u001b[39m\n\u001b[31m      if(bar){bar.style.transition='opacity .6s';bar.style.opacity='0';}\u001b[39m\n\u001b[31m      setTimeout(function(){if(bar)bar.style.display='none';},650);\u001b[39m\n\u001b[31m    },2000);\u001b[39m\n\u001b[31m    if(printPending){\u001b[39m\n\u001b[31m      printPending=false;\u001b[39m\n\u001b[31m      var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m      var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m      var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(poFill) poFill.style.width='100%';\u001b[39m\n\u001b[31m      if(poSub) poSub.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},Math.max(400,2000-(Date.now()-printShowTime)));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function onImg(){\u001b[39m\n\u001b[31m    loaded++;\u001b[39m\n\u001b[31m    if(fill) fill.style.width=Math.round(loaded/total*100)+'%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… '+loaded+' / '+total;\u001b[39m\n\u001b[31m    if(printPending) updatePoBar();\u001b[39m\n\u001b[31m    if(loaded>=total) done();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  /* ── PDF layout helpers ── */\u001b[39m\n\u001b[31m  function fitBandFonts(pageW){\u001b[39m\n\u001b[31m    var padH=2*13*mm,gapH=2*10*mm,noPadH=2*8*mm;\u001b[39m\n\u001b[31m    var avail=pageW-padH-gapH;\u001b[39m\n\u001b[31m    var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-band').forEach(function(band){\u001b[39m\n\u001b[31m      var cat=band.querySelector('.ph-cat');\u001b[39m\n\u001b[31m      var dims=band.querySelector('.ph-dims');\u001b[39m\n\u001b[31m      var no=band.querySelector('.ph-no');\u001b[39m\n\u001b[31m      if(!cat) return;\u001b[39m\n\u001b[31m      var catTxt=cat.textContent.trim();\u001b[39m\n\u001b[31m      var dimsTxt=dims?dims.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      var noTxt=no?no.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      function tw(sc){\u001b[39m\n\u001b[31m        var cf=15*sc*mm,df=10*sc*mm,nf=12*sc*mm;\u001b[39m\n\u001b[31m        ctx.font='800 '+cf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var cw=ctx.measureText(catTxt).width;\u001b[39m\n\u001b[31m        ctx.font='600 '+df+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var dw=dims?ctx.measureText(dimsTxt).width:0;\u001b[39m\n\u001b[31m        ctx.font='700 '+nf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var nw=no?ctx.measureText(noTxt).width+noPadH:0;\u001b[39m\n\u001b[31m        return cw+dw+nw;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      var scale=1.0;\u001b[39m\n\u001b[31m      if(tw(scale)>avail){\u001b[39m\n\u001b[31m        var lo=0.3,hi=1.0;\u001b[39m\n\u001b[31m        for(var i=0;i<10;i++){var mid=(lo+hi)/2;if(tw(mid)<=avail)lo=mid;else hi=mid;}\u001b[39m\n\u001b[31m        scale=lo*0.93;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      cat.style.setProperty('font-size',Math.round(15*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(dims) dims.style.setProperty('font-size',Math.round(10*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(no) no.style.setProperty('font-size',Math.round(12*scale*mm)+'px','important');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function sizePdfThumbs(pageW,pageH){\u001b[39m\n\u001b[31m    var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m    if(!grid||!grid.children.length) return;\u001b[39m\n\u001b[31m    var coverPage=document.getElementById('pg-cover');\u001b[39m\n\u001b[31m    var usedH=56;\u001b[39m\n\u001b[31m    if(coverPage){\u001b[39m\n\u001b[31m      Array.from(coverPage.children).forEach(function(el){\u001b[39m\n\u001b[31m        if(el!==grid) usedH+=el.offsetHeight||0;\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    var gridH=Math.max(80,pageH-usedH);\u001b[39m\n\u001b[31m    var n=grid.children.length,gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m    for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m      var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m      var w=(pageW-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m      var h=w*asp;\u001b[39m\n\u001b[31m      if(rows*h+(rows-1)*gap<=gridH&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m    grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m    grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m    var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m    var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m    var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function preparePdfLayout(){\u001b[39m\n\u001b[31m    var pageW=Math.round((297-24)*mm);\u001b[39m\n\u001b[31m    var pageH=Math.round((210-24)*mm);\u001b[39m\n\u001b[31m    fitBandFonts(pageW);\u001b[39m\n\u001b[31m    sizePdfThumbs(pageW,pageH);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.preparePdfLayout=preparePdfLayout;\u001b[39m\n\u001b[31m  function restorePdfLayout(){\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-cat,.ph-dims,.ph-no').forEach(function(el){\u001b[39m\n\u001b[31m      el.style.removeProperty('font-size');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(window._screenSizeThumbs) window._screenSizeThumbs();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.addEventListener('afterprint',restorePdfLayout);\u001b[39m\n\u001b[31m  function _doBrowserPrint(){\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    printShowTime=Date.now();\u001b[39m\n\u001b[31m    preparePdfLayout();\u001b[39m\n\u001b[31m    if(total===0||loaded>=total){\u001b[39m\n\u001b[31m      var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m      if(ps) ps.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},2000);\u001b[39m\n\u001b[31m      return;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    printPending=true;\u001b[39m\n\u001b[31m    updatePoBar();\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if((!img.complete||img.naturalWidth===0)&&img.getAttribute('loading')==='lazy'){\u001b[39m\n\u001b[31m        img.loading='eager';var s=img.src;img.src='';img.src=s;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.doPDF=async function(){\u001b[39m\n\u001b[31m    if(!SERVER_PDF){_doBrowserPrint();return;}\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      var r=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m      if(r.ok){window.open(SERVER_PDF,'_blank');return;}\u001b[39m\n\u001b[31m    }catch(_){}\u001b[39m\n\u001b[31m    // PDF not ready yet — show overlay and poll\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    if(pf) pf.style.width='0%';\u001b[39m\n\u001b[31m    if(ps) ps.textContent='Waiting for server PDF…';\u001b[39m\n\u001b[31m    var tries=0;\u001b[39m\n\u001b[31m    (async function poll(){\u001b[39m\n\u001b[31m      tries++;\u001b[39m\n\u001b[31m      if(pf) pf.style.width=Math.min(88,tries*8)+'%';\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        var r2=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m        if(r2.ok){\u001b[39m\n\u001b[31m          if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m          setTimeout(function(){if(ov)ov.style.display='none';window.open(SERVER_PDF,'_blank');},400);\u001b[39m\n\u001b[31m          return;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      }catch(_){}\u001b[39m\n\u001b[31m      if(tries>=12){if(ov)ov.style.display='none';_doBrowserPrint();return;}\u001b[39m\n\u001b[31m      setTimeout(poll,5000);\u001b[39m\n\u001b[31m    })();\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  if(total===0){if(bar)bar.style.display='none';}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… 0 / '+total;\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if(img.complete&&img.naturalWidth>0) onImg();\u001b[39m\n\u001b[31m      else{img.addEventListener('load',onImg);img.addEventListener('error',onImg);}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m  if(grid&&grid.children.length>0){\u001b[39m\n\u001b[31m    function sizeThumbs(){\u001b[39m\n\u001b[31m      var n=grid.children.length;\u001b[39m\n\u001b[31m      var gw=grid.clientWidth,gh=grid.clientHeight;\u001b[39m\n\u001b[31m      if(!gw||!gh) return;\u001b[39m\n\u001b[31m      var gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m      for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m        var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m        var w=(gw-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m        var h=w*asp;\u001b[39m\n\u001b[31m        if(rows*h+(rows-1)*gap<=gh&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m      grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m      grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m      var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m      var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m      var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    window._screenSizeThumbs=sizeThumbs;\u001b[39m\n\u001b[31m    requestAnimationFrame(function(){requestAnimationFrame(sizeThumbs);});\u001b[39m\n\u001b[31m    window.addEventListener('resize',sizeThumbs);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m</scr`+'ipt>'+`\u001b[39m\n\u001b[31m</body></html>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncToPostgres(entry) {\u001b[39m\n\u001b[31m  const d   = entry.data || {};\u001b[39m\n\u001b[31m  const hub = _recceHubUser();·\u001b[39m\n\u001b[31m  // Step 1 — upload all photos to VPS, get permanent server URLs\u001b[39m\n\u001b[31m  let photoUrls = { front:[], inside:[], brandings:[], addl:[], doc:null };\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const pResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type: 'save-photos', subId: entry.id,\u001b[39m\n\u001b[31m        photos: {\u001b[39m\n\u001b[31m          front:    (d.frontPhotos||[]).map(p=>({b64:p.b64,   cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64,  cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||null})),\u001b[39m\n\u001b[31m          addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64,   desc:p.desc||''})),\u001b[39m\n\u001b[31m          doc:      d.docB64 || null,\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (pResp.ok) { const r=await pResp.json(); if(r.success) {\u001b[39m\n\u001b[31m      photoUrls=r.photoUrls;\u001b[39m\n\u001b[31m      // Merge retained existing URLs for edit re-submits\u001b[39m\n\u001b[31m      if (entry.editedAt) {\u001b[39m\n\u001b[31m        photoUrls.front    =(photoUrls.front   ||[]).map((u,i)=>u||(d.frontPhotos  ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.inside   =(photoUrls.inside  ||[]).map((u,i)=>u||(d.insidePhotos ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.addl     =(photoUrls.addl    ||[]).map((u,i)=>u||(d.addlPhotos   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.brandings=(photoUrls.brandings||[]).map((u,i)=>u||(d.brandings   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        if(!photoUrls.doc) photoUrls.doc=d._docExistingUrl||null;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }}\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-photos] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 1.5 — trigger Google Slides via proxy using permanent photo URLs (fire-and-forget)\u001b[39m\n\u001b[31m  (async()=>{try{\u001b[39m\n\u001b[31m    const _hasPh=(photoUrls.front||[]).some(Boolean)||(photoUrls.inside||[]).some(Boolean)||(photoUrls.brandings||[]).some(Boolean);\u001b[39m\n\u001b[31m    if(!_hasPh)return;\u001b[39m\n\u001b[31m    const _gu=(await cfg('slides-gas-url'))||(await cfg('gas-url'))||DEFAULT_GAS_URL;if(!_gu)return;\u001b[39m\n\u001b[31m    await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({\u001b[39m\n\u001b[31m      type:'make-slides',gasUrl:_gu,subId:entry.id,\u001b[39m\n\u001b[31m      storeInfo:{storeName:d.storeName||'',brand:d.brand||'',address:d.address||'',mobile:d.mobile||'',date:d.date||'',city:d.city||'',gpsCoords:d.gpsCoords||null},\u001b[39m\n\u001b[31m      photoGroups:{\u001b[39m\n\u001b[31m        front:    (photoUrls.front   ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.frontPhotos  ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        inside:   (photoUrls.inside  ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.insidePhotos ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        brandings:(photoUrls.brandings||[]).filter(Boolean).map((url,i)=>({url,meta:{type:(d.brandings||[])[i]?.type,w:(d.brandings||[])[i]?.w,h:(d.brandings||[])[i]?.h,qty:(d.brandings||[])[i]?.qty,sqft:(d.brandings||[])[i]?.sqft}})),\u001b[39m\n\u001b[31m        addl:    (photoUrls.addl    ||[]).filter(Boolean).map((url,i)=>({url,desc:(d.addlPhotos  ||[])[i]?.desc||''})),\u001b[39m\n\u001b[31m      },\u001b[39m\n\u001b[31m    })});\u001b[39m\n\u001b[31m    entry.gasAt=new Date().toISOString();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[recce-slides]',e.message);}}\u001b[39m\n\u001b[31m  )();·\u001b[39m\n\u001b[31m  // Step 2 — generate rich HTML report using server URLs, save to VPS\u001b[39m\n\u001b[31m  let view_url = null;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const html  = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m    const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-view', subId: entry.id, html })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (vResp.ok) { const r=await vResp.json(); if(r.success) view_url=r.url; }\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-view] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 3 — upsert to PostgreSQL with photo URLs + view URL\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch(`${_RC_BASE}/submissions`, {\u001b[39m\n\u001b[31m      method: 'POST', headers: _RC_UPSERT,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        sub_id:         entry.id,\u001b[39m\n\u001b[31m        store_name:     d.storeName    || 'Unknown',\u001b[39m\n\u001b[31m        brand:          d.brand        || null,\u001b[39m\n\u001b[31m        client_name:    d.clientName   || null,\u001b[39m\n\u001b[31m        visit_date:     d.date         || new Date().toISOString().slice(0,10),\u001b[39m\n\u001b[31m        address:        d.address      || null,\u001b[39m\n\u001b[31m        mobile:         d.mobile       || null,\u001b[39m\n\u001b[31m        city:           d.city         || null,\u001b[39m\n\u001b[31m        has_branding:   !!(d.brandings?.length),\u001b[39m\n\u001b[31m        branding_count: d.brandings?.length || 0,\u001b[39m\n\u001b[31m        has_video:      !!d.hasVideo,\u001b[39m\n\u001b[31m        front_photos:   d.frontPhotos?.length  || 0,\u001b[39m\n\u001b[31m        inside_photos:  d.insidePhotos?.length || 0,\u001b[39m\n\u001b[31m        addl_photos:    d.addlPhotos?.length   || 0,\u001b[39m\n\u001b[31m        gps_lat:        d.gpsCoords?.lat       || null,\u001b[39m\n\u001b[31m        gps_lng:        d.gpsCoords?.lng       || null,\u001b[39m\n\u001b[31m        submitted_by:   hub.empId              || null,\u001b[39m\n\u001b[31m        submitted_at:   entry.timestamp,\u001b[39m\n\u001b[31m        campaign_id:    entry.campaignId       || null,\u001b[39m\n\u001b[31m        photo_urls:     photoUrls,\u001b[39m\n\u001b[31m        view_url,\u001b[39m\n\u001b[31m        meta: {\u001b[39m\n\u001b[31m          brandings: (d.brandings||[]).map(b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft})),\u001b[39m\n\u001b[31m          videoNote: d.videoNote || null,\u001b[39m\n\u001b[31m          videoCmt:  d.videoCmt  || null,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        status: 'submitted',\u001b[39m\n\u001b[31m        edit_assigned_to: null,\u001b[39m\n\u001b[31m        edit_comment: null,\u001b[39m\n\u001b[31m        edited_at: entry.editedAt || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    return { ok: true, viewUrl: view_url };\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    console.warn('[recce-db] sync error:', e.message);\u001b[39m\n\u001b[31m    return { ok: false, viewUrl: null };\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mconst DEFAULT_ADMIN_HASH='42d372e6110bee134990ac6881c3d5eb568482008add9a859f37f10d759430e8';·\u001b[39m\n\u001b[31masync function saveGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('gas-url',url||DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  toast('Endpoint saved','success');\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function testEndpoint(){\u001b[39m\n\u001b[31m  const url=(await cfg('gas-url'))||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  try{await fetch(url,{method:'POST',mode:'no-cors',body:JSON.stringify({test:true})});toast('Endpoint reachable ✓','success');}\u001b[39m\n\u001b[31m  catch{toast('Cannot reach endpoint','error')}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  cfg('gas-url').then(url=>{\u001b[39m\n\u001b[31m    const u=url||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    // Show last 30 chars only for privacy\u001b[39m\n\u001b[31m    el.textContent='Endpoint: …'+u.slice(-30);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── SLIDES GAS URL ────────────────────────────────────────────\u001b[39m\n\u001b[31masync function saveSlidesGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('slides-gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('slides-gas-url', url);\u001b[39m\n\u001b[31m  toast('Slides GAS URL saved','success');\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function updateSlidesGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('slides-gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  const u=await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  el.textContent=u?'Configured: …'+u.slice(-30):'Not configured';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── MAKE SLIDES ───────────────────────────────────────────────\u001b[39m\n\u001b[31masync function makeSlides(id){\u001b[39m\n\u001b[31m  const gasUrl = await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  if(!gasUrl){\u001b[39m\n\u001b[31m    toast('Configure Slides GAS URL in Settings first','error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const entry = await dbGet('subs', id);\u001b[39m\n\u001b[31m  if(!entry){ toast('Entry not found','error'); return; }\u001b[39m\n\u001b[31m  const d = entry.data;·\u001b[39m\n\u001b[31m  toast('Uploading photos & generating slides…','info');·\u001b[39m\n\u001b[31m  // Build photo groups payload\u001b[39m\n\u001b[31m  const photoGroups = {\u001b[39m\n\u001b[31m    front:    (d.frontPhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64, cmt:p.desc||''})),\u001b[39m\n\u001b[31m    brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||'', meta:{type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft}})),\u001b[39m\n\u001b[31m  };·\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type:       'recce',\u001b[39m\n\u001b[31m        subId:      id,\u001b[39m\n\u001b[31m        gasUrl:     gasUrl,\u001b[39m\n\u001b[31m        storeInfo:  {\u001b[39m\n\u001b[31m          storeName: d.storeName, brand: d.brand,\u001b[39m\n\u001b[31m          date: d.date, address: d.address,\u001b[39m\n\u001b[31m          mobile: d.mobile, gpsCoords: d.gpsCoords,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        photoGroups,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const result = await resp.json();\u001b[39m\n\u001b[31m    if(result.success && result.slideUrl){\u001b[39m\n\u001b[31m      // Store slide URL on the entry\u001b[39m\n\u001b[31m      entry.slideUrl = result.slideUrl;\u001b[39m\n\u001b[31m      await dbPut('subs', entry);\u001b[39m\n\u001b[31m      toast('✅ Slides ready!','success');\u001b[39m\n\u001b[31m      window.open(result.slideUrl, '_blank');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast('Slides error: '+(result.error||'Unknown'),'error');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e){\u001b[39m\n\u001b[31m    toast('Network error: '+e.message,'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN LOGIN ──────────────────────────────────────────────\u001b[39m\n\u001b[31mfunction showAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-error').style.display='none';\u001b[39m\n\u001b[31m  // Restore saved config URL\u001b[39m\n\u001b[31m  cfg('admin-cfg-url').then(u=>{if(u&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=u;});\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('admin-pwd').focus(),100);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveAdminCfgUrl(){\u001b[39m\n\u001b[31m  // Admin cfg URL can be saved without login (needed to set up auth itself)\u001b[39m\n\u001b[31m  // But we warn if saving while unlocked only\u001b[39m\n\u001b[31m  const url=document.getElementById('admin-cfg-url').value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  await cfg('admin-cfg-url',url);\u001b[39m\n\u001b[31m  toast('Config URL saved — will use on next login attempt','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function verifyAdmin(){\u001b[39m\n\u001b[31m  // Hub admins (harish/pramod) are auto-unlocked — no password needed\u001b[39m\n\u001b[31m  if (_adminUnlocked) { adminLoginSuccess(); return; }\u001b[39m\n\u001b[31m  const pwd=document.getElementById('admin-pwd').value;\u001b[39m\n\u001b[31m  if(!pwd){document.getElementById('admin-error').style.display='block';document.getElementById('admin-error').textContent='Enter password';return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('admin-login-btn');btn.disabled=true;btn.textContent='Verifying…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // Try server verification first\u001b[39m\n\u001b[31m    const cfgUrl=(await cfg('admin-cfg-url'))||'';\u001b[39m\n\u001b[31m    if(cfgUrl){\u001b[39m\n\u001b[31m      const r=await fetch(cfgUrl,{cache:'no-store'});\u001b[39m\n\u001b[31m      const j=await r.json();\u001b[39m\n\u001b[31m      // Server JSON format: {\\\"password\\\":\\\"plaintext\\\"} or {\\\"hash\\\":\\\"sha256hash\\\"}\u001b[39m\n\u001b[31m      let match=false;\u001b[39m\n\u001b[31m      if(j.password){match=(j.password===pwd);}\u001b[39m\n\u001b[31m      else if(j.hash){\u001b[39m\n\u001b[31m        // SHA-256 comparison\u001b[39m\n\u001b[31m        const enc=new TextEncoder();\u001b[39m\n\u001b[31m        const data=enc.encode(pwd);\u001b[39m\n\u001b[31m        const hashBuf=await crypto.subtle.digest('SHA-256',data);\u001b[39m\n\u001b[31m        const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m        match=(hashHex===j.hash);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      if(match){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m      else{showAdminError('Incorrect password');return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Fallback: local password stored in settings\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if(localHash){\u001b[39m\n\u001b[31m      const enc=new TextEncoder();\u001b[39m\n\u001b[31m      const hashBuf=await crypto.subtle.digest('SHA-256',enc.encode(pwd));\u001b[39m\n\u001b[31m      const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m      if(hashHex===localHash){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Final fallback: check against hardcoded default hash\u001b[39m\n\u001b[31m    const enc2=new TextEncoder();\u001b[39m\n\u001b[31m    const hb2=await crypto.subtle.digest('SHA-256',enc2.encode(pwd));\u001b[39m\n\u001b[31m    const hh2=Array.from(new Uint8Array(hb2)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    if(hh2===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }catch(err){\u001b[39m\n\u001b[31m    // Network error — try all local fallbacks\u001b[39m\n\u001b[31m    const enc3=new TextEncoder();\u001b[39m\n\u001b[31m    const hb3=await crypto.subtle.digest('SHA-256',enc3.encode(pwd));\u001b[39m\n\u001b[31m    const hh3=Array.from(new Uint8Array(hb3)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if((localHash&&hh3===localHash)||hh3===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }finally{btn.disabled=false;btn.textContent='Login';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showAdminError(msg){\u001b[39m\n\u001b[31m  const el=document.getElementById('admin-error');\u001b[39m\n\u001b[31m  el.textContent=msg;el.style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminLoginSuccess(){\u001b[39m\n\u001b[31m  _adminUnlocked=true;\u001b[39m\n\u001b[31m  closeAdminLogin();\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  cfg('gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  cfg('slides-gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('slides-gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||'';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  toast('Admin mode unlocked','success');\u001b[39m\n\u001b[31m  setTimeout(lockAdmin,10*60*1000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction lockAdmin(){\u001b[39m\n\u001b[31m  _adminUnlocked=false;\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  toast('Admin session ended','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updAvailTag(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-avail-tag');\u001b[39m\n\u001b[31m  const ct=document.getElementById('store-avail-count');\u001b[39m\n\u001b[31m  const txt=stores.length?`${stores.length} stores`:'No store list';\u001b[39m\n\u001b[31m  if(el)el.textContent=txt;\u001b[39m\n\u001b[31m  if(ct)ct.textContent=stores.length?t(`${stores.length} stores available — tap to browse`,`${stores.length} स्टोर उपलब्ध — दबाएं`):t('No store list loaded yet','कोई स्टोर सूची नहीं');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PICKER\u001b[39m\n\u001b[31mfunction openPicker(){\u001b[39m\n\u001b[31m  if(!stores.length){toast('Load a store list in Settings first','error');return;}\u001b[39m\n\u001b[31m  document.getElementById('povl').classList.add('open');\u001b[39m\n\u001b[31m  document.getElementById('psearch').value='';\u001b[39m\n\u001b[31m  filterPicker('');\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('psearch').focus(),150);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closePicker(){document.getElementById('povl').classList.remove('open');}\u001b[39m\n\u001b[31masync function filterPicker(q){\u001b[39m\n\u001b[31m  const list=document.getElementById('plist');\u001b[39m\n\u001b[31m  const words=q.toLowerCase().trim().split(/\\\\s+/).filter(Boolean);\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const lastVisit={};\u001b[39m\n\u001b[31m  subs.forEach(s=>{const nm=s.data?.storeName;if(nm&&(!lastVisit[nm]||s.timestamp>lastVisit[nm]))lastVisit[nm]=s.timestamp;});·\u001b[39m\n\u001b[31m  // Multi-word: ALL words must match somewhere in any field (search across both English and Hindi)\u001b[39m\n\u001b[31m  let fl=stores.filter(s=>{\u001b[39m\n\u001b[31m    if(!words.length)return true;\u001b[39m\n\u001b[31m    const hay=[s.name,s.nameHi,s.address,s.addressHi,s.mobile,s.city,s.cityHi,s.distName,s.distNameHi,s.brand,s.sales,s.proj,s.glowSign,s.inshop]\u001b[39m\n\u001b[31m               .map(x=>(x||'').toLowerCase()).join(' ');\u001b[39m\n\u001b[31m    return words.every(w=>hay.includes(w));\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(fl.length>100)fl=fl.slice(0,100);·\u001b[39m\n\u001b[31m  if(!fl.length){\u001b[39m\n\u001b[31m    const esc=q.replace(/'/g,\\\"\\\\\\\\'\\\");\u001b[39m\n\u001b[31m    list.innerHTML=`<div style=\\\"text-align:center;padding:32px 16px;color:var(--g400);font-size:14px\\\">No stores match \\\"${q}\\\"<br><span style=\\\"font-size:12px\\\">Try fewer or different words</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('${esc}')\\\">+ Add \\\"${q}\\\" as new store</div>`;\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Group by brand (including empty brand)\u001b[39m\n\u001b[31m  const g={};\u001b[39m\n\u001b[31m  fl.forEach(s=>{\u001b[39m\n\u001b[31m    const b=s.brand||'(No Brand — will ask)';\u001b[39m\n\u001b[31m    if(!g[b])g[b]=[];\u001b[39m\n\u001b[31m    g[b].push(s);\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html='';\u001b[39m\n\u001b[31m  Object.keys(g).sort().forEach(br=>{\u001b[39m\n\u001b[31m    html+=`<div class=\\\"psec\\\">${br}</div>`;\u001b[39m\n\u001b[31m    g[br].forEach(s=>{\u001b[39m\n\u001b[31m      const lv=lastVisit[s.name];\u001b[39m\n\u001b[31m      const lvStr=lv?`🕐 Last: ${new Date(lv).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'2-digit'})}`:'';\u001b[39m\n\u001b[31m      const chips=[];\u001b[39m\n\u001b[31m      if(s.glowSign&&s.glowSign.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dcfce7;color:#14532d;padding:2px 6px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m      if(s.inshop&&s.inshop.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dbeafe;color:#1e40af;padding:2px 6px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m      if(s.proj)chips.push(`<span style=\\\"font-size:10px;background:var(--g100);color:var(--g600);padding:2px 6px;border-radius:10px\\\">Target: ${s.proj}</span>`);\u001b[39m\n\u001b[31m      const enc=JSON.stringify(s).replace(/\\\"/g,'&quot;');\u001b[39m\n\u001b[31m      const mapsUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m      const waUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const telUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const dispName=LANG==='hi'&&s.nameHi?s.nameHi:s.name;\u001b[39m\n\u001b[31m      const dispAddr=LANG==='hi'&&s.addressHi?s.addressHi:s.address;\u001b[39m\n\u001b[31m      const dispDist=LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m      html+=`<div class=\\\"pitem\\\" onclick=\\\"pickStore(${enc})\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"pi-name\\\">${dispName}</div>\u001b[39m\n\u001b[31m          ${dispAddr?`<div class=\\\"pi-addr\\\">📍 ${dispAddr}</div>`:''}\u001b[39m\n\u001b[31m          ${s.mobile?`<div class=\\\"pi-addr\\\">📞 ${s.mobile}</div>`:''}\u001b[39m\n\u001b[31m          ${dispDist?`<div class=\\\"pi-addr\\\" style=\\\"color:var(--am)\\\">👤 ${dispDist}</div>`:''}\u001b[39m\n\u001b[31m          ${lvStr?`<div class=\\\"pi-last\\\">${lvStr}</div>`:''}\u001b[39m\n\u001b[31m          ${chips.length?`<div style=\\\"display:flex;gap:4px;flex-wrap:wrap;margin-top:4px\\\">${chips.join('')}</div>`:''}\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;gap:6px;margin-top:7px\\\" onclick=\\\"event.stopPropagation()\\\">\u001b[39m\n\u001b[31m            ${mapsUrl?`<a href=\\\"${mapsUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#e0f2fe;color:#0369a1;border-radius:20px;text-decoration:none;font-weight:600\\\">🗺 Maps</a>`:''}\u001b[39m\n\u001b[31m            ${waUrl?`<a href=\\\"${waUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#dcfce7;color:#15803d;border-radius:20px;text-decoration:none;font-weight:600\\\">💬 WhatsApp</a>`:''}\u001b[39m\n\u001b[31m            ${telUrl?`<a href=\\\"${telUrl}\\\" style=\\\"font-size:11px;padding:4px 10px;background:#f0fdf4;color:#166534;border-radius:20px;text-decoration:none;font-weight:600\\\">📞 Call</a>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        ${s.brand?`<div class=\\\"pi-brand\\\">${s.brand}</div>`:'<div class=\\\"pi-brand\\\" style=\\\"background:var(--rd)\\\">?</div>'}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html+=`<div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('')\\\">+ Not in list? Add new store</div>`;\u001b[39m\n\u001b[31m  list.innerHTML=html;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function pickStore(s){\u001b[39m\n\u001b[31m  selectedStore=s;manualMode=false;closePicker();\u001b[39m\n\u001b[31m  const _dn =LANG==='hi'&&s.nameHi    ?s.nameHi    :s.name;\u001b[39m\n\u001b[31m  const _da =LANG==='hi'&&s.addressHi ?s.addressHi :s.address;\u001b[39m\n\u001b[31m  const _dd =LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m  const _dc =LANG==='hi'&&s.cityHi    ?s.cityHi    :s.city;\u001b[39m\n\u001b[31m  document.getElementById('sc-name').textContent=_dn;\u001b[39m\n\u001b[31m  const brandEl=document.getElementById('sc-brand');\u001b[39m\n\u001b[31m  brandEl.textContent=s.brand||'No Brand';brandEl.style.background=s.brand?'var(--nv)':'var(--rd)';\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const prev=subs.filter(x=>x.data?.storeName===s.name).sort((a,b)=>new Date(b.timestamp)-new Date(a.timestamp))[0];\u001b[39m\n\u001b[31m  const lc=document.getElementById('sc-last');\u001b[39m\n\u001b[31m  if(prev){const d=new Date(prev.timestamp);lc.textContent='Last: '+d.toLocaleDateString('en-IN',{day:'numeric',month:'short'});lc.style.display='inline-flex';}\u001b[39m\n\u001b[31m  else lc.style.display='none';\u001b[39m\n\u001b[31m  // All Excel fields — display in active language\u001b[39m\n\u001b[31m  const mUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m  const wUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const tUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const details=[];\u001b[39m\n\u001b[31m  if(_da)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📍 ${_da}${mUrl?` <a href=\\\"${mUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#0369a1;margin-left:6px\\\">🗺 Navigate</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(s.mobile)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📞 ${s.mobile}${tUrl?` <a href=\\\"${tUrl}\\\" style=\\\"font-size:11px;color:#166534;margin-left:6px\\\">Call</a>`:''}${wUrl?` <a href=\\\"${wUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#15803d;margin-left:6px\\\">WhatsApp</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(_dd)details.push(`<div style=\\\"font-size:12px;color:var(--am)\\\">👤 ${_dd}</div>`);\u001b[39m\n\u001b[31m  if(_dc)details.push(`<div style=\\\"font-size:12px;color:var(--g500)\\\">🏙 ${_dc}</div>`);\u001b[39m\n\u001b[31m  const opp=[];\u001b[39m\n\u001b[31m  if(s.glowSign&&s.glowSign.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dcfce7;color:#14532d;padding:2px 7px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m  if(s.inshop&&s.inshop.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dbeafe;color:#1e40af;padding:2px 7px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m  if(s.proj)opp.push(`<span style=\\\"font-size:11px;background:var(--g100);color:var(--g600);padding:2px 7px;border-radius:10px\\\">Target 2026: ${s.proj}</span>`);\u001b[39m\n\u001b[31m  if(opp.length)details.push(`<div style=\\\"display:flex;gap:5px;flex-wrap:wrap;margin-top:3px\\\">${opp.join('')}</div>`);\u001b[39m\n\u001b[31m  document.getElementById('sc-details').innerHTML=details.join('');\u001b[39m\n\u001b[31m  // Missing fields\u001b[39m\n\u001b[31m  const missing=[];\u001b[39m\n\u001b[31m  if(!s.address)missing.push({key:'address',label:'Store Address',type:'textarea',placeholder:'Full address'});\u001b[39m\n\u001b[31m  if(!s.mobile)missing.push({key:'mobile',label:'Mobile No.',type:'tel',placeholder:'10-digit number',maxlen:'10'});\u001b[39m\n\u001b[31m  const mw=document.getElementById('sc-missing'),mf=document.getElementById('sc-missing-fields');\u001b[39m\n\u001b[31m  if(missing.length){\u001b[39m\n\u001b[31m    mf.innerHTML=missing.map(m=>`<div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\"><label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">${m.label} <span class=\\\"req\\\">*</span></label>${m.type==='textarea'?`<textarea id=\\\"sc-miss-${m.key}\\\" rows=\\\"2\\\" placeholder=\\\"${m.placeholder}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></textarea>`:`<input type=\\\"${m.type}\\\" id=\\\"sc-miss-${m.key}\\\" placeholder=\\\"${m.placeholder}\\\" ${m.maxlen?`maxlength=\\\"${m.maxlen}\\\"`:''}  inputmode=\\\"${m.type==='tel'?'numeric':'text'}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\">`}</div>`).join('');\u001b[39m\n\u001b[31m    mw.style.display='block';\u001b[39m\n\u001b[31m  } else {mw.style.display='none';}\u001b[39m\n\u001b[31m  // Brand selector\u001b[39m\n\u001b[31m  const bSel=document.getElementById('brand-selector'),bChips=document.getElementById('brand-chips');\u001b[39m\n\u001b[31m  if(!s.brand){\u001b[39m\n\u001b[31m    renderBrandChips();\u001b[39m\n\u001b[31m    bSel.style.display='block';\u001b[39m\n\u001b[31m  } else {bSel.style.display='none';}\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  F.storeName=s.name;F.brand=s.brand||'';F.address=s.address||'';F.mobile=s.mobile||'';\u001b[39m\n\u001b[31m  if(s.brand&&!_selectedClient&&!_clientOtherMode) autoSetClient(s.brand);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateMissingField(key,val){if(!selectedStore)return;selectedStore[key]=val.trim();F[key]=val.trim();saveDraft();}\u001b[39m\n\u001b[31mfunction selectStoreBrand(b){\u001b[39m\n\u001b[31m  F.brand=b;F.brandLogoUrl=_brandLogos[b]||'';\u001b[39m\n\u001b[31m  if(selectedStore)selectedStore.brand=b;\u001b[39m\n\u001b[31m  const el=document.getElementById('sc-brand');if(el){el.textContent=b;el.style.background='var(--nv)';}\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-chips .chip').forEach(c=>{c.classList.toggle('sel',c.querySelector('span')?.textContent===b||c.textContent.trim()===b);});\u001b[39m\n\u001b[31m  if(!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction onManualBrandChange(){\u001b[39m\n\u001b[31m  const b=document.getElementById('f-brand')?.value||'';\u001b[39m\n\u001b[31m  F.brandLogoUrl=b?(_brandLogos[b]||''):'';\u001b[39m\n\u001b[31m  if(b&&!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction openManual(prefill){\u001b[39m\n\u001b[31m  manualMode=true;\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').classList.add('on');\u001b[39m\n\u001b[31m  document.getElementById('mt-label').innerHTML='← Back to store list';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='block';\u001b[39m\n\u001b[31m  // Pre-fill from selectedStore if available (e.g. when toggling after picker selection)\u001b[39m\n\u001b[31m  const s=selectedStore;\u001b[39m\n\u001b[31m  if(s){\u001b[39m\n\u001b[31m    if(document.getElementById('f-brand'))document.getElementById('f-brand').value=s.brand||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-store'))document.getElementById('f-store').value=s.name||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-addr'))document.getElementById('f-addr').value=s.address||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-mobile'))document.getElementById('f-mobile').value=s.mobile||'';\u001b[39m\n\u001b[31m  } else if(prefill){\u001b[39m\n\u001b[31m    document.getElementById('f-store').value=prefill;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  selectedStore=null;\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction toggleManual(){\u001b[39m\n\u001b[31m  if(manualMode){\u001b[39m\n\u001b[31m    manualMode=false;\u001b[39m\n\u001b[31m    document.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31m    document.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31m    document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    openManual('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// GPS\u001b[39m\n\u001b[31mfunction captureGPS(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gps-status');el.textContent='Getting location…';el.style.color='var(--g500)';\u001b[39m\n\u001b[31m  if(!navigator.geolocation){el.textContent='GPS not available';return;}\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(pos=>{\u001b[39m\n\u001b[31m    gpsCoords={lat:pos.coords.latitude.toFixed(6),lng:pos.coords.longitude.toFixed(6),acc:Math.round(pos.coords.accuracy)};\u001b[39m\n\u001b[31m    el.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${gpsCoords.acc}m)`;el.style.color='var(--gn)';saveDraft();\u001b[39m\n\u001b[31m  },()=>{el.textContent='GPS failed — enter address manually';el.style.color='var(--rd)';},{enableHighAccuracy:true,timeout:10000});\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// DRAFT\u001b[39m\n\u001b[31mlet draftT;\u001b[39m\n\u001b[31mfunction saveDraft(){\u001b[39m\n\u001b[31m  clearTimeout(draftT);\u001b[39m\n\u001b[31m  draftT=setTimeout(async()=>{\u001b[39m\n\u001b[31m    const draft={k:'current',ts:Date.now(),F:{...F,date:document.getElementById('f-date')?.value||'',brand:manualMode?(document.getElementById('f-brand')?.value||''):(selectedStore?.brand||F.brand||''),storeName:selectedStore?selectedStore.name:(document.getElementById('f-store')?.value||''),address:manualMode?(document.getElementById('f-addr')?.value||''):(selectedStore?.address||F.address||''),mobile:manualMode?(document.getElementById('f-mobile')?.value||''):(selectedStore?.mobile||F.mobile||''),clientName:getClientName()},selectedStore,manualMode,gpsCoords,_selectedClient,_clientOtherMode,fCnt:frontPhotos.length,iCnt:insidePhotos.length,bCnt:brandings.length};\u001b[39m\n\u001b[31m    await dbPut('draft',draft);\u001b[39m\n\u001b[31m    // Also save photos as b64 blobs to draft so they survive exit\u001b[39m\n\u001b[31m    await saveDraftPhotos();\u001b[39m\n\u001b[31m  },500);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveDraftPhotos(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const photoData={\u001b[39m\n\u001b[31m      front:await Promise.all(frontPhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      inside:await Promise.all(insidePhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      addl:await Promise.all(addlPhotos.map(async p=>({b64:await b64(p.blob),desc:p.desc||''}))),\u001b[39m\n\u001b[31m      brand:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,b64:b.blob?await b64(b.blob):null})))\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    await dbPut('draft',{k:'photos',...photoData});\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function checkDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');const wrap=document.getElementById('resume-wrap');\u001b[39m\n\u001b[31m  if(!d||!d.F?.storeName){wrap.innerHTML='';return;}\u001b[39m\n\u001b[31m  const ago=Math.round((Date.now()-d.ts)/60000);\u001b[39m\n\u001b[31m  const agoStr=ago<1?'just now':ago<60?`${ago}m ago`:`${Math.round(ago/60)}h ago`;\u001b[39m\n\u001b[31m  wrap.innerHTML=`<button class=\\\"resume-btn\\\" onclick=\\\"resumeDraft()\\\">\u001b[39m\n\u001b[31m    <div><div style=\\\"font-size:12px;color:rgba(255,255,255,.5);margin-bottom:3px\\\">Resume draft · ${agoStr}</div><div>${d.F.storeName} · ${d.F.brand||'No brand'}</div></div>\u001b[39m\n\u001b[31m    <div style=\\\"text-align:right\\\"><div style=\\\"font-size:13px;color:var(--or)\\\">${d.fCnt||0} photos · ${d.bCnt||0} brandings →</div></div>\u001b[39m\n\u001b[31m  </button>`;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function resumeDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');if(!d)return;\u001b[39m\n\u001b[31m  F=d.F||{};gpsCoords=d.gpsCoords||null;\u001b[39m\n\u001b[31m  if(d.selectedStore){await pickStore(d.selectedStore);}\u001b[39m\n\u001b[31m  else if(d.manualMode){openManual('');if(F.brand)document.getElementById('f-brand').value=F.brand;if(F.storeName)document.getElementById('f-store').value=F.storeName;if(F.address)document.getElementById('f-addr').value=F.address;if(F.mobile)document.getElementById('f-mobile').value=F.mobile;}\u001b[39m\n\u001b[31m  if(F.date)document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  // Restore client chip state\u001b[39m\n\u001b[31m  if(d._clientOtherMode){_clientOtherMode=true;_selectedClient='';const inp=document.getElementById('f-client-other');if(inp&&F.clientName)inp.value=F.clientName;}\u001b[39m\n\u001b[31m  else if(d._selectedClient){_selectedClient=d._selectedClient;_clientOtherMode=false;}\u001b[39m\n\u001b[31m  else if(F.clientName){autoSetClient(F.clientName);}\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  // Restore photos from draft\u001b[39m\n\u001b[31m  const pd=await dbGet('draft','photos');\u001b[39m\n\u001b[31m  if(pd){\u001b[39m\n\u001b[31m    async function b64ToBlob(b64str){if(!b64str)return null;try{const r=await fetch(b64str);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m    for(const p of(pd.front||[])){const bl=await b64ToBlob(p.b64);if(bl)frontPhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.inside||[])){const bl=await b64ToBlob(p.b64);if(bl)insidePhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.addl||[])){const bl=await b64ToBlob(p.b64);if(bl)addlPhotos.push({blob:bl,prev:URL.createObjectURL(bl),desc:p.desc||''});}\u001b[39m\n\u001b[31m    for(const b of(pd.brand||[])){const bl=await b64ToBlob(b.b64);brandings.push({type:b.type,w:b.w,h:b.h,qty:b.qty,blob:bl,prev:bl?URL.createObjectURL(bl):null});}\u001b[39m\n\u001b[31m    toast('Draft restored with '+frontPhotos.length+' photos ✓','success');\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    toast('Draft restored — photos could not be recovered','info');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PHOTOS\u001b[39m\n\u001b[31mfunction updPhotoBadge(type){const arr=type==='front'?frontPhotos:insidePhotos;const el=document.getElementById(type+'-badge');if(el){el.textContent=arr.length;el.className='cnt-badge '+(arr.length?'':'gray');}}\u001b[39m\n\u001b[31mfunction renderPhotos(type){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  const cont=document.getElementById(type+'-cont');const addBtn=document.getElementById('add-'+type);\u001b[39m\n\u001b[31m  updPhotoBadge(type);\u001b[39m\n\u001b[31m  if(arr.length===0){cont.innerHTML=`<div class=\\\"pslot\\\" onclick=\\\"addPhoto('${type}')\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to capture or upload</span><span class=\\\"hi-txt\\\">फोटो खींचें या अपलोड करें</span></div></div>`;addBtn.style.display='none';return;}\u001b[39m\n\u001b[31m  cont.innerHTML=arr.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const badge=isRetained?`<span class=\\\"pbadge\\\" style=\\\"background:#475569\\\">Existing</span>`:`<span class=\\\"pbadge\\\">${fmtSz(p.blob.size)}</span>`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replacePhoto('${type}',${i})\\\" style=\\\"right:36px;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"margin-bottom:12px\\\"><div class=\\\"pslot filled\\\" style=\\\"margin-bottom:8px\\\"><img src=\\\"${p.prev}\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmPhoto('${type}',${i})\\\">×</button>${badge}</div><input type=\\\"text\\\" placeholder=\\\"Comments (optional)\\\" value=\\\"${p.cmt||''}\\\" onchange=\\\"${type==='front'?'frontPhotos':'insidePhotos'}[${i}].cmt=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  addBtn.style.display=arr.length<(type==='inside'?5:3)?'inline-flex':'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// Photo source: 'camera' stamps geo, 'gallery' does not\u001b[39m\n\u001b[31mlet _photoSourceCb=null,_photoSourceQuality=null;·\u001b[39m\n\u001b[31mfunction capPhoto(cb,forceSource,quality){\u001b[39m\n\u001b[31m  // quality override: null=use setting, 'hd', 'compressed'\u001b[39m\n\u001b[31m  _photoSourceCb=cb;_photoSourceQuality=quality||null;\u001b[39m\n\u001b[31m  if(forceSource==='camera'){_doCapture(cb,'camera',quality);return;}\u001b[39m\n\u001b[31m  if(forceSource==='gallery'){_doCapture(cb,'gallery',quality);return;}\u001b[39m\n\u001b[31m  // Show picker\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _doCapture(cb,src,quality){\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  const i=document.createElement('input');\u001b[39m\n\u001b[31m  i.type='file';i.accept='image/*';\u001b[39m\n\u001b[31m  if(src==='camera')i.setAttribute('capture','environment');\u001b[39m\n\u001b[31m  i.style.display='none';\u001b[39m\n\u001b[31m  i.onchange=async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f)return;\u001b[39m\n\u001b[31m    const q=quality||_photoSourceQuality||null;\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      const blob=await compress(f,q==='hd'?1920:q==='compressed'?1280:null,q==='hd'?0.90:q==='compressed'?0.78:null);\u001b[39m\n\u001b[31m      // Only stamp if from camera (live photo)\u001b[39m\n\u001b[31m      const stamped=(src==='camera')?await stampPhoto(blob):blob;\u001b[39m\n\u001b[31m      // Save to device (auto-download trigger)\u001b[39m\n\u001b[31m      savePhotoToDevice(stamped);\u001b[39m\n\u001b[31m      cb({target:{files:[f]},_blob:stamped,_src:src});\u001b[39m\n\u001b[31m    }catch(err){toast('Photo processing failed — try again','error');console.error('_doCapture error:',err);}\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  document.body.appendChild(i);i.click();setTimeout(()=>i.remove(),8000);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction photoSrcCamera(){_doCapture(_photoSourceCb,'camera',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcGallery(){_doCapture(_photoSourceCb,'gallery',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcCancel(){document.getElementById('photo-src-dialog').classList.remove('open');_photoSourceCb=null;}·\u001b[39m\n\u001b[31m// Save photo to device gallery/downloads\u001b[39m\n\u001b[31mfunction savePhotoToDevice(blob){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    const a=document.createElement('a');\u001b[39m\n\u001b[31m    a.href=url;\u001b[39m\n\u001b[31m    a.download='Recce_'+Date.now()+'.jpg';\u001b[39m\n\u001b[31m    a.style.display='none';\u001b[39m\n\u001b[31m    document.body.appendChild(a);a.click();\u001b[39m\n\u001b[31m    setTimeout(()=>{URL.revokeObjectURL(url);a.remove();},1000);\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addPhoto(type){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}${e._src==='camera'&&geoStampEnabled?' · Stamped':''}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31masync function handleCapture(e,type){\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmPhoto(type,i){(type==='front'?frontPhotos:insidePhotos).splice(i,1);renderPhotos(type);saveDraft();}\u001b[39m\n\u001b[31mfunction replacePhoto(type,idx){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m    arr[idx]={...arr[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAddl(){\u001b[39m\n\u001b[31m  const cont=document.getElementById('add-cont');const btn=document.getElementById('add-addl');\u001b[39m\n\u001b[31m  const badge=document.getElementById('addl-badge');if(badge){badge.textContent=`${addlPhotos.length} / 8`;badge.className='cnt-badge '+(addlPhotos.length?'':'gray');}\u001b[39m\n\u001b[31m  cont.innerHTML=addlPhotos.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const sizeInfo=isRetained?'<span style=\\\"color:#475569\\\">Existing</span>':`${fmtSz(p.blob.size)}`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replaceAddl(${i})\\\" style=\\\"top:3px;left:3px;right:auto;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;gap:10px;align-items:start;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--g100)\\\"><div style=\\\"position:relative;flex-shrink:0\\\"><img src=\\\"${p.prev}\\\" style=\\\"width:80px;height:80px;object-fit:cover;border-radius:var(--rs)\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmAddl(${i})\\\" style=\\\"top:3px;right:3px\\\">×</button></div><div style=\\\"flex:1\\\"><input type=\\\"text\\\" placeholder=\\\"Description (optional)\\\" value=\\\"${p.desc||''}\\\" onchange=\\\"addlPhotos[${i}].desc=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"><div style=\\\"font-size:11px;color:var(--g400);margin-top:4px\\\">${sizeInfo}</div></div></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  btn.style.display=addlPhotos.length>=8?'none':'inline-flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction addAdditional(){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  addlPhotos.push({blob:bs,prev:URL.createObjectURL(bs),desc:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderAddl();saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31mfunction rmAddl(i){addlPhotos.splice(i,1);renderAddl();saveDraft();}\u001b[39m\n\u001b[31mfunction replaceAddl(idx){\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m    addlPhotos[idx]={...addlPhotos[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderAddl();saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// BRANDING\u001b[39m\n\u001b[31mfunction calcSqft(w,h){const wf=parseFloat(w),hf=parseFloat(h);if(!wf||!hf)return '';return `${(wf*hf).toFixed(0)} sq.in = ${(wf*hf/144).toFixed(2)} sq.ft`;}\u001b[39m\n\u001b[31mfunction renderBrandings(){\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  const cont=document.getElementById('br-items');\u001b[39m\n\u001b[31m  const hb=document.getElementById('br-hdr-badge');if(hb)hb.textContent=`${brandings.length} ${t(brandings.length!==1?'items':'item',brandings.length!==1?'आइटम':'आइटम')}`;\u001b[39m\n\u001b[31m  cont.innerHTML=brandings.map((b,i)=>`<div class=\\\"bitem\\\"><div class=\\\"bitem-hdr\\\"><div class=\\\"bitem-title\\\">${t('Branding','ब्रांडिंग')} ${i+1}${b.type?' — '+b.type:''}</div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:6px\\\">${i>0?`<button class=\\\"btn-d\\\" onclick=\\\"dupBr(${i})\\\" style=\\\"color:var(--or);border-color:var(--orl)\\\">${t('Dup ↑','डुप ↑')}</button>`:''}<button class=\\\"btn-d\\\" onclick=\\\"rmBr(${i})\\\">${t('Remove','हटाएं')}</button></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\"><label>${t('Type','प्रकार')} <span class=\\\"req\\\">*</span></label><div class=\\\"chip-grid\\\">${BTYPE.map(tp=>`<div class=\\\"chip${b.type===tp?' sel':''}\\\" onclick=\\\"setBType(${i},'${tp.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\"> ${tp}</div>`).join('')}</div></div>\u001b[39m\n\u001b[31m    <div class=\\\"dim-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Width (in)','चौड़ाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.w||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].w=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Height (in)','ऊंचाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.h||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].h=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"max-width:74px\\\"><label>${t('Qty','मात्रा')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.qty||''}\\\" placeholder=\\\"1\\\" inputmode=\\\"numeric\\\" onchange=\\\"brandings[${i}].qty=this.value;saveDraft()\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <span class=\\\"sqft\\\" id=\\\"sf${i}\\\">${calcSqft(b.w,b.h)||t('Enter W × H','W × H दर्ज करें')}</span>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-top:12px\\\"><label>${t('Photo','फोटो')} <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      ${b.prev?`<div class=\\\"pslot filled\\\" onclick=\\\"capBr(${i})\\\"><img src=\\\"${b.prev}\\\"><button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();rmBrPh(${i})\\\">×</button><span class=\\\"pbadge\\\">${b.blob?fmtSz(b.blob.size):'Existing'}</span></div>`:`<div><div class=\\\"pslot\\\" onclick=\\\"capBr(${i})\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\">${t('Tap to capture','दबाकर कैप्चर करें')}</div></div><div style=\\\"display:flex;gap:6px;margin-top:6px\\\"><button class=\\\"atool${(b.quality||imgQuality)==='compressed'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'compressed');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">${t('Compressed','कम्प्रेस्ड')}</button><button class=\\\"atool${(b.quality||imgQuality)==='hd'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'hd');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">HD</button></div></div>`}\u001b[39m\n\u001b[31m    </div></div>`).join('');\u001b[39m\n\u001b[31m  // Only show \\\"Add Another\\\" when last item is fully complete\u001b[39m\n\u001b[31m  const addDiv=document.getElementById('br-add');\u001b[39m\n\u001b[31m  if(addDiv&&brandings.length>0){\u001b[39m\n\u001b[31m    const last=brandings[brandings.length-1];\u001b[39m\n\u001b[31m    const lastComplete=last.type&&last.w&&last.h&&last.qty&&last.prev;\u001b[39m\n\u001b[31m    addDiv.style.display=(lastComplete&&brandings.length<15)?'block':'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updSqft(i){const el=document.getElementById('sf'+i);if(el)el.textContent=calcSqft(brandings[i].w,brandings[i].h)||t('Enter W × H','W × H दर्ज करें');saveDraft();}\u001b[39m\n\u001b[31mfunction setBType(i,tp){brandings[i].type=tp;renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction addBranding(){if(brandings.length>=15){toast(t('Max 15 items','अधिकतम 15 आइटम'),'error');return;}brandings.push({type:'',w:'',h:'',qty:'1',blob:null,prev:null});renderBrandings();}\u001b[39m\n\u001b[31mfunction dupBr(i){if(brandings.length>=10){toast(t('Max 10 items','अधिकतम 10 आइटम'),'error');return;}const s=brandings[i-1];brandings.splice(i,0,{type:s.type,w:s.w,h:s.h,qty:s.qty,blob:null,prev:null});renderBrandings();toast(t('Duplicated — add photo','डुप्लीकेट — फोटो जोड़ें'),'info');}\u001b[39m\n\u001b[31mfunction rmBr(i){brandings.splice(i,1);renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction capBr(i){\u001b[39m\n\u001b[31m  const q=brandings[i]?.quality||imgQuality;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f,q==='hd'?1920:1280,q==='hd'?0.90:0.78));\u001b[39m\n\u001b[31m    brandings[i].blob=bs;brandings[i].prev=URL.createObjectURL(bs);\u001b[39m\n\u001b[31m    brandings[i].fromCamera=(e._src==='camera');\u001b[39m\n\u001b[31m    openAnnot(i);\u001b[39m\n\u001b[31m  },null,q);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmBrPh(i){brandings[i].blob=null;brandings[i].prev=null;renderBrandings();}\u001b[39m\n\u001b[31mfunction setBrQuality(i,q){brandings[i].quality=q;renderBrandings();}·\u001b[39m\n\u001b[31m// VIDEO / DOC\u001b[39m\n\u001b[31mfunction setVideo(v){F.hasVideo=v;document.getElementById('vid-yes').classList.toggle('sel',v);document.getElementById('vid-no').classList.toggle('sel',!v);document.getElementById('vid-sec').style.display=v?'block':'none';saveDraft();}\u001b[39m\n\u001b[31masync function handleVideo(e){videoBlob=e.target.files[0];if(!videoBlob)return;document.getElementById('vid-slot').innerHTML=`<div style=\\\"padding:14px;font-size:13px;color:var(--gn)\\\">✓ ${videoBlob.name} (${fmtSz(videoBlob.size)})</div>`;}\u001b[39m\n\u001b[31mfunction setBranding(v){F.hasBranding=v;document.getElementById('br-yes').classList.toggle('sel',v);document.getElementById('br-no').classList.toggle('sel',!v);document.getElementById('br-add').style.display=v?'block':'none';if(v&&brandings.length===0)addBranding();saveDraft();}\u001b[39m\n\u001b[31masync function handleDoc(e){const f=e.target.files[0];if(!f)return;submissionDoc=f.type.startsWith('image/')?await compress(f,1600,.85):f;const slot=document.getElementById('doc-slot');if(f.type.startsWith('image/')){slot.classList.add('filled');slot.innerHTML=`<img src=\\\"${URL.createObjectURL(submissionDoc)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}else{slot.innerHTML=`<div style=\\\"padding:16px;font-size:13px;color:var(--gn)\\\">✓ ${f.name} (${fmtSz(f.size)})</div>`;}buildReview();}·\u001b[39m\n\u001b[31m// CLIENT CHIPS\u001b[39m\n\u001b[31mfunction renderClientChips(){\u001b[39m\n\u001b[31m  const grid = document.getElementById('client-chips'); if (!grid) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  clientList.forEach(c => {\u001b[39m\n\u001b[31m    const sel = !_clientOtherMode && _selectedClient === c;\u001b[39m\n\u001b[31m    html += `<div class=\\\"cl-chip${sel?' sel':''}\\\" onclick=\\\"selectClientChip('${esc(c)}')\\\">${esc(c)}</div>`;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html += `<div class=\\\"cl-chip cl-chip-other${_clientOtherMode?' sel':''}\\\" onclick=\\\"selectClientOther()\\\"><span class=\\\"en-txt\\\">Other…</span><span class=\\\"hi-txt\\\">अन्य…</span></div>`;\u001b[39m\n\u001b[31m  grid.innerHTML = html;\u001b[39m\n\u001b[31m  document.getElementById('client-other-wrap').style.display = _clientOtherMode ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientChip(name){\u001b[39m\n\u001b[31m  _selectedClient = name; _clientOtherMode = false;\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').value = '';\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientOther(){\u001b[39m\n\u001b[31m  _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onClientOtherInput(){\u001b[39m\n\u001b[31m  _selectedClient = document.getElementById('f-client-other').value.trim();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction getClientName(){\u001b[39m\n\u001b[31m  if (_clientOtherMode) return (document.getElementById('f-client-other')?.value||'').trim();\u001b[39m\n\u001b[31m  return _selectedClient;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction autoSetClient(brandName){\u001b[39m\n\u001b[31m  if (!brandName) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  if (clientList.includes(brandName)){\u001b[39m\n\u001b[31m    _selectedClient = brandName; _clientOtherMode = false;\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    // Not in list — pre-fill the Other field\u001b[39m\n\u001b[31m    _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m    const inp = document.getElementById('f-client-other');\u001b[39m\n\u001b[31m    if (inp && !inp.value) inp.value = brandName;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// STEP VALIDATION\u001b[39m\n\u001b[31mfunction getSD(){if(selectedStore&&!manualMode)return{storeName:selectedStore.name,brand:selectedStore.brand||'',address:selectedStore.address||'',mobile:selectedStore.mobile||''};return{storeName:(document.getElementById('f-store')?.value||'').trim(),brand:document.getElementById('f-brand')?.value||'',address:(document.getElementById('f-addr')?.value||'').trim(),mobile:(document.getElementById('f-mobile')?.value||'').trim()};}\u001b[39m\n\u001b[31mfunction step2(){\u001b[39m\n\u001b[31m  const d=document.getElementById('f-date').value;\u001b[39m\n\u001b[31m  if(!d){toast('Select date','error');return;}\u001b[39m\n\u001b[31m  const sd=getSD();\u001b[39m\n\u001b[31m  if(!sd.storeName){toast('Select or enter store name','error');return;}\u001b[39m\n\u001b[31m  if(!sd.brand){toast('Select a brand','error');document.getElementById('brand-selector').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  if(!sd.address){toast('Enter store address','error');return;}\u001b[39m\n\u001b[31m  const clientName=getClientName();\u001b[39m\n\u001b[31m  if(!clientName){toast(t('Select a client','क्लाइंट चुनें'),'error');document.getElementById('client-chips').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  // Check missing fields filled\u001b[39m\n\u001b[31m  const missAddr=document.getElementById('sc-miss-address');\u001b[39m\n\u001b[31m  if(missAddr&&!missAddr.value.trim()){toast('Enter store address in the highlighted field','error');missAddr.focus();return;}\u001b[39m\n\u001b[31m  const missMob=document.getElementById('sc-miss-mobile');\u001b[39m\n\u001b[31m  // mobile not required — just copy if filled\u001b[39m\n\u001b[31m  if(missMob&&missMob.value.trim()&&!F.mobile)F.mobile=missMob.value.trim();\u001b[39m\n\u001b[31m  Object.assign(F,{date:d,...sd,clientName});saveDraft();\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');showView('form-photos');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction step3(){if(!frontPhotos.length){toast('Add at least 1 front view photo','error');return;}showView('form-video');}\u001b[39m\n\u001b[31mfunction step4(){if(F.hasVideo===undefined||F.hasVideo===null){toast('Select Yes or No for video','error');return;}renderBrandings();showView('form-branding');}\u001b[39m\n\u001b[31mfunction step5(){if(F.hasBranding===undefined||F.hasBranding===null){toast('Select Yes or No for branding space','error');return;}if(F.hasBranding){for(let i=0;i<brandings.length;i++){const b=brandings[i];if(!b.type){toast(`Select branding type for item ${i+1}`,'error');return;}if(!b.w||!b.h){toast(`Enter W and H dimensions for item ${i+1}`,'error');return;}if(!b.qty){toast(`Enter qty for item ${i+1}`,'error');return;}if(!b.blob&&!b.prev){toast(`Add photo for item ${i+1}`,'error');return;}}}renderAddl();buildReview();showView('form-additional');}·\u001b[39m\n\u001b[31m// REVIEW\u001b[39m\n\u001b[31mfunction buildReview(){const el=document.getElementById('rev-body');if(!el)return;const sd=getSD();const cn=getClientName();el.innerHTML=`<div><div class=\\\"rev-lbl\\\">Store</div><div class=\\\"rev-val\\\">${sd.storeName||'—'} · ${sd.brand||'—'}</div><div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">${sd.address||'—'}${sd.mobile?' · '+sd.mobile:''}</div>${gpsCoords?`<div style=\\\"font-size:11px;color:var(--gn);margin-top:3px\\\">📍 ${gpsCoords.lat}, ${gpsCoords.lng} ±${gpsCoords.acc}m</div>`:''}</div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Client</div><div class=\\\"rev-val\\\" style=\\\"color:${cn?'var(--nv)':'var(--rd)'}\\\">${cn||'⚠ Not selected — required'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Photos — Front · Inside · Additional</div><div class=\\\"rev-val\\\">${frontPhotos.length} · ${insidePhotos.length} · ${addlPhotos.length}</div><div class=\\\"rev-photos\\\">${[...frontPhotos,...insidePhotos].slice(0,6).map(p=>`<img class=\\\"rev-thumb\\\" src=\\\"${p.prev}\\\">`).join('')}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Video · Branding items</div><div class=\\\"rev-val\\\">${F.hasVideo?'Yes':'No'} · ${brandings.length} item(s)</div></div>${F.hasBranding&&brandings.length?`<div style=\\\"margin-top:8px\\\">${brandings.map((b,i)=>`<div style=\\\"font-size:12px;color:var(--g600);padding:4px 0;border-bottom:1px solid var(--g100)\\\">${i+1}. ${b.type||'No type'} — ${b.w||'?'}×${b.h||'?'}\\\" × ${b.qty||'?'} — ${calcSqft(b.w,b.h)||'?'}</div>`).join('')}</div>`:''}<div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Additional photos <span style=\\\"font-size:11px;color:var(--g400)\\\">(optional)</span></div><div class=\\\"rev-val\\\" style=\\\"color:${addlPhotos.length?'var(--gn)':'var(--g500)'}\\\">${addlPhotos.length?`✓ ${addlPhotos.length} photo(s) added`:'None added'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Mandatory document</div><div class=\\\"rev-val\\\" style=\\\"color:${(submissionDoc||_docExistingUrl)?'var(--gn)':'var(--rd)'}\\\">${(submissionDoc||_docExistingUrl)?'✓ Uploaded':'⚠ Missing — required'}</div></div>`;}·\u001b[39m\n\u001b[31m// SUBMIT\u001b[39m\n\u001b[31masync function submitRecce(){\u001b[39m\n\u001b[31m  if(!submissionDoc&&!_docExistingUrl){toast('Upload mandatory doc first','error');return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('sub-btn');btn.disabled=true;btn.textContent='Saving…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const isEdit=!!(F.editingId);\u001b[39m\n\u001b[31m    const id=isEdit?F.editingId:('RC_'+Date.now()+'_'+Math.random().toString(36).slice(2,6).toUpperCase());\u001b[39m\n\u001b[31m    const sd=getSD();\u001b[39m\n\u001b[31m    const _hub=_recceHubUser();\u001b[39m\n\u001b[31m    const entry={id,timestamp:isEdit?(await dbGet('subs',id))?.timestamp||new Date().toISOString():new Date().toISOString(),editedAt:isEdit?new Date().toISOString():undefined,status:'pending',submittedBy:_hub.empId||null,submittedByName:_hub.name||null,data:{...F,...sd,gpsCoords,frontPhotos:await Promise.all(frontPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),insidePhotos:await Promise.all(insidePhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),videoNote:F.hasVideo&&videoBlob?`Video local (${fmtSz(videoBlob.size)}) — share via WhatsApp`:null,videoCmt:document.getElementById('f-vid-cmt')?.value||'',brandings:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:calcSqft(b.w,b.h),photoB64:b.blob?await b64(b.blob):null,existingUrl:b.existingUrl||null}))),addlPhotos:await Promise.all(addlPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,desc:p.desc,existingUrl:p.existingUrl||null}))),docB64:submissionDoc?await b64(submissionDoc):null,_docExistingUrl:_docExistingUrl||null}};\u001b[39m\n\u001b[31m    entry.campaignId       = _selectedCampaignId || null;\u001b[39m\n\u001b[31m    entry.notifySupervisor = _notifySupervisor   || false;\u001b[39m\n\u001b[31m    await dbPut('subs',entry);\u001b[39m\n\u001b[31m    await dbDel('draft','current');\u001b[39m\n\u001b[31m    toast(isEdit?'Recce updated ✓':'Recce saved ✓','success');\u001b[39m\n\u001b[31m    if(navigator.onLine)syncNow();\u001b[39m\n\u001b[31m    showView('home');loadHome();checkDraft();\u001b[39m\n\u001b[31m  }catch(err){toast('Error: '+err.message,'error');}\u001b[39m\n\u001b[31m  finally{btn.disabled=false;btn.textContent='Submit Recce ✓';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// SYNC\u001b[39m\n\u001b[31masync function syncNow() {\u001b[39m\n\u001b[31m  if (!navigator.onLine) { toast('Offline — sync when back online', 'info'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('sync-btn');\u001b[39m\n\u001b[31m  const SYNC_ICON = '<svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg>Sync';\u001b[39m\n\u001b[31m  if (btn) { btn.innerHTML = '<span class=\\\"spin\\\">↻</span> Syncing'; btn.disabled = true; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const all      = await dbAll('subs');\u001b[39m\n\u001b[31m    const pend     = all.filter(s => s.status === 'pending' || s.status === 'failed');\u001b[39m\n\u001b[31m    const backfill = all.filter(s => s.status === 'synced' && !s.gasAt);\u001b[39m\n\u001b[31m    if (!pend.length && !backfill.length) { toast('All synced ✓', 'success'); return; }·\u001b[39m\n\u001b[31m    const gasUrl = (await cfg('gas-url')) || DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    function fireGas(s) {\u001b[39m\n\u001b[31m      if (!gasUrl) return;\u001b[39m\n\u001b[31m      fetch(gasUrl, { method:'POST', mode:'no-cors',\u001b[39m\n\u001b[31m        body: JSON.stringify({ action:'syncSheet', submission: s }) })\u001b[39m\n\u001b[31m        .catch(() => {});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    let ok = 0;\u001b[39m\n\u001b[31m    for (const s of pend) {\u001b[39m\n\u001b[31m      // Fire Sheet sync (no-cors fire-and-forget — writes row to Google Sheet)\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      // Primary: upload photos → auto-trigger slides → generate report → store in PostgreSQL\u001b[39m\n\u001b[31m      const { ok: pgOk, viewUrl } = await syncToPostgres(s);\u001b[39m\n\u001b[31m      if (pgOk) {\u001b[39m\n\u001b[31m        s.status = 'synced'; s.syncedAt = new Date().toISOString();\u001b[39m\n\u001b[31m        if (viewUrl) s.viewUrl = viewUrl;\u001b[39m\n\u001b[31m        await dbPut('subs', s); ok++;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        s.status = 'failed'; await dbPut('subs', s);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Backfill: entries synced to Postgres but never reached Sheet GAS\u001b[39m\n\u001b[31m    for (const s of backfill) {\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      await dbPut('subs', s);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if (backfill.length) toast(`Sent ${backfill.length} older entries to Sheet`, 'info');·\u001b[39m\n\u001b[31m    await cfg('last-sync', new Date().toISOString());\u001b[39m\n\u001b[31m    if (pend.length) toast(`Synced ${ok}/${pend.length}`, ok === pend.length ? 'success' : 'error');\u001b[39m\n\u001b[31m    loadHome();\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.innerHTML = SYNC_ICON; btn.disabled = false; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN HOME ──────────────────────────────────────────────\u001b[39m\n\u001b[31masync function loadHomeAdmin() {\u001b[39m\n\u001b[31m  // Adapt UI for admin view\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const _sh = document.querySelector('.sh'); if (_sh) _sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = 'All Submissions';\u001b[39m\n\u001b[31m  const slbls = document.querySelectorAll('.slbl');\u001b[39m\n\u001b[31m  if (slbls[0]) slbls[0].textContent = 'Showing';\u001b[39m\n\u001b[31m  if (slbls[1]) slbls[1].textContent = 'Agents';·\u001b[39m\n\u001b[31m  // Back-to-menu button for supervisors\u001b[39m\n\u001b[31m  if (_isSupervisor() && !document.getElementById('sup-back-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => { document.getElementById('sup-back-btn').remove(); renderSupLanding(); };\u001b[39m\n\u001b[31m    const content = document.querySelector('#view-home .content');\u001b[39m\n\u001b[31m    content.prepend(bb);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Show filter bar — restore if hidden by renderSupLanding, else inject fresh\u001b[39m\n\u001b[31m  const _existingFb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (_existingFb) { _existingFb.style.display = ''; }\u001b[39m\n\u001b[31m  if (!_existingFb) {\u001b[39m\n\u001b[31m    const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m    const fb = document.createElement('div');\u001b[39m\n\u001b[31m    fb.id = 'admin-filter-bar';\u001b[39m\n\u001b[31m    fb.className = 'af-bar';\u001b[39m\n\u001b[31m    fb.innerHTML =\u001b[39m\n\u001b[31m      `<div class=\\\"af-grid\\\">\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-agent\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Agents</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-brand\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Brands</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-client\\\" onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Clients</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-period\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">All Time</option>\u001b[39m\n\u001b[31m          <option value=\\\"7\\\">Last 7 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"30\\\">Last 30 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"90\\\">Last 3 months</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-group\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"date\\\">Sort: Recent</option>\u001b[39m\n\u001b[31m          <option value=\\\"agent\\\">Group: Agent</option>\u001b[39m\n\u001b[31m          <option value=\\\"brand\\\">Group: Brand</option>\u001b[39m\n\u001b[31m          <option value=\\\"client\\\">Group: Client</option>\u001b[39m\n\u001b[31m          <option value=\\\"city\\\">Group: City</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m        <input class=\\\"af-inp\\\" id=\\\"af-search\\\" type=\\\"text\\\" placeholder=\\\"🔍 Search store or city…\\\" oninput=\\\"renderAdminList()\\\" style=\\\"flex:1;min-width:120px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"del-toggle-btn\\\" id=\\\"del-toggle-btn\\\" onclick=\\\"toggleDeletedView()\\\" style=\\\"flex-shrink:0\\\">📋 View Deleted</button>\u001b[39m\n\u001b[31m        ${_isSupervisor() ? `<button class=\\\"del-toggle-btn\\\" id=\\\"pending-job-btn\\\" onclick=\\\"togglePendingJobView()\\\" style=\\\"flex-shrink:0;background:#fef3c7;color:#92400e;border-color:#f59e0b\\\">⚑ Unlinked <span id=\\\"pending-job-count\\\" style=\\\"font-weight:900\\\"></span></button>` : ''}\u001b[39m\n\u001b[31m        ${_adminUnlocked ? `<button class=\\\"del-toggle-btn\\\" id=\\\"regen-rpt-btn\\\" onclick=\\\"regenAllReports()\\\" style=\\\"flex-shrink:0\\\">&#x21BB; Regen Reports</button>` : ''}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    sh.parentNode.insertBefore(fb, sh);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Fetch\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  list.innerHTML = '<div style=\\\"text-align:center;padding:40px\\\"><div class=\\\"spinner\\\"></div></div>';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?order=submitted_at.desc&limit=500`, { headers: _RC_READ });\u001b[39m\n\u001b[31m    _adminRows = resp.ok ? await resp.json() : [];\u001b[39m\n\u001b[31m    document.getElementById('stat-total').textContent = _adminRows.length;\u001b[39m\n\u001b[31m    if (resp.ok) {\u001b[39m\n\u001b[31m      const now = new Date();\u001b[39m\n\u001b[31m      document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m        'Loaded ' + now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Populate agent dropdown\u001b[39m\n\u001b[31m    const agents = [...new Set(_adminRows.map(r => r.submitted_by).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-agent').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Agents (${agents.length})</option>` +\u001b[39m\n\u001b[31m      agents.map(a => `<option value=\\\"${a}\\\">${a}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate brand dropdown\u001b[39m\n\u001b[31m    const brands = [...new Set(_adminRows.map(r => r.brand).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-brand').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Brands (${brands.length})</option>` +\u001b[39m\n\u001b[31m      brands.map(b => `<option value=\\\"${b}\\\">${b}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate client dropdown\u001b[39m\n\u001b[31m    const clients = [...new Set(_adminRows.map(r => r.client_name).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-client').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Clients (${clients.length})</option>` +\u001b[39m\n\u001b[31m      clients.map(c => `<option value=\\\"${c}\\\">${c}</option>`).join('');·\u001b[39m\n\u001b[31m    // Update pending-job count badge\u001b[39m\n\u001b[31m    const unlinkedCount = _adminRows.filter(r => !r.deleted_at && !r.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinkedCount ? `(${unlinkedCount})` : '';·\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">⚠️</div><div class=\\\"empty-txt\\\">Could not load — check connection</div></div>';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction togglePendingJobView() {\u001b[39m\n\u001b[31m  _pendingJobFilter = !_pendingJobFilter;\u001b[39m\n\u001b[31m  _showDeletedView  = false;\u001b[39m\n\u001b[31m  const btn = document.getElementById('pending-job-btn');\u001b[39m\n\u001b[31m  if (btn) btn.style.background = _pendingJobFilter ? '#f59e0b' : '#fef3c7';\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function openLinkJobModal(subId, storeName) {\u001b[39m\n\u001b[31m  _linkJobSubId = subId;\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  const storeEl = document.getElementById('link-job-store');\u001b[39m\n\u001b[31m  const sel = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  if (!modal) return;\u001b[39m\n\u001b[31m  if (storeEl) storeEl.textContent = storeName || subId;\u001b[39m\n\u001b[31m  if (errEl) errEl.textContent = '';\u001b[39m\n\u001b[31m  // Load campaigns into dropdown\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (!_campaignList.length) {\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m      _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  if (sel) {\u001b[39m\n\u001b[31m    sel.innerHTML = '<option value=\\\"\\\">— Select campaign —</option>' +\u001b[39m\n\u001b[31m      _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  modal.style.display = 'flex';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeLinkJobModal() {\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  if (modal) modal.style.display = 'none';\u001b[39m\n\u001b[31m  _linkJobSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function saveLinkJob() {\u001b[39m\n\u001b[31m  const sel    = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl  = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  const campId = sel?.value || '';\u001b[39m\n\u001b[31m  if (!campId) { if (errEl) errEl.textContent = 'Select a campaign'; return; }\u001b[39m\n\u001b[31m  if (!_linkJobSubId) return;\u001b[39m\n\u001b[31m  const btn = document.querySelector('#modal-link-job button[onclick=\\\"saveLinkJob()\\\"]');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Linking…'; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(_linkJobSubId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ campaign_id: campId }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Patch failed');\u001b[39m\n\u001b[31m    // Update local cache\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === _linkJobSubId);\u001b[39m\n\u001b[31m    if (idx >= 0) _adminRows[idx].campaign_id = campId;\u001b[39m\n\u001b[31m    // Update pending count badge\u001b[39m\n\u001b[31m    const unlinked = _adminRows.filter(x => !x.deleted_at && !x.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinked ? `(${unlinked})` : '';\u001b[39m\n\u001b[31m    closeLinkJobModal();\u001b[39m\n\u001b[31m    toast('Job linked ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    if (errEl) errEl.textContent = 'Failed to link — try again';\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.disabled = false; btn.textContent = '🔗 Link Job'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAdminList() {\u001b[39m\n\u001b[31m  const agent  = document.getElementById('af-agent')?.value  || '';\u001b[39m\n\u001b[31m  const brand  = document.getElementById('af-brand')?.value  || '';\u001b[39m\n\u001b[31m  const period = document.getElementById('af-period')?.value || '';\u001b[39m\n\u001b[31m  const search = (document.getElementById('af-search')?.value || '').toLowerCase().trim();\u001b[39m\n\u001b[31m  const group  = document.getElementById('af-group')?.value  || 'date';·\u001b[39m\n\u001b[31m  // Pending-job filter overrides deleted/normal modes\u001b[39m\n\u001b[31m  let rows;\u001b[39m\n\u001b[31m  if (_pendingJobFilter) {\u001b[39m\n\u001b[31m    rows = _adminRows.filter(r => !r.deleted_at && !r.campaign_id);\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows = _showDeletedView\u001b[39m\n\u001b[31m      ? _adminRows.filter(r => r.deleted_at)\u001b[39m\n\u001b[31m      : _adminRows.filter(r => !r.deleted_at);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const client = document.getElementById('af-client')?.value || '';\u001b[39m\n\u001b[31m  if (agent)  rows = rows.filter(r => r.submitted_by === agent);\u001b[39m\n\u001b[31m  if (brand)  rows = rows.filter(r => r.brand === brand);\u001b[39m\n\u001b[31m  if (client) rows = rows.filter(r => r.client_name === client);\u001b[39m\n\u001b[31m  if (search) rows = rows.filter(r => (r.store_name||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.city||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.client_name||'').toLowerCase().includes(search));\u001b[39m\n\u001b[31m  if (period && !_showDeletedView) {\u001b[39m\n\u001b[31m    const cut = new Date(); cut.setDate(cut.getDate() - parseInt(period));\u001b[39m\n\u001b[31m    rows = rows.filter(r => new Date(r.submitted_at) >= cut);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const uniqueAgents = new Set(rows.map(r => r.submitted_by).filter(Boolean)).size;\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = rows.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = uniqueAgents;\u001b[39m\n\u001b[31m  const deletedCount = _adminRows.filter(r => r.deleted_at).length;\u001b[39m\n\u001b[31m  const delBtn = document.getElementById('del-toggle-btn');\u001b[39m\n\u001b[31m  if (delBtn) {\u001b[39m\n\u001b[31m    if (_showDeletedView) {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 Hide Deleted (${deletedCount})` : '📋 Hide Deleted';\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 View Deleted (${deletedCount})` : '📋 View Deleted';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    delBtn.classList.toggle('active', _showDeletedView);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!rows.length) {\u001b[39m\n\u001b[31m    list.innerHTML = _showDeletedView\u001b[39m\n\u001b[31m      ? '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">✅</div><div class=\\\"empty-txt\\\">No deleted recces</div></div>'\u001b[39m\n\u001b[31m      : '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">🔍</div><div class=\\\"empty-txt\\\">No matching submissions</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (group === 'agent') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.submitted_by||'').localeCompare(b.submitted_by||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.submitted_by || 'Unknown';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">👤 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'brand') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.brand||'').localeCompare(b.brand||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.brand || 'No Brand';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🏷 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'client') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.client_name||'').localeCompare(b.client_name||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.client_name || 'No Client';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🤝 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'city') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.city||'').localeCompare(b.city||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.city || 'No City';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">📍 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows.sort((a,b) => new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    rows.forEach(r => { html += adminCard(r); });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminCard(r) {\u001b[39m\n\u001b[31m  const dt    = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds    = dt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m  const tm    = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const photos = (r.front_photos||0) + (r.inside_photos||0) + (r.addl_photos||0);\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const canDelete  = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const canArchive = _RECCE_CFG_ADMINS.includes(hub?.empId) && !r.client_archived;·\u001b[39m\n\u001b[31m  // Client status badge\u001b[39m\n\u001b[31m  const clientStatusMap = {\u001b[39m\n\u001b[31m    approved:              {t:'✓ Approved',    s:'color:#166534;background:#dcfce7;border:1px solid #86efac'},\u001b[39m\n\u001b[31m    rejected:              {t:'✕ Rejected',    s:'color:#991b1b;background:#fee2e2;border:1px solid #fca5a5'},\u001b[39m\n\u001b[31m    approved_with_changes: {t:'✎ Approved w/ Comments', s:'color:#92400e;background:#fef3c7;border:1px solid #fcd34d'},\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const csCfg = clientStatusMap[r.client_status];\u001b[39m\n\u001b[31m  const clientStatusBadge = csCfg\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;${csCfg.s}\\\">${csCfg.t}</span>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const archiveBadge = r.client_archived\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;color:#475569;background:#f1f5f9;border:1px solid #cbd5e1\\\">⬚ Client hidden</span>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  if (r.deleted_at) {\u001b[39m\n\u001b[31m    const delDt = new Date(r.deleted_at);\u001b[39m\n\u001b[31m    const delDs = delDt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m    const reasonLabel = r.deletion_reason === 'wrong' ? 'Wrong' : r.deletion_reason === 'duplicate' ? 'Duplicate' : 'Test';\u001b[39m\n\u001b[31m    return `<div class=\\\"asc deleted-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m        <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m            <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds}</span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m          <span class=\\\"del-reason-tag\\\">❌ ${reasonLabel}</span>\u001b[39m\n\u001b[31m          <div class=\\\"del-by-txt\\\">by ${r.deleted_by||'?'} · ${delDs}</div>\u001b[39m\n\u001b[31m          ${canDelete ? `<button class=\\\"restore-btn\\\" onclick=\\\"event.stopPropagation();restoreRecce('${r.sub_id}')\\\">↩ Restore</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Submitted by ${r.submitted_by||'?'}</div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const chips = [\u001b[39m\n\u001b[31m    photos > 0   ? `📷 ${photos} photo${photos!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.has_video  ? '🎥 Video' : null,\u001b[39m\n\u001b[31m    r.has_branding ? `🪧 ${r.branding_count} branding${r.branding_count!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.city       ? `📍 ${r.city}` : (r.address ? `📍 ${r.address}` : null),\u001b[39m\n\u001b[31m    r.view_url   ? '👁 View available' : null,\u001b[39m\n\u001b[31m  ].filter(Boolean);·\u001b[39m\n\u001b[31m  const delBtnHtml = canDelete\u001b[39m\n\u001b[31m    ? `<button class=\\\"del-btn\\\" onclick=\\\"event.stopPropagation();openDeleteModal('${r.sub_id}')\\\" title=\\\"Delete recce\\\">🗑</button>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const editReqHtml = r.edit_assigned_to\u001b[39m\n\u001b[31m    ? `<span class=\\\"edit-req-badge\\\">✏ Edit sent to ${r.edit_assigned_to}</span>`\u001b[39m\n\u001b[31m    : (_isSupervisor()\u001b[39m\n\u001b[31m        ? `<button class=\\\"req-edit-btn\\\" onclick=\\\"event.stopPropagation();openEditRequestModal('${r.sub_id}')\\\">✏ Request Edit</button>`\u001b[39m\n\u001b[31m        : '');·\u001b[39m\n\u001b[31m  const editRow = editReqHtml\u001b[39m\n\u001b[31m    ? `<div style=\\\"margin-top:6px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">${editReqHtml}</div>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const showPdfBtn = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m  const pdfClass = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m  const pdfLabel = '📄 PDF';\u001b[39m\n\u001b[31m  const linkJobBtn = (_pendingJobFilter && _isSupervisor() && !r.campaign_id)\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:#f59e0b;color:#000;border-color:#f59e0b;font-weight:700\\\" onclick=\\\"event.stopPropagation();openLinkJobModal('${r.sub_id}','${(r.store_name||'Unknown').replace(/'/g,'\\\\\\\\\\\\'')}')\\\">🔗 Link Job</button>`\u001b[39m\n\u001b[31m    : (r.campaign_id ? `<span style=\\\"font-size:10px;color:var(--g400);align-self:center\\\">🔗 ${r.campaign_id}</span>` : '');\u001b[39m\n\u001b[31m  const archiveBtn = canArchive\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:rgba(99,102,241,.08);border-color:var(--nv);color:var(--nv)\\\" onclick=\\\"event.stopPropagation();archiveRecce('${r.sub_id}')\\\">⛚ Archive</button>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const btnsRow = `<div class=\\\"rpt-btns\\\">\u001b[39m\n\u001b[31m    <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openAdminRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m    ${showPdfBtn ? `<button class=\\\"${pdfClass}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">${pdfLabel}</button>` : ''}\u001b[39m\n\u001b[31m    ${linkJobBtn}\u001b[39m\n\u001b[31m    ${archiveBtn}\u001b[39m\n\u001b[31m  </div>`;·\u001b[39m\n\u001b[31m  return `<div class=\\\"asc\\\">\u001b[39m\n\u001b[31m    <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m      <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m          ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          ${r.client_name&&r.client_name!==r.brand?`<span class=\\\"client-tag\\\">🤝 ${r.client_name}</span>`:''}\u001b[39m\n\u001b[31m          <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds} · ${tm}</span>\u001b[39m\n\u001b[31m          ${clientStatusBadge}\u001b[39m\n\u001b[31m          ${archiveBadge}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <span class=\\\"asc-agent\\\">👤 ${r.submitted_by||'?'}</span>\u001b[39m\n\u001b[31m        ${delBtnHtml}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    ${chips.length?`<div class=\\\"asc-chips\\\">${chips.map(c=>`<span class=\\\"asc-chip\\\">${c}</span>`).join('')}</div>`:''}\u001b[39m\n\u001b[31m    ${editRow}\u001b[39m\n\u001b[31m    ${btnsRow}\u001b[39m\n\u001b[31m  </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _ensurePdfOverlay() {\u001b[39m\n\u001b[31m  if (document.getElementById('pdf-wait-ov')) return;\u001b[39m\n\u001b[31m  const ov = document.createElement('div');\u001b[39m\n\u001b[31m  ov.id = 'pdf-wait-ov';\u001b[39m\n\u001b[31m  ov.innerHTML = '<div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Generating PDF…</div><div class=\\\"po-sub\\\" id=\\\"pw-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"pw-pfill\\\"></div></div>';\u001b[39m\n\u001b[31m  document.body.appendChild(ov);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _showPdfOverlay(msg) {\u001b[39m\n\u001b[31m  _ensurePdfOverlay();\u001b[39m\n\u001b[31m  document.getElementById('pw-sub').textContent = msg || '';\u001b[39m\n\u001b[31m  document.getElementById('pw-pfill').style.width = '0%';\u001b[39m\n\u001b[31m  document.getElementById('pdf-wait-ov').style.display = 'flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _hidePdfOverlay() {\u001b[39m\n\u001b[31m  const ov = document.getElementById('pdf-wait-ov');\u001b[39m\n\u001b[31m  if (ov) ov.style.display = 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function openPdf(subId, pdfUrl, viewUrl) {\u001b[39m\n\u001b[31m  if (pdfUrl) { window.open(pdfUrl, '_blank'); return; }\u001b[39m\n\u001b[31m  if (!viewUrl) {\u001b[39m\n\u001b[31m    toast('Report view not available yet — please try after the report is generated.', 'info');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _showPdfOverlay('Requesting PDF generation…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type': 'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({type: 'regen-pdf', subId, viewUrl})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  let attempts = 0;\u001b[39m\n\u001b[31m  const MAX = 24;\u001b[39m\n\u001b[31m  const poll = async () => {\u001b[39m\n\u001b[31m    attempts++;\u001b[39m\n\u001b[31m    const pct = Math.min(88, Math.round(attempts / MAX * 88));\u001b[39m\n\u001b[31m    document.getElementById('pw-pfill').style.width = pct + '%';\u001b[39m\n\u001b[31m    const left = Math.ceil((MAX - attempts) * 5);\u001b[39m\n\u001b[31m    document.getElementById('pw-sub').textContent = 'Checking… (' + left + 's remaining)';\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const res = await fetch('/db/submissions?sub_id=eq.' + subId + '&select=pdf_url', {\u001b[39m\n\u001b[31m        headers: {'Content-Profile': 'recce', 'Accept-Profile': 'recce'}\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      const rows = await res.json();\u001b[39m\n\u001b[31m      if (rows && rows[0] && rows[0].pdf_url) {\u001b[39m\n\u001b[31m        document.getElementById('pw-pfill').style.width = '100%';\u001b[39m\n\u001b[31m        setTimeout(() => { _hidePdfOverlay(); window.open(rows[0].pdf_url, '_blank'); }, 400);\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(_) {}\u001b[39m\n\u001b[31m    if (attempts >= MAX) { _hidePdfOverlay(); toast('PDF generation timed out. Please try again later.', 'error'); return; }\u001b[39m\n\u001b[31m    setTimeout(poll, 5000);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  setTimeout(poll, 4000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openAdminRecce(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];·\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">\u001b[39m\n\u001b[31m         📍 View on Google Maps (${Number(r.gps_lat).toFixed(4)}, ${Number(r.gps_lng).toFixed(4)})\u001b[39m\n\u001b[31m       </a>` : '';·\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} ft × ${b.h||'?'} ft · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos not yet available — field agent must re-sync from their device to upload view\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Submission Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">👤 ${r.submitted_by||'Unknown'}</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            ${meta.videoCmt?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500);font-size:12px\\\">${meta.videoCmt}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m          ${(()=>{\u001b[39m\n\u001b[31m            const hub2 = _recceHubUser();\u001b[39m\n\u001b[31m            const isHP = _RECCE_CFG_ADMINS.includes(hub2?.empId);\u001b[39m\n\u001b[31m            const csMap = {\u001b[39m\n\u001b[31m              approved:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#166534;background:#dcfce7\\\">✓ Approved</span>',\u001b[39m\n\u001b[31m              rejected:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#991b1b;background:#fee2e2\\\">✕ Rejected</span>',\u001b[39m\n\u001b[31m              approved_with_changes: '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#92400e;background:#fef3c7\\\">✎ Approved w/ Comments</span>',\u001b[39m\n\u001b[31m            };\u001b[39m\n\u001b[31m            const csBadge = csMap[r.client_status] || '';\u001b[39m\n\u001b[31m            const approvedAt = r.client_approved_at\u001b[39m\n\u001b[31m              ? new Date(r.client_approved_at).toLocaleString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit',timeZone:'Asia/Kolkata'})\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const pdfLink = r.client_approval_pdf_url\u001b[39m\n\u001b[31m              ? `<a href=\\\"${r.client_approval_pdf_url}\\\" target=\\\"_blank\\\" style=\\\"font-size:12px;color:var(--or);text-decoration:none\\\">⬇ Approval PDF</a>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const archAct = isHP && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveRecce('${r.sub_id}')\\\" style=\\\"font-size:12px;color:var(--nv);background:none;border:1px solid var(--nv);border-radius:6px;padding:4px 10px;cursor:pointer\\\">⦽ Archive from client</button>`\u001b[39m\n\u001b[31m              : (r.client_archived ? '<span style=\\\"font-size:11px;color:var(--g400)\\\">⦽ Hidden from client</span>' : '');\u001b[39m\n\u001b[31m            const campAct = isHP && r.campaign_id && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveAllForCampaign('${r.campaign_id}')\\\" style=\\\"font-size:11px;color:#991b1b;background:none;border:1px solid #fca5a5;border-radius:6px;padding:3px 8px;cursor:pointer\\\">Archive ALL for ${r.campaign_id}</button>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            if (!csBadge && !pdfLink && !archAct) return '';\u001b[39m\n\u001b[31m            return `<div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m              <div class=\\\"ardl-lbl\\\">Client Approval</div>\u001b[39m\n\u001b[31m              ${csBadge ? `<div style=\\\"margin-bottom:5px\\\">${csBadge}${approvedAt ? ' <span style=\\\"font-size:11px;color:var(--g400)\\\">' + approvedAt + '</span>' : ''}</div>` : ''}\u001b[39m\n\u001b[31m              ${r.client_comment ? `<div style=\\\"font-size:12px;color:var(--g600);background:var(--g50);border-radius:6px;padding:7px 10px;margin-bottom:5px\\\">\\\"${r.client_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m              ${pdfLink ? `<div style=\\\"margin-bottom:4px\\\">${pdfLink}</div>` : ''}\u001b[39m\n\u001b[31m              ${archAct ? `<div style=\\\"margin-bottom:4px\\\">${archAct}</div>` : ''}\u001b[39m\n\u001b[31m              ${campAct ? `<div>${campAct}</div>` : ''}\u001b[39m\n\u001b[31m            </div>`;\u001b[39m\n\u001b[31m          })()}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeAdminDetail() {\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveRecce(subId) {\u001b[39m\n\u001b[31m  if (!confirm('Archive this recce from client view? The client will no longer see it.')) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(subId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) Object.assign(_adminRows[idx], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    toast('Archived from client view ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveAllForCampaign(campaignId) {\u001b[39m\n\u001b[31m  if (!confirm(`Archive ALL recces for campaign \\\"${campaignId}\\\" from client view?\\\\nClients will no longer see any recce from this campaign.`)) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?campaign_id=eq.${encodeURIComponent(campaignId)}&client_archived=eq.false`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    _adminRows.forEach((row, i) => {\u001b[39m\n\u001b[31m      if (row.campaign_id === campaignId) Object.assign(_adminRows[i], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    toast(`All recces for ${campaignId} archived ✓`, 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function regenAllReports() {\u001b[39m\n\u001b[31m  if (!_adminUnlocked) { toast('Admin access required', 'error'); return; }\u001b[39m\n\u001b[31m  const rows = _adminRows.filter(r => !r.deleted_at && r.photo_urls);\u001b[39m\n\u001b[31m  if (!rows.length) { toast('No synced rows with photos found', 'error'); return; }·\u001b[39m\n\u001b[31m  const btn = document.getElementById('regen-rpt-btn');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Regenerating…'; }\u001b[39m\n\u001b[31m  toast(`Regenerating ${rows.length} reports…`, 'info');·\u001b[39m\n\u001b[31m  let done = 0, failed = 0;\u001b[39m\n\u001b[31m  for (const r of rows) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const photoUrls = typeof r.photo_urls === 'string' ? JSON.parse(r.photo_urls) : (r.photo_urls || {});\u001b[39m\n\u001b[31m      let meta = {};\u001b[39m\n\u001b[31m      try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m      const entry = {\u001b[39m\n\u001b[31m        id: r.sub_id,\u001b[39m\n\u001b[31m        timestamp: r.submitted_at,\u001b[39m\n\u001b[31m        submittedBy: r.submitted_by,\u001b[39m\n\u001b[31m        data: {\u001b[39m\n\u001b[31m          storeName:    r.store_name,\u001b[39m\n\u001b[31m          brand:        r.brand,\u001b[39m\n\u001b[31m          clientName:   r.client_name,\u001b[39m\n\u001b[31m          date:         r.visit_date,\u001b[39m\n\u001b[31m          address:      r.address,\u001b[39m\n\u001b[31m          city:         r.city,\u001b[39m\n\u001b[31m          mobile:       r.mobile,\u001b[39m\n\u001b[31m          gpsCoords:    (r.gps_lat && r.gps_lng) ? { lat: r.gps_lat, lng: r.gps_lng } : null,\u001b[39m\n\u001b[31m          hasVideo:     r.has_video,\u001b[39m\n\u001b[31m          videoNote:    meta.videoNote || '',\u001b[39m\n\u001b[31m          videoCmt:     meta.videoCmt  || '',\u001b[39m\n\u001b[31m          frontPhotos:  (photoUrls.front   || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          insidePhotos: (photoUrls.inside  || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          addlPhotos:   (photoUrls.addl    || []).map(() => ({ desc: '' })),\u001b[39m\n\u001b[31m          brandings:    (meta.brandings    || []),\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      };·\u001b[39m\n\u001b[31m      const html = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m      const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m        method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m        body: JSON.stringify({ type: 'save-view', subId: r.sub_id, html })\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!vResp.ok) { failed++; continue; }\u001b[39m\n\u001b[31m      const vr = await vResp.json();\u001b[39m\n\u001b[31m      if (!vr.success) { failed++; continue; }·\u001b[39m\n\u001b[31m      if (vr.url && vr.url !== r.view_url) {\u001b[39m\n\u001b[31m        await fetch(`${_RC_BASE}/submissions?sub_id=eq.${r.sub_id}`, {\u001b[39m\n\u001b[31m          method: 'PATCH', headers: _RC_WRITE,\u001b[39m\n\u001b[31m          body: JSON.stringify({ view_url: vr.url })\u001b[39m\n\u001b[31m        });\u001b[39m\n\u001b[31m        const idx = _adminRows.findIndex(x => x.sub_id === r.sub_id);\u001b[39m\n\u001b[31m        if (idx >= 0) _adminRows[idx].view_url = vr.url;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      done++;\u001b[39m\n\u001b[31m    } catch(e) { failed++; }\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = false; btn.textContent = '↻ Regen Reports'; }\u001b[39m\n\u001b[31m  toast(`Done: ${done} regenerated${failed ? `, ${failed} failed` : ''}`, done > 0 ? 'success' : 'error');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction toggleDeletedView() {\u001b[39m\n\u001b[31m  _showDeletedView = !_showDeletedView;\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openDeleteModal(subId) {\u001b[39m\n\u001b[31m  _pendingDeleteId = subId;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  const sub = document.getElementById('del-modal-sub');\u001b[39m\n\u001b[31m  if (sub) sub.textContent = r ? `Delete: \\\"${r.store_name||'Unknown'}\\\"` : 'Select reason for deletion:';\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectDeleteReason(reason) {\u001b[39m\n\u001b[31m  _pendingDeleteReason = reason;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  document.getElementById('reason-' + reason)?.classList.add('sel');\u001b[39m\n\u001b[31m  document.getElementById('del-confirm-btn').classList.remove('no-reason');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeDeleteModal() {\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingDeleteId = null;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  clearTimeout(_tt);\u001b[39m\n\u001b[31m  document.getElementById('toast').classList.remove('show');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function restoreRecce(subId) {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({ deleted_at: null, deleted_by: null, deletion_reason: null }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Restore failed: ' + r.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_at = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_by = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deletion_reason = null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    toast('Recce restored ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Restore failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmDelete() {\u001b[39m\n\u001b[31m  if (!_pendingDeleteReason) {\u001b[39m\n\u001b[31m    const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m    btn.style.animation = 'none';\u001b[39m\n\u001b[31m    btn.offsetHeight; // reflow\u001b[39m\n\u001b[31m    btn.style.animation = 'shake .35s ease';\u001b[39m\n\u001b[31m    toast('Select a reason first', 'error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if (!_pendingDeleteId) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Deleting…';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      // Hard delete — no audit trail\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'DELETE',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Delete failed: ' + r.status);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Soft delete — stamp deleted_at, deleted_by, deletion_reason\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'PATCH',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m        body: JSON.stringify({\u001b[39m\n\u001b[31m          deleted_at: new Date().toISOString(),\u001b[39m\n\u001b[31m          deleted_by: hub.empId,\u001b[39m\n\u001b[31m          deletion_reason: _pendingDeleteReason,\u001b[39m\n\u001b[31m        }),\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Update failed: ' + r.status);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Remove or update in local cache\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      _adminRows = _adminRows.filter(x => x.sub_id !== _pendingDeleteId);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      const idx = _adminRows.findIndex(x => x.sub_id === _pendingDeleteId);\u001b[39m\n\u001b[31m      if (idx >= 0) {\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_at = new Date().toISOString();\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_by = hub.empId;\u001b[39m\n\u001b[31m        _adminRows[idx].deletion_reason = _pendingDeleteReason;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeDeleteModal();\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast('Recce deleted', 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Delete failed', 'error');\u001b[39m\n\u001b[31m    btn.classList.remove('no-reason');\u001b[39m\n\u001b[31m    btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openMyServerRecce(subId) {\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  // No view yet — show metadata modal (same layout as admin detail)\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta==='string' ? JSON.parse(r.meta) : (r.meta||{}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">📍 View on Google Maps</a>` : '';\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} × ${b.h||'?'} in · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos will appear after next sync from original device\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Visit Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupLanding() {\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = 'none';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = 'none';\u001b[39m\n\u001b[31m  // Clean up admin + create-mode UI\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('sup-back-btn')?.remove();\u001b[39m\n\u001b[31m  document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m  _supCreateMode = false;\u001b[39m\n\u001b[31m  // Resume-wrap may have been hidden by loadHomeAdmin() — restore it so draft banner shows\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = '';\u001b[39m\n\u001b[31m  document.getElementById('sub-list').innerHTML = `\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorViewAll()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0f9ff\\\">📋</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">View All Recces</span><span class=\\\"hi-txt\\\">सभी रेकी देखें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">Browse & review submissions from all agents</span><span class=\\\"hi-txt\\\">सभी एजेंट की सबमिशन देखें</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorCreateView()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0fdf4\\\">✍️</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">Create Recce</span><span class=\\\"hi-txt\\\">नई रेकी बनाएं</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">My submissions + New Recce button</span><span class=\\\"hi-txt\\\">मेरी सबमिशन + नई रेकी</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorViewAll() {\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  await loadHomeAdmin();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorCreateView() {\u001b[39m\n\u001b[31m  _supCreateMode = true;\u001b[39m\n\u001b[31m  // Restore field-agent UI\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh'); if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = t('My Submissions','मेरी सबमिशन');\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar'); if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  // Add Back to Menu button (once)\u001b[39m\n\u001b[31m  if (!document.getElementById('sup-back-create-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-create-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => {\u001b[39m\n\u001b[31m      _supCreateMode = false;\u001b[39m\n\u001b[31m      document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m      renderSupLanding();\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    document.querySelector('#view-home .content').prepend(bb);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  await loadHome();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadHome() {\u001b[39m\n\u001b[31m  if (_isSupervisor() && !_supCreateMode) { renderSupLanding(); return; }\u001b[39m\n\u001b[31m  if (_adminUnlocked && !_supCreateMode) { await loadHomeAdmin(); return; }·\u001b[39m\n\u001b[31m  const all  = await dbAll('subs');\u001b[39m\n\u001b[31m  const sy   = all.filter(s => s.status === 'synced').length;\u001b[39m\n\u001b[31m  const pe   = all.filter(s => s.status !== 'synced').length;·\u001b[39m\n\u001b[31m  // Fetch this agent's submissions from server — works on any device\u001b[39m\n\u001b[31m  let serverOnly = [];\u001b[39m\n\u001b[31m  let editAssigned = [];\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (navigator.onLine && hub?.empId) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?submitted_by=eq.${encodeURIComponent(hub.empId)}&order=submitted_at.desc&limit=200`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp.ok) {\u001b[39m\n\u001b[31m        const rows = await resp.json();\u001b[39m\n\u001b[31m        const localIds = new Set(all.map(s => s.id));\u001b[39m\n\u001b[31m        serverOnly = rows.filter(r => !localIds.has(r.sub_id));\u001b[39m\n\u001b[31m        _myServerRows = serverOnly;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m    // Fetch edit-assigned recces (supervisor assigned this creator to edit)\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp2 = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?edit_assigned_to=eq.${encodeURIComponent(hub.empId)}&deleted_at=is.null&order=submitted_at.desc`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp2.ok) editAssigned = await resp2.json();\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = sy + serverOnly.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = pe;\u001b[39m\n\u001b[31m  document.getElementById('stat-total').textContent   = all.length + serverOnly.length;·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!all.length && !serverOnly.length && !editAssigned.length) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">📋</div><div class=\\\"empty-txt\\\">No submissions yet</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const icos   = { synced:'✅', pending:'⏳', failed:'❌' };\u001b[39m\n\u001b[31m  const sorted = [...all].sort((a,b) => new Date(b.timestamp) - new Date(a.timestamp)).slice(0, 50);·\u001b[39m\n\u001b[31m  const localCards = sorted.map(s => {\u001b[39m\n\u001b[31m    const dt = new Date(s.timestamp);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const viewBtn = s.viewUrl\u001b[39m\n\u001b[31m      ? `<button class=\\\"edit-btn-sm\\\" onclick=\\\"window.open('${s.viewUrl}','_blank')\\\">👁 View</button>`\u001b[39m\n\u001b[31m      : `<button class=\\\"edit-btn-sm\\\" onclick=\\\"viewRecce('${s.id}')\\\">👁 View</button>`;\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico ${s.status}\\\">${icos[s.status]||'📋'}</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${s.data.storeName||'Unknown'} · ${s.data.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${s.data.address||''}</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge ${s.status}\\\">${s.status}</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          ${viewBtn}\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"editRecce('${s.id}')\\\" style=\\\"background:#fff7ed;border-color:var(--or);color:var(--or)\\\">✏ Edit</button>\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"makeSlides('${s.id}')\\\" style=\\\"background:#eff6ff;border-color:#3b82f6;color:#1d4ed8\\\">📊 Slides</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const serverCards = serverOnly.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const showPdf = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m    const pdfCls = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico synced\\\">✅</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\" style=\\\"min-width:0;flex:1\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"rpt-btns\\\" style=\\\"margin-top:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openMyServerRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m          ${showPdf ? `<button class=\\\"${pdfCls}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">📄 PDF</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge synced\\\">synced</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const editAssignedCards = editAssigned.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    return `<div class=\\\"edit-req-card\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:26px;flex-shrink:0\\\">✏</div>\u001b[39m\n\u001b[31m      <div class=\\\"edit-req-card-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-meta\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        ${r.edit_comment ? `<div class=\\\"edit-req-cmt\\\">\\\"${r.edit_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:10px;display:flex;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"startCreatorEdit('${r.sub_id}')\\\" style=\\\"padding:9px 16px;font-size:13px;font-weight:600\\\">✏ Edit this Recce</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (editAssignedCards.length) {\u001b[39m\n\u001b[31m    html += `<div class=\\\"edit-req-section-hdr\\\">✏ Edit Requested (${editAssignedCards.length})</div>`;\u001b[39m\n\u001b[31m    html += editAssignedCards.join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  html += localCards.join('') + serverCards.join('');\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m  const ls = await cfg('last-sync');\u001b[39m\n\u001b[31m  if (ls) {\u001b[39m\n\u001b[31m    const d = new Date(ls);\u001b[39m\n\u001b[31m    document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m      'Synced ' + d.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// RESET\u001b[39m\n\u001b[31mfunction startNewRecce(){F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  if(geoStampEnabled)autoRequestGPS();\u001b[39m\n\u001b[31m['f-date','f-brand','f-store','f-addr','f-mobile','f-client-other'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';});\u001b[39m\n\u001b[31m_selectedClient='';_clientOtherMode=false;\u001b[39m\n\u001b[31m_selectedCampaignId=null;_notifySupervisor=false;_brandingLocked=false;\u001b[39m\n\u001b[31mconst _camSel=document.getElementById('f-campaign-id');if(_camSel)_camSel.value='';\u001b[39m\n\u001b[31mconst _camNotice=document.getElementById('campaign-notify-msg');if(_camNotice)_camNotice.style.display='none';\u001b[39m\n\u001b[31mloadCampaignsForForm();\u001b[39m\n\u001b[31mrenderClientChips();\u001b[39m\n\u001b[31mdocument.getElementById('f-date').value=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31m// Block future dates\u001b[39m\n\u001b[31mdocument.getElementById('f-date').max=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31mdocument.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('pick-trigger-wrap').style.display=stores.length?'block':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').style.display=stores.length?'flex':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31mdocument.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31mdocument.getElementById('manual-fields').style.display=stores.length?'none':'block';\u001b[39m\n\u001b[31mdocument.getElementById('gps-status').textContent='';\u001b[39m\n\u001b[31m['vid-yes','vid-no','br-yes','br-no'].forEach(id=>document.getElementById(id).classList.remove('sel'));\u001b[39m\n\u001b[31mdocument.getElementById('vid-sec').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('vid-slot').innerHTML=`<div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('br-add').style.display='none';document.getElementById('br-items').innerHTML='';\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').classList.remove('filled');\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').innerHTML=`<div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('brand-selector').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('sc-missing').style.display='none';\u001b[39m\n\u001b[31mpopulateBrandDropdown();\u001b[39m\n\u001b[31mrenderPhotos('front');renderPhotos('inside');renderAddl();updAvailTag();showView('form-store');}\u001b[39m\n\u001b[31mfunction exitForm(){\u001b[39m\n\u001b[31m  // Show safe exit dialog instead of confirm\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitSaveAndLeave(){\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m  checkDraft();\u001b[39m\n\u001b[31m  toast('Draft saved — tap Resume to continue','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitDiscard(){\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];\u001b[39m\n\u001b[31m  videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  dbDel('draft','current');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitCancel(){document.getElementById('exit-dialog').classList.remove('open');}\u001b[39m\n\u001b[31mfunction showView(n){document.querySelectorAll('.view').forEach(v=>v.classList.remove('active'));const t=document.getElementById('view-'+n);if(t){t.classList.add('active');window.scrollTo(0,0);}}\u001b[39m\n\u001b[31mlet _tt;\u001b[39m\n\u001b[31mfunction toast(msg,type='info'){const el=document.getElementById('toast');el.textContent=msg;el.className='toast show '+type;clearTimeout(_tt);_tt=setTimeout(()=>el.classList.remove('show'),3000);}\u001b[39m\n\u001b[31mfunction netStatus(){const on=navigator.onLine;const dot=document.getElementById('net-dot');const txt=document.getElementById('net-txt');if(dot)dot.className='sdot '+(on?'on':'off');if(txt)txt.textContent=on?t('Online','ऑनलाइन'):t('Offline — saves locally','ऑफलाइन — स्थानीय रूप से सेव');}\u001b[39m\n\u001b[31masync function loadSettings(){\u001b[39m\n\u001b[31m  // Gas URL: pre-load default if none saved, update preview\u001b[39m\n\u001b[31m  const gu=await cfg('gas-url');\u001b[39m\n\u001b[31m  if(!gu)await cfg('gas-url',DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m  // Admin cfg url\u001b[39m\n\u001b[31m  const acu=await cfg('admin-cfg-url');if(acu&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=acu;\u001b[39m\n\u001b[31m  const su=await cfg('srv-url')||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su)document.getElementById('srv-url').value=su;\u001b[39m\n\u001b[31m  const sc=await cfg('stores');\u001b[39m\n\u001b[31m  if(sc){\u001b[39m\n\u001b[31m    stores=JSON.parse(sc);\u001b[39m\n\u001b[31m    const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m    document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m      `✓ ${stores.length} stores in cache${noBrand?` · ${noBrand} without brand`:''}`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const sf=await cfg('store-files');if(sf){_storeFiles=JSON.parse(sf);renderStoreFileList();}\u001b[39m\n\u001b[31m  const iq=await cfg('img-quality');imgQuality=iq||'compressed';applyQualityUI(imgQuality);\u001b[39m\n\u001b[31m  const gs=await cfg('geo-stamp');geoStampEnabled=(gs===null||gs==='1');applyGeoStampUI();\u001b[39m\n\u001b[31m  const bl=await cfg('brands');if(bl)brands=JSON.parse(bl);\u001b[39m\n\u001b[31m  loadBrandsFromDb();  // async — updates brands + logos from DB in background\u001b[39m\n\u001b[31m  renderBrandManageList();\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m  // Show store upload row + brand add row to supervisors only\u001b[39m\n\u001b[31m  const sur = document.getElementById('store-upload-row');\u001b[39m\n\u001b[31m  if (sur) sur.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const bar = document.getElementById('brand-add-row');\u001b[39m\n\u001b[31m  if (bar) bar.style.display = _isSupervisor() ? 'flex' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction populateBrandDropdown(){\u001b[39m\n\u001b[31m  const sel=document.getElementById('f-brand');if(!sel)return;\u001b[39m\n\u001b[31m  const cur=sel.value;\u001b[39m\n\u001b[31m  sel.innerHTML='<option value=\\\"\\\">Select brand</option>'+brands.map(b=>`<option${cur===b?' selected':''}>${b}</option>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderBrandManageList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('brand-manage-list');if(!el)return;\u001b[39m\n\u001b[31m  const isSup=_isSupervisor();\u001b[39m\n\u001b[31m  el.innerHTML=brands.map((b,i)=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    const logoHtml=logo?`<img src=\\\"${logo}\\\" style=\\\"height:20px;max-width:48px;object-fit:contain;flex-shrink:0;border-radius:3px\\\">`:'';\u001b[39m\n\u001b[31m    const ctrlHtml=isSup?`<div style=\\\"display:flex;gap:2px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"openEditBrandDialog(${i})\\\" style=\\\"background:none;border:none;color:var(--nv);font-size:15px;cursor:pointer;padding:2px 6px\\\" title=\\\"Edit\\\">✏</button>\u001b[39m\n\u001b[31m      ${brands.length>1?`<button onclick=\\\"confirmRemoveBrand(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:2px 4px\\\">×</button>`:'<span style=\\\"font-size:11px;color:var(--g400);padding:0 6px\\\">Last</span>'}\u001b[39m\n\u001b[31m    </div>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;min-width:0\\\">${logoHtml}<span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${b}</span></div>\u001b[39m\n\u001b[31m      ${ctrlHtml}\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function addBrandToList(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const inp=document.getElementById('brand-add-inp');\u001b[39m\n\u001b[31m  const val=(inp.value.trim()||'').toUpperCase();\u001b[39m\n\u001b[31m  if(!val){toast('Enter a brand name','error');return;}\u001b[39m\n\u001b[31m  if(brands.some(b=>b.toLowerCase()===val.toLowerCase())){toast(`${val} already in list`,'error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands`,{method:'POST',headers:{..._RC_WRITE,'Prefer':'return=minimal'},body:JSON.stringify({name:val,sort_order:99})});\u001b[39m\n\u001b[31m    if(resp.status===409){toast(`${val} already exists in DB`,'error');return;}\u001b[39m\n\u001b[31m    if(!resp.ok){const e=await resp.json().catch(()=>({}));throw new Error(e.message||resp.status);}\u001b[39m\n\u001b[31m    inp.value='';\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${val} added ✓`,'success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Add failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmRemoveBrand(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const name=brands[idx];\u001b[39m\n\u001b[31m  if(brands.length<=1){toast('Need at least one brand','error');return;}\u001b[39m\n\u001b[31m  let count=0;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(name)}&select=sub_id`,{headers:_RC_READ});\u001b[39m\n\u001b[31m    if(r.ok){const rows=await r.json();count=rows.length;}\u001b[39m\n\u001b[31m  }catch(_){}\u001b[39m\n\u001b[31m  const msg=count>0?`Delete \\\"${name}\\\" from brand list?\\\\n(${count} submission${count!==1?'s':''} reference this brand — they keep the name as text.)`:`Delete \\\"${name}\\\" from brand list?`;\u001b[39m\n\u001b[31m  if(!confirm(msg))return;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(name)}`,{method:'DELETE',headers:{'Content-Profile':'recce','Accept-Profile':'recce'}});\u001b[39m\n\u001b[31m    if(!resp.ok&&resp.status!==204){throw new Error(resp.status);}\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${name} removed ✓`,'info');\u001b[39m\n\u001b[31m  }catch(e){toast(`Remove failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadBrandsFromDb(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch('/db/brands?select=name,logo_url&order=sort_order',{\u001b[39m\n\u001b[31m      headers:{'Content-Profile':'recce','Accept-Profile':'recce'}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(!r.ok) return;\u001b[39m\n\u001b[31m    const rows=await r.json();\u001b[39m\n\u001b[31m    if(!rows||!rows.length) return;\u001b[39m\n\u001b[31m    const dbNames=rows.map(r=>r.name);\u001b[39m\n\u001b[31m    const logos={};rows.forEach(r=>{if(r.logo_url)logos[r.name]=r.logo_url;});\u001b[39m\n\u001b[31m    // Merge: DB brands canonical, keep locally-added extras\u001b[39m\n\u001b[31m    const extras=brands.filter(b=>!dbNames.some(n=>n.toLowerCase()===b.toLowerCase()));\u001b[39m\n\u001b[31m    brands=[...dbNames,...extras];\u001b[39m\n\u001b[31m    _brandLogos=logos;\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    // Refresh brand chips if brand-selector is visible\u001b[39m\n\u001b[31m    const bSel=document.getElementById('brand-selector');\u001b[39m\n\u001b[31m    if(bSel&&bSel.style.display!=='none') renderBrandChips();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[brands-db]',e.message);}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction renderBrandChips(){\u001b[39m\n\u001b[31m  const bChips=document.getElementById('brand-chips');if(!bChips)return;\u001b[39m\n\u001b[31m  bChips.innerHTML=brands.map(b=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    return `<div class=\\\"chip brand-chip${F.brand===b?' sel':''}\\\" onclick=\\\"selectStoreBrand('${b.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\">` +\u001b[39m\n\u001b[31m      (logo?`<img src=\\\"${logo}\\\" class=\\\"brand-chip-logo\\\" alt=\\\"\\\">`:'') +\u001b[39m\n\u001b[31m      `<span>${b}</span></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _editBrandIdx=null,_editBrandOld=null;\u001b[39m\n\u001b[31mfunction openEditBrandDialog(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor())return;\u001b[39m\n\u001b[31m  _editBrandIdx=idx;_editBrandOld=brands[idx];\u001b[39m\n\u001b[31m  document.getElementById('be-name').value=brands[idx];\u001b[39m\n\u001b[31m  const logo=_brandLogos[brands[idx]]||'';\u001b[39m\n\u001b[31m  document.getElementById('be-logo').value=logo;\u001b[39m\n\u001b[31m  document.getElementById('be-logo-preview').innerHTML=logo?`<img src=\\\"${logo}\\\" style=\\\"height:28px;object-fit:contain\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Current logo</span>`:'';\u001b[39m\n\u001b[31m  document.getElementById('be-cascade-info').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('brand-edit-modal').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeBrandEditModal(){document.getElementById('brand-edit-modal').classList.remove('open');_editBrandIdx=null;_editBrandOld=null;}\u001b[39m\n\u001b[31mfunction previewBrandLogo(){\u001b[39m\n\u001b[31m  const url=(document.getElementById('be-logo')?.value||'').trim();\u001b[39m\n\u001b[31m  const prev=document.getElementById('be-logo-preview');\u001b[39m\n\u001b[31m  if(prev)prev.innerHTML=url?`<img src=\\\"${url}\\\" style=\\\"height:28px;object-fit:contain\\\" onerror=\\\"this.style.display='none'\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Preview</span>`:'';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveBrandEdit(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const oldName=_editBrandOld;\u001b[39m\n\u001b[31m  const newName=(document.getElementById('be-name').value||'').trim().toUpperCase();\u001b[39m\n\u001b[31m  const newLogo=(document.getElementById('be-logo').value||'').trim();\u001b[39m\n\u001b[31m  if(!newName){toast('Brand name required','error');return;}\u001b[39m\n\u001b[31m  const isRename=newName!==oldName;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // 1. Update recce.brands\u001b[39m\n\u001b[31m    const pResp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m      method:'PATCH',headers:{..._RC_WRITE,'Prefer':'return=minimal'},\u001b[39m\n\u001b[31m      body:JSON.stringify({name:newName,logo_url:newLogo||null})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(pResp.status===409){toast(`\\\"${newName}\\\" already exists`,'error');return;}\u001b[39m\n\u001b[31m    if(!pResp.ok&&pResp.status!==204){const e=await pResp.json().catch(()=>({}));throw new Error(e.message||pResp.status);}\u001b[39m\n\u001b[31m    if(isRename){\u001b[39m\n\u001b[31m      const hub=_recceHubUser();\u001b[39m\n\u001b[31m      // 2. Cascade to submissions\u001b[39m\n\u001b[31m      await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m        method:'PATCH',headers:_RC_WRITE,body:JSON.stringify({brand:newName})\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      // 3. Cascade to stores.json + view HTML files + PDFs\u001b[39m\n\u001b[31m      toast('Cascading rename to reports…','info');\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        const cResp=await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},\u001b[39m\n\u001b[31m          body:JSON.stringify({type:'cascade-rename-brand',oldName,newName,empId:hub?.empId||''})});\u001b[39m\n\u001b[31m        const cRes=cResp.ok?await cResp.json():{};\u001b[39m\n\u001b[31m        const msg=`Brand renamed ✓${cRes.viewsUpdated?` · ${cRes.viewsUpdated} reports re-queued`:''}`;\u001b[39m\n\u001b[31m        closeBrandEditModal();\u001b[39m\n\u001b[31m        await loadBrandsFromDb();\u001b[39m\n\u001b[31m        toast(msg,'success');\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }catch(e){console.warn('[cascade-rename]',e.message);}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeBrandEditModal();\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast('Brand updated ✓','success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Save failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function fetchServerBrands(){\u001b[39m\n\u001b[31m  const url=document.getElementById('brands-url')?.value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    toast('Fetching brands…','info');\u001b[39m\n\u001b[31m    const r=await fetch(url);const j=await r.json();\u001b[39m\n\u001b[31m    const list=Array.isArray(j)?j:j.brands||[];\u001b[39m\n\u001b[31m    if(!list.length){toast('No brands found in response','error');return;}\u001b[39m\n\u001b[31m    brands=list.map(b=>b.toString().toUpperCase());\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    toast(`${brands.length} brands loaded from server`,'success');\u001b[39m\n\u001b[31m  }catch{toast('Failed to fetch — check URL','error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setImgQuality(q){\u001b[39m\n\u001b[31m  imgQuality=q;\u001b[39m\n\u001b[31m  cfg('img-quality',q);\u001b[39m\n\u001b[31m  applyQualityUI(q);\u001b[39m\n\u001b[31m  toast(q==='hd'?'HD Quality selected (~400–600 KB per photo)':'Full Compression selected (~150–200 KB per photo)','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction applyQualityUI(q){\u001b[39m\n\u001b[31m  ['compressed','hd'].forEach(opt=>{\u001b[39m\n\u001b[31m    const label=document.getElementById('q-opt-'+opt);\u001b[39m\n\u001b[31m    const radio=document.getElementById('q-radio-'+opt);\u001b[39m\n\u001b[31m    const dot  =document.getElementById('q-dot-'+opt);\u001b[39m\n\u001b[31m    if(!label)return;\u001b[39m\n\u001b[31m    const active=opt===q;\u001b[39m\n\u001b[31m    label.style.borderColor=active?'var(--or)':'var(--g200)';\u001b[39m\n\u001b[31m    label.style.background=active?'#fff7ed':'var(--g50)';\u001b[39m\n\u001b[31m    if(radio)radio.style.borderColor=active?'var(--or)':'var(--g300)';\u001b[39m\n\u001b[31m    if(dot)dot.style.display=active?'block':'none';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const badge=document.getElementById('q-current-badge');\u001b[39m\n\u001b[31m  if(badge){\u001b[39m\n\u001b[31m    const label=q==='hd'?'HD Quality (~400–600 KB)':'Full Compression (~150–200 KB)';\u001b[39m\n\u001b[31m    badge.innerHTML=`Active: <strong>${label}</strong>`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function clearData(){if(!confirm('Delete ALL local data?'))return;const all=await dbAll('subs');for(const s of all)await dbDel('subs',s.id);stores=[];await cfg('stores',null);toast('All cleared','success');loadHome();}\u001b[39m\n\u001b[31mif('serviceWorker' in navigator){const sw=`const C='recce-v37';self.addEventListener('install',e=>{e.waitUntil(caches.open(C).then(c=>c.add('/')));self.skipWaiting();});self.addEventListener('activate',e=>e.waitUntil(clients.claim()));self.addEventListener('fetch',e=>{if(e.request.method!=='GET')return;e.respondWith(caches.match(e.request).then(r=>{if(r)return r;return fetch(e.request).then(res=>{if(res&&res.status===200&&res.type==='basic'){const cl=res.clone();caches.open(C).then(c=>c.put(e.request,cl));}return res;}).catch(()=>caches.match('/'));}))}); `;const blob=new Blob([sw],{type:'application/javascript'});navigator.serviceWorker.register(URL.createObjectURL(blob),{scope:'/'}).catch(()=>{});}·\u001b[39m\n\u001b[31m// ── GEOLOCATION STAMP ────────────────────────────────────────\u001b[39m\n\u001b[31mfunction applyGeoStampUI(){\u001b[39m\n\u001b[31m  const tog=document.getElementById('geo-tog');\u001b[39m\n\u001b[31m  if(tog)tog.classList.toggle('on',geoStampEnabled);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function toggleGeoStamp(){\u001b[39m\n\u001b[31m  geoStampEnabled=!geoStampEnabled;\u001b[39m\n\u001b[31m  await cfg('geo-stamp',geoStampEnabled?'1':'0');\u001b[39m\n\u001b[31m  applyGeoStampUI();\u001b[39m\n\u001b[31m  toast(geoStampEnabled?'Geolocation stamp enabled':'Geolocation stamp disabled','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Auto-request GPS silently when a new recce starts\u001b[39m\n\u001b[31mfunction autoRequestGPS(){\u001b[39m\n\u001b[31m  if(!navigator.geolocation)return;\u001b[39m\n\u001b[31m  const statusEl=document.getElementById('geo-status');\u001b[39m\n\u001b[31m  if(statusEl)statusEl.textContent='Acquiring GPS…';\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(\u001b[39m\n\u001b[31m    pos=>{\u001b[39m\n\u001b[31m      gpsCoords={\u001b[39m\n\u001b[31m        lat:pos.coords.latitude.toFixed(6),\u001b[39m\n\u001b[31m        lng:pos.coords.longitude.toFixed(6),\u001b[39m\n\u001b[31m        acc:Math.round(pos.coords.accuracy)\u001b[39m\n\u001b[31m      };\u001b[39m\n\u001b[31m      const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m      const quality=acc<=15?'Excellent':acc<=50?'Good':acc<=200?'Fair':'Poor (cell tower)';\u001b[39m\n\u001b[31m      const color=acc<=15?'var(--gn)':acc<=50?'#16a34a':acc<=200?'var(--am)':'var(--rd)';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.innerHTML=`GPS: ${gpsCoords.lat}, ${gpsCoords.lng} · ±${acc}m · <span style=\\\"color:${color};font-weight:600\\\">${quality}</span>`;\u001b[39m\n\u001b[31m      // Update form GPS status too\u001b[39m\n\u001b[31m      const fs=document.getElementById('gps-status');\u001b[39m\n\u001b[31m      if(fs){fs.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${acc}m)`;fs.style.color='var(--gn)';}\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    err=>{\u001b[39m\n\u001b[31m      const msgs={1:'Location permission denied in Chrome',2:'GPS signal unavailable',3:'GPS timed out'};\u001b[39m\n\u001b[31m      const msg=msgs[err.code]||'GPS unavailable';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.textContent=msg+' — stamp will use store address';\u001b[39m\n\u001b[31m      if(err.code===1)toast('Tap the lock icon in Chrome address bar → allow Location','info');\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    {enableHighAccuracy:true,timeout:20000,maximumAge:60000}\u001b[39m\n\u001b[31m  );\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Draw stamp on a photo blob — returns new blob with stamp baked in\u001b[39m\n\u001b[31mfunction roundRectPath(ctx,x,y,w,h,r){\u001b[39m\n\u001b[31m  ctx.beginPath();ctx.moveTo(x+r,y);ctx.lineTo(x+w-r,y);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y,x+w,y+r);ctx.lineTo(x+w,y+h-r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);ctx.lineTo(x+r,y+h);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y+h,x,y+h-r);ctx.lineTo(x,y+r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y,x+r,y);ctx.closePath();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction fitText(ctx,text,maxW){\u001b[39m\n\u001b[31m  if(ctx.measureText(text).width<=maxW)return text;\u001b[39m\n\u001b[31m  while(text.length>1&&ctx.measureText(text+'…').width>maxW)text=text.slice(0,-1);\u001b[39m\n\u001b[31m  return text+'…';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction stampPhoto(blob){\u001b[39m\n\u001b[31m  if(!geoStampEnabled)return Promise.resolve(blob);\u001b[39m\n\u001b[31m  return new Promise(res=>{\u001b[39m\n\u001b[31m    const img=new Image(),url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    img.onload=()=>{\u001b[39m\n\u001b[31m      URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m      const W=img.width,H=img.height;\u001b[39m\n\u001b[31m      const c=document.createElement('canvas');c.width=W;c.height=H;\u001b[39m\n\u001b[31m      const ctx=c.getContext('2d');\u001b[39m\n\u001b[31m      ctx.drawImage(img,0,0);·\u001b[39m\n\u001b[31m      // Stamp dimensions — 18% of image height\u001b[39m\n\u001b[31m      const SH=Math.round(H*0.18);\u001b[39m\n\u001b[31m      const pad=Math.round(W*0.03);\u001b[39m\n\u001b[31m      const SY=H-SH;·\u001b[39m\n\u001b[31m      // Semi-transparent background\u001b[39m\n\u001b[31m      ctx.fillStyle='rgba(10,18,35,0.78)';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,SH);·\u001b[39m\n\u001b[31m      // Orange top accent line\u001b[39m\n\u001b[31m      ctx.fillStyle='#f97316';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,Math.max(3,Math.round(H*0.004)));·\u001b[39m\n\u001b[31m      // Font sizes scaled to image\u001b[39m\n\u001b[31m      const f1=Math.round(SH*0.26); // store name\u001b[39m\n\u001b[31m      const f2=Math.round(SH*0.22); // coords / address\u001b[39m\n\u001b[31m      const f3=Math.round(SH*0.20); // timestamp·\u001b[39m\n\u001b[31m      // Row Y centres\u001b[39m\n\u001b[31m      const r1=SY+SH*0.26;\u001b[39m\n\u001b[31m      const r2=SY+SH*0.55;\u001b[39m\n\u001b[31m      const r3=SY+SH*0.82;·\u001b[39m\n\u001b[31m      // Get stamp data\u001b[39m\n\u001b[31m      const storeName=F.storeName||selectedStore?.name||'';\u001b[39m\n\u001b[31m      const brand=F.brand||selectedStore?.brand||'';\u001b[39m\n\u001b[31m      const addr=F.address||selectedStore?.address||'';\u001b[39m\n\u001b[31m      const now=new Date();\u001b[39m\n\u001b[31m      const dateStr=now.toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m      const timeStr=now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit',hour12:true});·\u001b[39m\n\u001b[31m      // Badge (right side — GPS quality)\u001b[39m\n\u001b[31m      let badgeLabel='',badgeColor='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m        if(acc<=15){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=50){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=200){badgeLabel='~'+acc+'m';badgeColor='#d97706';}\u001b[39m\n\u001b[31m        else{badgeLabel='Cell ~'+acc+'m';badgeColor='#dc2626';}\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        badgeLabel='No GPS';badgeColor='#64748b';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      const bFontSz=Math.round(SH*0.18);\u001b[39m\n\u001b[31m      ctx.font=`bold ${bFontSz}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      const bW=Math.round(ctx.measureText(badgeLabel).width+pad);\u001b[39m\n\u001b[31m      const bH=Math.round(SH*0.32);\u001b[39m\n\u001b[31m      const bX=W-bW-pad;const bY=SY+(SH-bH)/2;\u001b[39m\n\u001b[31m      ctx.fillStyle=badgeColor+'cc';\u001b[39m\n\u001b[31m      roundRectPath(ctx,bX,bY,bW,bH,4);ctx.fill();\u001b[39m\n\u001b[31m      ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';\u001b[39m\n\u001b[31m      ctx.fillText(badgeLabel,bX+bW/2,bY+bH/2);\u001b[39m\n\u001b[31m      ctx.textAlign='left';ctx.textBaseline='alphabetic';·\u001b[39m\n\u001b[31m      const textMaxW=bX-pad*2;·\u001b[39m\n\u001b[31m      // Row 1 — store name + brand\u001b[39m\n\u001b[31m      ctx.font=`bold ${f1}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#ffffff';\u001b[39m\n\u001b[31m      const nameText=storeName+(brand?' · '+brand:'');\u001b[39m\n\u001b[31m      ctx.fillText('📍 '+fitText(ctx,nameText,textMaxW-f1*1.4),pad,r1);·\u001b[39m\n\u001b[31m      // Row 2 — GPS coords OR address\u001b[39m\n\u001b[31m      ctx.font=`${f2}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#cbd5e1';\u001b[39m\n\u001b[31m      let row2='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        row2=`Lat ${gpsCoords.lat}°   Long ${gpsCoords.lng}°`;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        row2=addr?fitText(ctx,addr,textMaxW):'GPS coordinates unavailable';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      ctx.fillText(row2,pad,r2);·\u001b[39m\n\u001b[31m      // Row 3 — date and time\u001b[39m\n\u001b[31m      ctx.font=`${f3}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#94a3b8';\u001b[39m\n\u001b[31m      ctx.fillText(`${dateStr}   ${timeStr}`,pad,r3);·\u001b[39m\n\u001b[31m      c.toBlob(b=>res(b||blob),'image/jpeg',imgQuality==='hd'?0.88:0.82);\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    img.onerror=()=>{URL.revokeObjectURL(url);res(blob);};\u001b[39m\n\u001b[31m    img.src=url;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _aTool='rect',_aColor='#f97316',_aWidth=4,_aTarget=-1;\u001b[39m\n\u001b[31mlet _aImg=null,_aHistory=[],_aDrawing=false,_aStart={},_aPts=[];\u001b[39m\n\u001b[31mlet _aSel=-1,_aDragMode=null,_aDragOff={x:0,y:0};\u001b[39m\n\u001b[31m// Larger hit radius on touch devices for easier finger selection\u001b[39m\n\u001b[31mconst HIT_R=()=>('ontouchstart' in window)?32:16;·\u001b[39m\n\u001b[31mfunction setATool(t){\u001b[39m\n\u001b[31m  _aTool=t;\u001b[39m\n\u001b[31m  ['rect','ellipse','line','arrow','free'].forEach(id=>{const el=document.getElementById('at-'+id);if(el)el.classList.toggle('on',id===t&&t!=='move');});\u001b[39m\n\u001b[31m  const mv=document.getElementById('at-move');if(mv)mv.classList.toggle('sel-on',t==='move');\u001b[39m\n\u001b[31m  const info=document.getElementById('annot-sel-info');if(info)info.style.display=t==='move'?'block':'none';\u001b[39m\n\u001b[31m  if(t!=='move'){_aSel=-1;redrawAnnot();}\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(cvs)cvs.style.cursor=t==='move'?'default':'crosshair';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAColor(c){\u001b[39m\n\u001b[31m  _aColor=c;\u001b[39m\n\u001b[31m  const m={'#f97316':'or','#ef4444':'rd','#ffffff':'wh','#facc15':'yw','#22c55e':'gn'};\u001b[39m\n\u001b[31m  Object.entries(m).forEach(([col,id])=>{const el=document.getElementById('ac-'+id);if(el)el.classList.toggle('on',col===c);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAWidth(w){_aWidth=w;[2,4,7].forEach(v=>{const el=document.getElementById('aw-'+v);if(el)el.classList.toggle('on',v===w);});}·\u001b[39m\n\u001b[31mfunction openAnnot(idx){\u001b[39m\n\u001b[31m  _aTarget=idx;_aHistory=[];_aDrawing=false;_aPts=[];_aSel=-1;_aDragMode=null;\u001b[39m\n\u001b[31m  document.getElementById('annot-modal').classList.add('open');\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');\u001b[39m\n\u001b[31m  const img=new Image(),url=URL.createObjectURL(brandings[idx].blob);\u001b[39m\n\u001b[31m  img.onload=()=>{\u001b[39m\n\u001b[31m    const sc=Math.min(1,window.innerWidth/img.width,(window.innerHeight-185)/img.height);\u001b[39m\n\u001b[31m    cvs.width=Math.round(img.width*sc);cvs.height=Math.round(img.height*sc);\u001b[39m\n\u001b[31m    _aImg=img;redrawAnnot();URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  img.src=url;\u001b[39m\n\u001b[31m  cvs.ontouchstart=aDown;cvs.ontouchmove=aMove;cvs.ontouchend=aUp;\u001b[39m\n\u001b[31m  cvs.onmousedown=aDown;cvs.onmousemove=aMove;cvs.onmouseup=aUp;\u001b[39m\n\u001b[31m  setATool('rect');setAColor('#f97316');setAWidth(4);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aPos(e){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const r=cvs.getBoundingClientRect();\u001b[39m\n\u001b[31m  const src=e.touches?e.touches[0]:e;\u001b[39m\n\u001b[31m  return{x:(src.clientX-r.left)*(cvs.width/r.width),y:(src.clientY-r.top)*(cvs.height/r.height)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Always return normalised (positive w,h) bounds\u001b[39m\n\u001b[31mfunction sBounds(s){\u001b[39m\n\u001b[31m  if(s.type==='free'){\u001b[39m\n\u001b[31m    if(!s.pts||!s.pts.length)return null;\u001b[39m\n\u001b[31m    const xs=s.pts.map(p=>p.x),ys=s.pts.map(p=>p.y);\u001b[39m\n\u001b[31m    const x=Math.min(...xs),y=Math.min(...ys);\u001b[39m\n\u001b[31m    return{x,y,w:Math.max(...xs)-x,h:Math.max(...ys)-y};\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  return{x:Math.min(s.x,s.x+s.w),y:Math.min(s.y,s.y+s.h),w:Math.abs(s.w),h:Math.abs(s.h)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction hitHandle(px,py,s){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return null;\u001b[39m\n\u001b[31m  const b=sBounds(s);const hr=HIT_R();\u001b[39m\n\u001b[31m  for(const[n,x,y]of[['tl',b.x,b.y],['tr',b.x+b.w,b.y],['bl',b.x,b.y+b.h],['br',b.x+b.w,b.y+b.h]])\u001b[39m\n\u001b[31m    if(Math.hypot(px-x,py-y)<hr)return n;\u001b[39m\n\u001b[31m  return null;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction hitShape(px,py,s){\u001b[39m\n\u001b[31m  const b=sBounds(s);if(!b)return false;\u001b[39m\n\u001b[31m  const pad=HIT_R();\u001b[39m\n\u001b[31m  return px>=b.x-pad&&px<=b.x+b.w+pad&&py>=b.y-pad&&py<=b.y+b.h+pad;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aDown(e){\u001b[39m\n\u001b[31m  e.preventDefault();const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'){\u001b[39m\n\u001b[31m    // Check handles of selected shape first\u001b[39m\n\u001b[31m    if(_aSel>=0&&_aSel<_aHistory.length){\u001b[39m\n\u001b[31m      const h=hitHandle(p.x,p.y,_aHistory[_aSel]);\u001b[39m\n\u001b[31m      if(h){_aDragMode='r-'+h;_aDragOff={x:p.x,y:p.y};_aDrawing=true;return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Hit test all shapes topmost first\u001b[39m\n\u001b[31m    for(let i=_aHistory.length-1;i>=0;i--){\u001b[39m\n\u001b[31m      if(hitShape(p.x,p.y,_aHistory[i])){\u001b[39m\n\u001b[31m        _aSel=i;_aDragMode='move';\u001b[39m\n\u001b[31m        const s=_aHistory[i];\u001b[39m\n\u001b[31m        const b=sBounds(s);\u001b[39m\n\u001b[31m        // Store offset from shape top-left corner (normalised)\u001b[39m\n\u001b[31m        _aDragOff={x:p.x-b.x,y:p.y-b.y};\u001b[39m\n\u001b[31m        _aDrawing=true;redrawAnnot();return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    _aSel=-1;redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _aDrawing=true;_aStart={x:p.x,y:p.y};if(_aTool==='free')_aPts=[{x:p.x,y:p.y}];\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aMove(e){\u001b[39m\n\u001b[31m  e.preventDefault();if(!_aDrawing)return;const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'&&_aDragMode){\u001b[39m\n\u001b[31m    const s=_aHistory[_aSel];if(!s)return;\u001b[39m\n\u001b[31m    if(_aDragMode==='move'){\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      // New top-left position\u001b[39m\n\u001b[31m      const nx=p.x-_aDragOff.x;\u001b[39m\n\u001b[31m      const ny=p.y-_aDragOff.y;\u001b[39m\n\u001b[31m      const dx=nx-b.x,dy=ny-b.y;\u001b[39m\n\u001b[31m      if(s.type==='free'){\u001b[39m\n\u001b[31m        s.pts=s.pts.map(pt=>({x:pt.x+dx,y:pt.y+dy}));\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        // Move preserving w/h sign (don't normalise — keep original drawing direction)\u001b[39m\n\u001b[31m        s.x+=dx;s.y+=dy;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Resize from corner — always work on normalised bounds then re-apply\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      const n=_aDragMode.slice(2);\u001b[39m\n\u001b[31m      let nx=b.x,ny=b.y,nw=b.w,nh=b.h;\u001b[39m\n\u001b[31m      if(n==='br'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,p.y-b.y);}\u001b[39m\n\u001b[31m      else if(n==='tl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,b.y+b.h-p.y);nx=p.x;ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='tr'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,b.y+b.h-p.y);ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='bl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,p.y-b.y);nx=p.x;}\u001b[39m\n\u001b[31m      s.x=nx;s.y=ny;s.w=nw;s.h=nh; // store as normalised going forward\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if(_aTool==='free'){_aPts.push({x:p.x,y:p.y});redrawAnnot();drawSh({type:'free',pts:[..._aPts],color:_aColor,lw:_aWidth},true);return;}\u001b[39m\n\u001b[31m  redrawAnnot();drawSh({type:_aTool,x:_aStart.x,y:_aStart.y,w:p.x-_aStart.x,h:p.y-_aStart.y,color:_aColor,lw:_aWidth},true);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction aUp(e){\u001b[39m\n\u001b[31m  if(!_aDrawing)return;_aDrawing=false;\u001b[39m\n\u001b[31m  if(_aTool==='move'){_aDragMode=null;return;}\u001b[39m\n\u001b[31m  const p=aPos(e||{touches:[{clientX:0,clientY:0}]});\u001b[39m\n\u001b[31m  if(_aTool==='free'){if(_aPts.length>2){_aHistory.push({type:'free',pts:[..._aPts],x:_aPts[0].x,y:_aPts[0].y,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  else{const w=p.x-_aStart.x,h=p.y-_aStart.y;if(Math.abs(w)>4||Math.abs(h)>4){_aHistory.push({type:_aTool,x:_aStart.x,y:_aStart.y,w,h,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  _aPts=[];redrawAnnot();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction redrawAnnot(){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.clearRect(0,0,cvs.width,cvs.height);if(_aImg)ctx.drawImage(_aImg,0,0,cvs.width,cvs.height);\u001b[39m\n\u001b[31m  _aHistory.forEach((s,i)=>{drawSh(s,false,ctx);if(_aTool==='move'&&i===_aSel)drawHandles(s,ctx);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawHandles(s,ctx){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return;const b=sBounds(s);ctx.save();\u001b[39m\n\u001b[31m  ctx.setLineDash([5,3]);ctx.strokeStyle='#facc15';ctx.lineWidth=1.5;ctx.strokeRect(b.x-2,b.y-2,b.w+4,b.h+4);ctx.setLineDash([]);\u001b[39m\n\u001b[31m  [[b.x,b.y],[b.x+b.w,b.y],[b.x,b.y+b.h],[b.x+b.w,b.y+b.h]].forEach(([x,y])=>{ctx.beginPath();ctx.arc(x,y,7,0,2*Math.PI);ctx.fillStyle='#f97316';ctx.fill();ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();});\u001b[39m\n\u001b[31m  ctx.restore();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawSh(s,preview=false,ctx){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(!ctx)ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.save();ctx.strokeStyle=s.color;ctx.lineWidth=preview?Math.max(s.lw||4,2):s.lw||4;\u001b[39m\n\u001b[31m  ctx.lineCap='round';ctx.lineJoin='round';ctx.setLineDash(preview?[6,3]:[]);\u001b[39m\n\u001b[31m  if(s.type==='rect'){ctx.strokeRect(s.x,s.y,s.w,s.h);ctx.fillStyle=s.color+'28';ctx.fillRect(s.x,s.y,s.w,s.h);}\u001b[39m\n\u001b[31m  else if(s.type==='ellipse'){const cx=s.x+s.w/2,cy=s.y+s.h/2;ctx.beginPath();ctx.ellipse(cx,cy,Math.abs(s.w/2),Math.abs(s.h/2),0,0,2*Math.PI);ctx.stroke();ctx.fillStyle=s.color+'28';ctx.fill();}\u001b[39m\n\u001b[31m  else if(s.type==='line'){ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(s.x+s.w,s.y+s.h);ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='arrow'){const ex=s.x+s.w,ey=s.y+s.h;ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(ex,ey);ctx.stroke();const a=Math.atan2(s.h,s.w),al=20,aa=0.4;ctx.setLineDash([]);ctx.beginPath();ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a-aa),ey-al*Math.sin(a-aa));ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a+aa),ey-al*Math.sin(a+aa));ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='free'){if(s.pts.length<2){ctx.restore();return;}ctx.beginPath();s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));ctx.stroke();}\u001b[39m\n\u001b[31m  ctx.setLineDash([]);ctx.restore();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction undoAnnot(){if(_aHistory.length){_aHistory.pop();_aSel=Math.min(_aSel,_aHistory.length-1);redrawAnnot();}}\u001b[39m\n\u001b[31mfunction clearAnnot(){_aHistory=[];_aSel=-1;redrawAnnot();}·\u001b[39m\n\u001b[31m// Bottom dialog\u001b[39m\n\u001b[31mlet _bdCb=null;\u001b[39m\n\u001b[31mfunction showBDialog(title,sub,onYes){\u001b[39m\n\u001b[31m  document.getElementById('bdialog-title').textContent=title;\u001b[39m\n\u001b[31m  document.getElementById('bdialog-sub').textContent=sub;\u001b[39m\n\u001b[31m  _bdCb=onYes;document.getElementById('bdialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction bdialogYes(){document.getElementById('bdialog').classList.remove('open');if(_bdCb)_bdCb();_bdCb=null;}\u001b[39m\n\u001b[31mfunction bdialogNo(){document.getElementById('bdialog').classList.remove('open');_bdCb=null;}·\u001b[39m\n\u001b[31mfunction _afterBrandingPhoto(){\u001b[39m\n\u001b[31m  const idx=_aTarget;\u001b[39m\n\u001b[31m  showBDialog(t(`Add reference photos for Branding ${idx+1}?`,`ब्रांडिंग ${idx+1} के लिए अतिरिक्त फोटो?`),t('Optional extra photos for future reference.','वैकल्पिक — भविष्य के लिए अतिरिक्त फोटो।'),()=>{showView('form-additional');setTimeout(()=>addAdditional(),200);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction skipAnnot(){document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo added (${fmtSz(brandings[_aTarget].blob.size)})`,'success');_afterBrandingPhoto();}\u001b[39m\n\u001b[31mfunction saveAnnot(){const cvs=document.getElementById('annot-cvs');cvs.toBlob(blob=>{brandings[_aTarget].blob=blob;brandings[_aTarget].prev=URL.createObjectURL(blob);document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo + markup saved (${fmtSz(blob.size)})`,'success');_afterBrandingPhoto();},'image/jpeg',0.88);}·\u001b[39m\n\u001b[31m// ── VIEW RECCE (read-only) ──────────────────────────────────\u001b[39m\n\u001b[31masync function viewRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  // Synced entries have a server-side rich report — open it directly\u001b[39m\n\u001b[31m  if(entry.viewUrl){window.open(entry.viewUrl,'_blank');return;}\u001b[39m\n\u001b[31m  // Offline / not-yet-synced fallback: generate from local base64 data\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  const ts=new Date(entry.timestamp).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'});·\u001b[39m\n\u001b[31m  async function b64ToUrl(b64){if(!b64)return'';try{const r=await fetch(b64);const bl=await r.blob();return URL.createObjectURL(bl);}catch{return'';}}·\u001b[39m\n\u001b[31m  const fvUrls=await Promise.all((d.frontPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const ivUrls=await Promise.all((d.insidePhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const brUrls=await Promise.all((d.brandings||[]).map(b=>b64ToUrl(b.photoB64)));\u001b[39m\n\u001b[31m  const adUrls=await Promise.all((d.addlPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const docUrl=await b64ToUrl(d.docB64);·\u001b[39m\n\u001b[31m  const brRows=(d.brandings||[]).map((b,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:16px;padding:12px;background:#f8fafc;border-radius:8px;border-left:3px solid #f97316\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-weight:600;font-size:14px;color:#0f172a;margin-bottom:6px\\\">${i+1}. ${b.type||'—'}: ${b.w||'?'}\\\"×${b.h||'?'}\\\" · Qty: ${b.qty||'?'} · ${b.sqft||'?'}</div>\u001b[39m\n\u001b[31m      ${brUrls[i]?`<img src=\\\"${brUrls[i]}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:6px\\\">`:'<div style=\\\"color:#94a3b8;font-size:12px\\\">No photo</div>'}\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  const html=`<!DOCTYPE html><html><head><meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m  <title>Recce — ${d.storeName||'Unknown'}</title>\u001b[39m\n\u001b[31m  <style>body{font-family:Arial,sans-serif;margin:0;padding:16px;background:#f1f5f9}\u001b[39m\n\u001b[31m  .card{background:#fff;border-radius:12px;padding:16px;margin-bottom:14px;box-shadow:0 1px 4px rgba(0,0,0,.08)}\u001b[39m\n\u001b[31m  h1{font-size:18px;color:#0f172a;margin:0 0 4px}h2{font-size:14px;color:#f97316;text-transform:uppercase;letter-spacing:.5px;margin:0 0 10px}\u001b[39m\n\u001b[31m  .meta{font-size:12px;color:#64748b;margin-bottom:12px}.photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}\u001b[39m\n\u001b[31m  img{width:100%;border-radius:8px;object-fit:cover}\u001b[39m\n\u001b[31m  .tag{display:inline-block;background:#0f172a;color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-right:4px}\u001b[39m\n\u001b[31m  @media print{body{background:#fff}.card{box-shadow:none}}</style></head><body>\u001b[39m\n\u001b[31m  <div class=\\\"card\\\">\u001b[39m\n\u001b[31m    <h1>${d.storeName||'Unknown Store'}</h1>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\"><span class=\\\"tag\\\">${d.brand||'No Brand'}</span>${d.address||''}</div>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\">📞 ${d.mobile||'—'} &nbsp;|&nbsp; 📅 ${d.date||'—'} &nbsp;|&nbsp; Submitted: ${ts}</div>\u001b[39m\n\u001b[31m    ${d.gpsCoords?`<div class=\\\"meta\\\">📍 ${d.gpsCoords.lat}, ${d.gpsCoords.lng} ±${d.gpsCoords.acc}m</div>`:''}\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${fvUrls.length?`<div class=\\\"card\\\"><h2>Front View Photos</h2><div class=\\\"photos\\\">${fvUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${ivUrls.length?`<div class=\\\"card\\\"><h2>Inside View Photos</h2><div class=\\\"photos\\\">${ivUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${d.hasVideo?`<div class=\\\"card\\\"><h2>Video</h2><div>${d.videoNote||'Video recorded'}</div></div>`:''}\u001b[39m\n\u001b[31m  ${(d.brandings||[]).length?`<div class=\\\"card\\\"><h2>Branding Items (${(d.brandings||[]).length})</h2>${brRows}</div>`:''}\u001b[39m\n\u001b[31m  ${adUrls.length?`<div class=\\\"card\\\"><h2>Additional Photos</h2><div class=\\\"photos\\\">${adUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${docUrl?`<div class=\\\"card\\\"><h2>Submission Document</h2><img src=\\\"${docUrl}\\\" style=\\\"width:100%;max-height:300px;object-fit:contain\\\"></div>`:''}\u001b[39m\n\u001b[31m  <div style=\\\"text-align:center;margin:16px 0\\\">\u001b[39m\n\u001b[31m    <button onclick=\\\"window.print()\\\" style=\\\"background:#f97316;color:#fff;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer\\\">🖨 Print / Save as PDF</button>\u001b[39m\n\u001b[31m    <button onclick=\\\"window.close()\\\" style=\\\"background:#e2e8f0;color:#475569;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer;margin-left:10px\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  </body></html>`;\u001b[39m\n\u001b[31m  const blob=new Blob([html],{type:'text/html'});\u001b[39m\n\u001b[31m  const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m  window.open(url,'_blank');\u001b[39m\n\u001b[31m  setTimeout(()=>URL.revokeObjectURL(url),30000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── EDIT OLD RECCE ───────────────────────────────────────────\u001b[39m\n\u001b[31masync function editRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=d.gpsCoords||null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  F.editingId=id;F.date=d.date||'';F.brand=d.brand||'';F.storeName=d.storeName||'';F.address=d.address||'';F.mobile=d.mobile||'';F.hasVideo=d.hasVideo;F.hasBranding=d.hasBranding;\u001b[39m\n\u001b[31m  async function b64ToBlob(b64){if(!b64)return null;try{const r=await fetch(b64);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m  toast('Loading recce data…','info');\u001b[39m\n\u001b[31m  for(const p of(d.frontPhotos||[])){const b=await b64ToBlob(p.b64);if(b)frontPhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const p of(d.insidePhotos||[])){const b=await b64ToBlob(p.b64);if(b)insidePhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const br of(d.brandings||[])){const b=await b64ToBlob(br.photoB64);brandings.push({type:br.type,w:br.w,h:br.h,qty:br.qty,blob:b,prev:b?URL.createObjectURL(b):null});}\u001b[39m\n\u001b[31m  for(const p of(d.addlPhotos||[])){const b=await b64ToBlob(p.b64);if(b)addlPhotos.push({blob:b,prev:URL.createObjectURL(b),desc:p.desc||''});}\u001b[39m\n\u001b[31m  if(d.docB64){const b=await b64ToBlob(d.docB64);if(b){submissionDoc=b;const sl=document.getElementById('doc-slot');sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${URL.createObjectURL(b)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}}\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  if(F.brand)document.getElementById('f-brand').value=F.brand;\u001b[39m\n\u001b[31m  if(F.storeName)document.getElementById('f-store').value=F.storeName;\u001b[39m\n\u001b[31m  if(F.address)document.getElementById('f-addr').value=F.address;\u001b[39m\n\u001b[31m  if(F.mobile)document.getElementById('f-mobile').value=F.mobile;\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();updAvailTag();\u001b[39m\n\u001b[31m  toast('Recce loaded — make changes and re-submit','success');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── EDIT REQUEST ────────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mlet _editReqSubId = null;·\u001b[39m\n\u001b[31mfunction _hydratePhotosFromRow(r) {\u001b[39m\n\u001b[31m  let pu={};\u001b[39m\n\u001b[31m  try{pu=typeof r.photo_urls==='string'?JSON.parse(r.photo_urls):(r.photo_urls||{});}catch(_){}\u001b[39m\n\u001b[31m  let meta={};\u001b[39m\n\u001b[31m  try{meta=typeof r.meta==='string'?JSON.parse(r.meta):(r.meta||{});}catch(_){}\u001b[39m\n\u001b[31m  frontPhotos =(pu.front   ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  insidePhotos=(pu.inside  ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  addlPhotos  =(pu.addl    ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,desc:''}));\u001b[39m\n\u001b[31m  brandings   =(meta.brandings||[]).map((b,i)=>({type:b.type,w:b.w,h:b.h,qty:b.qty,existingUrl:(pu.brandings||[])[i]||null,blob:null,prev:(pu.brandings||[])[i]||null}));\u001b[39m\n\u001b[31m  _docExistingUrl=pu.doc||null;\u001b[39m\n\u001b[31m  // Show retained doc in slot\u001b[39m\n\u001b[31m  const sl=document.getElementById('doc-slot');\u001b[39m\n\u001b[31m  if(sl&&_docExistingUrl){sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${_docExistingUrl}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openEditRequestModal(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  _editReqSubId = subId;\u001b[39m\n\u001b[31m  document.getElementById('er-store-name').textContent = r.store_name || 'Unknown';\u001b[39m\n\u001b[31m  document.getElementById('er-comment').value = '';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const assignBtn = document.getElementById('er-assign-btn');\u001b[39m\n\u001b[31m  if (r.submitted_by && r.submitted_by !== hub?.empId) {\u001b[39m\n\u001b[31m    assignBtn.textContent = `👤 Assign to ${r.submitted_by}`;\u001b[39m\n\u001b[31m    assignBtn.style.display = '';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    assignBtn.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeEditRequestModal() {\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _editReqSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorEditMyself() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  // Lock branding if client has reviewed (preserve their approval)\u001b[39m\n\u001b[31m  _brandingLocked = !!(r.client_status && r.client_status !== 'pending');\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function assignEditToCreator() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r || !r.submitted_by) { toast('No creator found for this recce', 'error'); return; }\u001b[39m\n\u001b[31m  const comment = (document.getElementById('er-comment').value || '').trim();\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        status: 'edit_requested',\u001b[39m\n\u001b[31m        edit_assigned_to: r.submitted_by,\u001b[39m\n\u001b[31m        edit_comment: comment || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!resp.ok) throw new Error('Update failed: ' + resp.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].status = 'edit_requested';\u001b[39m\n\u001b[31m      _adminRows[idx].edit_assigned_to = r.submitted_by;\u001b[39m\n\u001b[31m      _adminRows[idx].edit_comment = comment || null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Push notification to creator\u001b[39m\n\u001b[31m    const notifBody = comment || `Please review and re-submit: ${r.store_name || 'your recce'}`;\u001b[39m\n\u001b[31m    fetch('/push-server/notify', {\u001b[39m\n\u001b[31m      method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        user_id: r.submitted_by, title: '✏ Edit Requested',\u001b[39m\n\u001b[31m        body: notifBody, tag: `recce-edit-${subId}`, url: '/recce/',\u001b[39m\n\u001b[31m        icon: '/hub/icons/icon-192.png', badge: '/hub/icons/icon-192.png',\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    }).catch(() => {});\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast(`Edit assigned to ${r.submitted_by} ✓`, 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Assign failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function startCreatorEdit(subId) {\u001b[39m\n\u001b[31m  // Try local IndexedDB first (has photos)\u001b[39m\n\u001b[31m  const local = await dbGet('subs', subId);\u001b[39m\n\u001b[31m  if (local) { await editRecce(subId); return; }\u001b[39m\n\u001b[31m  // Fallback: load text fields from server row\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId)\u001b[39m\n\u001b[31m         || (await (async () => {\u001b[39m\n\u001b[31m              try {\u001b[39m\n\u001b[31m                const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, { headers: _RC_READ });\u001b[39m\n\u001b[31m                if (resp.ok) { const arr = await resp.json(); return arr[0]; }\u001b[39m\n\u001b[31m              } catch(_) {} return null;\u001b[39m\n\u001b[31m            })());\u001b[39m\n\u001b[31m  if (!r) { toast('Record not found', 'error'); return; }\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── End edit request ─────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mfunction goToHub() { window.location.href = '/hub/'; }\u001b[39m\n\u001b[31mfunction recceLogout() {\u001b[39m\n\u001b[31m  if (!confirm('Log out?')) return;\u001b[39m\n\u001b[31m  localStorage.removeItem('lm360-session');\u001b[39m\n\u001b[31m  localStorage.removeItem('360exp-session');\u001b[39m\n\u001b[31m  window.location.href = '/hub/';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction injectHubButtons() {\u001b[39m\n\u001b[31m  const u = _recceHubUser();\u001b[39m\n\u001b[31m  const name = u ? (u.name || '') : '';\u001b[39m\n\u001b[31m  if (name) {\u001b[39m\n\u001b[31m    const bar = document.getElementById('recce-hero-ubar');\u001b[39m\n\u001b[31m    const nm  = document.getElementById('recce-hero-name');\u001b[39m\n\u001b[31m    if (bar) { nm.textContent = name; bar.style.display = 'flex'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.querySelectorAll('.hdr').forEach(hdr => {\u001b[39m\n\u001b[31m    const r = document.createElement('div');\u001b[39m\n\u001b[31m    r.className = 'hdr-r';\u001b[39m\n\u001b[31m    if (name) {\u001b[39m\n\u001b[31m      const un = document.createElement('span');\u001b[39m\n\u001b[31m      un.className = 'hdr-user';\u001b[39m\n\u001b[31m      un.textContent = name;\u001b[39m\n\u001b[31m      r.appendChild(un);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    const hub = document.createElement('button');\u001b[39m\n\u001b[31m    hub.className = 'btn-hub';\u001b[39m\n\u001b[31m    hub.innerHTML = '🏡 Hub';\u001b[39m\n\u001b[31m    hub.addEventListener('click', goToHub);\u001b[39m\n\u001b[31m    r.appendChild(hub);\u001b[39m\n\u001b[31m    const lo = document.createElement('button');\u001b[39m\n\u001b[31m    lo.className = 'btn-logout';\u001b[39m\n\u001b[31m    lo.textContent = 'Logout';\u001b[39m\n\u001b[31m    lo.addEventListener('click', recceLogout);\u001b[39m\n\u001b[31m    r.appendChild(lo);\u001b[39m\n\u001b[31m    hdr.appendChild(r);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction checkAppUpdate(){\u001b[39m\n\u001b[31m  const seen=localStorage.getItem('recce-ver-seen');\u001b[39m\n\u001b[31m  localStorage.setItem('recce-ver-seen',CACHE_VER);\u001b[39m\n\u001b[31m  if(seen&&seen!==CACHE_VER){\u001b[39m\n\u001b[31m    const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m    if(b){b.classList.add('show');setTimeout(()=>b.classList.remove('show'),5000);}\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction dismissUpdateBanner(){\u001b[39m\n\u001b[31m  const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m  if(b)b.classList.remove('show');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function init(){\u001b[39m\n\u001b[31m  // Detect host banners (tiiny.host, etc) and raise bnav above them\u001b[39m\n\u001b[31m  (function detectHostBar(){\u001b[39m\n\u001b[31m    const h=window.location.hostname;\u001b[39m\n\u001b[31m    let extra=0;\u001b[39m\n\u001b[31m    if(h.includes('tiiny'))extra=58;\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // Generic detection: check if window is shorter than expected (host injected a bar)\u001b[39m\n\u001b[31m      const gap=screen.height - window.innerHeight;\u001b[39m\n\u001b[31m      if(gap>100&&gap<200)extra=58; // a fixed bar is roughly 56-60px\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if(extra>0){\u001b[39m\n\u001b[31m      document.documentElement.style.setProperty('--host-bar',extra+'px');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  })();\u001b[39m\n\u001b[31m  setLang(LANG);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m  checkAppUpdate();\u001b[39m\n\u001b[31m  await loadRecceCfg();\u001b[39m\n\u001b[31m  _checkAccessMode();\u001b[39m\n\u001b[31m  await initDB();await loadSettings();await loadHome();await checkDraft();netStatus();window.addEventListener('online',()=>{netStatus();syncNow();});window.addEventListener('offline',netStatus);injectHubButtons();document.getElementById('today-date').textContent=new Date().toLocaleDateString('en-IN',{weekday:'long',day:'numeric',month:'long',year:'numeric'});updAvailTag();\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m  // Auto-fetch stores from server on every startup (uses default Netlify URL if none saved)\u001b[39m\n\u001b[31m  const su=(await cfg('srv-url'))||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su&&navigator.onLine){\u001b[39m\n\u001b[31m    fetch(su).then(r=>r.json()).then(async j=>{\u001b[39m\n\u001b[31m      const d=Array.isArray(j)?j:j.stores||[];\u001b[39m\n\u001b[31m      if(d.length){stores=d;await cfg('stores',JSON.stringify(d));await cfg('srv-url',su);updAvailTag();\u001b[39m\n\u001b[31m        document.getElementById('srv-url').value=su;}\u001b[39m\n\u001b[31m    }).catch(()=>{});\u001b[39m\n\u001b[31m  }}init();\u001b[39m\n\u001b[31m</script>\u001b[39m\n\u001b[31m</body>\u001b[39m\n\u001b[31m</html>\u001b[39m\n\u001b[31m\"\u001b[39m",
                        "stack": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoContain\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // indexOf\u001b[22m\n\nExpected substring: \u001b[32m\"recce-v15\"\u001b[39m\nReceived string:    \u001b[31m\"<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\">\u001b[39m\n\u001b[31m<head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\">\u001b[39m\n\u001b[31m<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\\\">\u001b[39m\n\u001b[31m<meta name=\\\"theme-color\\\" content=\\\"#0f172a\\\">\u001b[39m\n\u001b[31m<meta name=\\\"apple-mobile-web-app-capable\\\" content=\\\"yes\\\">\u001b[39m\n\u001b[31m<title>Branding Recce</title>\u001b[39m\n\u001b[31m<link rel=\\\"manifest\\\" href=\\\"manifest.json\\\">\u001b[39m\n\u001b[31m<link rel=\\\"preconnect\\\" href=\\\"https://fonts.googleapis.com\\\">\u001b[39m\n\u001b[31m<link href=\\\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap\\\" rel=\\\"stylesheet\\\">\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--nv:#0f172a;--nv2:#1e293b;--or:#f97316;--orl:#fed7aa;--gn:#16a34a;--rd:#dc2626;--am:#d97706;--g50:#f8fafc;--g100:#f1f5f9;--g200:#e2e8f0;--g300:#cbd5e1;--g400:#94a3b8;--g500:#64748b;--g600:#475569;--r:12px;--rs:8px;--sh:0 1px 3px rgba(0,0,0,.1),0 1px 2px rgba(0,0,0,.06);--bnav-h:72px;--host-bar:0px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}\u001b[39m\n\u001b[31mbody{font-family:'DM Sans',sans-serif;background:var(--g50);color:var(--nv);min-height:100vh;overflow-x:hidden}\u001b[39m\n\u001b[31m.hdr{background:var(--nv);color:#fff;padding:0 16px;height:56px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}\u001b[39m\n\u001b[31m.hdr-l{display:flex;align-items:center;gap:10px}\u001b[39m\n\u001b[31m.hdr-title{font-size:16px;font-weight:600}.hdr-sub{font-size:11px;color:var(--g400)}\u001b[39m\n\u001b[31m.back-btn,.icon-btn{background:none;border:none;color:#fff;padding:8px;cursor:pointer;display:flex;align-items:center}\u001b[39m\n\u001b[31m.back-btn{margin-left:-8px}\u001b[39m\n\u001b[31m.pgbar{height:3px;background:var(--g200)}.pgfill{height:100%;background:var(--or);transition:width .3s}\u001b[39m\n\u001b[31m.view{display:none;min-height:calc(100vh - 56px);padding-bottom:calc(var(--bnav-h) + var(--host-bar) + 24px)}.view.active{display:block}\u001b[39m\n\u001b[31m.content{padding:16px}\u001b[39m\n\u001b[31m.card{background:#fff;border-radius:var(--r);padding:16px;box-shadow:var(--sh);margin-bottom:12px}\u001b[39m\n\u001b[31m.card-title{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;letter-spacing:.6px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between}\u001b[39m\n\u001b[31m.cnt-badge{background:var(--or);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;min-width:22px;text-align:center}\u001b[39m\n\u001b[31m.cnt-badge.gray{background:var(--g400)}\u001b[39m\n\u001b[31m.field{margin-bottom:16px}.field:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.field label{display:block;font-size:13px;font-weight:500;color:var(--g600);margin-bottom:6px}\u001b[39m\n\u001b[31m.req{color:var(--or);margin-left:2px}\u001b[39m\n\u001b[31m.field input,.field select,.field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;color:var(--nv);background:#fff;transition:border-color .15s;-webkit-appearance:none;appearance:none}\u001b[39m\n\u001b[31m.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--or)}\u001b[39m\n\u001b[31m.field input:read-only{background:var(--g50);color:var(--g600)}\u001b[39m\n\u001b[31m.field textarea{resize:vertical;min-height:68px}\u001b[39m\n\u001b[31m.field select{background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}\u001b[39m\n\u001b[31m.pslot{border:2px dashed var(--g300);border-radius:var(--r);min-height:110px;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all .15s;position:relative;overflow:hidden;text-align:center;padding:16px}\u001b[39m\n\u001b[31m.pslot:active{border-color:var(--or);background:var(--g50)}\u001b[39m\n\u001b[31m.pslot.filled{border-style:solid;border-color:var(--or);padding:0;min-height:0}\u001b[39m\n\u001b[31m.pslot img{width:100%;height:150px;object-fit:cover;border-radius:calc(var(--r) - 2px);display:block}\u001b[39m\n\u001b[31m.pslot-lbl{font-size:13px;color:var(--g400);margin-top:6px}.pslot-ico{font-size:28px;color:var(--g300)}\u001b[39m\n\u001b[31m.pbadge{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.premove{position:absolute;top:6px;right:6px;background:var(--rd);color:#fff;border:none;border-radius:50%;width:26px;height:26px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;z-index:5}\u001b[39m\n\u001b[31minput[type=file]{display:none}\u001b[39m\n\u001b[31m.rgroup{display:flex;gap:10px}\u001b[39m\n\u001b[31m.rbtn{flex:1;padding:13px;border:1.5px solid var(--g200);border-radius:var(--rs);text-align:center;cursor:pointer;font-size:14px;font-weight:500;color:var(--g500);transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.rbtn.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.chip-grid{display:flex;flex-wrap:wrap;gap:8px}\u001b[39m\n\u001b[31m.chip{padding:7px 12px;border:1.5px solid var(--g200);border-radius:20px;font-size:13px;color:var(--g600);cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.chip.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.brand-chip{display:flex;align-items:center;gap:6px;padding:5px 12px}\u001b[39m\n\u001b[31m.brand-chip-logo{width:28px;height:18px;object-fit:contain;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{display:block;width:100%;padding:15px;background:var(--or);color:#fff;border:none;border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:700;cursor:pointer;text-align:center;transition:background .15s}\u001b[39m\n\u001b[31m.btn-p:active{background:#ea6c05}.btn-p:disabled{background:var(--g300);cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-s{display:block;width:100%;padding:14px;background:#fff;color:var(--nv);border:1.5px solid var(--g200);border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:500;cursor:pointer;text-align:center}\u001b[39m\n\u001b[31m.btn-s:active{background:var(--g100)}\u001b[39m\n\u001b[31m.btn-o{display:inline-flex;align-items:center;gap:6px;padding:10px 16px;background:#fff;color:var(--or);border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer}\u001b[39m\n\u001b[31m.btn-o:active{background:var(--orl)}\u001b[39m\n\u001b[31m.btn-d{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;background:#fff;color:var(--rd);border:1.5px solid #fecaca;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:12px;cursor:pointer}\u001b[39m\n\u001b[31m.bnav{position:fixed;bottom:var(--host-bar);left:0;right:0;background:#fff;border-top:1px solid var(--g200);display:flex;padding:10px 16px;gap:10px;z-index:100}\u001b[39m\n\u001b[31m.hero{background:var(--nv);color:#fff;padding:20px 16px 24px}\u001b[39m\n\u001b[31m.hero-title{font-size:22px;font-weight:700;margin-bottom:2px}.hero-sub{font-size:13px;color:var(--g400)}\u001b[39m\n\u001b[31m.stats{display:flex;gap:10px;margin-top:16px}\u001b[39m\n\u001b[31m.scard{flex:1;background:rgba(255,255,255,.08);border-radius:var(--rs);padding:12px;text-align:center}\u001b[39m\n\u001b[31m.snum{font-size:22px;font-weight:700}.slbl{font-size:11px;color:var(--g400);margin-top:2px}\u001b[39m\n\u001b[31m.scard.g .snum{color:#4ade80}.scard.a .snum{color:#fbbf24}\u001b[39m\n\u001b[31m.new-btn{background:var(--or);color:#fff;border:none;border-radius:var(--r);padding:16px;font-family:'DM Sans',sans-serif;font-size:16px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:10px;cursor:pointer;width:100%;margin-bottom:10px}\u001b[39m\n\u001b[31m.new-btn:active{background:#ea6c05}\u001b[39m\n\u001b[31m.resume-btn{background:var(--nv2);color:#fff;border:none;border-radius:var(--r);padding:13px 16px;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;display:flex;align-items:center;justify-content:space-between;cursor:pointer;width:100%;margin-bottom:18px}\u001b[39m\n\u001b[31m.sub-card{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:10px;display:flex;align-items:center;gap:12px}\u001b[39m\n\u001b[31m.sub-ico{width:40px;height:40px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}\u001b[39m\n\u001b[31m.sub-ico.pending{background:#fef3c7}.sub-ico.synced{background:#dcfce7}.sub-ico.failed{background:#fee2e2}\u001b[39m\n\u001b[31m.sub-meta{flex:1;min-width:0}.sub-name{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.sub-dtl{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.sbadge{font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;flex-shrink:0}\u001b[39m\n\u001b[31m.sbadge.pending{background:#fef3c7;color:#92400e}.sbadge.synced{background:#dcfce7;color:#14532d}.sbadge.failed{background:#fee2e2;color:#991b1b}\u001b[39m\n\u001b[31m.sh{display:flex;align-items:center;justify-content:space-between;margin:20px 0 12px}\u001b[39m\n\u001b[31m.st{font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.toast{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 8px);left:16px;right:16px;background:var(--nv);color:#fff;padding:12px 16px;border-radius:var(--r);font-size:14px;z-index:1000;transform:translateY(120px);opacity:0;transition:all .3s;pointer-events:none}\u001b[39m\n\u001b[31m.toast.show{transform:translateY(0);opacity:1}.toast.success{background:#16a34a}.toast.error{background:var(--rd)}.toast.info{background:var(--nv2)}\u001b[39m\n\u001b[31m.srow{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:#fff;border-top:1px solid var(--g100);font-size:12px;color:var(--g500)}\u001b[39m\n\u001b[31m.sdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px}.sdot.on{background:var(--gn)}.sdot.off{background:var(--g300)}\u001b[39m\n\u001b[31m.set-item{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:8px}\u001b[39m\n\u001b[31m.set-lbl{font-size:14px;font-weight:600;color:var(--nv);margin-bottom:4px}\u001b[39m\n\u001b[31m.set-sub{font-size:12px;color:var(--g500);margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem{background:#fff;border-radius:var(--r);border:1.5px solid var(--g200);padding:14px;margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\u001b[39m\n\u001b[31m.bitem-title{font-size:14px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.dim-row{display:flex;gap:8px}.dim-row .field{flex:1}\u001b[39m\n\u001b[31m.sqft{display:inline-block;background:var(--g100);color:var(--g600);font-size:12px;padding:4px 10px;border-radius:20px;margin-top:6px}\u001b[39m\n\u001b[31m.divider{height:1px;background:var(--g100);margin:12px 0}\u001b[39m\n\u001b[31m.rev-lbl{font-size:12px;color:var(--g500);margin-bottom:2px}\u001b[39m\n\u001b[31m.rev-val{font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.rev-photos{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}\u001b[39m\n\u001b[31m.rev-thumb{width:56px;height:56px;object-fit:cover;border-radius:var(--rs)}\u001b[39m\n\u001b[31m.empty{text-align:center;padding:40px 20px;color:var(--g400)}.empty-ico{font-size:40px;margin-bottom:12px}.empty-txt{font-size:14px}\u001b[39m\n\u001b[31m/* store picker */\u001b[39m\n\u001b[31m.store-card{border:1.5px solid var(--g200);border-radius:var(--rs);padding:13px 14px;background:#fff;position:relative;cursor:pointer}\u001b[39m\n\u001b[31m.store-card:active{background:var(--g50)}\u001b[39m\n\u001b[31m.store-card-name{font-size:15px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.store-card-meta{font-size:13px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.store-card-change{position:absolute;top:11px;right:12px;background:none;border:none;color:var(--or);font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer}\u001b[39m\n\u001b[31m.brand-tag{display:inline-block;background:var(--nv);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-top:4px}\u001b[39m\n\u001b[31m.last-chip{display:inline-flex;align-items:center;gap:4px;background:#fef3c7;color:#92400e;font-size:11px;font-weight:500;padding:3px 9px;border-radius:20px;margin-left:6px}\u001b[39m\n\u001b[31m.pick-trigger{border:2px solid var(--or);border-radius:var(--rs);padding:14px 16px;background:#fff7ed;display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-size:15px;font-weight:600;color:var(--or)}\u001b[39m\n\u001b[31m.pick-trigger:active{background:#ffedd5;border-color:#ea6800}\u001b[39m\n\u001b[31m.manual-toggle{display:flex;align-items:center;gap:8px;padding:10px 14px;border:1.5px dashed var(--g300);border-radius:var(--rs);cursor:pointer;font-size:13px;color:var(--g600);margin-top:8px;user-select:none}\u001b[39m\n\u001b[31m/* client chip grid */\u001b[39m\n\u001b[31m.cl-chip-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}\u001b[39m\n\u001b[31m.cl-chip{padding:8px 14px;border-radius:20px;border:1.5px solid var(--g200);font-size:13px;font-weight:500;color:var(--g600);background:#fff;cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.cl-chip:active,.cl-chip.sel{background:var(--or);border-color:var(--or);color:#fff;font-weight:600}\u001b[39m\n\u001b[31m.cl-chip-other{border-style:dashed}\u001b[39m\n\u001b[31m.client-tag{display:inline-block;background:#e0f2fe;color:#0369a1;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-left:4px}\u001b[39m\n\u001b[31m.manual-toggle.on{border-color:var(--or);background:#fff7ed;color:var(--or)}\u001b[39m\n\u001b[31m/* picker overlay */\u001b[39m\n\u001b[31m.povl{display:none;position:fixed;inset:0;background:var(--g50);z-index:200;flex-direction:column}\u001b[39m\n\u001b[31m.povl.open{display:flex}\u001b[39m\n\u001b[31m.povl-hdr{background:var(--nv);padding:12px 16px;display:flex;align-items:center;gap:12px;flex-shrink:0}\u001b[39m\n\u001b[31m.psearch{flex:1;padding:10px 14px;border:none;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;background:rgba(255,255,255,.12);color:#fff;outline:none}\u001b[39m\n\u001b[31m.psearch::placeholder{color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.pcancel{background:none;border:none;color:rgba(255,255,255,.7);font-family:'DM Sans',sans-serif;font-size:14px;cursor:pointer;padding:4px;white-space:nowrap}\u001b[39m\n\u001b[31m.plist{overflow-y:auto;flex:1}\u001b[39m\n\u001b[31m.pitem{padding:14px 16px;border-bottom:.5px solid var(--g100);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px}\u001b[39m\n\u001b[31m.pitem:active{background:var(--g100)}\u001b[39m\n\u001b[31m.pi-name{font-size:15px;font-weight:600;color:var(--nv)}.pi-addr{font-size:12px;color:var(--g500);margin-top:2px}.pi-last{font-size:11px;color:var(--am);margin-top:2px}\u001b[39m\n\u001b[31m.pi-brand{font-size:11px;font-weight:700;padding:3px 8px;border-radius:20px;background:var(--nv);color:#fff;flex-shrink:0}\u001b[39m\n\u001b[31m.psec{padding:8px 16px 4px;font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;background:var(--g50)}\u001b[39m\n\u001b[31m.padd{padding:16px;text-align:center;font-size:14px;color:var(--or);font-weight:600;cursor:pointer;background:#fff7ed;border-top:1.5px dashed var(--or)}\u001b[39m\n\u001b[31m.gps-row{display:flex;gap:8px;margin-top:8px}\u001b[39m\n\u001b[31m.gps-btn{flex-shrink:0;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;color:var(--g500);display:flex;align-items:center;gap:6px}\u001b[39m\n\u001b[31m.gps-btn:active{background:var(--orl);border-color:var(--or);color:var(--or)}\u001b[39m\n\u001b[31m@keyframes spin{to{transform:rotate(360deg)}}.spin{animation:spin .7s linear infinite;display:inline-block}\u001b[39m\n\u001b[31m/* ANNOTATION TOOL */\u001b[39m\n\u001b[31m.annot-modal{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column}\u001b[39m\n\u001b[31m.annot-modal.open{display:flex}\u001b[39m\n\u001b[31m.annot-bar{background:var(--nv);padding:8px 12px;flex-shrink:0}\u001b[39m\n\u001b[31m.annot-row{display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap}\u001b[39m\n\u001b[31m.annot-row:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.atool{padding:6px 10px;background:rgba(255,255,255,.1);border:1.5px solid rgba(255,255,255,.2);border-radius:var(--rs);color:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:500;cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.atool.on{background:var(--or);border-color:var(--or)}\u001b[39m\n\u001b[31m.atool.sel-on{background:#7c3aed;border-color:#7c3aed}\u001b[39m\n\u001b[31m.acolor{width:24px;height:24px;border-radius:50%;border:2px solid rgba(255,255,255,.3);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.acolor.on{border-color:#fff;border-width:3px;transform:scale(1.15)}\u001b[39m\n\u001b[31m.annot-cvs-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#111;position:relative}\u001b[39m\n\u001b[31m#annot-cvs{max-width:100%;max-height:100%;display:block;touch-action:none;cursor:crosshair}\u001b[39m\n\u001b[31m.annot-foot{background:var(--nv);padding:10px 16px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.req-note{font-size:12px;color:var(--rd);margin-top:6px;font-weight:500}\u001b[39m\n\u001b[31m/* Bottom dialog */\u001b[39m\n\u001b[31m.bdialog-wrap{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:400;align-items:flex-end}\u001b[39m\n\u001b[31m.bdialog-wrap.open{display:flex}\u001b[39m\n\u001b[31m.bdialog{background:#fff;border-radius:var(--r) var(--r) 0 0;padding:20px 16px 32px;width:100%}\u001b[39m\n\u001b[31m.bdialog-title{font-size:16px;font-weight:700;color:var(--nv);margin-bottom:6px}\u001b[39m\n\u001b[31m.bdialog-sub{font-size:13px;color:var(--g500);margin-bottom:16px}\u001b[39m\n\u001b[31m.bdialog-btns{display:flex;gap:10px}\u001b[39m\n\u001b[31m/* Edit badge on sub-card */\u001b[39m\n\u001b[31m.edit-btn-sm{padding:5px 12px;background:var(--g50);border:1px solid var(--g200);border-radius:20px;font-family:'DM Sans',sans-serif;font-size:12px;color:var(--g600);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m/* Toggle switch */\u001b[39m\n\u001b[31m.tog{width:48px;height:26px;background:var(--g300);border-radius:13px;cursor:pointer;transition:background .2s;flex-shrink:0;position:relative;display:inline-block}\u001b[39m\n\u001b[31m.tog.on{background:var(--or)}\u001b[39m\n\u001b[31m.tog-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2);pointer-events:none}\u001b[39m\n\u001b[31m.tog.on .tog-knob{transform:translateX(22px)}\u001b[39m\n\u001b[31m/* ── ADMIN RECCE VIEW ── */\u001b[39m\n\u001b[31m.af-bar{background:var(--g100);padding:10px 16px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--g200);overflow:hidden}\u001b[39m\n\u001b[31m.af-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}\u001b[39m\n\u001b[31m.af-sel{width:100%;padding:8px 10px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv);cursor:pointer;\u001b[39m\n\u001b[31m  white-space:normal;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.af-sel:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.af-inp{width:100%;padding:8px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv)}\u001b[39m\n\u001b[31m.af-inp:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.grp-hdr{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;\u001b[39m\n\u001b[31m  letter-spacing:.5px;padding:14px 0 6px;border-bottom:1px solid var(--g200);margin-bottom:6px}\u001b[39m\n\u001b[31m.grp-hdr:first-child{padding-top:0}\u001b[39m\n\u001b[31m.asc{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:12px 14px;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;gap:6px;margin-bottom:8px;cursor:pointer;\u001b[39m\n\u001b[31m  transition:box-shadow .15s}\u001b[39m\n\u001b[31m.asc:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.asc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}\u001b[39m\n\u001b[31m.asc-name{font-size:14px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.asc-brand{display:inline-block;background:#fff7ed;color:var(--or);font-size:11px;\u001b[39m\n\u001b[31m  font-weight:600;padding:2px 8px;border-radius:20px;border:1px solid #fed7aa;white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chip{background:var(--g100);border-radius:20px;padding:2px 8px;font-size:11px;color:var(--g600);white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chips{display:flex;flex-wrap:wrap;gap:5px}\u001b[39m\n\u001b[31m.asc-agent{background:var(--nv);color:#fff;font-size:11px;font-weight:600;\u001b[39m\n\u001b[31m  padding:2px 8px;border-radius:20px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m/* Admin detail modal */\u001b[39m\n\u001b[31m.ardl-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:600;\u001b[39m\n\u001b[31m  display:flex;align-items:flex-end;justify-content:center}\u001b[39m\n\u001b[31m.ardl-box{background:#fff;border-radius:var(--r) var(--r) 0 0;width:100%;max-height:80vh;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ardl-hdr{display:flex;align-items:flex-start;justify-content:space-between;\u001b[39m\n\u001b[31m  padding:16px 16px 10px;border-bottom:1px solid var(--g200);gap:10px}\u001b[39m\n\u001b[31m.ardl-title{font-size:17px;font-weight:700;color:var(--nv);line-height:1.3}\u001b[39m\n\u001b[31m.ardl-body{flex:1;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:14px}\u001b[39m\n\u001b[31m.ardl-sec{display:flex;flex-direction:column;gap:6px}\u001b[39m\n\u001b[31m.ardl-lbl{font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.ardl-val{font-size:13px;color:var(--nv);line-height:1.5}\u001b[39m\n\u001b[31m.ardl-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\u001b[39m\n\u001b[31m/* Hub home button */\u001b[39m\n\u001b[31m.btn-hub{background:none;border:1px solid rgba(255,255,255,.25);color:rgba(255,255,255,.85);\u001b[39m\n\u001b[31m  font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;cursor:pointer;\u001b[39m\n\u001b[31m  display:flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-hub:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hdr-r{display:flex;align-items:center;gap:6px;margin-left:auto;flex-shrink:0}\u001b[39m\n\u001b[31m.hdr-user{font-size:11px;color:rgba(255,255,255,.7);white-space:nowrap;max-width:80px;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.btn-logout{background:none;border:1px solid rgba(255,255,255,.2);color:rgba(255,255,255,.7);font-size:11px;font-weight:600;padding:4px 8px;border-radius:20px;cursor:pointer;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-logout:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hero-ubar{display:flex;align-items:center;justify-content:space-between;padding-top:6px;margin-top:2px}\u001b[39m\n\u001b[31m.hero-uname{font-size:12px;color:rgba(255,255,255,.65)}\u001b[39m\n\u001b[31m.hi-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .en-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .hi-txt{display:inline}\u001b[39m\n\u001b[31m.lang-btn{background:none;border:1px solid rgba(255,255,255,.3);color:rgba(255,255,255,.8);font-size:12px;font-weight:700;padding:4px 10px;border-radius:20px;cursor:pointer;display:flex;align-items:center;gap:3px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.lang-btn:active{background:rgba(255,255,255,.15)}\u001b[39m\n\u001b[31m/* ── DELETE / AUDIT ── */\u001b[39m\n\u001b[31m.del-btn{background:none;border:none;padding:6px 8px;cursor:pointer;color:var(--g400);font-size:16px;flex-shrink:0;border-radius:var(--rs);transition:color .15s,background .15s}\u001b[39m\n\u001b[31m.del-btn:active{color:var(--rd);background:#fee2e2}\u001b[39m\n\u001b[31m.asc.deleted-row{background:#fff5f5;border:1px solid #fecaca;opacity:.85}\u001b[39m\n\u001b[31m.asc.deleted-row .asc-name{text-decoration:line-through;color:var(--g500)}\u001b[39m\n\u001b[31m.del-reason-tag{display:inline-block;background:#fee2e2;color:var(--rd);font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.del-by-txt{font-size:11px;color:var(--g400);margin-top:3px}\u001b[39m\n\u001b[31m.restore-btn{background:none;border:1.5px solid #bbf7d0;border-radius:20px;color:#16a34a;font-size:11px;font-weight:700;padding:3px 10px;cursor:pointer;white-space:nowrap;margin-top:5px}\u001b[39m\n\u001b[31m.restore-btn:active{background:#dcfce7}\u001b[39m\n\u001b[31m.sup-tile{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:20px 16px;cursor:pointer;display:flex;align-items:center;gap:14px;margin-bottom:12px;transition:box-shadow .15s}\u001b[39m\n\u001b[31m.sup-tile:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.sup-tile-ico{width:48px;height:48px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:26px;flex-shrink:0}\u001b[39m\n\u001b[31m.sup-tile-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.sup-tile-title{font-size:15px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.sup-tile-sub{font-size:12px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.del-toggle-btn{padding:6px 14px;border:1.5px solid var(--g200);border-radius:20px;background:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:600;color:var(--g500);cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.del-toggle-btn.active{background:#fee2e2;border-color:#fecaca;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1.5px solid var(--g200);border-radius:var(--r);margin-bottom:10px;cursor:pointer;transition:all .15s;font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.reason-opt:active{background:var(--g50)}\u001b[39m\n\u001b[31m.reason-opt.sel{border-color:var(--rd);background:#fff5f5;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt.danger{border-color:#fdba74;background:#fff7ed;color:#9a3412}\u001b[39m\n\u001b[31m.reason-opt.danger.sel{border-color:#c2410c;background:#fff1e6;color:#9a3412}\u001b[39m\n\u001b[31m#del-confirm-btn.no-reason{background:var(--g300)!important;cursor:default}\u001b[39m\n\u001b[31m@keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}\u001b[39m\n\u001b[31m.reason-opt-ico{font-size:22px;flex-shrink:0}\u001b[39m\n\u001b[31m/* ── APP UPDATE BANNER ── */\u001b[39m\n\u001b[31m.upd-banner{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);left:12px;right:12px;background:#16a34a;color:#fff;padding:11px 14px;border-radius:var(--r);display:flex;align-items:center;justify-content:space-between;gap:10px;z-index:550;box-shadow:0 4px 16px rgba(0,0,0,.18);transform:translateY(120px);opacity:0;transition:transform .35s ease,opacity .35s ease;pointer-events:none}\u001b[39m\n\u001b[31m.upd-banner.show{transform:translateY(0);opacity:1;pointer-events:auto}\u001b[39m\n\u001b[31m/* ── EDIT REQUEST ── */\u001b[39m\n\u001b[31m.req-edit-btn{padding:4px 10px;background:#fffbeb;border:1px solid #fde68a;border-radius:20px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:600;color:#92400e;cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.req-edit-btn:active{background:#fef3c7}\u001b[39m\n\u001b[31m.edit-req-badge{display:inline-block;background:#fef3c7;color:#92400e;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;white-space:nowrap}\u001b[39m\n\u001b[31m.edit-req-card{background:#fffbeb;border:1.5px solid #fde68a;border-radius:var(--r);padding:14px 16px;margin-bottom:10px;display:flex;align-items:flex-start;gap:12px}\u001b[39m\n\u001b[31m.edit-req-card-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.edit-req-card-name{font-size:14px;font-weight:600;color:var(--nv);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.edit-req-card-meta{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.edit-req-cmt{font-size:12px;color:#78350f;background:#fff;border:1px solid #fde68a;border-radius:var(--rs);padding:8px 10px;margin-top:8px;line-height:1.5}\u001b[39m\n\u001b[31m.edit-req-section-hdr{font-size:11px;font-weight:700;color:#92400e;text-transform:uppercase;letter-spacing:.5px;padding:10px 0 6px;border-bottom:1px solid #fde68a;margin-bottom:8px}\u001b[39m\n\u001b[31m.upd-banner-ok{background:rgba(255,255,255,.2);border:none;color:#fff;border-radius:20px;padding:5px 13px;font-size:12px;font-weight:600;cursor:pointer;font-family:'DM Sans',sans-serif;white-space:nowrap}\u001b[39m\n\u001b[31m.upd-banner-ok:active{background:rgba(255,255,255,.35)}\u001b[39m\n\u001b[31m/* ── FONT SIZE WIDGET ── */\u001b[39m\n\u001b[31m.fs-widget{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);right:12px;display:flex;align-items:center;gap:0;background:#fff;border:1.5px solid var(--g200);border-radius:24px;box-shadow:0 2px 8px rgba(0,0,0,.12);z-index:500;overflow:hidden;user-select:none}\u001b[39m\n\u001b[31m.fs-btn{background:none;border:none;cursor:pointer;padding:7px 11px;color:var(--g500);line-height:1;transition:background .15s}\u001b[39m\n\u001b[31m.fs-btn:active{background:var(--g100)}\u001b[39m\n\u001b[31m.fs-btn:disabled{color:var(--g300);cursor:default}\u001b[39m\n\u001b[31m.fs-label{font-size:11px;font-weight:700;color:var(--g500);padding:0 4px;pointer-events:none}\u001b[39m\n\u001b[31m/* Level 1 — Large (+15%) */\u001b[39m\n\u001b[31mbody.fs-1 .field label,body.fs-1 .card-title,body.fs-1 .set-lbl,body.fs-1 .set-sub,\u001b[39m\n\u001b[31mbody.fs-1 .hdr-title,body.fs-1 .hdr-sub,body.fs-1 .slbl,body.fs-1 .rev-lbl,body.fs-1 .rev-val,\u001b[39m\n\u001b[31mbody.fs-1 .rbtn,body.fs-1 .chip,body.fs-1 .btn-p,body.fs-1 .btn-s,body.fs-1 .btn-o,\u001b[39m\n\u001b[31mbody.fs-1 .bdialog-title,body.fs-1 .bdialog-sub,body.fs-1 .sub-name,body.fs-1 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-1 .pslot-lbl,body.fs-1 .bitem-title,body.fs-1 .pi-name,body.fs-1 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-1 .asc-name,body.fs-1 .new-btn,body.fs-1 .resume-btn,body.fs-1 .ardl-lbl,body.fs-1 .ardl-val{font-size:calc(1em * 1.15) !important}\u001b[39m\n\u001b[31m/* Level 2 — X-Large (+30%) */\u001b[39m\n\u001b[31mbody.fs-2 .field label,body.fs-2 .card-title,body.fs-2 .set-lbl,body.fs-2 .set-sub,\u001b[39m\n\u001b[31mbody.fs-2 .hdr-title,body.fs-2 .hdr-sub,body.fs-2 .slbl,body.fs-2 .rev-lbl,body.fs-2 .rev-val,\u001b[39m\n\u001b[31mbody.fs-2 .rbtn,body.fs-2 .chip,body.fs-2 .btn-p,body.fs-2 .btn-s,body.fs-2 .btn-o,\u001b[39m\n\u001b[31mbody.fs-2 .bdialog-title,body.fs-2 .bdialog-sub,body.fs-2 .sub-name,body.fs-2 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-2 .pslot-lbl,body.fs-2 .bitem-title,body.fs-2 .pi-name,body.fs-2 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-2 .asc-name,body.fs-2 .new-btn,body.fs-2 .resume-btn,body.fs-2 .ardl-lbl,body.fs-2 .ardl-val{font-size:calc(1em * 1.30) !important}\u001b[39m\n\u001b[31m/* Level 3 — XX-Large (+50%) */\u001b[39m\n\u001b[31mbody.fs-3 .field label,body.fs-3 .card-title,body.fs-3 .set-lbl,body.fs-3 .set-sub,\u001b[39m\n\u001b[31mbody.fs-3 .hdr-title,body.fs-3 .hdr-sub,body.fs-3 .slbl,body.fs-3 .rev-lbl,body.fs-3 .rev-val,\u001b[39m\n\u001b[31mbody.fs-3 .rbtn,body.fs-3 .chip,body.fs-3 .btn-p,body.fs-3 .btn-s,body.fs-3 .btn-o,\u001b[39m\n\u001b[31mbody.fs-3 .bdialog-title,body.fs-3 .bdialog-sub,body.fs-3 .sub-name,body.fs-3 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-3 .pslot-lbl,body.fs-3 .bitem-title,body.fs-3 .pi-name,body.fs-3 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-3 .asc-name,body.fs-3 .new-btn,body.fs-3 .resume-btn,body.fs-3 .ardl-lbl,body.fs-3 .ardl-val{font-size:calc(1em * 1.50) !important}\u001b[39m\n\u001b[31m/* Level 4 — Max (+70%) */\u001b[39m\n\u001b[31mbody.fs-4 .field label,body.fs-4 .card-title,body.fs-4 .set-lbl,body.fs-4 .set-sub,\u001b[39m\n\u001b[31mbody.fs-4 .hdr-title,body.fs-4 .hdr-sub,body.fs-4 .slbl,body.fs-4 .rev-lbl,body.fs-4 .rev-val,\u001b[39m\n\u001b[31mbody.fs-4 .rbtn,body.fs-4 .chip,body.fs-4 .btn-p,body.fs-4 .btn-s,body.fs-4 .btn-o,\u001b[39m\n\u001b[31mbody.fs-4 .bdialog-title,body.fs-4 .bdialog-sub,body.fs-4 .sub-name,body.fs-4 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-4 .pslot-lbl,body.fs-4 .bitem-title,body.fs-4 .pi-name,body.fs-4 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-4 .asc-name,body.fs-4 .new-btn,body.fs-4 .resume-btn,body.fs-4 .ardl-lbl,body.fs-4 .ardl-val{font-size:calc(1em * 1.70) !important}\u001b[39m\n\u001b[31m/* ── RECCE TILE ACTION BUTTONS ── */\u001b[39m\n\u001b[31m.rpt-btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid rgba(0,0,0,.06)}\u001b[39m\n\u001b[31m.rpt-btn{display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 14px;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;border:none;font-family:inherit;transition:background .15s,opacity .15s;flex:1;min-width:110px;letter-spacing:.1px;white-space:nowrap}\u001b[39m\n\u001b[31m.rpt-btn-report{background:#fff7ed;color:var(--or);border:1.5px solid var(--or)}\u001b[39m\n\u001b[31m.rpt-btn-report:active{background:#fed7aa}\u001b[39m\n\u001b[31m.rpt-btn-pdf{background:var(--g100);color:var(--g400);border:1.5px solid var(--g200)}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready{background:var(--or);color:#fff;border-color:transparent}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready:active{background:#ea6c00}\u001b[39m\n\u001b[31m/* PDF wait overlay */\u001b[39m\n\u001b[31m#pdf-wait-ov{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m</style>\u001b[39m\n\u001b[31m</head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<!-- PICKER OVERLAY -->\u001b[39m\n\u001b[31m<div class=\\\"povl\\\" id=\\\"povl\\\">\u001b[39m\n\u001b[31m  <div class=\\\"povl-hdr\\\">\u001b[39m\n\u001b[31m    <input class=\\\"psearch\\\" id=\\\"psearch\\\" type=\\\"text\\\" placeholder=\\\"Search store / दुकान खोजें…\\\" oninput=\\\"filterPicker(this.value)\\\" autocomplete=\\\"off\\\">\u001b[39m\n\u001b[31m    <button class=\\\"pcancel\\\" onclick=\\\"closePicker()\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"plist\\\" id=\\\"plist\\\"></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"app\\\">·\u001b[39m\n\u001b[31m<!-- HOME -->\u001b[39m\n\u001b[31m<div class=\\\"view active\\\" id=\\\"view-home\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hero\\\">\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;justify-content:space-between;align-items:center\\\">\u001b[39m\n\u001b[31m      <div><div class=\\\"hero-title\\\"><span class=\\\"en-txt\\\">Branding Recce</span><span class=\\\"hi-txt\\\">ब्रांडिंग रेकी</span></div><div class=\\\"hero-sub\\\" id=\\\"today-date\\\">—</div></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:6px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"lang-btn\\\" onclick=\\\"setLang(LANG==='en'?'hi':'en')\\\" id=\\\"lang-btn\\\" title=\\\"Switch language / भाषा बदलें\\\">EN | हि</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-hub\\\" onclick=\\\"goToHub()\\\">🏡 Hub</button>\u001b[39m\n\u001b[31m      <button class=\\\"icon-btn\\\" onclick=\\\"showView('settings')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12 15a3 3 0 100-6 3 3 0 000 6z\\\"/><path d=\\\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\\\"/></svg></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"hero-ubar\\\" id=\\\"recce-hero-ubar\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <span class=\\\"hero-uname\\\" id=\\\"recce-hero-name\\\"></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-logout\\\" onclick=\\\"recceLogout()\\\">Logout</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"stats\\\">\u001b[39m\n\u001b[31m      <div class=\\\"scard g\\\"><div class=\\\"snum\\\" id=\\\"stat-synced\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Synced</span><span class=\\\"hi-txt\\\">सिंक्ड</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard a\\\"><div class=\\\"snum\\\" id=\\\"stat-pending\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Pending</span><span class=\\\"hi-txt\\\">बाकी</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard\\\"><div class=\\\"snum\\\" id=\\\"stat-total\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Total</span><span class=\\\"hi-txt\\\">कुल</span></div></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <button class=\\\"new-btn\\\" onclick=\\\"startNewRecce()\\\"><svg width=\\\"20\\\" height=\\\"20\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">New Recce</span><span class=\\\"hi-txt\\\">नई रेकी</span></button>\u001b[39m\n\u001b[31m    <div id=\\\"resume-wrap\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"sh\\\"><span class=\\\"st\\\"><span class=\\\"en-txt\\\">Recent Submissions</span><span class=\\\"hi-txt\\\">हाल की सबमिशन</span></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"syncNow()\\\" id=\\\"sync-btn\\\" style=\\\"padding:7px 12px;font-size:12px\\\"><svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg><span class=\\\"en-txt\\\">Sync</span><span class=\\\"hi-txt\\\">सिंक</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"sub-list\\\"></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"srow\\\"><div><span class=\\\"sdot\\\" id=\\\"net-dot\\\"></span><span id=\\\"net-txt\\\"><span class=\\\"en-txt\\\">Checking…</span><span class=\\\"hi-txt\\\">जाँच…</span></span></div><span id=\\\"last-sync-txt\\\" style=\\\"font-size:11px\\\"><span class=\\\"en-txt\\\">Never synced</span><span class=\\\"hi-txt\\\">कभी सिंक नहीं</span></span></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- SETTINGS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-settings\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('home')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Settings</span><span class=\\\"hi-txt\\\">सेटिंग</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Brand List</span><span class=\\\"hi-txt\\\">ब्रांड सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Manage Brands</span><span class=\\\"hi-txt\\\">ब्रांड प्रबंधन</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">These appear in the brand dropdown and store picker. Add client brands as needed.</div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-manage-list\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-add-row\\\" style=\\\"display:none;gap:8px;align-items:center\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"brand-add-inp\\\" placeholder=\\\"Type brand name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addBrandToList()\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"addBrandToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Store Lists</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Supervisors can upload XLS/CSV store lists here. Updates sync to all devices via server.</span><span class=\\\"hi-txt\\\">सुपरवाइजर यहाँ XLS/CSV स्टोर सूची अपलोड कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m      <!-- Upload/Clear row — supervisor only -->\u001b[39m\n\u001b[31m      <div id=\\\"store-upload-row\\\" style=\\\"display:none;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;margin-top:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"document.getElementById('store-xl').click()\\\"><svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Add File</span><span class=\\\"hi-txt\\\">फ़ाइल जोड़ें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-d\\\" onclick=\\\"clearStoreList()\\\" style=\\\"font-size:12px\\\"><span class=\\\"en-txt\\\">Clear All Stores</span><span class=\\\"hi-txt\\\">सभी स्टोर हटाएं</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" id=\\\"store-push-btn\\\" onclick=\\\"pushStoresToServer()\\\" style=\\\"font-size:12px;display:none\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Push to Server</span><span class=\\\"hi-txt\\\">सर्वर पर पुश करें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"store-xl\\\" accept=\\\".xlsx,.xls,.csv\\\" onchange=\\\"handleStoreUpload(event)\\\">\u001b[39m\n\u001b[31m      <div id=\\\"store-count\\\" style=\\\"font-size:13px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"store-file-list\\\" style=\\\"margin-top:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Brand assignment dialog for files with no brand column -->\u001b[39m\n\u001b[31m    <div id=\\\"brand-assign-dialog\\\" style=\\\"display:none;margin-top:10px;padding:14px;background:#fff7ed;border:1.5px solid var(--or);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\">Which brand is this store list for?</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\" id=\\\"brand-assign-fname\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-assign-chips\\\" class=\\\"chip-grid\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"confirmBrandAssign()\\\" style=\\\"flex:2;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">Assign Brand</span><span class=\\\"hi-txt\\\">ब्रांड असाइन करें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"skipBrandAssign()\\\" style=\\\"flex:1;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">No Brand</span><span class=\\\"hi-txt\\\">कोई ब्रांड नहीं</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Server Store List URL (Admin)</span><span class=\\\"hi-txt\\\">सर्वर स्टोर सूची URL</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Admin pushes stores.json to any public URL. App auto-fetches on open and caches offline.</div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"srv-url\\\" placeholder=\\\"https://yourserver.com/stores.json\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"fetchServerStores()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Fetch Now</button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"saveServerUrl()\\\" style=\\\"padding:9px 14px;font-size:13px;width:auto\\\">Save URL</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Sync Endpoint</span><span class=\\\"hi-txt\\\">सिंक एंडपॉइंट</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Slides Generator</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Managed by admin. Deploy gas_slides.gs from /opt/slides-proxy/ to Google Apps Script and paste the URL here.</div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"slides-gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Not configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"slides-gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"saveSlidesGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Sheet Sync</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Legacy sync endpoint. Writes recce data to Google Sheet.</div>·\u001b[39m\n\u001b[31m      <!-- Locked state (default) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Endpoint configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Unlocked state (after admin login) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;align-items:center;gap:8px;margin-bottom:10px;padding:7px 12px;background:#dcfce7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          <span style=\\\"font-size:12px;color:#14532d;font-weight:600\\\">🔓 Admin mode active</span>\u001b[39m\n\u001b[31m          <button onclick=\\\"lockAdmin()\\\" style=\\\"margin-left:auto;background:none;border:none;color:#14532d;font-size:12px;cursor:pointer;font-weight:600\\\">Lock ×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"testEndpoint()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Test</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>·\u001b[39m\n\u001b[31m    <!-- Admin Login Modal -->\u001b[39m\n\u001b[31m    <div id=\\\"admin-login-modal\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m      <div style=\\\"background:#fff;border-radius:var(--r);padding:24px 20px;margin:20px;max-width:380px;width:100%;box-shadow:0 8px 32px rgba(0,0,0,.2)\\\">\u001b[39m\n\u001b[31m        <div style=\\\"font-size:17px;font-weight:700;color:var(--nv);margin-bottom:4px\\\">Admin Login</div>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:18px\\\">Enter admin password to unlock settings</div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m          <label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">Password</label>\u001b[39m\n\u001b[31m          <input type=\\\"password\\\" id=\\\"admin-pwd\\\" placeholder=\\\"Enter admin password\\\" style=\\\"width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px\\\" onkeydown=\\\"if(event.key==='Enter')verifyAdmin()\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div id=\\\"admin-error\\\" style=\\\"display:none;font-size:12px;color:var(--rd);margin-bottom:12px;padding:8px 12px;background:#fee2e2;border-radius:var(--rs)\\\">Incorrect password</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"verifyAdmin()\\\" style=\\\"flex:2;padding:13px\\\" id=\\\"admin-login-btn\\\">Login</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-s\\\" onclick=\\\"closeAdminLogin()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:14px;padding-top:14px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.4px;margin-bottom:8px\\\">Admin Password Config URL</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:8px\\\">URL to your admin.json file on server (contains hashed password)</div>\u001b[39m\n\u001b[31m          <input type=\\\"url\\\" id=\\\"admin-cfg-url\\\" placeholder=\\\"https://yourserver.com/admin.json\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px;margin-bottom:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveAdminCfgUrl()\\\" style=\\\"font-size:12px;padding:7px 12px;width:100%;justify-content:center\\\">Save Config URL</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Geolocation Stamp</span><span class=\\\"hi-txt\\\">जियोलोकेशन स्टैम्प</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;justify-content:space-between;gap:16px\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1\\\">\u001b[39m\n\u001b[31m          <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Stamp on Photos</span><span class=\\\"hi-txt\\\">फोटो पर स्टैम्प</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"set-sub\\\" style=\\\"margin-bottom:0\\\">Bakes GPS coordinates, store name and timestamp into every photo — visible in the image itself. Same as GPS Map Camera app. Default: On.</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"tog on\\\" id=\\\"geo-tog\\\" onclick=\\\"toggleGeoStamp()\\\"><div class=\\\"tog-knob\\\"></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"geo-status\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\">GPS not yet captured</div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Image Quality</span><span class=\\\"hi-txt\\\">फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Default Photo Quality</span><span class=\\\"hi-txt\\\">डिफ़ॉल्ट फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Applies to all photos — front view, inside view, branding, and additional. HD uses more storage and takes longer to sync on poor networks.</div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;gap:10px;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-compressed\\\" onclick=\\\"setImgQuality('compressed')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-compressed\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-compressed\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">Full Compression</span><span class=\\\"hi-txt\\\">पूर्ण कम्प्रेशन</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~150–200 KB · Max 1280px · Best for poor network</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-left:auto;font-size:11px;font-weight:700;color:var(--gn);background:#dcfce7;padding:3px 8px;border-radius:20px\\\"><span class=\\\"en-txt\\\">Recommended</span><span class=\\\"hi-txt\\\">अनुशंसित</span></div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-hd\\\" onclick=\\\"setImgQuality('hd')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-hd\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-hd\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">HD Quality</span><span class=\\\"hi-txt\\\">HD क्वालिटी</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~400–600 KB · Max 1920px · Better detail for print</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"q-current-badge\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Supervisor Config panel — shown only to supervisors via renderSupPanel() -->\u001b[39m\n\u001b[31m    <div id=\\\"sup-panel\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">🔐 Recce Access Config</span><span class=\\\"hi-txt\\\">🔐 रेकी एक्सेस कॉन्फ़िग</span></div>\u001b[39m\n\u001b[31m      <!-- Access mode — only H/P can change -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"mode-row\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Access Mode</span><span class=\\\"hi-txt\\\">एक्सेस मोड</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Public: any Hub user can submit Recces. Assigned: only Supervisors and Creators can access.</span><span class=\\\"hi-txt\\\">सार्वजनिक: कोई भी Hub यूजर। नियत: सिर्फ़ Supervisors और Creators।</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\" style=\\\"margin-bottom:8px;margin-top:8px\\\">\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-public\\\" onclick=\\\"setRecceMode('public')\\\"><span class=\\\"en-txt\\\">Public</span><span class=\\\"hi-txt\\\">सार्वजनिक</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-assigned\\\" onclick=\\\"setRecceMode('assigned')\\\"><span class=\\\"en-txt\\\">Assigned</span><span class=\\\"hi-txt\\\">नियत</span></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Supervisor list — view all + delete + create -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Supervisors</span><span class=\\\"hi-txt\\\">सुपरवाइजर</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can view all recces, delete with reason, and submit. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">सभी रेकी देख सकते हैं, कारण से हटा सकते हैं, और सबमिट कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"sup-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addSupervisor()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addSupervisor()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Creator list — creation only -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Creators</span><span class=\\\"hi-txt\\\">क्रिएटर्स</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can submit Recces only — no admin view or deletion rights. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">केवल रेकी सबमिट कर सकते हैं — एडमिन व्यू या डिलीट नहीं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"creator-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addCreator()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addCreator()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Client list — used for client portal scoping -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clients</span><span class=\\\"hi-txt\\\">क्लाइंट</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Names that appear as chips when submitting a recce. Add the brand or agency name (e.g. \\\"Marketing Vibe\\\"). These are used to scope what clients see in the Client Portal.</span><span class=\\\"hi-txt\\\">रेकी सबमिट करते समय दिखने वाले क्लाइंट नाम। ब्रांड या एजेंसी नाम जोड़ें।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-mgmt-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"client-add-inp\\\" placeholder=\\\"Client name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addClientToList()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addClientToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Sync to server — only H/P -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"cfg-sync-btn\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Sync Config to Server</span><span class=\\\"hi-txt\\\">सर्वर पर कॉन्फ़िग सिंक करें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Apply supervisor/creator/client lists and access mode to all devices.</span><span class=\\\"hi-txt\\\">सभी डिवाइस पर कॉन्फ़िग लागू करें।</span></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"syncCfgToServer()\\\" style=\\\"max-width:220px;font-size:14px;padding:12px;margin-top:8px\\\"><span class=\\\"en-txt\\\">Sync to Server</span><span class=\\\"hi-txt\\\">सर्वर पर सिंक करें</span></button>\u001b[39m\n\u001b[31m        <div id=\\\"cfg-sync-status\\\" style=\\\"margin-top:8px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Danger Zone</span><span class=\\\"hi-txt\\\">खतरनाक ज़ोन</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\"><div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clear All Local Data</span><span class=\\\"hi-txt\\\">सभी डेटा हटाएं</span></div><div class=\\\"set-sub\\\">Removes all submissions from this device.</div><button class=\\\"btn-d\\\" onclick=\\\"clearData()\\\" style=\\\"padding:9px 14px;font-size:13px\\\">Clear All</button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: STORE INFO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-store\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"exitForm()\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Details</span><span class=\\\"hi-txt\\\">दुकान विवरण</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 1 of 5</span><span class=\\\"hi-txt\\\">चरण 1 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:20%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Recce Info</span><span class=\\\"hi-txt\\\">रेकी जानकारी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Date of Recce</span><span class=\\\"hi-txt\\\">रेकी की तारीख</span> <span class=\\\"req\\\">*</span></label><input type=\\\"date\\\" id=\\\"f-date\\\" onchange=\\\"saveDraft()\\\" max=\\\"\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" id=\\\"campaign-field\\\">\u001b[39m\n\u001b[31m        <label><span class=\\\"en-txt\\\">Job / Campaign</span><span class=\\\"hi-txt\\\">जॉब / कैंपेन</span></label>\u001b[39m\n\u001b[31m        <select id=\\\"f-campaign-id\\\" onchange=\\\"onCampaignSelect()\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">Loading campaigns…</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <div id=\\\"campaign-notify-msg\\\" style=\\\"display:none;font-size:12px;color:#92400e;margin-top:6px;padding:8px 10px;background:#fef3c7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          ⚑ <span class=\\\"en-txt\\\">Recce will submit without a job ID. A notification will flag this for your supervisor to link it later.</span><span class=\\\"hi-txt\\\">रेकी बिना जॉब ID के सबमिट होगी। सुपरवाइजर बाद में लिंक करेगा।</span>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Store</span><span class=\\\"hi-txt\\\">दुकान</span> <span id=\\\"store-avail-tag\\\" style=\\\"font-size:11px;color:var(--g400);font-weight:400;text-transform:none;letter-spacing:0\\\"></span></div>·\u001b[39m\n\u001b[31m      <!-- When store is selected -->\u001b[39m\n\u001b[31m      <div id=\\\"store-selected\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"store-card\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:start;justify-content:space-between;gap:8px\\\">\u001b[39m\n\u001b[31m            <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m              <div class=\\\"store-card-name\\\" id=\\\"sc-name\\\">—</div>\u001b[39m\n\u001b[31m              <div style=\\\"display:flex;align-items:center;gap:6px;margin-top:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m                <span class=\\\"brand-tag\\\" id=\\\"sc-brand\\\">—</span>\u001b[39m\n\u001b[31m                <span class=\\\"last-chip\\\" id=\\\"sc-last\\\" style=\\\"display:none\\\">—</span>\u001b[39m\n\u001b[31m              </div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            <button class=\\\"store-card-change\\\" onclick=\\\"openPicker()\\\"><span class=\\\"en-txt\\\">Change ›</span><span class=\\\"hi-txt\\\">बदलें ›</span></button>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <!-- All fields from Excel shown here -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-details\\\" style=\\\"margin-top:10px;display:flex;flex-direction:column;gap:4px\\\"></div>\u001b[39m\n\u001b[31m          <!-- Missing required fields — editable inline -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-missing\\\" style=\\\"display:none;margin-top:12px;padding-top:12px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m            <div style=\\\"font-size:11px;font-weight:700;color:var(--rd);text-transform:uppercase;letter-spacing:.4px;margin-bottom:10px\\\">⚠ Please complete missing fields</div>\u001b[39m\n\u001b[31m            <div id=\\\"sc-missing-fields\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <!-- Brand selector — shown when store has no brand -->\u001b[39m\n\u001b[31m        <div id=\\\"brand-selector\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\"><span class=\\\"en-txt\\\">Select Brand</span><span class=\\\"hi-txt\\\">ब्रांड चुनें</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\">This store has no brand in the list — select one:</div>\u001b[39m\n\u001b[31m          <div id=\\\"brand-chips\\\" class=\\\"chip-grid\\\"></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Picker trigger (shown when stores loaded) -->\u001b[39m\n\u001b[31m      <div id=\\\"pick-trigger-wrap\\\">\u001b[39m\n\u001b[31m        <div class=\\\"pick-trigger\\\" onclick=\\\"openPicker()\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:center;gap:10px\\\">\u001b[39m\n\u001b[31m            <span style=\\\"font-size:20px\\\">🏪</span>\u001b[39m\n\u001b[31m            <div>\u001b[39m\n\u001b[31m              <div style=\\\"font-size:15px;font-weight:700;color:var(--or)\\\"><span class=\\\"en-txt\\\">Select Store from List</span><span class=\\\"hi-txt\\\">सूची से दुकान चुनें</span></div>\u001b[39m\n\u001b[31m              <div id=\\\"store-avail-count\\\" style=\\\"font-size:12px;font-weight:400;color:var(--am);margin-top:1px\\\"><span class=\\\"en-txt\\\">Tap to browse stores</span><span class=\\\"hi-txt\\\">दुकान खोजने के लिए दबाएं</span></div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual / new store toggle -->\u001b[39m\n\u001b[31m      <div class=\\\"manual-toggle\\\" id=\\\"manual-toggle\\\" onclick=\\\"toggleManual()\\\">\u001b[39m\n\u001b[31m        <svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\" id=\\\"mt-icon\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg>\u001b[39m\n\u001b[31m        <span id=\\\"mt-label\\\"><span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span></span>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual fields -->\u001b[39m\n\u001b[31m      <div id=\\\"manual-fields\\\" style=\\\"display:none;margin-top:14px\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\" style=\\\"margin-bottom:14px\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <select id=\\\"f-brand\\\" onchange=\\\"onManualBrandChange()\\\">\u001b[39m\n\u001b[31m            <option value=\\\"\\\">Select brand</option>\u001b[39m\n\u001b[31m          </select>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span> <span class=\\\"req\\\">*</span></label><input type=\\\"text\\\" id=\\\"f-store\\\" placeholder=\\\"Enter store name\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\">\u001b[39m\n\u001b[31m          <label><span class=\\\"en-txt\\\">Store Address</span><span class=\\\"hi-txt\\\">दुकान का पता</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <textarea id=\\\"f-addr\\\" rows=\\\"2\\\" placeholder=\\\"Full address\\\" onchange=\\\"saveDraft()\\\"></textarea>\u001b[39m\n\u001b[31m          <div class=\\\"gps-row\\\">\u001b[39m\n\u001b[31m            <button class=\\\"gps-btn\\\" onclick=\\\"captureGPS()\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\"/><path d=\\\"M12 2v3M12 19v3M2 12h3M19 12h3\\\"/></svg><span class=\\\"en-txt\\\">Capture GPS</span><span class=\\\"hi-txt\\\">GPS लें</span></button>\u001b[39m\n\u001b[31m            <span id=\\\"gps-status\\\" style=\\\"font-size:12px;color:var(--g500);align-self:center\\\"></span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Mobile No.</span><span class=\\\"hi-txt\\\">मोबाइल नंबर</span></label><input type=\\\"tel\\\" id=\\\"f-mobile\\\" placeholder=\\\"10-digit number\\\" maxlength=\\\"10\\\" inputmode=\\\"numeric\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Client card -->\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Client</span><span class=\\\"hi-txt\\\">क्लाइंट</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\"><span class=\\\"en-txt\\\">Select who this recce is for. Defaults to brand — change if work came via an agency.</span><span class=\\\"hi-txt\\\">यह रेकी किसके लिए है चुनें। ब्रांड से डिफ़ॉल्ट — एजेंसी के ज़रिए हो तो बदलें।</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"cl-chip-grid\\\" id=\\\"client-chips\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"client-other-wrap\\\" style=\\\"display:none;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"f-client-other\\\" placeholder=\\\"Type client name\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" oninput=\\\"onClientOtherInput()\\\">\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-p\\\" onclick=\\\"step2()\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: PHOTOS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-photos\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-store')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Photos</span><span class=\\\"hi-txt\\\">दुकान की फोटो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 2 of 5</span><span class=\\\"hi-txt\\\">चरण 2 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:40%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Front View</span><span class=\\\"hi-txt\\\">आगे का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(min 1, max 3)</span><span class=\\\"cnt-badge gray\\\" id=\\\"front-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"front-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-front\\\" onclick=\\\"addPhoto('front')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Front Photo</span><span class=\\\"hi-txt\\\">आगे की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Inside View</span><span class=\\\"hi-txt\\\">अंदर का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 5)</span><span class=\\\"cnt-badge gray\\\" id=\\\"inside-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"inside-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-inside\\\" onclick=\\\"addPhoto('inside')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Inside Photo</span><span class=\\\"hi-txt\\\">अंदर की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-store')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step3()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: VIDEO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-video\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-photos')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Recce Video</span><span class=\\\"hi-txt\\\">रेकी वीडियो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 3 of 5</span><span class=\\\"hi-txt\\\">चरण 3 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:60%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Video</span><span class=\\\"hi-txt\\\">वीडियो</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Recce video available?</span><span class=\\\"hi-txt\\\">रेकी वीडियो है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"vid-yes\\\" onclick=\\\"setVideo(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"vid-no\\\" onclick=\\\"setVideo(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"vid-sec\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Upload Video</span><span class=\\\"hi-txt\\\">वीडियो अपलोड करें</span></label>\u001b[39m\n\u001b[31m          <div class=\\\"pslot\\\" id=\\\"vid-slot\\\" onclick=\\\"document.getElementById('vid-inp').click()\\\"><div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div></div>\u001b[39m\n\u001b[31m          <input type=\\\"file\\\" id=\\\"vid-inp\\\" accept=\\\"video/*\\\" onchange=\\\"handleVideo(event)\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Video Comments</span><span class=\\\"hi-txt\\\">वीडियो टिप्पणी</span></label><input type=\\\"text\\\" id=\\\"f-vid-cmt\\\" placeholder=\\\"Optional\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-photos')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step4()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: BRANDING -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-branding\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-video')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Branding</span><span class=\\\"hi-txt\\\">ब्रांडिंग</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 4 of 5</span><span class=\\\"hi-txt\\\">चरण 4 / 5</span></div></div></div>\u001b[39m\n\u001b[31m    <span id=\\\"br-hdr-badge\\\" style=\\\"background:rgba(255,255,255,.2);color:#fff;font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px\\\"><span class=\\\"en-txt\\\">0 items</span><span class=\\\"hi-txt\\\">0 आइटम</span></span>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:80%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Branding Space</span><span class=\\\"hi-txt\\\">ब्रांडिंग स्थान</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Space available?</span><span class=\\\"hi-txt\\\">जगह उपलब्ध है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"br-yes\\\" onclick=\\\"setBranding(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"br-no\\\" onclick=\\\"setBranding(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"branding-lock-banner\\\" style=\\\"display:none;background:#fef3c7;border:1.5px solid #f59e0b;border-radius:10px;padding:12px 14px;margin-bottom:10px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:700;color:#92400e\\\">Client approval exists — branding locked</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:#78350f;margin-top:4px\\\"><span class=\\\"en-txt\\\">The client has reviewed this recce. Create a new recce to revise branding items.</span><span class=\\\"hi-txt\\\">क्लाइंट ने रेकी की समीक्षा की है। बदलाव के लिए नई रेकी बनाएं।</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"branding-override-wrap\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m        <button onclick=\\\"unlockBrandingOverride()\\\" style=\\\"background:#f59e0b;color:#000;border:none;border-radius:8px;padding:8px 14px;font-size:12px;font-weight:700;cursor:pointer\\\">Override Edit (H&amp;P only)</button>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:11px;color:#92400e;margin-top:5px\\\">Use only when client has verbally confirmed and app needs correction.</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"br-items\\\"></div>\u001b[39m\n\u001b[31m    <div id=\\\"br-add\\\" style=\\\"display:none;margin-bottom:80px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"addBranding()\\\" style=\\\"width:100%;justify-content:center\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Another Branding Item</span><span class=\\\"hi-txt\\\">एक और ब्रांडिंग जोड़ें</span></button>\u001b[39m\n\u001b[31m      <div style=\\\"text-align:center;font-size:12px;color:var(--g400);margin-top:8px\\\"><span class=\\\"en-txt\\\">Tap Continue below when done adding items</span><span class=\\\"hi-txt\\\">सभी आइटम जोड़ने के बाद आगे दबाएं</span></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-video')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step5()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: ADDITIONAL + SUBMIT -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-additional\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-branding')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Submit</span><span class=\\\"hi-txt\\\">सबमिट</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 5 of 5</span><span class=\\\"hi-txt\\\">चरण 5 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:100%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Mandatory Document</span><span class=\\\"hi-txt\\\">अनिवार्य दस्तावेज़</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"pslot\\\" id=\\\"doc-slot\\\" onclick=\\\"document.getElementById('doc-inp').click()\\\"><div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div></div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"doc-inp\\\" accept=\\\"image/*,.pdf\\\" onchange=\\\"handleDoc(event)\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Additional Photos</span><span class=\\\"hi-txt\\\">अतिरिक्त फोटो</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 8)</span><span class=\\\"cnt-badge gray\\\" id=\\\"addl-badge\\\">0 / 8</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"add-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-addl\\\" onclick=\\\"addAdditional()\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\"><div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Review</span><span class=\\\"hi-txt\\\">समीक्षा</span></div><div id=\\\"rev-body\\\"></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-branding')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"submitRecce()\\\" id=\\\"sub-btn\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Submit Recce ✓</span><span class=\\\"hi-txt\\\">रेकी सबमिट करें ✓</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- ANNOTATION MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"annot-modal\\\" id=\\\"annot-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"annot-bar\\\">\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Draw:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"at-rect\\\"    onclick=\\\"setATool('rect')\\\">▭ Rect</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-ellipse\\\" onclick=\\\"setATool('ellipse')\\\">◯ Ellipse</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-line\\\"    onclick=\\\"setATool('line')\\\">╱ Line</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-arrow\\\"   onclick=\\\"setATool('arrow')\\\">↗ Arrow</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-free\\\"    onclick=\\\"setATool('free')\\\">✏ Free</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool sel-on\\\" id=\\\"at-move\\\" onclick=\\\"setATool('move')\\\" style=\\\"margin-left:4px\\\">⊹ Move</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Color:</span>\u001b[39m\n\u001b[31m      <div class=\\\"acolor on\\\" id=\\\"ac-or\\\" style=\\\"background:#f97316\\\" onclick=\\\"setAColor('#f97316')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-rd\\\" style=\\\"background:#ef4444\\\" onclick=\\\"setAColor('#ef4444')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-wh\\\" style=\\\"background:#ffffff\\\" onclick=\\\"setAColor('#ffffff')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-yw\\\" style=\\\"background:#facc15\\\" onclick=\\\"setAColor('#facc15')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-gn\\\" style=\\\"background:#22c55e\\\" onclick=\\\"setAColor('#22c55e')\\\"></div>\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Width:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-2\\\" onclick=\\\"setAWidth(2)\\\" style=\\\"padding:5px 8px\\\">Thin</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"aw-4\\\" onclick=\\\"setAWidth(4)\\\" style=\\\"padding:5px 8px\\\">Med</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-7\\\" onclick=\\\"setAWidth(7)\\\" style=\\\"padding:5px 8px\\\">Thick</button>\u001b[39m\n\u001b[31m      <div style=\\\"flex:1\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"undoAnnot()\\\">↩</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"clearAnnot()\\\">✕</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"annot-sel-info\\\" style=\\\"display:none;font-size:11px;color:#facc15;padding:4px 0 2px\\\">\u001b[39m\n\u001b[31m      Shape selected — drag to move · drag corners to resize · tap elsewhere to deselect\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-cvs-wrap\\\"><canvas id=\\\"annot-cvs\\\"></canvas></div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-foot\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-s\\\" onclick=\\\"skipAnnot()\\\" style=\\\"flex:1;padding:12px;font-size:14px\\\"><span class=\\\"en-txt\\\">Skip markup</span><span class=\\\"hi-txt\\\">मार्कअप छोड़ें</span></button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" onclick=\\\"saveAnnot()\\\" style=\\\"flex:2;padding:12px\\\"><span class=\\\"en-txt\\\">Done — Save ✓</span><span class=\\\"hi-txt\\\">हो गया — सेव करें ✓</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EXIT DIALOG -->\u001b[39m\n\u001b[31m<!-- MODAL: Link Job to Recce (supervisor only) -->\u001b[39m\n\u001b[31m<div id=\\\"modal-link-job\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m  <div style=\\\"background:#fff;border-radius:14px;padding:20px;width:90%;max-width:380px;display:flex;flex-direction:column;gap:12px;box-shadow:0 8px 32px rgba(0,0,0,.35)\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:15px;font-weight:700;color:#1e293b\\\">&#x1F517; Link Job to Recce</div>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-store\\\" style=\\\"font-size:13px;color:#64748b\\\"></div>\u001b[39m\n\u001b[31m    <select id=\\\"link-job-sel\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m      <option value=\\\"\\\">&#x2014; Select campaign &#x2014;</option>\u001b[39m\n\u001b[31m    </select>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-err\\\" style=\\\"font-size:12px;color:#ef4444;min-height:14px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"closeLinkJobModal()\\\" style=\\\"flex:1;padding:12px;border:1px solid #cbd5e1;border-radius:8px;cursor:pointer;background:#f8fafc;font-size:14px\\\">Cancel</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"saveLinkJob()\\\" style=\\\"flex:2;padding:12px;background:#f59e0b;color:#000;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:700\\\">&#x1F517; Link Job</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"exit-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Exit Recce?</span><span class=\\\"hi-txt\\\">रेकी से बाहर?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Your progress and photos will be saved as a draft. Resume anytime from the home screen.</span><span class=\\\"hi-txt\\\">आपकी प्रगति और फोटो ड्राफ्ट में सेव होंगी। होम स्क्रीन से कभी भी जारी रखें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"exitSaveAndLeave()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">💾 Save Draft & Exit</span><span class=\\\"hi-txt\\\">💾 ड्राफ्ट सेव करें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-d\\\" onclick=\\\"exitDiscard()\\\" style=\\\"flex:1;padding:13px;font-size:13px\\\"><span class=\\\"en-txt\\\">Discard</span><span class=\\\"hi-txt\\\">हटाएं</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"exitCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">← Continue Recce</span><span class=\\\"hi-txt\\\">← रेकी जारी रखें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- PHOTO SOURCE PICKER -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"photo-src-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Camera photos get GPS stamp baked in. Gallery photos are added without stamp.</span><span class=\\\"hi-txt\\\">कैमरा फोटो में GPS स्टैम्प लगती है। गैलरी फोटो में नहीं।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"photoSrcCamera()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">📷 Use Camera</span><span class=\\\"hi-txt\\\">📷 कैमरा</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">GPS stamp applied</span><span class=\\\"hi-txt\\\">GPS स्टैम्प लगेगी</span></span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"photoSrcGallery()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">🖼 Choose from Gallery</span><span class=\\\"hi-txt\\\">🖼 गैलरी से चुनें</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">No stamp</span><span class=\\\"hi-txt\\\">स्टैम्प नहीं</span></span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"photoSrcCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- STORE PREVIEW DIALOG -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"store-preview-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:80vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"store-preview-title\\\"><span class=\\\"en-txt\\\">Preview Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची का प्रीव्यू</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Review before adding to your store list:</span><span class=\\\"hi-txt\\\">जोड़ने से पहले जाँचें:</span></div>\u001b[39m\n\u001b[31m    <div style=\\\"overflow-x:auto;margin-bottom:14px\\\">\u001b[39m\n\u001b[31m      <table style=\\\"width:100%;border-collapse:collapse;font-size:12px\\\">\u001b[39m\n\u001b[31m        <thead><tr style=\\\"background:var(--nv);color:#fff\\\">\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Address</span><span class=\\\"hi-txt\\\">पता</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Mobile</span><span class=\\\"hi-txt\\\">मोबाइल</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span></th>\u001b[39m\n\u001b[31m        </tr></thead>\u001b[39m\n\u001b[31m        <tbody id=\\\"store-preview-body\\\"></tbody>\u001b[39m\n\u001b[31m      </table>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"confirmStorePreview()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">✓ Confirm & Add Stores</span><span class=\\\"hi-txt\\\">✓ स्टोर जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"cancelStorePreview()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BOTTOM DIALOG (branding additional photo prompt) -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"bdialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add reference photos?</span><span class=\\\"hi-txt\\\">संदर्भ फोटो जोड़ें?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Add extra photos for this branding item for future reference.</span><span class=\\\"hi-txt\\\">इस ब्रांडिंग आइटम के लिए अतिरिक्त फोटो जोड़ें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"bdialogYes()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">Yes, add photos</span><span class=\\\"hi-txt\\\">हाँ, जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"bdialogNo()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Skip</span><span class=\\\"hi-txt\\\">छोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- DELETE REASON MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"delete-reason-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"padding-bottom:28px;max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">🗑 Delete Recce</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"del-modal-sub\\\">Select reason for deletion:</div>\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-wrong\\\" onclick=\\\"selectDeleteReason('wrong')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">❌</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Wrong</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Incorrect store / submission error</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-duplicate\\\" onclick=\\\"selectDeleteReason('duplicate')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">📋</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Duplicate</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Same store submitted more than once</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt danger\\\" id=\\\"reason-test\\\" onclick=\\\"selectDeleteReason('test')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">⚠️</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Test Recce</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:#9a3412;margin-top:2px\\\">Permanently deleted — no audit trail</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p no-reason\\\" id=\\\"del-confirm-btn\\\" onclick=\\\"confirmDelete()\\\" style=\\\"flex:2;padding:13px;background:var(--rd)\\\">Delete</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"closeDeleteModal()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EDIT REQUEST MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"edit-req-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Request Edit</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"er-store-name\\\" style=\\\"font-weight:600;color:var(--nv);margin-bottom:4px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:14px\\\">Add a note for the creator (optional)</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m      <textarea id=\\\"er-comment\\\" placeholder=\\\"e.g. Please re-check store address and re-upload front photo\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;color:var(--nv);resize:vertical;min-height:80px;background:#fff\\\"></textarea>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button id=\\\"er-assign-btn\\\" class=\\\"btn-p\\\" onclick=\\\"assignEditToCreator()\\\" style=\\\"padding:14px\\\">👤 Assign to Creator</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"supervisorEditMyself()\\\" style=\\\"padding:14px\\\">✏ Edit Myself</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"closeEditRequestModal()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BRAND EDIT MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"brand-edit-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Edit Brand</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Brand Name <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"text\\\" id=\\\"be-name\\\" placeholder=\\\"e.g. PHILIPS\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:600;text-transform:uppercase\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Logo URL <span style=\\\"font-size:11px;font-weight:400;color:var(--g400)\\\">(optional)</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"url\\\" id=\\\"be-logo\\\" placeholder=\\\"https://…/logo.svg\\\" oninput=\\\"previewBrandLogo()\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px\\\">\u001b[39m\n\u001b[31m      <div id=\\\"be-logo-preview\\\" style=\\\"margin-top:8px;min-height:36px;display:flex;align-items:center;gap:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"be-cascade-info\\\" style=\\\"display:none;font-size:12px;color:var(--g500);padding:8px 12px;background:var(--g50);border-radius:var(--rs);margin-bottom:12px\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"saveBrandEdit()\\\" style=\\\"padding:14px\\\">Save</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"closeBrandEditModal()\\\" style=\\\"width:100%;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FONT SIZE WIDGET -->\u001b[39m\n\u001b[31m<div class=\\\"fs-widget\\\" id=\\\"fs-widget\\\">\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-dec\\\" onclick=\\\"changeFontSize(-1)\\\" title=\\\"Decrease font size\\\" aria-label=\\\"Decrease font size\\\">A<sup style=\\\"font-size:9px\\\">−</sup></button>\u001b[39m\n\u001b[31m  <span class=\\\"fs-label\\\" id=\\\"fs-lbl\\\">A</span>\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-inc\\\" onclick=\\\"changeFontSize(1)\\\" title=\\\"Increase font size\\\" aria-label=\\\"Increase font size\\\"><strong>A</strong><sup style=\\\"font-size:9px\\\">+</sup></button>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"upd-banner\\\" id=\\\"upd-banner\\\">\u001b[39m\n\u001b[31m  <span style=\\\"font-size:13px;font-weight:600;line-height:1.4\\\"><span class=\\\"en-txt\\\">✓ App updated to latest version</span><span class=\\\"hi-txt\\\">✓ ऐप नया संस्करण अपडेट हुआ</span></span>\u001b[39m\n\u001b[31m  <button class=\\\"upd-banner-ok\\\" onclick=\\\"dismissUpdateBanner()\\\"><span class=\\\"en-txt\\\">OK</span><span class=\\\"hi-txt\\\">ठीक है</span></button>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m<div class=\\\"toast\\\" id=\\\"toast\\\"></div>\u001b[39m\n\u001b[31m<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js\\\"></script>\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m// LANGUAGE\u001b[39m\n\u001b[31mlet LANG = localStorage.getItem('recce-lang') || 'en';\u001b[39m\n\u001b[31mfunction setLang(l) {\u001b[39m\n\u001b[31m  LANG = l;\u001b[39m\n\u001b[31m  localStorage.setItem('recce-lang', l);\u001b[39m\n\u001b[31m  document.body.classList.toggle('lang-hi', l === 'hi');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction t(en, hi) { return LANG === 'hi' ? hi : en; }·\u001b[39m\n\u001b[31m// FONT SIZE\u001b[39m\n\u001b[31mlet FS_LEVEL = parseInt(localStorage.getItem('recce-fs') || '0', 10);\u001b[39m\n\u001b[31mconst FS_LABELS = ['A', 'A+', 'A++', 'A+++', 'A++++'];\u001b[39m\n\u001b[31mfunction applyFontSize() {\u001b[39m\n\u001b[31m  document.body.classList.remove('fs-0', 'fs-1', 'fs-2');\u001b[39m\n\u001b[31m  if (FS_LEVEL > 0) document.body.classList.add('fs-' + FS_LEVEL);\u001b[39m\n\u001b[31m  const lbl = document.getElementById('fs-lbl');\u001b[39m\n\u001b[31m  if (lbl) lbl.textContent = FS_LABELS[FS_LEVEL];\u001b[39m\n\u001b[31m  const dec = document.getElementById('fs-dec');\u001b[39m\n\u001b[31m  const inc = document.getElementById('fs-inc');\u001b[39m\n\u001b[31m  if (dec) dec.disabled = FS_LEVEL === 0;\u001b[39m\n\u001b[31m  if (inc) inc.disabled = FS_LEVEL === 4;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction changeFontSize(delta) {\u001b[39m\n\u001b[31m  FS_LEVEL = Math.min(4, Math.max(0, FS_LEVEL + delta));\u001b[39m\n\u001b[31m  localStorage.setItem('recce-fs', FS_LEVEL);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Hub auth gate\u001b[39m\n\u001b[31m(function() {\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (!s || !s.loginAt || Date.now() - new Date(s.loginAt).getTime() > 12 * 3600 * 1000) {\u001b[39m\n\u001b[31m      window.location.replace('/hub/');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) { window.location.replace('/hub/'); }\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31m// STATE\u001b[39m\n\u001b[31mlet F={},frontPhotos=[],insidePhotos=[],addlPhotos=[],brandings=[];\u001b[39m\n\u001b[31mlet videoBlob=null,submissionDoc=null,_docExistingUrl=null,gpsCoords=null;\u001b[39m\n\u001b[31mlet stores=[],selectedStore=null,manualMode=false,DB;\u001b[39m\n\u001b[31mlet imgQuality='compressed'; // 'compressed' | 'hd'\u001b[39m\n\u001b[31mlet geoStampEnabled=true;    // stamp GPS+timestamp on every photo\u001b[39m\n\u001b[31mlet brands=['PHILIPS']; // editable brand list\u001b[39m\n\u001b[31mlet _brandLogos={};   // name → logo_url, loaded from DB\u001b[39m\n\u001b[31mlet _selectedClient=''; // currently selected client chip value\u001b[39m\n\u001b[31mlet _clientOtherMode=false; // true when \\\"Other\\\" chip selected\u001b[39m\n\u001b[31mconst BTYPE=['Glow Sign Board','Inshop Branding','ACP Board','One Way Vision','Fabric Board','Lollypop','Non Lit Flex','Double Side GSB','Clip on Board','Translit','Vinyl Printing','Roll up Standee','Sunboard Standee'];\u001b[39m\n\u001b[31mconst CACHE_VER='recce-v37'; // campaign dropdown + pending job link tab·\u001b[39m\n\u001b[31m// DB\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',3);r.onupgradeneeded=e=>{const d=e.target.result;['subs','cfg','draft'].forEach(s=>{if(!d.objectStoreNames.contains(s))d.createObjectStore(s,{keyPath:'k'||'id'});});if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);});}\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',4);r.onupgradeneeded=e=>{const d=e.target.result;if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);})}\u001b[39m\n\u001b[31mfunction dbGet(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).get(k);r.onsuccess=()=>res(r.result);r.onerror=()=>res(null);}catch{res(null)}})}\u001b[39m\n\u001b[31mfunction dbPut(s,v){return new Promise((res,rej)=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).put(v);r.onsuccess=()=>res();r.onerror=()=>rej();}catch(e){rej(e)}})}\u001b[39m\n\u001b[31mfunction dbAll(s){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).getAll();r.onsuccess=()=>res(r.result);r.onerror=()=>res([]);}catch{res([])}})}\u001b[39m\n\u001b[31mfunction dbDel(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).delete(k);r.onsuccess=()=>res();r.onerror=()=>res();}catch{res()}})}\u001b[39m\n\u001b[31masync function cfg(k,v){if(v===undefined){const r=await dbGet('cfg',k);return r?r.v:null;}await dbPut('cfg',{k,v});}·\u001b[39m\n\u001b[31m// COMPRESS — respects imgQuality setting\u001b[39m\n\u001b[31mfunction compress(file, maxPxOverride, qOverride){\u001b[39m\n\u001b[31m  const maxPx = maxPxOverride || (imgQuality==='hd' ? 1920 : 1280);\u001b[39m\n\u001b[31m  const q     = qOverride     || (imgQuality==='hd' ? 0.90 : 0.78);\u001b[39m\n\u001b[31m  return new Promise(res=>{const img=new Image(),url=URL.createObjectURL(file);img.onload=()=>{const sc=Math.min(1,maxPx/Math.max(img.width,img.height));const c=document.createElement('canvas');c.width=Math.round(img.width*sc);c.height=Math.round(img.height*sc);c.getContext('2d').drawImage(img,0,0,c.width,c.height);URL.revokeObjectURL(url);c.toBlob(b=>res(b),'image/jpeg',q);};img.onerror=()=>{URL.revokeObjectURL(url);res(file)};img.src=url;});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction b64(blob){return new Promise(res=>{const r=new FileReader();r.onload=()=>res(r.result);r.readAsDataURL(blob)})}\u001b[39m\n\u001b[31mfunction fmtSz(b){if(b<1024)return b+'B';if(b<1048576)return(b/1024).toFixed(0)+'KB';return(b/1048576).toFixed(1)+'MB'}·\u001b[39m\n\u001b[31m// STORE LIST\u001b[39m\n\u001b[31mlet _storeFiles=[]; // track uploaded files {name, brand, count}\u001b[39m\n\u001b[31mlet _pendingParse=null; // parsed rows waiting for brand assignment·\u001b[39m\n\u001b[31mfunction parseStoreRow(row, keyFn){\u001b[39m\n\u001b[31m  const v=k=>{\u001b[39m\n\u001b[31m    // Try exact match first, then partial\u001b[39m\n\u001b[31m    const exactKey=Object.keys(row||{}).find(hk=>hk.toLowerCase()===k);\u001b[39m\n\u001b[31m    const partKey=Object.keys(row||{}).find(hk=>hk.toLowerCase().includes(k));\u001b[39m\n\u001b[31m    const useKey=exactKey||partKey;\u001b[39m\n\u001b[31m    if(useKey)return row[useKey]!=null?row[useKey].toString().trim():'';\u001b[39m\n\u001b[31m    // CSV path: keyFn provides value directly\u001b[39m\n\u001b[31m    const col=keyFn(k);return col!=null?col.toString().trim():'';\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const name    = v('sub dealer name')||v('sub dealer')||v('dealer name')||v('store name')||v('store')||v('name');\u001b[39m\n\u001b[31m  const address = v('address')||v('addr')||v('location')||v('area');\u001b[39m\n\u001b[31m  // Contact Detail often stored as a number — toString handles it\u001b[39m\n\u001b[31m  const rawMob  = v('contact detail')||v('contact no.')||v('contact no')||v('mobile no')||v('mobile')||v('phone')||v('mob')||v('contact');\u001b[39m\n\u001b[31m  const mobile  = rawMob.replace(/\\\\D/g,'').slice(-10);\u001b[39m\n\u001b[31m  // Brand: EXACT match only — \\\"Brand\\\" or \\\"Brand Name\\\" columns\u001b[39m\n\u001b[31m  // Partial match is intentionally avoided here because \\\"Inshop Branding\\\" contains \\\"brand\\\"\u001b[39m\n\u001b[31m  const brandKey=Object.keys(row||{}).find(hk=>{\u001b[39m\n\u001b[31m    const lk=hk.toLowerCase().trim();\u001b[39m\n\u001b[31m    return lk==='brand'||lk==='brand name'||lk==='brand_name'||lk==='brandname';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const brand=brandKey?(row[brandKey]||'').toString().trim().toUpperCase():'';\u001b[39m\n\u001b[31m  const distName= v('dist name')||v('distributor name')||v('distributor')||v('dist')||v('territory')||v('tsm')||v('asm');\u001b[39m\n\u001b[31m  const city    = v('city')||v('district')||v('town');\u001b[39m\n\u001b[31m  const sales   = v('2025 full year')||v('2025')||v('full year sales')||v('fy25')||v('sales');\u001b[39m\n\u001b[31m  const proj    = v('2026 projection')||v('2026')||v('projection')||v('fy26')||v('target');\u001b[39m\n\u001b[31m  const glowSign= v('glow sign')||v('glow');\u001b[39m\n\u001b[31m  const inshop  = v('inshop branding')||v('inshop')||v('in-shop')||v('in shop');\u001b[39m\n\u001b[31m  return {name, brand, address, mobile, distName, city, sales, proj, glowSign, inshop};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction dedupeStores(list){\u001b[39m\n\u001b[31m  const seen=new Map();\u001b[39m\n\u001b[31m  list.forEach(s=>{\u001b[39m\n\u001b[31m    // Include address in key — same store name at different locations = different stores\u001b[39m\n\u001b[31m    const key=(s.name.toLowerCase().trim())+'__'+(s.brand||'').toLowerCase()\u001b[39m\n\u001b[31m              +'__'+(s.address||'').toLowerCase().trim().slice(0,30);\u001b[39m\n\u001b[31m    if(!seen.has(key))seen.set(key,s);\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // True duplicate — merge missing fields from second record\u001b[39m\n\u001b[31m      const ex=seen.get(key);\u001b[39m\n\u001b[31m      Object.keys(s).forEach(k=>{ if(!ex[k]&&s[k])ex[k]=s[k]; });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  return Array.from(seen.values());\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderStoreFileList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-file-list');if(!el)return;\u001b[39m\n\u001b[31m  if(!_storeFiles.length){el.innerHTML='';return;}\u001b[39m\n\u001b[31m  el.innerHTML=_storeFiles.map((f,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:5px;font-size:12px\\\">\u001b[39m\n\u001b[31m      <div>\u001b[39m\n\u001b[31m        <span style=\\\"font-weight:600;color:var(--nv)\\\">${f.name}</span>\u001b[39m\n\u001b[31m        <span style=\\\"color:var(--g500);margin-left:6px\\\">${f.count} stores</span>\u001b[39m\n\u001b[31m        ${f.brand?`<span style=\\\"background:var(--nv);color:#fff;font-size:10px;font-weight:700;padding:1px 7px;border-radius:20px;margin-left:5px\\\">${f.brand}</span>`:'<span style=\\\"background:var(--g300);color:var(--g600);font-size:10px;padding:1px 7px;border-radius:20px;margin-left:5px\\\">Mixed brands</span>'}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <button onclick=\\\"removeStoreFile(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:17px;cursor:pointer;padding:0 4px;line-height:1\\\">×</button>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function removeStoreFile(i){\u001b[39m\n\u001b[31m  _storeFiles.splice(i,1);\u001b[39m\n\u001b[31m  // Rebuild stores from remaining files — re-parse from cache not possible, so just reload from DB and remove this file's contribution\u001b[39m\n\u001b[31m  // Simplest approach: clear and ask user to re-upload remaining files\u001b[39m\n\u001b[31m  if(!_storeFiles.length){stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    // Can't re-parse without original files; just note it and keep current store list\u001b[39m\n\u001b[31m    toast('Removed from list. Re-upload the remaining files to refresh store list.','info');\u001b[39m\n\u001b[31m    _storeFiles.splice(0); // clear tracking since we can't reconstruct\u001b[39m\n\u001b[31m    stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderStoreFileList();\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=stores.length?`✓ ${stores.length} stores`:'No stores loaded';\u001b[39m\n\u001b[31m  updAvailTag();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function clearStoreList(){\u001b[39m\n\u001b[31m  if(!confirm('Remove all loaded stores?'))return;\u001b[39m\n\u001b[31m  stores=[];_storeFiles=[];\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent='';\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast('Store list cleared','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function handleStoreUpload(e){\u001b[39m\n\u001b[31m  const file=e.target.files[0];if(!file)return;\u001b[39m\n\u001b[31m  e.target.value=''; // allow same file re-upload\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    let data=[];\u001b[39m\n\u001b[31m    if(file.name.toLowerCase().endsWith('.csv')){\u001b[39m\n\u001b[31m      const txt=await file.text();\u001b[39m\n\u001b[31m      const rows=txt.split('\\\\n').map(r=>r.split(',').map(c=>c.trim().replace(/^\\\"|\\\"$/g,'')));\u001b[39m\n\u001b[31m      if(!rows.length||!rows[0].length){toast('Empty CSV','error');return;}\u001b[39m\n\u001b[31m      const h=rows[0];\u001b[39m\n\u001b[31m      data=rows.slice(1).filter(r=>r.length>1&&r.some(c=>c)).map(r=>{\u001b[39m\n\u001b[31m        const rowObj={};h.forEach((hk,i)=>{rowObj[hk]=r[i]||'';});\u001b[39m\n\u001b[31m        return parseStoreRow(rowObj, ()=>'');\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }else{\u001b[39m\n\u001b[31m      const ab=await file.arrayBuffer();const wb=XLSX.read(ab,{type:'array'});\u001b[39m\n\u001b[31m      const js=XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]],{defval:''});\u001b[39m\n\u001b[31m      data=js.map(row=>parseStoreRow(row,()=>''));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    data=data.filter(d=>d.name.trim());\u001b[39m\n\u001b[31m    if(!data.length){toast('No valid rows found in file','error');return;}\u001b[39m\n\u001b[31m    // Check if any store has a brand\u001b[39m\n\u001b[31m    const hasBrand=data.some(d=>d.brand);\u001b[39m\n\u001b[31m    // Always show preview first before merging\u001b[39m\n\u001b[31m    _pendingParse={file:file.name,data,hasBrand};\u001b[39m\n\u001b[31m    showStorePreview(file.name, data, hasBrand);\u001b[39m\n\u001b[31m  }catch(err){toast('Failed: '+err.message,'error')}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mlet _pendingBrand='';\u001b[39m\n\u001b[31mfunction setPendingBrand(b){\u001b[39m\n\u001b[31m  _pendingBrand=b;\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-assign-chips .chip').forEach(c=>{\u001b[39m\n\u001b[31m    c.classList.toggle('sel',c.textContent===b);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  if(!_pendingBrand){toast('Select a brand first','error');return;}\u001b[39m\n\u001b[31m  // Assign brand to all rows in this file\u001b[39m\n\u001b[31m  const data=_pendingParse.data.map(s=>({...s,brand:_pendingBrand}));\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, data, _pendingBrand);\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function skipBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, _pendingParse.data, '');\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showStorePreview(filename, data, hasBrand){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-preview-dialog');\u001b[39m\n\u001b[31m  const tbody=document.getElementById('store-preview-body');\u001b[39m\n\u001b[31m  document.getElementById('store-preview-title').textContent=`${filename} · ${data.length} ${t('stores found','स्टोर मिले')}`;\u001b[39m\n\u001b[31m  // Show first 8 rows\u001b[39m\n\u001b[31m  const sample=data.slice(0,8);\u001b[39m\n\u001b[31m  tbody.innerHTML=sample.map(s=>`<tr>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;font-weight:500\\\">${s.name||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.address||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.mobile||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px\\\"><span style=\\\"background:${s.brand?'var(--nv)':'var(--rd)'};color:#fff;padding:1px 7px;border-radius:10px;font-size:10px\\\">${s.brand||'?'}</span></td>\u001b[39m\n\u001b[31m  </tr>`).join('');\u001b[39m\n\u001b[31m  if(data.length>8)tbody.innerHTML+=`<tr><td colspan=\\\"4\\\" style=\\\"text-align:center;padding:8px;font-size:12px;color:var(--g400)\\\">…and ${data.length-8} more stores</td></tr>`;\u001b[39m\n\u001b[31m  el.classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function confirmStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  const {file,data,hasBrand}=_pendingParse;\u001b[39m\n\u001b[31m  if(!hasBrand){\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-fname').textContent=`File: ${file} · ${data.length} stores found · No brand column detected`;\u001b[39m\n\u001b[31m    const chips=document.getElementById('brand-assign-chips');\u001b[39m\n\u001b[31m    chips.innerHTML=brands.map(b=>`<div class=\\\"chip\\\" onclick=\\\"setPendingBrand('${b}')\\\" id=\\\"bac-${b}\\\">${b}</div>`).join('');\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').style.display='block';\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    await mergeStores(file, data, '');\u001b[39m\n\u001b[31m    _pendingParse=null;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction cancelStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingParse=null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function mergeStores(filename, newData, assignedBrand){\u001b[39m\n\u001b[31m  const before=stores.length;\u001b[39m\n\u001b[31m  stores=[...stores,...newData];\u001b[39m\n\u001b[31m  stores=dedupeStores(stores);\u001b[39m\n\u001b[31m  const added=stores.length-before;\u001b[39m\n\u001b[31m  const dupes=newData.length-added;\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify(stores));\u001b[39m\n\u001b[31m  // Track file\u001b[39m\n\u001b[31m  _storeFiles.push({name:filename,count:newData.length,brand:assignedBrand||''});\u001b[39m\n\u001b[31m  await cfg('store-files',JSON.stringify(_storeFiles));\u001b[39m\n\u001b[31m  const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m    `✓ ${stores.length} total stores${dupes>0?` · ${dupes} duplicate${dupes>1?'s':''} removed`:''}${noBrand?` · ${noBrand} without brand`:' · All have brand'}`;\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast(`${added} stores added${dupes>0?`, ${dupes} duplicates skipped`:''}${assignedBrand?' as '+assignedBrand:''}`, 'success');\u001b[39m\n\u001b[31m  // Show server-push button for supervisors\u001b[39m\n\u001b[31m  const pb = document.getElementById('store-push-btn');\u001b[39m\n\u001b[31m  if (pb) pb.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function fetchServerStores(){const url=document.getElementById('srv-url').value.trim();if(!url){toast('Enter a URL first','error');return;}try{toast('Fetching…','info');const r=await fetch(url);const j=await r.json();const fetched=Array.isArray(j)?j:j.stores||[];await mergeStores('Server ('+url.split('/').pop()+')',fetched,'');await cfg('srv-url',url);}catch{toast('Fetch failed — check URL','error')}}\u001b[39m\n\u001b[31masync function saveServerUrl(){await cfg('srv-url',document.getElementById('srv-url').value.trim());toast('URL saved','success')}\u001b[39m\n\u001b[31mconst DEFAULT_GAS_URL='https://script.google.com/macros/s/AKfycbwyufC7gQyu1BErCxiDlbQUn0AWiIWv7nEmjk4UcAx3dvlV6bGk7q5fQOiv82CTbokbkA/exec';·\u001b[39m\n\u001b[31mconst DEFAULT_STORES_URL='/recce/stores.json';\u001b[39m\n\u001b[31mconst _RECCE_CFG_URL='/recce/recce-cfg.json';·\u001b[39m\n\u001b[31m// Admin auto-unlock for harish/pramod via hub session\u001b[39m\n\u001b[31mconst _RECCE_ADMIN_IDS = ['harish', 'pramod', 'rakesh'];\u001b[39m\n\u001b[31mconst _RECCE_CFG_ADMINS = ['harish', 'pramod'];\u001b[39m\n\u001b[31mlet _adminRows = [];\u001b[39m\n\u001b[31mlet _myServerRows = [];\u001b[39m\n\u001b[31mlet _adminUnlocked = false;\u001b[39m\n\u001b[31mlet _recceCfg = { version: 1, supervisors: ['harish','pramod','rakesh'], mode: 'public', creators: [], allowed_users: [] };\u001b[39m\n\u001b[31mfunction _isSupervisor() {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  return !!(hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId));\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _showDeletedView = false;\u001b[39m\n\u001b[31mlet _supCreateMode = false;\u001b[39m\n\u001b[31mlet _pendingDeleteId = null;\u001b[39m\n\u001b[31mlet _pendingDeleteReason = null;\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (s?.empId && _RECCE_ADMIN_IDS.includes(s.empId)) _adminUnlocked = true;\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31masync function loadRecceCfg(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(_RECCE_CFG_URL + '?t=' + Date.now());\u001b[39m\n\u001b[31m    if (r.ok) {\u001b[39m\n\u001b[31m      const j = await r.json();\u001b[39m\n\u001b[31m      if (j && j.version) {\u001b[39m\n\u001b[31m        _recceCfg = j;\u001b[39m\n\u001b[31m        if (Array.isArray(j.supervisors) && j.supervisors.length) {\u001b[39m\n\u001b[31m          _recceCfg.supervisors = j.supervisors;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.creators)) _recceCfg.creators = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.allowed_users)) _recceCfg.allowed_users = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.clients)) _recceCfg.clients = [];\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  // Re-check admin status against server supervisor list\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId)) {\u001b[39m\n\u001b[31m    _adminUnlocked = true;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _checkAccessMode(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (_recceCfg.mode !== 'assigned') return;\u001b[39m\n\u001b[31m  const allowed = [\u001b[39m\n\u001b[31m    ...(_recceCfg.supervisors || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.creators || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.allowed_users || []),\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  if (hub?.empId && allowed.includes(hub.empId)) return;\u001b[39m\n\u001b[31m  // Block access — show locked overlay\u001b[39m\n\u001b[31m  document.body.innerHTML = `<div style=\\\"min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0f172a;color:#fff;padding:32px;text-align:center\\\"><div style=\\\"font-size:48px;margin-bottom:16px\\\">🔒</div><div style=\\\"font-size:20px;font-weight:700;margin-bottom:8px\\\">${t('Access Restricted','एक्सेस प्रतिबंधित')}</div><div style=\\\"font-size:14px;color:#94a3b8\\\">${t('You are not authorised to use Branding Recce. Please contact your supervisor.','आप ब्रांडिंग रेक्की उपयोग के लिए अधिकृत नहीं हैं।')}</div></div>`;\u001b[39m\n\u001b[31m  throw new Error('access-restricted');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _recceHubUser() {\u001b[39m\n\u001b[31m  try { return JSON.parse(localStorage.getItem('lm360-session') || '{}'); }\u001b[39m\n\u001b[31m  catch(_) { return {}; }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── Supervisor config management ────────────────────────────────────\u001b[39m\n\u001b[31mfunction renderSupPanel(){\u001b[39m\n\u001b[31m  if (!_adminUnlocked) return;\u001b[39m\n\u001b[31m  const panel = document.getElementById('sup-panel');\u001b[39m\n\u001b[31m  if (panel) panel.style.display = 'block';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const modePublic = document.getElementById('mode-public');\u001b[39m\n\u001b[31m  const modeAssigned = document.getElementById('mode-assigned');\u001b[39m\n\u001b[31m  if (modePublic && modeAssigned) {\u001b[39m\n\u001b[31m    modePublic.classList.toggle('sel', _recceCfg.mode !== 'assigned');\u001b[39m\n\u001b[31m    modeAssigned.classList.toggle('sel', _recceCfg.mode === 'assigned');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  const addRow = document.getElementById('sup-add-row');\u001b[39m\n\u001b[31m  if (addRow) addRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const creatorAddRow = document.getElementById('creator-add-row');\u001b[39m\n\u001b[31m  if (creatorAddRow) creatorAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const clientAddRow = document.getElementById('client-add-row');\u001b[39m\n\u001b[31m  if (clientAddRow) clientAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const modeRow = document.getElementById('mode-row');\u001b[39m\n\u001b[31m  if (modeRow) {\u001b[39m\n\u001b[31m    modeRow.style.display = 'block';\u001b[39m\n\u001b[31m    // Non-cfg-admins see mode as read-only (toggles exist but setRecceMode guards them)\u001b[39m\n\u001b[31m    modeRow.style.opacity = isCfgAdmin ? '1' : '0.65';\u001b[39m\n\u001b[31m    modeRow.style.pointerEvents = isCfgAdmin ? '' : 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const syncBtn = document.getElementById('cfg-sync-btn');\u001b[39m\n\u001b[31m  if (syncBtn) syncBtn.style.display = isCfgAdmin ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('sup-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const sups = _recceCfg.supervisors || [];\u001b[39m\n\u001b[31m  el.innerHTML = sups.map((s,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${s}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin && sups.length > 1 ? `<button onclick=\\\"removeSupervisor(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderCreatorsList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('creator-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const creators = _recceCfg.creators || [];\u001b[39m\n\u001b[31m  el.innerHTML = creators.length ? creators.map((u,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${u}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeCreator(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No creators yet — any Hub user can submit in Public mode.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setRecceMode(mode){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.mode = mode;\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addSupervisor(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('sup-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.supervisors = [...(_recceCfg.supervisors || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeSupervisor(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.supervisors = (_recceCfg.supervisors || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addCreator(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('creator-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.creators || []).includes(val)) { toast(t('Already a creator','पहले से क्रिएटर है'), 'info'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor (includes creation rights)','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.creators = [...(_recceCfg.creators || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeCreator(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.creators = (_recceCfg.creators || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderClientMgmtList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('client-mgmt-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const list = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  el.innerHTML = list.length ? list.map((c,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${esc(c)}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeClientFromList(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No clients yet — add client or agency names to show them as chips in the form.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addClientToList(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('client-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter client name','क्लाइंट नाम दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.clients || []).includes(val)) { toast(t('Already in list','पहले से मौजूद है'), 'info'); return; }\u001b[39m\n\u001b[31m  if (!_recceCfg.clients) _recceCfg.clients = [];\u001b[39m\n\u001b[31m  _recceCfg.clients.push(val);\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeClientFromList(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.clients = (_recceCfg.clients || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncCfgToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast(t('Not authorised','अधिकृत नहीं'), 'error'); return; }\u001b[39m\n\u001b[31m  const st = document.getElementById('cfg-sync-status');\u001b[39m\n\u001b[31m  if (st) st.textContent = t('Syncing…','सिंक हो रहा है…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-cfg', empId: hub.empId, cfg: {\u001b[39m\n\u001b[31m        version: _recceCfg.version || 1,\u001b[39m\n\u001b[31m        supervisors: _recceCfg.supervisors || [],\u001b[39m\n\u001b[31m        mode: _recceCfg.mode || 'public',\u001b[39m\n\u001b[31m        creators: _recceCfg.creators || [],\u001b[39m\n\u001b[31m        allowed_users: _recceCfg.allowed_users || [],\u001b[39m\n\u001b[31m        clients: _recceCfg.clients || [],\u001b[39m\n\u001b[31m      }})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) {\u001b[39m\n\u001b[31m      toast(t('Config synced to server ✓','कॉन्फ़िग सर्वर पर सेव हुआ ✓'), 'success');\u001b[39m\n\u001b[31m      if (st) st.textContent = t('Last synced: just now','अभी सिंक हुआ');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast(j.error || t('Sync failed','सिंक विफल'), 'error');\u001b[39m\n\u001b[31m      if (st) st.textContent = j.error || '';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Network error','नेटवर्क त्रुटि'), 'error');\u001b[39m\n\u001b[31m    if (st) st.textContent = e.message;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function pushStoresToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!hub?.empId || !_adminUnlocked) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-stores', empId: hub.empId, stores })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) toast(`${t('Pushed to server','सर्वर पर पुश हुआ')} · ${j.count} ${t('stores','स्टोर')}`, 'success');\u001b[39m\n\u001b[31m    else toast(j.error || t('Server push failed','सर्वर पुश विफल'), 'error');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Could not reach server','सर्वर से संपर्क नहीं हो सका'), 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── End supervisor config management ────────────────────────────────·\u001b[39m\n\u001b[31m// PostgREST sync constants\u001b[39m\n\u001b[31mconst _RC_BASE      = '/db';\u001b[39m\n\u001b[31mconst _RC_READ      = { 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_WRITE     = { 'Content-Type': 'application/json', 'Content-Profile': 'recce', 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_UPSERT    = { ..._RC_WRITE, 'Prefer': 'resolution=merge-duplicates,return=minimal' };\u001b[39m\n\u001b[31mconst _INSTALL_RD   = { 'Content-Type': 'application/json', 'Accept-Profile': 'installation' };\u001b[39m\n\u001b[31mconst _INSTALL_WR   = { 'Content-Type': 'application/json', 'Content-Profile': 'installation', 'Accept-Profile': 'installation', 'Prefer': 'return=minimal' };·\u001b[39m\n\u001b[31m// ── Campaign selection state ──\u001b[39m\n\u001b[31mlet _selectedCampaignId = null;\u001b[39m\n\u001b[31mlet _notifySupervisor   = false;\u001b[39m\n\u001b[31mlet _campaignList       = [];\u001b[39m\n\u001b[31mlet _pendingJobFilter   = false;\u001b[39m\n\u001b[31mlet _linkJobSubId       = null;\u001b[39m\n\u001b[31mlet _brandingLocked     = false;·\u001b[39m\n\u001b[31mfunction _updateBrandingLock() {\u001b[39m\n\u001b[31m  const hub  = _recceHubUser();\u001b[39m\n\u001b[31m  const isHP = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const banner   = document.getElementById('branding-lock-banner');\u001b[39m\n\u001b[31m  const ovWrap   = document.getElementById('branding-override-wrap');\u001b[39m\n\u001b[31m  const brItems  = document.getElementById('br-items');\u001b[39m\n\u001b[31m  const brAdd    = document.getElementById('br-add');\u001b[39m\n\u001b[31m  const brYes    = document.getElementById('br-yes');\u001b[39m\n\u001b[31m  const brNo     = document.getElementById('br-no');\u001b[39m\n\u001b[31m  if (!banner) return;\u001b[39m\n\u001b[31m  if (_brandingLocked) {\u001b[39m\n\u001b[31m    banner.style.display   = '';\u001b[39m\n\u001b[31m    if (ovWrap)  ovWrap.style.display  = isHP ? '' : 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.pointerEvents = 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.opacity = '0.55';\u001b[39m\n\u001b[31m    if (brAdd)   brAdd.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='none'; brYes.style.opacity='0.5'; }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='none';  brNo.style.opacity='0.5';  }\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    banner.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brItems) { brItems.style.pointerEvents=''; brItems.style.opacity=''; }\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='';  brYes.style.opacity='';   }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='';   brNo.style.opacity='';    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction unlockBrandingOverride() {\u001b[39m\n\u001b[31m  if (!confirm(\u001b[39m\n\u001b[31m    'Client has already reviewed this recce.\\\\n' +\u001b[39m\n\u001b[31m    'Editing brandings will NOT remove their approval.\\\\n' +\u001b[39m\n\u001b[31m    'Continue ONLY if the client has verbally confirmed. Proceed?'\u001b[39m\n\u001b[31m  )) return;\u001b[39m\n\u001b[31m  _brandingLocked = false;\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  renderBrandings();\u001b[39m\n\u001b[31m  toast(t('Branding unlocked for this session', 'ब्रांडिंग इस सत्र के लिए अनलॉक'), 'info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadCampaignsForForm() {\u001b[39m\n\u001b[31m  const sel = document.getElementById('f-campaign-id');\u001b[39m\n\u001b[31m  if (!sel) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m    _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m  } catch(_) { _campaignList = []; }\u001b[39m\n\u001b[31m  sel.innerHTML =\u001b[39m\n\u001b[31m    '<option value=\\\"\\\">— Select job / campaign (optional) —</option>' +\u001b[39m\n\u001b[31m    _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('') +\u001b[39m\n\u001b[31m    '<option value=\\\"__NOTIFY__\\\">⚑ No campaign yet — notify supervisor</option>';\u001b[39m\n\u001b[31m  if (_selectedCampaignId) sel.value = _selectedCampaignId;\u001b[39m\n\u001b[31m  else if (_notifySupervisor) sel.value = '__NOTIFY__';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onCampaignSelect() {\u001b[39m\n\u001b[31m  const val = document.getElementById('f-campaign-id')?.value || '';\u001b[39m\n\u001b[31m  const noticeEl = document.getElementById('campaign-notify-msg');\u001b[39m\n\u001b[31m  if (val === '__NOTIFY__') {\u001b[39m\n\u001b[31m    _selectedCampaignId = null;\u001b[39m\n\u001b[31m    _notifySupervisor   = true;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'block';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    _selectedCampaignId = val || null;\u001b[39m\n\u001b[31m    _notifySupervisor   = false;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction generateRecceReportHtml(entry, photoUrls) {\u001b[39m\n\u001b[31m  const d    = entry.data || {};\u001b[39m\n\u001b[31m  const urls = photoUrls || {};\u001b[39m\n\u001b[31m  const agent = entry.submittedByName || entry.submittedBy || 'Field Agent';\u001b[39m\n\u001b[31m  const _safeId      = (entry.id||'').replace(/\\\\//g,'_').replace(/\\\\.\\\\./g,'');\u001b[39m\n\u001b[31m  const serverPdfUrl = _safeId ? `https://srv1111289.hstgr.cloud/screenshots/recce/views/${_safeId}.pdf` : '';\u001b[39m\n\u001b[31m  const brandLogoUrl = d.brandLogoUrl || _brandLogos[d.brand] || '';\u001b[39m\n\u001b[31m  const tsStr = new Date(entry.timestamp).toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric',hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\u001b[39m\n\u001b[31m  const gpsUrl = d.gpsCoords ? `https://maps.google.com/?q=${d.gpsCoords.lat},${d.gpsCoords.lng}` : null;·\u001b[39m\n\u001b[31m  const frontCount  = (urls.front||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const insideCount = (urls.inside||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const addlCount   = (urls.addl||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const brCount     = (d.brandings||[]).length;·\u001b[39m\n\u001b[31m  // pages: { id, url, bandHtml, cmt, dotLabel, dotColor }\u001b[39m\n\u001b[31m  const pages = [];·\u001b[39m\n\u001b[31m  (urls.front||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Front View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${frontCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.frontPhotos||[])[i]?.cmt||'', dotLabel:`FV${i+1}`, dotColor:'#3b82f6', catLabel:'Front View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.inside||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Inside View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${insideCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.insidePhotos||[])[i]?.cmt||'', dotLabel:`IV${i+1}`, dotColor:'#14b8a6', catLabel:'Inside View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (d.brandings||[]).forEach((b,i)=>{\u001b[39m\n\u001b[31m    const url=(urls.brandings||[])[i]; if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">${esc(b.type||'Branding')}</div><div class=\\\"ph-dims\\\">Width : ${esc(b.w||'?')}&Prime;&nbsp;&times;&nbsp;Height : ${esc(b.h||'?')}&Prime;&nbsp;&mdash;&nbsp;${esc(b.qty||1)} Nos</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${brCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:'', dotLabel:`B${i+1}`, dotColor:'#f97316', catLabel:b.type||'Branding',\u001b[39m\n\u001b[31m      tileDims:`${b.w||'?'}″×${b.h||'?'}″ — ${String(b.qty||1).padStart(2,'0')} Nos` });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.addl||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Additional</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${addlCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.addlPhotos||[])[i]?.desc||'', dotLabel:`A${i+1}`, dotColor:'#94a3b8', catLabel:'Additional', tileDims:'' });\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const sideItems = [\u001b[39m\n\u001b[31m    `<div class=\\\"si-item active\\\" data-tgt=\\\"pg-cover\\\" title=\\\"Cover\\\"><div class=\\\"si-dot\\\" style=\\\"background:#475569\\\">CV</div></div>`\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  pages.forEach(p => {\u001b[39m\n\u001b[31m    sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"${p.id}\\\" title=\\\"${p.dotLabel}\\\"><div class=\\\"si-dot\\\" style=\\\"background:${p.dotColor}\\\">${p.dotLabel}</div></div>`);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(d.hasVideo) sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-vid\\\" title=\\\"Video\\\"><div class=\\\"si-dot\\\" style=\\\"background:#a855f7\\\">VD</div></div>`);\u001b[39m\n\u001b[31m  if(urls.doc)   sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-doc\\\" title=\\\"Document\\\"><div class=\\\"si-dot\\\" style=\\\"background:#64748b\\\">DC</div></div>`);·\u001b[39m\n\u001b[31m  const thumbItems = [\u001b[39m\n\u001b[31m    ...pages,\u001b[39m\n\u001b[31m    ...(d.hasVideo?[{id:'pg-vid',url:null,catLabel:'Video',tileDims:'',dotLabel:'VD',dotColor:'#a855f7'}]:[]),\u001b[39m\n\u001b[31m    ...(urls.doc?[{id:'pg-doc',url:urls.doc,catLabel:'Document',tileDims:'',dotLabel:'DC',dotColor:'#64748b'}]:[])\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  const thumbsHtml = thumbItems.map(p=>`<div class=\\\"cov-thumb\\\" onclick=\\\"document.getElementById('${p.id}').scrollIntoView({behavior:'smooth'})\\\">${p.url?`<img src=\\\"${p.url}\\\" alt=\\\"\\\">`:(`<div class=\\\"cov-thumb-vid\\\">${p.catLabel==='Video'?'&#x25B6;&#xFE0F;':'&#x1F4C4;'}</div>`)}<div class=\\\"cov-thumb-ov\\\" style=\\\"border-top:3px solid ${p.dotColor}\\\"><div class=\\\"cov-thumb-cat\\\">${esc(p.catLabel)}</div>${p.tileDims?`<div class=\\\"cov-thumb-dims\\\">${esc(p.tileDims)}</div>`:''}<div class=\\\"cov-thumb-no\\\">${p.dotLabel}</div></div></div>`).join('');·\u001b[39m\n\u001b[31m  const pagesHtml = pages.map(p => `\u001b[39m\n\u001b[31m<div class=\\\"photo-page\\\" id=\\\"${p.id}\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\">${p.bandHtml}</div>\u001b[39m\n\u001b[31m  <div class=\\\"ph-img\\\"><a href=\\\"${p.url}\\\" target=\\\"_blank\\\"><img src=\\\"${p.url}\\\" loading=\\\"lazy\\\" alt=\\\"\\\"></a>${p.cmt?`<div class=\\\"ph-cmt\\\">${esc(p.cmt)}</div>`:''}</div>\u001b[39m\n\u001b[31m</div>`).join('');·\u001b[39m\n\u001b[31m  return `<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\"><head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m<title>Recce — ${esc(d.storeName||'Unknown')} · ${esc(d.brand||'')}</title>\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--dk:#0f172a;--nv2:#1a2f52;--or:#f97316;--g200:#e2e8f0;--g400:#94a3b8;--g600:#475569;--si:54px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0}\u001b[39m\n\u001b[31mhtml,body{height:100%;overflow:hidden}\u001b[39m\n\u001b[31mbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#111;color:var(--dk);display:flex}\u001b[39m\n\u001b[31ma{color:var(--or);text-decoration:none}\u001b[39m\n\u001b[31mimg{display:block}·\u001b[39m\n\u001b[31m/* ── Side index ── */\u001b[39m\n\u001b[31m.side-idx{width:var(--si);flex-shrink:0;background:var(--dk);overflow-y:auto;display:flex;flex-direction:column;align-items:center;padding:4px 0;scrollbar-width:none;z-index:50}\u001b[39m\n\u001b[31m.side-idx::-webkit-scrollbar{display:none}\u001b[39m\n\u001b[31m.si-item{width:100%;min-height:56px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s}\u001b[39m\n\u001b[31m.si-item:hover{background:rgba(255,255,255,.07)}\u001b[39m\n\u001b[31m.si-dot{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff;opacity:.4;transition:opacity .18s,transform .18s;line-height:1;text-align:center}\u001b[39m\n\u001b[31m.si-item.active .si-dot{opacity:1;transform:scale(1.15)}·\u001b[39m\n\u001b[31m/* ── Main scroll area ── */\u001b[39m\n\u001b[31m.main{flex:1;overflow-y:scroll;scroll-snap-type:y mandatory;scroll-behavior:smooth;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar{width:3px}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15)}·\u001b[39m\n\u001b[31m/* ── Cover ── */\u001b[39m\n\u001b[31m.cover{height:100vh;scroll-snap-align:start;flex-shrink:0;background:linear-gradient(135deg,#0f172a 0%,var(--nv2) 100%);color:#fff;display:flex;flex-direction:column;padding:24px 20px 20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.cover-badge{display:inline-flex;align-items:center;gap:5px;background:var(--or);color:#fff;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:1px;padding:3px 12px;border-radius:20px;margin-bottom:12px;align-self:flex-start}\u001b[39m\n\u001b[31m.cover h1{font-size:20px;font-weight:700;line-height:1.3;margin-bottom:4px}\u001b[39m\n\u001b[31m.cover-addr{color:rgba(255,255,255,.55);font-size:12px;margin-bottom:16px}\u001b[39m\n\u001b[31m.cg{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}\u001b[39m\n\u001b[31m.cm{background:rgba(255,255,255,.08);border-radius:8px;padding:8px 12px}\u001b[39m\n\u001b[31m.cm-l{font-size:9px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}\u001b[39m\n\u001b[31m.cm-v{font-size:13px;font-weight:600;color:#fff}\u001b[39m\n\u001b[31m.cm-v a{color:#fb923c}\u001b[39m\n\u001b[31m.cover-pbar{padding-top:8px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{background:var(--or);color:#fff;border:none;padding:10px 22px;border-radius:22px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}\u001b[39m\n\u001b[31m.btn-p:disabled{opacity:.4;cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-c{background:rgba(255,255,255,.1);color:rgba(255,255,255,.75);border:1px solid rgba(255,255,255,.2);padding:10px 18px;border-radius:22px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit}·\u001b[39m\n\u001b[31m/* ── Cover thumbnail grid ── */\u001b[39m\n\u001b[31m.cov-grid-hdr{font-size:10px;font-weight:700;color:rgba(255,255,255,.35);text-transform:uppercase;letter-spacing:1.2px;padding:10px 0 5px;flex-shrink:0}\u001b[39m\n\u001b[31m.cov-grid{flex:1;min-height:0;display:grid;gap:5px;overflow:hidden;align-content:start}\u001b[39m\n\u001b[31m.cov-thumb{position:relative;overflow:hidden;border-radius:7px;cursor:pointer;background:#1e293b;transition:transform .18s,box-shadow .18s}\u001b[39m\n\u001b[31m.cov-thumb:hover{transform:scale(1.05);box-shadow:0 4px 18px rgba(0,0,0,.55)}\u001b[39m\n\u001b[31m.cov-thumb img{width:100%;height:100%;object-fit:cover;display:block}\u001b[39m\n\u001b[31m.cov-thumb-vid{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:#0f172a}\u001b[39m\n\u001b[31m.cov-thumb-ov{position:absolute;inset:0;background:rgba(0,0,0,.28);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:5px;border-radius:7px}\u001b[39m\n\u001b[31m.cov-thumb-cat{color:rgba(255,255,255,.5);font-weight:900;text-align:center;text-transform:uppercase;letter-spacing:.8px;text-shadow:0 1px 6px rgba(0,0,0,.95);line-height:1.2;word-break:break-word}\u001b[39m\n\u001b[31m.cov-thumb-dims{color:rgba(255,255,255,.5);font-weight:700;text-align:center;text-shadow:0 1px 5px rgba(0,0,0,.95);letter-spacing:.3px;line-height:1.3}\u001b[39m\n\u001b[31m.cov-thumb-no{color:rgba(255,255,255,.5);font-weight:800;text-shadow:0 1px 4px rgba(0,0,0,.95);letter-spacing:.5px}\u001b[39m\n\u001b[31m#cover-btn{position:fixed;bottom:20px;right:16px;display:none;align-items:center;gap:6px;background:rgba(255,255,255,.15);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.25);color:#fff;padding:10px 22px;border-radius:50px;font-size:13px;font-weight:700;cursor:pointer;z-index:200;letter-spacing:.3px;box-shadow:0 2px 12px rgba(0,0,0,.3);font-family:inherit;transition:background .15s,transform .15s}\u001b[39m\n\u001b[31m#cover-btn:hover{background:rgba(255,255,255,.22);transform:scale(1.04)}·\u001b[39m\n\u001b[31m/* ── Print wait overlay ── */\u001b[39m\n\u001b[31m#print-overlay{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m@media print{#print-overlay{display:none!important}}·\u001b[39m\n\u001b[31m/* ── Loading progress bar ── */\u001b[39m\n\u001b[31m.load-bar{position:fixed;bottom:0;left:0;right:0;background:rgba(15,23,42,.95);padding:9px 16px;z-index:9999;display:flex;align-items:center;gap:12px;backdrop-filter:blur(6px)}\u001b[39m\n\u001b[31m.load-track{flex:1;height:5px;background:rgba(255,255,255,.12);border-radius:3px;overflow:hidden}\u001b[39m\n\u001b[31m.load-fill{height:100%;background:var(--or);width:0%;transition:width .35s ease;border-radius:3px}\u001b[39m\n\u001b[31m.load-txt{font-size:11px;color:rgba(255,255,255,.6);white-space:nowrap;min-width:160px}·\u001b[39m\n\u001b[31m/* ── Photo page ── */\u001b[39m\n\u001b[31m.photo-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ph-band{background:var(--dk);padding:16px 26px;flex-shrink:0;display:flex;align-items:center;gap:20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.ph-cat{font-size:35px;font-weight:800;color:#fff;letter-spacing:-.5px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.ph-dims{flex:1;font-size:18px;font-weight:600;color:var(--or);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}\u001b[39m\n\u001b[31m.ph-no{margin-left:auto;flex-shrink:0;font-size:21px;font-weight:700;color:rgba(255,255,255,.85);background:rgba(255,255,255,.1);padding:5px 20px;border-radius:24px;white-space:nowrap}\u001b[39m\n\u001b[31m.ph-of{font-size:18px;font-weight:400;color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.ph-img{flex:1;overflow:hidden;position:relative;background:#111}\u001b[39m\n\u001b[31m.ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m.ph-img img{width:100%;height:100%;object-fit:contain;display:block}\u001b[39m\n\u001b[31m.ph-cmt{position:absolute;bottom:0;left:0;right:0;padding:6px 14px;background:rgba(0,0,0,.62);font-size:11px;color:rgba(255,255,255,.75);font-style:italic;pointer-events:none}·\u001b[39m\n\u001b[31m/* ── Video / Doc pages ── */\u001b[39m\n\u001b[31m.vid-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;background:#fff}\u001b[39m\n\u001b[31m.vid-body{flex:1;padding:20px 24px;font-size:14px;color:var(--g600);border-left:4px solid var(--or)}\u001b[39m\n\u001b[31m.vid-body em{display:block;font-size:12px;color:var(--g400);margin-top:6px}\u001b[39m\n\u001b[31m.doc-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m.doc-wrap{flex:1;display:flex;align-items:center;justify-content:center;background:#111;overflow:hidden}\u001b[39m\n\u001b[31m.doc-img{max-width:100%;max-height:100%;object-fit:contain}·\u001b[39m\n\u001b[31m/* ── Cover header band ── */\u001b[39m\n\u001b[31m.cov-hdr{display:flex;gap:0;margin-bottom:12px;flex-shrink:0;border-radius:10px;overflow:hidden;border:1px solid rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.cov-hdr-l{flex:1;padding:14px 18px;display:flex;flex-direction:column;gap:5px;border-right:1px solid rgba(255,255,255,.1);min-width:0}\u001b[39m\n\u001b[31m.cov-hdr-r{width:170px;flex-shrink:0;padding:14px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:rgba(255,255,255,.04)}\u001b[39m\n\u001b[31m.cov-store{font-size:18px;font-weight:800;color:#fff;line-height:1.25;margin-bottom:2px}\u001b[39m\n\u001b[31m.cov-meta{font-size:12px;color:rgba(255,255,255,.55);display:flex;align-items:center;gap:5px;line-height:1.5}\u001b[39m\n\u001b[31m.cov-brand{background:var(--or);color:#fff;font-size:13px;font-weight:800;padding:5px 16px;border-radius:20px;text-align:center;letter-spacing:.3px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\u001b[39m\n\u001b[31m.cov-date-l{font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.8px;margin-bottom:2px;text-align:center}\u001b[39m\n\u001b[31m.cov-date-v{font-size:13px;font-weight:700;color:#fff;text-align:center}\u001b[39m\n\u001b[31m.cov-logo-box{background:#fff;border-radius:8px;padding:8px 14px;display:flex;align-items:center;justify-content:center;width:100%;max-width:138px}\u001b[39m\n\u001b[31m.cov-logo-box img{max-width:110px;max-height:44px;object-fit:contain;display:block}·\u001b[39m\n\u001b[31m/* ── Print ── */\u001b[39m\n\u001b[31m@page{size:A4 landscape;margin:12mm}\u001b[39m\n\u001b[31m@media print{\u001b[39m\n\u001b[31m  html,body{height:auto;overflow:visible;display:block}\u001b[39m\n\u001b[31m  .side-idx{display:none}\u001b[39m\n\u001b[31m  .main{overflow:visible;display:block;height:auto;scroll-snap-type:none}\u001b[39m\n\u001b[31m  .cover,.vid-page,.doc-page{height:auto;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m  .photo-page{height:186mm;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m  .cover{padding:20px 24px}\u001b[39m\n\u001b[31m  .cover-pbar{display:none}\u001b[39m\n\u001b[31m  .cov-hdr{margin-bottom:8px;border-radius:7px}\u001b[39m\n\u001b[31m  .cov-hdr-l{padding:10px 14px}\u001b[39m\n\u001b[31m  .cov-hdr-r{padding:10px 12px;width:150px}\u001b[39m\n\u001b[31m  .cov-store{font-size:15px}\u001b[39m\n\u001b[31m  .cov-meta{font-size:10px}\u001b[39m\n\u001b[31m  .cov-brand{font-size:11px;padding:3px 12px}\u001b[39m\n\u001b[31m  .cov-date-v{font-size:11px}\u001b[39m\n\u001b[31m  .ph-band{padding:5mm 13mm;gap:10mm}\u001b[39m\n\u001b[31m  .ph-cat{font-size:15mm}\u001b[39m\n\u001b[31m  .ph-dims{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-no{font-size:12mm;padding:2mm 8mm}\u001b[39m\n\u001b[31m  .ph-of{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-img{flex:1;display:flex;align-items:center;justify-content:center;background:#fff;overflow:hidden}\u001b[39m\n\u001b[31m  .ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m  .ph-img img{width:100%;height:100%;object-fit:contain}\u001b[39m\n\u001b[31m  .ph-cmt{position:static;background:transparent;color:#475569;padding:2mm 8mm;font-size:6mm}\u001b[39m\n\u001b[31m  .main>*:last-child{page-break-after:avoid;break-after:avoid}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m</style></head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<div class=\\\"side-idx\\\" id=\\\"side-idx\\\">${sideItems.join('')}</div>·\u001b[39m\n\u001b[31m<div class=\\\"main\\\" id=\\\"main\\\">·\u001b[39m\n\u001b[31m<div class=\\\"cover\\\" id=\\\"pg-cover\\\">\u001b[39m\n\u001b[31m  <div class=\\\"cov-hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-l\\\">\u001b[39m\n\u001b[31m      <div class=\\\"cov-store\\\">${esc(d.storeName||'Unknown Store')}</div>\u001b[39m\n\u001b[31m      ${(d.address||d.city)?`<div class=\\\"cov-meta\\\">&#x1F4CD; ${esc(d.address||'')}${d.city&&!(d.address||'').includes(d.city)?', '+esc(d.city):''}</div>`:''}\u001b[39m\n\u001b[31m      ${d.mobile?`<div class=\\\"cov-meta\\\">&#x1F4DE; ${esc(d.mobile)}</div>`:''}\u001b[39m\n\u001b[31m      ${d.email?`<div class=\\\"cov-meta\\\">&#x2709; ${esc(d.email)}</div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-r\\\">\u001b[39m\n\u001b[31m      ${brandLogoUrl\u001b[39m\n\u001b[31m        ? `<div class=\\\"cov-logo-box\\\"><img src=\\\"${brandLogoUrl}\\\" alt=\\\"${esc(d.brand||'')}\\\"></div>`\u001b[39m\n\u001b[31m        : (d.brand?`<div class=\\\"cov-brand\\\">${esc(d.brand)}</div>`:'')}\u001b[39m\n\u001b[31m      ${d.date?`<div><div class=\\\"cov-date-l\\\">Recce Date</div><div class=\\\"cov-date-v\\\">${esc(d.date)}</div></div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${thumbItems.length ? `<div class=\\\"cov-grid-hdr\\\">&#x1F4F7; ${thumbItems.length} page${thumbItems.length!==1?'s':''} &mdash; tap any to jump</div><div class=\\\"cov-grid\\\" id=\\\"cov-grid\\\">${thumbsHtml}</div>` : ''}\u001b[39m\n\u001b[31m  <div class=\\\"cover-pbar\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" id=\\\"btn-print\\\" onclick=\\\"doPDF()\\\">&#x1F4C4;&nbsp;PDF</button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-c\\\" onclick=\\\"window.close()\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m${pagesHtml}·\u001b[39m\n\u001b[31m${d.hasVideo?`\u001b[39m\n\u001b[31m<div class=\\\"vid-page\\\" id=\\\"pg-vid\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Video</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"vid-body\\\">${esc(d.videoNote||'Video recorded during visit')}${d.videoCmt?`<em>${esc(d.videoCmt)}</em>`:''}</div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m${urls.doc?`\u001b[39m\n\u001b[31m<div class=\\\"doc-page\\\" id=\\\"pg-doc\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Document</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"doc-wrap\\\"><a href=\\\"${urls.doc}\\\" target=\\\"_blank\\\"><img class=\\\"doc-img\\\" src=\\\"${urls.doc}\\\" loading=\\\"lazy\\\" alt=\\\"Document\\\"></a></div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"print-overlay\\\"><div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Preparing print&hellip;</div><div class=\\\"po-sub\\\" id=\\\"po-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"po-pfill\\\"></div></div></div>\u001b[39m\n\u001b[31m${pages.length ? `<div class=\\\"load-bar\\\" id=\\\"load-bar\\\"><div class=\\\"load-track\\\"><div class=\\\"load-fill\\\" id=\\\"load-fill\\\"></div></div><div class=\\\"load-txt\\\" id=\\\"load-txt\\\">Loading photos&#x2026;</div></div>` : ''}\u001b[39m\n\u001b[31m${thumbItems.length ? `<button id=\\\"cover-btn\\\" onclick=\\\"document.getElementById('pg-cover').scrollIntoView({behavior:'smooth'})\\\">&#x1F3E0;&nbsp;Cover Page</button>` : ''}·\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var main=document.getElementById('main');\u001b[39m\n\u001b[31m  var items=document.querySelectorAll('.si-item');\u001b[39m\n\u001b[31m  var covBtn=document.getElementById('cover-btn');\u001b[39m\n\u001b[31m  function setActive(id){\u001b[39m\n\u001b[31m    items.forEach(function(el){el.classList.toggle('active',el.dataset.tgt===id);});\u001b[39m\n\u001b[31m    var a=document.querySelector('.si-item[data-tgt=\\\"'+id+'\\\"]');\u001b[39m\n\u001b[31m    if(a) a.scrollIntoView({block:'nearest'});\u001b[39m\n\u001b[31m    if(covBtn) covBtn.style.display=id==='pg-cover'?'none':'flex';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  items.forEach(function(el){\u001b[39m\n\u001b[31m    el.addEventListener('click',function(){\u001b[39m\n\u001b[31m      var t=document.getElementById(el.dataset.tgt);\u001b[39m\n\u001b[31m      if(t) t.scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if('IntersectionObserver' in window){\u001b[39m\n\u001b[31m    var obs=new IntersectionObserver(function(entries){\u001b[39m\n\u001b[31m      entries.forEach(function(e){if(e.isIntersecting&&e.intersectionRatio>=0.45) setActive(e.target.id);});\u001b[39m\n\u001b[31m    },{root:main,threshold:0.45});\u001b[39m\n\u001b[31m    document.querySelectorAll('[id^=\\\"pg-\\\"]').forEach(function(p){obs.observe(p);});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  setActive('pg-cover');\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var imgs=Array.from(document.querySelectorAll('img'));\u001b[39m\n\u001b[31m  var total=imgs.length,loaded=0;\u001b[39m\n\u001b[31m  var bar=document.getElementById('load-bar');\u001b[39m\n\u001b[31m  var fill=document.getElementById('load-fill');\u001b[39m\n\u001b[31m  var txt=document.getElementById('load-txt');\u001b[39m\n\u001b[31m  var printPending=false,printShowTime=0;\u001b[39m\n\u001b[31m  var mm=96/25.4;\u001b[39m\n\u001b[31m  var SERVER_PDF='${serverPdfUrl}';\u001b[39m\n\u001b[31m  function updatePoBar(){\u001b[39m\n\u001b[31m    var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m    var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(poFill) poFill.style.width=(total?Math.round(loaded/total*100):100)+'%';\u001b[39m\n\u001b[31m    if(poSub) poSub.textContent=loaded+' / '+total+' photos ready';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function done(){\u001b[39m\n\u001b[31m    if(fill) fill.style.width='100%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='✓ All '+total+' photos ready';\u001b[39m\n\u001b[31m    setTimeout(function(){\u001b[39m\n\u001b[31m      if(bar){bar.style.transition='opacity .6s';bar.style.opacity='0';}\u001b[39m\n\u001b[31m      setTimeout(function(){if(bar)bar.style.display='none';},650);\u001b[39m\n\u001b[31m    },2000);\u001b[39m\n\u001b[31m    if(printPending){\u001b[39m\n\u001b[31m      printPending=false;\u001b[39m\n\u001b[31m      var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m      var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m      var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(poFill) poFill.style.width='100%';\u001b[39m\n\u001b[31m      if(poSub) poSub.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},Math.max(400,2000-(Date.now()-printShowTime)));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function onImg(){\u001b[39m\n\u001b[31m    loaded++;\u001b[39m\n\u001b[31m    if(fill) fill.style.width=Math.round(loaded/total*100)+'%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… '+loaded+' / '+total;\u001b[39m\n\u001b[31m    if(printPending) updatePoBar();\u001b[39m\n\u001b[31m    if(loaded>=total) done();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  /* ── PDF layout helpers ── */\u001b[39m\n\u001b[31m  function fitBandFonts(pageW){\u001b[39m\n\u001b[31m    var padH=2*13*mm,gapH=2*10*mm,noPadH=2*8*mm;\u001b[39m\n\u001b[31m    var avail=pageW-padH-gapH;\u001b[39m\n\u001b[31m    var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-band').forEach(function(band){\u001b[39m\n\u001b[31m      var cat=band.querySelector('.ph-cat');\u001b[39m\n\u001b[31m      var dims=band.querySelector('.ph-dims');\u001b[39m\n\u001b[31m      var no=band.querySelector('.ph-no');\u001b[39m\n\u001b[31m      if(!cat) return;\u001b[39m\n\u001b[31m      var catTxt=cat.textContent.trim();\u001b[39m\n\u001b[31m      var dimsTxt=dims?dims.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      var noTxt=no?no.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      function tw(sc){\u001b[39m\n\u001b[31m        var cf=15*sc*mm,df=10*sc*mm,nf=12*sc*mm;\u001b[39m\n\u001b[31m        ctx.font='800 '+cf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var cw=ctx.measureText(catTxt).width;\u001b[39m\n\u001b[31m        ctx.font='600 '+df+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var dw=dims?ctx.measureText(dimsTxt).width:0;\u001b[39m\n\u001b[31m        ctx.font='700 '+nf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var nw=no?ctx.measureText(noTxt).width+noPadH:0;\u001b[39m\n\u001b[31m        return cw+dw+nw;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      var scale=1.0;\u001b[39m\n\u001b[31m      if(tw(scale)>avail){\u001b[39m\n\u001b[31m        var lo=0.3,hi=1.0;\u001b[39m\n\u001b[31m        for(var i=0;i<10;i++){var mid=(lo+hi)/2;if(tw(mid)<=avail)lo=mid;else hi=mid;}\u001b[39m\n\u001b[31m        scale=lo*0.93;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      cat.style.setProperty('font-size',Math.round(15*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(dims) dims.style.setProperty('font-size',Math.round(10*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(no) no.style.setProperty('font-size',Math.round(12*scale*mm)+'px','important');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function sizePdfThumbs(pageW,pageH){\u001b[39m\n\u001b[31m    var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m    if(!grid||!grid.children.length) return;\u001b[39m\n\u001b[31m    var coverPage=document.getElementById('pg-cover');\u001b[39m\n\u001b[31m    var usedH=56;\u001b[39m\n\u001b[31m    if(coverPage){\u001b[39m\n\u001b[31m      Array.from(coverPage.children).forEach(function(el){\u001b[39m\n\u001b[31m        if(el!==grid) usedH+=el.offsetHeight||0;\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    var gridH=Math.max(80,pageH-usedH);\u001b[39m\n\u001b[31m    var n=grid.children.length,gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m    for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m      var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m      var w=(pageW-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m      var h=w*asp;\u001b[39m\n\u001b[31m      if(rows*h+(rows-1)*gap<=gridH&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m    grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m    grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m    var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m    var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m    var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function preparePdfLayout(){\u001b[39m\n\u001b[31m    var pageW=Math.round((297-24)*mm);\u001b[39m\n\u001b[31m    var pageH=Math.round((210-24)*mm);\u001b[39m\n\u001b[31m    fitBandFonts(pageW);\u001b[39m\n\u001b[31m    sizePdfThumbs(pageW,pageH);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.preparePdfLayout=preparePdfLayout;\u001b[39m\n\u001b[31m  function restorePdfLayout(){\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-cat,.ph-dims,.ph-no').forEach(function(el){\u001b[39m\n\u001b[31m      el.style.removeProperty('font-size');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(window._screenSizeThumbs) window._screenSizeThumbs();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.addEventListener('afterprint',restorePdfLayout);\u001b[39m\n\u001b[31m  function _doBrowserPrint(){\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    printShowTime=Date.now();\u001b[39m\n\u001b[31m    preparePdfLayout();\u001b[39m\n\u001b[31m    if(total===0||loaded>=total){\u001b[39m\n\u001b[31m      var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m      if(ps) ps.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},2000);\u001b[39m\n\u001b[31m      return;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    printPending=true;\u001b[39m\n\u001b[31m    updatePoBar();\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if((!img.complete||img.naturalWidth===0)&&img.getAttribute('loading')==='lazy'){\u001b[39m\n\u001b[31m        img.loading='eager';var s=img.src;img.src='';img.src=s;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.doPDF=async function(){\u001b[39m\n\u001b[31m    if(!SERVER_PDF){_doBrowserPrint();return;}\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      var r=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m      if(r.ok){window.open(SERVER_PDF,'_blank');return;}\u001b[39m\n\u001b[31m    }catch(_){}\u001b[39m\n\u001b[31m    // PDF not ready yet — show overlay and poll\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    if(pf) pf.style.width='0%';\u001b[39m\n\u001b[31m    if(ps) ps.textContent='Waiting for server PDF…';\u001b[39m\n\u001b[31m    var tries=0;\u001b[39m\n\u001b[31m    (async function poll(){\u001b[39m\n\u001b[31m      tries++;\u001b[39m\n\u001b[31m      if(pf) pf.style.width=Math.min(88,tries*8)+'%';\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        var r2=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m        if(r2.ok){\u001b[39m\n\u001b[31m          if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m          setTimeout(function(){if(ov)ov.style.display='none';window.open(SERVER_PDF,'_blank');},400);\u001b[39m\n\u001b[31m          return;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      }catch(_){}\u001b[39m\n\u001b[31m      if(tries>=12){if(ov)ov.style.display='none';_doBrowserPrint();return;}\u001b[39m\n\u001b[31m      setTimeout(poll,5000);\u001b[39m\n\u001b[31m    })();\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  if(total===0){if(bar)bar.style.display='none';}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… 0 / '+total;\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if(img.complete&&img.naturalWidth>0) onImg();\u001b[39m\n\u001b[31m      else{img.addEventListener('load',onImg);img.addEventListener('error',onImg);}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m  if(grid&&grid.children.length>0){\u001b[39m\n\u001b[31m    function sizeThumbs(){\u001b[39m\n\u001b[31m      var n=grid.children.length;\u001b[39m\n\u001b[31m      var gw=grid.clientWidth,gh=grid.clientHeight;\u001b[39m\n\u001b[31m      if(!gw||!gh) return;\u001b[39m\n\u001b[31m      var gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m      for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m        var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m        var w=(gw-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m        var h=w*asp;\u001b[39m\n\u001b[31m        if(rows*h+(rows-1)*gap<=gh&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m      grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m      grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m      var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m      var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m      var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    window._screenSizeThumbs=sizeThumbs;\u001b[39m\n\u001b[31m    requestAnimationFrame(function(){requestAnimationFrame(sizeThumbs);});\u001b[39m\n\u001b[31m    window.addEventListener('resize',sizeThumbs);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m</scr`+'ipt>'+`\u001b[39m\n\u001b[31m</body></html>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncToPostgres(entry) {\u001b[39m\n\u001b[31m  const d   = entry.data || {};\u001b[39m\n\u001b[31m  const hub = _recceHubUser();·\u001b[39m\n\u001b[31m  // Step 1 — upload all photos to VPS, get permanent server URLs\u001b[39m\n\u001b[31m  let photoUrls = { front:[], inside:[], brandings:[], addl:[], doc:null };\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const pResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type: 'save-photos', subId: entry.id,\u001b[39m\n\u001b[31m        photos: {\u001b[39m\n\u001b[31m          front:    (d.frontPhotos||[]).map(p=>({b64:p.b64,   cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64,  cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||null})),\u001b[39m\n\u001b[31m          addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64,   desc:p.desc||''})),\u001b[39m\n\u001b[31m          doc:      d.docB64 || null,\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (pResp.ok) { const r=await pResp.json(); if(r.success) {\u001b[39m\n\u001b[31m      photoUrls=r.photoUrls;\u001b[39m\n\u001b[31m      // Merge retained existing URLs for edit re-submits\u001b[39m\n\u001b[31m      if (entry.editedAt) {\u001b[39m\n\u001b[31m        photoUrls.front    =(photoUrls.front   ||[]).map((u,i)=>u||(d.frontPhotos  ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.inside   =(photoUrls.inside  ||[]).map((u,i)=>u||(d.insidePhotos ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.addl     =(photoUrls.addl    ||[]).map((u,i)=>u||(d.addlPhotos   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.brandings=(photoUrls.brandings||[]).map((u,i)=>u||(d.brandings   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        if(!photoUrls.doc) photoUrls.doc=d._docExistingUrl||null;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }}\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-photos] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 1.5 — trigger Google Slides via proxy using permanent photo URLs (fire-and-forget)\u001b[39m\n\u001b[31m  (async()=>{try{\u001b[39m\n\u001b[31m    const _hasPh=(photoUrls.front||[]).some(Boolean)||(photoUrls.inside||[]).some(Boolean)||(photoUrls.brandings||[]).some(Boolean);\u001b[39m\n\u001b[31m    if(!_hasPh)return;\u001b[39m\n\u001b[31m    const _gu=(await cfg('slides-gas-url'))||(await cfg('gas-url'))||DEFAULT_GAS_URL;if(!_gu)return;\u001b[39m\n\u001b[31m    await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({\u001b[39m\n\u001b[31m      type:'make-slides',gasUrl:_gu,subId:entry.id,\u001b[39m\n\u001b[31m      storeInfo:{storeName:d.storeName||'',brand:d.brand||'',address:d.address||'',mobile:d.mobile||'',date:d.date||'',city:d.city||'',gpsCoords:d.gpsCoords||null},\u001b[39m\n\u001b[31m      photoGroups:{\u001b[39m\n\u001b[31m        front:    (photoUrls.front   ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.frontPhotos  ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        inside:   (photoUrls.inside  ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.insidePhotos ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        brandings:(photoUrls.brandings||[]).filter(Boolean).map((url,i)=>({url,meta:{type:(d.brandings||[])[i]?.type,w:(d.brandings||[])[i]?.w,h:(d.brandings||[])[i]?.h,qty:(d.brandings||[])[i]?.qty,sqft:(d.brandings||[])[i]?.sqft}})),\u001b[39m\n\u001b[31m        addl:    (photoUrls.addl    ||[]).filter(Boolean).map((url,i)=>({url,desc:(d.addlPhotos  ||[])[i]?.desc||''})),\u001b[39m\n\u001b[31m      },\u001b[39m\n\u001b[31m    })});\u001b[39m\n\u001b[31m    entry.gasAt=new Date().toISOString();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[recce-slides]',e.message);}}\u001b[39m\n\u001b[31m  )();·\u001b[39m\n\u001b[31m  // Step 2 — generate rich HTML report using server URLs, save to VPS\u001b[39m\n\u001b[31m  let view_url = null;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const html  = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m    const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-view', subId: entry.id, html })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (vResp.ok) { const r=await vResp.json(); if(r.success) view_url=r.url; }\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-view] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 3 — upsert to PostgreSQL with photo URLs + view URL\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch(`${_RC_BASE}/submissions`, {\u001b[39m\n\u001b[31m      method: 'POST', headers: _RC_UPSERT,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        sub_id:         entry.id,\u001b[39m\n\u001b[31m        store_name:     d.storeName    || 'Unknown',\u001b[39m\n\u001b[31m        brand:          d.brand        || null,\u001b[39m\n\u001b[31m        client_name:    d.clientName   || null,\u001b[39m\n\u001b[31m        visit_date:     d.date         || new Date().toISOString().slice(0,10),\u001b[39m\n\u001b[31m        address:        d.address      || null,\u001b[39m\n\u001b[31m        mobile:         d.mobile       || null,\u001b[39m\n\u001b[31m        city:           d.city         || null,\u001b[39m\n\u001b[31m        has_branding:   !!(d.brandings?.length),\u001b[39m\n\u001b[31m        branding_count: d.brandings?.length || 0,\u001b[39m\n\u001b[31m        has_video:      !!d.hasVideo,\u001b[39m\n\u001b[31m        front_photos:   d.frontPhotos?.length  || 0,\u001b[39m\n\u001b[31m        inside_photos:  d.insidePhotos?.length || 0,\u001b[39m\n\u001b[31m        addl_photos:    d.addlPhotos?.length   || 0,\u001b[39m\n\u001b[31m        gps_lat:        d.gpsCoords?.lat       || null,\u001b[39m\n\u001b[31m        gps_lng:        d.gpsCoords?.lng       || null,\u001b[39m\n\u001b[31m        submitted_by:   hub.empId              || null,\u001b[39m\n\u001b[31m        submitted_at:   entry.timestamp,\u001b[39m\n\u001b[31m        campaign_id:    entry.campaignId       || null,\u001b[39m\n\u001b[31m        photo_urls:     photoUrls,\u001b[39m\n\u001b[31m        view_url,\u001b[39m\n\u001b[31m        meta: {\u001b[39m\n\u001b[31m          brandings: (d.brandings||[]).map(b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft})),\u001b[39m\n\u001b[31m          videoNote: d.videoNote || null,\u001b[39m\n\u001b[31m          videoCmt:  d.videoCmt  || null,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        status: 'submitted',\u001b[39m\n\u001b[31m        edit_assigned_to: null,\u001b[39m\n\u001b[31m        edit_comment: null,\u001b[39m\n\u001b[31m        edited_at: entry.editedAt || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    return { ok: true, viewUrl: view_url };\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    console.warn('[recce-db] sync error:', e.message);\u001b[39m\n\u001b[31m    return { ok: false, viewUrl: null };\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mconst DEFAULT_ADMIN_HASH='42d372e6110bee134990ac6881c3d5eb568482008add9a859f37f10d759430e8';·\u001b[39m\n\u001b[31masync function saveGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('gas-url',url||DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  toast('Endpoint saved','success');\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function testEndpoint(){\u001b[39m\n\u001b[31m  const url=(await cfg('gas-url'))||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  try{await fetch(url,{method:'POST',mode:'no-cors',body:JSON.stringify({test:true})});toast('Endpoint reachable ✓','success');}\u001b[39m\n\u001b[31m  catch{toast('Cannot reach endpoint','error')}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  cfg('gas-url').then(url=>{\u001b[39m\n\u001b[31m    const u=url||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    // Show last 30 chars only for privacy\u001b[39m\n\u001b[31m    el.textContent='Endpoint: …'+u.slice(-30);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── SLIDES GAS URL ────────────────────────────────────────────\u001b[39m\n\u001b[31masync function saveSlidesGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('slides-gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('slides-gas-url', url);\u001b[39m\n\u001b[31m  toast('Slides GAS URL saved','success');\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function updateSlidesGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('slides-gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  const u=await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  el.textContent=u?'Configured: …'+u.slice(-30):'Not configured';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── MAKE SLIDES ───────────────────────────────────────────────\u001b[39m\n\u001b[31masync function makeSlides(id){\u001b[39m\n\u001b[31m  const gasUrl = await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  if(!gasUrl){\u001b[39m\n\u001b[31m    toast('Configure Slides GAS URL in Settings first','error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const entry = await dbGet('subs', id);\u001b[39m\n\u001b[31m  if(!entry){ toast('Entry not found','error'); return; }\u001b[39m\n\u001b[31m  const d = entry.data;·\u001b[39m\n\u001b[31m  toast('Uploading photos & generating slides…','info');·\u001b[39m\n\u001b[31m  // Build photo groups payload\u001b[39m\n\u001b[31m  const photoGroups = {\u001b[39m\n\u001b[31m    front:    (d.frontPhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64, cmt:p.desc||''})),\u001b[39m\n\u001b[31m    brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||'', meta:{type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft}})),\u001b[39m\n\u001b[31m  };·\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type:       'recce',\u001b[39m\n\u001b[31m        subId:      id,\u001b[39m\n\u001b[31m        gasUrl:     gasUrl,\u001b[39m\n\u001b[31m        storeInfo:  {\u001b[39m\n\u001b[31m          storeName: d.storeName, brand: d.brand,\u001b[39m\n\u001b[31m          date: d.date, address: d.address,\u001b[39m\n\u001b[31m          mobile: d.mobile, gpsCoords: d.gpsCoords,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        photoGroups,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const result = await resp.json();\u001b[39m\n\u001b[31m    if(result.success && result.slideUrl){\u001b[39m\n\u001b[31m      // Store slide URL on the entry\u001b[39m\n\u001b[31m      entry.slideUrl = result.slideUrl;\u001b[39m\n\u001b[31m      await dbPut('subs', entry);\u001b[39m\n\u001b[31m      toast('✅ Slides ready!','success');\u001b[39m\n\u001b[31m      window.open(result.slideUrl, '_blank');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast('Slides error: '+(result.error||'Unknown'),'error');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e){\u001b[39m\n\u001b[31m    toast('Network error: '+e.message,'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN LOGIN ──────────────────────────────────────────────\u001b[39m\n\u001b[31mfunction showAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-error').style.display='none';\u001b[39m\n\u001b[31m  // Restore saved config URL\u001b[39m\n\u001b[31m  cfg('admin-cfg-url').then(u=>{if(u&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=u;});\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('admin-pwd').focus(),100);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveAdminCfgUrl(){\u001b[39m\n\u001b[31m  // Admin cfg URL can be saved without login (needed to set up auth itself)\u001b[39m\n\u001b[31m  // But we warn if saving while unlocked only\u001b[39m\n\u001b[31m  const url=document.getElementById('admin-cfg-url').value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  await cfg('admin-cfg-url',url);\u001b[39m\n\u001b[31m  toast('Config URL saved — will use on next login attempt','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function verifyAdmin(){\u001b[39m\n\u001b[31m  // Hub admins (harish/pramod) are auto-unlocked — no password needed\u001b[39m\n\u001b[31m  if (_adminUnlocked) { adminLoginSuccess(); return; }\u001b[39m\n\u001b[31m  const pwd=document.getElementById('admin-pwd').value;\u001b[39m\n\u001b[31m  if(!pwd){document.getElementById('admin-error').style.display='block';document.getElementById('admin-error').textContent='Enter password';return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('admin-login-btn');btn.disabled=true;btn.textContent='Verifying…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // Try server verification first\u001b[39m\n\u001b[31m    const cfgUrl=(await cfg('admin-cfg-url'))||'';\u001b[39m\n\u001b[31m    if(cfgUrl){\u001b[39m\n\u001b[31m      const r=await fetch(cfgUrl,{cache:'no-store'});\u001b[39m\n\u001b[31m      const j=await r.json();\u001b[39m\n\u001b[31m      // Server JSON format: {\\\"password\\\":\\\"plaintext\\\"} or {\\\"hash\\\":\\\"sha256hash\\\"}\u001b[39m\n\u001b[31m      let match=false;\u001b[39m\n\u001b[31m      if(j.password){match=(j.password===pwd);}\u001b[39m\n\u001b[31m      else if(j.hash){\u001b[39m\n\u001b[31m        // SHA-256 comparison\u001b[39m\n\u001b[31m        const enc=new TextEncoder();\u001b[39m\n\u001b[31m        const data=enc.encode(pwd);\u001b[39m\n\u001b[31m        const hashBuf=await crypto.subtle.digest('SHA-256',data);\u001b[39m\n\u001b[31m        const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m        match=(hashHex===j.hash);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      if(match){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m      else{showAdminError('Incorrect password');return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Fallback: local password stored in settings\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if(localHash){\u001b[39m\n\u001b[31m      const enc=new TextEncoder();\u001b[39m\n\u001b[31m      const hashBuf=await crypto.subtle.digest('SHA-256',enc.encode(pwd));\u001b[39m\n\u001b[31m      const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m      if(hashHex===localHash){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Final fallback: check against hardcoded default hash\u001b[39m\n\u001b[31m    const enc2=new TextEncoder();\u001b[39m\n\u001b[31m    const hb2=await crypto.subtle.digest('SHA-256',enc2.encode(pwd));\u001b[39m\n\u001b[31m    const hh2=Array.from(new Uint8Array(hb2)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    if(hh2===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }catch(err){\u001b[39m\n\u001b[31m    // Network error — try all local fallbacks\u001b[39m\n\u001b[31m    const enc3=new TextEncoder();\u001b[39m\n\u001b[31m    const hb3=await crypto.subtle.digest('SHA-256',enc3.encode(pwd));\u001b[39m\n\u001b[31m    const hh3=Array.from(new Uint8Array(hb3)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if((localHash&&hh3===localHash)||hh3===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }finally{btn.disabled=false;btn.textContent='Login';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showAdminError(msg){\u001b[39m\n\u001b[31m  const el=document.getElementById('admin-error');\u001b[39m\n\u001b[31m  el.textContent=msg;el.style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminLoginSuccess(){\u001b[39m\n\u001b[31m  _adminUnlocked=true;\u001b[39m\n\u001b[31m  closeAdminLogin();\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  cfg('gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  cfg('slides-gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('slides-gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||'';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  toast('Admin mode unlocked','success');\u001b[39m\n\u001b[31m  setTimeout(lockAdmin,10*60*1000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction lockAdmin(){\u001b[39m\n\u001b[31m  _adminUnlocked=false;\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  toast('Admin session ended','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updAvailTag(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-avail-tag');\u001b[39m\n\u001b[31m  const ct=document.getElementById('store-avail-count');\u001b[39m\n\u001b[31m  const txt=stores.length?`${stores.length} stores`:'No store list';\u001b[39m\n\u001b[31m  if(el)el.textContent=txt;\u001b[39m\n\u001b[31m  if(ct)ct.textContent=stores.length?t(`${stores.length} stores available — tap to browse`,`${stores.length} स्टोर उपलब्ध — दबाएं`):t('No store list loaded yet','कोई स्टोर सूची नहीं');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PICKER\u001b[39m\n\u001b[31mfunction openPicker(){\u001b[39m\n\u001b[31m  if(!stores.length){toast('Load a store list in Settings first','error');return;}\u001b[39m\n\u001b[31m  document.getElementById('povl').classList.add('open');\u001b[39m\n\u001b[31m  document.getElementById('psearch').value='';\u001b[39m\n\u001b[31m  filterPicker('');\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('psearch').focus(),150);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closePicker(){document.getElementById('povl').classList.remove('open');}\u001b[39m\n\u001b[31masync function filterPicker(q){\u001b[39m\n\u001b[31m  const list=document.getElementById('plist');\u001b[39m\n\u001b[31m  const words=q.toLowerCase().trim().split(/\\\\s+/).filter(Boolean);\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const lastVisit={};\u001b[39m\n\u001b[31m  subs.forEach(s=>{const nm=s.data?.storeName;if(nm&&(!lastVisit[nm]||s.timestamp>lastVisit[nm]))lastVisit[nm]=s.timestamp;});·\u001b[39m\n\u001b[31m  // Multi-word: ALL words must match somewhere in any field (search across both English and Hindi)\u001b[39m\n\u001b[31m  let fl=stores.filter(s=>{\u001b[39m\n\u001b[31m    if(!words.length)return true;\u001b[39m\n\u001b[31m    const hay=[s.name,s.nameHi,s.address,s.addressHi,s.mobile,s.city,s.cityHi,s.distName,s.distNameHi,s.brand,s.sales,s.proj,s.glowSign,s.inshop]\u001b[39m\n\u001b[31m               .map(x=>(x||'').toLowerCase()).join(' ');\u001b[39m\n\u001b[31m    return words.every(w=>hay.includes(w));\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(fl.length>100)fl=fl.slice(0,100);·\u001b[39m\n\u001b[31m  if(!fl.length){\u001b[39m\n\u001b[31m    const esc=q.replace(/'/g,\\\"\\\\\\\\'\\\");\u001b[39m\n\u001b[31m    list.innerHTML=`<div style=\\\"text-align:center;padding:32px 16px;color:var(--g400);font-size:14px\\\">No stores match \\\"${q}\\\"<br><span style=\\\"font-size:12px\\\">Try fewer or different words</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('${esc}')\\\">+ Add \\\"${q}\\\" as new store</div>`;\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Group by brand (including empty brand)\u001b[39m\n\u001b[31m  const g={};\u001b[39m\n\u001b[31m  fl.forEach(s=>{\u001b[39m\n\u001b[31m    const b=s.brand||'(No Brand — will ask)';\u001b[39m\n\u001b[31m    if(!g[b])g[b]=[];\u001b[39m\n\u001b[31m    g[b].push(s);\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html='';\u001b[39m\n\u001b[31m  Object.keys(g).sort().forEach(br=>{\u001b[39m\n\u001b[31m    html+=`<div class=\\\"psec\\\">${br}</div>`;\u001b[39m\n\u001b[31m    g[br].forEach(s=>{\u001b[39m\n\u001b[31m      const lv=lastVisit[s.name];\u001b[39m\n\u001b[31m      const lvStr=lv?`🕐 Last: ${new Date(lv).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'2-digit'})}`:'';\u001b[39m\n\u001b[31m      const chips=[];\u001b[39m\n\u001b[31m      if(s.glowSign&&s.glowSign.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dcfce7;color:#14532d;padding:2px 6px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m      if(s.inshop&&s.inshop.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dbeafe;color:#1e40af;padding:2px 6px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m      if(s.proj)chips.push(`<span style=\\\"font-size:10px;background:var(--g100);color:var(--g600);padding:2px 6px;border-radius:10px\\\">Target: ${s.proj}</span>`);\u001b[39m\n\u001b[31m      const enc=JSON.stringify(s).replace(/\\\"/g,'&quot;');\u001b[39m\n\u001b[31m      const mapsUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m      const waUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const telUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const dispName=LANG==='hi'&&s.nameHi?s.nameHi:s.name;\u001b[39m\n\u001b[31m      const dispAddr=LANG==='hi'&&s.addressHi?s.addressHi:s.address;\u001b[39m\n\u001b[31m      const dispDist=LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m      html+=`<div class=\\\"pitem\\\" onclick=\\\"pickStore(${enc})\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"pi-name\\\">${dispName}</div>\u001b[39m\n\u001b[31m          ${dispAddr?`<div class=\\\"pi-addr\\\">📍 ${dispAddr}</div>`:''}\u001b[39m\n\u001b[31m          ${s.mobile?`<div class=\\\"pi-addr\\\">📞 ${s.mobile}</div>`:''}\u001b[39m\n\u001b[31m          ${dispDist?`<div class=\\\"pi-addr\\\" style=\\\"color:var(--am)\\\">👤 ${dispDist}</div>`:''}\u001b[39m\n\u001b[31m          ${lvStr?`<div class=\\\"pi-last\\\">${lvStr}</div>`:''}\u001b[39m\n\u001b[31m          ${chips.length?`<div style=\\\"display:flex;gap:4px;flex-wrap:wrap;margin-top:4px\\\">${chips.join('')}</div>`:''}\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;gap:6px;margin-top:7px\\\" onclick=\\\"event.stopPropagation()\\\">\u001b[39m\n\u001b[31m            ${mapsUrl?`<a href=\\\"${mapsUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#e0f2fe;color:#0369a1;border-radius:20px;text-decoration:none;font-weight:600\\\">🗺 Maps</a>`:''}\u001b[39m\n\u001b[31m            ${waUrl?`<a href=\\\"${waUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#dcfce7;color:#15803d;border-radius:20px;text-decoration:none;font-weight:600\\\">💬 WhatsApp</a>`:''}\u001b[39m\n\u001b[31m            ${telUrl?`<a href=\\\"${telUrl}\\\" style=\\\"font-size:11px;padding:4px 10px;background:#f0fdf4;color:#166534;border-radius:20px;text-decoration:none;font-weight:600\\\">📞 Call</a>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        ${s.brand?`<div class=\\\"pi-brand\\\">${s.brand}</div>`:'<div class=\\\"pi-brand\\\" style=\\\"background:var(--rd)\\\">?</div>'}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html+=`<div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('')\\\">+ Not in list? Add new store</div>`;\u001b[39m\n\u001b[31m  list.innerHTML=html;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function pickStore(s){\u001b[39m\n\u001b[31m  selectedStore=s;manualMode=false;closePicker();\u001b[39m\n\u001b[31m  const _dn =LANG==='hi'&&s.nameHi    ?s.nameHi    :s.name;\u001b[39m\n\u001b[31m  const _da =LANG==='hi'&&s.addressHi ?s.addressHi :s.address;\u001b[39m\n\u001b[31m  const _dd =LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m  const _dc =LANG==='hi'&&s.cityHi    ?s.cityHi    :s.city;\u001b[39m\n\u001b[31m  document.getElementById('sc-name').textContent=_dn;\u001b[39m\n\u001b[31m  const brandEl=document.getElementById('sc-brand');\u001b[39m\n\u001b[31m  brandEl.textContent=s.brand||'No Brand';brandEl.style.background=s.brand?'var(--nv)':'var(--rd)';\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const prev=subs.filter(x=>x.data?.storeName===s.name).sort((a,b)=>new Date(b.timestamp)-new Date(a.timestamp))[0];\u001b[39m\n\u001b[31m  const lc=document.getElementById('sc-last');\u001b[39m\n\u001b[31m  if(prev){const d=new Date(prev.timestamp);lc.textContent='Last: '+d.toLocaleDateString('en-IN',{day:'numeric',month:'short'});lc.style.display='inline-flex';}\u001b[39m\n\u001b[31m  else lc.style.display='none';\u001b[39m\n\u001b[31m  // All Excel fields — display in active language\u001b[39m\n\u001b[31m  const mUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m  const wUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const tUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const details=[];\u001b[39m\n\u001b[31m  if(_da)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📍 ${_da}${mUrl?` <a href=\\\"${mUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#0369a1;margin-left:6px\\\">🗺 Navigate</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(s.mobile)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📞 ${s.mobile}${tUrl?` <a href=\\\"${tUrl}\\\" style=\\\"font-size:11px;color:#166534;margin-left:6px\\\">Call</a>`:''}${wUrl?` <a href=\\\"${wUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#15803d;margin-left:6px\\\">WhatsApp</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(_dd)details.push(`<div style=\\\"font-size:12px;color:var(--am)\\\">👤 ${_dd}</div>`);\u001b[39m\n\u001b[31m  if(_dc)details.push(`<div style=\\\"font-size:12px;color:var(--g500)\\\">🏙 ${_dc}</div>`);\u001b[39m\n\u001b[31m  const opp=[];\u001b[39m\n\u001b[31m  if(s.glowSign&&s.glowSign.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dcfce7;color:#14532d;padding:2px 7px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m  if(s.inshop&&s.inshop.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dbeafe;color:#1e40af;padding:2px 7px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m  if(s.proj)opp.push(`<span style=\\\"font-size:11px;background:var(--g100);color:var(--g600);padding:2px 7px;border-radius:10px\\\">Target 2026: ${s.proj}</span>`);\u001b[39m\n\u001b[31m  if(opp.length)details.push(`<div style=\\\"display:flex;gap:5px;flex-wrap:wrap;margin-top:3px\\\">${opp.join('')}</div>`);\u001b[39m\n\u001b[31m  document.getElementById('sc-details').innerHTML=details.join('');\u001b[39m\n\u001b[31m  // Missing fields\u001b[39m\n\u001b[31m  const missing=[];\u001b[39m\n\u001b[31m  if(!s.address)missing.push({key:'address',label:'Store Address',type:'textarea',placeholder:'Full address'});\u001b[39m\n\u001b[31m  if(!s.mobile)missing.push({key:'mobile',label:'Mobile No.',type:'tel',placeholder:'10-digit number',maxlen:'10'});\u001b[39m\n\u001b[31m  const mw=document.getElementById('sc-missing'),mf=document.getElementById('sc-missing-fields');\u001b[39m\n\u001b[31m  if(missing.length){\u001b[39m\n\u001b[31m    mf.innerHTML=missing.map(m=>`<div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\"><label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">${m.label} <span class=\\\"req\\\">*</span></label>${m.type==='textarea'?`<textarea id=\\\"sc-miss-${m.key}\\\" rows=\\\"2\\\" placeholder=\\\"${m.placeholder}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></textarea>`:`<input type=\\\"${m.type}\\\" id=\\\"sc-miss-${m.key}\\\" placeholder=\\\"${m.placeholder}\\\" ${m.maxlen?`maxlength=\\\"${m.maxlen}\\\"`:''}  inputmode=\\\"${m.type==='tel'?'numeric':'text'}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\">`}</div>`).join('');\u001b[39m\n\u001b[31m    mw.style.display='block';\u001b[39m\n\u001b[31m  } else {mw.style.display='none';}\u001b[39m\n\u001b[31m  // Brand selector\u001b[39m\n\u001b[31m  const bSel=document.getElementById('brand-selector'),bChips=document.getElementById('brand-chips');\u001b[39m\n\u001b[31m  if(!s.brand){\u001b[39m\n\u001b[31m    renderBrandChips();\u001b[39m\n\u001b[31m    bSel.style.display='block';\u001b[39m\n\u001b[31m  } else {bSel.style.display='none';}\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  F.storeName=s.name;F.brand=s.brand||'';F.address=s.address||'';F.mobile=s.mobile||'';\u001b[39m\n\u001b[31m  if(s.brand&&!_selectedClient&&!_clientOtherMode) autoSetClient(s.brand);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateMissingField(key,val){if(!selectedStore)return;selectedStore[key]=val.trim();F[key]=val.trim();saveDraft();}\u001b[39m\n\u001b[31mfunction selectStoreBrand(b){\u001b[39m\n\u001b[31m  F.brand=b;F.brandLogoUrl=_brandLogos[b]||'';\u001b[39m\n\u001b[31m  if(selectedStore)selectedStore.brand=b;\u001b[39m\n\u001b[31m  const el=document.getElementById('sc-brand');if(el){el.textContent=b;el.style.background='var(--nv)';}\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-chips .chip').forEach(c=>{c.classList.toggle('sel',c.querySelector('span')?.textContent===b||c.textContent.trim()===b);});\u001b[39m\n\u001b[31m  if(!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction onManualBrandChange(){\u001b[39m\n\u001b[31m  const b=document.getElementById('f-brand')?.value||'';\u001b[39m\n\u001b[31m  F.brandLogoUrl=b?(_brandLogos[b]||''):'';\u001b[39m\n\u001b[31m  if(b&&!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction openManual(prefill){\u001b[39m\n\u001b[31m  manualMode=true;\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').classList.add('on');\u001b[39m\n\u001b[31m  document.getElementById('mt-label').innerHTML='← Back to store list';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='block';\u001b[39m\n\u001b[31m  // Pre-fill from selectedStore if available (e.g. when toggling after picker selection)\u001b[39m\n\u001b[31m  const s=selectedStore;\u001b[39m\n\u001b[31m  if(s){\u001b[39m\n\u001b[31m    if(document.getElementById('f-brand'))document.getElementById('f-brand').value=s.brand||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-store'))document.getElementById('f-store').value=s.name||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-addr'))document.getElementById('f-addr').value=s.address||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-mobile'))document.getElementById('f-mobile').value=s.mobile||'';\u001b[39m\n\u001b[31m  } else if(prefill){\u001b[39m\n\u001b[31m    document.getElementById('f-store').value=prefill;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  selectedStore=null;\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction toggleManual(){\u001b[39m\n\u001b[31m  if(manualMode){\u001b[39m\n\u001b[31m    manualMode=false;\u001b[39m\n\u001b[31m    document.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31m    document.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31m    document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    openManual('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// GPS\u001b[39m\n\u001b[31mfunction captureGPS(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gps-status');el.textContent='Getting location…';el.style.color='var(--g500)';\u001b[39m\n\u001b[31m  if(!navigator.geolocation){el.textContent='GPS not available';return;}\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(pos=>{\u001b[39m\n\u001b[31m    gpsCoords={lat:pos.coords.latitude.toFixed(6),lng:pos.coords.longitude.toFixed(6),acc:Math.round(pos.coords.accuracy)};\u001b[39m\n\u001b[31m    el.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${gpsCoords.acc}m)`;el.style.color='var(--gn)';saveDraft();\u001b[39m\n\u001b[31m  },()=>{el.textContent='GPS failed — enter address manually';el.style.color='var(--rd)';},{enableHighAccuracy:true,timeout:10000});\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// DRAFT\u001b[39m\n\u001b[31mlet draftT;\u001b[39m\n\u001b[31mfunction saveDraft(){\u001b[39m\n\u001b[31m  clearTimeout(draftT);\u001b[39m\n\u001b[31m  draftT=setTimeout(async()=>{\u001b[39m\n\u001b[31m    const draft={k:'current',ts:Date.now(),F:{...F,date:document.getElementById('f-date')?.value||'',brand:manualMode?(document.getElementById('f-brand')?.value||''):(selectedStore?.brand||F.brand||''),storeName:selectedStore?selectedStore.name:(document.getElementById('f-store')?.value||''),address:manualMode?(document.getElementById('f-addr')?.value||''):(selectedStore?.address||F.address||''),mobile:manualMode?(document.getElementById('f-mobile')?.value||''):(selectedStore?.mobile||F.mobile||''),clientName:getClientName()},selectedStore,manualMode,gpsCoords,_selectedClient,_clientOtherMode,fCnt:frontPhotos.length,iCnt:insidePhotos.length,bCnt:brandings.length};\u001b[39m\n\u001b[31m    await dbPut('draft',draft);\u001b[39m\n\u001b[31m    // Also save photos as b64 blobs to draft so they survive exit\u001b[39m\n\u001b[31m    await saveDraftPhotos();\u001b[39m\n\u001b[31m  },500);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveDraftPhotos(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const photoData={\u001b[39m\n\u001b[31m      front:await Promise.all(frontPhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      inside:await Promise.all(insidePhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      addl:await Promise.all(addlPhotos.map(async p=>({b64:await b64(p.blob),desc:p.desc||''}))),\u001b[39m\n\u001b[31m      brand:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,b64:b.blob?await b64(b.blob):null})))\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    await dbPut('draft',{k:'photos',...photoData});\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function checkDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');const wrap=document.getElementById('resume-wrap');\u001b[39m\n\u001b[31m  if(!d||!d.F?.storeName){wrap.innerHTML='';return;}\u001b[39m\n\u001b[31m  const ago=Math.round((Date.now()-d.ts)/60000);\u001b[39m\n\u001b[31m  const agoStr=ago<1?'just now':ago<60?`${ago}m ago`:`${Math.round(ago/60)}h ago`;\u001b[39m\n\u001b[31m  wrap.innerHTML=`<button class=\\\"resume-btn\\\" onclick=\\\"resumeDraft()\\\">\u001b[39m\n\u001b[31m    <div><div style=\\\"font-size:12px;color:rgba(255,255,255,.5);margin-bottom:3px\\\">Resume draft · ${agoStr}</div><div>${d.F.storeName} · ${d.F.brand||'No brand'}</div></div>\u001b[39m\n\u001b[31m    <div style=\\\"text-align:right\\\"><div style=\\\"font-size:13px;color:var(--or)\\\">${d.fCnt||0} photos · ${d.bCnt||0} brandings →</div></div>\u001b[39m\n\u001b[31m  </button>`;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function resumeDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');if(!d)return;\u001b[39m\n\u001b[31m  F=d.F||{};gpsCoords=d.gpsCoords||null;\u001b[39m\n\u001b[31m  if(d.selectedStore){await pickStore(d.selectedStore);}\u001b[39m\n\u001b[31m  else if(d.manualMode){openManual('');if(F.brand)document.getElementById('f-brand').value=F.brand;if(F.storeName)document.getElementById('f-store').value=F.storeName;if(F.address)document.getElementById('f-addr').value=F.address;if(F.mobile)document.getElementById('f-mobile').value=F.mobile;}\u001b[39m\n\u001b[31m  if(F.date)document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  // Restore client chip state\u001b[39m\n\u001b[31m  if(d._clientOtherMode){_clientOtherMode=true;_selectedClient='';const inp=document.getElementById('f-client-other');if(inp&&F.clientName)inp.value=F.clientName;}\u001b[39m\n\u001b[31m  else if(d._selectedClient){_selectedClient=d._selectedClient;_clientOtherMode=false;}\u001b[39m\n\u001b[31m  else if(F.clientName){autoSetClient(F.clientName);}\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  // Restore photos from draft\u001b[39m\n\u001b[31m  const pd=await dbGet('draft','photos');\u001b[39m\n\u001b[31m  if(pd){\u001b[39m\n\u001b[31m    async function b64ToBlob(b64str){if(!b64str)return null;try{const r=await fetch(b64str);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m    for(const p of(pd.front||[])){const bl=await b64ToBlob(p.b64);if(bl)frontPhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.inside||[])){const bl=await b64ToBlob(p.b64);if(bl)insidePhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.addl||[])){const bl=await b64ToBlob(p.b64);if(bl)addlPhotos.push({blob:bl,prev:URL.createObjectURL(bl),desc:p.desc||''});}\u001b[39m\n\u001b[31m    for(const b of(pd.brand||[])){const bl=await b64ToBlob(b.b64);brandings.push({type:b.type,w:b.w,h:b.h,qty:b.qty,blob:bl,prev:bl?URL.createObjectURL(bl):null});}\u001b[39m\n\u001b[31m    toast('Draft restored with '+frontPhotos.length+' photos ✓','success');\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    toast('Draft restored — photos could not be recovered','info');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PHOTOS\u001b[39m\n\u001b[31mfunction updPhotoBadge(type){const arr=type==='front'?frontPhotos:insidePhotos;const el=document.getElementById(type+'-badge');if(el){el.textContent=arr.length;el.className='cnt-badge '+(arr.length?'':'gray');}}\u001b[39m\n\u001b[31mfunction renderPhotos(type){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  const cont=document.getElementById(type+'-cont');const addBtn=document.getElementById('add-'+type);\u001b[39m\n\u001b[31m  updPhotoBadge(type);\u001b[39m\n\u001b[31m  if(arr.length===0){cont.innerHTML=`<div class=\\\"pslot\\\" onclick=\\\"addPhoto('${type}')\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to capture or upload</span><span class=\\\"hi-txt\\\">फोटो खींचें या अपलोड करें</span></div></div>`;addBtn.style.display='none';return;}\u001b[39m\n\u001b[31m  cont.innerHTML=arr.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const badge=isRetained?`<span class=\\\"pbadge\\\" style=\\\"background:#475569\\\">Existing</span>`:`<span class=\\\"pbadge\\\">${fmtSz(p.blob.size)}</span>`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replacePhoto('${type}',${i})\\\" style=\\\"right:36px;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"margin-bottom:12px\\\"><div class=\\\"pslot filled\\\" style=\\\"margin-bottom:8px\\\"><img src=\\\"${p.prev}\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmPhoto('${type}',${i})\\\">×</button>${badge}</div><input type=\\\"text\\\" placeholder=\\\"Comments (optional)\\\" value=\\\"${p.cmt||''}\\\" onchange=\\\"${type==='front'?'frontPhotos':'insidePhotos'}[${i}].cmt=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  addBtn.style.display=arr.length<(type==='inside'?5:3)?'inline-flex':'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// Photo source: 'camera' stamps geo, 'gallery' does not\u001b[39m\n\u001b[31mlet _photoSourceCb=null,_photoSourceQuality=null;·\u001b[39m\n\u001b[31mfunction capPhoto(cb,forceSource,quality){\u001b[39m\n\u001b[31m  // quality override: null=use setting, 'hd', 'compressed'\u001b[39m\n\u001b[31m  _photoSourceCb=cb;_photoSourceQuality=quality||null;\u001b[39m\n\u001b[31m  if(forceSource==='camera'){_doCapture(cb,'camera',quality);return;}\u001b[39m\n\u001b[31m  if(forceSource==='gallery'){_doCapture(cb,'gallery',quality);return;}\u001b[39m\n\u001b[31m  // Show picker\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _doCapture(cb,src,quality){\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  const i=document.createElement('input');\u001b[39m\n\u001b[31m  i.type='file';i.accept='image/*';\u001b[39m\n\u001b[31m  if(src==='camera')i.setAttribute('capture','environment');\u001b[39m\n\u001b[31m  i.style.display='none';\u001b[39m\n\u001b[31m  i.onchange=async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f)return;\u001b[39m\n\u001b[31m    const q=quality||_photoSourceQuality||null;\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      const blob=await compress(f,q==='hd'?1920:q==='compressed'?1280:null,q==='hd'?0.90:q==='compressed'?0.78:null);\u001b[39m\n\u001b[31m      // Only stamp if from camera (live photo)\u001b[39m\n\u001b[31m      const stamped=(src==='camera')?await stampPhoto(blob):blob;\u001b[39m\n\u001b[31m      // Save to device (auto-download trigger)\u001b[39m\n\u001b[31m      savePhotoToDevice(stamped);\u001b[39m\n\u001b[31m      cb({target:{files:[f]},_blob:stamped,_src:src});\u001b[39m\n\u001b[31m    }catch(err){toast('Photo processing failed — try again','error');console.error('_doCapture error:',err);}\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  document.body.appendChild(i);i.click();setTimeout(()=>i.remove(),8000);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction photoSrcCamera(){_doCapture(_photoSourceCb,'camera',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcGallery(){_doCapture(_photoSourceCb,'gallery',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcCancel(){document.getElementById('photo-src-dialog').classList.remove('open');_photoSourceCb=null;}·\u001b[39m\n\u001b[31m// Save photo to device gallery/downloads\u001b[39m\n\u001b[31mfunction savePhotoToDevice(blob){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    const a=document.createElement('a');\u001b[39m\n\u001b[31m    a.href=url;\u001b[39m\n\u001b[31m    a.download='Recce_'+Date.now()+'.jpg';\u001b[39m\n\u001b[31m    a.style.display='none';\u001b[39m\n\u001b[31m    document.body.appendChild(a);a.click();\u001b[39m\n\u001b[31m    setTimeout(()=>{URL.revokeObjectURL(url);a.remove();},1000);\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addPhoto(type){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}${e._src==='camera'&&geoStampEnabled?' · Stamped':''}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31masync function handleCapture(e,type){\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmPhoto(type,i){(type==='front'?frontPhotos:insidePhotos).splice(i,1);renderPhotos(type);saveDraft();}\u001b[39m\n\u001b[31mfunction replacePhoto(type,idx){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m    arr[idx]={...arr[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAddl(){\u001b[39m\n\u001b[31m  const cont=document.getElementById('add-cont');const btn=document.getElementById('add-addl');\u001b[39m\n\u001b[31m  const badge=document.getElementById('addl-badge');if(badge){badge.textContent=`${addlPhotos.length} / 8`;badge.className='cnt-badge '+(addlPhotos.length?'':'gray');}\u001b[39m\n\u001b[31m  cont.innerHTML=addlPhotos.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const sizeInfo=isRetained?'<span style=\\\"color:#475569\\\">Existing</span>':`${fmtSz(p.blob.size)}`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replaceAddl(${i})\\\" style=\\\"top:3px;left:3px;right:auto;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;gap:10px;align-items:start;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--g100)\\\"><div style=\\\"position:relative;flex-shrink:0\\\"><img src=\\\"${p.prev}\\\" style=\\\"width:80px;height:80px;object-fit:cover;border-radius:var(--rs)\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmAddl(${i})\\\" style=\\\"top:3px;right:3px\\\">×</button></div><div style=\\\"flex:1\\\"><input type=\\\"text\\\" placeholder=\\\"Description (optional)\\\" value=\\\"${p.desc||''}\\\" onchange=\\\"addlPhotos[${i}].desc=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"><div style=\\\"font-size:11px;color:var(--g400);margin-top:4px\\\">${sizeInfo}</div></div></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  btn.style.display=addlPhotos.length>=8?'none':'inline-flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction addAdditional(){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  addlPhotos.push({blob:bs,prev:URL.createObjectURL(bs),desc:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderAddl();saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31mfunction rmAddl(i){addlPhotos.splice(i,1);renderAddl();saveDraft();}\u001b[39m\n\u001b[31mfunction replaceAddl(idx){\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m    addlPhotos[idx]={...addlPhotos[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderAddl();saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// BRANDING\u001b[39m\n\u001b[31mfunction calcSqft(w,h){const wf=parseFloat(w),hf=parseFloat(h);if(!wf||!hf)return '';return `${(wf*hf).toFixed(0)} sq.in = ${(wf*hf/144).toFixed(2)} sq.ft`;}\u001b[39m\n\u001b[31mfunction renderBrandings(){\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  const cont=document.getElementById('br-items');\u001b[39m\n\u001b[31m  const hb=document.getElementById('br-hdr-badge');if(hb)hb.textContent=`${brandings.length} ${t(brandings.length!==1?'items':'item',brandings.length!==1?'आइटम':'आइटम')}`;\u001b[39m\n\u001b[31m  cont.innerHTML=brandings.map((b,i)=>`<div class=\\\"bitem\\\"><div class=\\\"bitem-hdr\\\"><div class=\\\"bitem-title\\\">${t('Branding','ब्रांडिंग')} ${i+1}${b.type?' — '+b.type:''}</div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:6px\\\">${i>0?`<button class=\\\"btn-d\\\" onclick=\\\"dupBr(${i})\\\" style=\\\"color:var(--or);border-color:var(--orl)\\\">${t('Dup ↑','डुप ↑')}</button>`:''}<button class=\\\"btn-d\\\" onclick=\\\"rmBr(${i})\\\">${t('Remove','हटाएं')}</button></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\"><label>${t('Type','प्रकार')} <span class=\\\"req\\\">*</span></label><div class=\\\"chip-grid\\\">${BTYPE.map(tp=>`<div class=\\\"chip${b.type===tp?' sel':''}\\\" onclick=\\\"setBType(${i},'${tp.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\"> ${tp}</div>`).join('')}</div></div>\u001b[39m\n\u001b[31m    <div class=\\\"dim-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Width (in)','चौड़ाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.w||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].w=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Height (in)','ऊंचाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.h||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].h=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"max-width:74px\\\"><label>${t('Qty','मात्रा')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.qty||''}\\\" placeholder=\\\"1\\\" inputmode=\\\"numeric\\\" onchange=\\\"brandings[${i}].qty=this.value;saveDraft()\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <span class=\\\"sqft\\\" id=\\\"sf${i}\\\">${calcSqft(b.w,b.h)||t('Enter W × H','W × H दर्ज करें')}</span>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-top:12px\\\"><label>${t('Photo','फोटो')} <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      ${b.prev?`<div class=\\\"pslot filled\\\" onclick=\\\"capBr(${i})\\\"><img src=\\\"${b.prev}\\\"><button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();rmBrPh(${i})\\\">×</button><span class=\\\"pbadge\\\">${b.blob?fmtSz(b.blob.size):'Existing'}</span></div>`:`<div><div class=\\\"pslot\\\" onclick=\\\"capBr(${i})\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\">${t('Tap to capture','दबाकर कैप्चर करें')}</div></div><div style=\\\"display:flex;gap:6px;margin-top:6px\\\"><button class=\\\"atool${(b.quality||imgQuality)==='compressed'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'compressed');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">${t('Compressed','कम्प्रेस्ड')}</button><button class=\\\"atool${(b.quality||imgQuality)==='hd'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'hd');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">HD</button></div></div>`}\u001b[39m\n\u001b[31m    </div></div>`).join('');\u001b[39m\n\u001b[31m  // Only show \\\"Add Another\\\" when last item is fully complete\u001b[39m\n\u001b[31m  const addDiv=document.getElementById('br-add');\u001b[39m\n\u001b[31m  if(addDiv&&brandings.length>0){\u001b[39m\n\u001b[31m    const last=brandings[brandings.length-1];\u001b[39m\n\u001b[31m    const lastComplete=last.type&&last.w&&last.h&&last.qty&&last.prev;\u001b[39m\n\u001b[31m    addDiv.style.display=(lastComplete&&brandings.length<15)?'block':'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updSqft(i){const el=document.getElementById('sf'+i);if(el)el.textContent=calcSqft(brandings[i].w,brandings[i].h)||t('Enter W × H','W × H दर्ज करें');saveDraft();}\u001b[39m\n\u001b[31mfunction setBType(i,tp){brandings[i].type=tp;renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction addBranding(){if(brandings.length>=15){toast(t('Max 15 items','अधिकतम 15 आइटम'),'error');return;}brandings.push({type:'',w:'',h:'',qty:'1',blob:null,prev:null});renderBrandings();}\u001b[39m\n\u001b[31mfunction dupBr(i){if(brandings.length>=10){toast(t('Max 10 items','अधिकतम 10 आइटम'),'error');return;}const s=brandings[i-1];brandings.splice(i,0,{type:s.type,w:s.w,h:s.h,qty:s.qty,blob:null,prev:null});renderBrandings();toast(t('Duplicated — add photo','डुप्लीकेट — फोटो जोड़ें'),'info');}\u001b[39m\n\u001b[31mfunction rmBr(i){brandings.splice(i,1);renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction capBr(i){\u001b[39m\n\u001b[31m  const q=brandings[i]?.quality||imgQuality;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f,q==='hd'?1920:1280,q==='hd'?0.90:0.78));\u001b[39m\n\u001b[31m    brandings[i].blob=bs;brandings[i].prev=URL.createObjectURL(bs);\u001b[39m\n\u001b[31m    brandings[i].fromCamera=(e._src==='camera');\u001b[39m\n\u001b[31m    openAnnot(i);\u001b[39m\n\u001b[31m  },null,q);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmBrPh(i){brandings[i].blob=null;brandings[i].prev=null;renderBrandings();}\u001b[39m\n\u001b[31mfunction setBrQuality(i,q){brandings[i].quality=q;renderBrandings();}·\u001b[39m\n\u001b[31m// VIDEO / DOC\u001b[39m\n\u001b[31mfunction setVideo(v){F.hasVideo=v;document.getElementById('vid-yes').classList.toggle('sel',v);document.getElementById('vid-no').classList.toggle('sel',!v);document.getElementById('vid-sec').style.display=v?'block':'none';saveDraft();}\u001b[39m\n\u001b[31masync function handleVideo(e){videoBlob=e.target.files[0];if(!videoBlob)return;document.getElementById('vid-slot').innerHTML=`<div style=\\\"padding:14px;font-size:13px;color:var(--gn)\\\">✓ ${videoBlob.name} (${fmtSz(videoBlob.size)})</div>`;}\u001b[39m\n\u001b[31mfunction setBranding(v){F.hasBranding=v;document.getElementById('br-yes').classList.toggle('sel',v);document.getElementById('br-no').classList.toggle('sel',!v);document.getElementById('br-add').style.display=v?'block':'none';if(v&&brandings.length===0)addBranding();saveDraft();}\u001b[39m\n\u001b[31masync function handleDoc(e){const f=e.target.files[0];if(!f)return;submissionDoc=f.type.startsWith('image/')?await compress(f,1600,.85):f;const slot=document.getElementById('doc-slot');if(f.type.startsWith('image/')){slot.classList.add('filled');slot.innerHTML=`<img src=\\\"${URL.createObjectURL(submissionDoc)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}else{slot.innerHTML=`<div style=\\\"padding:16px;font-size:13px;color:var(--gn)\\\">✓ ${f.name} (${fmtSz(f.size)})</div>`;}buildReview();}·\u001b[39m\n\u001b[31m// CLIENT CHIPS\u001b[39m\n\u001b[31mfunction renderClientChips(){\u001b[39m\n\u001b[31m  const grid = document.getElementById('client-chips'); if (!grid) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  clientList.forEach(c => {\u001b[39m\n\u001b[31m    const sel = !_clientOtherMode && _selectedClient === c;\u001b[39m\n\u001b[31m    html += `<div class=\\\"cl-chip${sel?' sel':''}\\\" onclick=\\\"selectClientChip('${esc(c)}')\\\">${esc(c)}</div>`;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html += `<div class=\\\"cl-chip cl-chip-other${_clientOtherMode?' sel':''}\\\" onclick=\\\"selectClientOther()\\\"><span class=\\\"en-txt\\\">Other…</span><span class=\\\"hi-txt\\\">अन्य…</span></div>`;\u001b[39m\n\u001b[31m  grid.innerHTML = html;\u001b[39m\n\u001b[31m  document.getElementById('client-other-wrap').style.display = _clientOtherMode ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientChip(name){\u001b[39m\n\u001b[31m  _selectedClient = name; _clientOtherMode = false;\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').value = '';\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientOther(){\u001b[39m\n\u001b[31m  _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onClientOtherInput(){\u001b[39m\n\u001b[31m  _selectedClient = document.getElementById('f-client-other').value.trim();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction getClientName(){\u001b[39m\n\u001b[31m  if (_clientOtherMode) return (document.getElementById('f-client-other')?.value||'').trim();\u001b[39m\n\u001b[31m  return _selectedClient;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction autoSetClient(brandName){\u001b[39m\n\u001b[31m  if (!brandName) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  if (clientList.includes(brandName)){\u001b[39m\n\u001b[31m    _selectedClient = brandName; _clientOtherMode = false;\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    // Not in list — pre-fill the Other field\u001b[39m\n\u001b[31m    _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m    const inp = document.getElementById('f-client-other');\u001b[39m\n\u001b[31m    if (inp && !inp.value) inp.value = brandName;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// STEP VALIDATION\u001b[39m\n\u001b[31mfunction getSD(){if(selectedStore&&!manualMode)return{storeName:selectedStore.name,brand:selectedStore.brand||'',address:selectedStore.address||'',mobile:selectedStore.mobile||''};return{storeName:(document.getElementById('f-store')?.value||'').trim(),brand:document.getElementById('f-brand')?.value||'',address:(document.getElementById('f-addr')?.value||'').trim(),mobile:(document.getElementById('f-mobile')?.value||'').trim()};}\u001b[39m\n\u001b[31mfunction step2(){\u001b[39m\n\u001b[31m  const d=document.getElementById('f-date').value;\u001b[39m\n\u001b[31m  if(!d){toast('Select date','error');return;}\u001b[39m\n\u001b[31m  const sd=getSD();\u001b[39m\n\u001b[31m  if(!sd.storeName){toast('Select or enter store name','error');return;}\u001b[39m\n\u001b[31m  if(!sd.brand){toast('Select a brand','error');document.getElementById('brand-selector').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  if(!sd.address){toast('Enter store address','error');return;}\u001b[39m\n\u001b[31m  const clientName=getClientName();\u001b[39m\n\u001b[31m  if(!clientName){toast(t('Select a client','क्लाइंट चुनें'),'error');document.getElementById('client-chips').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  // Check missing fields filled\u001b[39m\n\u001b[31m  const missAddr=document.getElementById('sc-miss-address');\u001b[39m\n\u001b[31m  if(missAddr&&!missAddr.value.trim()){toast('Enter store address in the highlighted field','error');missAddr.focus();return;}\u001b[39m\n\u001b[31m  const missMob=document.getElementById('sc-miss-mobile');\u001b[39m\n\u001b[31m  // mobile not required — just copy if filled\u001b[39m\n\u001b[31m  if(missMob&&missMob.value.trim()&&!F.mobile)F.mobile=missMob.value.trim();\u001b[39m\n\u001b[31m  Object.assign(F,{date:d,...sd,clientName});saveDraft();\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');showView('form-photos');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction step3(){if(!frontPhotos.length){toast('Add at least 1 front view photo','error');return;}showView('form-video');}\u001b[39m\n\u001b[31mfunction step4(){if(F.hasVideo===undefined||F.hasVideo===null){toast('Select Yes or No for video','error');return;}renderBrandings();showView('form-branding');}\u001b[39m\n\u001b[31mfunction step5(){if(F.hasBranding===undefined||F.hasBranding===null){toast('Select Yes or No for branding space','error');return;}if(F.hasBranding){for(let i=0;i<brandings.length;i++){const b=brandings[i];if(!b.type){toast(`Select branding type for item ${i+1}`,'error');return;}if(!b.w||!b.h){toast(`Enter W and H dimensions for item ${i+1}`,'error');return;}if(!b.qty){toast(`Enter qty for item ${i+1}`,'error');return;}if(!b.blob&&!b.prev){toast(`Add photo for item ${i+1}`,'error');return;}}}renderAddl();buildReview();showView('form-additional');}·\u001b[39m\n\u001b[31m// REVIEW\u001b[39m\n\u001b[31mfunction buildReview(){const el=document.getElementById('rev-body');if(!el)return;const sd=getSD();const cn=getClientName();el.innerHTML=`<div><div class=\\\"rev-lbl\\\">Store</div><div class=\\\"rev-val\\\">${sd.storeName||'—'} · ${sd.brand||'—'}</div><div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">${sd.address||'—'}${sd.mobile?' · '+sd.mobile:''}</div>${gpsCoords?`<div style=\\\"font-size:11px;color:var(--gn);margin-top:3px\\\">📍 ${gpsCoords.lat}, ${gpsCoords.lng} ±${gpsCoords.acc}m</div>`:''}</div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Client</div><div class=\\\"rev-val\\\" style=\\\"color:${cn?'var(--nv)':'var(--rd)'}\\\">${cn||'⚠ Not selected — required'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Photos — Front · Inside · Additional</div><div class=\\\"rev-val\\\">${frontPhotos.length} · ${insidePhotos.length} · ${addlPhotos.length}</div><div class=\\\"rev-photos\\\">${[...frontPhotos,...insidePhotos].slice(0,6).map(p=>`<img class=\\\"rev-thumb\\\" src=\\\"${p.prev}\\\">`).join('')}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Video · Branding items</div><div class=\\\"rev-val\\\">${F.hasVideo?'Yes':'No'} · ${brandings.length} item(s)</div></div>${F.hasBranding&&brandings.length?`<div style=\\\"margin-top:8px\\\">${brandings.map((b,i)=>`<div style=\\\"font-size:12px;color:var(--g600);padding:4px 0;border-bottom:1px solid var(--g100)\\\">${i+1}. ${b.type||'No type'} — ${b.w||'?'}×${b.h||'?'}\\\" × ${b.qty||'?'} — ${calcSqft(b.w,b.h)||'?'}</div>`).join('')}</div>`:''}<div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Additional photos <span style=\\\"font-size:11px;color:var(--g400)\\\">(optional)</span></div><div class=\\\"rev-val\\\" style=\\\"color:${addlPhotos.length?'var(--gn)':'var(--g500)'}\\\">${addlPhotos.length?`✓ ${addlPhotos.length} photo(s) added`:'None added'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Mandatory document</div><div class=\\\"rev-val\\\" style=\\\"color:${(submissionDoc||_docExistingUrl)?'var(--gn)':'var(--rd)'}\\\">${(submissionDoc||_docExistingUrl)?'✓ Uploaded':'⚠ Missing — required'}</div></div>`;}·\u001b[39m\n\u001b[31m// SUBMIT\u001b[39m\n\u001b[31masync function submitRecce(){\u001b[39m\n\u001b[31m  if(!submissionDoc&&!_docExistingUrl){toast('Upload mandatory doc first','error');return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('sub-btn');btn.disabled=true;btn.textContent='Saving…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const isEdit=!!(F.editingId);\u001b[39m\n\u001b[31m    const id=isEdit?F.editingId:('RC_'+Date.now()+'_'+Math.random().toString(36).slice(2,6).toUpperCase());\u001b[39m\n\u001b[31m    const sd=getSD();\u001b[39m\n\u001b[31m    const _hub=_recceHubUser();\u001b[39m\n\u001b[31m    const entry={id,timestamp:isEdit?(await dbGet('subs',id))?.timestamp||new Date().toISOString():new Date().toISOString(),editedAt:isEdit?new Date().toISOString():undefined,status:'pending',submittedBy:_hub.empId||null,submittedByName:_hub.name||null,data:{...F,...sd,gpsCoords,frontPhotos:await Promise.all(frontPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),insidePhotos:await Promise.all(insidePhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),videoNote:F.hasVideo&&videoBlob?`Video local (${fmtSz(videoBlob.size)}) — share via WhatsApp`:null,videoCmt:document.getElementById('f-vid-cmt')?.value||'',brandings:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:calcSqft(b.w,b.h),photoB64:b.blob?await b64(b.blob):null,existingUrl:b.existingUrl||null}))),addlPhotos:await Promise.all(addlPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,desc:p.desc,existingUrl:p.existingUrl||null}))),docB64:submissionDoc?await b64(submissionDoc):null,_docExistingUrl:_docExistingUrl||null}};\u001b[39m\n\u001b[31m    entry.campaignId       = _selectedCampaignId || null;\u001b[39m\n\u001b[31m    entry.notifySupervisor = _notifySupervisor   || false;\u001b[39m\n\u001b[31m    await dbPut('subs',entry);\u001b[39m\n\u001b[31m    await dbDel('draft','current');\u001b[39m\n\u001b[31m    toast(isEdit?'Recce updated ✓':'Recce saved ✓','success');\u001b[39m\n\u001b[31m    if(navigator.onLine)syncNow();\u001b[39m\n\u001b[31m    showView('home');loadHome();checkDraft();\u001b[39m\n\u001b[31m  }catch(err){toast('Error: '+err.message,'error');}\u001b[39m\n\u001b[31m  finally{btn.disabled=false;btn.textContent='Submit Recce ✓';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// SYNC\u001b[39m\n\u001b[31masync function syncNow() {\u001b[39m\n\u001b[31m  if (!navigator.onLine) { toast('Offline — sync when back online', 'info'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('sync-btn');\u001b[39m\n\u001b[31m  const SYNC_ICON = '<svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg>Sync';\u001b[39m\n\u001b[31m  if (btn) { btn.innerHTML = '<span class=\\\"spin\\\">↻</span> Syncing'; btn.disabled = true; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const all      = await dbAll('subs');\u001b[39m\n\u001b[31m    const pend     = all.filter(s => s.status === 'pending' || s.status === 'failed');\u001b[39m\n\u001b[31m    const backfill = all.filter(s => s.status === 'synced' && !s.gasAt);\u001b[39m\n\u001b[31m    if (!pend.length && !backfill.length) { toast('All synced ✓', 'success'); return; }·\u001b[39m\n\u001b[31m    const gasUrl = (await cfg('gas-url')) || DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    function fireGas(s) {\u001b[39m\n\u001b[31m      if (!gasUrl) return;\u001b[39m\n\u001b[31m      fetch(gasUrl, { method:'POST', mode:'no-cors',\u001b[39m\n\u001b[31m        body: JSON.stringify({ action:'syncSheet', submission: s }) })\u001b[39m\n\u001b[31m        .catch(() => {});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    let ok = 0;\u001b[39m\n\u001b[31m    for (const s of pend) {\u001b[39m\n\u001b[31m      // Fire Sheet sync (no-cors fire-and-forget — writes row to Google Sheet)\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      // Primary: upload photos → auto-trigger slides → generate report → store in PostgreSQL\u001b[39m\n\u001b[31m      const { ok: pgOk, viewUrl } = await syncToPostgres(s);\u001b[39m\n\u001b[31m      if (pgOk) {\u001b[39m\n\u001b[31m        s.status = 'synced'; s.syncedAt = new Date().toISOString();\u001b[39m\n\u001b[31m        if (viewUrl) s.viewUrl = viewUrl;\u001b[39m\n\u001b[31m        await dbPut('subs', s); ok++;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        s.status = 'failed'; await dbPut('subs', s);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Backfill: entries synced to Postgres but never reached Sheet GAS\u001b[39m\n\u001b[31m    for (const s of backfill) {\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      await dbPut('subs', s);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if (backfill.length) toast(`Sent ${backfill.length} older entries to Sheet`, 'info');·\u001b[39m\n\u001b[31m    await cfg('last-sync', new Date().toISOString());\u001b[39m\n\u001b[31m    if (pend.length) toast(`Synced ${ok}/${pend.length}`, ok === pend.length ? 'success' : 'error');\u001b[39m\n\u001b[31m    loadHome();\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.innerHTML = SYNC_ICON; btn.disabled = false; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN HOME ──────────────────────────────────────────────\u001b[39m\n\u001b[31masync function loadHomeAdmin() {\u001b[39m\n\u001b[31m  // Adapt UI for admin view\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const _sh = document.querySelector('.sh'); if (_sh) _sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = 'All Submissions';\u001b[39m\n\u001b[31m  const slbls = document.querySelectorAll('.slbl');\u001b[39m\n\u001b[31m  if (slbls[0]) slbls[0].textContent = 'Showing';\u001b[39m\n\u001b[31m  if (slbls[1]) slbls[1].textContent = 'Agents';·\u001b[39m\n\u001b[31m  // Back-to-menu button for supervisors\u001b[39m\n\u001b[31m  if (_isSupervisor() && !document.getElementById('sup-back-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => { document.getElementById('sup-back-btn').remove(); renderSupLanding(); };\u001b[39m\n\u001b[31m    const content = document.querySelector('#view-home .content');\u001b[39m\n\u001b[31m    content.prepend(bb);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Show filter bar — restore if hidden by renderSupLanding, else inject fresh\u001b[39m\n\u001b[31m  const _existingFb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (_existingFb) { _existingFb.style.display = ''; }\u001b[39m\n\u001b[31m  if (!_existingFb) {\u001b[39m\n\u001b[31m    const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m    const fb = document.createElement('div');\u001b[39m\n\u001b[31m    fb.id = 'admin-filter-bar';\u001b[39m\n\u001b[31m    fb.className = 'af-bar';\u001b[39m\n\u001b[31m    fb.innerHTML =\u001b[39m\n\u001b[31m      `<div class=\\\"af-grid\\\">\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-agent\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Agents</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-brand\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Brands</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-client\\\" onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Clients</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-period\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">All Time</option>\u001b[39m\n\u001b[31m          <option value=\\\"7\\\">Last 7 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"30\\\">Last 30 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"90\\\">Last 3 months</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-group\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"date\\\">Sort: Recent</option>\u001b[39m\n\u001b[31m          <option value=\\\"agent\\\">Group: Agent</option>\u001b[39m\n\u001b[31m          <option value=\\\"brand\\\">Group: Brand</option>\u001b[39m\n\u001b[31m          <option value=\\\"client\\\">Group: Client</option>\u001b[39m\n\u001b[31m          <option value=\\\"city\\\">Group: City</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m        <input class=\\\"af-inp\\\" id=\\\"af-search\\\" type=\\\"text\\\" placeholder=\\\"🔍 Search store or city…\\\" oninput=\\\"renderAdminList()\\\" style=\\\"flex:1;min-width:120px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"del-toggle-btn\\\" id=\\\"del-toggle-btn\\\" onclick=\\\"toggleDeletedView()\\\" style=\\\"flex-shrink:0\\\">📋 View Deleted</button>\u001b[39m\n\u001b[31m        ${_isSupervisor() ? `<button class=\\\"del-toggle-btn\\\" id=\\\"pending-job-btn\\\" onclick=\\\"togglePendingJobView()\\\" style=\\\"flex-shrink:0;background:#fef3c7;color:#92400e;border-color:#f59e0b\\\">⚑ Unlinked <span id=\\\"pending-job-count\\\" style=\\\"font-weight:900\\\"></span></button>` : ''}\u001b[39m\n\u001b[31m        ${_adminUnlocked ? `<button class=\\\"del-toggle-btn\\\" id=\\\"regen-rpt-btn\\\" onclick=\\\"regenAllReports()\\\" style=\\\"flex-shrink:0\\\">&#x21BB; Regen Reports</button>` : ''}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    sh.parentNode.insertBefore(fb, sh);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Fetch\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  list.innerHTML = '<div style=\\\"text-align:center;padding:40px\\\"><div class=\\\"spinner\\\"></div></div>';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?order=submitted_at.desc&limit=500`, { headers: _RC_READ });\u001b[39m\n\u001b[31m    _adminRows = resp.ok ? await resp.json() : [];\u001b[39m\n\u001b[31m    document.getElementById('stat-total').textContent = _adminRows.length;\u001b[39m\n\u001b[31m    if (resp.ok) {\u001b[39m\n\u001b[31m      const now = new Date();\u001b[39m\n\u001b[31m      document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m        'Loaded ' + now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Populate agent dropdown\u001b[39m\n\u001b[31m    const agents = [...new Set(_adminRows.map(r => r.submitted_by).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-agent').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Agents (${agents.length})</option>` +\u001b[39m\n\u001b[31m      agents.map(a => `<option value=\\\"${a}\\\">${a}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate brand dropdown\u001b[39m\n\u001b[31m    const brands = [...new Set(_adminRows.map(r => r.brand).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-brand').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Brands (${brands.length})</option>` +\u001b[39m\n\u001b[31m      brands.map(b => `<option value=\\\"${b}\\\">${b}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate client dropdown\u001b[39m\n\u001b[31m    const clients = [...new Set(_adminRows.map(r => r.client_name).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-client').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Clients (${clients.length})</option>` +\u001b[39m\n\u001b[31m      clients.map(c => `<option value=\\\"${c}\\\">${c}</option>`).join('');·\u001b[39m\n\u001b[31m    // Update pending-job count badge\u001b[39m\n\u001b[31m    const unlinkedCount = _adminRows.filter(r => !r.deleted_at && !r.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinkedCount ? `(${unlinkedCount})` : '';·\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">⚠️</div><div class=\\\"empty-txt\\\">Could not load — check connection</div></div>';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction togglePendingJobView() {\u001b[39m\n\u001b[31m  _pendingJobFilter = !_pendingJobFilter;\u001b[39m\n\u001b[31m  _showDeletedView  = false;\u001b[39m\n\u001b[31m  const btn = document.getElementById('pending-job-btn');\u001b[39m\n\u001b[31m  if (btn) btn.style.background = _pendingJobFilter ? '#f59e0b' : '#fef3c7';\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function openLinkJobModal(subId, storeName) {\u001b[39m\n\u001b[31m  _linkJobSubId = subId;\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  const storeEl = document.getElementById('link-job-store');\u001b[39m\n\u001b[31m  const sel = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  if (!modal) return;\u001b[39m\n\u001b[31m  if (storeEl) storeEl.textContent = storeName || subId;\u001b[39m\n\u001b[31m  if (errEl) errEl.textContent = '';\u001b[39m\n\u001b[31m  // Load campaigns into dropdown\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (!_campaignList.length) {\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m      _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  if (sel) {\u001b[39m\n\u001b[31m    sel.innerHTML = '<option value=\\\"\\\">— Select campaign —</option>' +\u001b[39m\n\u001b[31m      _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  modal.style.display = 'flex';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeLinkJobModal() {\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  if (modal) modal.style.display = 'none';\u001b[39m\n\u001b[31m  _linkJobSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function saveLinkJob() {\u001b[39m\n\u001b[31m  const sel    = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl  = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  const campId = sel?.value || '';\u001b[39m\n\u001b[31m  if (!campId) { if (errEl) errEl.textContent = 'Select a campaign'; return; }\u001b[39m\n\u001b[31m  if (!_linkJobSubId) return;\u001b[39m\n\u001b[31m  const btn = document.querySelector('#modal-link-job button[onclick=\\\"saveLinkJob()\\\"]');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Linking…'; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(_linkJobSubId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ campaign_id: campId }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Patch failed');\u001b[39m\n\u001b[31m    // Update local cache\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === _linkJobSubId);\u001b[39m\n\u001b[31m    if (idx >= 0) _adminRows[idx].campaign_id = campId;\u001b[39m\n\u001b[31m    // Update pending count badge\u001b[39m\n\u001b[31m    const unlinked = _adminRows.filter(x => !x.deleted_at && !x.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinked ? `(${unlinked})` : '';\u001b[39m\n\u001b[31m    closeLinkJobModal();\u001b[39m\n\u001b[31m    toast('Job linked ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    if (errEl) errEl.textContent = 'Failed to link — try again';\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.disabled = false; btn.textContent = '🔗 Link Job'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAdminList() {\u001b[39m\n\u001b[31m  const agent  = document.getElementById('af-agent')?.value  || '';\u001b[39m\n\u001b[31m  const brand  = document.getElementById('af-brand')?.value  || '';\u001b[39m\n\u001b[31m  const period = document.getElementById('af-period')?.value || '';\u001b[39m\n\u001b[31m  const search = (document.getElementById('af-search')?.value || '').toLowerCase().trim();\u001b[39m\n\u001b[31m  const group  = document.getElementById('af-group')?.value  || 'date';·\u001b[39m\n\u001b[31m  // Pending-job filter overrides deleted/normal modes\u001b[39m\n\u001b[31m  let rows;\u001b[39m\n\u001b[31m  if (_pendingJobFilter) {\u001b[39m\n\u001b[31m    rows = _adminRows.filter(r => !r.deleted_at && !r.campaign_id);\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows = _showDeletedView\u001b[39m\n\u001b[31m      ? _adminRows.filter(r => r.deleted_at)\u001b[39m\n\u001b[31m      : _adminRows.filter(r => !r.deleted_at);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const client = document.getElementById('af-client')?.value || '';\u001b[39m\n\u001b[31m  if (agent)  rows = rows.filter(r => r.submitted_by === agent);\u001b[39m\n\u001b[31m  if (brand)  rows = rows.filter(r => r.brand === brand);\u001b[39m\n\u001b[31m  if (client) rows = rows.filter(r => r.client_name === client);\u001b[39m\n\u001b[31m  if (search) rows = rows.filter(r => (r.store_name||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.city||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.client_name||'').toLowerCase().includes(search));\u001b[39m\n\u001b[31m  if (period && !_showDeletedView) {\u001b[39m\n\u001b[31m    const cut = new Date(); cut.setDate(cut.getDate() - parseInt(period));\u001b[39m\n\u001b[31m    rows = rows.filter(r => new Date(r.submitted_at) >= cut);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const uniqueAgents = new Set(rows.map(r => r.submitted_by).filter(Boolean)).size;\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = rows.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = uniqueAgents;\u001b[39m\n\u001b[31m  const deletedCount = _adminRows.filter(r => r.deleted_at).length;\u001b[39m\n\u001b[31m  const delBtn = document.getElementById('del-toggle-btn');\u001b[39m\n\u001b[31m  if (delBtn) {\u001b[39m\n\u001b[31m    if (_showDeletedView) {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 Hide Deleted (${deletedCount})` : '📋 Hide Deleted';\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 View Deleted (${deletedCount})` : '📋 View Deleted';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    delBtn.classList.toggle('active', _showDeletedView);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!rows.length) {\u001b[39m\n\u001b[31m    list.innerHTML = _showDeletedView\u001b[39m\n\u001b[31m      ? '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">✅</div><div class=\\\"empty-txt\\\">No deleted recces</div></div>'\u001b[39m\n\u001b[31m      : '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">🔍</div><div class=\\\"empty-txt\\\">No matching submissions</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (group === 'agent') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.submitted_by||'').localeCompare(b.submitted_by||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.submitted_by || 'Unknown';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">👤 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'brand') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.brand||'').localeCompare(b.brand||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.brand || 'No Brand';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🏷 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'client') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.client_name||'').localeCompare(b.client_name||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.client_name || 'No Client';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🤝 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'city') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.city||'').localeCompare(b.city||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.city || 'No City';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">📍 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows.sort((a,b) => new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    rows.forEach(r => { html += adminCard(r); });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminCard(r) {\u001b[39m\n\u001b[31m  const dt    = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds    = dt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m  const tm    = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const photos = (r.front_photos||0) + (r.inside_photos||0) + (r.addl_photos||0);\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const canDelete  = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const canArchive = _RECCE_CFG_ADMINS.includes(hub?.empId) && !r.client_archived;·\u001b[39m\n\u001b[31m  // Client status badge\u001b[39m\n\u001b[31m  const clientStatusMap = {\u001b[39m\n\u001b[31m    approved:              {t:'✓ Approved',    s:'color:#166534;background:#dcfce7;border:1px solid #86efac'},\u001b[39m\n\u001b[31m    rejected:              {t:'✕ Rejected',    s:'color:#991b1b;background:#fee2e2;border:1px solid #fca5a5'},\u001b[39m\n\u001b[31m    approved_with_changes: {t:'✎ Approved w/ Comments', s:'color:#92400e;background:#fef3c7;border:1px solid #fcd34d'},\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const csCfg = clientStatusMap[r.client_status];\u001b[39m\n\u001b[31m  const clientStatusBadge = csCfg\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;${csCfg.s}\\\">${csCfg.t}</span>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const archiveBadge = r.client_archived\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;color:#475569;background:#f1f5f9;border:1px solid #cbd5e1\\\">⬚ Client hidden</span>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  if (r.deleted_at) {\u001b[39m\n\u001b[31m    const delDt = new Date(r.deleted_at);\u001b[39m\n\u001b[31m    const delDs = delDt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m    const reasonLabel = r.deletion_reason === 'wrong' ? 'Wrong' : r.deletion_reason === 'duplicate' ? 'Duplicate' : 'Test';\u001b[39m\n\u001b[31m    return `<div class=\\\"asc deleted-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m        <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m            <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds}</span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m          <span class=\\\"del-reason-tag\\\">❌ ${reasonLabel}</span>\u001b[39m\n\u001b[31m          <div class=\\\"del-by-txt\\\">by ${r.deleted_by||'?'} · ${delDs}</div>\u001b[39m\n\u001b[31m          ${canDelete ? `<button class=\\\"restore-btn\\\" onclick=\\\"event.stopPropagation();restoreRecce('${r.sub_id}')\\\">↩ Restore</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Submitted by ${r.submitted_by||'?'}</div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const chips = [\u001b[39m\n\u001b[31m    photos > 0   ? `📷 ${photos} photo${photos!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.has_video  ? '🎥 Video' : null,\u001b[39m\n\u001b[31m    r.has_branding ? `🪧 ${r.branding_count} branding${r.branding_count!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.city       ? `📍 ${r.city}` : (r.address ? `📍 ${r.address}` : null),\u001b[39m\n\u001b[31m    r.view_url   ? '👁 View available' : null,\u001b[39m\n\u001b[31m  ].filter(Boolean);·\u001b[39m\n\u001b[31m  const delBtnHtml = canDelete\u001b[39m\n\u001b[31m    ? `<button class=\\\"del-btn\\\" onclick=\\\"event.stopPropagation();openDeleteModal('${r.sub_id}')\\\" title=\\\"Delete recce\\\">🗑</button>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const editReqHtml = r.edit_assigned_to\u001b[39m\n\u001b[31m    ? `<span class=\\\"edit-req-badge\\\">✏ Edit sent to ${r.edit_assigned_to}</span>`\u001b[39m\n\u001b[31m    : (_isSupervisor()\u001b[39m\n\u001b[31m        ? `<button class=\\\"req-edit-btn\\\" onclick=\\\"event.stopPropagation();openEditRequestModal('${r.sub_id}')\\\">✏ Request Edit</button>`\u001b[39m\n\u001b[31m        : '');·\u001b[39m\n\u001b[31m  const editRow = editReqHtml\u001b[39m\n\u001b[31m    ? `<div style=\\\"margin-top:6px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">${editReqHtml}</div>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const showPdfBtn = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m  const pdfClass = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m  const pdfLabel = '📄 PDF';\u001b[39m\n\u001b[31m  const linkJobBtn = (_pendingJobFilter && _isSupervisor() && !r.campaign_id)\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:#f59e0b;color:#000;border-color:#f59e0b;font-weight:700\\\" onclick=\\\"event.stopPropagation();openLinkJobModal('${r.sub_id}','${(r.store_name||'Unknown').replace(/'/g,'\\\\\\\\\\\\'')}')\\\">🔗 Link Job</button>`\u001b[39m\n\u001b[31m    : (r.campaign_id ? `<span style=\\\"font-size:10px;color:var(--g400);align-self:center\\\">🔗 ${r.campaign_id}</span>` : '');\u001b[39m\n\u001b[31m  const archiveBtn = canArchive\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:rgba(99,102,241,.08);border-color:var(--nv);color:var(--nv)\\\" onclick=\\\"event.stopPropagation();archiveRecce('${r.sub_id}')\\\">⛚ Archive</button>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const btnsRow = `<div class=\\\"rpt-btns\\\">\u001b[39m\n\u001b[31m    <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openAdminRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m    ${showPdfBtn ? `<button class=\\\"${pdfClass}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">${pdfLabel}</button>` : ''}\u001b[39m\n\u001b[31m    ${linkJobBtn}\u001b[39m\n\u001b[31m    ${archiveBtn}\u001b[39m\n\u001b[31m  </div>`;·\u001b[39m\n\u001b[31m  return `<div class=\\\"asc\\\">\u001b[39m\n\u001b[31m    <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m      <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m          ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          ${r.client_name&&r.client_name!==r.brand?`<span class=\\\"client-tag\\\">🤝 ${r.client_name}</span>`:''}\u001b[39m\n\u001b[31m          <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds} · ${tm}</span>\u001b[39m\n\u001b[31m          ${clientStatusBadge}\u001b[39m\n\u001b[31m          ${archiveBadge}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <span class=\\\"asc-agent\\\">👤 ${r.submitted_by||'?'}</span>\u001b[39m\n\u001b[31m        ${delBtnHtml}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    ${chips.length?`<div class=\\\"asc-chips\\\">${chips.map(c=>`<span class=\\\"asc-chip\\\">${c}</span>`).join('')}</div>`:''}\u001b[39m\n\u001b[31m    ${editRow}\u001b[39m\n\u001b[31m    ${btnsRow}\u001b[39m\n\u001b[31m  </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _ensurePdfOverlay() {\u001b[39m\n\u001b[31m  if (document.getElementById('pdf-wait-ov')) return;\u001b[39m\n\u001b[31m  const ov = document.createElement('div');\u001b[39m\n\u001b[31m  ov.id = 'pdf-wait-ov';\u001b[39m\n\u001b[31m  ov.innerHTML = '<div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Generating PDF…</div><div class=\\\"po-sub\\\" id=\\\"pw-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"pw-pfill\\\"></div></div>';\u001b[39m\n\u001b[31m  document.body.appendChild(ov);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _showPdfOverlay(msg) {\u001b[39m\n\u001b[31m  _ensurePdfOverlay();\u001b[39m\n\u001b[31m  document.getElementById('pw-sub').textContent = msg || '';\u001b[39m\n\u001b[31m  document.getElementById('pw-pfill').style.width = '0%';\u001b[39m\n\u001b[31m  document.getElementById('pdf-wait-ov').style.display = 'flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _hidePdfOverlay() {\u001b[39m\n\u001b[31m  const ov = document.getElementById('pdf-wait-ov');\u001b[39m\n\u001b[31m  if (ov) ov.style.display = 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function openPdf(subId, pdfUrl, viewUrl) {\u001b[39m\n\u001b[31m  if (pdfUrl) { window.open(pdfUrl, '_blank'); return; }\u001b[39m\n\u001b[31m  if (!viewUrl) {\u001b[39m\n\u001b[31m    toast('Report view not available yet — please try after the report is generated.', 'info');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _showPdfOverlay('Requesting PDF generation…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type': 'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({type: 'regen-pdf', subId, viewUrl})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  let attempts = 0;\u001b[39m\n\u001b[31m  const MAX = 24;\u001b[39m\n\u001b[31m  const poll = async () => {\u001b[39m\n\u001b[31m    attempts++;\u001b[39m\n\u001b[31m    const pct = Math.min(88, Math.round(attempts / MAX * 88));\u001b[39m\n\u001b[31m    document.getElementById('pw-pfill').style.width = pct + '%';\u001b[39m\n\u001b[31m    const left = Math.ceil((MAX - attempts) * 5);\u001b[39m\n\u001b[31m    document.getElementById('pw-sub').textContent = 'Checking… (' + left + 's remaining)';\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const res = await fetch('/db/submissions?sub_id=eq.' + subId + '&select=pdf_url', {\u001b[39m\n\u001b[31m        headers: {'Content-Profile': 'recce', 'Accept-Profile': 'recce'}\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      const rows = await res.json();\u001b[39m\n\u001b[31m      if (rows && rows[0] && rows[0].pdf_url) {\u001b[39m\n\u001b[31m        document.getElementById('pw-pfill').style.width = '100%';\u001b[39m\n\u001b[31m        setTimeout(() => { _hidePdfOverlay(); window.open(rows[0].pdf_url, '_blank'); }, 400);\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(_) {}\u001b[39m\n\u001b[31m    if (attempts >= MAX) { _hidePdfOverlay(); toast('PDF generation timed out. Please try again later.', 'error'); return; }\u001b[39m\n\u001b[31m    setTimeout(poll, 5000);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  setTimeout(poll, 4000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openAdminRecce(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];·\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">\u001b[39m\n\u001b[31m         📍 View on Google Maps (${Number(r.gps_lat).toFixed(4)}, ${Number(r.gps_lng).toFixed(4)})\u001b[39m\n\u001b[31m       </a>` : '';·\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} ft × ${b.h||'?'} ft · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos not yet available — field agent must re-sync from their device to upload view\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Submission Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">👤 ${r.submitted_by||'Unknown'}</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            ${meta.videoCmt?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500);font-size:12px\\\">${meta.videoCmt}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m          ${(()=>{\u001b[39m\n\u001b[31m            const hub2 = _recceHubUser();\u001b[39m\n\u001b[31m            const isHP = _RECCE_CFG_ADMINS.includes(hub2?.empId);\u001b[39m\n\u001b[31m            const csMap = {\u001b[39m\n\u001b[31m              approved:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#166534;background:#dcfce7\\\">✓ Approved</span>',\u001b[39m\n\u001b[31m              rejected:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#991b1b;background:#fee2e2\\\">✕ Rejected</span>',\u001b[39m\n\u001b[31m              approved_with_changes: '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#92400e;background:#fef3c7\\\">✎ Approved w/ Comments</span>',\u001b[39m\n\u001b[31m            };\u001b[39m\n\u001b[31m            const csBadge = csMap[r.client_status] || '';\u001b[39m\n\u001b[31m            const approvedAt = r.client_approved_at\u001b[39m\n\u001b[31m              ? new Date(r.client_approved_at).toLocaleString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit',timeZone:'Asia/Kolkata'})\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const pdfLink = r.client_approval_pdf_url\u001b[39m\n\u001b[31m              ? `<a href=\\\"${r.client_approval_pdf_url}\\\" target=\\\"_blank\\\" style=\\\"font-size:12px;color:var(--or);text-decoration:none\\\">⬇ Approval PDF</a>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const archAct = isHP && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveRecce('${r.sub_id}')\\\" style=\\\"font-size:12px;color:var(--nv);background:none;border:1px solid var(--nv);border-radius:6px;padding:4px 10px;cursor:pointer\\\">⦽ Archive from client</button>`\u001b[39m\n\u001b[31m              : (r.client_archived ? '<span style=\\\"font-size:11px;color:var(--g400)\\\">⦽ Hidden from client</span>' : '');\u001b[39m\n\u001b[31m            const campAct = isHP && r.campaign_id && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveAllForCampaign('${r.campaign_id}')\\\" style=\\\"font-size:11px;color:#991b1b;background:none;border:1px solid #fca5a5;border-radius:6px;padding:3px 8px;cursor:pointer\\\">Archive ALL for ${r.campaign_id}</button>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            if (!csBadge && !pdfLink && !archAct) return '';\u001b[39m\n\u001b[31m            return `<div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m              <div class=\\\"ardl-lbl\\\">Client Approval</div>\u001b[39m\n\u001b[31m              ${csBadge ? `<div style=\\\"margin-bottom:5px\\\">${csBadge}${approvedAt ? ' <span style=\\\"font-size:11px;color:var(--g400)\\\">' + approvedAt + '</span>' : ''}</div>` : ''}\u001b[39m\n\u001b[31m              ${r.client_comment ? `<div style=\\\"font-size:12px;color:var(--g600);background:var(--g50);border-radius:6px;padding:7px 10px;margin-bottom:5px\\\">\\\"${r.client_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m              ${pdfLink ? `<div style=\\\"margin-bottom:4px\\\">${pdfLink}</div>` : ''}\u001b[39m\n\u001b[31m              ${archAct ? `<div style=\\\"margin-bottom:4px\\\">${archAct}</div>` : ''}\u001b[39m\n\u001b[31m              ${campAct ? `<div>${campAct}</div>` : ''}\u001b[39m\n\u001b[31m            </div>`;\u001b[39m\n\u001b[31m          })()}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeAdminDetail() {\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveRecce(subId) {\u001b[39m\n\u001b[31m  if (!confirm('Archive this recce from client view? The client will no longer see it.')) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(subId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) Object.assign(_adminRows[idx], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    toast('Archived from client view ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveAllForCampaign(campaignId) {\u001b[39m\n\u001b[31m  if (!confirm(`Archive ALL recces for campaign \\\"${campaignId}\\\" from client view?\\\\nClients will no longer see any recce from this campaign.`)) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?campaign_id=eq.${encodeURIComponent(campaignId)}&client_archived=eq.false`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    _adminRows.forEach((row, i) => {\u001b[39m\n\u001b[31m      if (row.campaign_id === campaignId) Object.assign(_adminRows[i], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    toast(`All recces for ${campaignId} archived ✓`, 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function regenAllReports() {\u001b[39m\n\u001b[31m  if (!_adminUnlocked) { toast('Admin access required', 'error'); return; }\u001b[39m\n\u001b[31m  const rows = _adminRows.filter(r => !r.deleted_at && r.photo_urls);\u001b[39m\n\u001b[31m  if (!rows.length) { toast('No synced rows with photos found', 'error'); return; }·\u001b[39m\n\u001b[31m  const btn = document.getElementById('regen-rpt-btn');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Regenerating…'; }\u001b[39m\n\u001b[31m  toast(`Regenerating ${rows.length} reports…`, 'info');·\u001b[39m\n\u001b[31m  let done = 0, failed = 0;\u001b[39m\n\u001b[31m  for (const r of rows) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const photoUrls = typeof r.photo_urls === 'string' ? JSON.parse(r.photo_urls) : (r.photo_urls || {});\u001b[39m\n\u001b[31m      let meta = {};\u001b[39m\n\u001b[31m      try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m      const entry = {\u001b[39m\n\u001b[31m        id: r.sub_id,\u001b[39m\n\u001b[31m        timestamp: r.submitted_at,\u001b[39m\n\u001b[31m        submittedBy: r.submitted_by,\u001b[39m\n\u001b[31m        data: {\u001b[39m\n\u001b[31m          storeName:    r.store_name,\u001b[39m\n\u001b[31m          brand:        r.brand,\u001b[39m\n\u001b[31m          clientName:   r.client_name,\u001b[39m\n\u001b[31m          date:         r.visit_date,\u001b[39m\n\u001b[31m          address:      r.address,\u001b[39m\n\u001b[31m          city:         r.city,\u001b[39m\n\u001b[31m          mobile:       r.mobile,\u001b[39m\n\u001b[31m          gpsCoords:    (r.gps_lat && r.gps_lng) ? { lat: r.gps_lat, lng: r.gps_lng } : null,\u001b[39m\n\u001b[31m          hasVideo:     r.has_video,\u001b[39m\n\u001b[31m          videoNote:    meta.videoNote || '',\u001b[39m\n\u001b[31m          videoCmt:     meta.videoCmt  || '',\u001b[39m\n\u001b[31m          frontPhotos:  (photoUrls.front   || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          insidePhotos: (photoUrls.inside  || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          addlPhotos:   (photoUrls.addl    || []).map(() => ({ desc: '' })),\u001b[39m\n\u001b[31m          brandings:    (meta.brandings    || []),\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      };·\u001b[39m\n\u001b[31m      const html = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m      const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m        method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m        body: JSON.stringify({ type: 'save-view', subId: r.sub_id, html })\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!vResp.ok) { failed++; continue; }\u001b[39m\n\u001b[31m      const vr = await vResp.json();\u001b[39m\n\u001b[31m      if (!vr.success) { failed++; continue; }·\u001b[39m\n\u001b[31m      if (vr.url && vr.url !== r.view_url) {\u001b[39m\n\u001b[31m        await fetch(`${_RC_BASE}/submissions?sub_id=eq.${r.sub_id}`, {\u001b[39m\n\u001b[31m          method: 'PATCH', headers: _RC_WRITE,\u001b[39m\n\u001b[31m          body: JSON.stringify({ view_url: vr.url })\u001b[39m\n\u001b[31m        });\u001b[39m\n\u001b[31m        const idx = _adminRows.findIndex(x => x.sub_id === r.sub_id);\u001b[39m\n\u001b[31m        if (idx >= 0) _adminRows[idx].view_url = vr.url;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      done++;\u001b[39m\n\u001b[31m    } catch(e) { failed++; }\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = false; btn.textContent = '↻ Regen Reports'; }\u001b[39m\n\u001b[31m  toast(`Done: ${done} regenerated${failed ? `, ${failed} failed` : ''}`, done > 0 ? 'success' : 'error');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction toggleDeletedView() {\u001b[39m\n\u001b[31m  _showDeletedView = !_showDeletedView;\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openDeleteModal(subId) {\u001b[39m\n\u001b[31m  _pendingDeleteId = subId;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  const sub = document.getElementById('del-modal-sub');\u001b[39m\n\u001b[31m  if (sub) sub.textContent = r ? `Delete: \\\"${r.store_name||'Unknown'}\\\"` : 'Select reason for deletion:';\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectDeleteReason(reason) {\u001b[39m\n\u001b[31m  _pendingDeleteReason = reason;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  document.getElementById('reason-' + reason)?.classList.add('sel');\u001b[39m\n\u001b[31m  document.getElementById('del-confirm-btn').classList.remove('no-reason');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeDeleteModal() {\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingDeleteId = null;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  clearTimeout(_tt);\u001b[39m\n\u001b[31m  document.getElementById('toast').classList.remove('show');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function restoreRecce(subId) {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({ deleted_at: null, deleted_by: null, deletion_reason: null }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Restore failed: ' + r.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_at = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_by = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deletion_reason = null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    toast('Recce restored ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Restore failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmDelete() {\u001b[39m\n\u001b[31m  if (!_pendingDeleteReason) {\u001b[39m\n\u001b[31m    const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m    btn.style.animation = 'none';\u001b[39m\n\u001b[31m    btn.offsetHeight; // reflow\u001b[39m\n\u001b[31m    btn.style.animation = 'shake .35s ease';\u001b[39m\n\u001b[31m    toast('Select a reason first', 'error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if (!_pendingDeleteId) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Deleting…';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      // Hard delete — no audit trail\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'DELETE',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Delete failed: ' + r.status);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Soft delete — stamp deleted_at, deleted_by, deletion_reason\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'PATCH',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m        body: JSON.stringify({\u001b[39m\n\u001b[31m          deleted_at: new Date().toISOString(),\u001b[39m\n\u001b[31m          deleted_by: hub.empId,\u001b[39m\n\u001b[31m          deletion_reason: _pendingDeleteReason,\u001b[39m\n\u001b[31m        }),\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Update failed: ' + r.status);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Remove or update in local cache\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      _adminRows = _adminRows.filter(x => x.sub_id !== _pendingDeleteId);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      const idx = _adminRows.findIndex(x => x.sub_id === _pendingDeleteId);\u001b[39m\n\u001b[31m      if (idx >= 0) {\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_at = new Date().toISOString();\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_by = hub.empId;\u001b[39m\n\u001b[31m        _adminRows[idx].deletion_reason = _pendingDeleteReason;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeDeleteModal();\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast('Recce deleted', 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Delete failed', 'error');\u001b[39m\n\u001b[31m    btn.classList.remove('no-reason');\u001b[39m\n\u001b[31m    btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openMyServerRecce(subId) {\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  // No view yet — show metadata modal (same layout as admin detail)\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta==='string' ? JSON.parse(r.meta) : (r.meta||{}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">📍 View on Google Maps</a>` : '';\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} × ${b.h||'?'} in · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos will appear after next sync from original device\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Visit Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupLanding() {\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = 'none';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = 'none';\u001b[39m\n\u001b[31m  // Clean up admin + create-mode UI\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('sup-back-btn')?.remove();\u001b[39m\n\u001b[31m  document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m  _supCreateMode = false;\u001b[39m\n\u001b[31m  // Resume-wrap may have been hidden by loadHomeAdmin() — restore it so draft banner shows\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = '';\u001b[39m\n\u001b[31m  document.getElementById('sub-list').innerHTML = `\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorViewAll()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0f9ff\\\">📋</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">View All Recces</span><span class=\\\"hi-txt\\\">सभी रेकी देखें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">Browse & review submissions from all agents</span><span class=\\\"hi-txt\\\">सभी एजेंट की सबमिशन देखें</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorCreateView()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0fdf4\\\">✍️</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">Create Recce</span><span class=\\\"hi-txt\\\">नई रेकी बनाएं</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">My submissions + New Recce button</span><span class=\\\"hi-txt\\\">मेरी सबमिशन + नई रेकी</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorViewAll() {\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  await loadHomeAdmin();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorCreateView() {\u001b[39m\n\u001b[31m  _supCreateMode = true;\u001b[39m\n\u001b[31m  // Restore field-agent UI\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh'); if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = t('My Submissions','मेरी सबमिशन');\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar'); if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  // Add Back to Menu button (once)\u001b[39m\n\u001b[31m  if (!document.getElementById('sup-back-create-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-create-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => {\u001b[39m\n\u001b[31m      _supCreateMode = false;\u001b[39m\n\u001b[31m      document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m      renderSupLanding();\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    document.querySelector('#view-home .content').prepend(bb);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  await loadHome();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadHome() {\u001b[39m\n\u001b[31m  if (_isSupervisor() && !_supCreateMode) { renderSupLanding(); return; }\u001b[39m\n\u001b[31m  if (_adminUnlocked && !_supCreateMode) { await loadHomeAdmin(); return; }·\u001b[39m\n\u001b[31m  const all  = await dbAll('subs');\u001b[39m\n\u001b[31m  const sy   = all.filter(s => s.status === 'synced').length;\u001b[39m\n\u001b[31m  const pe   = all.filter(s => s.status !== 'synced').length;·\u001b[39m\n\u001b[31m  // Fetch this agent's submissions from server — works on any device\u001b[39m\n\u001b[31m  let serverOnly = [];\u001b[39m\n\u001b[31m  let editAssigned = [];\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (navigator.onLine && hub?.empId) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?submitted_by=eq.${encodeURIComponent(hub.empId)}&order=submitted_at.desc&limit=200`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp.ok) {\u001b[39m\n\u001b[31m        const rows = await resp.json();\u001b[39m\n\u001b[31m        const localIds = new Set(all.map(s => s.id));\u001b[39m\n\u001b[31m        serverOnly = rows.filter(r => !localIds.has(r.sub_id));\u001b[39m\n\u001b[31m        _myServerRows = serverOnly;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m    // Fetch edit-assigned recces (supervisor assigned this creator to edit)\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp2 = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?edit_assigned_to=eq.${encodeURIComponent(hub.empId)}&deleted_at=is.null&order=submitted_at.desc`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp2.ok) editAssigned = await resp2.json();\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = sy + serverOnly.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = pe;\u001b[39m\n\u001b[31m  document.getElementById('stat-total').textContent   = all.length + serverOnly.length;·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!all.length && !serverOnly.length && !editAssigned.length) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">📋</div><div class=\\\"empty-txt\\\">No submissions yet</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const icos   = { synced:'✅', pending:'⏳', failed:'❌' };\u001b[39m\n\u001b[31m  const sorted = [...all].sort((a,b) => new Date(b.timestamp) - new Date(a.timestamp)).slice(0, 50);·\u001b[39m\n\u001b[31m  const localCards = sorted.map(s => {\u001b[39m\n\u001b[31m    const dt = new Date(s.timestamp);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const viewBtn = s.viewUrl\u001b[39m\n\u001b[31m      ? `<button class=\\\"edit-btn-sm\\\" onclick=\\\"window.open('${s.viewUrl}','_blank')\\\">👁 View</button>`\u001b[39m\n\u001b[31m      : `<button class=\\\"edit-btn-sm\\\" onclick=\\\"viewRecce('${s.id}')\\\">👁 View</button>`;\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico ${s.status}\\\">${icos[s.status]||'📋'}</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${s.data.storeName||'Unknown'} · ${s.data.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${s.data.address||''}</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge ${s.status}\\\">${s.status}</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          ${viewBtn}\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"editRecce('${s.id}')\\\" style=\\\"background:#fff7ed;border-color:var(--or);color:var(--or)\\\">✏ Edit</button>\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"makeSlides('${s.id}')\\\" style=\\\"background:#eff6ff;border-color:#3b82f6;color:#1d4ed8\\\">📊 Slides</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const serverCards = serverOnly.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const showPdf = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m    const pdfCls = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico synced\\\">✅</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\" style=\\\"min-width:0;flex:1\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"rpt-btns\\\" style=\\\"margin-top:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openMyServerRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m          ${showPdf ? `<button class=\\\"${pdfCls}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">📄 PDF</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge synced\\\">synced</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const editAssignedCards = editAssigned.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    return `<div class=\\\"edit-req-card\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:26px;flex-shrink:0\\\">✏</div>\u001b[39m\n\u001b[31m      <div class=\\\"edit-req-card-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-meta\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        ${r.edit_comment ? `<div class=\\\"edit-req-cmt\\\">\\\"${r.edit_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:10px;display:flex;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"startCreatorEdit('${r.sub_id}')\\\" style=\\\"padding:9px 16px;font-size:13px;font-weight:600\\\">✏ Edit this Recce</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (editAssignedCards.length) {\u001b[39m\n\u001b[31m    html += `<div class=\\\"edit-req-section-hdr\\\">✏ Edit Requested (${editAssignedCards.length})</div>`;\u001b[39m\n\u001b[31m    html += editAssignedCards.join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  html += localCards.join('') + serverCards.join('');\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m  const ls = await cfg('last-sync');\u001b[39m\n\u001b[31m  if (ls) {\u001b[39m\n\u001b[31m    const d = new Date(ls);\u001b[39m\n\u001b[31m    document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m      'Synced ' + d.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// RESET\u001b[39m\n\u001b[31mfunction startNewRecce(){F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  if(geoStampEnabled)autoRequestGPS();\u001b[39m\n\u001b[31m['f-date','f-brand','f-store','f-addr','f-mobile','f-client-other'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';});\u001b[39m\n\u001b[31m_selectedClient='';_clientOtherMode=false;\u001b[39m\n\u001b[31m_selectedCampaignId=null;_notifySupervisor=false;_brandingLocked=false;\u001b[39m\n\u001b[31mconst _camSel=document.getElementById('f-campaign-id');if(_camSel)_camSel.value='';\u001b[39m\n\u001b[31mconst _camNotice=document.getElementById('campaign-notify-msg');if(_camNotice)_camNotice.style.display='none';\u001b[39m\n\u001b[31mloadCampaignsForForm();\u001b[39m\n\u001b[31mrenderClientChips();\u001b[39m\n\u001b[31mdocument.getElementById('f-date').value=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31m// Block future dates\u001b[39m\n\u001b[31mdocument.getElementById('f-date').max=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31mdocument.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('pick-trigger-wrap').style.display=stores.length?'block':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').style.display=stores.length?'flex':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31mdocument.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31mdocument.getElementById('manual-fields').style.display=stores.length?'none':'block';\u001b[39m\n\u001b[31mdocument.getElementById('gps-status').textContent='';\u001b[39m\n\u001b[31m['vid-yes','vid-no','br-yes','br-no'].forEach(id=>document.getElementById(id).classList.remove('sel'));\u001b[39m\n\u001b[31mdocument.getElementById('vid-sec').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('vid-slot').innerHTML=`<div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('br-add').style.display='none';document.getElementById('br-items').innerHTML='';\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').classList.remove('filled');\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').innerHTML=`<div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('brand-selector').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('sc-missing').style.display='none';\u001b[39m\n\u001b[31mpopulateBrandDropdown();\u001b[39m\n\u001b[31mrenderPhotos('front');renderPhotos('inside');renderAddl();updAvailTag();showView('form-store');}\u001b[39m\n\u001b[31mfunction exitForm(){\u001b[39m\n\u001b[31m  // Show safe exit dialog instead of confirm\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitSaveAndLeave(){\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m  checkDraft();\u001b[39m\n\u001b[31m  toast('Draft saved — tap Resume to continue','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitDiscard(){\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];\u001b[39m\n\u001b[31m  videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  dbDel('draft','current');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitCancel(){document.getElementById('exit-dialog').classList.remove('open');}\u001b[39m\n\u001b[31mfunction showView(n){document.querySelectorAll('.view').forEach(v=>v.classList.remove('active'));const t=document.getElementById('view-'+n);if(t){t.classList.add('active');window.scrollTo(0,0);}}\u001b[39m\n\u001b[31mlet _tt;\u001b[39m\n\u001b[31mfunction toast(msg,type='info'){const el=document.getElementById('toast');el.textContent=msg;el.className='toast show '+type;clearTimeout(_tt);_tt=setTimeout(()=>el.classList.remove('show'),3000);}\u001b[39m\n\u001b[31mfunction netStatus(){const on=navigator.onLine;const dot=document.getElementById('net-dot');const txt=document.getElementById('net-txt');if(dot)dot.className='sdot '+(on?'on':'off');if(txt)txt.textContent=on?t('Online','ऑनलाइन'):t('Offline — saves locally','ऑफलाइन — स्थानीय रूप से सेव');}\u001b[39m\n\u001b[31masync function loadSettings(){\u001b[39m\n\u001b[31m  // Gas URL: pre-load default if none saved, update preview\u001b[39m\n\u001b[31m  const gu=await cfg('gas-url');\u001b[39m\n\u001b[31m  if(!gu)await cfg('gas-url',DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m  // Admin cfg url\u001b[39m\n\u001b[31m  const acu=await cfg('admin-cfg-url');if(acu&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=acu;\u001b[39m\n\u001b[31m  const su=await cfg('srv-url')||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su)document.getElementById('srv-url').value=su;\u001b[39m\n\u001b[31m  const sc=await cfg('stores');\u001b[39m\n\u001b[31m  if(sc){\u001b[39m\n\u001b[31m    stores=JSON.parse(sc);\u001b[39m\n\u001b[31m    const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m    document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m      `✓ ${stores.length} stores in cache${noBrand?` · ${noBrand} without brand`:''}`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const sf=await cfg('store-files');if(sf){_storeFiles=JSON.parse(sf);renderStoreFileList();}\u001b[39m\n\u001b[31m  const iq=await cfg('img-quality');imgQuality=iq||'compressed';applyQualityUI(imgQuality);\u001b[39m\n\u001b[31m  const gs=await cfg('geo-stamp');geoStampEnabled=(gs===null||gs==='1');applyGeoStampUI();\u001b[39m\n\u001b[31m  const bl=await cfg('brands');if(bl)brands=JSON.parse(bl);\u001b[39m\n\u001b[31m  loadBrandsFromDb();  // async — updates brands + logos from DB in background\u001b[39m\n\u001b[31m  renderBrandManageList();\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m  // Show store upload row + brand add row to supervisors only\u001b[39m\n\u001b[31m  const sur = document.getElementById('store-upload-row');\u001b[39m\n\u001b[31m  if (sur) sur.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const bar = document.getElementById('brand-add-row');\u001b[39m\n\u001b[31m  if (bar) bar.style.display = _isSupervisor() ? 'flex' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction populateBrandDropdown(){\u001b[39m\n\u001b[31m  const sel=document.getElementById('f-brand');if(!sel)return;\u001b[39m\n\u001b[31m  const cur=sel.value;\u001b[39m\n\u001b[31m  sel.innerHTML='<option value=\\\"\\\">Select brand</option>'+brands.map(b=>`<option${cur===b?' selected':''}>${b}</option>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderBrandManageList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('brand-manage-list');if(!el)return;\u001b[39m\n\u001b[31m  const isSup=_isSupervisor();\u001b[39m\n\u001b[31m  el.innerHTML=brands.map((b,i)=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    const logoHtml=logo?`<img src=\\\"${logo}\\\" style=\\\"height:20px;max-width:48px;object-fit:contain;flex-shrink:0;border-radius:3px\\\">`:'';\u001b[39m\n\u001b[31m    const ctrlHtml=isSup?`<div style=\\\"display:flex;gap:2px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"openEditBrandDialog(${i})\\\" style=\\\"background:none;border:none;color:var(--nv);font-size:15px;cursor:pointer;padding:2px 6px\\\" title=\\\"Edit\\\">✏</button>\u001b[39m\n\u001b[31m      ${brands.length>1?`<button onclick=\\\"confirmRemoveBrand(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:2px 4px\\\">×</button>`:'<span style=\\\"font-size:11px;color:var(--g400);padding:0 6px\\\">Last</span>'}\u001b[39m\n\u001b[31m    </div>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;min-width:0\\\">${logoHtml}<span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${b}</span></div>\u001b[39m\n\u001b[31m      ${ctrlHtml}\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function addBrandToList(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const inp=document.getElementById('brand-add-inp');\u001b[39m\n\u001b[31m  const val=(inp.value.trim()||'').toUpperCase();\u001b[39m\n\u001b[31m  if(!val){toast('Enter a brand name','error');return;}\u001b[39m\n\u001b[31m  if(brands.some(b=>b.toLowerCase()===val.toLowerCase())){toast(`${val} already in list`,'error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands`,{method:'POST',headers:{..._RC_WRITE,'Prefer':'return=minimal'},body:JSON.stringify({name:val,sort_order:99})});\u001b[39m\n\u001b[31m    if(resp.status===409){toast(`${val} already exists in DB`,'error');return;}\u001b[39m\n\u001b[31m    if(!resp.ok){const e=await resp.json().catch(()=>({}));throw new Error(e.message||resp.status);}\u001b[39m\n\u001b[31m    inp.value='';\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${val} added ✓`,'success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Add failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmRemoveBrand(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const name=brands[idx];\u001b[39m\n\u001b[31m  if(brands.length<=1){toast('Need at least one brand','error');return;}\u001b[39m\n\u001b[31m  let count=0;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(name)}&select=sub_id`,{headers:_RC_READ});\u001b[39m\n\u001b[31m    if(r.ok){const rows=await r.json();count=rows.length;}\u001b[39m\n\u001b[31m  }catch(_){}\u001b[39m\n\u001b[31m  const msg=count>0?`Delete \\\"${name}\\\" from brand list?\\\\n(${count} submission${count!==1?'s':''} reference this brand — they keep the name as text.)`:`Delete \\\"${name}\\\" from brand list?`;\u001b[39m\n\u001b[31m  if(!confirm(msg))return;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(name)}`,{method:'DELETE',headers:{'Content-Profile':'recce','Accept-Profile':'recce'}});\u001b[39m\n\u001b[31m    if(!resp.ok&&resp.status!==204){throw new Error(resp.status);}\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${name} removed ✓`,'info');\u001b[39m\n\u001b[31m  }catch(e){toast(`Remove failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadBrandsFromDb(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch('/db/brands?select=name,logo_url&order=sort_order',{\u001b[39m\n\u001b[31m      headers:{'Content-Profile':'recce','Accept-Profile':'recce'}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(!r.ok) return;\u001b[39m\n\u001b[31m    const rows=await r.json();\u001b[39m\n\u001b[31m    if(!rows||!rows.length) return;\u001b[39m\n\u001b[31m    const dbNames=rows.map(r=>r.name);\u001b[39m\n\u001b[31m    const logos={};rows.forEach(r=>{if(r.logo_url)logos[r.name]=r.logo_url;});\u001b[39m\n\u001b[31m    // Merge: DB brands canonical, keep locally-added extras\u001b[39m\n\u001b[31m    const extras=brands.filter(b=>!dbNames.some(n=>n.toLowerCase()===b.toLowerCase()));\u001b[39m\n\u001b[31m    brands=[...dbNames,...extras];\u001b[39m\n\u001b[31m    _brandLogos=logos;\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    // Refresh brand chips if brand-selector is visible\u001b[39m\n\u001b[31m    const bSel=document.getElementById('brand-selector');\u001b[39m\n\u001b[31m    if(bSel&&bSel.style.display!=='none') renderBrandChips();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[brands-db]',e.message);}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction renderBrandChips(){\u001b[39m\n\u001b[31m  const bChips=document.getElementById('brand-chips');if(!bChips)return;\u001b[39m\n\u001b[31m  bChips.innerHTML=brands.map(b=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    return `<div class=\\\"chip brand-chip${F.brand===b?' sel':''}\\\" onclick=\\\"selectStoreBrand('${b.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\">` +\u001b[39m\n\u001b[31m      (logo?`<img src=\\\"${logo}\\\" class=\\\"brand-chip-logo\\\" alt=\\\"\\\">`:'') +\u001b[39m\n\u001b[31m      `<span>${b}</span></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _editBrandIdx=null,_editBrandOld=null;\u001b[39m\n\u001b[31mfunction openEditBrandDialog(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor())return;\u001b[39m\n\u001b[31m  _editBrandIdx=idx;_editBrandOld=brands[idx];\u001b[39m\n\u001b[31m  document.getElementById('be-name').value=brands[idx];\u001b[39m\n\u001b[31m  const logo=_brandLogos[brands[idx]]||'';\u001b[39m\n\u001b[31m  document.getElementById('be-logo').value=logo;\u001b[39m\n\u001b[31m  document.getElementById('be-logo-preview').innerHTML=logo?`<img src=\\\"${logo}\\\" style=\\\"height:28px;object-fit:contain\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Current logo</span>`:'';\u001b[39m\n\u001b[31m  document.getElementById('be-cascade-info').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('brand-edit-modal').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeBrandEditModal(){document.getElementById('brand-edit-modal').classList.remove('open');_editBrandIdx=null;_editBrandOld=null;}\u001b[39m\n\u001b[31mfunction previewBrandLogo(){\u001b[39m\n\u001b[31m  const url=(document.getElementById('be-logo')?.value||'').trim();\u001b[39m\n\u001b[31m  const prev=document.getElementById('be-logo-preview');\u001b[39m\n\u001b[31m  if(prev)prev.innerHTML=url?`<img src=\\\"${url}\\\" style=\\\"height:28px;object-fit:contain\\\" onerror=\\\"this.style.display='none'\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Preview</span>`:'';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveBrandEdit(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const oldName=_editBrandOld;\u001b[39m\n\u001b[31m  const newName=(document.getElementById('be-name').value||'').trim().toUpperCase();\u001b[39m\n\u001b[31m  const newLogo=(document.getElementById('be-logo').value||'').trim();\u001b[39m\n\u001b[31m  if(!newName){toast('Brand name required','error');return;}\u001b[39m\n\u001b[31m  const isRename=newName!==oldName;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // 1. Update recce.brands\u001b[39m\n\u001b[31m    const pResp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m      method:'PATCH',headers:{..._RC_WRITE,'Prefer':'return=minimal'},\u001b[39m\n\u001b[31m      body:JSON.stringify({name:newName,logo_url:newLogo||null})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(pResp.status===409){toast(`\\\"${newName}\\\" already exists`,'error');return;}\u001b[39m\n\u001b[31m    if(!pResp.ok&&pResp.status!==204){const e=await pResp.json().catch(()=>({}));throw new Error(e.message||pResp.status);}\u001b[39m\n\u001b[31m    if(isRename){\u001b[39m\n\u001b[31m      const hub=_recceHubUser();\u001b[39m\n\u001b[31m      // 2. Cascade to submissions\u001b[39m\n\u001b[31m      await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m        method:'PATCH',headers:_RC_WRITE,body:JSON.stringify({brand:newName})\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      // 3. Cascade to stores.json + view HTML files + PDFs\u001b[39m\n\u001b[31m      toast('Cascading rename to reports…','info');\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        const cResp=await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},\u001b[39m\n\u001b[31m          body:JSON.stringify({type:'cascade-rename-brand',oldName,newName,empId:hub?.empId||''})});\u001b[39m\n\u001b[31m        const cRes=cResp.ok?await cResp.json():{};\u001b[39m\n\u001b[31m        const msg=`Brand renamed ✓${cRes.viewsUpdated?` · ${cRes.viewsUpdated} reports re-queued`:''}`;\u001b[39m\n\u001b[31m        closeBrandEditModal();\u001b[39m\n\u001b[31m        await loadBrandsFromDb();\u001b[39m\n\u001b[31m        toast(msg,'success');\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }catch(e){console.warn('[cascade-rename]',e.message);}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeBrandEditModal();\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast('Brand updated ✓','success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Save failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function fetchServerBrands(){\u001b[39m\n\u001b[31m  const url=document.getElementById('brands-url')?.value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    toast('Fetching brands…','info');\u001b[39m\n\u001b[31m    const r=await fetch(url);const j=await r.json();\u001b[39m\n\u001b[31m    const list=Array.isArray(j)?j:j.brands||[];\u001b[39m\n\u001b[31m    if(!list.length){toast('No brands found in response','error');return;}\u001b[39m\n\u001b[31m    brands=list.map(b=>b.toString().toUpperCase());\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    toast(`${brands.length} brands loaded from server`,'success');\u001b[39m\n\u001b[31m  }catch{toast('Failed to fetch — check URL','error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setImgQuality(q){\u001b[39m\n\u001b[31m  imgQuality=q;\u001b[39m\n\u001b[31m  cfg('img-quality',q);\u001b[39m\n\u001b[31m  applyQualityUI(q);\u001b[39m\n\u001b[31m  toast(q==='hd'?'HD Quality selected (~400–600 KB per photo)':'Full Compression selected (~150–200 KB per photo)','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction applyQualityUI(q){\u001b[39m\n\u001b[31m  ['compressed','hd'].forEach(opt=>{\u001b[39m\n\u001b[31m    const label=document.getElementById('q-opt-'+opt);\u001b[39m\n\u001b[31m    const radio=document.getElementById('q-radio-'+opt);\u001b[39m\n\u001b[31m    const dot  =document.getElementById('q-dot-'+opt);\u001b[39m\n\u001b[31m    if(!label)return;\u001b[39m\n\u001b[31m    const active=opt===q;\u001b[39m\n\u001b[31m    label.style.borderColor=active?'var(--or)':'var(--g200)';\u001b[39m\n\u001b[31m    label.style.background=active?'#fff7ed':'var(--g50)';\u001b[39m\n\u001b[31m    if(radio)radio.style.borderColor=active?'var(--or)':'var(--g300)';\u001b[39m\n\u001b[31m    if(dot)dot.style.display=active?'block':'none';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const badge=document.getElementById('q-current-badge');\u001b[39m\n\u001b[31m  if(badge){\u001b[39m\n\u001b[31m    const label=q==='hd'?'HD Quality (~400–600 KB)':'Full Compression (~150–200 KB)';\u001b[39m\n\u001b[31m    badge.innerHTML=`Active: <strong>${label}</strong>`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function clearData(){if(!confirm('Delete ALL local data?'))return;const all=await dbAll('subs');for(const s of all)await dbDel('subs',s.id);stores=[];await cfg('stores',null);toast('All cleared','success');loadHome();}\u001b[39m\n\u001b[31mif('serviceWorker' in navigator){const sw=`const C='recce-v37';self.addEventListener('install',e=>{e.waitUntil(caches.open(C).then(c=>c.add('/')));self.skipWaiting();});self.addEventListener('activate',e=>e.waitUntil(clients.claim()));self.addEventListener('fetch',e=>{if(e.request.method!=='GET')return;e.respondWith(caches.match(e.request).then(r=>{if(r)return r;return fetch(e.request).then(res=>{if(res&&res.status===200&&res.type==='basic'){const cl=res.clone();caches.open(C).then(c=>c.put(e.request,cl));}return res;}).catch(()=>caches.match('/'));}))}); `;const blob=new Blob([sw],{type:'application/javascript'});navigator.serviceWorker.register(URL.createObjectURL(blob),{scope:'/'}).catch(()=>{});}·\u001b[39m\n\u001b[31m// ── GEOLOCATION STAMP ────────────────────────────────────────\u001b[39m\n\u001b[31mfunction applyGeoStampUI(){\u001b[39m\n\u001b[31m  const tog=document.getElementById('geo-tog');\u001b[39m\n\u001b[31m  if(tog)tog.classList.toggle('on',geoStampEnabled);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function toggleGeoStamp(){\u001b[39m\n\u001b[31m  geoStampEnabled=!geoStampEnabled;\u001b[39m\n\u001b[31m  await cfg('geo-stamp',geoStampEnabled?'1':'0');\u001b[39m\n\u001b[31m  applyGeoStampUI();\u001b[39m\n\u001b[31m  toast(geoStampEnabled?'Geolocation stamp enabled':'Geolocation stamp disabled','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Auto-request GPS silently when a new recce starts\u001b[39m\n\u001b[31mfunction autoRequestGPS(){\u001b[39m\n\u001b[31m  if(!navigator.geolocation)return;\u001b[39m\n\u001b[31m  const statusEl=document.getElementById('geo-status');\u001b[39m\n\u001b[31m  if(statusEl)statusEl.textContent='Acquiring GPS…';\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(\u001b[39m\n\u001b[31m    pos=>{\u001b[39m\n\u001b[31m      gpsCoords={\u001b[39m\n\u001b[31m        lat:pos.coords.latitude.toFixed(6),\u001b[39m\n\u001b[31m        lng:pos.coords.longitude.toFixed(6),\u001b[39m\n\u001b[31m        acc:Math.round(pos.coords.accuracy)\u001b[39m\n\u001b[31m      };\u001b[39m\n\u001b[31m      const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m      const quality=acc<=15?'Excellent':acc<=50?'Good':acc<=200?'Fair':'Poor (cell tower)';\u001b[39m\n\u001b[31m      const color=acc<=15?'var(--gn)':acc<=50?'#16a34a':acc<=200?'var(--am)':'var(--rd)';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.innerHTML=`GPS: ${gpsCoords.lat}, ${gpsCoords.lng} · ±${acc}m · <span style=\\\"color:${color};font-weight:600\\\">${quality}</span>`;\u001b[39m\n\u001b[31m      // Update form GPS status too\u001b[39m\n\u001b[31m      const fs=document.getElementById('gps-status');\u001b[39m\n\u001b[31m      if(fs){fs.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${acc}m)`;fs.style.color='var(--gn)';}\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    err=>{\u001b[39m\n\u001b[31m      const msgs={1:'Location permission denied in Chrome',2:'GPS signal unavailable',3:'GPS timed out'};\u001b[39m\n\u001b[31m      const msg=msgs[err.code]||'GPS unavailable';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.textContent=msg+' — stamp will use store address';\u001b[39m\n\u001b[31m      if(err.code===1)toast('Tap the lock icon in Chrome address bar → allow Location','info');\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    {enableHighAccuracy:true,timeout:20000,maximumAge:60000}\u001b[39m\n\u001b[31m  );\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Draw stamp on a photo blob — returns new blob with stamp baked in\u001b[39m\n\u001b[31mfunction roundRectPath(ctx,x,y,w,h,r){\u001b[39m\n\u001b[31m  ctx.beginPath();ctx.moveTo(x+r,y);ctx.lineTo(x+w-r,y);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y,x+w,y+r);ctx.lineTo(x+w,y+h-r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);ctx.lineTo(x+r,y+h);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y+h,x,y+h-r);ctx.lineTo(x,y+r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y,x+r,y);ctx.closePath();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction fitText(ctx,text,maxW){\u001b[39m\n\u001b[31m  if(ctx.measureText(text).width<=maxW)return text;\u001b[39m\n\u001b[31m  while(text.length>1&&ctx.measureText(text+'…').width>maxW)text=text.slice(0,-1);\u001b[39m\n\u001b[31m  return text+'…';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction stampPhoto(blob){\u001b[39m\n\u001b[31m  if(!geoStampEnabled)return Promise.resolve(blob);\u001b[39m\n\u001b[31m  return new Promise(res=>{\u001b[39m\n\u001b[31m    const img=new Image(),url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    img.onload=()=>{\u001b[39m\n\u001b[31m      URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m      const W=img.width,H=img.height;\u001b[39m\n\u001b[31m      const c=document.createElement('canvas');c.width=W;c.height=H;\u001b[39m\n\u001b[31m      const ctx=c.getContext('2d');\u001b[39m\n\u001b[31m      ctx.drawImage(img,0,0);·\u001b[39m\n\u001b[31m      // Stamp dimensions — 18% of image height\u001b[39m\n\u001b[31m      const SH=Math.round(H*0.18);\u001b[39m\n\u001b[31m      const pad=Math.round(W*0.03);\u001b[39m\n\u001b[31m      const SY=H-SH;·\u001b[39m\n\u001b[31m      // Semi-transparent background\u001b[39m\n\u001b[31m      ctx.fillStyle='rgba(10,18,35,0.78)';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,SH);·\u001b[39m\n\u001b[31m      // Orange top accent line\u001b[39m\n\u001b[31m      ctx.fillStyle='#f97316';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,Math.max(3,Math.round(H*0.004)));·\u001b[39m\n\u001b[31m      // Font sizes scaled to image\u001b[39m\n\u001b[31m      const f1=Math.round(SH*0.26); // store name\u001b[39m\n\u001b[31m      const f2=Math.round(SH*0.22); // coords / address\u001b[39m\n\u001b[31m      const f3=Math.round(SH*0.20); // timestamp·\u001b[39m\n\u001b[31m      // Row Y centres\u001b[39m\n\u001b[31m      const r1=SY+SH*0.26;\u001b[39m\n\u001b[31m      const r2=SY+SH*0.55;\u001b[39m\n\u001b[31m      const r3=SY+SH*0.82;·\u001b[39m\n\u001b[31m      // Get stamp data\u001b[39m\n\u001b[31m      const storeName=F.storeName||selectedStore?.name||'';\u001b[39m\n\u001b[31m      const brand=F.brand||selectedStore?.brand||'';\u001b[39m\n\u001b[31m      const addr=F.address||selectedStore?.address||'';\u001b[39m\n\u001b[31m      const now=new Date();\u001b[39m\n\u001b[31m      const dateStr=now.toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m      const timeStr=now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit',hour12:true});·\u001b[39m\n\u001b[31m      // Badge (right side — GPS quality)\u001b[39m\n\u001b[31m      let badgeLabel='',badgeColor='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m        if(acc<=15){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=50){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=200){badgeLabel='~'+acc+'m';badgeColor='#d97706';}\u001b[39m\n\u001b[31m        else{badgeLabel='Cell ~'+acc+'m';badgeColor='#dc2626';}\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        badgeLabel='No GPS';badgeColor='#64748b';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      const bFontSz=Math.round(SH*0.18);\u001b[39m\n\u001b[31m      ctx.font=`bold ${bFontSz}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      const bW=Math.round(ctx.measureText(badgeLabel).width+pad);\u001b[39m\n\u001b[31m      const bH=Math.round(SH*0.32);\u001b[39m\n\u001b[31m      const bX=W-bW-pad;const bY=SY+(SH-bH)/2;\u001b[39m\n\u001b[31m      ctx.fillStyle=badgeColor+'cc';\u001b[39m\n\u001b[31m      roundRectPath(ctx,bX,bY,bW,bH,4);ctx.fill();\u001b[39m\n\u001b[31m      ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';\u001b[39m\n\u001b[31m      ctx.fillText(badgeLabel,bX+bW/2,bY+bH/2);\u001b[39m\n\u001b[31m      ctx.textAlign='left';ctx.textBaseline='alphabetic';·\u001b[39m\n\u001b[31m      const textMaxW=bX-pad*2;·\u001b[39m\n\u001b[31m      // Row 1 — store name + brand\u001b[39m\n\u001b[31m      ctx.font=`bold ${f1}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#ffffff';\u001b[39m\n\u001b[31m      const nameText=storeName+(brand?' · '+brand:'');\u001b[39m\n\u001b[31m      ctx.fillText('📍 '+fitText(ctx,nameText,textMaxW-f1*1.4),pad,r1);·\u001b[39m\n\u001b[31m      // Row 2 — GPS coords OR address\u001b[39m\n\u001b[31m      ctx.font=`${f2}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#cbd5e1';\u001b[39m\n\u001b[31m      let row2='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        row2=`Lat ${gpsCoords.lat}°   Long ${gpsCoords.lng}°`;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        row2=addr?fitText(ctx,addr,textMaxW):'GPS coordinates unavailable';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      ctx.fillText(row2,pad,r2);·\u001b[39m\n\u001b[31m      // Row 3 — date and time\u001b[39m\n\u001b[31m      ctx.font=`${f3}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#94a3b8';\u001b[39m\n\u001b[31m      ctx.fillText(`${dateStr}   ${timeStr}`,pad,r3);·\u001b[39m\n\u001b[31m      c.toBlob(b=>res(b||blob),'image/jpeg',imgQuality==='hd'?0.88:0.82);\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    img.onerror=()=>{URL.revokeObjectURL(url);res(blob);};\u001b[39m\n\u001b[31m    img.src=url;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _aTool='rect',_aColor='#f97316',_aWidth=4,_aTarget=-1;\u001b[39m\n\u001b[31mlet _aImg=null,_aHistory=[],_aDrawing=false,_aStart={},_aPts=[];\u001b[39m\n\u001b[31mlet _aSel=-1,_aDragMode=null,_aDragOff={x:0,y:0};\u001b[39m\n\u001b[31m// Larger hit radius on touch devices for easier finger selection\u001b[39m\n\u001b[31mconst HIT_R=()=>('ontouchstart' in window)?32:16;·\u001b[39m\n\u001b[31mfunction setATool(t){\u001b[39m\n\u001b[31m  _aTool=t;\u001b[39m\n\u001b[31m  ['rect','ellipse','line','arrow','free'].forEach(id=>{const el=document.getElementById('at-'+id);if(el)el.classList.toggle('on',id===t&&t!=='move');});\u001b[39m\n\u001b[31m  const mv=document.getElementById('at-move');if(mv)mv.classList.toggle('sel-on',t==='move');\u001b[39m\n\u001b[31m  const info=document.getElementById('annot-sel-info');if(info)info.style.display=t==='move'?'block':'none';\u001b[39m\n\u001b[31m  if(t!=='move'){_aSel=-1;redrawAnnot();}\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(cvs)cvs.style.cursor=t==='move'?'default':'crosshair';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAColor(c){\u001b[39m\n\u001b[31m  _aColor=c;\u001b[39m\n\u001b[31m  const m={'#f97316':'or','#ef4444':'rd','#ffffff':'wh','#facc15':'yw','#22c55e':'gn'};\u001b[39m\n\u001b[31m  Object.entries(m).forEach(([col,id])=>{const el=document.getElementById('ac-'+id);if(el)el.classList.toggle('on',col===c);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAWidth(w){_aWidth=w;[2,4,7].forEach(v=>{const el=document.getElementById('aw-'+v);if(el)el.classList.toggle('on',v===w);});}·\u001b[39m\n\u001b[31mfunction openAnnot(idx){\u001b[39m\n\u001b[31m  _aTarget=idx;_aHistory=[];_aDrawing=false;_aPts=[];_aSel=-1;_aDragMode=null;\u001b[39m\n\u001b[31m  document.getElementById('annot-modal').classList.add('open');\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');\u001b[39m\n\u001b[31m  const img=new Image(),url=URL.createObjectURL(brandings[idx].blob);\u001b[39m\n\u001b[31m  img.onload=()=>{\u001b[39m\n\u001b[31m    const sc=Math.min(1,window.innerWidth/img.width,(window.innerHeight-185)/img.height);\u001b[39m\n\u001b[31m    cvs.width=Math.round(img.width*sc);cvs.height=Math.round(img.height*sc);\u001b[39m\n\u001b[31m    _aImg=img;redrawAnnot();URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  img.src=url;\u001b[39m\n\u001b[31m  cvs.ontouchstart=aDown;cvs.ontouchmove=aMove;cvs.ontouchend=aUp;\u001b[39m\n\u001b[31m  cvs.onmousedown=aDown;cvs.onmousemove=aMove;cvs.onmouseup=aUp;\u001b[39m\n\u001b[31m  setATool('rect');setAColor('#f97316');setAWidth(4);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aPos(e){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const r=cvs.getBoundingClientRect();\u001b[39m\n\u001b[31m  const src=e.touches?e.touches[0]:e;\u001b[39m\n\u001b[31m  return{x:(src.clientX-r.left)*(cvs.width/r.width),y:(src.clientY-r.top)*(cvs.height/r.height)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Always return normalised (positive w,h) bounds\u001b[39m\n\u001b[31mfunction sBounds(s){\u001b[39m\n\u001b[31m  if(s.type==='free'){\u001b[39m\n\u001b[31m    if(!s.pts||!s.pts.length)return null;\u001b[39m\n\u001b[31m    const xs=s.pts.map(p=>p.x),ys=s.pts.map(p=>p.y);\u001b[39m\n\u001b[31m    const x=Math.min(...xs),y=Math.min(...ys);\u001b[39m\n\u001b[31m    return{x,y,w:Math.max(...xs)-x,h:Math.max(...ys)-y};\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  return{x:Math.min(s.x,s.x+s.w),y:Math.min(s.y,s.y+s.h),w:Math.abs(s.w),h:Math.abs(s.h)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction hitHandle(px,py,s){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return null;\u001b[39m\n\u001b[31m  const b=sBounds(s);const hr=HIT_R();\u001b[39m\n\u001b[31m  for(const[n,x,y]of[['tl',b.x,b.y],['tr',b.x+b.w,b.y],['bl',b.x,b.y+b.h],['br',b.x+b.w,b.y+b.h]])\u001b[39m\n\u001b[31m    if(Math.hypot(px-x,py-y)<hr)return n;\u001b[39m\n\u001b[31m  return null;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction hitShape(px,py,s){\u001b[39m\n\u001b[31m  const b=sBounds(s);if(!b)return false;\u001b[39m\n\u001b[31m  const pad=HIT_R();\u001b[39m\n\u001b[31m  return px>=b.x-pad&&px<=b.x+b.w+pad&&py>=b.y-pad&&py<=b.y+b.h+pad;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aDown(e){\u001b[39m\n\u001b[31m  e.preventDefault();const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'){\u001b[39m\n\u001b[31m    // Check handles of selected shape first\u001b[39m\n\u001b[31m    if(_aSel>=0&&_aSel<_aHistory.length){\u001b[39m\n\u001b[31m      const h=hitHandle(p.x,p.y,_aHistory[_aSel]);\u001b[39m\n\u001b[31m      if(h){_aDragMode='r-'+h;_aDragOff={x:p.x,y:p.y};_aDrawing=true;return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Hit test all shapes topmost first\u001b[39m\n\u001b[31m    for(let i=_aHistory.length-1;i>=0;i--){\u001b[39m\n\u001b[31m      if(hitShape(p.x,p.y,_aHistory[i])){\u001b[39m\n\u001b[31m        _aSel=i;_aDragMode='move';\u001b[39m\n\u001b[31m        const s=_aHistory[i];\u001b[39m\n\u001b[31m        const b=sBounds(s);\u001b[39m\n\u001b[31m        // Store offset from shape top-left corner (normalised)\u001b[39m\n\u001b[31m        _aDragOff={x:p.x-b.x,y:p.y-b.y};\u001b[39m\n\u001b[31m        _aDrawing=true;redrawAnnot();return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    _aSel=-1;redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _aDrawing=true;_aStart={x:p.x,y:p.y};if(_aTool==='free')_aPts=[{x:p.x,y:p.y}];\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aMove(e){\u001b[39m\n\u001b[31m  e.preventDefault();if(!_aDrawing)return;const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'&&_aDragMode){\u001b[39m\n\u001b[31m    const s=_aHistory[_aSel];if(!s)return;\u001b[39m\n\u001b[31m    if(_aDragMode==='move'){\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      // New top-left position\u001b[39m\n\u001b[31m      const nx=p.x-_aDragOff.x;\u001b[39m\n\u001b[31m      const ny=p.y-_aDragOff.y;\u001b[39m\n\u001b[31m      const dx=nx-b.x,dy=ny-b.y;\u001b[39m\n\u001b[31m      if(s.type==='free'){\u001b[39m\n\u001b[31m        s.pts=s.pts.map(pt=>({x:pt.x+dx,y:pt.y+dy}));\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        // Move preserving w/h sign (don't normalise — keep original drawing direction)\u001b[39m\n\u001b[31m        s.x+=dx;s.y+=dy;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Resize from corner — always work on normalised bounds then re-apply\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      const n=_aDragMode.slice(2);\u001b[39m\n\u001b[31m      let nx=b.x,ny=b.y,nw=b.w,nh=b.h;\u001b[39m\n\u001b[31m      if(n==='br'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,p.y-b.y);}\u001b[39m\n\u001b[31m      else if(n==='tl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,b.y+b.h-p.y);nx=p.x;ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='tr'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,b.y+b.h-p.y);ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='bl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,p.y-b.y);nx=p.x;}\u001b[39m\n\u001b[31m      s.x=nx;s.y=ny;s.w=nw;s.h=nh; // store as normalised going forward\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if(_aTool==='free'){_aPts.push({x:p.x,y:p.y});redrawAnnot();drawSh({type:'free',pts:[..._aPts],color:_aColor,lw:_aWidth},true);return;}\u001b[39m\n\u001b[31m  redrawAnnot();drawSh({type:_aTool,x:_aStart.x,y:_aStart.y,w:p.x-_aStart.x,h:p.y-_aStart.y,color:_aColor,lw:_aWidth},true);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction aUp(e){\u001b[39m\n\u001b[31m  if(!_aDrawing)return;_aDrawing=false;\u001b[39m\n\u001b[31m  if(_aTool==='move'){_aDragMode=null;return;}\u001b[39m\n\u001b[31m  const p=aPos(e||{touches:[{clientX:0,clientY:0}]});\u001b[39m\n\u001b[31m  if(_aTool==='free'){if(_aPts.length>2){_aHistory.push({type:'free',pts:[..._aPts],x:_aPts[0].x,y:_aPts[0].y,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  else{const w=p.x-_aStart.x,h=p.y-_aStart.y;if(Math.abs(w)>4||Math.abs(h)>4){_aHistory.push({type:_aTool,x:_aStart.x,y:_aStart.y,w,h,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  _aPts=[];redrawAnnot();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction redrawAnnot(){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.clearRect(0,0,cvs.width,cvs.height);if(_aImg)ctx.drawImage(_aImg,0,0,cvs.width,cvs.height);\u001b[39m\n\u001b[31m  _aHistory.forEach((s,i)=>{drawSh(s,false,ctx);if(_aTool==='move'&&i===_aSel)drawHandles(s,ctx);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawHandles(s,ctx){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return;const b=sBounds(s);ctx.save();\u001b[39m\n\u001b[31m  ctx.setLineDash([5,3]);ctx.strokeStyle='#facc15';ctx.lineWidth=1.5;ctx.strokeRect(b.x-2,b.y-2,b.w+4,b.h+4);ctx.setLineDash([]);\u001b[39m\n\u001b[31m  [[b.x,b.y],[b.x+b.w,b.y],[b.x,b.y+b.h],[b.x+b.w,b.y+b.h]].forEach(([x,y])=>{ctx.beginPath();ctx.arc(x,y,7,0,2*Math.PI);ctx.fillStyle='#f97316';ctx.fill();ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();});\u001b[39m\n\u001b[31m  ctx.restore();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawSh(s,preview=false,ctx){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(!ctx)ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.save();ctx.strokeStyle=s.color;ctx.lineWidth=preview?Math.max(s.lw||4,2):s.lw||4;\u001b[39m\n\u001b[31m  ctx.lineCap='round';ctx.lineJoin='round';ctx.setLineDash(preview?[6,3]:[]);\u001b[39m\n\u001b[31m  if(s.type==='rect'){ctx.strokeRect(s.x,s.y,s.w,s.h);ctx.fillStyle=s.color+'28';ctx.fillRect(s.x,s.y,s.w,s.h);}\u001b[39m\n\u001b[31m  else if(s.type==='ellipse'){const cx=s.x+s.w/2,cy=s.y+s.h/2;ctx.beginPath();ctx.ellipse(cx,cy,Math.abs(s.w/2),Math.abs(s.h/2),0,0,2*Math.PI);ctx.stroke();ctx.fillStyle=s.color+'28';ctx.fill();}\u001b[39m\n\u001b[31m  else if(s.type==='line'){ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(s.x+s.w,s.y+s.h);ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='arrow'){const ex=s.x+s.w,ey=s.y+s.h;ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(ex,ey);ctx.stroke();const a=Math.atan2(s.h,s.w),al=20,aa=0.4;ctx.setLineDash([]);ctx.beginPath();ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a-aa),ey-al*Math.sin(a-aa));ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a+aa),ey-al*Math.sin(a+aa));ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='free'){if(s.pts.length<2){ctx.restore();return;}ctx.beginPath();s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));ctx.stroke();}\u001b[39m\n\u001b[31m  ctx.setLineDash([]);ctx.restore();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction undoAnnot(){if(_aHistory.length){_aHistory.pop();_aSel=Math.min(_aSel,_aHistory.length-1);redrawAnnot();}}\u001b[39m\n\u001b[31mfunction clearAnnot(){_aHistory=[];_aSel=-1;redrawAnnot();}·\u001b[39m\n\u001b[31m// Bottom dialog\u001b[39m\n\u001b[31mlet _bdCb=null;\u001b[39m\n\u001b[31mfunction showBDialog(title,sub,onYes){\u001b[39m\n\u001b[31m  document.getElementById('bdialog-title').textContent=title;\u001b[39m\n\u001b[31m  document.getElementById('bdialog-sub').textContent=sub;\u001b[39m\n\u001b[31m  _bdCb=onYes;document.getElementById('bdialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction bdialogYes(){document.getElementById('bdialog').classList.remove('open');if(_bdCb)_bdCb();_bdCb=null;}\u001b[39m\n\u001b[31mfunction bdialogNo(){document.getElementById('bdialog').classList.remove('open');_bdCb=null;}·\u001b[39m\n\u001b[31mfunction _afterBrandingPhoto(){\u001b[39m\n\u001b[31m  const idx=_aTarget;\u001b[39m\n\u001b[31m  showBDialog(t(`Add reference photos for Branding ${idx+1}?`,`ब्रांडिंग ${idx+1} के लिए अतिरिक्त फोटो?`),t('Optional extra photos for future reference.','वैकल्पिक — भविष्य के लिए अतिरिक्त फोटो।'),()=>{showView('form-additional');setTimeout(()=>addAdditional(),200);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction skipAnnot(){document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo added (${fmtSz(brandings[_aTarget].blob.size)})`,'success');_afterBrandingPhoto();}\u001b[39m\n\u001b[31mfunction saveAnnot(){const cvs=document.getElementById('annot-cvs');cvs.toBlob(blob=>{brandings[_aTarget].blob=blob;brandings[_aTarget].prev=URL.createObjectURL(blob);document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo + markup saved (${fmtSz(blob.size)})`,'success');_afterBrandingPhoto();},'image/jpeg',0.88);}·\u001b[39m\n\u001b[31m// ── VIEW RECCE (read-only) ──────────────────────────────────\u001b[39m\n\u001b[31masync function viewRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  // Synced entries have a server-side rich report — open it directly\u001b[39m\n\u001b[31m  if(entry.viewUrl){window.open(entry.viewUrl,'_blank');return;}\u001b[39m\n\u001b[31m  // Offline / not-yet-synced fallback: generate from local base64 data\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  const ts=new Date(entry.timestamp).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'});·\u001b[39m\n\u001b[31m  async function b64ToUrl(b64){if(!b64)return'';try{const r=await fetch(b64);const bl=await r.blob();return URL.createObjectURL(bl);}catch{return'';}}·\u001b[39m\n\u001b[31m  const fvUrls=await Promise.all((d.frontPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const ivUrls=await Promise.all((d.insidePhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const brUrls=await Promise.all((d.brandings||[]).map(b=>b64ToUrl(b.photoB64)));\u001b[39m\n\u001b[31m  const adUrls=await Promise.all((d.addlPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const docUrl=await b64ToUrl(d.docB64);·\u001b[39m\n\u001b[31m  const brRows=(d.brandings||[]).map((b,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:16px;padding:12px;background:#f8fafc;border-radius:8px;border-left:3px solid #f97316\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-weight:600;font-size:14px;color:#0f172a;margin-bottom:6px\\\">${i+1}. ${b.type||'—'}: ${b.w||'?'}\\\"×${b.h||'?'}\\\" · Qty: ${b.qty||'?'} · ${b.sqft||'?'}</div>\u001b[39m\n\u001b[31m      ${brUrls[i]?`<img src=\\\"${brUrls[i]}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:6px\\\">`:'<div style=\\\"color:#94a3b8;font-size:12px\\\">No photo</div>'}\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  const html=`<!DOCTYPE html><html><head><meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m  <title>Recce — ${d.storeName||'Unknown'}</title>\u001b[39m\n\u001b[31m  <style>body{font-family:Arial,sans-serif;margin:0;padding:16px;background:#f1f5f9}\u001b[39m\n\u001b[31m  .card{background:#fff;border-radius:12px;padding:16px;margin-bottom:14px;box-shadow:0 1px 4px rgba(0,0,0,.08)}\u001b[39m\n\u001b[31m  h1{font-size:18px;color:#0f172a;margin:0 0 4px}h2{font-size:14px;color:#f97316;text-transform:uppercase;letter-spacing:.5px;margin:0 0 10px}\u001b[39m\n\u001b[31m  .meta{font-size:12px;color:#64748b;margin-bottom:12px}.photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}\u001b[39m\n\u001b[31m  img{width:100%;border-radius:8px;object-fit:cover}\u001b[39m\n\u001b[31m  .tag{display:inline-block;background:#0f172a;color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-right:4px}\u001b[39m\n\u001b[31m  @media print{body{background:#fff}.card{box-shadow:none}}</style></head><body>\u001b[39m\n\u001b[31m  <div class=\\\"card\\\">\u001b[39m\n\u001b[31m    <h1>${d.storeName||'Unknown Store'}</h1>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\"><span class=\\\"tag\\\">${d.brand||'No Brand'}</span>${d.address||''}</div>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\">📞 ${d.mobile||'—'} &nbsp;|&nbsp; 📅 ${d.date||'—'} &nbsp;|&nbsp; Submitted: ${ts}</div>\u001b[39m\n\u001b[31m    ${d.gpsCoords?`<div class=\\\"meta\\\">📍 ${d.gpsCoords.lat}, ${d.gpsCoords.lng} ±${d.gpsCoords.acc}m</div>`:''}\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${fvUrls.length?`<div class=\\\"card\\\"><h2>Front View Photos</h2><div class=\\\"photos\\\">${fvUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${ivUrls.length?`<div class=\\\"card\\\"><h2>Inside View Photos</h2><div class=\\\"photos\\\">${ivUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${d.hasVideo?`<div class=\\\"card\\\"><h2>Video</h2><div>${d.videoNote||'Video recorded'}</div></div>`:''}\u001b[39m\n\u001b[31m  ${(d.brandings||[]).length?`<div class=\\\"card\\\"><h2>Branding Items (${(d.brandings||[]).length})</h2>${brRows}</div>`:''}\u001b[39m\n\u001b[31m  ${adUrls.length?`<div class=\\\"card\\\"><h2>Additional Photos</h2><div class=\\\"photos\\\">${adUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${docUrl?`<div class=\\\"card\\\"><h2>Submission Document</h2><img src=\\\"${docUrl}\\\" style=\\\"width:100%;max-height:300px;object-fit:contain\\\"></div>`:''}\u001b[39m\n\u001b[31m  <div style=\\\"text-align:center;margin:16px 0\\\">\u001b[39m\n\u001b[31m    <button onclick=\\\"window.print()\\\" style=\\\"background:#f97316;color:#fff;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer\\\">🖨 Print / Save as PDF</button>\u001b[39m\n\u001b[31m    <button onclick=\\\"window.close()\\\" style=\\\"background:#e2e8f0;color:#475569;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer;margin-left:10px\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  </body></html>`;\u001b[39m\n\u001b[31m  const blob=new Blob([html],{type:'text/html'});\u001b[39m\n\u001b[31m  const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m  window.open(url,'_blank');\u001b[39m\n\u001b[31m  setTimeout(()=>URL.revokeObjectURL(url),30000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── EDIT OLD RECCE ───────────────────────────────────────────\u001b[39m\n\u001b[31masync function editRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=d.gpsCoords||null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  F.editingId=id;F.date=d.date||'';F.brand=d.brand||'';F.storeName=d.storeName||'';F.address=d.address||'';F.mobile=d.mobile||'';F.hasVideo=d.hasVideo;F.hasBranding=d.hasBranding;\u001b[39m\n\u001b[31m  async function b64ToBlob(b64){if(!b64)return null;try{const r=await fetch(b64);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m  toast('Loading recce data…','info');\u001b[39m\n\u001b[31m  for(const p of(d.frontPhotos||[])){const b=await b64ToBlob(p.b64);if(b)frontPhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const p of(d.insidePhotos||[])){const b=await b64ToBlob(p.b64);if(b)insidePhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const br of(d.brandings||[])){const b=await b64ToBlob(br.photoB64);brandings.push({type:br.type,w:br.w,h:br.h,qty:br.qty,blob:b,prev:b?URL.createObjectURL(b):null});}\u001b[39m\n\u001b[31m  for(const p of(d.addlPhotos||[])){const b=await b64ToBlob(p.b64);if(b)addlPhotos.push({blob:b,prev:URL.createObjectURL(b),desc:p.desc||''});}\u001b[39m\n\u001b[31m  if(d.docB64){const b=await b64ToBlob(d.docB64);if(b){submissionDoc=b;const sl=document.getElementById('doc-slot');sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${URL.createObjectURL(b)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}}\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  if(F.brand)document.getElementById('f-brand').value=F.brand;\u001b[39m\n\u001b[31m  if(F.storeName)document.getElementById('f-store').value=F.storeName;\u001b[39m\n\u001b[31m  if(F.address)document.getElementById('f-addr').value=F.address;\u001b[39m\n\u001b[31m  if(F.mobile)document.getElementById('f-mobile').value=F.mobile;\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();updAvailTag();\u001b[39m\n\u001b[31m  toast('Recce loaded — make changes and re-submit','success');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── EDIT REQUEST ────────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mlet _editReqSubId = null;·\u001b[39m\n\u001b[31mfunction _hydratePhotosFromRow(r) {\u001b[39m\n\u001b[31m  let pu={};\u001b[39m\n\u001b[31m  try{pu=typeof r.photo_urls==='string'?JSON.parse(r.photo_urls):(r.photo_urls||{});}catch(_){}\u001b[39m\n\u001b[31m  let meta={};\u001b[39m\n\u001b[31m  try{meta=typeof r.meta==='string'?JSON.parse(r.meta):(r.meta||{});}catch(_){}\u001b[39m\n\u001b[31m  frontPhotos =(pu.front   ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  insidePhotos=(pu.inside  ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  addlPhotos  =(pu.addl    ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,desc:''}));\u001b[39m\n\u001b[31m  brandings   =(meta.brandings||[]).map((b,i)=>({type:b.type,w:b.w,h:b.h,qty:b.qty,existingUrl:(pu.brandings||[])[i]||null,blob:null,prev:(pu.brandings||[])[i]||null}));\u001b[39m\n\u001b[31m  _docExistingUrl=pu.doc||null;\u001b[39m\n\u001b[31m  // Show retained doc in slot\u001b[39m\n\u001b[31m  const sl=document.getElementById('doc-slot');\u001b[39m\n\u001b[31m  if(sl&&_docExistingUrl){sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${_docExistingUrl}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openEditRequestModal(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  _editReqSubId = subId;\u001b[39m\n\u001b[31m  document.getElementById('er-store-name').textContent = r.store_name || 'Unknown';\u001b[39m\n\u001b[31m  document.getElementById('er-comment').value = '';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const assignBtn = document.getElementById('er-assign-btn');\u001b[39m\n\u001b[31m  if (r.submitted_by && r.submitted_by !== hub?.empId) {\u001b[39m\n\u001b[31m    assignBtn.textContent = `👤 Assign to ${r.submitted_by}`;\u001b[39m\n\u001b[31m    assignBtn.style.display = '';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    assignBtn.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeEditRequestModal() {\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _editReqSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorEditMyself() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  // Lock branding if client has reviewed (preserve their approval)\u001b[39m\n\u001b[31m  _brandingLocked = !!(r.client_status && r.client_status !== 'pending');\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function assignEditToCreator() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r || !r.submitted_by) { toast('No creator found for this recce', 'error'); return; }\u001b[39m\n\u001b[31m  const comment = (document.getElementById('er-comment').value || '').trim();\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        status: 'edit_requested',\u001b[39m\n\u001b[31m        edit_assigned_to: r.submitted_by,\u001b[39m\n\u001b[31m        edit_comment: comment || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!resp.ok) throw new Error('Update failed: ' + resp.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].status = 'edit_requested';\u001b[39m\n\u001b[31m      _adminRows[idx].edit_assigned_to = r.submitted_by;\u001b[39m\n\u001b[31m      _adminRows[idx].edit_comment = comment || null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Push notification to creator\u001b[39m\n\u001b[31m    const notifBody = comment || `Please review and re-submit: ${r.store_name || 'your recce'}`;\u001b[39m\n\u001b[31m    fetch('/push-server/notify', {\u001b[39m\n\u001b[31m      method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        user_id: r.submitted_by, title: '✏ Edit Requested',\u001b[39m\n\u001b[31m        body: notifBody, tag: `recce-edit-${subId}`, url: '/recce/',\u001b[39m\n\u001b[31m        icon: '/hub/icons/icon-192.png', badge: '/hub/icons/icon-192.png',\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    }).catch(() => {});\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast(`Edit assigned to ${r.submitted_by} ✓`, 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Assign failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function startCreatorEdit(subId) {\u001b[39m\n\u001b[31m  // Try local IndexedDB first (has photos)\u001b[39m\n\u001b[31m  const local = await dbGet('subs', subId);\u001b[39m\n\u001b[31m  if (local) { await editRecce(subId); return; }\u001b[39m\n\u001b[31m  // Fallback: load text fields from server row\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId)\u001b[39m\n\u001b[31m         || (await (async () => {\u001b[39m\n\u001b[31m              try {\u001b[39m\n\u001b[31m                const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, { headers: _RC_READ });\u001b[39m\n\u001b[31m                if (resp.ok) { const arr = await resp.json(); return arr[0]; }\u001b[39m\n\u001b[31m              } catch(_) {} return null;\u001b[39m\n\u001b[31m            })());\u001b[39m\n\u001b[31m  if (!r) { toast('Record not found', 'error'); return; }\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── End edit request ─────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mfunction goToHub() { window.location.href = '/hub/'; }\u001b[39m\n\u001b[31mfunction recceLogout() {\u001b[39m\n\u001b[31m  if (!confirm('Log out?')) return;\u001b[39m\n\u001b[31m  localStorage.removeItem('lm360-session');\u001b[39m\n\u001b[31m  localStorage.removeItem('360exp-session');\u001b[39m\n\u001b[31m  window.location.href = '/hub/';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction injectHubButtons() {\u001b[39m\n\u001b[31m  const u = _recceHubUser();\u001b[39m\n\u001b[31m  const name = u ? (u.name || '') : '';\u001b[39m\n\u001b[31m  if (name) {\u001b[39m\n\u001b[31m    const bar = document.getElementById('recce-hero-ubar');\u001b[39m\n\u001b[31m    const nm  = document.getElementById('recce-hero-name');\u001b[39m\n\u001b[31m    if (bar) { nm.textContent = name; bar.style.display = 'flex'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.querySelectorAll('.hdr').forEach(hdr => {\u001b[39m\n\u001b[31m    const r = document.createElement('div');\u001b[39m\n\u001b[31m    r.className = 'hdr-r';\u001b[39m\n\u001b[31m    if (name) {\u001b[39m\n\u001b[31m      const un = document.createElement('span');\u001b[39m\n\u001b[31m      un.className = 'hdr-user';\u001b[39m\n\u001b[31m      un.textContent = name;\u001b[39m\n\u001b[31m      r.appendChild(un);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    const hub = document.createElement('button');\u001b[39m\n\u001b[31m    hub.className = 'btn-hub';\u001b[39m\n\u001b[31m    hub.innerHTML = '🏡 Hub';\u001b[39m\n\u001b[31m    hub.addEventListener('click', goToHub);\u001b[39m\n\u001b[31m    r.appendChild(hub);\u001b[39m\n\u001b[31m    const lo = document.createElement('button');\u001b[39m\n\u001b[31m    lo.className = 'btn-logout';\u001b[39m\n\u001b[31m    lo.textContent = 'Logout';\u001b[39m\n\u001b[31m    lo.addEventListener('click', recceLogout);\u001b[39m\n\u001b[31m    r.appendChild(lo);\u001b[39m\n\u001b[31m    hdr.appendChild(r);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction checkAppUpdate(){\u001b[39m\n\u001b[31m  const seen=localStorage.getItem('recce-ver-seen');\u001b[39m\n\u001b[31m  localStorage.setItem('recce-ver-seen',CACHE_VER);\u001b[39m\n\u001b[31m  if(seen&&seen!==CACHE_VER){\u001b[39m\n\u001b[31m    const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m    if(b){b.classList.add('show');setTimeout(()=>b.classList.remove('show'),5000);}\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction dismissUpdateBanner(){\u001b[39m\n\u001b[31m  const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m  if(b)b.classList.remove('show');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function init(){\u001b[39m\n\u001b[31m  // Detect host banners (tiiny.host, etc) and raise bnav above them\u001b[39m\n\u001b[31m  (function detectHostBar(){\u001b[39m\n\u001b[31m    const h=window.location.hostname;\u001b[39m\n\u001b[31m    let extra=0;\u001b[39m\n\u001b[31m    if(h.includes('tiiny'))extra=58;\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // Generic detection: check if window is shorter than expected (host injected a bar)\u001b[39m\n\u001b[31m      const gap=screen.height - window.innerHeight;\u001b[39m\n\u001b[31m      if(gap>100&&gap<200)extra=58; // a fixed bar is roughly 56-60px\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if(extra>0){\u001b[39m\n\u001b[31m      document.documentElement.style.setProperty('--host-bar',extra+'px');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  })();\u001b[39m\n\u001b[31m  setLang(LANG);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m  checkAppUpdate();\u001b[39m\n\u001b[31m  await loadRecceCfg();\u001b[39m\n\u001b[31m  _checkAccessMode();\u001b[39m\n\u001b[31m  await initDB();await loadSettings();await loadHome();await checkDraft();netStatus();window.addEventListener('online',()=>{netStatus();syncNow();});window.addEventListener('offline',netStatus);injectHubButtons();document.getElementById('today-date').textContent=new Date().toLocaleDateString('en-IN',{weekday:'long',day:'numeric',month:'long',year:'numeric'});updAvailTag();\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m  // Auto-fetch stores from server on every startup (uses default Netlify URL if none saved)\u001b[39m\n\u001b[31m  const su=(await cfg('srv-url'))||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su&&navigator.onLine){\u001b[39m\n\u001b[31m    fetch(su).then(r=>r.json()).then(async j=>{\u001b[39m\n\u001b[31m      const d=Array.isArray(j)?j:j.stores||[];\u001b[39m\n\u001b[31m      if(d.length){stores=d;await cfg('stores',JSON.stringify(d));await cfg('srv-url',su);updAvailTag();\u001b[39m\n\u001b[31m        document.getElementById('srv-url').value=su;}\u001b[39m\n\u001b[31m    }).catch(()=>{});\u001b[39m\n\u001b[31m  }}init();\u001b[39m\n\u001b[31m</script>\u001b[39m\n\u001b[31m</body>\u001b[39m\n\u001b[31m</html>\u001b[39m\n\u001b[31m\"\u001b[39m\n    at /var/www/360lm/tests/recce.spec.js:337:17",
                        "location": {
                          "file": "/var/www/360lm/tests/recce.spec.js",
                          "column": 17,
                          "line": 337
                        },
                        "snippet": "  335 |     const resp = await page.request.get(BASE_URL);\n  336 |     const src = await resp.text();\n> 337 |     expect(src).toContain('recce-v15');\n      |                 ^\n  338 |     expect(src).not.toContain('recce-v14');\n  339 |   });\n  340 | });"
                      },
                      "errors": [
                        {
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "column": 17,
                            "line": 337
                          },
                          "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoContain\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // indexOf\u001b[22m\n\nExpected substring: \u001b[32m\"recce-v15\"\u001b[39m\nReceived string:    \u001b[31m\"<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\">\u001b[39m\n\u001b[31m<head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\">\u001b[39m\n\u001b[31m<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\\\">\u001b[39m\n\u001b[31m<meta name=\\\"theme-color\\\" content=\\\"#0f172a\\\">\u001b[39m\n\u001b[31m<meta name=\\\"apple-mobile-web-app-capable\\\" content=\\\"yes\\\">\u001b[39m\n\u001b[31m<title>Branding Recce</title>\u001b[39m\n\u001b[31m<link rel=\\\"manifest\\\" href=\\\"manifest.json\\\">\u001b[39m\n\u001b[31m<link rel=\\\"preconnect\\\" href=\\\"https://fonts.googleapis.com\\\">\u001b[39m\n\u001b[31m<link href=\\\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap\\\" rel=\\\"stylesheet\\\">\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--nv:#0f172a;--nv2:#1e293b;--or:#f97316;--orl:#fed7aa;--gn:#16a34a;--rd:#dc2626;--am:#d97706;--g50:#f8fafc;--g100:#f1f5f9;--g200:#e2e8f0;--g300:#cbd5e1;--g400:#94a3b8;--g500:#64748b;--g600:#475569;--r:12px;--rs:8px;--sh:0 1px 3px rgba(0,0,0,.1),0 1px 2px rgba(0,0,0,.06);--bnav-h:72px;--host-bar:0px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}\u001b[39m\n\u001b[31mbody{font-family:'DM Sans',sans-serif;background:var(--g50);color:var(--nv);min-height:100vh;overflow-x:hidden}\u001b[39m\n\u001b[31m.hdr{background:var(--nv);color:#fff;padding:0 16px;height:56px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}\u001b[39m\n\u001b[31m.hdr-l{display:flex;align-items:center;gap:10px}\u001b[39m\n\u001b[31m.hdr-title{font-size:16px;font-weight:600}.hdr-sub{font-size:11px;color:var(--g400)}\u001b[39m\n\u001b[31m.back-btn,.icon-btn{background:none;border:none;color:#fff;padding:8px;cursor:pointer;display:flex;align-items:center}\u001b[39m\n\u001b[31m.back-btn{margin-left:-8px}\u001b[39m\n\u001b[31m.pgbar{height:3px;background:var(--g200)}.pgfill{height:100%;background:var(--or);transition:width .3s}\u001b[39m\n\u001b[31m.view{display:none;min-height:calc(100vh - 56px);padding-bottom:calc(var(--bnav-h) + var(--host-bar) + 24px)}.view.active{display:block}\u001b[39m\n\u001b[31m.content{padding:16px}\u001b[39m\n\u001b[31m.card{background:#fff;border-radius:var(--r);padding:16px;box-shadow:var(--sh);margin-bottom:12px}\u001b[39m\n\u001b[31m.card-title{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;letter-spacing:.6px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between}\u001b[39m\n\u001b[31m.cnt-badge{background:var(--or);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;min-width:22px;text-align:center}\u001b[39m\n\u001b[31m.cnt-badge.gray{background:var(--g400)}\u001b[39m\n\u001b[31m.field{margin-bottom:16px}.field:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.field label{display:block;font-size:13px;font-weight:500;color:var(--g600);margin-bottom:6px}\u001b[39m\n\u001b[31m.req{color:var(--or);margin-left:2px}\u001b[39m\n\u001b[31m.field input,.field select,.field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;color:var(--nv);background:#fff;transition:border-color .15s;-webkit-appearance:none;appearance:none}\u001b[39m\n\u001b[31m.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--or)}\u001b[39m\n\u001b[31m.field input:read-only{background:var(--g50);color:var(--g600)}\u001b[39m\n\u001b[31m.field textarea{resize:vertical;min-height:68px}\u001b[39m\n\u001b[31m.field select{background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}\u001b[39m\n\u001b[31m.pslot{border:2px dashed var(--g300);border-radius:var(--r);min-height:110px;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all .15s;position:relative;overflow:hidden;text-align:center;padding:16px}\u001b[39m\n\u001b[31m.pslot:active{border-color:var(--or);background:var(--g50)}\u001b[39m\n\u001b[31m.pslot.filled{border-style:solid;border-color:var(--or);padding:0;min-height:0}\u001b[39m\n\u001b[31m.pslot img{width:100%;height:150px;object-fit:cover;border-radius:calc(var(--r) - 2px);display:block}\u001b[39m\n\u001b[31m.pslot-lbl{font-size:13px;color:var(--g400);margin-top:6px}.pslot-ico{font-size:28px;color:var(--g300)}\u001b[39m\n\u001b[31m.pbadge{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.premove{position:absolute;top:6px;right:6px;background:var(--rd);color:#fff;border:none;border-radius:50%;width:26px;height:26px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;z-index:5}\u001b[39m\n\u001b[31minput[type=file]{display:none}\u001b[39m\n\u001b[31m.rgroup{display:flex;gap:10px}\u001b[39m\n\u001b[31m.rbtn{flex:1;padding:13px;border:1.5px solid var(--g200);border-radius:var(--rs);text-align:center;cursor:pointer;font-size:14px;font-weight:500;color:var(--g500);transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.rbtn.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.chip-grid{display:flex;flex-wrap:wrap;gap:8px}\u001b[39m\n\u001b[31m.chip{padding:7px 12px;border:1.5px solid var(--g200);border-radius:20px;font-size:13px;color:var(--g600);cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.chip.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.brand-chip{display:flex;align-items:center;gap:6px;padding:5px 12px}\u001b[39m\n\u001b[31m.brand-chip-logo{width:28px;height:18px;object-fit:contain;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{display:block;width:100%;padding:15px;background:var(--or);color:#fff;border:none;border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:700;cursor:pointer;text-align:center;transition:background .15s}\u001b[39m\n\u001b[31m.btn-p:active{background:#ea6c05}.btn-p:disabled{background:var(--g300);cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-s{display:block;width:100%;padding:14px;background:#fff;color:var(--nv);border:1.5px solid var(--g200);border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:500;cursor:pointer;text-align:center}\u001b[39m\n\u001b[31m.btn-s:active{background:var(--g100)}\u001b[39m\n\u001b[31m.btn-o{display:inline-flex;align-items:center;gap:6px;padding:10px 16px;background:#fff;color:var(--or);border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer}\u001b[39m\n\u001b[31m.btn-o:active{background:var(--orl)}\u001b[39m\n\u001b[31m.btn-d{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;background:#fff;color:var(--rd);border:1.5px solid #fecaca;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:12px;cursor:pointer}\u001b[39m\n\u001b[31m.bnav{position:fixed;bottom:var(--host-bar);left:0;right:0;background:#fff;border-top:1px solid var(--g200);display:flex;padding:10px 16px;gap:10px;z-index:100}\u001b[39m\n\u001b[31m.hero{background:var(--nv);color:#fff;padding:20px 16px 24px}\u001b[39m\n\u001b[31m.hero-title{font-size:22px;font-weight:700;margin-bottom:2px}.hero-sub{font-size:13px;color:var(--g400)}\u001b[39m\n\u001b[31m.stats{display:flex;gap:10px;margin-top:16px}\u001b[39m\n\u001b[31m.scard{flex:1;background:rgba(255,255,255,.08);border-radius:var(--rs);padding:12px;text-align:center}\u001b[39m\n\u001b[31m.snum{font-size:22px;font-weight:700}.slbl{font-size:11px;color:var(--g400);margin-top:2px}\u001b[39m\n\u001b[31m.scard.g .snum{color:#4ade80}.scard.a .snum{color:#fbbf24}\u001b[39m\n\u001b[31m.new-btn{background:var(--or);color:#fff;border:none;border-radius:var(--r);padding:16px;font-family:'DM Sans',sans-serif;font-size:16px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:10px;cursor:pointer;width:100%;margin-bottom:10px}\u001b[39m\n\u001b[31m.new-btn:active{background:#ea6c05}\u001b[39m\n\u001b[31m.resume-btn{background:var(--nv2);color:#fff;border:none;border-radius:var(--r);padding:13px 16px;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;display:flex;align-items:center;justify-content:space-between;cursor:pointer;width:100%;margin-bottom:18px}\u001b[39m\n\u001b[31m.sub-card{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:10px;display:flex;align-items:center;gap:12px}\u001b[39m\n\u001b[31m.sub-ico{width:40px;height:40px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}\u001b[39m\n\u001b[31m.sub-ico.pending{background:#fef3c7}.sub-ico.synced{background:#dcfce7}.sub-ico.failed{background:#fee2e2}\u001b[39m\n\u001b[31m.sub-meta{flex:1;min-width:0}.sub-name{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.sub-dtl{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.sbadge{font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;flex-shrink:0}\u001b[39m\n\u001b[31m.sbadge.pending{background:#fef3c7;color:#92400e}.sbadge.synced{background:#dcfce7;color:#14532d}.sbadge.failed{background:#fee2e2;color:#991b1b}\u001b[39m\n\u001b[31m.sh{display:flex;align-items:center;justify-content:space-between;margin:20px 0 12px}\u001b[39m\n\u001b[31m.st{font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.toast{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 8px);left:16px;right:16px;background:var(--nv);color:#fff;padding:12px 16px;border-radius:var(--r);font-size:14px;z-index:1000;transform:translateY(120px);opacity:0;transition:all .3s;pointer-events:none}\u001b[39m\n\u001b[31m.toast.show{transform:translateY(0);opacity:1}.toast.success{background:#16a34a}.toast.error{background:var(--rd)}.toast.info{background:var(--nv2)}\u001b[39m\n\u001b[31m.srow{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:#fff;border-top:1px solid var(--g100);font-size:12px;color:var(--g500)}\u001b[39m\n\u001b[31m.sdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px}.sdot.on{background:var(--gn)}.sdot.off{background:var(--g300)}\u001b[39m\n\u001b[31m.set-item{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:8px}\u001b[39m\n\u001b[31m.set-lbl{font-size:14px;font-weight:600;color:var(--nv);margin-bottom:4px}\u001b[39m\n\u001b[31m.set-sub{font-size:12px;color:var(--g500);margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem{background:#fff;border-radius:var(--r);border:1.5px solid var(--g200);padding:14px;margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\u001b[39m\n\u001b[31m.bitem-title{font-size:14px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.dim-row{display:flex;gap:8px}.dim-row .field{flex:1}\u001b[39m\n\u001b[31m.sqft{display:inline-block;background:var(--g100);color:var(--g600);font-size:12px;padding:4px 10px;border-radius:20px;margin-top:6px}\u001b[39m\n\u001b[31m.divider{height:1px;background:var(--g100);margin:12px 0}\u001b[39m\n\u001b[31m.rev-lbl{font-size:12px;color:var(--g500);margin-bottom:2px}\u001b[39m\n\u001b[31m.rev-val{font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.rev-photos{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}\u001b[39m\n\u001b[31m.rev-thumb{width:56px;height:56px;object-fit:cover;border-radius:var(--rs)}\u001b[39m\n\u001b[31m.empty{text-align:center;padding:40px 20px;color:var(--g400)}.empty-ico{font-size:40px;margin-bottom:12px}.empty-txt{font-size:14px}\u001b[39m\n\u001b[31m/* store picker */\u001b[39m\n\u001b[31m.store-card{border:1.5px solid var(--g200);border-radius:var(--rs);padding:13px 14px;background:#fff;position:relative;cursor:pointer}\u001b[39m\n\u001b[31m.store-card:active{background:var(--g50)}\u001b[39m\n\u001b[31m.store-card-name{font-size:15px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.store-card-meta{font-size:13px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.store-card-change{position:absolute;top:11px;right:12px;background:none;border:none;color:var(--or);font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer}\u001b[39m\n\u001b[31m.brand-tag{display:inline-block;background:var(--nv);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-top:4px}\u001b[39m\n\u001b[31m.last-chip{display:inline-flex;align-items:center;gap:4px;background:#fef3c7;color:#92400e;font-size:11px;font-weight:500;padding:3px 9px;border-radius:20px;margin-left:6px}\u001b[39m\n\u001b[31m.pick-trigger{border:2px solid var(--or);border-radius:var(--rs);padding:14px 16px;background:#fff7ed;display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-size:15px;font-weight:600;color:var(--or)}\u001b[39m\n\u001b[31m.pick-trigger:active{background:#ffedd5;border-color:#ea6800}\u001b[39m\n\u001b[31m.manual-toggle{display:flex;align-items:center;gap:8px;padding:10px 14px;border:1.5px dashed var(--g300);border-radius:var(--rs);cursor:pointer;font-size:13px;color:var(--g600);margin-top:8px;user-select:none}\u001b[39m\n\u001b[31m/* client chip grid */\u001b[39m\n\u001b[31m.cl-chip-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}\u001b[39m\n\u001b[31m.cl-chip{padding:8px 14px;border-radius:20px;border:1.5px solid var(--g200);font-size:13px;font-weight:500;color:var(--g600);background:#fff;cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.cl-chip:active,.cl-chip.sel{background:var(--or);border-color:var(--or);color:#fff;font-weight:600}\u001b[39m\n\u001b[31m.cl-chip-other{border-style:dashed}\u001b[39m\n\u001b[31m.client-tag{display:inline-block;background:#e0f2fe;color:#0369a1;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-left:4px}\u001b[39m\n\u001b[31m.manual-toggle.on{border-color:var(--or);background:#fff7ed;color:var(--or)}\u001b[39m\n\u001b[31m/* picker overlay */\u001b[39m\n\u001b[31m.povl{display:none;position:fixed;inset:0;background:var(--g50);z-index:200;flex-direction:column}\u001b[39m\n\u001b[31m.povl.open{display:flex}\u001b[39m\n\u001b[31m.povl-hdr{background:var(--nv);padding:12px 16px;display:flex;align-items:center;gap:12px;flex-shrink:0}\u001b[39m\n\u001b[31m.psearch{flex:1;padding:10px 14px;border:none;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;background:rgba(255,255,255,.12);color:#fff;outline:none}\u001b[39m\n\u001b[31m.psearch::placeholder{color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.pcancel{background:none;border:none;color:rgba(255,255,255,.7);font-family:'DM Sans',sans-serif;font-size:14px;cursor:pointer;padding:4px;white-space:nowrap}\u001b[39m\n\u001b[31m.plist{overflow-y:auto;flex:1}\u001b[39m\n\u001b[31m.pitem{padding:14px 16px;border-bottom:.5px solid var(--g100);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px}\u001b[39m\n\u001b[31m.pitem:active{background:var(--g100)}\u001b[39m\n\u001b[31m.pi-name{font-size:15px;font-weight:600;color:var(--nv)}.pi-addr{font-size:12px;color:var(--g500);margin-top:2px}.pi-last{font-size:11px;color:var(--am);margin-top:2px}\u001b[39m\n\u001b[31m.pi-brand{font-size:11px;font-weight:700;padding:3px 8px;border-radius:20px;background:var(--nv);color:#fff;flex-shrink:0}\u001b[39m\n\u001b[31m.psec{padding:8px 16px 4px;font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;background:var(--g50)}\u001b[39m\n\u001b[31m.padd{padding:16px;text-align:center;font-size:14px;color:var(--or);font-weight:600;cursor:pointer;background:#fff7ed;border-top:1.5px dashed var(--or)}\u001b[39m\n\u001b[31m.gps-row{display:flex;gap:8px;margin-top:8px}\u001b[39m\n\u001b[31m.gps-btn{flex-shrink:0;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;color:var(--g500);display:flex;align-items:center;gap:6px}\u001b[39m\n\u001b[31m.gps-btn:active{background:var(--orl);border-color:var(--or);color:var(--or)}\u001b[39m\n\u001b[31m@keyframes spin{to{transform:rotate(360deg)}}.spin{animation:spin .7s linear infinite;display:inline-block}\u001b[39m\n\u001b[31m/* ANNOTATION TOOL */\u001b[39m\n\u001b[31m.annot-modal{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column}\u001b[39m\n\u001b[31m.annot-modal.open{display:flex}\u001b[39m\n\u001b[31m.annot-bar{background:var(--nv);padding:8px 12px;flex-shrink:0}\u001b[39m\n\u001b[31m.annot-row{display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap}\u001b[39m\n\u001b[31m.annot-row:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.atool{padding:6px 10px;background:rgba(255,255,255,.1);border:1.5px solid rgba(255,255,255,.2);border-radius:var(--rs);color:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:500;cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.atool.on{background:var(--or);border-color:var(--or)}\u001b[39m\n\u001b[31m.atool.sel-on{background:#7c3aed;border-color:#7c3aed}\u001b[39m\n\u001b[31m.acolor{width:24px;height:24px;border-radius:50%;border:2px solid rgba(255,255,255,.3);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.acolor.on{border-color:#fff;border-width:3px;transform:scale(1.15)}\u001b[39m\n\u001b[31m.annot-cvs-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#111;position:relative}\u001b[39m\n\u001b[31m#annot-cvs{max-width:100%;max-height:100%;display:block;touch-action:none;cursor:crosshair}\u001b[39m\n\u001b[31m.annot-foot{background:var(--nv);padding:10px 16px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.req-note{font-size:12px;color:var(--rd);margin-top:6px;font-weight:500}\u001b[39m\n\u001b[31m/* Bottom dialog */\u001b[39m\n\u001b[31m.bdialog-wrap{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:400;align-items:flex-end}\u001b[39m\n\u001b[31m.bdialog-wrap.open{display:flex}\u001b[39m\n\u001b[31m.bdialog{background:#fff;border-radius:var(--r) var(--r) 0 0;padding:20px 16px 32px;width:100%}\u001b[39m\n\u001b[31m.bdialog-title{font-size:16px;font-weight:700;color:var(--nv);margin-bottom:6px}\u001b[39m\n\u001b[31m.bdialog-sub{font-size:13px;color:var(--g500);margin-bottom:16px}\u001b[39m\n\u001b[31m.bdialog-btns{display:flex;gap:10px}\u001b[39m\n\u001b[31m/* Edit badge on sub-card */\u001b[39m\n\u001b[31m.edit-btn-sm{padding:5px 12px;background:var(--g50);border:1px solid var(--g200);border-radius:20px;font-family:'DM Sans',sans-serif;font-size:12px;color:var(--g600);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m/* Toggle switch */\u001b[39m\n\u001b[31m.tog{width:48px;height:26px;background:var(--g300);border-radius:13px;cursor:pointer;transition:background .2s;flex-shrink:0;position:relative;display:inline-block}\u001b[39m\n\u001b[31m.tog.on{background:var(--or)}\u001b[39m\n\u001b[31m.tog-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2);pointer-events:none}\u001b[39m\n\u001b[31m.tog.on .tog-knob{transform:translateX(22px)}\u001b[39m\n\u001b[31m/* ── ADMIN RECCE VIEW ── */\u001b[39m\n\u001b[31m.af-bar{background:var(--g100);padding:10px 16px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--g200);overflow:hidden}\u001b[39m\n\u001b[31m.af-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}\u001b[39m\n\u001b[31m.af-sel{width:100%;padding:8px 10px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv);cursor:pointer;\u001b[39m\n\u001b[31m  white-space:normal;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.af-sel:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.af-inp{width:100%;padding:8px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv)}\u001b[39m\n\u001b[31m.af-inp:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.grp-hdr{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;\u001b[39m\n\u001b[31m  letter-spacing:.5px;padding:14px 0 6px;border-bottom:1px solid var(--g200);margin-bottom:6px}\u001b[39m\n\u001b[31m.grp-hdr:first-child{padding-top:0}\u001b[39m\n\u001b[31m.asc{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:12px 14px;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;gap:6px;margin-bottom:8px;cursor:pointer;\u001b[39m\n\u001b[31m  transition:box-shadow .15s}\u001b[39m\n\u001b[31m.asc:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.asc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}\u001b[39m\n\u001b[31m.asc-name{font-size:14px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.asc-brand{display:inline-block;background:#fff7ed;color:var(--or);font-size:11px;\u001b[39m\n\u001b[31m  font-weight:600;padding:2px 8px;border-radius:20px;border:1px solid #fed7aa;white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chip{background:var(--g100);border-radius:20px;padding:2px 8px;font-size:11px;color:var(--g600);white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chips{display:flex;flex-wrap:wrap;gap:5px}\u001b[39m\n\u001b[31m.asc-agent{background:var(--nv);color:#fff;font-size:11px;font-weight:600;\u001b[39m\n\u001b[31m  padding:2px 8px;border-radius:20px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m/* Admin detail modal */\u001b[39m\n\u001b[31m.ardl-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:600;\u001b[39m\n\u001b[31m  display:flex;align-items:flex-end;justify-content:center}\u001b[39m\n\u001b[31m.ardl-box{background:#fff;border-radius:var(--r) var(--r) 0 0;width:100%;max-height:80vh;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ardl-hdr{display:flex;align-items:flex-start;justify-content:space-between;\u001b[39m\n\u001b[31m  padding:16px 16px 10px;border-bottom:1px solid var(--g200);gap:10px}\u001b[39m\n\u001b[31m.ardl-title{font-size:17px;font-weight:700;color:var(--nv);line-height:1.3}\u001b[39m\n\u001b[31m.ardl-body{flex:1;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:14px}\u001b[39m\n\u001b[31m.ardl-sec{display:flex;flex-direction:column;gap:6px}\u001b[39m\n\u001b[31m.ardl-lbl{font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.ardl-val{font-size:13px;color:var(--nv);line-height:1.5}\u001b[39m\n\u001b[31m.ardl-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\u001b[39m\n\u001b[31m/* Hub home button */\u001b[39m\n\u001b[31m.btn-hub{background:none;border:1px solid rgba(255,255,255,.25);color:rgba(255,255,255,.85);\u001b[39m\n\u001b[31m  font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;cursor:pointer;\u001b[39m\n\u001b[31m  display:flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-hub:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hdr-r{display:flex;align-items:center;gap:6px;margin-left:auto;flex-shrink:0}\u001b[39m\n\u001b[31m.hdr-user{font-size:11px;color:rgba(255,255,255,.7);white-space:nowrap;max-width:80px;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.btn-logout{background:none;border:1px solid rgba(255,255,255,.2);color:rgba(255,255,255,.7);font-size:11px;font-weight:600;padding:4px 8px;border-radius:20px;cursor:pointer;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-logout:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hero-ubar{display:flex;align-items:center;justify-content:space-between;padding-top:6px;margin-top:2px}\u001b[39m\n\u001b[31m.hero-uname{font-size:12px;color:rgba(255,255,255,.65)}\u001b[39m\n\u001b[31m.hi-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .en-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .hi-txt{display:inline}\u001b[39m\n\u001b[31m.lang-btn{background:none;border:1px solid rgba(255,255,255,.3);color:rgba(255,255,255,.8);font-size:12px;font-weight:700;padding:4px 10px;border-radius:20px;cursor:pointer;display:flex;align-items:center;gap:3px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.lang-btn:active{background:rgba(255,255,255,.15)}\u001b[39m\n\u001b[31m/* ── DELETE / AUDIT ── */\u001b[39m\n\u001b[31m.del-btn{background:none;border:none;padding:6px 8px;cursor:pointer;color:var(--g400);font-size:16px;flex-shrink:0;border-radius:var(--rs);transition:color .15s,background .15s}\u001b[39m\n\u001b[31m.del-btn:active{color:var(--rd);background:#fee2e2}\u001b[39m\n\u001b[31m.asc.deleted-row{background:#fff5f5;border:1px solid #fecaca;opacity:.85}\u001b[39m\n\u001b[31m.asc.deleted-row .asc-name{text-decoration:line-through;color:var(--g500)}\u001b[39m\n\u001b[31m.del-reason-tag{display:inline-block;background:#fee2e2;color:var(--rd);font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.del-by-txt{font-size:11px;color:var(--g400);margin-top:3px}\u001b[39m\n\u001b[31m.restore-btn{background:none;border:1.5px solid #bbf7d0;border-radius:20px;color:#16a34a;font-size:11px;font-weight:700;padding:3px 10px;cursor:pointer;white-space:nowrap;margin-top:5px}\u001b[39m\n\u001b[31m.restore-btn:active{background:#dcfce7}\u001b[39m\n\u001b[31m.sup-tile{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:20px 16px;cursor:pointer;display:flex;align-items:center;gap:14px;margin-bottom:12px;transition:box-shadow .15s}\u001b[39m\n\u001b[31m.sup-tile:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.sup-tile-ico{width:48px;height:48px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:26px;flex-shrink:0}\u001b[39m\n\u001b[31m.sup-tile-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.sup-tile-title{font-size:15px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.sup-tile-sub{font-size:12px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.del-toggle-btn{padding:6px 14px;border:1.5px solid var(--g200);border-radius:20px;background:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:600;color:var(--g500);cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.del-toggle-btn.active{background:#fee2e2;border-color:#fecaca;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1.5px solid var(--g200);border-radius:var(--r);margin-bottom:10px;cursor:pointer;transition:all .15s;font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.reason-opt:active{background:var(--g50)}\u001b[39m\n\u001b[31m.reason-opt.sel{border-color:var(--rd);background:#fff5f5;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt.danger{border-color:#fdba74;background:#fff7ed;color:#9a3412}\u001b[39m\n\u001b[31m.reason-opt.danger.sel{border-color:#c2410c;background:#fff1e6;color:#9a3412}\u001b[39m\n\u001b[31m#del-confirm-btn.no-reason{background:var(--g300)!important;cursor:default}\u001b[39m\n\u001b[31m@keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}\u001b[39m\n\u001b[31m.reason-opt-ico{font-size:22px;flex-shrink:0}\u001b[39m\n\u001b[31m/* ── APP UPDATE BANNER ── */\u001b[39m\n\u001b[31m.upd-banner{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);left:12px;right:12px;background:#16a34a;color:#fff;padding:11px 14px;border-radius:var(--r);display:flex;align-items:center;justify-content:space-between;gap:10px;z-index:550;box-shadow:0 4px 16px rgba(0,0,0,.18);transform:translateY(120px);opacity:0;transition:transform .35s ease,opacity .35s ease;pointer-events:none}\u001b[39m\n\u001b[31m.upd-banner.show{transform:translateY(0);opacity:1;pointer-events:auto}\u001b[39m\n\u001b[31m/* ── EDIT REQUEST ── */\u001b[39m\n\u001b[31m.req-edit-btn{padding:4px 10px;background:#fffbeb;border:1px solid #fde68a;border-radius:20px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:600;color:#92400e;cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.req-edit-btn:active{background:#fef3c7}\u001b[39m\n\u001b[31m.edit-req-badge{display:inline-block;background:#fef3c7;color:#92400e;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;white-space:nowrap}\u001b[39m\n\u001b[31m.edit-req-card{background:#fffbeb;border:1.5px solid #fde68a;border-radius:var(--r);padding:14px 16px;margin-bottom:10px;display:flex;align-items:flex-start;gap:12px}\u001b[39m\n\u001b[31m.edit-req-card-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.edit-req-card-name{font-size:14px;font-weight:600;color:var(--nv);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.edit-req-card-meta{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.edit-req-cmt{font-size:12px;color:#78350f;background:#fff;border:1px solid #fde68a;border-radius:var(--rs);padding:8px 10px;margin-top:8px;line-height:1.5}\u001b[39m\n\u001b[31m.edit-req-section-hdr{font-size:11px;font-weight:700;color:#92400e;text-transform:uppercase;letter-spacing:.5px;padding:10px 0 6px;border-bottom:1px solid #fde68a;margin-bottom:8px}\u001b[39m\n\u001b[31m.upd-banner-ok{background:rgba(255,255,255,.2);border:none;color:#fff;border-radius:20px;padding:5px 13px;font-size:12px;font-weight:600;cursor:pointer;font-family:'DM Sans',sans-serif;white-space:nowrap}\u001b[39m\n\u001b[31m.upd-banner-ok:active{background:rgba(255,255,255,.35)}\u001b[39m\n\u001b[31m/* ── FONT SIZE WIDGET ── */\u001b[39m\n\u001b[31m.fs-widget{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);right:12px;display:flex;align-items:center;gap:0;background:#fff;border:1.5px solid var(--g200);border-radius:24px;box-shadow:0 2px 8px rgba(0,0,0,.12);z-index:500;overflow:hidden;user-select:none}\u001b[39m\n\u001b[31m.fs-btn{background:none;border:none;cursor:pointer;padding:7px 11px;color:var(--g500);line-height:1;transition:background .15s}\u001b[39m\n\u001b[31m.fs-btn:active{background:var(--g100)}\u001b[39m\n\u001b[31m.fs-btn:disabled{color:var(--g300);cursor:default}\u001b[39m\n\u001b[31m.fs-label{font-size:11px;font-weight:700;color:var(--g500);padding:0 4px;pointer-events:none}\u001b[39m\n\u001b[31m/* Level 1 — Large (+15%) */\u001b[39m\n\u001b[31mbody.fs-1 .field label,body.fs-1 .card-title,body.fs-1 .set-lbl,body.fs-1 .set-sub,\u001b[39m\n\u001b[31mbody.fs-1 .hdr-title,body.fs-1 .hdr-sub,body.fs-1 .slbl,body.fs-1 .rev-lbl,body.fs-1 .rev-val,\u001b[39m\n\u001b[31mbody.fs-1 .rbtn,body.fs-1 .chip,body.fs-1 .btn-p,body.fs-1 .btn-s,body.fs-1 .btn-o,\u001b[39m\n\u001b[31mbody.fs-1 .bdialog-title,body.fs-1 .bdialog-sub,body.fs-1 .sub-name,body.fs-1 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-1 .pslot-lbl,body.fs-1 .bitem-title,body.fs-1 .pi-name,body.fs-1 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-1 .asc-name,body.fs-1 .new-btn,body.fs-1 .resume-btn,body.fs-1 .ardl-lbl,body.fs-1 .ardl-val{font-size:calc(1em * 1.15) !important}\u001b[39m\n\u001b[31m/* Level 2 — X-Large (+30%) */\u001b[39m\n\u001b[31mbody.fs-2 .field label,body.fs-2 .card-title,body.fs-2 .set-lbl,body.fs-2 .set-sub,\u001b[39m\n\u001b[31mbody.fs-2 .hdr-title,body.fs-2 .hdr-sub,body.fs-2 .slbl,body.fs-2 .rev-lbl,body.fs-2 .rev-val,\u001b[39m\n\u001b[31mbody.fs-2 .rbtn,body.fs-2 .chip,body.fs-2 .btn-p,body.fs-2 .btn-s,body.fs-2 .btn-o,\u001b[39m\n\u001b[31mbody.fs-2 .bdialog-title,body.fs-2 .bdialog-sub,body.fs-2 .sub-name,body.fs-2 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-2 .pslot-lbl,body.fs-2 .bitem-title,body.fs-2 .pi-name,body.fs-2 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-2 .asc-name,body.fs-2 .new-btn,body.fs-2 .resume-btn,body.fs-2 .ardl-lbl,body.fs-2 .ardl-val{font-size:calc(1em * 1.30) !important}\u001b[39m\n\u001b[31m/* Level 3 — XX-Large (+50%) */\u001b[39m\n\u001b[31mbody.fs-3 .field label,body.fs-3 .card-title,body.fs-3 .set-lbl,body.fs-3 .set-sub,\u001b[39m\n\u001b[31mbody.fs-3 .hdr-title,body.fs-3 .hdr-sub,body.fs-3 .slbl,body.fs-3 .rev-lbl,body.fs-3 .rev-val,\u001b[39m\n\u001b[31mbody.fs-3 .rbtn,body.fs-3 .chip,body.fs-3 .btn-p,body.fs-3 .btn-s,body.fs-3 .btn-o,\u001b[39m\n\u001b[31mbody.fs-3 .bdialog-title,body.fs-3 .bdialog-sub,body.fs-3 .sub-name,body.fs-3 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-3 .pslot-lbl,body.fs-3 .bitem-title,body.fs-3 .pi-name,body.fs-3 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-3 .asc-name,body.fs-3 .new-btn,body.fs-3 .resume-btn,body.fs-3 .ardl-lbl,body.fs-3 .ardl-val{font-size:calc(1em * 1.50) !important}\u001b[39m\n\u001b[31m/* Level 4 — Max (+70%) */\u001b[39m\n\u001b[31mbody.fs-4 .field label,body.fs-4 .card-title,body.fs-4 .set-lbl,body.fs-4 .set-sub,\u001b[39m\n\u001b[31mbody.fs-4 .hdr-title,body.fs-4 .hdr-sub,body.fs-4 .slbl,body.fs-4 .rev-lbl,body.fs-4 .rev-val,\u001b[39m\n\u001b[31mbody.fs-4 .rbtn,body.fs-4 .chip,body.fs-4 .btn-p,body.fs-4 .btn-s,body.fs-4 .btn-o,\u001b[39m\n\u001b[31mbody.fs-4 .bdialog-title,body.fs-4 .bdialog-sub,body.fs-4 .sub-name,body.fs-4 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-4 .pslot-lbl,body.fs-4 .bitem-title,body.fs-4 .pi-name,body.fs-4 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-4 .asc-name,body.fs-4 .new-btn,body.fs-4 .resume-btn,body.fs-4 .ardl-lbl,body.fs-4 .ardl-val{font-size:calc(1em * 1.70) !important}\u001b[39m\n\u001b[31m/* ── RECCE TILE ACTION BUTTONS ── */\u001b[39m\n\u001b[31m.rpt-btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid rgba(0,0,0,.06)}\u001b[39m\n\u001b[31m.rpt-btn{display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 14px;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;border:none;font-family:inherit;transition:background .15s,opacity .15s;flex:1;min-width:110px;letter-spacing:.1px;white-space:nowrap}\u001b[39m\n\u001b[31m.rpt-btn-report{background:#fff7ed;color:var(--or);border:1.5px solid var(--or)}\u001b[39m\n\u001b[31m.rpt-btn-report:active{background:#fed7aa}\u001b[39m\n\u001b[31m.rpt-btn-pdf{background:var(--g100);color:var(--g400);border:1.5px solid var(--g200)}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready{background:var(--or);color:#fff;border-color:transparent}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready:active{background:#ea6c00}\u001b[39m\n\u001b[31m/* PDF wait overlay */\u001b[39m\n\u001b[31m#pdf-wait-ov{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m</style>\u001b[39m\n\u001b[31m</head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<!-- PICKER OVERLAY -->\u001b[39m\n\u001b[31m<div class=\\\"povl\\\" id=\\\"povl\\\">\u001b[39m\n\u001b[31m  <div class=\\\"povl-hdr\\\">\u001b[39m\n\u001b[31m    <input class=\\\"psearch\\\" id=\\\"psearch\\\" type=\\\"text\\\" placeholder=\\\"Search store / दुकान खोजें…\\\" oninput=\\\"filterPicker(this.value)\\\" autocomplete=\\\"off\\\">\u001b[39m\n\u001b[31m    <button class=\\\"pcancel\\\" onclick=\\\"closePicker()\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"plist\\\" id=\\\"plist\\\"></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"app\\\">·\u001b[39m\n\u001b[31m<!-- HOME -->\u001b[39m\n\u001b[31m<div class=\\\"view active\\\" id=\\\"view-home\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hero\\\">\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;justify-content:space-between;align-items:center\\\">\u001b[39m\n\u001b[31m      <div><div class=\\\"hero-title\\\"><span class=\\\"en-txt\\\">Branding Recce</span><span class=\\\"hi-txt\\\">ब्रांडिंग रेकी</span></div><div class=\\\"hero-sub\\\" id=\\\"today-date\\\">—</div></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:6px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"lang-btn\\\" onclick=\\\"setLang(LANG==='en'?'hi':'en')\\\" id=\\\"lang-btn\\\" title=\\\"Switch language / भाषा बदलें\\\">EN | हि</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-hub\\\" onclick=\\\"goToHub()\\\">🏡 Hub</button>\u001b[39m\n\u001b[31m      <button class=\\\"icon-btn\\\" onclick=\\\"showView('settings')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12 15a3 3 0 100-6 3 3 0 000 6z\\\"/><path d=\\\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\\\"/></svg></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"hero-ubar\\\" id=\\\"recce-hero-ubar\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <span class=\\\"hero-uname\\\" id=\\\"recce-hero-name\\\"></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-logout\\\" onclick=\\\"recceLogout()\\\">Logout</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"stats\\\">\u001b[39m\n\u001b[31m      <div class=\\\"scard g\\\"><div class=\\\"snum\\\" id=\\\"stat-synced\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Synced</span><span class=\\\"hi-txt\\\">सिंक्ड</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard a\\\"><div class=\\\"snum\\\" id=\\\"stat-pending\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Pending</span><span class=\\\"hi-txt\\\">बाकी</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard\\\"><div class=\\\"snum\\\" id=\\\"stat-total\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Total</span><span class=\\\"hi-txt\\\">कुल</span></div></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <button class=\\\"new-btn\\\" onclick=\\\"startNewRecce()\\\"><svg width=\\\"20\\\" height=\\\"20\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">New Recce</span><span class=\\\"hi-txt\\\">नई रेकी</span></button>\u001b[39m\n\u001b[31m    <div id=\\\"resume-wrap\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"sh\\\"><span class=\\\"st\\\"><span class=\\\"en-txt\\\">Recent Submissions</span><span class=\\\"hi-txt\\\">हाल की सबमिशन</span></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"syncNow()\\\" id=\\\"sync-btn\\\" style=\\\"padding:7px 12px;font-size:12px\\\"><svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg><span class=\\\"en-txt\\\">Sync</span><span class=\\\"hi-txt\\\">सिंक</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"sub-list\\\"></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"srow\\\"><div><span class=\\\"sdot\\\" id=\\\"net-dot\\\"></span><span id=\\\"net-txt\\\"><span class=\\\"en-txt\\\">Checking…</span><span class=\\\"hi-txt\\\">जाँच…</span></span></div><span id=\\\"last-sync-txt\\\" style=\\\"font-size:11px\\\"><span class=\\\"en-txt\\\">Never synced</span><span class=\\\"hi-txt\\\">कभी सिंक नहीं</span></span></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- SETTINGS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-settings\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('home')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Settings</span><span class=\\\"hi-txt\\\">सेटिंग</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Brand List</span><span class=\\\"hi-txt\\\">ब्रांड सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Manage Brands</span><span class=\\\"hi-txt\\\">ब्रांड प्रबंधन</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">These appear in the brand dropdown and store picker. Add client brands as needed.</div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-manage-list\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-add-row\\\" style=\\\"display:none;gap:8px;align-items:center\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"brand-add-inp\\\" placeholder=\\\"Type brand name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addBrandToList()\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"addBrandToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Store Lists</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Supervisors can upload XLS/CSV store lists here. Updates sync to all devices via server.</span><span class=\\\"hi-txt\\\">सुपरवाइजर यहाँ XLS/CSV स्टोर सूची अपलोड कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m      <!-- Upload/Clear row — supervisor only -->\u001b[39m\n\u001b[31m      <div id=\\\"store-upload-row\\\" style=\\\"display:none;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;margin-top:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"document.getElementById('store-xl').click()\\\"><svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Add File</span><span class=\\\"hi-txt\\\">फ़ाइल जोड़ें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-d\\\" onclick=\\\"clearStoreList()\\\" style=\\\"font-size:12px\\\"><span class=\\\"en-txt\\\">Clear All Stores</span><span class=\\\"hi-txt\\\">सभी स्टोर हटाएं</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" id=\\\"store-push-btn\\\" onclick=\\\"pushStoresToServer()\\\" style=\\\"font-size:12px;display:none\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Push to Server</span><span class=\\\"hi-txt\\\">सर्वर पर पुश करें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"store-xl\\\" accept=\\\".xlsx,.xls,.csv\\\" onchange=\\\"handleStoreUpload(event)\\\">\u001b[39m\n\u001b[31m      <div id=\\\"store-count\\\" style=\\\"font-size:13px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"store-file-list\\\" style=\\\"margin-top:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Brand assignment dialog for files with no brand column -->\u001b[39m\n\u001b[31m    <div id=\\\"brand-assign-dialog\\\" style=\\\"display:none;margin-top:10px;padding:14px;background:#fff7ed;border:1.5px solid var(--or);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\">Which brand is this store list for?</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\" id=\\\"brand-assign-fname\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-assign-chips\\\" class=\\\"chip-grid\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"confirmBrandAssign()\\\" style=\\\"flex:2;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">Assign Brand</span><span class=\\\"hi-txt\\\">ब्रांड असाइन करें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"skipBrandAssign()\\\" style=\\\"flex:1;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">No Brand</span><span class=\\\"hi-txt\\\">कोई ब्रांड नहीं</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Server Store List URL (Admin)</span><span class=\\\"hi-txt\\\">सर्वर स्टोर सूची URL</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Admin pushes stores.json to any public URL. App auto-fetches on open and caches offline.</div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"srv-url\\\" placeholder=\\\"https://yourserver.com/stores.json\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"fetchServerStores()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Fetch Now</button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"saveServerUrl()\\\" style=\\\"padding:9px 14px;font-size:13px;width:auto\\\">Save URL</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Sync Endpoint</span><span class=\\\"hi-txt\\\">सिंक एंडपॉइंट</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Slides Generator</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Managed by admin. Deploy gas_slides.gs from /opt/slides-proxy/ to Google Apps Script and paste the URL here.</div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"slides-gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Not configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"slides-gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"saveSlidesGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Sheet Sync</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Legacy sync endpoint. Writes recce data to Google Sheet.</div>·\u001b[39m\n\u001b[31m      <!-- Locked state (default) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Endpoint configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Unlocked state (after admin login) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;align-items:center;gap:8px;margin-bottom:10px;padding:7px 12px;background:#dcfce7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          <span style=\\\"font-size:12px;color:#14532d;font-weight:600\\\">🔓 Admin mode active</span>\u001b[39m\n\u001b[31m          <button onclick=\\\"lockAdmin()\\\" style=\\\"margin-left:auto;background:none;border:none;color:#14532d;font-size:12px;cursor:pointer;font-weight:600\\\">Lock ×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"testEndpoint()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Test</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>·\u001b[39m\n\u001b[31m    <!-- Admin Login Modal -->\u001b[39m\n\u001b[31m    <div id=\\\"admin-login-modal\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m      <div style=\\\"background:#fff;border-radius:var(--r);padding:24px 20px;margin:20px;max-width:380px;width:100%;box-shadow:0 8px 32px rgba(0,0,0,.2)\\\">\u001b[39m\n\u001b[31m        <div style=\\\"font-size:17px;font-weight:700;color:var(--nv);margin-bottom:4px\\\">Admin Login</div>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:18px\\\">Enter admin password to unlock settings</div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m          <label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">Password</label>\u001b[39m\n\u001b[31m          <input type=\\\"password\\\" id=\\\"admin-pwd\\\" placeholder=\\\"Enter admin password\\\" style=\\\"width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px\\\" onkeydown=\\\"if(event.key==='Enter')verifyAdmin()\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div id=\\\"admin-error\\\" style=\\\"display:none;font-size:12px;color:var(--rd);margin-bottom:12px;padding:8px 12px;background:#fee2e2;border-radius:var(--rs)\\\">Incorrect password</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"verifyAdmin()\\\" style=\\\"flex:2;padding:13px\\\" id=\\\"admin-login-btn\\\">Login</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-s\\\" onclick=\\\"closeAdminLogin()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:14px;padding-top:14px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.4px;margin-bottom:8px\\\">Admin Password Config URL</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:8px\\\">URL to your admin.json file on server (contains hashed password)</div>\u001b[39m\n\u001b[31m          <input type=\\\"url\\\" id=\\\"admin-cfg-url\\\" placeholder=\\\"https://yourserver.com/admin.json\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px;margin-bottom:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveAdminCfgUrl()\\\" style=\\\"font-size:12px;padding:7px 12px;width:100%;justify-content:center\\\">Save Config URL</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Geolocation Stamp</span><span class=\\\"hi-txt\\\">जियोलोकेशन स्टैम्प</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;justify-content:space-between;gap:16px\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1\\\">\u001b[39m\n\u001b[31m          <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Stamp on Photos</span><span class=\\\"hi-txt\\\">फोटो पर स्टैम्प</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"set-sub\\\" style=\\\"margin-bottom:0\\\">Bakes GPS coordinates, store name and timestamp into every photo — visible in the image itself. Same as GPS Map Camera app. Default: On.</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"tog on\\\" id=\\\"geo-tog\\\" onclick=\\\"toggleGeoStamp()\\\"><div class=\\\"tog-knob\\\"></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"geo-status\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\">GPS not yet captured</div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Image Quality</span><span class=\\\"hi-txt\\\">फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Default Photo Quality</span><span class=\\\"hi-txt\\\">डिफ़ॉल्ट फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Applies to all photos — front view, inside view, branding, and additional. HD uses more storage and takes longer to sync on poor networks.</div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;gap:10px;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-compressed\\\" onclick=\\\"setImgQuality('compressed')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-compressed\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-compressed\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">Full Compression</span><span class=\\\"hi-txt\\\">पूर्ण कम्प्रेशन</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~150–200 KB · Max 1280px · Best for poor network</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-left:auto;font-size:11px;font-weight:700;color:var(--gn);background:#dcfce7;padding:3px 8px;border-radius:20px\\\"><span class=\\\"en-txt\\\">Recommended</span><span class=\\\"hi-txt\\\">अनुशंसित</span></div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-hd\\\" onclick=\\\"setImgQuality('hd')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-hd\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-hd\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">HD Quality</span><span class=\\\"hi-txt\\\">HD क्वालिटी</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~400–600 KB · Max 1920px · Better detail for print</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"q-current-badge\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Supervisor Config panel — shown only to supervisors via renderSupPanel() -->\u001b[39m\n\u001b[31m    <div id=\\\"sup-panel\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">🔐 Recce Access Config</span><span class=\\\"hi-txt\\\">🔐 रेकी एक्सेस कॉन्फ़िग</span></div>\u001b[39m\n\u001b[31m      <!-- Access mode — only H/P can change -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"mode-row\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Access Mode</span><span class=\\\"hi-txt\\\">एक्सेस मोड</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Public: any Hub user can submit Recces. Assigned: only Supervisors and Creators can access.</span><span class=\\\"hi-txt\\\">सार्वजनिक: कोई भी Hub यूजर। नियत: सिर्फ़ Supervisors और Creators।</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\" style=\\\"margin-bottom:8px;margin-top:8px\\\">\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-public\\\" onclick=\\\"setRecceMode('public')\\\"><span class=\\\"en-txt\\\">Public</span><span class=\\\"hi-txt\\\">सार्वजनिक</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-assigned\\\" onclick=\\\"setRecceMode('assigned')\\\"><span class=\\\"en-txt\\\">Assigned</span><span class=\\\"hi-txt\\\">नियत</span></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Supervisor list — view all + delete + create -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Supervisors</span><span class=\\\"hi-txt\\\">सुपरवाइजर</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can view all recces, delete with reason, and submit. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">सभी रेकी देख सकते हैं, कारण से हटा सकते हैं, और सबमिट कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"sup-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addSupervisor()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addSupervisor()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Creator list — creation only -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Creators</span><span class=\\\"hi-txt\\\">क्रिएटर्स</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can submit Recces only — no admin view or deletion rights. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">केवल रेकी सबमिट कर सकते हैं — एडमिन व्यू या डिलीट नहीं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"creator-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addCreator()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addCreator()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Client list — used for client portal scoping -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clients</span><span class=\\\"hi-txt\\\">क्लाइंट</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Names that appear as chips when submitting a recce. Add the brand or agency name (e.g. \\\"Marketing Vibe\\\"). These are used to scope what clients see in the Client Portal.</span><span class=\\\"hi-txt\\\">रेकी सबमिट करते समय दिखने वाले क्लाइंट नाम। ब्रांड या एजेंसी नाम जोड़ें।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-mgmt-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"client-add-inp\\\" placeholder=\\\"Client name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addClientToList()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addClientToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Sync to server — only H/P -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"cfg-sync-btn\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Sync Config to Server</span><span class=\\\"hi-txt\\\">सर्वर पर कॉन्फ़िग सिंक करें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Apply supervisor/creator/client lists and access mode to all devices.</span><span class=\\\"hi-txt\\\">सभी डिवाइस पर कॉन्फ़िग लागू करें।</span></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"syncCfgToServer()\\\" style=\\\"max-width:220px;font-size:14px;padding:12px;margin-top:8px\\\"><span class=\\\"en-txt\\\">Sync to Server</span><span class=\\\"hi-txt\\\">सर्वर पर सिंक करें</span></button>\u001b[39m\n\u001b[31m        <div id=\\\"cfg-sync-status\\\" style=\\\"margin-top:8px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Danger Zone</span><span class=\\\"hi-txt\\\">खतरनाक ज़ोन</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\"><div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clear All Local Data</span><span class=\\\"hi-txt\\\">सभी डेटा हटाएं</span></div><div class=\\\"set-sub\\\">Removes all submissions from this device.</div><button class=\\\"btn-d\\\" onclick=\\\"clearData()\\\" style=\\\"padding:9px 14px;font-size:13px\\\">Clear All</button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: STORE INFO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-store\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"exitForm()\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Details</span><span class=\\\"hi-txt\\\">दुकान विवरण</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 1 of 5</span><span class=\\\"hi-txt\\\">चरण 1 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:20%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Recce Info</span><span class=\\\"hi-txt\\\">रेकी जानकारी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Date of Recce</span><span class=\\\"hi-txt\\\">रेकी की तारीख</span> <span class=\\\"req\\\">*</span></label><input type=\\\"date\\\" id=\\\"f-date\\\" onchange=\\\"saveDraft()\\\" max=\\\"\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" id=\\\"campaign-field\\\">\u001b[39m\n\u001b[31m        <label><span class=\\\"en-txt\\\">Job / Campaign</span><span class=\\\"hi-txt\\\">जॉब / कैंपेन</span></label>\u001b[39m\n\u001b[31m        <select id=\\\"f-campaign-id\\\" onchange=\\\"onCampaignSelect()\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">Loading campaigns…</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <div id=\\\"campaign-notify-msg\\\" style=\\\"display:none;font-size:12px;color:#92400e;margin-top:6px;padding:8px 10px;background:#fef3c7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          ⚑ <span class=\\\"en-txt\\\">Recce will submit without a job ID. A notification will flag this for your supervisor to link it later.</span><span class=\\\"hi-txt\\\">रेकी बिना जॉब ID के सबमिट होगी। सुपरवाइजर बाद में लिंक करेगा।</span>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Store</span><span class=\\\"hi-txt\\\">दुकान</span> <span id=\\\"store-avail-tag\\\" style=\\\"font-size:11px;color:var(--g400);font-weight:400;text-transform:none;letter-spacing:0\\\"></span></div>·\u001b[39m\n\u001b[31m      <!-- When store is selected -->\u001b[39m\n\u001b[31m      <div id=\\\"store-selected\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"store-card\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:start;justify-content:space-between;gap:8px\\\">\u001b[39m\n\u001b[31m            <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m              <div class=\\\"store-card-name\\\" id=\\\"sc-name\\\">—</div>\u001b[39m\n\u001b[31m              <div style=\\\"display:flex;align-items:center;gap:6px;margin-top:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m                <span class=\\\"brand-tag\\\" id=\\\"sc-brand\\\">—</span>\u001b[39m\n\u001b[31m                <span class=\\\"last-chip\\\" id=\\\"sc-last\\\" style=\\\"display:none\\\">—</span>\u001b[39m\n\u001b[31m              </div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            <button class=\\\"store-card-change\\\" onclick=\\\"openPicker()\\\"><span class=\\\"en-txt\\\">Change ›</span><span class=\\\"hi-txt\\\">बदलें ›</span></button>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <!-- All fields from Excel shown here -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-details\\\" style=\\\"margin-top:10px;display:flex;flex-direction:column;gap:4px\\\"></div>\u001b[39m\n\u001b[31m          <!-- Missing required fields — editable inline -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-missing\\\" style=\\\"display:none;margin-top:12px;padding-top:12px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m            <div style=\\\"font-size:11px;font-weight:700;color:var(--rd);text-transform:uppercase;letter-spacing:.4px;margin-bottom:10px\\\">⚠ Please complete missing fields</div>\u001b[39m\n\u001b[31m            <div id=\\\"sc-missing-fields\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <!-- Brand selector — shown when store has no brand -->\u001b[39m\n\u001b[31m        <div id=\\\"brand-selector\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\"><span class=\\\"en-txt\\\">Select Brand</span><span class=\\\"hi-txt\\\">ब्रांड चुनें</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\">This store has no brand in the list — select one:</div>\u001b[39m\n\u001b[31m          <div id=\\\"brand-chips\\\" class=\\\"chip-grid\\\"></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Picker trigger (shown when stores loaded) -->\u001b[39m\n\u001b[31m      <div id=\\\"pick-trigger-wrap\\\">\u001b[39m\n\u001b[31m        <div class=\\\"pick-trigger\\\" onclick=\\\"openPicker()\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:center;gap:10px\\\">\u001b[39m\n\u001b[31m            <span style=\\\"font-size:20px\\\">🏪</span>\u001b[39m\n\u001b[31m            <div>\u001b[39m\n\u001b[31m              <div style=\\\"font-size:15px;font-weight:700;color:var(--or)\\\"><span class=\\\"en-txt\\\">Select Store from List</span><span class=\\\"hi-txt\\\">सूची से दुकान चुनें</span></div>\u001b[39m\n\u001b[31m              <div id=\\\"store-avail-count\\\" style=\\\"font-size:12px;font-weight:400;color:var(--am);margin-top:1px\\\"><span class=\\\"en-txt\\\">Tap to browse stores</span><span class=\\\"hi-txt\\\">दुकान खोजने के लिए दबाएं</span></div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual / new store toggle -->\u001b[39m\n\u001b[31m      <div class=\\\"manual-toggle\\\" id=\\\"manual-toggle\\\" onclick=\\\"toggleManual()\\\">\u001b[39m\n\u001b[31m        <svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\" id=\\\"mt-icon\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg>\u001b[39m\n\u001b[31m        <span id=\\\"mt-label\\\"><span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span></span>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual fields -->\u001b[39m\n\u001b[31m      <div id=\\\"manual-fields\\\" style=\\\"display:none;margin-top:14px\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\" style=\\\"margin-bottom:14px\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <select id=\\\"f-brand\\\" onchange=\\\"onManualBrandChange()\\\">\u001b[39m\n\u001b[31m            <option value=\\\"\\\">Select brand</option>\u001b[39m\n\u001b[31m          </select>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span> <span class=\\\"req\\\">*</span></label><input type=\\\"text\\\" id=\\\"f-store\\\" placeholder=\\\"Enter store name\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\">\u001b[39m\n\u001b[31m          <label><span class=\\\"en-txt\\\">Store Address</span><span class=\\\"hi-txt\\\">दुकान का पता</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <textarea id=\\\"f-addr\\\" rows=\\\"2\\\" placeholder=\\\"Full address\\\" onchange=\\\"saveDraft()\\\"></textarea>\u001b[39m\n\u001b[31m          <div class=\\\"gps-row\\\">\u001b[39m\n\u001b[31m            <button class=\\\"gps-btn\\\" onclick=\\\"captureGPS()\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\"/><path d=\\\"M12 2v3M12 19v3M2 12h3M19 12h3\\\"/></svg><span class=\\\"en-txt\\\">Capture GPS</span><span class=\\\"hi-txt\\\">GPS लें</span></button>\u001b[39m\n\u001b[31m            <span id=\\\"gps-status\\\" style=\\\"font-size:12px;color:var(--g500);align-self:center\\\"></span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Mobile No.</span><span class=\\\"hi-txt\\\">मोबाइल नंबर</span></label><input type=\\\"tel\\\" id=\\\"f-mobile\\\" placeholder=\\\"10-digit number\\\" maxlength=\\\"10\\\" inputmode=\\\"numeric\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Client card -->\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Client</span><span class=\\\"hi-txt\\\">क्लाइंट</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\"><span class=\\\"en-txt\\\">Select who this recce is for. Defaults to brand — change if work came via an agency.</span><span class=\\\"hi-txt\\\">यह रेकी किसके लिए है चुनें। ब्रांड से डिफ़ॉल्ट — एजेंसी के ज़रिए हो तो बदलें।</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"cl-chip-grid\\\" id=\\\"client-chips\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"client-other-wrap\\\" style=\\\"display:none;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"f-client-other\\\" placeholder=\\\"Type client name\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" oninput=\\\"onClientOtherInput()\\\">\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-p\\\" onclick=\\\"step2()\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: PHOTOS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-photos\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-store')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Photos</span><span class=\\\"hi-txt\\\">दुकान की फोटो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 2 of 5</span><span class=\\\"hi-txt\\\">चरण 2 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:40%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Front View</span><span class=\\\"hi-txt\\\">आगे का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(min 1, max 3)</span><span class=\\\"cnt-badge gray\\\" id=\\\"front-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"front-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-front\\\" onclick=\\\"addPhoto('front')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Front Photo</span><span class=\\\"hi-txt\\\">आगे की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Inside View</span><span class=\\\"hi-txt\\\">अंदर का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 5)</span><span class=\\\"cnt-badge gray\\\" id=\\\"inside-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"inside-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-inside\\\" onclick=\\\"addPhoto('inside')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Inside Photo</span><span class=\\\"hi-txt\\\">अंदर की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-store')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step3()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: VIDEO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-video\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-photos')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Recce Video</span><span class=\\\"hi-txt\\\">रेकी वीडियो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 3 of 5</span><span class=\\\"hi-txt\\\">चरण 3 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:60%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Video</span><span class=\\\"hi-txt\\\">वीडियो</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Recce video available?</span><span class=\\\"hi-txt\\\">रेकी वीडियो है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"vid-yes\\\" onclick=\\\"setVideo(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"vid-no\\\" onclick=\\\"setVideo(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"vid-sec\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Upload Video</span><span class=\\\"hi-txt\\\">वीडियो अपलोड करें</span></label>\u001b[39m\n\u001b[31m          <div class=\\\"pslot\\\" id=\\\"vid-slot\\\" onclick=\\\"document.getElementById('vid-inp').click()\\\"><div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div></div>\u001b[39m\n\u001b[31m          <input type=\\\"file\\\" id=\\\"vid-inp\\\" accept=\\\"video/*\\\" onchange=\\\"handleVideo(event)\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Video Comments</span><span class=\\\"hi-txt\\\">वीडियो टिप्पणी</span></label><input type=\\\"text\\\" id=\\\"f-vid-cmt\\\" placeholder=\\\"Optional\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-photos')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step4()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: BRANDING -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-branding\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-video')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Branding</span><span class=\\\"hi-txt\\\">ब्रांडिंग</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 4 of 5</span><span class=\\\"hi-txt\\\">चरण 4 / 5</span></div></div></div>\u001b[39m\n\u001b[31m    <span id=\\\"br-hdr-badge\\\" style=\\\"background:rgba(255,255,255,.2);color:#fff;font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px\\\"><span class=\\\"en-txt\\\">0 items</span><span class=\\\"hi-txt\\\">0 आइटम</span></span>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:80%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Branding Space</span><span class=\\\"hi-txt\\\">ब्रांडिंग स्थान</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Space available?</span><span class=\\\"hi-txt\\\">जगह उपलब्ध है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"br-yes\\\" onclick=\\\"setBranding(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"br-no\\\" onclick=\\\"setBranding(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"branding-lock-banner\\\" style=\\\"display:none;background:#fef3c7;border:1.5px solid #f59e0b;border-radius:10px;padding:12px 14px;margin-bottom:10px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:700;color:#92400e\\\">Client approval exists — branding locked</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:#78350f;margin-top:4px\\\"><span class=\\\"en-txt\\\">The client has reviewed this recce. Create a new recce to revise branding items.</span><span class=\\\"hi-txt\\\">क्लाइंट ने रेकी की समीक्षा की है। बदलाव के लिए नई रेकी बनाएं।</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"branding-override-wrap\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m        <button onclick=\\\"unlockBrandingOverride()\\\" style=\\\"background:#f59e0b;color:#000;border:none;border-radius:8px;padding:8px 14px;font-size:12px;font-weight:700;cursor:pointer\\\">Override Edit (H&amp;P only)</button>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:11px;color:#92400e;margin-top:5px\\\">Use only when client has verbally confirmed and app needs correction.</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"br-items\\\"></div>\u001b[39m\n\u001b[31m    <div id=\\\"br-add\\\" style=\\\"display:none;margin-bottom:80px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"addBranding()\\\" style=\\\"width:100%;justify-content:center\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Another Branding Item</span><span class=\\\"hi-txt\\\">एक और ब्रांडिंग जोड़ें</span></button>\u001b[39m\n\u001b[31m      <div style=\\\"text-align:center;font-size:12px;color:var(--g400);margin-top:8px\\\"><span class=\\\"en-txt\\\">Tap Continue below when done adding items</span><span class=\\\"hi-txt\\\">सभी आइटम जोड़ने के बाद आगे दबाएं</span></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-video')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step5()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: ADDITIONAL + SUBMIT -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-additional\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-branding')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Submit</span><span class=\\\"hi-txt\\\">सबमिट</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 5 of 5</span><span class=\\\"hi-txt\\\">चरण 5 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:100%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Mandatory Document</span><span class=\\\"hi-txt\\\">अनिवार्य दस्तावेज़</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"pslot\\\" id=\\\"doc-slot\\\" onclick=\\\"document.getElementById('doc-inp').click()\\\"><div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div></div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"doc-inp\\\" accept=\\\"image/*,.pdf\\\" onchange=\\\"handleDoc(event)\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Additional Photos</span><span class=\\\"hi-txt\\\">अतिरिक्त फोटो</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 8)</span><span class=\\\"cnt-badge gray\\\" id=\\\"addl-badge\\\">0 / 8</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"add-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-addl\\\" onclick=\\\"addAdditional()\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\"><div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Review</span><span class=\\\"hi-txt\\\">समीक्षा</span></div><div id=\\\"rev-body\\\"></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-branding')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"submitRecce()\\\" id=\\\"sub-btn\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Submit Recce ✓</span><span class=\\\"hi-txt\\\">रेकी सबमिट करें ✓</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- ANNOTATION MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"annot-modal\\\" id=\\\"annot-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"annot-bar\\\">\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Draw:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"at-rect\\\"    onclick=\\\"setATool('rect')\\\">▭ Rect</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-ellipse\\\" onclick=\\\"setATool('ellipse')\\\">◯ Ellipse</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-line\\\"    onclick=\\\"setATool('line')\\\">╱ Line</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-arrow\\\"   onclick=\\\"setATool('arrow')\\\">↗ Arrow</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-free\\\"    onclick=\\\"setATool('free')\\\">✏ Free</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool sel-on\\\" id=\\\"at-move\\\" onclick=\\\"setATool('move')\\\" style=\\\"margin-left:4px\\\">⊹ Move</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Color:</span>\u001b[39m\n\u001b[31m      <div class=\\\"acolor on\\\" id=\\\"ac-or\\\" style=\\\"background:#f97316\\\" onclick=\\\"setAColor('#f97316')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-rd\\\" style=\\\"background:#ef4444\\\" onclick=\\\"setAColor('#ef4444')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-wh\\\" style=\\\"background:#ffffff\\\" onclick=\\\"setAColor('#ffffff')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-yw\\\" style=\\\"background:#facc15\\\" onclick=\\\"setAColor('#facc15')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-gn\\\" style=\\\"background:#22c55e\\\" onclick=\\\"setAColor('#22c55e')\\\"></div>\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Width:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-2\\\" onclick=\\\"setAWidth(2)\\\" style=\\\"padding:5px 8px\\\">Thin</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"aw-4\\\" onclick=\\\"setAWidth(4)\\\" style=\\\"padding:5px 8px\\\">Med</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-7\\\" onclick=\\\"setAWidth(7)\\\" style=\\\"padding:5px 8px\\\">Thick</button>\u001b[39m\n\u001b[31m      <div style=\\\"flex:1\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"undoAnnot()\\\">↩</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"clearAnnot()\\\">✕</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"annot-sel-info\\\" style=\\\"display:none;font-size:11px;color:#facc15;padding:4px 0 2px\\\">\u001b[39m\n\u001b[31m      Shape selected — drag to move · drag corners to resize · tap elsewhere to deselect\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-cvs-wrap\\\"><canvas id=\\\"annot-cvs\\\"></canvas></div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-foot\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-s\\\" onclick=\\\"skipAnnot()\\\" style=\\\"flex:1;padding:12px;font-size:14px\\\"><span class=\\\"en-txt\\\">Skip markup</span><span class=\\\"hi-txt\\\">मार्कअप छोड़ें</span></button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" onclick=\\\"saveAnnot()\\\" style=\\\"flex:2;padding:12px\\\"><span class=\\\"en-txt\\\">Done — Save ✓</span><span class=\\\"hi-txt\\\">हो गया — सेव करें ✓</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EXIT DIALOG -->\u001b[39m\n\u001b[31m<!-- MODAL: Link Job to Recce (supervisor only) -->\u001b[39m\n\u001b[31m<div id=\\\"modal-link-job\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m  <div style=\\\"background:#fff;border-radius:14px;padding:20px;width:90%;max-width:380px;display:flex;flex-direction:column;gap:12px;box-shadow:0 8px 32px rgba(0,0,0,.35)\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:15px;font-weight:700;color:#1e293b\\\">&#x1F517; Link Job to Recce</div>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-store\\\" style=\\\"font-size:13px;color:#64748b\\\"></div>\u001b[39m\n\u001b[31m    <select id=\\\"link-job-sel\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m      <option value=\\\"\\\">&#x2014; Select campaign &#x2014;</option>\u001b[39m\n\u001b[31m    </select>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-err\\\" style=\\\"font-size:12px;color:#ef4444;min-height:14px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"closeLinkJobModal()\\\" style=\\\"flex:1;padding:12px;border:1px solid #cbd5e1;border-radius:8px;cursor:pointer;background:#f8fafc;font-size:14px\\\">Cancel</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"saveLinkJob()\\\" style=\\\"flex:2;padding:12px;background:#f59e0b;color:#000;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:700\\\">&#x1F517; Link Job</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"exit-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Exit Recce?</span><span class=\\\"hi-txt\\\">रेकी से बाहर?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Your progress and photos will be saved as a draft. Resume anytime from the home screen.</span><span class=\\\"hi-txt\\\">आपकी प्रगति और फोटो ड्राफ्ट में सेव होंगी। होम स्क्रीन से कभी भी जारी रखें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"exitSaveAndLeave()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">💾 Save Draft & Exit</span><span class=\\\"hi-txt\\\">💾 ड्राफ्ट सेव करें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-d\\\" onclick=\\\"exitDiscard()\\\" style=\\\"flex:1;padding:13px;font-size:13px\\\"><span class=\\\"en-txt\\\">Discard</span><span class=\\\"hi-txt\\\">हटाएं</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"exitCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">← Continue Recce</span><span class=\\\"hi-txt\\\">← रेकी जारी रखें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- PHOTO SOURCE PICKER -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"photo-src-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Camera photos get GPS stamp baked in. Gallery photos are added without stamp.</span><span class=\\\"hi-txt\\\">कैमरा फोटो में GPS स्टैम्प लगती है। गैलरी फोटो में नहीं।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"photoSrcCamera()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">📷 Use Camera</span><span class=\\\"hi-txt\\\">📷 कैमरा</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">GPS stamp applied</span><span class=\\\"hi-txt\\\">GPS स्टैम्प लगेगी</span></span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"photoSrcGallery()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">🖼 Choose from Gallery</span><span class=\\\"hi-txt\\\">🖼 गैलरी से चुनें</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">No stamp</span><span class=\\\"hi-txt\\\">स्टैम्प नहीं</span></span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"photoSrcCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- STORE PREVIEW DIALOG -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"store-preview-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:80vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"store-preview-title\\\"><span class=\\\"en-txt\\\">Preview Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची का प्रीव्यू</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Review before adding to your store list:</span><span class=\\\"hi-txt\\\">जोड़ने से पहले जाँचें:</span></div>\u001b[39m\n\u001b[31m    <div style=\\\"overflow-x:auto;margin-bottom:14px\\\">\u001b[39m\n\u001b[31m      <table style=\\\"width:100%;border-collapse:collapse;font-size:12px\\\">\u001b[39m\n\u001b[31m        <thead><tr style=\\\"background:var(--nv);color:#fff\\\">\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Address</span><span class=\\\"hi-txt\\\">पता</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Mobile</span><span class=\\\"hi-txt\\\">मोबाइल</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span></th>\u001b[39m\n\u001b[31m        </tr></thead>\u001b[39m\n\u001b[31m        <tbody id=\\\"store-preview-body\\\"></tbody>\u001b[39m\n\u001b[31m      </table>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"confirmStorePreview()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">✓ Confirm & Add Stores</span><span class=\\\"hi-txt\\\">✓ स्टोर जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"cancelStorePreview()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BOTTOM DIALOG (branding additional photo prompt) -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"bdialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add reference photos?</span><span class=\\\"hi-txt\\\">संदर्भ फोटो जोड़ें?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Add extra photos for this branding item for future reference.</span><span class=\\\"hi-txt\\\">इस ब्रांडिंग आइटम के लिए अतिरिक्त फोटो जोड़ें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"bdialogYes()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">Yes, add photos</span><span class=\\\"hi-txt\\\">हाँ, जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"bdialogNo()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Skip</span><span class=\\\"hi-txt\\\">छोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- DELETE REASON MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"delete-reason-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"padding-bottom:28px;max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">🗑 Delete Recce</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"del-modal-sub\\\">Select reason for deletion:</div>\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-wrong\\\" onclick=\\\"selectDeleteReason('wrong')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">❌</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Wrong</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Incorrect store / submission error</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-duplicate\\\" onclick=\\\"selectDeleteReason('duplicate')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">📋</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Duplicate</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Same store submitted more than once</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt danger\\\" id=\\\"reason-test\\\" onclick=\\\"selectDeleteReason('test')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">⚠️</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Test Recce</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:#9a3412;margin-top:2px\\\">Permanently deleted — no audit trail</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p no-reason\\\" id=\\\"del-confirm-btn\\\" onclick=\\\"confirmDelete()\\\" style=\\\"flex:2;padding:13px;background:var(--rd)\\\">Delete</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"closeDeleteModal()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EDIT REQUEST MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"edit-req-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Request Edit</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"er-store-name\\\" style=\\\"font-weight:600;color:var(--nv);margin-bottom:4px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:14px\\\">Add a note for the creator (optional)</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m      <textarea id=\\\"er-comment\\\" placeholder=\\\"e.g. Please re-check store address and re-upload front photo\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;color:var(--nv);resize:vertical;min-height:80px;background:#fff\\\"></textarea>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button id=\\\"er-assign-btn\\\" class=\\\"btn-p\\\" onclick=\\\"assignEditToCreator()\\\" style=\\\"padding:14px\\\">👤 Assign to Creator</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"supervisorEditMyself()\\\" style=\\\"padding:14px\\\">✏ Edit Myself</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"closeEditRequestModal()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BRAND EDIT MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"brand-edit-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Edit Brand</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Brand Name <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"text\\\" id=\\\"be-name\\\" placeholder=\\\"e.g. PHILIPS\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:600;text-transform:uppercase\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Logo URL <span style=\\\"font-size:11px;font-weight:400;color:var(--g400)\\\">(optional)</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"url\\\" id=\\\"be-logo\\\" placeholder=\\\"https://…/logo.svg\\\" oninput=\\\"previewBrandLogo()\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px\\\">\u001b[39m\n\u001b[31m      <div id=\\\"be-logo-preview\\\" style=\\\"margin-top:8px;min-height:36px;display:flex;align-items:center;gap:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"be-cascade-info\\\" style=\\\"display:none;font-size:12px;color:var(--g500);padding:8px 12px;background:var(--g50);border-radius:var(--rs);margin-bottom:12px\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"saveBrandEdit()\\\" style=\\\"padding:14px\\\">Save</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"closeBrandEditModal()\\\" style=\\\"width:100%;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FONT SIZE WIDGET -->\u001b[39m\n\u001b[31m<div class=\\\"fs-widget\\\" id=\\\"fs-widget\\\">\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-dec\\\" onclick=\\\"changeFontSize(-1)\\\" title=\\\"Decrease font size\\\" aria-label=\\\"Decrease font size\\\">A<sup style=\\\"font-size:9px\\\">−</sup></button>\u001b[39m\n\u001b[31m  <span class=\\\"fs-label\\\" id=\\\"fs-lbl\\\">A</span>\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-inc\\\" onclick=\\\"changeFontSize(1)\\\" title=\\\"Increase font size\\\" aria-label=\\\"Increase font size\\\"><strong>A</strong><sup style=\\\"font-size:9px\\\">+</sup></button>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"upd-banner\\\" id=\\\"upd-banner\\\">\u001b[39m\n\u001b[31m  <span style=\\\"font-size:13px;font-weight:600;line-height:1.4\\\"><span class=\\\"en-txt\\\">✓ App updated to latest version</span><span class=\\\"hi-txt\\\">✓ ऐप नया संस्करण अपडेट हुआ</span></span>\u001b[39m\n\u001b[31m  <button class=\\\"upd-banner-ok\\\" onclick=\\\"dismissUpdateBanner()\\\"><span class=\\\"en-txt\\\">OK</span><span class=\\\"hi-txt\\\">ठीक है</span></button>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m<div class=\\\"toast\\\" id=\\\"toast\\\"></div>\u001b[39m\n\u001b[31m<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js\\\"></script>\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m// LANGUAGE\u001b[39m\n\u001b[31mlet LANG = localStorage.getItem('recce-lang') || 'en';\u001b[39m\n\u001b[31mfunction setLang(l) {\u001b[39m\n\u001b[31m  LANG = l;\u001b[39m\n\u001b[31m  localStorage.setItem('recce-lang', l);\u001b[39m\n\u001b[31m  document.body.classList.toggle('lang-hi', l === 'hi');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction t(en, hi) { return LANG === 'hi' ? hi : en; }·\u001b[39m\n\u001b[31m// FONT SIZE\u001b[39m\n\u001b[31mlet FS_LEVEL = parseInt(localStorage.getItem('recce-fs') || '0', 10);\u001b[39m\n\u001b[31mconst FS_LABELS = ['A', 'A+', 'A++', 'A+++', 'A++++'];\u001b[39m\n\u001b[31mfunction applyFontSize() {\u001b[39m\n\u001b[31m  document.body.classList.remove('fs-0', 'fs-1', 'fs-2');\u001b[39m\n\u001b[31m  if (FS_LEVEL > 0) document.body.classList.add('fs-' + FS_LEVEL);\u001b[39m\n\u001b[31m  const lbl = document.getElementById('fs-lbl');\u001b[39m\n\u001b[31m  if (lbl) lbl.textContent = FS_LABELS[FS_LEVEL];\u001b[39m\n\u001b[31m  const dec = document.getElementById('fs-dec');\u001b[39m\n\u001b[31m  const inc = document.getElementById('fs-inc');\u001b[39m\n\u001b[31m  if (dec) dec.disabled = FS_LEVEL === 0;\u001b[39m\n\u001b[31m  if (inc) inc.disabled = FS_LEVEL === 4;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction changeFontSize(delta) {\u001b[39m\n\u001b[31m  FS_LEVEL = Math.min(4, Math.max(0, FS_LEVEL + delta));\u001b[39m\n\u001b[31m  localStorage.setItem('recce-fs', FS_LEVEL);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Hub auth gate\u001b[39m\n\u001b[31m(function() {\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (!s || !s.loginAt || Date.now() - new Date(s.loginAt).getTime() > 12 * 3600 * 1000) {\u001b[39m\n\u001b[31m      window.location.replace('/hub/');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) { window.location.replace('/hub/'); }\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31m// STATE\u001b[39m\n\u001b[31mlet F={},frontPhotos=[],insidePhotos=[],addlPhotos=[],brandings=[];\u001b[39m\n\u001b[31mlet videoBlob=null,submissionDoc=null,_docExistingUrl=null,gpsCoords=null;\u001b[39m\n\u001b[31mlet stores=[],selectedStore=null,manualMode=false,DB;\u001b[39m\n\u001b[31mlet imgQuality='compressed'; // 'compressed' | 'hd'\u001b[39m\n\u001b[31mlet geoStampEnabled=true;    // stamp GPS+timestamp on every photo\u001b[39m\n\u001b[31mlet brands=['PHILIPS']; // editable brand list\u001b[39m\n\u001b[31mlet _brandLogos={};   // name → logo_url, loaded from DB\u001b[39m\n\u001b[31mlet _selectedClient=''; // currently selected client chip value\u001b[39m\n\u001b[31mlet _clientOtherMode=false; // true when \\\"Other\\\" chip selected\u001b[39m\n\u001b[31mconst BTYPE=['Glow Sign Board','Inshop Branding','ACP Board','One Way Vision','Fabric Board','Lollypop','Non Lit Flex','Double Side GSB','Clip on Board','Translit','Vinyl Printing','Roll up Standee','Sunboard Standee'];\u001b[39m\n\u001b[31mconst CACHE_VER='recce-v37'; // campaign dropdown + pending job link tab·\u001b[39m\n\u001b[31m// DB\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',3);r.onupgradeneeded=e=>{const d=e.target.result;['subs','cfg','draft'].forEach(s=>{if(!d.objectStoreNames.contains(s))d.createObjectStore(s,{keyPath:'k'||'id'});});if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);});}\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',4);r.onupgradeneeded=e=>{const d=e.target.result;if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);})}\u001b[39m\n\u001b[31mfunction dbGet(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).get(k);r.onsuccess=()=>res(r.result);r.onerror=()=>res(null);}catch{res(null)}})}\u001b[39m\n\u001b[31mfunction dbPut(s,v){return new Promise((res,rej)=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).put(v);r.onsuccess=()=>res();r.onerror=()=>rej();}catch(e){rej(e)}})}\u001b[39m\n\u001b[31mfunction dbAll(s){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).getAll();r.onsuccess=()=>res(r.result);r.onerror=()=>res([]);}catch{res([])}})}\u001b[39m\n\u001b[31mfunction dbDel(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).delete(k);r.onsuccess=()=>res();r.onerror=()=>res();}catch{res()}})}\u001b[39m\n\u001b[31masync function cfg(k,v){if(v===undefined){const r=await dbGet('cfg',k);return r?r.v:null;}await dbPut('cfg',{k,v});}·\u001b[39m\n\u001b[31m// COMPRESS — respects imgQuality setting\u001b[39m\n\u001b[31mfunction compress(file, maxPxOverride, qOverride){\u001b[39m\n\u001b[31m  const maxPx = maxPxOverride || (imgQuality==='hd' ? 1920 : 1280);\u001b[39m\n\u001b[31m  const q     = qOverride     || (imgQuality==='hd' ? 0.90 : 0.78);\u001b[39m\n\u001b[31m  return new Promise(res=>{const img=new Image(),url=URL.createObjectURL(file);img.onload=()=>{const sc=Math.min(1,maxPx/Math.max(img.width,img.height));const c=document.createElement('canvas');c.width=Math.round(img.width*sc);c.height=Math.round(img.height*sc);c.getContext('2d').drawImage(img,0,0,c.width,c.height);URL.revokeObjectURL(url);c.toBlob(b=>res(b),'image/jpeg',q);};img.onerror=()=>{URL.revokeObjectURL(url);res(file)};img.src=url;});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction b64(blob){return new Promise(res=>{const r=new FileReader();r.onload=()=>res(r.result);r.readAsDataURL(blob)})}\u001b[39m\n\u001b[31mfunction fmtSz(b){if(b<1024)return b+'B';if(b<1048576)return(b/1024).toFixed(0)+'KB';return(b/1048576).toFixed(1)+'MB'}·\u001b[39m\n\u001b[31m// STORE LIST\u001b[39m\n\u001b[31mlet _storeFiles=[]; // track uploaded files {name, brand, count}\u001b[39m\n\u001b[31mlet _pendingParse=null; // parsed rows waiting for brand assignment·\u001b[39m\n\u001b[31mfunction parseStoreRow(row, keyFn){\u001b[39m\n\u001b[31m  const v=k=>{\u001b[39m\n\u001b[31m    // Try exact match first, then partial\u001b[39m\n\u001b[31m    const exactKey=Object.keys(row||{}).find(hk=>hk.toLowerCase()===k);\u001b[39m\n\u001b[31m    const partKey=Object.keys(row||{}).find(hk=>hk.toLowerCase().includes(k));\u001b[39m\n\u001b[31m    const useKey=exactKey||partKey;\u001b[39m\n\u001b[31m    if(useKey)return row[useKey]!=null?row[useKey].toString().trim():'';\u001b[39m\n\u001b[31m    // CSV path: keyFn provides value directly\u001b[39m\n\u001b[31m    const col=keyFn(k);return col!=null?col.toString().trim():'';\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const name    = v('sub dealer name')||v('sub dealer')||v('dealer name')||v('store name')||v('store')||v('name');\u001b[39m\n\u001b[31m  const address = v('address')||v('addr')||v('location')||v('area');\u001b[39m\n\u001b[31m  // Contact Detail often stored as a number — toString handles it\u001b[39m\n\u001b[31m  const rawMob  = v('contact detail')||v('contact no.')||v('contact no')||v('mobile no')||v('mobile')||v('phone')||v('mob')||v('contact');\u001b[39m\n\u001b[31m  const mobile  = rawMob.replace(/\\\\D/g,'').slice(-10);\u001b[39m\n\u001b[31m  // Brand: EXACT match only — \\\"Brand\\\" or \\\"Brand Name\\\" columns\u001b[39m\n\u001b[31m  // Partial match is intentionally avoided here because \\\"Inshop Branding\\\" contains \\\"brand\\\"\u001b[39m\n\u001b[31m  const brandKey=Object.keys(row||{}).find(hk=>{\u001b[39m\n\u001b[31m    const lk=hk.toLowerCase().trim();\u001b[39m\n\u001b[31m    return lk==='brand'||lk==='brand name'||lk==='brand_name'||lk==='brandname';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const brand=brandKey?(row[brandKey]||'').toString().trim().toUpperCase():'';\u001b[39m\n\u001b[31m  const distName= v('dist name')||v('distributor name')||v('distributor')||v('dist')||v('territory')||v('tsm')||v('asm');\u001b[39m\n\u001b[31m  const city    = v('city')||v('district')||v('town');\u001b[39m\n\u001b[31m  const sales   = v('2025 full year')||v('2025')||v('full year sales')||v('fy25')||v('sales');\u001b[39m\n\u001b[31m  const proj    = v('2026 projection')||v('2026')||v('projection')||v('fy26')||v('target');\u001b[39m\n\u001b[31m  const glowSign= v('glow sign')||v('glow');\u001b[39m\n\u001b[31m  const inshop  = v('inshop branding')||v('inshop')||v('in-shop')||v('in shop');\u001b[39m\n\u001b[31m  return {name, brand, address, mobile, distName, city, sales, proj, glowSign, inshop};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction dedupeStores(list){\u001b[39m\n\u001b[31m  const seen=new Map();\u001b[39m\n\u001b[31m  list.forEach(s=>{\u001b[39m\n\u001b[31m    // Include address in key — same store name at different locations = different stores\u001b[39m\n\u001b[31m    const key=(s.name.toLowerCase().trim())+'__'+(s.brand||'').toLowerCase()\u001b[39m\n\u001b[31m              +'__'+(s.address||'').toLowerCase().trim().slice(0,30);\u001b[39m\n\u001b[31m    if(!seen.has(key))seen.set(key,s);\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // True duplicate — merge missing fields from second record\u001b[39m\n\u001b[31m      const ex=seen.get(key);\u001b[39m\n\u001b[31m      Object.keys(s).forEach(k=>{ if(!ex[k]&&s[k])ex[k]=s[k]; });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  return Array.from(seen.values());\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderStoreFileList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-file-list');if(!el)return;\u001b[39m\n\u001b[31m  if(!_storeFiles.length){el.innerHTML='';return;}\u001b[39m\n\u001b[31m  el.innerHTML=_storeFiles.map((f,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:5px;font-size:12px\\\">\u001b[39m\n\u001b[31m      <div>\u001b[39m\n\u001b[31m        <span style=\\\"font-weight:600;color:var(--nv)\\\">${f.name}</span>\u001b[39m\n\u001b[31m        <span style=\\\"color:var(--g500);margin-left:6px\\\">${f.count} stores</span>\u001b[39m\n\u001b[31m        ${f.brand?`<span style=\\\"background:var(--nv);color:#fff;font-size:10px;font-weight:700;padding:1px 7px;border-radius:20px;margin-left:5px\\\">${f.brand}</span>`:'<span style=\\\"background:var(--g300);color:var(--g600);font-size:10px;padding:1px 7px;border-radius:20px;margin-left:5px\\\">Mixed brands</span>'}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <button onclick=\\\"removeStoreFile(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:17px;cursor:pointer;padding:0 4px;line-height:1\\\">×</button>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function removeStoreFile(i){\u001b[39m\n\u001b[31m  _storeFiles.splice(i,1);\u001b[39m\n\u001b[31m  // Rebuild stores from remaining files — re-parse from cache not possible, so just reload from DB and remove this file's contribution\u001b[39m\n\u001b[31m  // Simplest approach: clear and ask user to re-upload remaining files\u001b[39m\n\u001b[31m  if(!_storeFiles.length){stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    // Can't re-parse without original files; just note it and keep current store list\u001b[39m\n\u001b[31m    toast('Removed from list. Re-upload the remaining files to refresh store list.','info');\u001b[39m\n\u001b[31m    _storeFiles.splice(0); // clear tracking since we can't reconstruct\u001b[39m\n\u001b[31m    stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderStoreFileList();\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=stores.length?`✓ ${stores.length} stores`:'No stores loaded';\u001b[39m\n\u001b[31m  updAvailTag();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function clearStoreList(){\u001b[39m\n\u001b[31m  if(!confirm('Remove all loaded stores?'))return;\u001b[39m\n\u001b[31m  stores=[];_storeFiles=[];\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent='';\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast('Store list cleared','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function handleStoreUpload(e){\u001b[39m\n\u001b[31m  const file=e.target.files[0];if(!file)return;\u001b[39m\n\u001b[31m  e.target.value=''; // allow same file re-upload\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    let data=[];\u001b[39m\n\u001b[31m    if(file.name.toLowerCase().endsWith('.csv')){\u001b[39m\n\u001b[31m      const txt=await file.text();\u001b[39m\n\u001b[31m      const rows=txt.split('\\\\n').map(r=>r.split(',').map(c=>c.trim().replace(/^\\\"|\\\"$/g,'')));\u001b[39m\n\u001b[31m      if(!rows.length||!rows[0].length){toast('Empty CSV','error');return;}\u001b[39m\n\u001b[31m      const h=rows[0];\u001b[39m\n\u001b[31m      data=rows.slice(1).filter(r=>r.length>1&&r.some(c=>c)).map(r=>{\u001b[39m\n\u001b[31m        const rowObj={};h.forEach((hk,i)=>{rowObj[hk]=r[i]||'';});\u001b[39m\n\u001b[31m        return parseStoreRow(rowObj, ()=>'');\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }else{\u001b[39m\n\u001b[31m      const ab=await file.arrayBuffer();const wb=XLSX.read(ab,{type:'array'});\u001b[39m\n\u001b[31m      const js=XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]],{defval:''});\u001b[39m\n\u001b[31m      data=js.map(row=>parseStoreRow(row,()=>''));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    data=data.filter(d=>d.name.trim());\u001b[39m\n\u001b[31m    if(!data.length){toast('No valid rows found in file','error');return;}\u001b[39m\n\u001b[31m    // Check if any store has a brand\u001b[39m\n\u001b[31m    const hasBrand=data.some(d=>d.brand);\u001b[39m\n\u001b[31m    // Always show preview first before merging\u001b[39m\n\u001b[31m    _pendingParse={file:file.name,data,hasBrand};\u001b[39m\n\u001b[31m    showStorePreview(file.name, data, hasBrand);\u001b[39m\n\u001b[31m  }catch(err){toast('Failed: '+err.message,'error')}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mlet _pendingBrand='';\u001b[39m\n\u001b[31mfunction setPendingBrand(b){\u001b[39m\n\u001b[31m  _pendingBrand=b;\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-assign-chips .chip').forEach(c=>{\u001b[39m\n\u001b[31m    c.classList.toggle('sel',c.textContent===b);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  if(!_pendingBrand){toast('Select a brand first','error');return;}\u001b[39m\n\u001b[31m  // Assign brand to all rows in this file\u001b[39m\n\u001b[31m  const data=_pendingParse.data.map(s=>({...s,brand:_pendingBrand}));\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, data, _pendingBrand);\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function skipBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, _pendingParse.data, '');\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showStorePreview(filename, data, hasBrand){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-preview-dialog');\u001b[39m\n\u001b[31m  const tbody=document.getElementById('store-preview-body');\u001b[39m\n\u001b[31m  document.getElementById('store-preview-title').textContent=`${filename} · ${data.length} ${t('stores found','स्टोर मिले')}`;\u001b[39m\n\u001b[31m  // Show first 8 rows\u001b[39m\n\u001b[31m  const sample=data.slice(0,8);\u001b[39m\n\u001b[31m  tbody.innerHTML=sample.map(s=>`<tr>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;font-weight:500\\\">${s.name||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.address||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.mobile||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px\\\"><span style=\\\"background:${s.brand?'var(--nv)':'var(--rd)'};color:#fff;padding:1px 7px;border-radius:10px;font-size:10px\\\">${s.brand||'?'}</span></td>\u001b[39m\n\u001b[31m  </tr>`).join('');\u001b[39m\n\u001b[31m  if(data.length>8)tbody.innerHTML+=`<tr><td colspan=\\\"4\\\" style=\\\"text-align:center;padding:8px;font-size:12px;color:var(--g400)\\\">…and ${data.length-8} more stores</td></tr>`;\u001b[39m\n\u001b[31m  el.classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function confirmStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  const {file,data,hasBrand}=_pendingParse;\u001b[39m\n\u001b[31m  if(!hasBrand){\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-fname').textContent=`File: ${file} · ${data.length} stores found · No brand column detected`;\u001b[39m\n\u001b[31m    const chips=document.getElementById('brand-assign-chips');\u001b[39m\n\u001b[31m    chips.innerHTML=brands.map(b=>`<div class=\\\"chip\\\" onclick=\\\"setPendingBrand('${b}')\\\" id=\\\"bac-${b}\\\">${b}</div>`).join('');\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').style.display='block';\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    await mergeStores(file, data, '');\u001b[39m\n\u001b[31m    _pendingParse=null;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction cancelStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingParse=null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function mergeStores(filename, newData, assignedBrand){\u001b[39m\n\u001b[31m  const before=stores.length;\u001b[39m\n\u001b[31m  stores=[...stores,...newData];\u001b[39m\n\u001b[31m  stores=dedupeStores(stores);\u001b[39m\n\u001b[31m  const added=stores.length-before;\u001b[39m\n\u001b[31m  const dupes=newData.length-added;\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify(stores));\u001b[39m\n\u001b[31m  // Track file\u001b[39m\n\u001b[31m  _storeFiles.push({name:filename,count:newData.length,brand:assignedBrand||''});\u001b[39m\n\u001b[31m  await cfg('store-files',JSON.stringify(_storeFiles));\u001b[39m\n\u001b[31m  const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m    `✓ ${stores.length} total stores${dupes>0?` · ${dupes} duplicate${dupes>1?'s':''} removed`:''}${noBrand?` · ${noBrand} without brand`:' · All have brand'}`;\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast(`${added} stores added${dupes>0?`, ${dupes} duplicates skipped`:''}${assignedBrand?' as '+assignedBrand:''}`, 'success');\u001b[39m\n\u001b[31m  // Show server-push button for supervisors\u001b[39m\n\u001b[31m  const pb = document.getElementById('store-push-btn');\u001b[39m\n\u001b[31m  if (pb) pb.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function fetchServerStores(){const url=document.getElementById('srv-url').value.trim();if(!url){toast('Enter a URL first','error');return;}try{toast('Fetching…','info');const r=await fetch(url);const j=await r.json();const fetched=Array.isArray(j)?j:j.stores||[];await mergeStores('Server ('+url.split('/').pop()+')',fetched,'');await cfg('srv-url',url);}catch{toast('Fetch failed — check URL','error')}}\u001b[39m\n\u001b[31masync function saveServerUrl(){await cfg('srv-url',document.getElementById('srv-url').value.trim());toast('URL saved','success')}\u001b[39m\n\u001b[31mconst DEFAULT_GAS_URL='https://script.google.com/macros/s/AKfycbwyufC7gQyu1BErCxiDlbQUn0AWiIWv7nEmjk4UcAx3dvlV6bGk7q5fQOiv82CTbokbkA/exec';·\u001b[39m\n\u001b[31mconst DEFAULT_STORES_URL='/recce/stores.json';\u001b[39m\n\u001b[31mconst _RECCE_CFG_URL='/recce/recce-cfg.json';·\u001b[39m\n\u001b[31m// Admin auto-unlock for harish/pramod via hub session\u001b[39m\n\u001b[31mconst _RECCE_ADMIN_IDS = ['harish', 'pramod', 'rakesh'];\u001b[39m\n\u001b[31mconst _RECCE_CFG_ADMINS = ['harish', 'pramod'];\u001b[39m\n\u001b[31mlet _adminRows = [];\u001b[39m\n\u001b[31mlet _myServerRows = [];\u001b[39m\n\u001b[31mlet _adminUnlocked = false;\u001b[39m\n\u001b[31mlet _recceCfg = { version: 1, supervisors: ['harish','pramod','rakesh'], mode: 'public', creators: [], allowed_users: [] };\u001b[39m\n\u001b[31mfunction _isSupervisor() {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  return !!(hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId));\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _showDeletedView = false;\u001b[39m\n\u001b[31mlet _supCreateMode = false;\u001b[39m\n\u001b[31mlet _pendingDeleteId = null;\u001b[39m\n\u001b[31mlet _pendingDeleteReason = null;\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (s?.empId && _RECCE_ADMIN_IDS.includes(s.empId)) _adminUnlocked = true;\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31masync function loadRecceCfg(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(_RECCE_CFG_URL + '?t=' + Date.now());\u001b[39m\n\u001b[31m    if (r.ok) {\u001b[39m\n\u001b[31m      const j = await r.json();\u001b[39m\n\u001b[31m      if (j && j.version) {\u001b[39m\n\u001b[31m        _recceCfg = j;\u001b[39m\n\u001b[31m        if (Array.isArray(j.supervisors) && j.supervisors.length) {\u001b[39m\n\u001b[31m          _recceCfg.supervisors = j.supervisors;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.creators)) _recceCfg.creators = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.allowed_users)) _recceCfg.allowed_users = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.clients)) _recceCfg.clients = [];\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  // Re-check admin status against server supervisor list\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId)) {\u001b[39m\n\u001b[31m    _adminUnlocked = true;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _checkAccessMode(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (_recceCfg.mode !== 'assigned') return;\u001b[39m\n\u001b[31m  const allowed = [\u001b[39m\n\u001b[31m    ...(_recceCfg.supervisors || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.creators || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.allowed_users || []),\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  if (hub?.empId && allowed.includes(hub.empId)) return;\u001b[39m\n\u001b[31m  // Block access — show locked overlay\u001b[39m\n\u001b[31m  document.body.innerHTML = `<div style=\\\"min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0f172a;color:#fff;padding:32px;text-align:center\\\"><div style=\\\"font-size:48px;margin-bottom:16px\\\">🔒</div><div style=\\\"font-size:20px;font-weight:700;margin-bottom:8px\\\">${t('Access Restricted','एक्सेस प्रतिबंधित')}</div><div style=\\\"font-size:14px;color:#94a3b8\\\">${t('You are not authorised to use Branding Recce. Please contact your supervisor.','आप ब्रांडिंग रेक्की उपयोग के लिए अधिकृत नहीं हैं।')}</div></div>`;\u001b[39m\n\u001b[31m  throw new Error('access-restricted');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _recceHubUser() {\u001b[39m\n\u001b[31m  try { return JSON.parse(localStorage.getItem('lm360-session') || '{}'); }\u001b[39m\n\u001b[31m  catch(_) { return {}; }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── Supervisor config management ────────────────────────────────────\u001b[39m\n\u001b[31mfunction renderSupPanel(){\u001b[39m\n\u001b[31m  if (!_adminUnlocked) return;\u001b[39m\n\u001b[31m  const panel = document.getElementById('sup-panel');\u001b[39m\n\u001b[31m  if (panel) panel.style.display = 'block';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const modePublic = document.getElementById('mode-public');\u001b[39m\n\u001b[31m  const modeAssigned = document.getElementById('mode-assigned');\u001b[39m\n\u001b[31m  if (modePublic && modeAssigned) {\u001b[39m\n\u001b[31m    modePublic.classList.toggle('sel', _recceCfg.mode !== 'assigned');\u001b[39m\n\u001b[31m    modeAssigned.classList.toggle('sel', _recceCfg.mode === 'assigned');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  const addRow = document.getElementById('sup-add-row');\u001b[39m\n\u001b[31m  if (addRow) addRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const creatorAddRow = document.getElementById('creator-add-row');\u001b[39m\n\u001b[31m  if (creatorAddRow) creatorAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const clientAddRow = document.getElementById('client-add-row');\u001b[39m\n\u001b[31m  if (clientAddRow) clientAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const modeRow = document.getElementById('mode-row');\u001b[39m\n\u001b[31m  if (modeRow) {\u001b[39m\n\u001b[31m    modeRow.style.display = 'block';\u001b[39m\n\u001b[31m    // Non-cfg-admins see mode as read-only (toggles exist but setRecceMode guards them)\u001b[39m\n\u001b[31m    modeRow.style.opacity = isCfgAdmin ? '1' : '0.65';\u001b[39m\n\u001b[31m    modeRow.style.pointerEvents = isCfgAdmin ? '' : 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const syncBtn = document.getElementById('cfg-sync-btn');\u001b[39m\n\u001b[31m  if (syncBtn) syncBtn.style.display = isCfgAdmin ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('sup-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const sups = _recceCfg.supervisors || [];\u001b[39m\n\u001b[31m  el.innerHTML = sups.map((s,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${s}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin && sups.length > 1 ? `<button onclick=\\\"removeSupervisor(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderCreatorsList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('creator-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const creators = _recceCfg.creators || [];\u001b[39m\n\u001b[31m  el.innerHTML = creators.length ? creators.map((u,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${u}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeCreator(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No creators yet — any Hub user can submit in Public mode.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setRecceMode(mode){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.mode = mode;\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addSupervisor(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('sup-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.supervisors = [...(_recceCfg.supervisors || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeSupervisor(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.supervisors = (_recceCfg.supervisors || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addCreator(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('creator-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.creators || []).includes(val)) { toast(t('Already a creator','पहले से क्रिएटर है'), 'info'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor (includes creation rights)','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.creators = [...(_recceCfg.creators || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeCreator(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.creators = (_recceCfg.creators || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderClientMgmtList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('client-mgmt-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const list = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  el.innerHTML = list.length ? list.map((c,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${esc(c)}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeClientFromList(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No clients yet — add client or agency names to show them as chips in the form.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addClientToList(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('client-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter client name','क्लाइंट नाम दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.clients || []).includes(val)) { toast(t('Already in list','पहले से मौजूद है'), 'info'); return; }\u001b[39m\n\u001b[31m  if (!_recceCfg.clients) _recceCfg.clients = [];\u001b[39m\n\u001b[31m  _recceCfg.clients.push(val);\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeClientFromList(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.clients = (_recceCfg.clients || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncCfgToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast(t('Not authorised','अधिकृत नहीं'), 'error'); return; }\u001b[39m\n\u001b[31m  const st = document.getElementById('cfg-sync-status');\u001b[39m\n\u001b[31m  if (st) st.textContent = t('Syncing…','सिंक हो रहा है…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-cfg', empId: hub.empId, cfg: {\u001b[39m\n\u001b[31m        version: _recceCfg.version || 1,\u001b[39m\n\u001b[31m        supervisors: _recceCfg.supervisors || [],\u001b[39m\n\u001b[31m        mode: _recceCfg.mode || 'public',\u001b[39m\n\u001b[31m        creators: _recceCfg.creators || [],\u001b[39m\n\u001b[31m        allowed_users: _recceCfg.allowed_users || [],\u001b[39m\n\u001b[31m        clients: _recceCfg.clients || [],\u001b[39m\n\u001b[31m      }})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) {\u001b[39m\n\u001b[31m      toast(t('Config synced to server ✓','कॉन्फ़िग सर्वर पर सेव हुआ ✓'), 'success');\u001b[39m\n\u001b[31m      if (st) st.textContent = t('Last synced: just now','अभी सिंक हुआ');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast(j.error || t('Sync failed','सिंक विफल'), 'error');\u001b[39m\n\u001b[31m      if (st) st.textContent = j.error || '';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Network error','नेटवर्क त्रुटि'), 'error');\u001b[39m\n\u001b[31m    if (st) st.textContent = e.message;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function pushStoresToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!hub?.empId || !_adminUnlocked) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-stores', empId: hub.empId, stores })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) toast(`${t('Pushed to server','सर्वर पर पुश हुआ')} · ${j.count} ${t('stores','स्टोर')}`, 'success');\u001b[39m\n\u001b[31m    else toast(j.error || t('Server push failed','सर्वर पुश विफल'), 'error');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Could not reach server','सर्वर से संपर्क नहीं हो सका'), 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── End supervisor config management ────────────────────────────────·\u001b[39m\n\u001b[31m// PostgREST sync constants\u001b[39m\n\u001b[31mconst _RC_BASE      = '/db';\u001b[39m\n\u001b[31mconst _RC_READ      = { 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_WRITE     = { 'Content-Type': 'application/json', 'Content-Profile': 'recce', 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_UPSERT    = { ..._RC_WRITE, 'Prefer': 'resolution=merge-duplicates,return=minimal' };\u001b[39m\n\u001b[31mconst _INSTALL_RD   = { 'Content-Type': 'application/json', 'Accept-Profile': 'installation' };\u001b[39m\n\u001b[31mconst _INSTALL_WR   = { 'Content-Type': 'application/json', 'Content-Profile': 'installation', 'Accept-Profile': 'installation', 'Prefer': 'return=minimal' };·\u001b[39m\n\u001b[31m// ── Campaign selection state ──\u001b[39m\n\u001b[31mlet _selectedCampaignId = null;\u001b[39m\n\u001b[31mlet _notifySupervisor   = false;\u001b[39m\n\u001b[31mlet _campaignList       = [];\u001b[39m\n\u001b[31mlet _pendingJobFilter   = false;\u001b[39m\n\u001b[31mlet _linkJobSubId       = null;\u001b[39m\n\u001b[31mlet _brandingLocked     = false;·\u001b[39m\n\u001b[31mfunction _updateBrandingLock() {\u001b[39m\n\u001b[31m  const hub  = _recceHubUser();\u001b[39m\n\u001b[31m  const isHP = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const banner   = document.getElementById('branding-lock-banner');\u001b[39m\n\u001b[31m  const ovWrap   = document.getElementById('branding-override-wrap');\u001b[39m\n\u001b[31m  const brItems  = document.getElementById('br-items');\u001b[39m\n\u001b[31m  const brAdd    = document.getElementById('br-add');\u001b[39m\n\u001b[31m  const brYes    = document.getElementById('br-yes');\u001b[39m\n\u001b[31m  const brNo     = document.getElementById('br-no');\u001b[39m\n\u001b[31m  if (!banner) return;\u001b[39m\n\u001b[31m  if (_brandingLocked) {\u001b[39m\n\u001b[31m    banner.style.display   = '';\u001b[39m\n\u001b[31m    if (ovWrap)  ovWrap.style.display  = isHP ? '' : 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.pointerEvents = 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.opacity = '0.55';\u001b[39m\n\u001b[31m    if (brAdd)   brAdd.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='none'; brYes.style.opacity='0.5'; }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='none';  brNo.style.opacity='0.5';  }\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    banner.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brItems) { brItems.style.pointerEvents=''; brItems.style.opacity=''; }\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='';  brYes.style.opacity='';   }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='';   brNo.style.opacity='';    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction unlockBrandingOverride() {\u001b[39m\n\u001b[31m  if (!confirm(\u001b[39m\n\u001b[31m    'Client has already reviewed this recce.\\\\n' +\u001b[39m\n\u001b[31m    'Editing brandings will NOT remove their approval.\\\\n' +\u001b[39m\n\u001b[31m    'Continue ONLY if the client has verbally confirmed. Proceed?'\u001b[39m\n\u001b[31m  )) return;\u001b[39m\n\u001b[31m  _brandingLocked = false;\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  renderBrandings();\u001b[39m\n\u001b[31m  toast(t('Branding unlocked for this session', 'ब्रांडिंग इस सत्र के लिए अनलॉक'), 'info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadCampaignsForForm() {\u001b[39m\n\u001b[31m  const sel = document.getElementById('f-campaign-id');\u001b[39m\n\u001b[31m  if (!sel) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m    _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m  } catch(_) { _campaignList = []; }\u001b[39m\n\u001b[31m  sel.innerHTML =\u001b[39m\n\u001b[31m    '<option value=\\\"\\\">— Select job / campaign (optional) —</option>' +\u001b[39m\n\u001b[31m    _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('') +\u001b[39m\n\u001b[31m    '<option value=\\\"__NOTIFY__\\\">⚑ No campaign yet — notify supervisor</option>';\u001b[39m\n\u001b[31m  if (_selectedCampaignId) sel.value = _selectedCampaignId;\u001b[39m\n\u001b[31m  else if (_notifySupervisor) sel.value = '__NOTIFY__';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onCampaignSelect() {\u001b[39m\n\u001b[31m  const val = document.getElementById('f-campaign-id')?.value || '';\u001b[39m\n\u001b[31m  const noticeEl = document.getElementById('campaign-notify-msg');\u001b[39m\n\u001b[31m  if (val === '__NOTIFY__') {\u001b[39m\n\u001b[31m    _selectedCampaignId = null;\u001b[39m\n\u001b[31m    _notifySupervisor   = true;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'block';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    _selectedCampaignId = val || null;\u001b[39m\n\u001b[31m    _notifySupervisor   = false;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction generateRecceReportHtml(entry, photoUrls) {\u001b[39m\n\u001b[31m  const d    = entry.data || {};\u001b[39m\n\u001b[31m  const urls = photoUrls || {};\u001b[39m\n\u001b[31m  const agent = entry.submittedByName || entry.submittedBy || 'Field Agent';\u001b[39m\n\u001b[31m  const _safeId      = (entry.id||'').replace(/\\\\//g,'_').replace(/\\\\.\\\\./g,'');\u001b[39m\n\u001b[31m  const serverPdfUrl = _safeId ? `https://srv1111289.hstgr.cloud/screenshots/recce/views/${_safeId}.pdf` : '';\u001b[39m\n\u001b[31m  const brandLogoUrl = d.brandLogoUrl || _brandLogos[d.brand] || '';\u001b[39m\n\u001b[31m  const tsStr = new Date(entry.timestamp).toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric',hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\u001b[39m\n\u001b[31m  const gpsUrl = d.gpsCoords ? `https://maps.google.com/?q=${d.gpsCoords.lat},${d.gpsCoords.lng}` : null;·\u001b[39m\n\u001b[31m  const frontCount  = (urls.front||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const insideCount = (urls.inside||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const addlCount   = (urls.addl||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const brCount     = (d.brandings||[]).length;·\u001b[39m\n\u001b[31m  // pages: { id, url, bandHtml, cmt, dotLabel, dotColor }\u001b[39m\n\u001b[31m  const pages = [];·\u001b[39m\n\u001b[31m  (urls.front||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Front View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${frontCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.frontPhotos||[])[i]?.cmt||'', dotLabel:`FV${i+1}`, dotColor:'#3b82f6', catLabel:'Front View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.inside||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Inside View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${insideCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.insidePhotos||[])[i]?.cmt||'', dotLabel:`IV${i+1}`, dotColor:'#14b8a6', catLabel:'Inside View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (d.brandings||[]).forEach((b,i)=>{\u001b[39m\n\u001b[31m    const url=(urls.brandings||[])[i]; if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">${esc(b.type||'Branding')}</div><div class=\\\"ph-dims\\\">Width : ${esc(b.w||'?')}&Prime;&nbsp;&times;&nbsp;Height : ${esc(b.h||'?')}&Prime;&nbsp;&mdash;&nbsp;${esc(b.qty||1)} Nos</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${brCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:'', dotLabel:`B${i+1}`, dotColor:'#f97316', catLabel:b.type||'Branding',\u001b[39m\n\u001b[31m      tileDims:`${b.w||'?'}″×${b.h||'?'}″ — ${String(b.qty||1).padStart(2,'0')} Nos` });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.addl||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Additional</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${addlCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.addlPhotos||[])[i]?.desc||'', dotLabel:`A${i+1}`, dotColor:'#94a3b8', catLabel:'Additional', tileDims:'' });\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const sideItems = [\u001b[39m\n\u001b[31m    `<div class=\\\"si-item active\\\" data-tgt=\\\"pg-cover\\\" title=\\\"Cover\\\"><div class=\\\"si-dot\\\" style=\\\"background:#475569\\\">CV</div></div>`\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  pages.forEach(p => {\u001b[39m\n\u001b[31m    sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"${p.id}\\\" title=\\\"${p.dotLabel}\\\"><div class=\\\"si-dot\\\" style=\\\"background:${p.dotColor}\\\">${p.dotLabel}</div></div>`);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(d.hasVideo) sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-vid\\\" title=\\\"Video\\\"><div class=\\\"si-dot\\\" style=\\\"background:#a855f7\\\">VD</div></div>`);\u001b[39m\n\u001b[31m  if(urls.doc)   sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-doc\\\" title=\\\"Document\\\"><div class=\\\"si-dot\\\" style=\\\"background:#64748b\\\">DC</div></div>`);·\u001b[39m\n\u001b[31m  const thumbItems = [\u001b[39m\n\u001b[31m    ...pages,\u001b[39m\n\u001b[31m    ...(d.hasVideo?[{id:'pg-vid',url:null,catLabel:'Video',tileDims:'',dotLabel:'VD',dotColor:'#a855f7'}]:[]),\u001b[39m\n\u001b[31m    ...(urls.doc?[{id:'pg-doc',url:urls.doc,catLabel:'Document',tileDims:'',dotLabel:'DC',dotColor:'#64748b'}]:[])\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  const thumbsHtml = thumbItems.map(p=>`<div class=\\\"cov-thumb\\\" onclick=\\\"document.getElementById('${p.id}').scrollIntoView({behavior:'smooth'})\\\">${p.url?`<img src=\\\"${p.url}\\\" alt=\\\"\\\">`:(`<div class=\\\"cov-thumb-vid\\\">${p.catLabel==='Video'?'&#x25B6;&#xFE0F;':'&#x1F4C4;'}</div>`)}<div class=\\\"cov-thumb-ov\\\" style=\\\"border-top:3px solid ${p.dotColor}\\\"><div class=\\\"cov-thumb-cat\\\">${esc(p.catLabel)}</div>${p.tileDims?`<div class=\\\"cov-thumb-dims\\\">${esc(p.tileDims)}</div>`:''}<div class=\\\"cov-thumb-no\\\">${p.dotLabel}</div></div></div>`).join('');·\u001b[39m\n\u001b[31m  const pagesHtml = pages.map(p => `\u001b[39m\n\u001b[31m<div class=\\\"photo-page\\\" id=\\\"${p.id}\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\">${p.bandHtml}</div>\u001b[39m\n\u001b[31m  <div class=\\\"ph-img\\\"><a href=\\\"${p.url}\\\" target=\\\"_blank\\\"><img src=\\\"${p.url}\\\" loading=\\\"lazy\\\" alt=\\\"\\\"></a>${p.cmt?`<div class=\\\"ph-cmt\\\">${esc(p.cmt)}</div>`:''}</div>\u001b[39m\n\u001b[31m</div>`).join('');·\u001b[39m\n\u001b[31m  return `<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\"><head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m<title>Recce — ${esc(d.storeName||'Unknown')} · ${esc(d.brand||'')}</title>\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--dk:#0f172a;--nv2:#1a2f52;--or:#f97316;--g200:#e2e8f0;--g400:#94a3b8;--g600:#475569;--si:54px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0}\u001b[39m\n\u001b[31mhtml,body{height:100%;overflow:hidden}\u001b[39m\n\u001b[31mbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#111;color:var(--dk);display:flex}\u001b[39m\n\u001b[31ma{color:var(--or);text-decoration:none}\u001b[39m\n\u001b[31mimg{display:block}·\u001b[39m\n\u001b[31m/* ── Side index ── */\u001b[39m\n\u001b[31m.side-idx{width:var(--si);flex-shrink:0;background:var(--dk);overflow-y:auto;display:flex;flex-direction:column;align-items:center;padding:4px 0;scrollbar-width:none;z-index:50}\u001b[39m\n\u001b[31m.side-idx::-webkit-scrollbar{display:none}\u001b[39m\n\u001b[31m.si-item{width:100%;min-height:56px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s}\u001b[39m\n\u001b[31m.si-item:hover{background:rgba(255,255,255,.07)}\u001b[39m\n\u001b[31m.si-dot{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff;opacity:.4;transition:opacity .18s,transform .18s;line-height:1;text-align:center}\u001b[39m\n\u001b[31m.si-item.active .si-dot{opacity:1;transform:scale(1.15)}·\u001b[39m\n\u001b[31m/* ── Main scroll area ── */\u001b[39m\n\u001b[31m.main{flex:1;overflow-y:scroll;scroll-snap-type:y mandatory;scroll-behavior:smooth;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar{width:3px}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15)}·\u001b[39m\n\u001b[31m/* ── Cover ── */\u001b[39m\n\u001b[31m.cover{height:100vh;scroll-snap-align:start;flex-shrink:0;background:linear-gradient(135deg,#0f172a 0%,var(--nv2) 100%);color:#fff;display:flex;flex-direction:column;padding:24px 20px 20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.cover-badge{display:inline-flex;align-items:center;gap:5px;background:var(--or);color:#fff;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:1px;padding:3px 12px;border-radius:20px;margin-bottom:12px;align-self:flex-start}\u001b[39m\n\u001b[31m.cover h1{font-size:20px;font-weight:700;line-height:1.3;margin-bottom:4px}\u001b[39m\n\u001b[31m.cover-addr{color:rgba(255,255,255,.55);font-size:12px;margin-bottom:16px}\u001b[39m\n\u001b[31m.cg{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}\u001b[39m\n\u001b[31m.cm{background:rgba(255,255,255,.08);border-radius:8px;padding:8px 12px}\u001b[39m\n\u001b[31m.cm-l{font-size:9px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}\u001b[39m\n\u001b[31m.cm-v{font-size:13px;font-weight:600;color:#fff}\u001b[39m\n\u001b[31m.cm-v a{color:#fb923c}\u001b[39m\n\u001b[31m.cover-pbar{padding-top:8px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{background:var(--or);color:#fff;border:none;padding:10px 22px;border-radius:22px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}\u001b[39m\n\u001b[31m.btn-p:disabled{opacity:.4;cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-c{background:rgba(255,255,255,.1);color:rgba(255,255,255,.75);border:1px solid rgba(255,255,255,.2);padding:10px 18px;border-radius:22px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit}·\u001b[39m\n\u001b[31m/* ── Cover thumbnail grid ── */\u001b[39m\n\u001b[31m.cov-grid-hdr{font-size:10px;font-weight:700;color:rgba(255,255,255,.35);text-transform:uppercase;letter-spacing:1.2px;padding:10px 0 5px;flex-shrink:0}\u001b[39m\n\u001b[31m.cov-grid{flex:1;min-height:0;display:grid;gap:5px;overflow:hidden;align-content:start}\u001b[39m\n\u001b[31m.cov-thumb{position:relative;overflow:hidden;border-radius:7px;cursor:pointer;background:#1e293b;transition:transform .18s,box-shadow .18s}\u001b[39m\n\u001b[31m.cov-thumb:hover{transform:scale(1.05);box-shadow:0 4px 18px rgba(0,0,0,.55)}\u001b[39m\n\u001b[31m.cov-thumb img{width:100%;height:100%;object-fit:cover;display:block}\u001b[39m\n\u001b[31m.cov-thumb-vid{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:#0f172a}\u001b[39m\n\u001b[31m.cov-thumb-ov{position:absolute;inset:0;background:rgba(0,0,0,.28);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:5px;border-radius:7px}\u001b[39m\n\u001b[31m.cov-thumb-cat{color:rgba(255,255,255,.5);font-weight:900;text-align:center;text-transform:uppercase;letter-spacing:.8px;text-shadow:0 1px 6px rgba(0,0,0,.95);line-height:1.2;word-break:break-word}\u001b[39m\n\u001b[31m.cov-thumb-dims{color:rgba(255,255,255,.5);font-weight:700;text-align:center;text-shadow:0 1px 5px rgba(0,0,0,.95);letter-spacing:.3px;line-height:1.3}\u001b[39m\n\u001b[31m.cov-thumb-no{color:rgba(255,255,255,.5);font-weight:800;text-shadow:0 1px 4px rgba(0,0,0,.95);letter-spacing:.5px}\u001b[39m\n\u001b[31m#cover-btn{position:fixed;bottom:20px;right:16px;display:none;align-items:center;gap:6px;background:rgba(255,255,255,.15);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.25);color:#fff;padding:10px 22px;border-radius:50px;font-size:13px;font-weight:700;cursor:pointer;z-index:200;letter-spacing:.3px;box-shadow:0 2px 12px rgba(0,0,0,.3);font-family:inherit;transition:background .15s,transform .15s}\u001b[39m\n\u001b[31m#cover-btn:hover{background:rgba(255,255,255,.22);transform:scale(1.04)}·\u001b[39m\n\u001b[31m/* ── Print wait overlay ── */\u001b[39m\n\u001b[31m#print-overlay{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m@media print{#print-overlay{display:none!important}}·\u001b[39m\n\u001b[31m/* ── Loading progress bar ── */\u001b[39m\n\u001b[31m.load-bar{position:fixed;bottom:0;left:0;right:0;background:rgba(15,23,42,.95);padding:9px 16px;z-index:9999;display:flex;align-items:center;gap:12px;backdrop-filter:blur(6px)}\u001b[39m\n\u001b[31m.load-track{flex:1;height:5px;background:rgba(255,255,255,.12);border-radius:3px;overflow:hidden}\u001b[39m\n\u001b[31m.load-fill{height:100%;background:var(--or);width:0%;transition:width .35s ease;border-radius:3px}\u001b[39m\n\u001b[31m.load-txt{font-size:11px;color:rgba(255,255,255,.6);white-space:nowrap;min-width:160px}·\u001b[39m\n\u001b[31m/* ── Photo page ── */\u001b[39m\n\u001b[31m.photo-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ph-band{background:var(--dk);padding:16px 26px;flex-shrink:0;display:flex;align-items:center;gap:20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.ph-cat{font-size:35px;font-weight:800;color:#fff;letter-spacing:-.5px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.ph-dims{flex:1;font-size:18px;font-weight:600;color:var(--or);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}\u001b[39m\n\u001b[31m.ph-no{margin-left:auto;flex-shrink:0;font-size:21px;font-weight:700;color:rgba(255,255,255,.85);background:rgba(255,255,255,.1);padding:5px 20px;border-radius:24px;white-space:nowrap}\u001b[39m\n\u001b[31m.ph-of{font-size:18px;font-weight:400;color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.ph-img{flex:1;overflow:hidden;position:relative;background:#111}\u001b[39m\n\u001b[31m.ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m.ph-img img{width:100%;height:100%;object-fit:contain;display:block}\u001b[39m\n\u001b[31m.ph-cmt{position:absolute;bottom:0;left:0;right:0;padding:6px 14px;background:rgba(0,0,0,.62);font-size:11px;color:rgba(255,255,255,.75);font-style:italic;pointer-events:none}·\u001b[39m\n\u001b[31m/* ── Video / Doc pages ── */\u001b[39m\n\u001b[31m.vid-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;background:#fff}\u001b[39m\n\u001b[31m.vid-body{flex:1;padding:20px 24px;font-size:14px;color:var(--g600);border-left:4px solid var(--or)}\u001b[39m\n\u001b[31m.vid-body em{display:block;font-size:12px;color:var(--g400);margin-top:6px}\u001b[39m\n\u001b[31m.doc-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m.doc-wrap{flex:1;display:flex;align-items:center;justify-content:center;background:#111;overflow:hidden}\u001b[39m\n\u001b[31m.doc-img{max-width:100%;max-height:100%;object-fit:contain}·\u001b[39m\n\u001b[31m/* ── Cover header band ── */\u001b[39m\n\u001b[31m.cov-hdr{display:flex;gap:0;margin-bottom:12px;flex-shrink:0;border-radius:10px;overflow:hidden;border:1px solid rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.cov-hdr-l{flex:1;padding:14px 18px;display:flex;flex-direction:column;gap:5px;border-right:1px solid rgba(255,255,255,.1);min-width:0}\u001b[39m\n\u001b[31m.cov-hdr-r{width:170px;flex-shrink:0;padding:14px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:rgba(255,255,255,.04)}\u001b[39m\n\u001b[31m.cov-store{font-size:18px;font-weight:800;color:#fff;line-height:1.25;margin-bottom:2px}\u001b[39m\n\u001b[31m.cov-meta{font-size:12px;color:rgba(255,255,255,.55);display:flex;align-items:center;gap:5px;line-height:1.5}\u001b[39m\n\u001b[31m.cov-brand{background:var(--or);color:#fff;font-size:13px;font-weight:800;padding:5px 16px;border-radius:20px;text-align:center;letter-spacing:.3px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\u001b[39m\n\u001b[31m.cov-date-l{font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.8px;margin-bottom:2px;text-align:center}\u001b[39m\n\u001b[31m.cov-date-v{font-size:13px;font-weight:700;color:#fff;text-align:center}\u001b[39m\n\u001b[31m.cov-logo-box{background:#fff;border-radius:8px;padding:8px 14px;display:flex;align-items:center;justify-content:center;width:100%;max-width:138px}\u001b[39m\n\u001b[31m.cov-logo-box img{max-width:110px;max-height:44px;object-fit:contain;display:block}·\u001b[39m\n\u001b[31m/* ── Print ── */\u001b[39m\n\u001b[31m@page{size:A4 landscape;margin:12mm}\u001b[39m\n\u001b[31m@media print{\u001b[39m\n\u001b[31m  html,body{height:auto;overflow:visible;display:block}\u001b[39m\n\u001b[31m  .side-idx{display:none}\u001b[39m\n\u001b[31m  .main{overflow:visible;display:block;height:auto;scroll-snap-type:none}\u001b[39m\n\u001b[31m  .cover,.vid-page,.doc-page{height:auto;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m  .photo-page{height:186mm;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m  .cover{padding:20px 24px}\u001b[39m\n\u001b[31m  .cover-pbar{display:none}\u001b[39m\n\u001b[31m  .cov-hdr{margin-bottom:8px;border-radius:7px}\u001b[39m\n\u001b[31m  .cov-hdr-l{padding:10px 14px}\u001b[39m\n\u001b[31m  .cov-hdr-r{padding:10px 12px;width:150px}\u001b[39m\n\u001b[31m  .cov-store{font-size:15px}\u001b[39m\n\u001b[31m  .cov-meta{font-size:10px}\u001b[39m\n\u001b[31m  .cov-brand{font-size:11px;padding:3px 12px}\u001b[39m\n\u001b[31m  .cov-date-v{font-size:11px}\u001b[39m\n\u001b[31m  .ph-band{padding:5mm 13mm;gap:10mm}\u001b[39m\n\u001b[31m  .ph-cat{font-size:15mm}\u001b[39m\n\u001b[31m  .ph-dims{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-no{font-size:12mm;padding:2mm 8mm}\u001b[39m\n\u001b[31m  .ph-of{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-img{flex:1;display:flex;align-items:center;justify-content:center;background:#fff;overflow:hidden}\u001b[39m\n\u001b[31m  .ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m  .ph-img img{width:100%;height:100%;object-fit:contain}\u001b[39m\n\u001b[31m  .ph-cmt{position:static;background:transparent;color:#475569;padding:2mm 8mm;font-size:6mm}\u001b[39m\n\u001b[31m  .main>*:last-child{page-break-after:avoid;break-after:avoid}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m</style></head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<div class=\\\"side-idx\\\" id=\\\"side-idx\\\">${sideItems.join('')}</div>·\u001b[39m\n\u001b[31m<div class=\\\"main\\\" id=\\\"main\\\">·\u001b[39m\n\u001b[31m<div class=\\\"cover\\\" id=\\\"pg-cover\\\">\u001b[39m\n\u001b[31m  <div class=\\\"cov-hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-l\\\">\u001b[39m\n\u001b[31m      <div class=\\\"cov-store\\\">${esc(d.storeName||'Unknown Store')}</div>\u001b[39m\n\u001b[31m      ${(d.address||d.city)?`<div class=\\\"cov-meta\\\">&#x1F4CD; ${esc(d.address||'')}${d.city&&!(d.address||'').includes(d.city)?', '+esc(d.city):''}</div>`:''}\u001b[39m\n\u001b[31m      ${d.mobile?`<div class=\\\"cov-meta\\\">&#x1F4DE; ${esc(d.mobile)}</div>`:''}\u001b[39m\n\u001b[31m      ${d.email?`<div class=\\\"cov-meta\\\">&#x2709; ${esc(d.email)}</div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-r\\\">\u001b[39m\n\u001b[31m      ${brandLogoUrl\u001b[39m\n\u001b[31m        ? `<div class=\\\"cov-logo-box\\\"><img src=\\\"${brandLogoUrl}\\\" alt=\\\"${esc(d.brand||'')}\\\"></div>`\u001b[39m\n\u001b[31m        : (d.brand?`<div class=\\\"cov-brand\\\">${esc(d.brand)}</div>`:'')}\u001b[39m\n\u001b[31m      ${d.date?`<div><div class=\\\"cov-date-l\\\">Recce Date</div><div class=\\\"cov-date-v\\\">${esc(d.date)}</div></div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${thumbItems.length ? `<div class=\\\"cov-grid-hdr\\\">&#x1F4F7; ${thumbItems.length} page${thumbItems.length!==1?'s':''} &mdash; tap any to jump</div><div class=\\\"cov-grid\\\" id=\\\"cov-grid\\\">${thumbsHtml}</div>` : ''}\u001b[39m\n\u001b[31m  <div class=\\\"cover-pbar\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" id=\\\"btn-print\\\" onclick=\\\"doPDF()\\\">&#x1F4C4;&nbsp;PDF</button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-c\\\" onclick=\\\"window.close()\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m${pagesHtml}·\u001b[39m\n\u001b[31m${d.hasVideo?`\u001b[39m\n\u001b[31m<div class=\\\"vid-page\\\" id=\\\"pg-vid\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Video</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"vid-body\\\">${esc(d.videoNote||'Video recorded during visit')}${d.videoCmt?`<em>${esc(d.videoCmt)}</em>`:''}</div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m${urls.doc?`\u001b[39m\n\u001b[31m<div class=\\\"doc-page\\\" id=\\\"pg-doc\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Document</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"doc-wrap\\\"><a href=\\\"${urls.doc}\\\" target=\\\"_blank\\\"><img class=\\\"doc-img\\\" src=\\\"${urls.doc}\\\" loading=\\\"lazy\\\" alt=\\\"Document\\\"></a></div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"print-overlay\\\"><div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Preparing print&hellip;</div><div class=\\\"po-sub\\\" id=\\\"po-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"po-pfill\\\"></div></div></div>\u001b[39m\n\u001b[31m${pages.length ? `<div class=\\\"load-bar\\\" id=\\\"load-bar\\\"><div class=\\\"load-track\\\"><div class=\\\"load-fill\\\" id=\\\"load-fill\\\"></div></div><div class=\\\"load-txt\\\" id=\\\"load-txt\\\">Loading photos&#x2026;</div></div>` : ''}\u001b[39m\n\u001b[31m${thumbItems.length ? `<button id=\\\"cover-btn\\\" onclick=\\\"document.getElementById('pg-cover').scrollIntoView({behavior:'smooth'})\\\">&#x1F3E0;&nbsp;Cover Page</button>` : ''}·\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var main=document.getElementById('main');\u001b[39m\n\u001b[31m  var items=document.querySelectorAll('.si-item');\u001b[39m\n\u001b[31m  var covBtn=document.getElementById('cover-btn');\u001b[39m\n\u001b[31m  function setActive(id){\u001b[39m\n\u001b[31m    items.forEach(function(el){el.classList.toggle('active',el.dataset.tgt===id);});\u001b[39m\n\u001b[31m    var a=document.querySelector('.si-item[data-tgt=\\\"'+id+'\\\"]');\u001b[39m\n\u001b[31m    if(a) a.scrollIntoView({block:'nearest'});\u001b[39m\n\u001b[31m    if(covBtn) covBtn.style.display=id==='pg-cover'?'none':'flex';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  items.forEach(function(el){\u001b[39m\n\u001b[31m    el.addEventListener('click',function(){\u001b[39m\n\u001b[31m      var t=document.getElementById(el.dataset.tgt);\u001b[39m\n\u001b[31m      if(t) t.scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if('IntersectionObserver' in window){\u001b[39m\n\u001b[31m    var obs=new IntersectionObserver(function(entries){\u001b[39m\n\u001b[31m      entries.forEach(function(e){if(e.isIntersecting&&e.intersectionRatio>=0.45) setActive(e.target.id);});\u001b[39m\n\u001b[31m    },{root:main,threshold:0.45});\u001b[39m\n\u001b[31m    document.querySelectorAll('[id^=\\\"pg-\\\"]').forEach(function(p){obs.observe(p);});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  setActive('pg-cover');\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var imgs=Array.from(document.querySelectorAll('img'));\u001b[39m\n\u001b[31m  var total=imgs.length,loaded=0;\u001b[39m\n\u001b[31m  var bar=document.getElementById('load-bar');\u001b[39m\n\u001b[31m  var fill=document.getElementById('load-fill');\u001b[39m\n\u001b[31m  var txt=document.getElementById('load-txt');\u001b[39m\n\u001b[31m  var printPending=false,printShowTime=0;\u001b[39m\n\u001b[31m  var mm=96/25.4;\u001b[39m\n\u001b[31m  var SERVER_PDF='${serverPdfUrl}';\u001b[39m\n\u001b[31m  function updatePoBar(){\u001b[39m\n\u001b[31m    var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m    var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(poFill) poFill.style.width=(total?Math.round(loaded/total*100):100)+'%';\u001b[39m\n\u001b[31m    if(poSub) poSub.textContent=loaded+' / '+total+' photos ready';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function done(){\u001b[39m\n\u001b[31m    if(fill) fill.style.width='100%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='✓ All '+total+' photos ready';\u001b[39m\n\u001b[31m    setTimeout(function(){\u001b[39m\n\u001b[31m      if(bar){bar.style.transition='opacity .6s';bar.style.opacity='0';}\u001b[39m\n\u001b[31m      setTimeout(function(){if(bar)bar.style.display='none';},650);\u001b[39m\n\u001b[31m    },2000);\u001b[39m\n\u001b[31m    if(printPending){\u001b[39m\n\u001b[31m      printPending=false;\u001b[39m\n\u001b[31m      var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m      var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m      var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(poFill) poFill.style.width='100%';\u001b[39m\n\u001b[31m      if(poSub) poSub.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},Math.max(400,2000-(Date.now()-printShowTime)));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function onImg(){\u001b[39m\n\u001b[31m    loaded++;\u001b[39m\n\u001b[31m    if(fill) fill.style.width=Math.round(loaded/total*100)+'%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… '+loaded+' / '+total;\u001b[39m\n\u001b[31m    if(printPending) updatePoBar();\u001b[39m\n\u001b[31m    if(loaded>=total) done();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  /* ── PDF layout helpers ── */\u001b[39m\n\u001b[31m  function fitBandFonts(pageW){\u001b[39m\n\u001b[31m    var padH=2*13*mm,gapH=2*10*mm,noPadH=2*8*mm;\u001b[39m\n\u001b[31m    var avail=pageW-padH-gapH;\u001b[39m\n\u001b[31m    var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-band').forEach(function(band){\u001b[39m\n\u001b[31m      var cat=band.querySelector('.ph-cat');\u001b[39m\n\u001b[31m      var dims=band.querySelector('.ph-dims');\u001b[39m\n\u001b[31m      var no=band.querySelector('.ph-no');\u001b[39m\n\u001b[31m      if(!cat) return;\u001b[39m\n\u001b[31m      var catTxt=cat.textContent.trim();\u001b[39m\n\u001b[31m      var dimsTxt=dims?dims.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      var noTxt=no?no.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      function tw(sc){\u001b[39m\n\u001b[31m        var cf=15*sc*mm,df=10*sc*mm,nf=12*sc*mm;\u001b[39m\n\u001b[31m        ctx.font='800 '+cf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var cw=ctx.measureText(catTxt).width;\u001b[39m\n\u001b[31m        ctx.font='600 '+df+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var dw=dims?ctx.measureText(dimsTxt).width:0;\u001b[39m\n\u001b[31m        ctx.font='700 '+nf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var nw=no?ctx.measureText(noTxt).width+noPadH:0;\u001b[39m\n\u001b[31m        return cw+dw+nw;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      var scale=1.0;\u001b[39m\n\u001b[31m      if(tw(scale)>avail){\u001b[39m\n\u001b[31m        var lo=0.3,hi=1.0;\u001b[39m\n\u001b[31m        for(var i=0;i<10;i++){var mid=(lo+hi)/2;if(tw(mid)<=avail)lo=mid;else hi=mid;}\u001b[39m\n\u001b[31m        scale=lo*0.93;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      cat.style.setProperty('font-size',Math.round(15*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(dims) dims.style.setProperty('font-size',Math.round(10*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(no) no.style.setProperty('font-size',Math.round(12*scale*mm)+'px','important');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function sizePdfThumbs(pageW,pageH){\u001b[39m\n\u001b[31m    var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m    if(!grid||!grid.children.length) return;\u001b[39m\n\u001b[31m    var coverPage=document.getElementById('pg-cover');\u001b[39m\n\u001b[31m    var usedH=56;\u001b[39m\n\u001b[31m    if(coverPage){\u001b[39m\n\u001b[31m      Array.from(coverPage.children).forEach(function(el){\u001b[39m\n\u001b[31m        if(el!==grid) usedH+=el.offsetHeight||0;\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    var gridH=Math.max(80,pageH-usedH);\u001b[39m\n\u001b[31m    var n=grid.children.length,gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m    for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m      var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m      var w=(pageW-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m      var h=w*asp;\u001b[39m\n\u001b[31m      if(rows*h+(rows-1)*gap<=gridH&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m    grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m    grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m    var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m    var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m    var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function preparePdfLayout(){\u001b[39m\n\u001b[31m    var pageW=Math.round((297-24)*mm);\u001b[39m\n\u001b[31m    var pageH=Math.round((210-24)*mm);\u001b[39m\n\u001b[31m    fitBandFonts(pageW);\u001b[39m\n\u001b[31m    sizePdfThumbs(pageW,pageH);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.preparePdfLayout=preparePdfLayout;\u001b[39m\n\u001b[31m  function restorePdfLayout(){\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-cat,.ph-dims,.ph-no').forEach(function(el){\u001b[39m\n\u001b[31m      el.style.removeProperty('font-size');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(window._screenSizeThumbs) window._screenSizeThumbs();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.addEventListener('afterprint',restorePdfLayout);\u001b[39m\n\u001b[31m  function _doBrowserPrint(){\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    printShowTime=Date.now();\u001b[39m\n\u001b[31m    preparePdfLayout();\u001b[39m\n\u001b[31m    if(total===0||loaded>=total){\u001b[39m\n\u001b[31m      var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m      if(ps) ps.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},2000);\u001b[39m\n\u001b[31m      return;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    printPending=true;\u001b[39m\n\u001b[31m    updatePoBar();\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if((!img.complete||img.naturalWidth===0)&&img.getAttribute('loading')==='lazy'){\u001b[39m\n\u001b[31m        img.loading='eager';var s=img.src;img.src='';img.src=s;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.doPDF=async function(){\u001b[39m\n\u001b[31m    if(!SERVER_PDF){_doBrowserPrint();return;}\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      var r=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m      if(r.ok){window.open(SERVER_PDF,'_blank');return;}\u001b[39m\n\u001b[31m    }catch(_){}\u001b[39m\n\u001b[31m    // PDF not ready yet — show overlay and poll\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    if(pf) pf.style.width='0%';\u001b[39m\n\u001b[31m    if(ps) ps.textContent='Waiting for server PDF…';\u001b[39m\n\u001b[31m    var tries=0;\u001b[39m\n\u001b[31m    (async function poll(){\u001b[39m\n\u001b[31m      tries++;\u001b[39m\n\u001b[31m      if(pf) pf.style.width=Math.min(88,tries*8)+'%';\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        var r2=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m        if(r2.ok){\u001b[39m\n\u001b[31m          if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m          setTimeout(function(){if(ov)ov.style.display='none';window.open(SERVER_PDF,'_blank');},400);\u001b[39m\n\u001b[31m          return;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      }catch(_){}\u001b[39m\n\u001b[31m      if(tries>=12){if(ov)ov.style.display='none';_doBrowserPrint();return;}\u001b[39m\n\u001b[31m      setTimeout(poll,5000);\u001b[39m\n\u001b[31m    })();\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  if(total===0){if(bar)bar.style.display='none';}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… 0 / '+total;\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if(img.complete&&img.naturalWidth>0) onImg();\u001b[39m\n\u001b[31m      else{img.addEventListener('load',onImg);img.addEventListener('error',onImg);}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m  if(grid&&grid.children.length>0){\u001b[39m\n\u001b[31m    function sizeThumbs(){\u001b[39m\n\u001b[31m      var n=grid.children.length;\u001b[39m\n\u001b[31m      var gw=grid.clientWidth,gh=grid.clientHeight;\u001b[39m\n\u001b[31m      if(!gw||!gh) return;\u001b[39m\n\u001b[31m      var gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m      for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m        var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m        var w=(gw-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m        var h=w*asp;\u001b[39m\n\u001b[31m        if(rows*h+(rows-1)*gap<=gh&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m      grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m      grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m      var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m      var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m      var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    window._screenSizeThumbs=sizeThumbs;\u001b[39m\n\u001b[31m    requestAnimationFrame(function(){requestAnimationFrame(sizeThumbs);});\u001b[39m\n\u001b[31m    window.addEventListener('resize',sizeThumbs);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m</scr`+'ipt>'+`\u001b[39m\n\u001b[31m</body></html>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncToPostgres(entry) {\u001b[39m\n\u001b[31m  const d   = entry.data || {};\u001b[39m\n\u001b[31m  const hub = _recceHubUser();·\u001b[39m\n\u001b[31m  // Step 1 — upload all photos to VPS, get permanent server URLs\u001b[39m\n\u001b[31m  let photoUrls = { front:[], inside:[], brandings:[], addl:[], doc:null };\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const pResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type: 'save-photos', subId: entry.id,\u001b[39m\n\u001b[31m        photos: {\u001b[39m\n\u001b[31m          front:    (d.frontPhotos||[]).map(p=>({b64:p.b64,   cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64,  cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||null})),\u001b[39m\n\u001b[31m          addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64,   desc:p.desc||''})),\u001b[39m\n\u001b[31m          doc:      d.docB64 || null,\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (pResp.ok) { const r=await pResp.json(); if(r.success) {\u001b[39m\n\u001b[31m      photoUrls=r.photoUrls;\u001b[39m\n\u001b[31m      // Merge retained existing URLs for edit re-submits\u001b[39m\n\u001b[31m      if (entry.editedAt) {\u001b[39m\n\u001b[31m        photoUrls.front    =(photoUrls.front   ||[]).map((u,i)=>u||(d.frontPhotos  ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.inside   =(photoUrls.inside  ||[]).map((u,i)=>u||(d.insidePhotos ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.addl     =(photoUrls.addl    ||[]).map((u,i)=>u||(d.addlPhotos   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.brandings=(photoUrls.brandings||[]).map((u,i)=>u||(d.brandings   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        if(!photoUrls.doc) photoUrls.doc=d._docExistingUrl||null;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }}\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-photos] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 1.5 — trigger Google Slides via proxy using permanent photo URLs (fire-and-forget)\u001b[39m\n\u001b[31m  (async()=>{try{\u001b[39m\n\u001b[31m    const _hasPh=(photoUrls.front||[]).some(Boolean)||(photoUrls.inside||[]).some(Boolean)||(photoUrls.brandings||[]).some(Boolean);\u001b[39m\n\u001b[31m    if(!_hasPh)return;\u001b[39m\n\u001b[31m    const _gu=(await cfg('slides-gas-url'))||(await cfg('gas-url'))||DEFAULT_GAS_URL;if(!_gu)return;\u001b[39m\n\u001b[31m    await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({\u001b[39m\n\u001b[31m      type:'make-slides',gasUrl:_gu,subId:entry.id,\u001b[39m\n\u001b[31m      storeInfo:{storeName:d.storeName||'',brand:d.brand||'',address:d.address||'',mobile:d.mobile||'',date:d.date||'',city:d.city||'',gpsCoords:d.gpsCoords||null},\u001b[39m\n\u001b[31m      photoGroups:{\u001b[39m\n\u001b[31m        front:    (photoUrls.front   ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.frontPhotos  ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        inside:   (photoUrls.inside  ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.insidePhotos ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        brandings:(photoUrls.brandings||[]).filter(Boolean).map((url,i)=>({url,meta:{type:(d.brandings||[])[i]?.type,w:(d.brandings||[])[i]?.w,h:(d.brandings||[])[i]?.h,qty:(d.brandings||[])[i]?.qty,sqft:(d.brandings||[])[i]?.sqft}})),\u001b[39m\n\u001b[31m        addl:    (photoUrls.addl    ||[]).filter(Boolean).map((url,i)=>({url,desc:(d.addlPhotos  ||[])[i]?.desc||''})),\u001b[39m\n\u001b[31m      },\u001b[39m\n\u001b[31m    })});\u001b[39m\n\u001b[31m    entry.gasAt=new Date().toISOString();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[recce-slides]',e.message);}}\u001b[39m\n\u001b[31m  )();·\u001b[39m\n\u001b[31m  // Step 2 — generate rich HTML report using server URLs, save to VPS\u001b[39m\n\u001b[31m  let view_url = null;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const html  = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m    const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-view', subId: entry.id, html })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (vResp.ok) { const r=await vResp.json(); if(r.success) view_url=r.url; }\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-view] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 3 — upsert to PostgreSQL with photo URLs + view URL\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch(`${_RC_BASE}/submissions`, {\u001b[39m\n\u001b[31m      method: 'POST', headers: _RC_UPSERT,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        sub_id:         entry.id,\u001b[39m\n\u001b[31m        store_name:     d.storeName    || 'Unknown',\u001b[39m\n\u001b[31m        brand:          d.brand        || null,\u001b[39m\n\u001b[31m        client_name:    d.clientName   || null,\u001b[39m\n\u001b[31m        visit_date:     d.date         || new Date().toISOString().slice(0,10),\u001b[39m\n\u001b[31m        address:        d.address      || null,\u001b[39m\n\u001b[31m        mobile:         d.mobile       || null,\u001b[39m\n\u001b[31m        city:           d.city         || null,\u001b[39m\n\u001b[31m        has_branding:   !!(d.brandings?.length),\u001b[39m\n\u001b[31m        branding_count: d.brandings?.length || 0,\u001b[39m\n\u001b[31m        has_video:      !!d.hasVideo,\u001b[39m\n\u001b[31m        front_photos:   d.frontPhotos?.length  || 0,\u001b[39m\n\u001b[31m        inside_photos:  d.insidePhotos?.length || 0,\u001b[39m\n\u001b[31m        addl_photos:    d.addlPhotos?.length   || 0,\u001b[39m\n\u001b[31m        gps_lat:        d.gpsCoords?.lat       || null,\u001b[39m\n\u001b[31m        gps_lng:        d.gpsCoords?.lng       || null,\u001b[39m\n\u001b[31m        submitted_by:   hub.empId              || null,\u001b[39m\n\u001b[31m        submitted_at:   entry.timestamp,\u001b[39m\n\u001b[31m        campaign_id:    entry.campaignId       || null,\u001b[39m\n\u001b[31m        photo_urls:     photoUrls,\u001b[39m\n\u001b[31m        view_url,\u001b[39m\n\u001b[31m        meta: {\u001b[39m\n\u001b[31m          brandings: (d.brandings||[]).map(b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft})),\u001b[39m\n\u001b[31m          videoNote: d.videoNote || null,\u001b[39m\n\u001b[31m          videoCmt:  d.videoCmt  || null,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        status: 'submitted',\u001b[39m\n\u001b[31m        edit_assigned_to: null,\u001b[39m\n\u001b[31m        edit_comment: null,\u001b[39m\n\u001b[31m        edited_at: entry.editedAt || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    return { ok: true, viewUrl: view_url };\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    console.warn('[recce-db] sync error:', e.message);\u001b[39m\n\u001b[31m    return { ok: false, viewUrl: null };\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mconst DEFAULT_ADMIN_HASH='42d372e6110bee134990ac6881c3d5eb568482008add9a859f37f10d759430e8';·\u001b[39m\n\u001b[31masync function saveGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('gas-url',url||DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  toast('Endpoint saved','success');\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function testEndpoint(){\u001b[39m\n\u001b[31m  const url=(await cfg('gas-url'))||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  try{await fetch(url,{method:'POST',mode:'no-cors',body:JSON.stringify({test:true})});toast('Endpoint reachable ✓','success');}\u001b[39m\n\u001b[31m  catch{toast('Cannot reach endpoint','error')}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  cfg('gas-url').then(url=>{\u001b[39m\n\u001b[31m    const u=url||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    // Show last 30 chars only for privacy\u001b[39m\n\u001b[31m    el.textContent='Endpoint: …'+u.slice(-30);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── SLIDES GAS URL ────────────────────────────────────────────\u001b[39m\n\u001b[31masync function saveSlidesGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('slides-gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('slides-gas-url', url);\u001b[39m\n\u001b[31m  toast('Slides GAS URL saved','success');\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function updateSlidesGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('slides-gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  const u=await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  el.textContent=u?'Configured: …'+u.slice(-30):'Not configured';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── MAKE SLIDES ───────────────────────────────────────────────\u001b[39m\n\u001b[31masync function makeSlides(id){\u001b[39m\n\u001b[31m  const gasUrl = await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  if(!gasUrl){\u001b[39m\n\u001b[31m    toast('Configure Slides GAS URL in Settings first','error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const entry = await dbGet('subs', id);\u001b[39m\n\u001b[31m  if(!entry){ toast('Entry not found','error'); return; }\u001b[39m\n\u001b[31m  const d = entry.data;·\u001b[39m\n\u001b[31m  toast('Uploading photos & generating slides…','info');·\u001b[39m\n\u001b[31m  // Build photo groups payload\u001b[39m\n\u001b[31m  const photoGroups = {\u001b[39m\n\u001b[31m    front:    (d.frontPhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64, cmt:p.desc||''})),\u001b[39m\n\u001b[31m    brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||'', meta:{type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft}})),\u001b[39m\n\u001b[31m  };·\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type:       'recce',\u001b[39m\n\u001b[31m        subId:      id,\u001b[39m\n\u001b[31m        gasUrl:     gasUrl,\u001b[39m\n\u001b[31m        storeInfo:  {\u001b[39m\n\u001b[31m          storeName: d.storeName, brand: d.brand,\u001b[39m\n\u001b[31m          date: d.date, address: d.address,\u001b[39m\n\u001b[31m          mobile: d.mobile, gpsCoords: d.gpsCoords,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        photoGroups,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const result = await resp.json();\u001b[39m\n\u001b[31m    if(result.success && result.slideUrl){\u001b[39m\n\u001b[31m      // Store slide URL on the entry\u001b[39m\n\u001b[31m      entry.slideUrl = result.slideUrl;\u001b[39m\n\u001b[31m      await dbPut('subs', entry);\u001b[39m\n\u001b[31m      toast('✅ Slides ready!','success');\u001b[39m\n\u001b[31m      window.open(result.slideUrl, '_blank');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast('Slides error: '+(result.error||'Unknown'),'error');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e){\u001b[39m\n\u001b[31m    toast('Network error: '+e.message,'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN LOGIN ──────────────────────────────────────────────\u001b[39m\n\u001b[31mfunction showAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-error').style.display='none';\u001b[39m\n\u001b[31m  // Restore saved config URL\u001b[39m\n\u001b[31m  cfg('admin-cfg-url').then(u=>{if(u&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=u;});\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('admin-pwd').focus(),100);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveAdminCfgUrl(){\u001b[39m\n\u001b[31m  // Admin cfg URL can be saved without login (needed to set up auth itself)\u001b[39m\n\u001b[31m  // But we warn if saving while unlocked only\u001b[39m\n\u001b[31m  const url=document.getElementById('admin-cfg-url').value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  await cfg('admin-cfg-url',url);\u001b[39m\n\u001b[31m  toast('Config URL saved — will use on next login attempt','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function verifyAdmin(){\u001b[39m\n\u001b[31m  // Hub admins (harish/pramod) are auto-unlocked — no password needed\u001b[39m\n\u001b[31m  if (_adminUnlocked) { adminLoginSuccess(); return; }\u001b[39m\n\u001b[31m  const pwd=document.getElementById('admin-pwd').value;\u001b[39m\n\u001b[31m  if(!pwd){document.getElementById('admin-error').style.display='block';document.getElementById('admin-error').textContent='Enter password';return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('admin-login-btn');btn.disabled=true;btn.textContent='Verifying…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // Try server verification first\u001b[39m\n\u001b[31m    const cfgUrl=(await cfg('admin-cfg-url'))||'';\u001b[39m\n\u001b[31m    if(cfgUrl){\u001b[39m\n\u001b[31m      const r=await fetch(cfgUrl,{cache:'no-store'});\u001b[39m\n\u001b[31m      const j=await r.json();\u001b[39m\n\u001b[31m      // Server JSON format: {\\\"password\\\":\\\"plaintext\\\"} or {\\\"hash\\\":\\\"sha256hash\\\"}\u001b[39m\n\u001b[31m      let match=false;\u001b[39m\n\u001b[31m      if(j.password){match=(j.password===pwd);}\u001b[39m\n\u001b[31m      else if(j.hash){\u001b[39m\n\u001b[31m        // SHA-256 comparison\u001b[39m\n\u001b[31m        const enc=new TextEncoder();\u001b[39m\n\u001b[31m        const data=enc.encode(pwd);\u001b[39m\n\u001b[31m        const hashBuf=await crypto.subtle.digest('SHA-256',data);\u001b[39m\n\u001b[31m        const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m        match=(hashHex===j.hash);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      if(match){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m      else{showAdminError('Incorrect password');return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Fallback: local password stored in settings\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if(localHash){\u001b[39m\n\u001b[31m      const enc=new TextEncoder();\u001b[39m\n\u001b[31m      const hashBuf=await crypto.subtle.digest('SHA-256',enc.encode(pwd));\u001b[39m\n\u001b[31m      const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m      if(hashHex===localHash){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Final fallback: check against hardcoded default hash\u001b[39m\n\u001b[31m    const enc2=new TextEncoder();\u001b[39m\n\u001b[31m    const hb2=await crypto.subtle.digest('SHA-256',enc2.encode(pwd));\u001b[39m\n\u001b[31m    const hh2=Array.from(new Uint8Array(hb2)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    if(hh2===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }catch(err){\u001b[39m\n\u001b[31m    // Network error — try all local fallbacks\u001b[39m\n\u001b[31m    const enc3=new TextEncoder();\u001b[39m\n\u001b[31m    const hb3=await crypto.subtle.digest('SHA-256',enc3.encode(pwd));\u001b[39m\n\u001b[31m    const hh3=Array.from(new Uint8Array(hb3)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if((localHash&&hh3===localHash)||hh3===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }finally{btn.disabled=false;btn.textContent='Login';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showAdminError(msg){\u001b[39m\n\u001b[31m  const el=document.getElementById('admin-error');\u001b[39m\n\u001b[31m  el.textContent=msg;el.style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminLoginSuccess(){\u001b[39m\n\u001b[31m  _adminUnlocked=true;\u001b[39m\n\u001b[31m  closeAdminLogin();\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  cfg('gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  cfg('slides-gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('slides-gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||'';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  toast('Admin mode unlocked','success');\u001b[39m\n\u001b[31m  setTimeout(lockAdmin,10*60*1000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction lockAdmin(){\u001b[39m\n\u001b[31m  _adminUnlocked=false;\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  toast('Admin session ended','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updAvailTag(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-avail-tag');\u001b[39m\n\u001b[31m  const ct=document.getElementById('store-avail-count');\u001b[39m\n\u001b[31m  const txt=stores.length?`${stores.length} stores`:'No store list';\u001b[39m\n\u001b[31m  if(el)el.textContent=txt;\u001b[39m\n\u001b[31m  if(ct)ct.textContent=stores.length?t(`${stores.length} stores available — tap to browse`,`${stores.length} स्टोर उपलब्ध — दबाएं`):t('No store list loaded yet','कोई स्टोर सूची नहीं');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PICKER\u001b[39m\n\u001b[31mfunction openPicker(){\u001b[39m\n\u001b[31m  if(!stores.length){toast('Load a store list in Settings first','error');return;}\u001b[39m\n\u001b[31m  document.getElementById('povl').classList.add('open');\u001b[39m\n\u001b[31m  document.getElementById('psearch').value='';\u001b[39m\n\u001b[31m  filterPicker('');\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('psearch').focus(),150);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closePicker(){document.getElementById('povl').classList.remove('open');}\u001b[39m\n\u001b[31masync function filterPicker(q){\u001b[39m\n\u001b[31m  const list=document.getElementById('plist');\u001b[39m\n\u001b[31m  const words=q.toLowerCase().trim().split(/\\\\s+/).filter(Boolean);\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const lastVisit={};\u001b[39m\n\u001b[31m  subs.forEach(s=>{const nm=s.data?.storeName;if(nm&&(!lastVisit[nm]||s.timestamp>lastVisit[nm]))lastVisit[nm]=s.timestamp;});·\u001b[39m\n\u001b[31m  // Multi-word: ALL words must match somewhere in any field (search across both English and Hindi)\u001b[39m\n\u001b[31m  let fl=stores.filter(s=>{\u001b[39m\n\u001b[31m    if(!words.length)return true;\u001b[39m\n\u001b[31m    const hay=[s.name,s.nameHi,s.address,s.addressHi,s.mobile,s.city,s.cityHi,s.distName,s.distNameHi,s.brand,s.sales,s.proj,s.glowSign,s.inshop]\u001b[39m\n\u001b[31m               .map(x=>(x||'').toLowerCase()).join(' ');\u001b[39m\n\u001b[31m    return words.every(w=>hay.includes(w));\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(fl.length>100)fl=fl.slice(0,100);·\u001b[39m\n\u001b[31m  if(!fl.length){\u001b[39m\n\u001b[31m    const esc=q.replace(/'/g,\\\"\\\\\\\\'\\\");\u001b[39m\n\u001b[31m    list.innerHTML=`<div style=\\\"text-align:center;padding:32px 16px;color:var(--g400);font-size:14px\\\">No stores match \\\"${q}\\\"<br><span style=\\\"font-size:12px\\\">Try fewer or different words</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('${esc}')\\\">+ Add \\\"${q}\\\" as new store</div>`;\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Group by brand (including empty brand)\u001b[39m\n\u001b[31m  const g={};\u001b[39m\n\u001b[31m  fl.forEach(s=>{\u001b[39m\n\u001b[31m    const b=s.brand||'(No Brand — will ask)';\u001b[39m\n\u001b[31m    if(!g[b])g[b]=[];\u001b[39m\n\u001b[31m    g[b].push(s);\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html='';\u001b[39m\n\u001b[31m  Object.keys(g).sort().forEach(br=>{\u001b[39m\n\u001b[31m    html+=`<div class=\\\"psec\\\">${br}</div>`;\u001b[39m\n\u001b[31m    g[br].forEach(s=>{\u001b[39m\n\u001b[31m      const lv=lastVisit[s.name];\u001b[39m\n\u001b[31m      const lvStr=lv?`🕐 Last: ${new Date(lv).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'2-digit'})}`:'';\u001b[39m\n\u001b[31m      const chips=[];\u001b[39m\n\u001b[31m      if(s.glowSign&&s.glowSign.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dcfce7;color:#14532d;padding:2px 6px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m      if(s.inshop&&s.inshop.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dbeafe;color:#1e40af;padding:2px 6px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m      if(s.proj)chips.push(`<span style=\\\"font-size:10px;background:var(--g100);color:var(--g600);padding:2px 6px;border-radius:10px\\\">Target: ${s.proj}</span>`);\u001b[39m\n\u001b[31m      const enc=JSON.stringify(s).replace(/\\\"/g,'&quot;');\u001b[39m\n\u001b[31m      const mapsUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m      const waUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const telUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const dispName=LANG==='hi'&&s.nameHi?s.nameHi:s.name;\u001b[39m\n\u001b[31m      const dispAddr=LANG==='hi'&&s.addressHi?s.addressHi:s.address;\u001b[39m\n\u001b[31m      const dispDist=LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m      html+=`<div class=\\\"pitem\\\" onclick=\\\"pickStore(${enc})\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"pi-name\\\">${dispName}</div>\u001b[39m\n\u001b[31m          ${dispAddr?`<div class=\\\"pi-addr\\\">📍 ${dispAddr}</div>`:''}\u001b[39m\n\u001b[31m          ${s.mobile?`<div class=\\\"pi-addr\\\">📞 ${s.mobile}</div>`:''}\u001b[39m\n\u001b[31m          ${dispDist?`<div class=\\\"pi-addr\\\" style=\\\"color:var(--am)\\\">👤 ${dispDist}</div>`:''}\u001b[39m\n\u001b[31m          ${lvStr?`<div class=\\\"pi-last\\\">${lvStr}</div>`:''}\u001b[39m\n\u001b[31m          ${chips.length?`<div style=\\\"display:flex;gap:4px;flex-wrap:wrap;margin-top:4px\\\">${chips.join('')}</div>`:''}\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;gap:6px;margin-top:7px\\\" onclick=\\\"event.stopPropagation()\\\">\u001b[39m\n\u001b[31m            ${mapsUrl?`<a href=\\\"${mapsUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#e0f2fe;color:#0369a1;border-radius:20px;text-decoration:none;font-weight:600\\\">🗺 Maps</a>`:''}\u001b[39m\n\u001b[31m            ${waUrl?`<a href=\\\"${waUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#dcfce7;color:#15803d;border-radius:20px;text-decoration:none;font-weight:600\\\">💬 WhatsApp</a>`:''}\u001b[39m\n\u001b[31m            ${telUrl?`<a href=\\\"${telUrl}\\\" style=\\\"font-size:11px;padding:4px 10px;background:#f0fdf4;color:#166534;border-radius:20px;text-decoration:none;font-weight:600\\\">📞 Call</a>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        ${s.brand?`<div class=\\\"pi-brand\\\">${s.brand}</div>`:'<div class=\\\"pi-brand\\\" style=\\\"background:var(--rd)\\\">?</div>'}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html+=`<div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('')\\\">+ Not in list? Add new store</div>`;\u001b[39m\n\u001b[31m  list.innerHTML=html;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function pickStore(s){\u001b[39m\n\u001b[31m  selectedStore=s;manualMode=false;closePicker();\u001b[39m\n\u001b[31m  const _dn =LANG==='hi'&&s.nameHi    ?s.nameHi    :s.name;\u001b[39m\n\u001b[31m  const _da =LANG==='hi'&&s.addressHi ?s.addressHi :s.address;\u001b[39m\n\u001b[31m  const _dd =LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m  const _dc =LANG==='hi'&&s.cityHi    ?s.cityHi    :s.city;\u001b[39m\n\u001b[31m  document.getElementById('sc-name').textContent=_dn;\u001b[39m\n\u001b[31m  const brandEl=document.getElementById('sc-brand');\u001b[39m\n\u001b[31m  brandEl.textContent=s.brand||'No Brand';brandEl.style.background=s.brand?'var(--nv)':'var(--rd)';\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const prev=subs.filter(x=>x.data?.storeName===s.name).sort((a,b)=>new Date(b.timestamp)-new Date(a.timestamp))[0];\u001b[39m\n\u001b[31m  const lc=document.getElementById('sc-last');\u001b[39m\n\u001b[31m  if(prev){const d=new Date(prev.timestamp);lc.textContent='Last: '+d.toLocaleDateString('en-IN',{day:'numeric',month:'short'});lc.style.display='inline-flex';}\u001b[39m\n\u001b[31m  else lc.style.display='none';\u001b[39m\n\u001b[31m  // All Excel fields — display in active language\u001b[39m\n\u001b[31m  const mUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m  const wUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const tUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const details=[];\u001b[39m\n\u001b[31m  if(_da)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📍 ${_da}${mUrl?` <a href=\\\"${mUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#0369a1;margin-left:6px\\\">🗺 Navigate</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(s.mobile)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📞 ${s.mobile}${tUrl?` <a href=\\\"${tUrl}\\\" style=\\\"font-size:11px;color:#166534;margin-left:6px\\\">Call</a>`:''}${wUrl?` <a href=\\\"${wUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#15803d;margin-left:6px\\\">WhatsApp</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(_dd)details.push(`<div style=\\\"font-size:12px;color:var(--am)\\\">👤 ${_dd}</div>`);\u001b[39m\n\u001b[31m  if(_dc)details.push(`<div style=\\\"font-size:12px;color:var(--g500)\\\">🏙 ${_dc}</div>`);\u001b[39m\n\u001b[31m  const opp=[];\u001b[39m\n\u001b[31m  if(s.glowSign&&s.glowSign.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dcfce7;color:#14532d;padding:2px 7px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m  if(s.inshop&&s.inshop.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dbeafe;color:#1e40af;padding:2px 7px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m  if(s.proj)opp.push(`<span style=\\\"font-size:11px;background:var(--g100);color:var(--g600);padding:2px 7px;border-radius:10px\\\">Target 2026: ${s.proj}</span>`);\u001b[39m\n\u001b[31m  if(opp.length)details.push(`<div style=\\\"display:flex;gap:5px;flex-wrap:wrap;margin-top:3px\\\">${opp.join('')}</div>`);\u001b[39m\n\u001b[31m  document.getElementById('sc-details').innerHTML=details.join('');\u001b[39m\n\u001b[31m  // Missing fields\u001b[39m\n\u001b[31m  const missing=[];\u001b[39m\n\u001b[31m  if(!s.address)missing.push({key:'address',label:'Store Address',type:'textarea',placeholder:'Full address'});\u001b[39m\n\u001b[31m  if(!s.mobile)missing.push({key:'mobile',label:'Mobile No.',type:'tel',placeholder:'10-digit number',maxlen:'10'});\u001b[39m\n\u001b[31m  const mw=document.getElementById('sc-missing'),mf=document.getElementById('sc-missing-fields');\u001b[39m\n\u001b[31m  if(missing.length){\u001b[39m\n\u001b[31m    mf.innerHTML=missing.map(m=>`<div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\"><label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">${m.label} <span class=\\\"req\\\">*</span></label>${m.type==='textarea'?`<textarea id=\\\"sc-miss-${m.key}\\\" rows=\\\"2\\\" placeholder=\\\"${m.placeholder}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></textarea>`:`<input type=\\\"${m.type}\\\" id=\\\"sc-miss-${m.key}\\\" placeholder=\\\"${m.placeholder}\\\" ${m.maxlen?`maxlength=\\\"${m.maxlen}\\\"`:''}  inputmode=\\\"${m.type==='tel'?'numeric':'text'}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\">`}</div>`).join('');\u001b[39m\n\u001b[31m    mw.style.display='block';\u001b[39m\n\u001b[31m  } else {mw.style.display='none';}\u001b[39m\n\u001b[31m  // Brand selector\u001b[39m\n\u001b[31m  const bSel=document.getElementById('brand-selector'),bChips=document.getElementById('brand-chips');\u001b[39m\n\u001b[31m  if(!s.brand){\u001b[39m\n\u001b[31m    renderBrandChips();\u001b[39m\n\u001b[31m    bSel.style.display='block';\u001b[39m\n\u001b[31m  } else {bSel.style.display='none';}\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  F.storeName=s.name;F.brand=s.brand||'';F.address=s.address||'';F.mobile=s.mobile||'';\u001b[39m\n\u001b[31m  if(s.brand&&!_selectedClient&&!_clientOtherMode) autoSetClient(s.brand);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateMissingField(key,val){if(!selectedStore)return;selectedStore[key]=val.trim();F[key]=val.trim();saveDraft();}\u001b[39m\n\u001b[31mfunction selectStoreBrand(b){\u001b[39m\n\u001b[31m  F.brand=b;F.brandLogoUrl=_brandLogos[b]||'';\u001b[39m\n\u001b[31m  if(selectedStore)selectedStore.brand=b;\u001b[39m\n\u001b[31m  const el=document.getElementById('sc-brand');if(el){el.textContent=b;el.style.background='var(--nv)';}\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-chips .chip').forEach(c=>{c.classList.toggle('sel',c.querySelector('span')?.textContent===b||c.textContent.trim()===b);});\u001b[39m\n\u001b[31m  if(!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction onManualBrandChange(){\u001b[39m\n\u001b[31m  const b=document.getElementById('f-brand')?.value||'';\u001b[39m\n\u001b[31m  F.brandLogoUrl=b?(_brandLogos[b]||''):'';\u001b[39m\n\u001b[31m  if(b&&!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction openManual(prefill){\u001b[39m\n\u001b[31m  manualMode=true;\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').classList.add('on');\u001b[39m\n\u001b[31m  document.getElementById('mt-label').innerHTML='← Back to store list';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='block';\u001b[39m\n\u001b[31m  // Pre-fill from selectedStore if available (e.g. when toggling after picker selection)\u001b[39m\n\u001b[31m  const s=selectedStore;\u001b[39m\n\u001b[31m  if(s){\u001b[39m\n\u001b[31m    if(document.getElementById('f-brand'))document.getElementById('f-brand').value=s.brand||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-store'))document.getElementById('f-store').value=s.name||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-addr'))document.getElementById('f-addr').value=s.address||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-mobile'))document.getElementById('f-mobile').value=s.mobile||'';\u001b[39m\n\u001b[31m  } else if(prefill){\u001b[39m\n\u001b[31m    document.getElementById('f-store').value=prefill;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  selectedStore=null;\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction toggleManual(){\u001b[39m\n\u001b[31m  if(manualMode){\u001b[39m\n\u001b[31m    manualMode=false;\u001b[39m\n\u001b[31m    document.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31m    document.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31m    document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    openManual('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// GPS\u001b[39m\n\u001b[31mfunction captureGPS(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gps-status');el.textContent='Getting location…';el.style.color='var(--g500)';\u001b[39m\n\u001b[31m  if(!navigator.geolocation){el.textContent='GPS not available';return;}\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(pos=>{\u001b[39m\n\u001b[31m    gpsCoords={lat:pos.coords.latitude.toFixed(6),lng:pos.coords.longitude.toFixed(6),acc:Math.round(pos.coords.accuracy)};\u001b[39m\n\u001b[31m    el.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${gpsCoords.acc}m)`;el.style.color='var(--gn)';saveDraft();\u001b[39m\n\u001b[31m  },()=>{el.textContent='GPS failed — enter address manually';el.style.color='var(--rd)';},{enableHighAccuracy:true,timeout:10000});\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// DRAFT\u001b[39m\n\u001b[31mlet draftT;\u001b[39m\n\u001b[31mfunction saveDraft(){\u001b[39m\n\u001b[31m  clearTimeout(draftT);\u001b[39m\n\u001b[31m  draftT=setTimeout(async()=>{\u001b[39m\n\u001b[31m    const draft={k:'current',ts:Date.now(),F:{...F,date:document.getElementById('f-date')?.value||'',brand:manualMode?(document.getElementById('f-brand')?.value||''):(selectedStore?.brand||F.brand||''),storeName:selectedStore?selectedStore.name:(document.getElementById('f-store')?.value||''),address:manualMode?(document.getElementById('f-addr')?.value||''):(selectedStore?.address||F.address||''),mobile:manualMode?(document.getElementById('f-mobile')?.value||''):(selectedStore?.mobile||F.mobile||''),clientName:getClientName()},selectedStore,manualMode,gpsCoords,_selectedClient,_clientOtherMode,fCnt:frontPhotos.length,iCnt:insidePhotos.length,bCnt:brandings.length};\u001b[39m\n\u001b[31m    await dbPut('draft',draft);\u001b[39m\n\u001b[31m    // Also save photos as b64 blobs to draft so they survive exit\u001b[39m\n\u001b[31m    await saveDraftPhotos();\u001b[39m\n\u001b[31m  },500);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveDraftPhotos(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const photoData={\u001b[39m\n\u001b[31m      front:await Promise.all(frontPhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      inside:await Promise.all(insidePhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      addl:await Promise.all(addlPhotos.map(async p=>({b64:await b64(p.blob),desc:p.desc||''}))),\u001b[39m\n\u001b[31m      brand:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,b64:b.blob?await b64(b.blob):null})))\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    await dbPut('draft',{k:'photos',...photoData});\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function checkDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');const wrap=document.getElementById('resume-wrap');\u001b[39m\n\u001b[31m  if(!d||!d.F?.storeName){wrap.innerHTML='';return;}\u001b[39m\n\u001b[31m  const ago=Math.round((Date.now()-d.ts)/60000);\u001b[39m\n\u001b[31m  const agoStr=ago<1?'just now':ago<60?`${ago}m ago`:`${Math.round(ago/60)}h ago`;\u001b[39m\n\u001b[31m  wrap.innerHTML=`<button class=\\\"resume-btn\\\" onclick=\\\"resumeDraft()\\\">\u001b[39m\n\u001b[31m    <div><div style=\\\"font-size:12px;color:rgba(255,255,255,.5);margin-bottom:3px\\\">Resume draft · ${agoStr}</div><div>${d.F.storeName} · ${d.F.brand||'No brand'}</div></div>\u001b[39m\n\u001b[31m    <div style=\\\"text-align:right\\\"><div style=\\\"font-size:13px;color:var(--or)\\\">${d.fCnt||0} photos · ${d.bCnt||0} brandings →</div></div>\u001b[39m\n\u001b[31m  </button>`;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function resumeDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');if(!d)return;\u001b[39m\n\u001b[31m  F=d.F||{};gpsCoords=d.gpsCoords||null;\u001b[39m\n\u001b[31m  if(d.selectedStore){await pickStore(d.selectedStore);}\u001b[39m\n\u001b[31m  else if(d.manualMode){openManual('');if(F.brand)document.getElementById('f-brand').value=F.brand;if(F.storeName)document.getElementById('f-store').value=F.storeName;if(F.address)document.getElementById('f-addr').value=F.address;if(F.mobile)document.getElementById('f-mobile').value=F.mobile;}\u001b[39m\n\u001b[31m  if(F.date)document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  // Restore client chip state\u001b[39m\n\u001b[31m  if(d._clientOtherMode){_clientOtherMode=true;_selectedClient='';const inp=document.getElementById('f-client-other');if(inp&&F.clientName)inp.value=F.clientName;}\u001b[39m\n\u001b[31m  else if(d._selectedClient){_selectedClient=d._selectedClient;_clientOtherMode=false;}\u001b[39m\n\u001b[31m  else if(F.clientName){autoSetClient(F.clientName);}\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  // Restore photos from draft\u001b[39m\n\u001b[31m  const pd=await dbGet('draft','photos');\u001b[39m\n\u001b[31m  if(pd){\u001b[39m\n\u001b[31m    async function b64ToBlob(b64str){if(!b64str)return null;try{const r=await fetch(b64str);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m    for(const p of(pd.front||[])){const bl=await b64ToBlob(p.b64);if(bl)frontPhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.inside||[])){const bl=await b64ToBlob(p.b64);if(bl)insidePhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.addl||[])){const bl=await b64ToBlob(p.b64);if(bl)addlPhotos.push({blob:bl,prev:URL.createObjectURL(bl),desc:p.desc||''});}\u001b[39m\n\u001b[31m    for(const b of(pd.brand||[])){const bl=await b64ToBlob(b.b64);brandings.push({type:b.type,w:b.w,h:b.h,qty:b.qty,blob:bl,prev:bl?URL.createObjectURL(bl):null});}\u001b[39m\n\u001b[31m    toast('Draft restored with '+frontPhotos.length+' photos ✓','success');\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    toast('Draft restored — photos could not be recovered','info');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PHOTOS\u001b[39m\n\u001b[31mfunction updPhotoBadge(type){const arr=type==='front'?frontPhotos:insidePhotos;const el=document.getElementById(type+'-badge');if(el){el.textContent=arr.length;el.className='cnt-badge '+(arr.length?'':'gray');}}\u001b[39m\n\u001b[31mfunction renderPhotos(type){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  const cont=document.getElementById(type+'-cont');const addBtn=document.getElementById('add-'+type);\u001b[39m\n\u001b[31m  updPhotoBadge(type);\u001b[39m\n\u001b[31m  if(arr.length===0){cont.innerHTML=`<div class=\\\"pslot\\\" onclick=\\\"addPhoto('${type}')\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to capture or upload</span><span class=\\\"hi-txt\\\">फोटो खींचें या अपलोड करें</span></div></div>`;addBtn.style.display='none';return;}\u001b[39m\n\u001b[31m  cont.innerHTML=arr.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const badge=isRetained?`<span class=\\\"pbadge\\\" style=\\\"background:#475569\\\">Existing</span>`:`<span class=\\\"pbadge\\\">${fmtSz(p.blob.size)}</span>`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replacePhoto('${type}',${i})\\\" style=\\\"right:36px;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"margin-bottom:12px\\\"><div class=\\\"pslot filled\\\" style=\\\"margin-bottom:8px\\\"><img src=\\\"${p.prev}\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmPhoto('${type}',${i})\\\">×</button>${badge}</div><input type=\\\"text\\\" placeholder=\\\"Comments (optional)\\\" value=\\\"${p.cmt||''}\\\" onchange=\\\"${type==='front'?'frontPhotos':'insidePhotos'}[${i}].cmt=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  addBtn.style.display=arr.length<(type==='inside'?5:3)?'inline-flex':'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// Photo source: 'camera' stamps geo, 'gallery' does not\u001b[39m\n\u001b[31mlet _photoSourceCb=null,_photoSourceQuality=null;·\u001b[39m\n\u001b[31mfunction capPhoto(cb,forceSource,quality){\u001b[39m\n\u001b[31m  // quality override: null=use setting, 'hd', 'compressed'\u001b[39m\n\u001b[31m  _photoSourceCb=cb;_photoSourceQuality=quality||null;\u001b[39m\n\u001b[31m  if(forceSource==='camera'){_doCapture(cb,'camera',quality);return;}\u001b[39m\n\u001b[31m  if(forceSource==='gallery'){_doCapture(cb,'gallery',quality);return;}\u001b[39m\n\u001b[31m  // Show picker\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _doCapture(cb,src,quality){\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  const i=document.createElement('input');\u001b[39m\n\u001b[31m  i.type='file';i.accept='image/*';\u001b[39m\n\u001b[31m  if(src==='camera')i.setAttribute('capture','environment');\u001b[39m\n\u001b[31m  i.style.display='none';\u001b[39m\n\u001b[31m  i.onchange=async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f)return;\u001b[39m\n\u001b[31m    const q=quality||_photoSourceQuality||null;\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      const blob=await compress(f,q==='hd'?1920:q==='compressed'?1280:null,q==='hd'?0.90:q==='compressed'?0.78:null);\u001b[39m\n\u001b[31m      // Only stamp if from camera (live photo)\u001b[39m\n\u001b[31m      const stamped=(src==='camera')?await stampPhoto(blob):blob;\u001b[39m\n\u001b[31m      // Save to device (auto-download trigger)\u001b[39m\n\u001b[31m      savePhotoToDevice(stamped);\u001b[39m\n\u001b[31m      cb({target:{files:[f]},_blob:stamped,_src:src});\u001b[39m\n\u001b[31m    }catch(err){toast('Photo processing failed — try again','error');console.error('_doCapture error:',err);}\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  document.body.appendChild(i);i.click();setTimeout(()=>i.remove(),8000);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction photoSrcCamera(){_doCapture(_photoSourceCb,'camera',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcGallery(){_doCapture(_photoSourceCb,'gallery',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcCancel(){document.getElementById('photo-src-dialog').classList.remove('open');_photoSourceCb=null;}·\u001b[39m\n\u001b[31m// Save photo to device gallery/downloads\u001b[39m\n\u001b[31mfunction savePhotoToDevice(blob){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    const a=document.createElement('a');\u001b[39m\n\u001b[31m    a.href=url;\u001b[39m\n\u001b[31m    a.download='Recce_'+Date.now()+'.jpg';\u001b[39m\n\u001b[31m    a.style.display='none';\u001b[39m\n\u001b[31m    document.body.appendChild(a);a.click();\u001b[39m\n\u001b[31m    setTimeout(()=>{URL.revokeObjectURL(url);a.remove();},1000);\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addPhoto(type){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}${e._src==='camera'&&geoStampEnabled?' · Stamped':''}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31masync function handleCapture(e,type){\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmPhoto(type,i){(type==='front'?frontPhotos:insidePhotos).splice(i,1);renderPhotos(type);saveDraft();}\u001b[39m\n\u001b[31mfunction replacePhoto(type,idx){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m    arr[idx]={...arr[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAddl(){\u001b[39m\n\u001b[31m  const cont=document.getElementById('add-cont');const btn=document.getElementById('add-addl');\u001b[39m\n\u001b[31m  const badge=document.getElementById('addl-badge');if(badge){badge.textContent=`${addlPhotos.length} / 8`;badge.className='cnt-badge '+(addlPhotos.length?'':'gray');}\u001b[39m\n\u001b[31m  cont.innerHTML=addlPhotos.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const sizeInfo=isRetained?'<span style=\\\"color:#475569\\\">Existing</span>':`${fmtSz(p.blob.size)}`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replaceAddl(${i})\\\" style=\\\"top:3px;left:3px;right:auto;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;gap:10px;align-items:start;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--g100)\\\"><div style=\\\"position:relative;flex-shrink:0\\\"><img src=\\\"${p.prev}\\\" style=\\\"width:80px;height:80px;object-fit:cover;border-radius:var(--rs)\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmAddl(${i})\\\" style=\\\"top:3px;right:3px\\\">×</button></div><div style=\\\"flex:1\\\"><input type=\\\"text\\\" placeholder=\\\"Description (optional)\\\" value=\\\"${p.desc||''}\\\" onchange=\\\"addlPhotos[${i}].desc=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"><div style=\\\"font-size:11px;color:var(--g400);margin-top:4px\\\">${sizeInfo}</div></div></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  btn.style.display=addlPhotos.length>=8?'none':'inline-flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction addAdditional(){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  addlPhotos.push({blob:bs,prev:URL.createObjectURL(bs),desc:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderAddl();saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31mfunction rmAddl(i){addlPhotos.splice(i,1);renderAddl();saveDraft();}\u001b[39m\n\u001b[31mfunction replaceAddl(idx){\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m    addlPhotos[idx]={...addlPhotos[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderAddl();saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// BRANDING\u001b[39m\n\u001b[31mfunction calcSqft(w,h){const wf=parseFloat(w),hf=parseFloat(h);if(!wf||!hf)return '';return `${(wf*hf).toFixed(0)} sq.in = ${(wf*hf/144).toFixed(2)} sq.ft`;}\u001b[39m\n\u001b[31mfunction renderBrandings(){\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  const cont=document.getElementById('br-items');\u001b[39m\n\u001b[31m  const hb=document.getElementById('br-hdr-badge');if(hb)hb.textContent=`${brandings.length} ${t(brandings.length!==1?'items':'item',brandings.length!==1?'आइटम':'आइटम')}`;\u001b[39m\n\u001b[31m  cont.innerHTML=brandings.map((b,i)=>`<div class=\\\"bitem\\\"><div class=\\\"bitem-hdr\\\"><div class=\\\"bitem-title\\\">${t('Branding','ब्रांडिंग')} ${i+1}${b.type?' — '+b.type:''}</div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:6px\\\">${i>0?`<button class=\\\"btn-d\\\" onclick=\\\"dupBr(${i})\\\" style=\\\"color:var(--or);border-color:var(--orl)\\\">${t('Dup ↑','डुप ↑')}</button>`:''}<button class=\\\"btn-d\\\" onclick=\\\"rmBr(${i})\\\">${t('Remove','हटाएं')}</button></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\"><label>${t('Type','प्रकार')} <span class=\\\"req\\\">*</span></label><div class=\\\"chip-grid\\\">${BTYPE.map(tp=>`<div class=\\\"chip${b.type===tp?' sel':''}\\\" onclick=\\\"setBType(${i},'${tp.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\"> ${tp}</div>`).join('')}</div></div>\u001b[39m\n\u001b[31m    <div class=\\\"dim-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Width (in)','चौड़ाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.w||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].w=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Height (in)','ऊंचाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.h||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].h=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"max-width:74px\\\"><label>${t('Qty','मात्रा')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.qty||''}\\\" placeholder=\\\"1\\\" inputmode=\\\"numeric\\\" onchange=\\\"brandings[${i}].qty=this.value;saveDraft()\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <span class=\\\"sqft\\\" id=\\\"sf${i}\\\">${calcSqft(b.w,b.h)||t('Enter W × H','W × H दर्ज करें')}</span>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-top:12px\\\"><label>${t('Photo','फोटो')} <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      ${b.prev?`<div class=\\\"pslot filled\\\" onclick=\\\"capBr(${i})\\\"><img src=\\\"${b.prev}\\\"><button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();rmBrPh(${i})\\\">×</button><span class=\\\"pbadge\\\">${b.blob?fmtSz(b.blob.size):'Existing'}</span></div>`:`<div><div class=\\\"pslot\\\" onclick=\\\"capBr(${i})\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\">${t('Tap to capture','दबाकर कैप्चर करें')}</div></div><div style=\\\"display:flex;gap:6px;margin-top:6px\\\"><button class=\\\"atool${(b.quality||imgQuality)==='compressed'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'compressed');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">${t('Compressed','कम्प्रेस्ड')}</button><button class=\\\"atool${(b.quality||imgQuality)==='hd'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'hd');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">HD</button></div></div>`}\u001b[39m\n\u001b[31m    </div></div>`).join('');\u001b[39m\n\u001b[31m  // Only show \\\"Add Another\\\" when last item is fully complete\u001b[39m\n\u001b[31m  const addDiv=document.getElementById('br-add');\u001b[39m\n\u001b[31m  if(addDiv&&brandings.length>0){\u001b[39m\n\u001b[31m    const last=brandings[brandings.length-1];\u001b[39m\n\u001b[31m    const lastComplete=last.type&&last.w&&last.h&&last.qty&&last.prev;\u001b[39m\n\u001b[31m    addDiv.style.display=(lastComplete&&brandings.length<15)?'block':'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updSqft(i){const el=document.getElementById('sf'+i);if(el)el.textContent=calcSqft(brandings[i].w,brandings[i].h)||t('Enter W × H','W × H दर्ज करें');saveDraft();}\u001b[39m\n\u001b[31mfunction setBType(i,tp){brandings[i].type=tp;renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction addBranding(){if(brandings.length>=15){toast(t('Max 15 items','अधिकतम 15 आइटम'),'error');return;}brandings.push({type:'',w:'',h:'',qty:'1',blob:null,prev:null});renderBrandings();}\u001b[39m\n\u001b[31mfunction dupBr(i){if(brandings.length>=10){toast(t('Max 10 items','अधिकतम 10 आइटम'),'error');return;}const s=brandings[i-1];brandings.splice(i,0,{type:s.type,w:s.w,h:s.h,qty:s.qty,blob:null,prev:null});renderBrandings();toast(t('Duplicated — add photo','डुप्लीकेट — फोटो जोड़ें'),'info');}\u001b[39m\n\u001b[31mfunction rmBr(i){brandings.splice(i,1);renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction capBr(i){\u001b[39m\n\u001b[31m  const q=brandings[i]?.quality||imgQuality;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f,q==='hd'?1920:1280,q==='hd'?0.90:0.78));\u001b[39m\n\u001b[31m    brandings[i].blob=bs;brandings[i].prev=URL.createObjectURL(bs);\u001b[39m\n\u001b[31m    brandings[i].fromCamera=(e._src==='camera');\u001b[39m\n\u001b[31m    openAnnot(i);\u001b[39m\n\u001b[31m  },null,q);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmBrPh(i){brandings[i].blob=null;brandings[i].prev=null;renderBrandings();}\u001b[39m\n\u001b[31mfunction setBrQuality(i,q){brandings[i].quality=q;renderBrandings();}·\u001b[39m\n\u001b[31m// VIDEO / DOC\u001b[39m\n\u001b[31mfunction setVideo(v){F.hasVideo=v;document.getElementById('vid-yes').classList.toggle('sel',v);document.getElementById('vid-no').classList.toggle('sel',!v);document.getElementById('vid-sec').style.display=v?'block':'none';saveDraft();}\u001b[39m\n\u001b[31masync function handleVideo(e){videoBlob=e.target.files[0];if(!videoBlob)return;document.getElementById('vid-slot').innerHTML=`<div style=\\\"padding:14px;font-size:13px;color:var(--gn)\\\">✓ ${videoBlob.name} (${fmtSz(videoBlob.size)})</div>`;}\u001b[39m\n\u001b[31mfunction setBranding(v){F.hasBranding=v;document.getElementById('br-yes').classList.toggle('sel',v);document.getElementById('br-no').classList.toggle('sel',!v);document.getElementById('br-add').style.display=v?'block':'none';if(v&&brandings.length===0)addBranding();saveDraft();}\u001b[39m\n\u001b[31masync function handleDoc(e){const f=e.target.files[0];if(!f)return;submissionDoc=f.type.startsWith('image/')?await compress(f,1600,.85):f;const slot=document.getElementById('doc-slot');if(f.type.startsWith('image/')){slot.classList.add('filled');slot.innerHTML=`<img src=\\\"${URL.createObjectURL(submissionDoc)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}else{slot.innerHTML=`<div style=\\\"padding:16px;font-size:13px;color:var(--gn)\\\">✓ ${f.name} (${fmtSz(f.size)})</div>`;}buildReview();}·\u001b[39m\n\u001b[31m// CLIENT CHIPS\u001b[39m\n\u001b[31mfunction renderClientChips(){\u001b[39m\n\u001b[31m  const grid = document.getElementById('client-chips'); if (!grid) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  clientList.forEach(c => {\u001b[39m\n\u001b[31m    const sel = !_clientOtherMode && _selectedClient === c;\u001b[39m\n\u001b[31m    html += `<div class=\\\"cl-chip${sel?' sel':''}\\\" onclick=\\\"selectClientChip('${esc(c)}')\\\">${esc(c)}</div>`;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html += `<div class=\\\"cl-chip cl-chip-other${_clientOtherMode?' sel':''}\\\" onclick=\\\"selectClientOther()\\\"><span class=\\\"en-txt\\\">Other…</span><span class=\\\"hi-txt\\\">अन्य…</span></div>`;\u001b[39m\n\u001b[31m  grid.innerHTML = html;\u001b[39m\n\u001b[31m  document.getElementById('client-other-wrap').style.display = _clientOtherMode ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientChip(name){\u001b[39m\n\u001b[31m  _selectedClient = name; _clientOtherMode = false;\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').value = '';\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientOther(){\u001b[39m\n\u001b[31m  _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onClientOtherInput(){\u001b[39m\n\u001b[31m  _selectedClient = document.getElementById('f-client-other').value.trim();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction getClientName(){\u001b[39m\n\u001b[31m  if (_clientOtherMode) return (document.getElementById('f-client-other')?.value||'').trim();\u001b[39m\n\u001b[31m  return _selectedClient;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction autoSetClient(brandName){\u001b[39m\n\u001b[31m  if (!brandName) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  if (clientList.includes(brandName)){\u001b[39m\n\u001b[31m    _selectedClient = brandName; _clientOtherMode = false;\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    // Not in list — pre-fill the Other field\u001b[39m\n\u001b[31m    _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m    const inp = document.getElementById('f-client-other');\u001b[39m\n\u001b[31m    if (inp && !inp.value) inp.value = brandName;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// STEP VALIDATION\u001b[39m\n\u001b[31mfunction getSD(){if(selectedStore&&!manualMode)return{storeName:selectedStore.name,brand:selectedStore.brand||'',address:selectedStore.address||'',mobile:selectedStore.mobile||''};return{storeName:(document.getElementById('f-store')?.value||'').trim(),brand:document.getElementById('f-brand')?.value||'',address:(document.getElementById('f-addr')?.value||'').trim(),mobile:(document.getElementById('f-mobile')?.value||'').trim()};}\u001b[39m\n\u001b[31mfunction step2(){\u001b[39m\n\u001b[31m  const d=document.getElementById('f-date').value;\u001b[39m\n\u001b[31m  if(!d){toast('Select date','error');return;}\u001b[39m\n\u001b[31m  const sd=getSD();\u001b[39m\n\u001b[31m  if(!sd.storeName){toast('Select or enter store name','error');return;}\u001b[39m\n\u001b[31m  if(!sd.brand){toast('Select a brand','error');document.getElementById('brand-selector').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  if(!sd.address){toast('Enter store address','error');return;}\u001b[39m\n\u001b[31m  const clientName=getClientName();\u001b[39m\n\u001b[31m  if(!clientName){toast(t('Select a client','क्लाइंट चुनें'),'error');document.getElementById('client-chips').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  // Check missing fields filled\u001b[39m\n\u001b[31m  const missAddr=document.getElementById('sc-miss-address');\u001b[39m\n\u001b[31m  if(missAddr&&!missAddr.value.trim()){toast('Enter store address in the highlighted field','error');missAddr.focus();return;}\u001b[39m\n\u001b[31m  const missMob=document.getElementById('sc-miss-mobile');\u001b[39m\n\u001b[31m  // mobile not required — just copy if filled\u001b[39m\n\u001b[31m  if(missMob&&missMob.value.trim()&&!F.mobile)F.mobile=missMob.value.trim();\u001b[39m\n\u001b[31m  Object.assign(F,{date:d,...sd,clientName});saveDraft();\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');showView('form-photos');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction step3(){if(!frontPhotos.length){toast('Add at least 1 front view photo','error');return;}showView('form-video');}\u001b[39m\n\u001b[31mfunction step4(){if(F.hasVideo===undefined||F.hasVideo===null){toast('Select Yes or No for video','error');return;}renderBrandings();showView('form-branding');}\u001b[39m\n\u001b[31mfunction step5(){if(F.hasBranding===undefined||F.hasBranding===null){toast('Select Yes or No for branding space','error');return;}if(F.hasBranding){for(let i=0;i<brandings.length;i++){const b=brandings[i];if(!b.type){toast(`Select branding type for item ${i+1}`,'error');return;}if(!b.w||!b.h){toast(`Enter W and H dimensions for item ${i+1}`,'error');return;}if(!b.qty){toast(`Enter qty for item ${i+1}`,'error');return;}if(!b.blob&&!b.prev){toast(`Add photo for item ${i+1}`,'error');return;}}}renderAddl();buildReview();showView('form-additional');}·\u001b[39m\n\u001b[31m// REVIEW\u001b[39m\n\u001b[31mfunction buildReview(){const el=document.getElementById('rev-body');if(!el)return;const sd=getSD();const cn=getClientName();el.innerHTML=`<div><div class=\\\"rev-lbl\\\">Store</div><div class=\\\"rev-val\\\">${sd.storeName||'—'} · ${sd.brand||'—'}</div><div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">${sd.address||'—'}${sd.mobile?' · '+sd.mobile:''}</div>${gpsCoords?`<div style=\\\"font-size:11px;color:var(--gn);margin-top:3px\\\">📍 ${gpsCoords.lat}, ${gpsCoords.lng} ±${gpsCoords.acc}m</div>`:''}</div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Client</div><div class=\\\"rev-val\\\" style=\\\"color:${cn?'var(--nv)':'var(--rd)'}\\\">${cn||'⚠ Not selected — required'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Photos — Front · Inside · Additional</div><div class=\\\"rev-val\\\">${frontPhotos.length} · ${insidePhotos.length} · ${addlPhotos.length}</div><div class=\\\"rev-photos\\\">${[...frontPhotos,...insidePhotos].slice(0,6).map(p=>`<img class=\\\"rev-thumb\\\" src=\\\"${p.prev}\\\">`).join('')}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Video · Branding items</div><div class=\\\"rev-val\\\">${F.hasVideo?'Yes':'No'} · ${brandings.length} item(s)</div></div>${F.hasBranding&&brandings.length?`<div style=\\\"margin-top:8px\\\">${brandings.map((b,i)=>`<div style=\\\"font-size:12px;color:var(--g600);padding:4px 0;border-bottom:1px solid var(--g100)\\\">${i+1}. ${b.type||'No type'} — ${b.w||'?'}×${b.h||'?'}\\\" × ${b.qty||'?'} — ${calcSqft(b.w,b.h)||'?'}</div>`).join('')}</div>`:''}<div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Additional photos <span style=\\\"font-size:11px;color:var(--g400)\\\">(optional)</span></div><div class=\\\"rev-val\\\" style=\\\"color:${addlPhotos.length?'var(--gn)':'var(--g500)'}\\\">${addlPhotos.length?`✓ ${addlPhotos.length} photo(s) added`:'None added'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Mandatory document</div><div class=\\\"rev-val\\\" style=\\\"color:${(submissionDoc||_docExistingUrl)?'var(--gn)':'var(--rd)'}\\\">${(submissionDoc||_docExistingUrl)?'✓ Uploaded':'⚠ Missing — required'}</div></div>`;}·\u001b[39m\n\u001b[31m// SUBMIT\u001b[39m\n\u001b[31masync function submitRecce(){\u001b[39m\n\u001b[31m  if(!submissionDoc&&!_docExistingUrl){toast('Upload mandatory doc first','error');return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('sub-btn');btn.disabled=true;btn.textContent='Saving…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const isEdit=!!(F.editingId);\u001b[39m\n\u001b[31m    const id=isEdit?F.editingId:('RC_'+Date.now()+'_'+Math.random().toString(36).slice(2,6).toUpperCase());\u001b[39m\n\u001b[31m    const sd=getSD();\u001b[39m\n\u001b[31m    const _hub=_recceHubUser();\u001b[39m\n\u001b[31m    const entry={id,timestamp:isEdit?(await dbGet('subs',id))?.timestamp||new Date().toISOString():new Date().toISOString(),editedAt:isEdit?new Date().toISOString():undefined,status:'pending',submittedBy:_hub.empId||null,submittedByName:_hub.name||null,data:{...F,...sd,gpsCoords,frontPhotos:await Promise.all(frontPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),insidePhotos:await Promise.all(insidePhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),videoNote:F.hasVideo&&videoBlob?`Video local (${fmtSz(videoBlob.size)}) — share via WhatsApp`:null,videoCmt:document.getElementById('f-vid-cmt')?.value||'',brandings:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:calcSqft(b.w,b.h),photoB64:b.blob?await b64(b.blob):null,existingUrl:b.existingUrl||null}))),addlPhotos:await Promise.all(addlPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,desc:p.desc,existingUrl:p.existingUrl||null}))),docB64:submissionDoc?await b64(submissionDoc):null,_docExistingUrl:_docExistingUrl||null}};\u001b[39m\n\u001b[31m    entry.campaignId       = _selectedCampaignId || null;\u001b[39m\n\u001b[31m    entry.notifySupervisor = _notifySupervisor   || false;\u001b[39m\n\u001b[31m    await dbPut('subs',entry);\u001b[39m\n\u001b[31m    await dbDel('draft','current');\u001b[39m\n\u001b[31m    toast(isEdit?'Recce updated ✓':'Recce saved ✓','success');\u001b[39m\n\u001b[31m    if(navigator.onLine)syncNow();\u001b[39m\n\u001b[31m    showView('home');loadHome();checkDraft();\u001b[39m\n\u001b[31m  }catch(err){toast('Error: '+err.message,'error');}\u001b[39m\n\u001b[31m  finally{btn.disabled=false;btn.textContent='Submit Recce ✓';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// SYNC\u001b[39m\n\u001b[31masync function syncNow() {\u001b[39m\n\u001b[31m  if (!navigator.onLine) { toast('Offline — sync when back online', 'info'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('sync-btn');\u001b[39m\n\u001b[31m  const SYNC_ICON = '<svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg>Sync';\u001b[39m\n\u001b[31m  if (btn) { btn.innerHTML = '<span class=\\\"spin\\\">↻</span> Syncing'; btn.disabled = true; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const all      = await dbAll('subs');\u001b[39m\n\u001b[31m    const pend     = all.filter(s => s.status === 'pending' || s.status === 'failed');\u001b[39m\n\u001b[31m    const backfill = all.filter(s => s.status === 'synced' && !s.gasAt);\u001b[39m\n\u001b[31m    if (!pend.length && !backfill.length) { toast('All synced ✓', 'success'); return; }·\u001b[39m\n\u001b[31m    const gasUrl = (await cfg('gas-url')) || DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    function fireGas(s) {\u001b[39m\n\u001b[31m      if (!gasUrl) return;\u001b[39m\n\u001b[31m      fetch(gasUrl, { method:'POST', mode:'no-cors',\u001b[39m\n\u001b[31m        body: JSON.stringify({ action:'syncSheet', submission: s }) })\u001b[39m\n\u001b[31m        .catch(() => {});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    let ok = 0;\u001b[39m\n\u001b[31m    for (const s of pend) {\u001b[39m\n\u001b[31m      // Fire Sheet sync (no-cors fire-and-forget — writes row to Google Sheet)\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      // Primary: upload photos → auto-trigger slides → generate report → store in PostgreSQL\u001b[39m\n\u001b[31m      const { ok: pgOk, viewUrl } = await syncToPostgres(s);\u001b[39m\n\u001b[31m      if (pgOk) {\u001b[39m\n\u001b[31m        s.status = 'synced'; s.syncedAt = new Date().toISOString();\u001b[39m\n\u001b[31m        if (viewUrl) s.viewUrl = viewUrl;\u001b[39m\n\u001b[31m        await dbPut('subs', s); ok++;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        s.status = 'failed'; await dbPut('subs', s);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Backfill: entries synced to Postgres but never reached Sheet GAS\u001b[39m\n\u001b[31m    for (const s of backfill) {\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      await dbPut('subs', s);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if (backfill.length) toast(`Sent ${backfill.length} older entries to Sheet`, 'info');·\u001b[39m\n\u001b[31m    await cfg('last-sync', new Date().toISOString());\u001b[39m\n\u001b[31m    if (pend.length) toast(`Synced ${ok}/${pend.length}`, ok === pend.length ? 'success' : 'error');\u001b[39m\n\u001b[31m    loadHome();\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.innerHTML = SYNC_ICON; btn.disabled = false; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN HOME ──────────────────────────────────────────────\u001b[39m\n\u001b[31masync function loadHomeAdmin() {\u001b[39m\n\u001b[31m  // Adapt UI for admin view\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const _sh = document.querySelector('.sh'); if (_sh) _sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = 'All Submissions';\u001b[39m\n\u001b[31m  const slbls = document.querySelectorAll('.slbl');\u001b[39m\n\u001b[31m  if (slbls[0]) slbls[0].textContent = 'Showing';\u001b[39m\n\u001b[31m  if (slbls[1]) slbls[1].textContent = 'Agents';·\u001b[39m\n\u001b[31m  // Back-to-menu button for supervisors\u001b[39m\n\u001b[31m  if (_isSupervisor() && !document.getElementById('sup-back-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => { document.getElementById('sup-back-btn').remove(); renderSupLanding(); };\u001b[39m\n\u001b[31m    const content = document.querySelector('#view-home .content');\u001b[39m\n\u001b[31m    content.prepend(bb);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Show filter bar — restore if hidden by renderSupLanding, else inject fresh\u001b[39m\n\u001b[31m  const _existingFb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (_existingFb) { _existingFb.style.display = ''; }\u001b[39m\n\u001b[31m  if (!_existingFb) {\u001b[39m\n\u001b[31m    const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m    const fb = document.createElement('div');\u001b[39m\n\u001b[31m    fb.id = 'admin-filter-bar';\u001b[39m\n\u001b[31m    fb.className = 'af-bar';\u001b[39m\n\u001b[31m    fb.innerHTML =\u001b[39m\n\u001b[31m      `<div class=\\\"af-grid\\\">\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-agent\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Agents</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-brand\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Brands</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-client\\\" onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Clients</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-period\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">All Time</option>\u001b[39m\n\u001b[31m          <option value=\\\"7\\\">Last 7 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"30\\\">Last 30 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"90\\\">Last 3 months</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-group\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"date\\\">Sort: Recent</option>\u001b[39m\n\u001b[31m          <option value=\\\"agent\\\">Group: Agent</option>\u001b[39m\n\u001b[31m          <option value=\\\"brand\\\">Group: Brand</option>\u001b[39m\n\u001b[31m          <option value=\\\"client\\\">Group: Client</option>\u001b[39m\n\u001b[31m          <option value=\\\"city\\\">Group: City</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m        <input class=\\\"af-inp\\\" id=\\\"af-search\\\" type=\\\"text\\\" placeholder=\\\"🔍 Search store or city…\\\" oninput=\\\"renderAdminList()\\\" style=\\\"flex:1;min-width:120px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"del-toggle-btn\\\" id=\\\"del-toggle-btn\\\" onclick=\\\"toggleDeletedView()\\\" style=\\\"flex-shrink:0\\\">📋 View Deleted</button>\u001b[39m\n\u001b[31m        ${_isSupervisor() ? `<button class=\\\"del-toggle-btn\\\" id=\\\"pending-job-btn\\\" onclick=\\\"togglePendingJobView()\\\" style=\\\"flex-shrink:0;background:#fef3c7;color:#92400e;border-color:#f59e0b\\\">⚑ Unlinked <span id=\\\"pending-job-count\\\" style=\\\"font-weight:900\\\"></span></button>` : ''}\u001b[39m\n\u001b[31m        ${_adminUnlocked ? `<button class=\\\"del-toggle-btn\\\" id=\\\"regen-rpt-btn\\\" onclick=\\\"regenAllReports()\\\" style=\\\"flex-shrink:0\\\">&#x21BB; Regen Reports</button>` : ''}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    sh.parentNode.insertBefore(fb, sh);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Fetch\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  list.innerHTML = '<div style=\\\"text-align:center;padding:40px\\\"><div class=\\\"spinner\\\"></div></div>';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?order=submitted_at.desc&limit=500`, { headers: _RC_READ });\u001b[39m\n\u001b[31m    _adminRows = resp.ok ? await resp.json() : [];\u001b[39m\n\u001b[31m    document.getElementById('stat-total').textContent = _adminRows.length;\u001b[39m\n\u001b[31m    if (resp.ok) {\u001b[39m\n\u001b[31m      const now = new Date();\u001b[39m\n\u001b[31m      document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m        'Loaded ' + now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Populate agent dropdown\u001b[39m\n\u001b[31m    const agents = [...new Set(_adminRows.map(r => r.submitted_by).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-agent').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Agents (${agents.length})</option>` +\u001b[39m\n\u001b[31m      agents.map(a => `<option value=\\\"${a}\\\">${a}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate brand dropdown\u001b[39m\n\u001b[31m    const brands = [...new Set(_adminRows.map(r => r.brand).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-brand').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Brands (${brands.length})</option>` +\u001b[39m\n\u001b[31m      brands.map(b => `<option value=\\\"${b}\\\">${b}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate client dropdown\u001b[39m\n\u001b[31m    const clients = [...new Set(_adminRows.map(r => r.client_name).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-client').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Clients (${clients.length})</option>` +\u001b[39m\n\u001b[31m      clients.map(c => `<option value=\\\"${c}\\\">${c}</option>`).join('');·\u001b[39m\n\u001b[31m    // Update pending-job count badge\u001b[39m\n\u001b[31m    const unlinkedCount = _adminRows.filter(r => !r.deleted_at && !r.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinkedCount ? `(${unlinkedCount})` : '';·\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">⚠️</div><div class=\\\"empty-txt\\\">Could not load — check connection</div></div>';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction togglePendingJobView() {\u001b[39m\n\u001b[31m  _pendingJobFilter = !_pendingJobFilter;\u001b[39m\n\u001b[31m  _showDeletedView  = false;\u001b[39m\n\u001b[31m  const btn = document.getElementById('pending-job-btn');\u001b[39m\n\u001b[31m  if (btn) btn.style.background = _pendingJobFilter ? '#f59e0b' : '#fef3c7';\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function openLinkJobModal(subId, storeName) {\u001b[39m\n\u001b[31m  _linkJobSubId = subId;\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  const storeEl = document.getElementById('link-job-store');\u001b[39m\n\u001b[31m  const sel = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  if (!modal) return;\u001b[39m\n\u001b[31m  if (storeEl) storeEl.textContent = storeName || subId;\u001b[39m\n\u001b[31m  if (errEl) errEl.textContent = '';\u001b[39m\n\u001b[31m  // Load campaigns into dropdown\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (!_campaignList.length) {\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m      _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  if (sel) {\u001b[39m\n\u001b[31m    sel.innerHTML = '<option value=\\\"\\\">— Select campaign —</option>' +\u001b[39m\n\u001b[31m      _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  modal.style.display = 'flex';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeLinkJobModal() {\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  if (modal) modal.style.display = 'none';\u001b[39m\n\u001b[31m  _linkJobSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function saveLinkJob() {\u001b[39m\n\u001b[31m  const sel    = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl  = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  const campId = sel?.value || '';\u001b[39m\n\u001b[31m  if (!campId) { if (errEl) errEl.textContent = 'Select a campaign'; return; }\u001b[39m\n\u001b[31m  if (!_linkJobSubId) return;\u001b[39m\n\u001b[31m  const btn = document.querySelector('#modal-link-job button[onclick=\\\"saveLinkJob()\\\"]');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Linking…'; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(_linkJobSubId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ campaign_id: campId }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Patch failed');\u001b[39m\n\u001b[31m    // Update local cache\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === _linkJobSubId);\u001b[39m\n\u001b[31m    if (idx >= 0) _adminRows[idx].campaign_id = campId;\u001b[39m\n\u001b[31m    // Update pending count badge\u001b[39m\n\u001b[31m    const unlinked = _adminRows.filter(x => !x.deleted_at && !x.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinked ? `(${unlinked})` : '';\u001b[39m\n\u001b[31m    closeLinkJobModal();\u001b[39m\n\u001b[31m    toast('Job linked ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    if (errEl) errEl.textContent = 'Failed to link — try again';\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.disabled = false; btn.textContent = '🔗 Link Job'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAdminList() {\u001b[39m\n\u001b[31m  const agent  = document.getElementById('af-agent')?.value  || '';\u001b[39m\n\u001b[31m  const brand  = document.getElementById('af-brand')?.value  || '';\u001b[39m\n\u001b[31m  const period = document.getElementById('af-period')?.value || '';\u001b[39m\n\u001b[31m  const search = (document.getElementById('af-search')?.value || '').toLowerCase().trim();\u001b[39m\n\u001b[31m  const group  = document.getElementById('af-group')?.value  || 'date';·\u001b[39m\n\u001b[31m  // Pending-job filter overrides deleted/normal modes\u001b[39m\n\u001b[31m  let rows;\u001b[39m\n\u001b[31m  if (_pendingJobFilter) {\u001b[39m\n\u001b[31m    rows = _adminRows.filter(r => !r.deleted_at && !r.campaign_id);\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows = _showDeletedView\u001b[39m\n\u001b[31m      ? _adminRows.filter(r => r.deleted_at)\u001b[39m\n\u001b[31m      : _adminRows.filter(r => !r.deleted_at);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const client = document.getElementById('af-client')?.value || '';\u001b[39m\n\u001b[31m  if (agent)  rows = rows.filter(r => r.submitted_by === agent);\u001b[39m\n\u001b[31m  if (brand)  rows = rows.filter(r => r.brand === brand);\u001b[39m\n\u001b[31m  if (client) rows = rows.filter(r => r.client_name === client);\u001b[39m\n\u001b[31m  if (search) rows = rows.filter(r => (r.store_name||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.city||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.client_name||'').toLowerCase().includes(search));\u001b[39m\n\u001b[31m  if (period && !_showDeletedView) {\u001b[39m\n\u001b[31m    const cut = new Date(); cut.setDate(cut.getDate() - parseInt(period));\u001b[39m\n\u001b[31m    rows = rows.filter(r => new Date(r.submitted_at) >= cut);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const uniqueAgents = new Set(rows.map(r => r.submitted_by).filter(Boolean)).size;\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = rows.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = uniqueAgents;\u001b[39m\n\u001b[31m  const deletedCount = _adminRows.filter(r => r.deleted_at).length;\u001b[39m\n\u001b[31m  const delBtn = document.getElementById('del-toggle-btn');\u001b[39m\n\u001b[31m  if (delBtn) {\u001b[39m\n\u001b[31m    if (_showDeletedView) {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 Hide Deleted (${deletedCount})` : '📋 Hide Deleted';\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 View Deleted (${deletedCount})` : '📋 View Deleted';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    delBtn.classList.toggle('active', _showDeletedView);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!rows.length) {\u001b[39m\n\u001b[31m    list.innerHTML = _showDeletedView\u001b[39m\n\u001b[31m      ? '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">✅</div><div class=\\\"empty-txt\\\">No deleted recces</div></div>'\u001b[39m\n\u001b[31m      : '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">🔍</div><div class=\\\"empty-txt\\\">No matching submissions</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (group === 'agent') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.submitted_by||'').localeCompare(b.submitted_by||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.submitted_by || 'Unknown';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">👤 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'brand') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.brand||'').localeCompare(b.brand||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.brand || 'No Brand';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🏷 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'client') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.client_name||'').localeCompare(b.client_name||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.client_name || 'No Client';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🤝 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'city') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.city||'').localeCompare(b.city||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.city || 'No City';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">📍 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows.sort((a,b) => new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    rows.forEach(r => { html += adminCard(r); });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminCard(r) {\u001b[39m\n\u001b[31m  const dt    = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds    = dt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m  const tm    = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const photos = (r.front_photos||0) + (r.inside_photos||0) + (r.addl_photos||0);\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const canDelete  = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const canArchive = _RECCE_CFG_ADMINS.includes(hub?.empId) && !r.client_archived;·\u001b[39m\n\u001b[31m  // Client status badge\u001b[39m\n\u001b[31m  const clientStatusMap = {\u001b[39m\n\u001b[31m    approved:              {t:'✓ Approved',    s:'color:#166534;background:#dcfce7;border:1px solid #86efac'},\u001b[39m\n\u001b[31m    rejected:              {t:'✕ Rejected',    s:'color:#991b1b;background:#fee2e2;border:1px solid #fca5a5'},\u001b[39m\n\u001b[31m    approved_with_changes: {t:'✎ Approved w/ Comments', s:'color:#92400e;background:#fef3c7;border:1px solid #fcd34d'},\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const csCfg = clientStatusMap[r.client_status];\u001b[39m\n\u001b[31m  const clientStatusBadge = csCfg\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;${csCfg.s}\\\">${csCfg.t}</span>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const archiveBadge = r.client_archived\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;color:#475569;background:#f1f5f9;border:1px solid #cbd5e1\\\">⬚ Client hidden</span>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  if (r.deleted_at) {\u001b[39m\n\u001b[31m    const delDt = new Date(r.deleted_at);\u001b[39m\n\u001b[31m    const delDs = delDt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m    const reasonLabel = r.deletion_reason === 'wrong' ? 'Wrong' : r.deletion_reason === 'duplicate' ? 'Duplicate' : 'Test';\u001b[39m\n\u001b[31m    return `<div class=\\\"asc deleted-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m        <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m            <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds}</span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m          <span class=\\\"del-reason-tag\\\">❌ ${reasonLabel}</span>\u001b[39m\n\u001b[31m          <div class=\\\"del-by-txt\\\">by ${r.deleted_by||'?'} · ${delDs}</div>\u001b[39m\n\u001b[31m          ${canDelete ? `<button class=\\\"restore-btn\\\" onclick=\\\"event.stopPropagation();restoreRecce('${r.sub_id}')\\\">↩ Restore</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Submitted by ${r.submitted_by||'?'}</div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const chips = [\u001b[39m\n\u001b[31m    photos > 0   ? `📷 ${photos} photo${photos!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.has_video  ? '🎥 Video' : null,\u001b[39m\n\u001b[31m    r.has_branding ? `🪧 ${r.branding_count} branding${r.branding_count!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.city       ? `📍 ${r.city}` : (r.address ? `📍 ${r.address}` : null),\u001b[39m\n\u001b[31m    r.view_url   ? '👁 View available' : null,\u001b[39m\n\u001b[31m  ].filter(Boolean);·\u001b[39m\n\u001b[31m  const delBtnHtml = canDelete\u001b[39m\n\u001b[31m    ? `<button class=\\\"del-btn\\\" onclick=\\\"event.stopPropagation();openDeleteModal('${r.sub_id}')\\\" title=\\\"Delete recce\\\">🗑</button>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const editReqHtml = r.edit_assigned_to\u001b[39m\n\u001b[31m    ? `<span class=\\\"edit-req-badge\\\">✏ Edit sent to ${r.edit_assigned_to}</span>`\u001b[39m\n\u001b[31m    : (_isSupervisor()\u001b[39m\n\u001b[31m        ? `<button class=\\\"req-edit-btn\\\" onclick=\\\"event.stopPropagation();openEditRequestModal('${r.sub_id}')\\\">✏ Request Edit</button>`\u001b[39m\n\u001b[31m        : '');·\u001b[39m\n\u001b[31m  const editRow = editReqHtml\u001b[39m\n\u001b[31m    ? `<div style=\\\"margin-top:6px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">${editReqHtml}</div>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const showPdfBtn = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m  const pdfClass = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m  const pdfLabel = '📄 PDF';\u001b[39m\n\u001b[31m  const linkJobBtn = (_pendingJobFilter && _isSupervisor() && !r.campaign_id)\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:#f59e0b;color:#000;border-color:#f59e0b;font-weight:700\\\" onclick=\\\"event.stopPropagation();openLinkJobModal('${r.sub_id}','${(r.store_name||'Unknown').replace(/'/g,'\\\\\\\\\\\\'')}')\\\">🔗 Link Job</button>`\u001b[39m\n\u001b[31m    : (r.campaign_id ? `<span style=\\\"font-size:10px;color:var(--g400);align-self:center\\\">🔗 ${r.campaign_id}</span>` : '');\u001b[39m\n\u001b[31m  const archiveBtn = canArchive\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:rgba(99,102,241,.08);border-color:var(--nv);color:var(--nv)\\\" onclick=\\\"event.stopPropagation();archiveRecce('${r.sub_id}')\\\">⛚ Archive</button>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const btnsRow = `<div class=\\\"rpt-btns\\\">\u001b[39m\n\u001b[31m    <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openAdminRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m    ${showPdfBtn ? `<button class=\\\"${pdfClass}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">${pdfLabel}</button>` : ''}\u001b[39m\n\u001b[31m    ${linkJobBtn}\u001b[39m\n\u001b[31m    ${archiveBtn}\u001b[39m\n\u001b[31m  </div>`;·\u001b[39m\n\u001b[31m  return `<div class=\\\"asc\\\">\u001b[39m\n\u001b[31m    <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m      <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m          ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          ${r.client_name&&r.client_name!==r.brand?`<span class=\\\"client-tag\\\">🤝 ${r.client_name}</span>`:''}\u001b[39m\n\u001b[31m          <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds} · ${tm}</span>\u001b[39m\n\u001b[31m          ${clientStatusBadge}\u001b[39m\n\u001b[31m          ${archiveBadge}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <span class=\\\"asc-agent\\\">👤 ${r.submitted_by||'?'}</span>\u001b[39m\n\u001b[31m        ${delBtnHtml}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    ${chips.length?`<div class=\\\"asc-chips\\\">${chips.map(c=>`<span class=\\\"asc-chip\\\">${c}</span>`).join('')}</div>`:''}\u001b[39m\n\u001b[31m    ${editRow}\u001b[39m\n\u001b[31m    ${btnsRow}\u001b[39m\n\u001b[31m  </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _ensurePdfOverlay() {\u001b[39m\n\u001b[31m  if (document.getElementById('pdf-wait-ov')) return;\u001b[39m\n\u001b[31m  const ov = document.createElement('div');\u001b[39m\n\u001b[31m  ov.id = 'pdf-wait-ov';\u001b[39m\n\u001b[31m  ov.innerHTML = '<div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Generating PDF…</div><div class=\\\"po-sub\\\" id=\\\"pw-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"pw-pfill\\\"></div></div>';\u001b[39m\n\u001b[31m  document.body.appendChild(ov);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _showPdfOverlay(msg) {\u001b[39m\n\u001b[31m  _ensurePdfOverlay();\u001b[39m\n\u001b[31m  document.getElementById('pw-sub').textContent = msg || '';\u001b[39m\n\u001b[31m  document.getElementById('pw-pfill').style.width = '0%';\u001b[39m\n\u001b[31m  document.getElementById('pdf-wait-ov').style.display = 'flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _hidePdfOverlay() {\u001b[39m\n\u001b[31m  const ov = document.getElementById('pdf-wait-ov');\u001b[39m\n\u001b[31m  if (ov) ov.style.display = 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function openPdf(subId, pdfUrl, viewUrl) {\u001b[39m\n\u001b[31m  if (pdfUrl) { window.open(pdfUrl, '_blank'); return; }\u001b[39m\n\u001b[31m  if (!viewUrl) {\u001b[39m\n\u001b[31m    toast('Report view not available yet — please try after the report is generated.', 'info');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _showPdfOverlay('Requesting PDF generation…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type': 'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({type: 'regen-pdf', subId, viewUrl})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  let attempts = 0;\u001b[39m\n\u001b[31m  const MAX = 24;\u001b[39m\n\u001b[31m  const poll = async () => {\u001b[39m\n\u001b[31m    attempts++;\u001b[39m\n\u001b[31m    const pct = Math.min(88, Math.round(attempts / MAX * 88));\u001b[39m\n\u001b[31m    document.getElementById('pw-pfill').style.width = pct + '%';\u001b[39m\n\u001b[31m    const left = Math.ceil((MAX - attempts) * 5);\u001b[39m\n\u001b[31m    document.getElementById('pw-sub').textContent = 'Checking… (' + left + 's remaining)';\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const res = await fetch('/db/submissions?sub_id=eq.' + subId + '&select=pdf_url', {\u001b[39m\n\u001b[31m        headers: {'Content-Profile': 'recce', 'Accept-Profile': 'recce'}\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      const rows = await res.json();\u001b[39m\n\u001b[31m      if (rows && rows[0] && rows[0].pdf_url) {\u001b[39m\n\u001b[31m        document.getElementById('pw-pfill').style.width = '100%';\u001b[39m\n\u001b[31m        setTimeout(() => { _hidePdfOverlay(); window.open(rows[0].pdf_url, '_blank'); }, 400);\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(_) {}\u001b[39m\n\u001b[31m    if (attempts >= MAX) { _hidePdfOverlay(); toast('PDF generation timed out. Please try again later.', 'error'); return; }\u001b[39m\n\u001b[31m    setTimeout(poll, 5000);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  setTimeout(poll, 4000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openAdminRecce(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];·\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">\u001b[39m\n\u001b[31m         📍 View on Google Maps (${Number(r.gps_lat).toFixed(4)}, ${Number(r.gps_lng).toFixed(4)})\u001b[39m\n\u001b[31m       </a>` : '';·\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} ft × ${b.h||'?'} ft · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos not yet available — field agent must re-sync from their device to upload view\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Submission Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">👤 ${r.submitted_by||'Unknown'}</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            ${meta.videoCmt?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500);font-size:12px\\\">${meta.videoCmt}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m          ${(()=>{\u001b[39m\n\u001b[31m            const hub2 = _recceHubUser();\u001b[39m\n\u001b[31m            const isHP = _RECCE_CFG_ADMINS.includes(hub2?.empId);\u001b[39m\n\u001b[31m            const csMap = {\u001b[39m\n\u001b[31m              approved:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#166534;background:#dcfce7\\\">✓ Approved</span>',\u001b[39m\n\u001b[31m              rejected:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#991b1b;background:#fee2e2\\\">✕ Rejected</span>',\u001b[39m\n\u001b[31m              approved_with_changes: '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#92400e;background:#fef3c7\\\">✎ Approved w/ Comments</span>',\u001b[39m\n\u001b[31m            };\u001b[39m\n\u001b[31m            const csBadge = csMap[r.client_status] || '';\u001b[39m\n\u001b[31m            const approvedAt = r.client_approved_at\u001b[39m\n\u001b[31m              ? new Date(r.client_approved_at).toLocaleString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit',timeZone:'Asia/Kolkata'})\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const pdfLink = r.client_approval_pdf_url\u001b[39m\n\u001b[31m              ? `<a href=\\\"${r.client_approval_pdf_url}\\\" target=\\\"_blank\\\" style=\\\"font-size:12px;color:var(--or);text-decoration:none\\\">⬇ Approval PDF</a>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const archAct = isHP && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveRecce('${r.sub_id}')\\\" style=\\\"font-size:12px;color:var(--nv);background:none;border:1px solid var(--nv);border-radius:6px;padding:4px 10px;cursor:pointer\\\">⦽ Archive from client</button>`\u001b[39m\n\u001b[31m              : (r.client_archived ? '<span style=\\\"font-size:11px;color:var(--g400)\\\">⦽ Hidden from client</span>' : '');\u001b[39m\n\u001b[31m            const campAct = isHP && r.campaign_id && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveAllForCampaign('${r.campaign_id}')\\\" style=\\\"font-size:11px;color:#991b1b;background:none;border:1px solid #fca5a5;border-radius:6px;padding:3px 8px;cursor:pointer\\\">Archive ALL for ${r.campaign_id}</button>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            if (!csBadge && !pdfLink && !archAct) return '';\u001b[39m\n\u001b[31m            return `<div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m              <div class=\\\"ardl-lbl\\\">Client Approval</div>\u001b[39m\n\u001b[31m              ${csBadge ? `<div style=\\\"margin-bottom:5px\\\">${csBadge}${approvedAt ? ' <span style=\\\"font-size:11px;color:var(--g400)\\\">' + approvedAt + '</span>' : ''}</div>` : ''}\u001b[39m\n\u001b[31m              ${r.client_comment ? `<div style=\\\"font-size:12px;color:var(--g600);background:var(--g50);border-radius:6px;padding:7px 10px;margin-bottom:5px\\\">\\\"${r.client_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m              ${pdfLink ? `<div style=\\\"margin-bottom:4px\\\">${pdfLink}</div>` : ''}\u001b[39m\n\u001b[31m              ${archAct ? `<div style=\\\"margin-bottom:4px\\\">${archAct}</div>` : ''}\u001b[39m\n\u001b[31m              ${campAct ? `<div>${campAct}</div>` : ''}\u001b[39m\n\u001b[31m            </div>`;\u001b[39m\n\u001b[31m          })()}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeAdminDetail() {\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveRecce(subId) {\u001b[39m\n\u001b[31m  if (!confirm('Archive this recce from client view? The client will no longer see it.')) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(subId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) Object.assign(_adminRows[idx], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    toast('Archived from client view ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveAllForCampaign(campaignId) {\u001b[39m\n\u001b[31m  if (!confirm(`Archive ALL recces for campaign \\\"${campaignId}\\\" from client view?\\\\nClients will no longer see any recce from this campaign.`)) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?campaign_id=eq.${encodeURIComponent(campaignId)}&client_archived=eq.false`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    _adminRows.forEach((row, i) => {\u001b[39m\n\u001b[31m      if (row.campaign_id === campaignId) Object.assign(_adminRows[i], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    toast(`All recces for ${campaignId} archived ✓`, 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function regenAllReports() {\u001b[39m\n\u001b[31m  if (!_adminUnlocked) { toast('Admin access required', 'error'); return; }\u001b[39m\n\u001b[31m  const rows = _adminRows.filter(r => !r.deleted_at && r.photo_urls);\u001b[39m\n\u001b[31m  if (!rows.length) { toast('No synced rows with photos found', 'error'); return; }·\u001b[39m\n\u001b[31m  const btn = document.getElementById('regen-rpt-btn');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Regenerating…'; }\u001b[39m\n\u001b[31m  toast(`Regenerating ${rows.length} reports…`, 'info');·\u001b[39m\n\u001b[31m  let done = 0, failed = 0;\u001b[39m\n\u001b[31m  for (const r of rows) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const photoUrls = typeof r.photo_urls === 'string' ? JSON.parse(r.photo_urls) : (r.photo_urls || {});\u001b[39m\n\u001b[31m      let meta = {};\u001b[39m\n\u001b[31m      try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m      const entry = {\u001b[39m\n\u001b[31m        id: r.sub_id,\u001b[39m\n\u001b[31m        timestamp: r.submitted_at,\u001b[39m\n\u001b[31m        submittedBy: r.submitted_by,\u001b[39m\n\u001b[31m        data: {\u001b[39m\n\u001b[31m          storeName:    r.store_name,\u001b[39m\n\u001b[31m          brand:        r.brand,\u001b[39m\n\u001b[31m          clientName:   r.client_name,\u001b[39m\n\u001b[31m          date:         r.visit_date,\u001b[39m\n\u001b[31m          address:      r.address,\u001b[39m\n\u001b[31m          city:         r.city,\u001b[39m\n\u001b[31m          mobile:       r.mobile,\u001b[39m\n\u001b[31m          gpsCoords:    (r.gps_lat && r.gps_lng) ? { lat: r.gps_lat, lng: r.gps_lng } : null,\u001b[39m\n\u001b[31m          hasVideo:     r.has_video,\u001b[39m\n\u001b[31m          videoNote:    meta.videoNote || '',\u001b[39m\n\u001b[31m          videoCmt:     meta.videoCmt  || '',\u001b[39m\n\u001b[31m          frontPhotos:  (photoUrls.front   || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          insidePhotos: (photoUrls.inside  || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          addlPhotos:   (photoUrls.addl    || []).map(() => ({ desc: '' })),\u001b[39m\n\u001b[31m          brandings:    (meta.brandings    || []),\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      };·\u001b[39m\n\u001b[31m      const html = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m      const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m        method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m        body: JSON.stringify({ type: 'save-view', subId: r.sub_id, html })\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!vResp.ok) { failed++; continue; }\u001b[39m\n\u001b[31m      const vr = await vResp.json();\u001b[39m\n\u001b[31m      if (!vr.success) { failed++; continue; }·\u001b[39m\n\u001b[31m      if (vr.url && vr.url !== r.view_url) {\u001b[39m\n\u001b[31m        await fetch(`${_RC_BASE}/submissions?sub_id=eq.${r.sub_id}`, {\u001b[39m\n\u001b[31m          method: 'PATCH', headers: _RC_WRITE,\u001b[39m\n\u001b[31m          body: JSON.stringify({ view_url: vr.url })\u001b[39m\n\u001b[31m        });\u001b[39m\n\u001b[31m        const idx = _adminRows.findIndex(x => x.sub_id === r.sub_id);\u001b[39m\n\u001b[31m        if (idx >= 0) _adminRows[idx].view_url = vr.url;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      done++;\u001b[39m\n\u001b[31m    } catch(e) { failed++; }\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = false; btn.textContent = '↻ Regen Reports'; }\u001b[39m\n\u001b[31m  toast(`Done: ${done} regenerated${failed ? `, ${failed} failed` : ''}`, done > 0 ? 'success' : 'error');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction toggleDeletedView() {\u001b[39m\n\u001b[31m  _showDeletedView = !_showDeletedView;\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openDeleteModal(subId) {\u001b[39m\n\u001b[31m  _pendingDeleteId = subId;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  const sub = document.getElementById('del-modal-sub');\u001b[39m\n\u001b[31m  if (sub) sub.textContent = r ? `Delete: \\\"${r.store_name||'Unknown'}\\\"` : 'Select reason for deletion:';\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectDeleteReason(reason) {\u001b[39m\n\u001b[31m  _pendingDeleteReason = reason;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  document.getElementById('reason-' + reason)?.classList.add('sel');\u001b[39m\n\u001b[31m  document.getElementById('del-confirm-btn').classList.remove('no-reason');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeDeleteModal() {\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingDeleteId = null;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  clearTimeout(_tt);\u001b[39m\n\u001b[31m  document.getElementById('toast').classList.remove('show');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function restoreRecce(subId) {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({ deleted_at: null, deleted_by: null, deletion_reason: null }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Restore failed: ' + r.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_at = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_by = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deletion_reason = null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    toast('Recce restored ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Restore failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmDelete() {\u001b[39m\n\u001b[31m  if (!_pendingDeleteReason) {\u001b[39m\n\u001b[31m    const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m    btn.style.animation = 'none';\u001b[39m\n\u001b[31m    btn.offsetHeight; // reflow\u001b[39m\n\u001b[31m    btn.style.animation = 'shake .35s ease';\u001b[39m\n\u001b[31m    toast('Select a reason first', 'error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if (!_pendingDeleteId) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Deleting…';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      // Hard delete — no audit trail\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'DELETE',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Delete failed: ' + r.status);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Soft delete — stamp deleted_at, deleted_by, deletion_reason\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'PATCH',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m        body: JSON.stringify({\u001b[39m\n\u001b[31m          deleted_at: new Date().toISOString(),\u001b[39m\n\u001b[31m          deleted_by: hub.empId,\u001b[39m\n\u001b[31m          deletion_reason: _pendingDeleteReason,\u001b[39m\n\u001b[31m        }),\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Update failed: ' + r.status);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Remove or update in local cache\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      _adminRows = _adminRows.filter(x => x.sub_id !== _pendingDeleteId);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      const idx = _adminRows.findIndex(x => x.sub_id === _pendingDeleteId);\u001b[39m\n\u001b[31m      if (idx >= 0) {\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_at = new Date().toISOString();\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_by = hub.empId;\u001b[39m\n\u001b[31m        _adminRows[idx].deletion_reason = _pendingDeleteReason;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeDeleteModal();\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast('Recce deleted', 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Delete failed', 'error');\u001b[39m\n\u001b[31m    btn.classList.remove('no-reason');\u001b[39m\n\u001b[31m    btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openMyServerRecce(subId) {\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  // No view yet — show metadata modal (same layout as admin detail)\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta==='string' ? JSON.parse(r.meta) : (r.meta||{}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">📍 View on Google Maps</a>` : '';\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} × ${b.h||'?'} in · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos will appear after next sync from original device\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Visit Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupLanding() {\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = 'none';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = 'none';\u001b[39m\n\u001b[31m  // Clean up admin + create-mode UI\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('sup-back-btn')?.remove();\u001b[39m\n\u001b[31m  document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m  _supCreateMode = false;\u001b[39m\n\u001b[31m  // Resume-wrap may have been hidden by loadHomeAdmin() — restore it so draft banner shows\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = '';\u001b[39m\n\u001b[31m  document.getElementById('sub-list').innerHTML = `\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorViewAll()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0f9ff\\\">📋</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">View All Recces</span><span class=\\\"hi-txt\\\">सभी रेकी देखें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">Browse & review submissions from all agents</span><span class=\\\"hi-txt\\\">सभी एजेंट की सबमिशन देखें</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorCreateView()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0fdf4\\\">✍️</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">Create Recce</span><span class=\\\"hi-txt\\\">नई रेकी बनाएं</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">My submissions + New Recce button</span><span class=\\\"hi-txt\\\">मेरी सबमिशन + नई रेकी</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorViewAll() {\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  await loadHomeAdmin();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorCreateView() {\u001b[39m\n\u001b[31m  _supCreateMode = true;\u001b[39m\n\u001b[31m  // Restore field-agent UI\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh'); if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = t('My Submissions','मेरी सबमिशन');\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar'); if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  // Add Back to Menu button (once)\u001b[39m\n\u001b[31m  if (!document.getElementById('sup-back-create-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-create-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => {\u001b[39m\n\u001b[31m      _supCreateMode = false;\u001b[39m\n\u001b[31m      document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m      renderSupLanding();\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    document.querySelector('#view-home .content').prepend(bb);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  await loadHome();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadHome() {\u001b[39m\n\u001b[31m  if (_isSupervisor() && !_supCreateMode) { renderSupLanding(); return; }\u001b[39m\n\u001b[31m  if (_adminUnlocked && !_supCreateMode) { await loadHomeAdmin(); return; }·\u001b[39m\n\u001b[31m  const all  = await dbAll('subs');\u001b[39m\n\u001b[31m  const sy   = all.filter(s => s.status === 'synced').length;\u001b[39m\n\u001b[31m  const pe   = all.filter(s => s.status !== 'synced').length;·\u001b[39m\n\u001b[31m  // Fetch this agent's submissions from server — works on any device\u001b[39m\n\u001b[31m  let serverOnly = [];\u001b[39m\n\u001b[31m  let editAssigned = [];\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (navigator.onLine && hub?.empId) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?submitted_by=eq.${encodeURIComponent(hub.empId)}&order=submitted_at.desc&limit=200`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp.ok) {\u001b[39m\n\u001b[31m        const rows = await resp.json();\u001b[39m\n\u001b[31m        const localIds = new Set(all.map(s => s.id));\u001b[39m\n\u001b[31m        serverOnly = rows.filter(r => !localIds.has(r.sub_id));\u001b[39m\n\u001b[31m        _myServerRows = serverOnly;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m    // Fetch edit-assigned recces (supervisor assigned this creator to edit)\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp2 = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?edit_assigned_to=eq.${encodeURIComponent(hub.empId)}&deleted_at=is.null&order=submitted_at.desc`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp2.ok) editAssigned = await resp2.json();\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = sy + serverOnly.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = pe;\u001b[39m\n\u001b[31m  document.getElementById('stat-total').textContent   = all.length + serverOnly.length;·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!all.length && !serverOnly.length && !editAssigned.length) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">📋</div><div class=\\\"empty-txt\\\">No submissions yet</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const icos   = { synced:'✅', pending:'⏳', failed:'❌' };\u001b[39m\n\u001b[31m  const sorted = [...all].sort((a,b) => new Date(b.timestamp) - new Date(a.timestamp)).slice(0, 50);·\u001b[39m\n\u001b[31m  const localCards = sorted.map(s => {\u001b[39m\n\u001b[31m    const dt = new Date(s.timestamp);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const viewBtn = s.viewUrl\u001b[39m\n\u001b[31m      ? `<button class=\\\"edit-btn-sm\\\" onclick=\\\"window.open('${s.viewUrl}','_blank')\\\">👁 View</button>`\u001b[39m\n\u001b[31m      : `<button class=\\\"edit-btn-sm\\\" onclick=\\\"viewRecce('${s.id}')\\\">👁 View</button>`;\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico ${s.status}\\\">${icos[s.status]||'📋'}</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${s.data.storeName||'Unknown'} · ${s.data.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${s.data.address||''}</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge ${s.status}\\\">${s.status}</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          ${viewBtn}\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"editRecce('${s.id}')\\\" style=\\\"background:#fff7ed;border-color:var(--or);color:var(--or)\\\">✏ Edit</button>\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"makeSlides('${s.id}')\\\" style=\\\"background:#eff6ff;border-color:#3b82f6;color:#1d4ed8\\\">📊 Slides</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const serverCards = serverOnly.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const showPdf = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m    const pdfCls = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico synced\\\">✅</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\" style=\\\"min-width:0;flex:1\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"rpt-btns\\\" style=\\\"margin-top:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openMyServerRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m          ${showPdf ? `<button class=\\\"${pdfCls}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">📄 PDF</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge synced\\\">synced</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const editAssignedCards = editAssigned.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    return `<div class=\\\"edit-req-card\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:26px;flex-shrink:0\\\">✏</div>\u001b[39m\n\u001b[31m      <div class=\\\"edit-req-card-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-meta\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        ${r.edit_comment ? `<div class=\\\"edit-req-cmt\\\">\\\"${r.edit_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:10px;display:flex;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"startCreatorEdit('${r.sub_id}')\\\" style=\\\"padding:9px 16px;font-size:13px;font-weight:600\\\">✏ Edit this Recce</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (editAssignedCards.length) {\u001b[39m\n\u001b[31m    html += `<div class=\\\"edit-req-section-hdr\\\">✏ Edit Requested (${editAssignedCards.length})</div>`;\u001b[39m\n\u001b[31m    html += editAssignedCards.join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  html += localCards.join('') + serverCards.join('');\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m  const ls = await cfg('last-sync');\u001b[39m\n\u001b[31m  if (ls) {\u001b[39m\n\u001b[31m    const d = new Date(ls);\u001b[39m\n\u001b[31m    document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m      'Synced ' + d.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// RESET\u001b[39m\n\u001b[31mfunction startNewRecce(){F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  if(geoStampEnabled)autoRequestGPS();\u001b[39m\n\u001b[31m['f-date','f-brand','f-store','f-addr','f-mobile','f-client-other'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';});\u001b[39m\n\u001b[31m_selectedClient='';_clientOtherMode=false;\u001b[39m\n\u001b[31m_selectedCampaignId=null;_notifySupervisor=false;_brandingLocked=false;\u001b[39m\n\u001b[31mconst _camSel=document.getElementById('f-campaign-id');if(_camSel)_camSel.value='';\u001b[39m\n\u001b[31mconst _camNotice=document.getElementById('campaign-notify-msg');if(_camNotice)_camNotice.style.display='none';\u001b[39m\n\u001b[31mloadCampaignsForForm();\u001b[39m\n\u001b[31mrenderClientChips();\u001b[39m\n\u001b[31mdocument.getElementById('f-date').value=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31m// Block future dates\u001b[39m\n\u001b[31mdocument.getElementById('f-date').max=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31mdocument.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('pick-trigger-wrap').style.display=stores.length?'block':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').style.display=stores.length?'flex':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31mdocument.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31mdocument.getElementById('manual-fields').style.display=stores.length?'none':'block';\u001b[39m\n\u001b[31mdocument.getElementById('gps-status').textContent='';\u001b[39m\n\u001b[31m['vid-yes','vid-no','br-yes','br-no'].forEach(id=>document.getElementById(id).classList.remove('sel'));\u001b[39m\n\u001b[31mdocument.getElementById('vid-sec').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('vid-slot').innerHTML=`<div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('br-add').style.display='none';document.getElementById('br-items').innerHTML='';\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').classList.remove('filled');\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').innerHTML=`<div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('brand-selector').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('sc-missing').style.display='none';\u001b[39m\n\u001b[31mpopulateBrandDropdown();\u001b[39m\n\u001b[31mrenderPhotos('front');renderPhotos('inside');renderAddl();updAvailTag();showView('form-store');}\u001b[39m\n\u001b[31mfunction exitForm(){\u001b[39m\n\u001b[31m  // Show safe exit dialog instead of confirm\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitSaveAndLeave(){\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m  checkDraft();\u001b[39m\n\u001b[31m  toast('Draft saved — tap Resume to continue','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitDiscard(){\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];\u001b[39m\n\u001b[31m  videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  dbDel('draft','current');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitCancel(){document.getElementById('exit-dialog').classList.remove('open');}\u001b[39m\n\u001b[31mfunction showView(n){document.querySelectorAll('.view').forEach(v=>v.classList.remove('active'));const t=document.getElementById('view-'+n);if(t){t.classList.add('active');window.scrollTo(0,0);}}\u001b[39m\n\u001b[31mlet _tt;\u001b[39m\n\u001b[31mfunction toast(msg,type='info'){const el=document.getElementById('toast');el.textContent=msg;el.className='toast show '+type;clearTimeout(_tt);_tt=setTimeout(()=>el.classList.remove('show'),3000);}\u001b[39m\n\u001b[31mfunction netStatus(){const on=navigator.onLine;const dot=document.getElementById('net-dot');const txt=document.getElementById('net-txt');if(dot)dot.className='sdot '+(on?'on':'off');if(txt)txt.textContent=on?t('Online','ऑनलाइन'):t('Offline — saves locally','ऑफलाइन — स्थानीय रूप से सेव');}\u001b[39m\n\u001b[31masync function loadSettings(){\u001b[39m\n\u001b[31m  // Gas URL: pre-load default if none saved, update preview\u001b[39m\n\u001b[31m  const gu=await cfg('gas-url');\u001b[39m\n\u001b[31m  if(!gu)await cfg('gas-url',DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m  // Admin cfg url\u001b[39m\n\u001b[31m  const acu=await cfg('admin-cfg-url');if(acu&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=acu;\u001b[39m\n\u001b[31m  const su=await cfg('srv-url')||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su)document.getElementById('srv-url').value=su;\u001b[39m\n\u001b[31m  const sc=await cfg('stores');\u001b[39m\n\u001b[31m  if(sc){\u001b[39m\n\u001b[31m    stores=JSON.parse(sc);\u001b[39m\n\u001b[31m    const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m    document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m      `✓ ${stores.length} stores in cache${noBrand?` · ${noBrand} without brand`:''}`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const sf=await cfg('store-files');if(sf){_storeFiles=JSON.parse(sf);renderStoreFileList();}\u001b[39m\n\u001b[31m  const iq=await cfg('img-quality');imgQuality=iq||'compressed';applyQualityUI(imgQuality);\u001b[39m\n\u001b[31m  const gs=await cfg('geo-stamp');geoStampEnabled=(gs===null||gs==='1');applyGeoStampUI();\u001b[39m\n\u001b[31m  const bl=await cfg('brands');if(bl)brands=JSON.parse(bl);\u001b[39m\n\u001b[31m  loadBrandsFromDb();  // async — updates brands + logos from DB in background\u001b[39m\n\u001b[31m  renderBrandManageList();\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m  // Show store upload row + brand add row to supervisors only\u001b[39m\n\u001b[31m  const sur = document.getElementById('store-upload-row');\u001b[39m\n\u001b[31m  if (sur) sur.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const bar = document.getElementById('brand-add-row');\u001b[39m\n\u001b[31m  if (bar) bar.style.display = _isSupervisor() ? 'flex' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction populateBrandDropdown(){\u001b[39m\n\u001b[31m  const sel=document.getElementById('f-brand');if(!sel)return;\u001b[39m\n\u001b[31m  const cur=sel.value;\u001b[39m\n\u001b[31m  sel.innerHTML='<option value=\\\"\\\">Select brand</option>'+brands.map(b=>`<option${cur===b?' selected':''}>${b}</option>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderBrandManageList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('brand-manage-list');if(!el)return;\u001b[39m\n\u001b[31m  const isSup=_isSupervisor();\u001b[39m\n\u001b[31m  el.innerHTML=brands.map((b,i)=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    const logoHtml=logo?`<img src=\\\"${logo}\\\" style=\\\"height:20px;max-width:48px;object-fit:contain;flex-shrink:0;border-radius:3px\\\">`:'';\u001b[39m\n\u001b[31m    const ctrlHtml=isSup?`<div style=\\\"display:flex;gap:2px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"openEditBrandDialog(${i})\\\" style=\\\"background:none;border:none;color:var(--nv);font-size:15px;cursor:pointer;padding:2px 6px\\\" title=\\\"Edit\\\">✏</button>\u001b[39m\n\u001b[31m      ${brands.length>1?`<button onclick=\\\"confirmRemoveBrand(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:2px 4px\\\">×</button>`:'<span style=\\\"font-size:11px;color:var(--g400);padding:0 6px\\\">Last</span>'}\u001b[39m\n\u001b[31m    </div>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;min-width:0\\\">${logoHtml}<span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${b}</span></div>\u001b[39m\n\u001b[31m      ${ctrlHtml}\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function addBrandToList(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const inp=document.getElementById('brand-add-inp');\u001b[39m\n\u001b[31m  const val=(inp.value.trim()||'').toUpperCase();\u001b[39m\n\u001b[31m  if(!val){toast('Enter a brand name','error');return;}\u001b[39m\n\u001b[31m  if(brands.some(b=>b.toLowerCase()===val.toLowerCase())){toast(`${val} already in list`,'error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands`,{method:'POST',headers:{..._RC_WRITE,'Prefer':'return=minimal'},body:JSON.stringify({name:val,sort_order:99})});\u001b[39m\n\u001b[31m    if(resp.status===409){toast(`${val} already exists in DB`,'error');return;}\u001b[39m\n\u001b[31m    if(!resp.ok){const e=await resp.json().catch(()=>({}));throw new Error(e.message||resp.status);}\u001b[39m\n\u001b[31m    inp.value='';\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${val} added ✓`,'success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Add failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmRemoveBrand(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const name=brands[idx];\u001b[39m\n\u001b[31m  if(brands.length<=1){toast('Need at least one brand','error');return;}\u001b[39m\n\u001b[31m  let count=0;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(name)}&select=sub_id`,{headers:_RC_READ});\u001b[39m\n\u001b[31m    if(r.ok){const rows=await r.json();count=rows.length;}\u001b[39m\n\u001b[31m  }catch(_){}\u001b[39m\n\u001b[31m  const msg=count>0?`Delete \\\"${name}\\\" from brand list?\\\\n(${count} submission${count!==1?'s':''} reference this brand — they keep the name as text.)`:`Delete \\\"${name}\\\" from brand list?`;\u001b[39m\n\u001b[31m  if(!confirm(msg))return;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(name)}`,{method:'DELETE',headers:{'Content-Profile':'recce','Accept-Profile':'recce'}});\u001b[39m\n\u001b[31m    if(!resp.ok&&resp.status!==204){throw new Error(resp.status);}\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${name} removed ✓`,'info');\u001b[39m\n\u001b[31m  }catch(e){toast(`Remove failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadBrandsFromDb(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch('/db/brands?select=name,logo_url&order=sort_order',{\u001b[39m\n\u001b[31m      headers:{'Content-Profile':'recce','Accept-Profile':'recce'}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(!r.ok) return;\u001b[39m\n\u001b[31m    const rows=await r.json();\u001b[39m\n\u001b[31m    if(!rows||!rows.length) return;\u001b[39m\n\u001b[31m    const dbNames=rows.map(r=>r.name);\u001b[39m\n\u001b[31m    const logos={};rows.forEach(r=>{if(r.logo_url)logos[r.name]=r.logo_url;});\u001b[39m\n\u001b[31m    // Merge: DB brands canonical, keep locally-added extras\u001b[39m\n\u001b[31m    const extras=brands.filter(b=>!dbNames.some(n=>n.toLowerCase()===b.toLowerCase()));\u001b[39m\n\u001b[31m    brands=[...dbNames,...extras];\u001b[39m\n\u001b[31m    _brandLogos=logos;\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    // Refresh brand chips if brand-selector is visible\u001b[39m\n\u001b[31m    const bSel=document.getElementById('brand-selector');\u001b[39m\n\u001b[31m    if(bSel&&bSel.style.display!=='none') renderBrandChips();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[brands-db]',e.message);}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction renderBrandChips(){\u001b[39m\n\u001b[31m  const bChips=document.getElementById('brand-chips');if(!bChips)return;\u001b[39m\n\u001b[31m  bChips.innerHTML=brands.map(b=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    return `<div class=\\\"chip brand-chip${F.brand===b?' sel':''}\\\" onclick=\\\"selectStoreBrand('${b.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\">` +\u001b[39m\n\u001b[31m      (logo?`<img src=\\\"${logo}\\\" class=\\\"brand-chip-logo\\\" alt=\\\"\\\">`:'') +\u001b[39m\n\u001b[31m      `<span>${b}</span></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _editBrandIdx=null,_editBrandOld=null;\u001b[39m\n\u001b[31mfunction openEditBrandDialog(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor())return;\u001b[39m\n\u001b[31m  _editBrandIdx=idx;_editBrandOld=brands[idx];\u001b[39m\n\u001b[31m  document.getElementById('be-name').value=brands[idx];\u001b[39m\n\u001b[31m  const logo=_brandLogos[brands[idx]]||'';\u001b[39m\n\u001b[31m  document.getElementById('be-logo').value=logo;\u001b[39m\n\u001b[31m  document.getElementById('be-logo-preview').innerHTML=logo?`<img src=\\\"${logo}\\\" style=\\\"height:28px;object-fit:contain\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Current logo</span>`:'';\u001b[39m\n\u001b[31m  document.getElementById('be-cascade-info').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('brand-edit-modal').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeBrandEditModal(){document.getElementById('brand-edit-modal').classList.remove('open');_editBrandIdx=null;_editBrandOld=null;}\u001b[39m\n\u001b[31mfunction previewBrandLogo(){\u001b[39m\n\u001b[31m  const url=(document.getElementById('be-logo')?.value||'').trim();\u001b[39m\n\u001b[31m  const prev=document.getElementById('be-logo-preview');\u001b[39m\n\u001b[31m  if(prev)prev.innerHTML=url?`<img src=\\\"${url}\\\" style=\\\"height:28px;object-fit:contain\\\" onerror=\\\"this.style.display='none'\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Preview</span>`:'';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveBrandEdit(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const oldName=_editBrandOld;\u001b[39m\n\u001b[31m  const newName=(document.getElementById('be-name').value||'').trim().toUpperCase();\u001b[39m\n\u001b[31m  const newLogo=(document.getElementById('be-logo').value||'').trim();\u001b[39m\n\u001b[31m  if(!newName){toast('Brand name required','error');return;}\u001b[39m\n\u001b[31m  const isRename=newName!==oldName;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // 1. Update recce.brands\u001b[39m\n\u001b[31m    const pResp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m      method:'PATCH',headers:{..._RC_WRITE,'Prefer':'return=minimal'},\u001b[39m\n\u001b[31m      body:JSON.stringify({name:newName,logo_url:newLogo||null})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(pResp.status===409){toast(`\\\"${newName}\\\" already exists`,'error');return;}\u001b[39m\n\u001b[31m    if(!pResp.ok&&pResp.status!==204){const e=await pResp.json().catch(()=>({}));throw new Error(e.message||pResp.status);}\u001b[39m\n\u001b[31m    if(isRename){\u001b[39m\n\u001b[31m      const hub=_recceHubUser();\u001b[39m\n\u001b[31m      // 2. Cascade to submissions\u001b[39m\n\u001b[31m      await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m        method:'PATCH',headers:_RC_WRITE,body:JSON.stringify({brand:newName})\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      // 3. Cascade to stores.json + view HTML files + PDFs\u001b[39m\n\u001b[31m      toast('Cascading rename to reports…','info');\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        const cResp=await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},\u001b[39m\n\u001b[31m          body:JSON.stringify({type:'cascade-rename-brand',oldName,newName,empId:hub?.empId||''})});\u001b[39m\n\u001b[31m        const cRes=cResp.ok?await cResp.json():{};\u001b[39m\n\u001b[31m        const msg=`Brand renamed ✓${cRes.viewsUpdated?` · ${cRes.viewsUpdated} reports re-queued`:''}`;\u001b[39m\n\u001b[31m        closeBrandEditModal();\u001b[39m\n\u001b[31m        await loadBrandsFromDb();\u001b[39m\n\u001b[31m        toast(msg,'success');\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }catch(e){console.warn('[cascade-rename]',e.message);}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeBrandEditModal();\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast('Brand updated ✓','success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Save failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function fetchServerBrands(){\u001b[39m\n\u001b[31m  const url=document.getElementById('brands-url')?.value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    toast('Fetching brands…','info');\u001b[39m\n\u001b[31m    const r=await fetch(url);const j=await r.json();\u001b[39m\n\u001b[31m    const list=Array.isArray(j)?j:j.brands||[];\u001b[39m\n\u001b[31m    if(!list.length){toast('No brands found in response','error');return;}\u001b[39m\n\u001b[31m    brands=list.map(b=>b.toString().toUpperCase());\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    toast(`${brands.length} brands loaded from server`,'success');\u001b[39m\n\u001b[31m  }catch{toast('Failed to fetch — check URL','error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setImgQuality(q){\u001b[39m\n\u001b[31m  imgQuality=q;\u001b[39m\n\u001b[31m  cfg('img-quality',q);\u001b[39m\n\u001b[31m  applyQualityUI(q);\u001b[39m\n\u001b[31m  toast(q==='hd'?'HD Quality selected (~400–600 KB per photo)':'Full Compression selected (~150–200 KB per photo)','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction applyQualityUI(q){\u001b[39m\n\u001b[31m  ['compressed','hd'].forEach(opt=>{\u001b[39m\n\u001b[31m    const label=document.getElementById('q-opt-'+opt);\u001b[39m\n\u001b[31m    const radio=document.getElementById('q-radio-'+opt);\u001b[39m\n\u001b[31m    const dot  =document.getElementById('q-dot-'+opt);\u001b[39m\n\u001b[31m    if(!label)return;\u001b[39m\n\u001b[31m    const active=opt===q;\u001b[39m\n\u001b[31m    label.style.borderColor=active?'var(--or)':'var(--g200)';\u001b[39m\n\u001b[31m    label.style.background=active?'#fff7ed':'var(--g50)';\u001b[39m\n\u001b[31m    if(radio)radio.style.borderColor=active?'var(--or)':'var(--g300)';\u001b[39m\n\u001b[31m    if(dot)dot.style.display=active?'block':'none';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const badge=document.getElementById('q-current-badge');\u001b[39m\n\u001b[31m  if(badge){\u001b[39m\n\u001b[31m    const label=q==='hd'?'HD Quality (~400–600 KB)':'Full Compression (~150–200 KB)';\u001b[39m\n\u001b[31m    badge.innerHTML=`Active: <strong>${label}</strong>`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function clearData(){if(!confirm('Delete ALL local data?'))return;const all=await dbAll('subs');for(const s of all)await dbDel('subs',s.id);stores=[];await cfg('stores',null);toast('All cleared','success');loadHome();}\u001b[39m\n\u001b[31mif('serviceWorker' in navigator){const sw=`const C='recce-v37';self.addEventListener('install',e=>{e.waitUntil(caches.open(C).then(c=>c.add('/')));self.skipWaiting();});self.addEventListener('activate',e=>e.waitUntil(clients.claim()));self.addEventListener('fetch',e=>{if(e.request.method!=='GET')return;e.respondWith(caches.match(e.request).then(r=>{if(r)return r;return fetch(e.request).then(res=>{if(res&&res.status===200&&res.type==='basic'){const cl=res.clone();caches.open(C).then(c=>c.put(e.request,cl));}return res;}).catch(()=>caches.match('/'));}))}); `;const blob=new Blob([sw],{type:'application/javascript'});navigator.serviceWorker.register(URL.createObjectURL(blob),{scope:'/'}).catch(()=>{});}·\u001b[39m\n\u001b[31m// ── GEOLOCATION STAMP ────────────────────────────────────────\u001b[39m\n\u001b[31mfunction applyGeoStampUI(){\u001b[39m\n\u001b[31m  const tog=document.getElementById('geo-tog');\u001b[39m\n\u001b[31m  if(tog)tog.classList.toggle('on',geoStampEnabled);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function toggleGeoStamp(){\u001b[39m\n\u001b[31m  geoStampEnabled=!geoStampEnabled;\u001b[39m\n\u001b[31m  await cfg('geo-stamp',geoStampEnabled?'1':'0');\u001b[39m\n\u001b[31m  applyGeoStampUI();\u001b[39m\n\u001b[31m  toast(geoStampEnabled?'Geolocation stamp enabled':'Geolocation stamp disabled','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Auto-request GPS silently when a new recce starts\u001b[39m\n\u001b[31mfunction autoRequestGPS(){\u001b[39m\n\u001b[31m  if(!navigator.geolocation)return;\u001b[39m\n\u001b[31m  const statusEl=document.getElementById('geo-status');\u001b[39m\n\u001b[31m  if(statusEl)statusEl.textContent='Acquiring GPS…';\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(\u001b[39m\n\u001b[31m    pos=>{\u001b[39m\n\u001b[31m      gpsCoords={\u001b[39m\n\u001b[31m        lat:pos.coords.latitude.toFixed(6),\u001b[39m\n\u001b[31m        lng:pos.coords.longitude.toFixed(6),\u001b[39m\n\u001b[31m        acc:Math.round(pos.coords.accuracy)\u001b[39m\n\u001b[31m      };\u001b[39m\n\u001b[31m      const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m      const quality=acc<=15?'Excellent':acc<=50?'Good':acc<=200?'Fair':'Poor (cell tower)';\u001b[39m\n\u001b[31m      const color=acc<=15?'var(--gn)':acc<=50?'#16a34a':acc<=200?'var(--am)':'var(--rd)';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.innerHTML=`GPS: ${gpsCoords.lat}, ${gpsCoords.lng} · ±${acc}m · <span style=\\\"color:${color};font-weight:600\\\">${quality}</span>`;\u001b[39m\n\u001b[31m      // Update form GPS status too\u001b[39m\n\u001b[31m      const fs=document.getElementById('gps-status');\u001b[39m\n\u001b[31m      if(fs){fs.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${acc}m)`;fs.style.color='var(--gn)';}\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    err=>{\u001b[39m\n\u001b[31m      const msgs={1:'Location permission denied in Chrome',2:'GPS signal unavailable',3:'GPS timed out'};\u001b[39m\n\u001b[31m      const msg=msgs[err.code]||'GPS unavailable';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.textContent=msg+' — stamp will use store address';\u001b[39m\n\u001b[31m      if(err.code===1)toast('Tap the lock icon in Chrome address bar → allow Location','info');\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    {enableHighAccuracy:true,timeout:20000,maximumAge:60000}\u001b[39m\n\u001b[31m  );\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Draw stamp on a photo blob — returns new blob with stamp baked in\u001b[39m\n\u001b[31mfunction roundRectPath(ctx,x,y,w,h,r){\u001b[39m\n\u001b[31m  ctx.beginPath();ctx.moveTo(x+r,y);ctx.lineTo(x+w-r,y);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y,x+w,y+r);ctx.lineTo(x+w,y+h-r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);ctx.lineTo(x+r,y+h);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y+h,x,y+h-r);ctx.lineTo(x,y+r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y,x+r,y);ctx.closePath();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction fitText(ctx,text,maxW){\u001b[39m\n\u001b[31m  if(ctx.measureText(text).width<=maxW)return text;\u001b[39m\n\u001b[31m  while(text.length>1&&ctx.measureText(text+'…').width>maxW)text=text.slice(0,-1);\u001b[39m\n\u001b[31m  return text+'…';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction stampPhoto(blob){\u001b[39m\n\u001b[31m  if(!geoStampEnabled)return Promise.resolve(blob);\u001b[39m\n\u001b[31m  return new Promise(res=>{\u001b[39m\n\u001b[31m    const img=new Image(),url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    img.onload=()=>{\u001b[39m\n\u001b[31m      URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m      const W=img.width,H=img.height;\u001b[39m\n\u001b[31m      const c=document.createElement('canvas');c.width=W;c.height=H;\u001b[39m\n\u001b[31m      const ctx=c.getContext('2d');\u001b[39m\n\u001b[31m      ctx.drawImage(img,0,0);·\u001b[39m\n\u001b[31m      // Stamp dimensions — 18% of image height\u001b[39m\n\u001b[31m      const SH=Math.round(H*0.18);\u001b[39m\n\u001b[31m      const pad=Math.round(W*0.03);\u001b[39m\n\u001b[31m      const SY=H-SH;·\u001b[39m\n\u001b[31m      // Semi-transparent background\u001b[39m\n\u001b[31m      ctx.fillStyle='rgba(10,18,35,0.78)';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,SH);·\u001b[39m\n\u001b[31m      // Orange top accent line\u001b[39m\n\u001b[31m      ctx.fillStyle='#f97316';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,Math.max(3,Math.round(H*0.004)));·\u001b[39m\n\u001b[31m      // Font sizes scaled to image\u001b[39m\n\u001b[31m      const f1=Math.round(SH*0.26); // store name\u001b[39m\n\u001b[31m      const f2=Math.round(SH*0.22); // coords / address\u001b[39m\n\u001b[31m      const f3=Math.round(SH*0.20); // timestamp·\u001b[39m\n\u001b[31m      // Row Y centres\u001b[39m\n\u001b[31m      const r1=SY+SH*0.26;\u001b[39m\n\u001b[31m      const r2=SY+SH*0.55;\u001b[39m\n\u001b[31m      const r3=SY+SH*0.82;·\u001b[39m\n\u001b[31m      // Get stamp data\u001b[39m\n\u001b[31m      const storeName=F.storeName||selectedStore?.name||'';\u001b[39m\n\u001b[31m      const brand=F.brand||selectedStore?.brand||'';\u001b[39m\n\u001b[31m      const addr=F.address||selectedStore?.address||'';\u001b[39m\n\u001b[31m      const now=new Date();\u001b[39m\n\u001b[31m      const dateStr=now.toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m      const timeStr=now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit',hour12:true});·\u001b[39m\n\u001b[31m      // Badge (right side — GPS quality)\u001b[39m\n\u001b[31m      let badgeLabel='',badgeColor='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m        if(acc<=15){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=50){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=200){badgeLabel='~'+acc+'m';badgeColor='#d97706';}\u001b[39m\n\u001b[31m        else{badgeLabel='Cell ~'+acc+'m';badgeColor='#dc2626';}\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        badgeLabel='No GPS';badgeColor='#64748b';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      const bFontSz=Math.round(SH*0.18);\u001b[39m\n\u001b[31m      ctx.font=`bold ${bFontSz}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      const bW=Math.round(ctx.measureText(badgeLabel).width+pad);\u001b[39m\n\u001b[31m      const bH=Math.round(SH*0.32);\u001b[39m\n\u001b[31m      const bX=W-bW-pad;const bY=SY+(SH-bH)/2;\u001b[39m\n\u001b[31m      ctx.fillStyle=badgeColor+'cc';\u001b[39m\n\u001b[31m      roundRectPath(ctx,bX,bY,bW,bH,4);ctx.fill();\u001b[39m\n\u001b[31m      ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';\u001b[39m\n\u001b[31m      ctx.fillText(badgeLabel,bX+bW/2,bY+bH/2);\u001b[39m\n\u001b[31m      ctx.textAlign='left';ctx.textBaseline='alphabetic';·\u001b[39m\n\u001b[31m      const textMaxW=bX-pad*2;·\u001b[39m\n\u001b[31m      // Row 1 — store name + brand\u001b[39m\n\u001b[31m      ctx.font=`bold ${f1}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#ffffff';\u001b[39m\n\u001b[31m      const nameText=storeName+(brand?' · '+brand:'');\u001b[39m\n\u001b[31m      ctx.fillText('📍 '+fitText(ctx,nameText,textMaxW-f1*1.4),pad,r1);·\u001b[39m\n\u001b[31m      // Row 2 — GPS coords OR address\u001b[39m\n\u001b[31m      ctx.font=`${f2}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#cbd5e1';\u001b[39m\n\u001b[31m      let row2='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        row2=`Lat ${gpsCoords.lat}°   Long ${gpsCoords.lng}°`;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        row2=addr?fitText(ctx,addr,textMaxW):'GPS coordinates unavailable';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      ctx.fillText(row2,pad,r2);·\u001b[39m\n\u001b[31m      // Row 3 — date and time\u001b[39m\n\u001b[31m      ctx.font=`${f3}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#94a3b8';\u001b[39m\n\u001b[31m      ctx.fillText(`${dateStr}   ${timeStr}`,pad,r3);·\u001b[39m\n\u001b[31m      c.toBlob(b=>res(b||blob),'image/jpeg',imgQuality==='hd'?0.88:0.82);\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    img.onerror=()=>{URL.revokeObjectURL(url);res(blob);};\u001b[39m\n\u001b[31m    img.src=url;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _aTool='rect',_aColor='#f97316',_aWidth=4,_aTarget=-1;\u001b[39m\n\u001b[31mlet _aImg=null,_aHistory=[],_aDrawing=false,_aStart={},_aPts=[];\u001b[39m\n\u001b[31mlet _aSel=-1,_aDragMode=null,_aDragOff={x:0,y:0};\u001b[39m\n\u001b[31m// Larger hit radius on touch devices for easier finger selection\u001b[39m\n\u001b[31mconst HIT_R=()=>('ontouchstart' in window)?32:16;·\u001b[39m\n\u001b[31mfunction setATool(t){\u001b[39m\n\u001b[31m  _aTool=t;\u001b[39m\n\u001b[31m  ['rect','ellipse','line','arrow','free'].forEach(id=>{const el=document.getElementById('at-'+id);if(el)el.classList.toggle('on',id===t&&t!=='move');});\u001b[39m\n\u001b[31m  const mv=document.getElementById('at-move');if(mv)mv.classList.toggle('sel-on',t==='move');\u001b[39m\n\u001b[31m  const info=document.getElementById('annot-sel-info');if(info)info.style.display=t==='move'?'block':'none';\u001b[39m\n\u001b[31m  if(t!=='move'){_aSel=-1;redrawAnnot();}\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(cvs)cvs.style.cursor=t==='move'?'default':'crosshair';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAColor(c){\u001b[39m\n\u001b[31m  _aColor=c;\u001b[39m\n\u001b[31m  const m={'#f97316':'or','#ef4444':'rd','#ffffff':'wh','#facc15':'yw','#22c55e':'gn'};\u001b[39m\n\u001b[31m  Object.entries(m).forEach(([col,id])=>{const el=document.getElementById('ac-'+id);if(el)el.classList.toggle('on',col===c);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAWidth(w){_aWidth=w;[2,4,7].forEach(v=>{const el=document.getElementById('aw-'+v);if(el)el.classList.toggle('on',v===w);});}·\u001b[39m\n\u001b[31mfunction openAnnot(idx){\u001b[39m\n\u001b[31m  _aTarget=idx;_aHistory=[];_aDrawing=false;_aPts=[];_aSel=-1;_aDragMode=null;\u001b[39m\n\u001b[31m  document.getElementById('annot-modal').classList.add('open');\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');\u001b[39m\n\u001b[31m  const img=new Image(),url=URL.createObjectURL(brandings[idx].blob);\u001b[39m\n\u001b[31m  img.onload=()=>{\u001b[39m\n\u001b[31m    const sc=Math.min(1,window.innerWidth/img.width,(window.innerHeight-185)/img.height);\u001b[39m\n\u001b[31m    cvs.width=Math.round(img.width*sc);cvs.height=Math.round(img.height*sc);\u001b[39m\n\u001b[31m    _aImg=img;redrawAnnot();URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  img.src=url;\u001b[39m\n\u001b[31m  cvs.ontouchstart=aDown;cvs.ontouchmove=aMove;cvs.ontouchend=aUp;\u001b[39m\n\u001b[31m  cvs.onmousedown=aDown;cvs.onmousemove=aMove;cvs.onmouseup=aUp;\u001b[39m\n\u001b[31m  setATool('rect');setAColor('#f97316');setAWidth(4);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aPos(e){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const r=cvs.getBoundingClientRect();\u001b[39m\n\u001b[31m  const src=e.touches?e.touches[0]:e;\u001b[39m\n\u001b[31m  return{x:(src.clientX-r.left)*(cvs.width/r.width),y:(src.clientY-r.top)*(cvs.height/r.height)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Always return normalised (positive w,h) bounds\u001b[39m\n\u001b[31mfunction sBounds(s){\u001b[39m\n\u001b[31m  if(s.type==='free'){\u001b[39m\n\u001b[31m    if(!s.pts||!s.pts.length)return null;\u001b[39m\n\u001b[31m    const xs=s.pts.map(p=>p.x),ys=s.pts.map(p=>p.y);\u001b[39m\n\u001b[31m    const x=Math.min(...xs),y=Math.min(...ys);\u001b[39m\n\u001b[31m    return{x,y,w:Math.max(...xs)-x,h:Math.max(...ys)-y};\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  return{x:Math.min(s.x,s.x+s.w),y:Math.min(s.y,s.y+s.h),w:Math.abs(s.w),h:Math.abs(s.h)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction hitHandle(px,py,s){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return null;\u001b[39m\n\u001b[31m  const b=sBounds(s);const hr=HIT_R();\u001b[39m\n\u001b[31m  for(const[n,x,y]of[['tl',b.x,b.y],['tr',b.x+b.w,b.y],['bl',b.x,b.y+b.h],['br',b.x+b.w,b.y+b.h]])\u001b[39m\n\u001b[31m    if(Math.hypot(px-x,py-y)<hr)return n;\u001b[39m\n\u001b[31m  return null;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction hitShape(px,py,s){\u001b[39m\n\u001b[31m  const b=sBounds(s);if(!b)return false;\u001b[39m\n\u001b[31m  const pad=HIT_R();\u001b[39m\n\u001b[31m  return px>=b.x-pad&&px<=b.x+b.w+pad&&py>=b.y-pad&&py<=b.y+b.h+pad;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aDown(e){\u001b[39m\n\u001b[31m  e.preventDefault();const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'){\u001b[39m\n\u001b[31m    // Check handles of selected shape first\u001b[39m\n\u001b[31m    if(_aSel>=0&&_aSel<_aHistory.length){\u001b[39m\n\u001b[31m      const h=hitHandle(p.x,p.y,_aHistory[_aSel]);\u001b[39m\n\u001b[31m      if(h){_aDragMode='r-'+h;_aDragOff={x:p.x,y:p.y};_aDrawing=true;return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Hit test all shapes topmost first\u001b[39m\n\u001b[31m    for(let i=_aHistory.length-1;i>=0;i--){\u001b[39m\n\u001b[31m      if(hitShape(p.x,p.y,_aHistory[i])){\u001b[39m\n\u001b[31m        _aSel=i;_aDragMode='move';\u001b[39m\n\u001b[31m        const s=_aHistory[i];\u001b[39m\n\u001b[31m        const b=sBounds(s);\u001b[39m\n\u001b[31m        // Store offset from shape top-left corner (normalised)\u001b[39m\n\u001b[31m        _aDragOff={x:p.x-b.x,y:p.y-b.y};\u001b[39m\n\u001b[31m        _aDrawing=true;redrawAnnot();return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    _aSel=-1;redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _aDrawing=true;_aStart={x:p.x,y:p.y};if(_aTool==='free')_aPts=[{x:p.x,y:p.y}];\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aMove(e){\u001b[39m\n\u001b[31m  e.preventDefault();if(!_aDrawing)return;const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'&&_aDragMode){\u001b[39m\n\u001b[31m    const s=_aHistory[_aSel];if(!s)return;\u001b[39m\n\u001b[31m    if(_aDragMode==='move'){\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      // New top-left position\u001b[39m\n\u001b[31m      const nx=p.x-_aDragOff.x;\u001b[39m\n\u001b[31m      const ny=p.y-_aDragOff.y;\u001b[39m\n\u001b[31m      const dx=nx-b.x,dy=ny-b.y;\u001b[39m\n\u001b[31m      if(s.type==='free'){\u001b[39m\n\u001b[31m        s.pts=s.pts.map(pt=>({x:pt.x+dx,y:pt.y+dy}));\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        // Move preserving w/h sign (don't normalise — keep original drawing direction)\u001b[39m\n\u001b[31m        s.x+=dx;s.y+=dy;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Resize from corner — always work on normalised bounds then re-apply\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      const n=_aDragMode.slice(2);\u001b[39m\n\u001b[31m      let nx=b.x,ny=b.y,nw=b.w,nh=b.h;\u001b[39m\n\u001b[31m      if(n==='br'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,p.y-b.y);}\u001b[39m\n\u001b[31m      else if(n==='tl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,b.y+b.h-p.y);nx=p.x;ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='tr'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,b.y+b.h-p.y);ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='bl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,p.y-b.y);nx=p.x;}\u001b[39m\n\u001b[31m      s.x=nx;s.y=ny;s.w=nw;s.h=nh; // store as normalised going forward\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if(_aTool==='free'){_aPts.push({x:p.x,y:p.y});redrawAnnot();drawSh({type:'free',pts:[..._aPts],color:_aColor,lw:_aWidth},true);return;}\u001b[39m\n\u001b[31m  redrawAnnot();drawSh({type:_aTool,x:_aStart.x,y:_aStart.y,w:p.x-_aStart.x,h:p.y-_aStart.y,color:_aColor,lw:_aWidth},true);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction aUp(e){\u001b[39m\n\u001b[31m  if(!_aDrawing)return;_aDrawing=false;\u001b[39m\n\u001b[31m  if(_aTool==='move'){_aDragMode=null;return;}\u001b[39m\n\u001b[31m  const p=aPos(e||{touches:[{clientX:0,clientY:0}]});\u001b[39m\n\u001b[31m  if(_aTool==='free'){if(_aPts.length>2){_aHistory.push({type:'free',pts:[..._aPts],x:_aPts[0].x,y:_aPts[0].y,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  else{const w=p.x-_aStart.x,h=p.y-_aStart.y;if(Math.abs(w)>4||Math.abs(h)>4){_aHistory.push({type:_aTool,x:_aStart.x,y:_aStart.y,w,h,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  _aPts=[];redrawAnnot();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction redrawAnnot(){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.clearRect(0,0,cvs.width,cvs.height);if(_aImg)ctx.drawImage(_aImg,0,0,cvs.width,cvs.height);\u001b[39m\n\u001b[31m  _aHistory.forEach((s,i)=>{drawSh(s,false,ctx);if(_aTool==='move'&&i===_aSel)drawHandles(s,ctx);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawHandles(s,ctx){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return;const b=sBounds(s);ctx.save();\u001b[39m\n\u001b[31m  ctx.setLineDash([5,3]);ctx.strokeStyle='#facc15';ctx.lineWidth=1.5;ctx.strokeRect(b.x-2,b.y-2,b.w+4,b.h+4);ctx.setLineDash([]);\u001b[39m\n\u001b[31m  [[b.x,b.y],[b.x+b.w,b.y],[b.x,b.y+b.h],[b.x+b.w,b.y+b.h]].forEach(([x,y])=>{ctx.beginPath();ctx.arc(x,y,7,0,2*Math.PI);ctx.fillStyle='#f97316';ctx.fill();ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();});\u001b[39m\n\u001b[31m  ctx.restore();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawSh(s,preview=false,ctx){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(!ctx)ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.save();ctx.strokeStyle=s.color;ctx.lineWidth=preview?Math.max(s.lw||4,2):s.lw||4;\u001b[39m\n\u001b[31m  ctx.lineCap='round';ctx.lineJoin='round';ctx.setLineDash(preview?[6,3]:[]);\u001b[39m\n\u001b[31m  if(s.type==='rect'){ctx.strokeRect(s.x,s.y,s.w,s.h);ctx.fillStyle=s.color+'28';ctx.fillRect(s.x,s.y,s.w,s.h);}\u001b[39m\n\u001b[31m  else if(s.type==='ellipse'){const cx=s.x+s.w/2,cy=s.y+s.h/2;ctx.beginPath();ctx.ellipse(cx,cy,Math.abs(s.w/2),Math.abs(s.h/2),0,0,2*Math.PI);ctx.stroke();ctx.fillStyle=s.color+'28';ctx.fill();}\u001b[39m\n\u001b[31m  else if(s.type==='line'){ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(s.x+s.w,s.y+s.h);ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='arrow'){const ex=s.x+s.w,ey=s.y+s.h;ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(ex,ey);ctx.stroke();const a=Math.atan2(s.h,s.w),al=20,aa=0.4;ctx.setLineDash([]);ctx.beginPath();ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a-aa),ey-al*Math.sin(a-aa));ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a+aa),ey-al*Math.sin(a+aa));ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='free'){if(s.pts.length<2){ctx.restore();return;}ctx.beginPath();s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));ctx.stroke();}\u001b[39m\n\u001b[31m  ctx.setLineDash([]);ctx.restore();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction undoAnnot(){if(_aHistory.length){_aHistory.pop();_aSel=Math.min(_aSel,_aHistory.length-1);redrawAnnot();}}\u001b[39m\n\u001b[31mfunction clearAnnot(){_aHistory=[];_aSel=-1;redrawAnnot();}·\u001b[39m\n\u001b[31m// Bottom dialog\u001b[39m\n\u001b[31mlet _bdCb=null;\u001b[39m\n\u001b[31mfunction showBDialog(title,sub,onYes){\u001b[39m\n\u001b[31m  document.getElementById('bdialog-title').textContent=title;\u001b[39m\n\u001b[31m  document.getElementById('bdialog-sub').textContent=sub;\u001b[39m\n\u001b[31m  _bdCb=onYes;document.getElementById('bdialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction bdialogYes(){document.getElementById('bdialog').classList.remove('open');if(_bdCb)_bdCb();_bdCb=null;}\u001b[39m\n\u001b[31mfunction bdialogNo(){document.getElementById('bdialog').classList.remove('open');_bdCb=null;}·\u001b[39m\n\u001b[31mfunction _afterBrandingPhoto(){\u001b[39m\n\u001b[31m  const idx=_aTarget;\u001b[39m\n\u001b[31m  showBDialog(t(`Add reference photos for Branding ${idx+1}?`,`ब्रांडिंग ${idx+1} के लिए अतिरिक्त फोटो?`),t('Optional extra photos for future reference.','वैकल्पिक — भविष्य के लिए अतिरिक्त फोटो।'),()=>{showView('form-additional');setTimeout(()=>addAdditional(),200);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction skipAnnot(){document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo added (${fmtSz(brandings[_aTarget].blob.size)})`,'success');_afterBrandingPhoto();}\u001b[39m\n\u001b[31mfunction saveAnnot(){const cvs=document.getElementById('annot-cvs');cvs.toBlob(blob=>{brandings[_aTarget].blob=blob;brandings[_aTarget].prev=URL.createObjectURL(blob);document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo + markup saved (${fmtSz(blob.size)})`,'success');_afterBrandingPhoto();},'image/jpeg',0.88);}·\u001b[39m\n\u001b[31m// ── VIEW RECCE (read-only) ──────────────────────────────────\u001b[39m\n\u001b[31masync function viewRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  // Synced entries have a server-side rich report — open it directly\u001b[39m\n\u001b[31m  if(entry.viewUrl){window.open(entry.viewUrl,'_blank');return;}\u001b[39m\n\u001b[31m  // Offline / not-yet-synced fallback: generate from local base64 data\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  const ts=new Date(entry.timestamp).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'});·\u001b[39m\n\u001b[31m  async function b64ToUrl(b64){if(!b64)return'';try{const r=await fetch(b64);const bl=await r.blob();return URL.createObjectURL(bl);}catch{return'';}}·\u001b[39m\n\u001b[31m  const fvUrls=await Promise.all((d.frontPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const ivUrls=await Promise.all((d.insidePhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const brUrls=await Promise.all((d.brandings||[]).map(b=>b64ToUrl(b.photoB64)));\u001b[39m\n\u001b[31m  const adUrls=await Promise.all((d.addlPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const docUrl=await b64ToUrl(d.docB64);·\u001b[39m\n\u001b[31m  const brRows=(d.brandings||[]).map((b,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:16px;padding:12px;background:#f8fafc;border-radius:8px;border-left:3px solid #f97316\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-weight:600;font-size:14px;color:#0f172a;margin-bottom:6px\\\">${i+1}. ${b.type||'—'}: ${b.w||'?'}\\\"×${b.h||'?'}\\\" · Qty: ${b.qty||'?'} · ${b.sqft||'?'}</div>\u001b[39m\n\u001b[31m      ${brUrls[i]?`<img src=\\\"${brUrls[i]}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:6px\\\">`:'<div style=\\\"color:#94a3b8;font-size:12px\\\">No photo</div>'}\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  const html=`<!DOCTYPE html><html><head><meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m  <title>Recce — ${d.storeName||'Unknown'}</title>\u001b[39m\n\u001b[31m  <style>body{font-family:Arial,sans-serif;margin:0;padding:16px;background:#f1f5f9}\u001b[39m\n\u001b[31m  .card{background:#fff;border-radius:12px;padding:16px;margin-bottom:14px;box-shadow:0 1px 4px rgba(0,0,0,.08)}\u001b[39m\n\u001b[31m  h1{font-size:18px;color:#0f172a;margin:0 0 4px}h2{font-size:14px;color:#f97316;text-transform:uppercase;letter-spacing:.5px;margin:0 0 10px}\u001b[39m\n\u001b[31m  .meta{font-size:12px;color:#64748b;margin-bottom:12px}.photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}\u001b[39m\n\u001b[31m  img{width:100%;border-radius:8px;object-fit:cover}\u001b[39m\n\u001b[31m  .tag{display:inline-block;background:#0f172a;color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-right:4px}\u001b[39m\n\u001b[31m  @media print{body{background:#fff}.card{box-shadow:none}}</style></head><body>\u001b[39m\n\u001b[31m  <div class=\\\"card\\\">\u001b[39m\n\u001b[31m    <h1>${d.storeName||'Unknown Store'}</h1>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\"><span class=\\\"tag\\\">${d.brand||'No Brand'}</span>${d.address||''}</div>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\">📞 ${d.mobile||'—'} &nbsp;|&nbsp; 📅 ${d.date||'—'} &nbsp;|&nbsp; Submitted: ${ts}</div>\u001b[39m\n\u001b[31m    ${d.gpsCoords?`<div class=\\\"meta\\\">📍 ${d.gpsCoords.lat}, ${d.gpsCoords.lng} ±${d.gpsCoords.acc}m</div>`:''}\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${fvUrls.length?`<div class=\\\"card\\\"><h2>Front View Photos</h2><div class=\\\"photos\\\">${fvUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${ivUrls.length?`<div class=\\\"card\\\"><h2>Inside View Photos</h2><div class=\\\"photos\\\">${ivUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${d.hasVideo?`<div class=\\\"card\\\"><h2>Video</h2><div>${d.videoNote||'Video recorded'}</div></div>`:''}\u001b[39m\n\u001b[31m  ${(d.brandings||[]).length?`<div class=\\\"card\\\"><h2>Branding Items (${(d.brandings||[]).length})</h2>${brRows}</div>`:''}\u001b[39m\n\u001b[31m  ${adUrls.length?`<div class=\\\"card\\\"><h2>Additional Photos</h2><div class=\\\"photos\\\">${adUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${docUrl?`<div class=\\\"card\\\"><h2>Submission Document</h2><img src=\\\"${docUrl}\\\" style=\\\"width:100%;max-height:300px;object-fit:contain\\\"></div>`:''}\u001b[39m\n\u001b[31m  <div style=\\\"text-align:center;margin:16px 0\\\">\u001b[39m\n\u001b[31m    <button onclick=\\\"window.print()\\\" style=\\\"background:#f97316;color:#fff;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer\\\">🖨 Print / Save as PDF</button>\u001b[39m\n\u001b[31m    <button onclick=\\\"window.close()\\\" style=\\\"background:#e2e8f0;color:#475569;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer;margin-left:10px\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  </body></html>`;\u001b[39m\n\u001b[31m  const blob=new Blob([html],{type:'text/html'});\u001b[39m\n\u001b[31m  const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m  window.open(url,'_blank');\u001b[39m\n\u001b[31m  setTimeout(()=>URL.revokeObjectURL(url),30000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── EDIT OLD RECCE ───────────────────────────────────────────\u001b[39m\n\u001b[31masync function editRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=d.gpsCoords||null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  F.editingId=id;F.date=d.date||'';F.brand=d.brand||'';F.storeName=d.storeName||'';F.address=d.address||'';F.mobile=d.mobile||'';F.hasVideo=d.hasVideo;F.hasBranding=d.hasBranding;\u001b[39m\n\u001b[31m  async function b64ToBlob(b64){if(!b64)return null;try{const r=await fetch(b64);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m  toast('Loading recce data…','info');\u001b[39m\n\u001b[31m  for(const p of(d.frontPhotos||[])){const b=await b64ToBlob(p.b64);if(b)frontPhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const p of(d.insidePhotos||[])){const b=await b64ToBlob(p.b64);if(b)insidePhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const br of(d.brandings||[])){const b=await b64ToBlob(br.photoB64);brandings.push({type:br.type,w:br.w,h:br.h,qty:br.qty,blob:b,prev:b?URL.createObjectURL(b):null});}\u001b[39m\n\u001b[31m  for(const p of(d.addlPhotos||[])){const b=await b64ToBlob(p.b64);if(b)addlPhotos.push({blob:b,prev:URL.createObjectURL(b),desc:p.desc||''});}\u001b[39m\n\u001b[31m  if(d.docB64){const b=await b64ToBlob(d.docB64);if(b){submissionDoc=b;const sl=document.getElementById('doc-slot');sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${URL.createObjectURL(b)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}}\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  if(F.brand)document.getElementById('f-brand').value=F.brand;\u001b[39m\n\u001b[31m  if(F.storeName)document.getElementById('f-store').value=F.storeName;\u001b[39m\n\u001b[31m  if(F.address)document.getElementById('f-addr').value=F.address;\u001b[39m\n\u001b[31m  if(F.mobile)document.getElementById('f-mobile').value=F.mobile;\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();updAvailTag();\u001b[39m\n\u001b[31m  toast('Recce loaded — make changes and re-submit','success');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── EDIT REQUEST ────────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mlet _editReqSubId = null;·\u001b[39m\n\u001b[31mfunction _hydratePhotosFromRow(r) {\u001b[39m\n\u001b[31m  let pu={};\u001b[39m\n\u001b[31m  try{pu=typeof r.photo_urls==='string'?JSON.parse(r.photo_urls):(r.photo_urls||{});}catch(_){}\u001b[39m\n\u001b[31m  let meta={};\u001b[39m\n\u001b[31m  try{meta=typeof r.meta==='string'?JSON.parse(r.meta):(r.meta||{});}catch(_){}\u001b[39m\n\u001b[31m  frontPhotos =(pu.front   ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  insidePhotos=(pu.inside  ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  addlPhotos  =(pu.addl    ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,desc:''}));\u001b[39m\n\u001b[31m  brandings   =(meta.brandings||[]).map((b,i)=>({type:b.type,w:b.w,h:b.h,qty:b.qty,existingUrl:(pu.brandings||[])[i]||null,blob:null,prev:(pu.brandings||[])[i]||null}));\u001b[39m\n\u001b[31m  _docExistingUrl=pu.doc||null;\u001b[39m\n\u001b[31m  // Show retained doc in slot\u001b[39m\n\u001b[31m  const sl=document.getElementById('doc-slot');\u001b[39m\n\u001b[31m  if(sl&&_docExistingUrl){sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${_docExistingUrl}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openEditRequestModal(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  _editReqSubId = subId;\u001b[39m\n\u001b[31m  document.getElementById('er-store-name').textContent = r.store_name || 'Unknown';\u001b[39m\n\u001b[31m  document.getElementById('er-comment').value = '';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const assignBtn = document.getElementById('er-assign-btn');\u001b[39m\n\u001b[31m  if (r.submitted_by && r.submitted_by !== hub?.empId) {\u001b[39m\n\u001b[31m    assignBtn.textContent = `👤 Assign to ${r.submitted_by}`;\u001b[39m\n\u001b[31m    assignBtn.style.display = '';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    assignBtn.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeEditRequestModal() {\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _editReqSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorEditMyself() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  // Lock branding if client has reviewed (preserve their approval)\u001b[39m\n\u001b[31m  _brandingLocked = !!(r.client_status && r.client_status !== 'pending');\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function assignEditToCreator() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r || !r.submitted_by) { toast('No creator found for this recce', 'error'); return; }\u001b[39m\n\u001b[31m  const comment = (document.getElementById('er-comment').value || '').trim();\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        status: 'edit_requested',\u001b[39m\n\u001b[31m        edit_assigned_to: r.submitted_by,\u001b[39m\n\u001b[31m        edit_comment: comment || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!resp.ok) throw new Error('Update failed: ' + resp.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].status = 'edit_requested';\u001b[39m\n\u001b[31m      _adminRows[idx].edit_assigned_to = r.submitted_by;\u001b[39m\n\u001b[31m      _adminRows[idx].edit_comment = comment || null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Push notification to creator\u001b[39m\n\u001b[31m    const notifBody = comment || `Please review and re-submit: ${r.store_name || 'your recce'}`;\u001b[39m\n\u001b[31m    fetch('/push-server/notify', {\u001b[39m\n\u001b[31m      method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        user_id: r.submitted_by, title: '✏ Edit Requested',\u001b[39m\n\u001b[31m        body: notifBody, tag: `recce-edit-${subId}`, url: '/recce/',\u001b[39m\n\u001b[31m        icon: '/hub/icons/icon-192.png', badge: '/hub/icons/icon-192.png',\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    }).catch(() => {});\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast(`Edit assigned to ${r.submitted_by} ✓`, 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Assign failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function startCreatorEdit(subId) {\u001b[39m\n\u001b[31m  // Try local IndexedDB first (has photos)\u001b[39m\n\u001b[31m  const local = await dbGet('subs', subId);\u001b[39m\n\u001b[31m  if (local) { await editRecce(subId); return; }\u001b[39m\n\u001b[31m  // Fallback: load text fields from server row\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId)\u001b[39m\n\u001b[31m         || (await (async () => {\u001b[39m\n\u001b[31m              try {\u001b[39m\n\u001b[31m                const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, { headers: _RC_READ });\u001b[39m\n\u001b[31m                if (resp.ok) { const arr = await resp.json(); return arr[0]; }\u001b[39m\n\u001b[31m              } catch(_) {} return null;\u001b[39m\n\u001b[31m            })());\u001b[39m\n\u001b[31m  if (!r) { toast('Record not found', 'error'); return; }\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── End edit request ─────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mfunction goToHub() { window.location.href = '/hub/'; }\u001b[39m\n\u001b[31mfunction recceLogout() {\u001b[39m\n\u001b[31m  if (!confirm('Log out?')) return;\u001b[39m\n\u001b[31m  localStorage.removeItem('lm360-session');\u001b[39m\n\u001b[31m  localStorage.removeItem('360exp-session');\u001b[39m\n\u001b[31m  window.location.href = '/hub/';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction injectHubButtons() {\u001b[39m\n\u001b[31m  const u = _recceHubUser();\u001b[39m\n\u001b[31m  const name = u ? (u.name || '') : '';\u001b[39m\n\u001b[31m  if (name) {\u001b[39m\n\u001b[31m    const bar = document.getElementById('recce-hero-ubar');\u001b[39m\n\u001b[31m    const nm  = document.getElementById('recce-hero-name');\u001b[39m\n\u001b[31m    if (bar) { nm.textContent = name; bar.style.display = 'flex'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.querySelectorAll('.hdr').forEach(hdr => {\u001b[39m\n\u001b[31m    const r = document.createElement('div');\u001b[39m\n\u001b[31m    r.className = 'hdr-r';\u001b[39m\n\u001b[31m    if (name) {\u001b[39m\n\u001b[31m      const un = document.createElement('span');\u001b[39m\n\u001b[31m      un.className = 'hdr-user';\u001b[39m\n\u001b[31m      un.textContent = name;\u001b[39m\n\u001b[31m      r.appendChild(un);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    const hub = document.createElement('button');\u001b[39m\n\u001b[31m    hub.className = 'btn-hub';\u001b[39m\n\u001b[31m    hub.innerHTML = '🏡 Hub';\u001b[39m\n\u001b[31m    hub.addEventListener('click', goToHub);\u001b[39m\n\u001b[31m    r.appendChild(hub);\u001b[39m\n\u001b[31m    const lo = document.createElement('button');\u001b[39m\n\u001b[31m    lo.className = 'btn-logout';\u001b[39m\n\u001b[31m    lo.textContent = 'Logout';\u001b[39m\n\u001b[31m    lo.addEventListener('click', recceLogout);\u001b[39m\n\u001b[31m    r.appendChild(lo);\u001b[39m\n\u001b[31m    hdr.appendChild(r);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction checkAppUpdate(){\u001b[39m\n\u001b[31m  const seen=localStorage.getItem('recce-ver-seen');\u001b[39m\n\u001b[31m  localStorage.setItem('recce-ver-seen',CACHE_VER);\u001b[39m\n\u001b[31m  if(seen&&seen!==CACHE_VER){\u001b[39m\n\u001b[31m    const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m    if(b){b.classList.add('show');setTimeout(()=>b.classList.remove('show'),5000);}\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction dismissUpdateBanner(){\u001b[39m\n\u001b[31m  const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m  if(b)b.classList.remove('show');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function init(){\u001b[39m\n\u001b[31m  // Detect host banners (tiiny.host, etc) and raise bnav above them\u001b[39m\n\u001b[31m  (function detectHostBar(){\u001b[39m\n\u001b[31m    const h=window.location.hostname;\u001b[39m\n\u001b[31m    let extra=0;\u001b[39m\n\u001b[31m    if(h.includes('tiiny'))extra=58;\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // Generic detection: check if window is shorter than expected (host injected a bar)\u001b[39m\n\u001b[31m      const gap=screen.height - window.innerHeight;\u001b[39m\n\u001b[31m      if(gap>100&&gap<200)extra=58; // a fixed bar is roughly 56-60px\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if(extra>0){\u001b[39m\n\u001b[31m      document.documentElement.style.setProperty('--host-bar',extra+'px');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  })();\u001b[39m\n\u001b[31m  setLang(LANG);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m  checkAppUpdate();\u001b[39m\n\u001b[31m  await loadRecceCfg();\u001b[39m\n\u001b[31m  _checkAccessMode();\u001b[39m\n\u001b[31m  await initDB();await loadSettings();await loadHome();await checkDraft();netStatus();window.addEventListener('online',()=>{netStatus();syncNow();});window.addEventListener('offline',netStatus);injectHubButtons();document.getElementById('today-date').textContent=new Date().toLocaleDateString('en-IN',{weekday:'long',day:'numeric',month:'long',year:'numeric'});updAvailTag();\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m  // Auto-fetch stores from server on every startup (uses default Netlify URL if none saved)\u001b[39m\n\u001b[31m  const su=(await cfg('srv-url'))||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su&&navigator.onLine){\u001b[39m\n\u001b[31m    fetch(su).then(r=>r.json()).then(async j=>{\u001b[39m\n\u001b[31m      const d=Array.isArray(j)?j:j.stores||[];\u001b[39m\n\u001b[31m      if(d.length){stores=d;await cfg('stores',JSON.stringify(d));await cfg('srv-url',su);updAvailTag();\u001b[39m\n\u001b[31m        document.getElementById('srv-url').value=su;}\u001b[39m\n\u001b[31m    }).catch(()=>{});\u001b[39m\n\u001b[31m  }}init();\u001b[39m\n\u001b[31m</script>\u001b[39m\n\u001b[31m</body>\u001b[39m\n\u001b[31m</html>\u001b[39m\n\u001b[31m\"\u001b[39m\n\n  335 |     const resp = await page.request.get(BASE_URL);\n  336 |     const src = await resp.text();\n> 337 |     expect(src).toContain('recce-v15');\n      |                 ^\n  338 |     expect(src).not.toContain('recce-v14');\n  339 |   });\n  340 | });\n    at /var/www/360lm/tests/recce.spec.js:337:17"
                        }
                      ],
                      "stdout": [],
                      "stderr": [],
                      "retry": 1,
                      "startTime": "2026-05-28T12:44:30.124Z",
                      "annotations": [],
                      "attachments": [
                        {
                          "name": "screenshot",
                          "contentType": "image/png",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v10-dbf60-tos-SW-version-is-recce-v15-android-chrome-retry1/test-failed-1.png"
                        },
                        {
                          "name": "error-context",
                          "contentType": "text/markdown",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v10-dbf60-tos-SW-version-is-recce-v15-android-chrome-retry1/error-context.md"
                        }
                      ],
                      "errorLocation": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "column": 17,
                        "line": 337
                      }
                    }
                  ],
                  "status": "unexpected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-bf9dff1f1d39f21f2c57",
              "file": "recce.spec.js",
              "line": 334,
              "column": 3
            },
            {
              "title": "inside view label shows \"(optional, max 5)\"",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 10443,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:48:17.895Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-290e517ef1b0aa6969f1",
              "file": "recce.spec.js",
              "line": 293,
              "column": 3
            },
            {
              "title": "front view label still shows \"(min 1, max 3)\"",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 10513,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:48:28.359Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-c2186030fc7e5640d768",
              "file": "recce.spec.js",
              "line": 307,
              "column": 3
            },
            {
              "title": "add-inside button hidden after 3 photos (before limit) — regression guard",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 723,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:48:38.900Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-61a619f43cbfc0e44e4f",
              "file": "recce.spec.js",
              "line": 319,
              "column": 3
            },
            {
              "title": "SW version is recce-v15",
              "ok": false,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 6,
                      "parallelIndex": 0,
                      "status": "failed",
                      "duration": 442,
                      "error": {
                        "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoContain\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // indexOf\u001b[22m\n\nExpected substring: \u001b[32m\"recce-v15\"\u001b[39m\nReceived string:    \u001b[31m\"<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\">\u001b[39m\n\u001b[31m<head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\">\u001b[39m\n\u001b[31m<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\\\">\u001b[39m\n\u001b[31m<meta name=\\\"theme-color\\\" content=\\\"#0f172a\\\">\u001b[39m\n\u001b[31m<meta name=\\\"apple-mobile-web-app-capable\\\" content=\\\"yes\\\">\u001b[39m\n\u001b[31m<title>Branding Recce</title>\u001b[39m\n\u001b[31m<link rel=\\\"manifest\\\" href=\\\"manifest.json\\\">\u001b[39m\n\u001b[31m<link rel=\\\"preconnect\\\" href=\\\"https://fonts.googleapis.com\\\">\u001b[39m\n\u001b[31m<link href=\\\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap\\\" rel=\\\"stylesheet\\\">\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--nv:#0f172a;--nv2:#1e293b;--or:#f97316;--orl:#fed7aa;--gn:#16a34a;--rd:#dc2626;--am:#d97706;--g50:#f8fafc;--g100:#f1f5f9;--g200:#e2e8f0;--g300:#cbd5e1;--g400:#94a3b8;--g500:#64748b;--g600:#475569;--r:12px;--rs:8px;--sh:0 1px 3px rgba(0,0,0,.1),0 1px 2px rgba(0,0,0,.06);--bnav-h:72px;--host-bar:0px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}\u001b[39m\n\u001b[31mbody{font-family:'DM Sans',sans-serif;background:var(--g50);color:var(--nv);min-height:100vh;overflow-x:hidden}\u001b[39m\n\u001b[31m.hdr{background:var(--nv);color:#fff;padding:0 16px;height:56px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}\u001b[39m\n\u001b[31m.hdr-l{display:flex;align-items:center;gap:10px}\u001b[39m\n\u001b[31m.hdr-title{font-size:16px;font-weight:600}.hdr-sub{font-size:11px;color:var(--g400)}\u001b[39m\n\u001b[31m.back-btn,.icon-btn{background:none;border:none;color:#fff;padding:8px;cursor:pointer;display:flex;align-items:center}\u001b[39m\n\u001b[31m.back-btn{margin-left:-8px}\u001b[39m\n\u001b[31m.pgbar{height:3px;background:var(--g200)}.pgfill{height:100%;background:var(--or);transition:width .3s}\u001b[39m\n\u001b[31m.view{display:none;min-height:calc(100vh - 56px);padding-bottom:calc(var(--bnav-h) + var(--host-bar) + 24px)}.view.active{display:block}\u001b[39m\n\u001b[31m.content{padding:16px}\u001b[39m\n\u001b[31m.card{background:#fff;border-radius:var(--r);padding:16px;box-shadow:var(--sh);margin-bottom:12px}\u001b[39m\n\u001b[31m.card-title{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;letter-spacing:.6px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between}\u001b[39m\n\u001b[31m.cnt-badge{background:var(--or);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;min-width:22px;text-align:center}\u001b[39m\n\u001b[31m.cnt-badge.gray{background:var(--g400)}\u001b[39m\n\u001b[31m.field{margin-bottom:16px}.field:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.field label{display:block;font-size:13px;font-weight:500;color:var(--g600);margin-bottom:6px}\u001b[39m\n\u001b[31m.req{color:var(--or);margin-left:2px}\u001b[39m\n\u001b[31m.field input,.field select,.field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;color:var(--nv);background:#fff;transition:border-color .15s;-webkit-appearance:none;appearance:none}\u001b[39m\n\u001b[31m.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--or)}\u001b[39m\n\u001b[31m.field input:read-only{background:var(--g50);color:var(--g600)}\u001b[39m\n\u001b[31m.field textarea{resize:vertical;min-height:68px}\u001b[39m\n\u001b[31m.field select{background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}\u001b[39m\n\u001b[31m.pslot{border:2px dashed var(--g300);border-radius:var(--r);min-height:110px;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all .15s;position:relative;overflow:hidden;text-align:center;padding:16px}\u001b[39m\n\u001b[31m.pslot:active{border-color:var(--or);background:var(--g50)}\u001b[39m\n\u001b[31m.pslot.filled{border-style:solid;border-color:var(--or);padding:0;min-height:0}\u001b[39m\n\u001b[31m.pslot img{width:100%;height:150px;object-fit:cover;border-radius:calc(var(--r) - 2px);display:block}\u001b[39m\n\u001b[31m.pslot-lbl{font-size:13px;color:var(--g400);margin-top:6px}.pslot-ico{font-size:28px;color:var(--g300)}\u001b[39m\n\u001b[31m.pbadge{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.premove{position:absolute;top:6px;right:6px;background:var(--rd);color:#fff;border:none;border-radius:50%;width:26px;height:26px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;z-index:5}\u001b[39m\n\u001b[31minput[type=file]{display:none}\u001b[39m\n\u001b[31m.rgroup{display:flex;gap:10px}\u001b[39m\n\u001b[31m.rbtn{flex:1;padding:13px;border:1.5px solid var(--g200);border-radius:var(--rs);text-align:center;cursor:pointer;font-size:14px;font-weight:500;color:var(--g500);transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.rbtn.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.chip-grid{display:flex;flex-wrap:wrap;gap:8px}\u001b[39m\n\u001b[31m.chip{padding:7px 12px;border:1.5px solid var(--g200);border-radius:20px;font-size:13px;color:var(--g600);cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.chip.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.brand-chip{display:flex;align-items:center;gap:6px;padding:5px 12px}\u001b[39m\n\u001b[31m.brand-chip-logo{width:28px;height:18px;object-fit:contain;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{display:block;width:100%;padding:15px;background:var(--or);color:#fff;border:none;border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:700;cursor:pointer;text-align:center;transition:background .15s}\u001b[39m\n\u001b[31m.btn-p:active{background:#ea6c05}.btn-p:disabled{background:var(--g300);cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-s{display:block;width:100%;padding:14px;background:#fff;color:var(--nv);border:1.5px solid var(--g200);border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:500;cursor:pointer;text-align:center}\u001b[39m\n\u001b[31m.btn-s:active{background:var(--g100)}\u001b[39m\n\u001b[31m.btn-o{display:inline-flex;align-items:center;gap:6px;padding:10px 16px;background:#fff;color:var(--or);border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer}\u001b[39m\n\u001b[31m.btn-o:active{background:var(--orl)}\u001b[39m\n\u001b[31m.btn-d{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;background:#fff;color:var(--rd);border:1.5px solid #fecaca;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:12px;cursor:pointer}\u001b[39m\n\u001b[31m.bnav{position:fixed;bottom:var(--host-bar);left:0;right:0;background:#fff;border-top:1px solid var(--g200);display:flex;padding:10px 16px;gap:10px;z-index:100}\u001b[39m\n\u001b[31m.hero{background:var(--nv);color:#fff;padding:20px 16px 24px}\u001b[39m\n\u001b[31m.hero-title{font-size:22px;font-weight:700;margin-bottom:2px}.hero-sub{font-size:13px;color:var(--g400)}\u001b[39m\n\u001b[31m.stats{display:flex;gap:10px;margin-top:16px}\u001b[39m\n\u001b[31m.scard{flex:1;background:rgba(255,255,255,.08);border-radius:var(--rs);padding:12px;text-align:center}\u001b[39m\n\u001b[31m.snum{font-size:22px;font-weight:700}.slbl{font-size:11px;color:var(--g400);margin-top:2px}\u001b[39m\n\u001b[31m.scard.g .snum{color:#4ade80}.scard.a .snum{color:#fbbf24}\u001b[39m\n\u001b[31m.new-btn{background:var(--or);color:#fff;border:none;border-radius:var(--r);padding:16px;font-family:'DM Sans',sans-serif;font-size:16px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:10px;cursor:pointer;width:100%;margin-bottom:10px}\u001b[39m\n\u001b[31m.new-btn:active{background:#ea6c05}\u001b[39m\n\u001b[31m.resume-btn{background:var(--nv2);color:#fff;border:none;border-radius:var(--r);padding:13px 16px;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;display:flex;align-items:center;justify-content:space-between;cursor:pointer;width:100%;margin-bottom:18px}\u001b[39m\n\u001b[31m.sub-card{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:10px;display:flex;align-items:center;gap:12px}\u001b[39m\n\u001b[31m.sub-ico{width:40px;height:40px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}\u001b[39m\n\u001b[31m.sub-ico.pending{background:#fef3c7}.sub-ico.synced{background:#dcfce7}.sub-ico.failed{background:#fee2e2}\u001b[39m\n\u001b[31m.sub-meta{flex:1;min-width:0}.sub-name{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.sub-dtl{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.sbadge{font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;flex-shrink:0}\u001b[39m\n\u001b[31m.sbadge.pending{background:#fef3c7;color:#92400e}.sbadge.synced{background:#dcfce7;color:#14532d}.sbadge.failed{background:#fee2e2;color:#991b1b}\u001b[39m\n\u001b[31m.sh{display:flex;align-items:center;justify-content:space-between;margin:20px 0 12px}\u001b[39m\n\u001b[31m.st{font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.toast{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 8px);left:16px;right:16px;background:var(--nv);color:#fff;padding:12px 16px;border-radius:var(--r);font-size:14px;z-index:1000;transform:translateY(120px);opacity:0;transition:all .3s;pointer-events:none}\u001b[39m\n\u001b[31m.toast.show{transform:translateY(0);opacity:1}.toast.success{background:#16a34a}.toast.error{background:var(--rd)}.toast.info{background:var(--nv2)}\u001b[39m\n\u001b[31m.srow{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:#fff;border-top:1px solid var(--g100);font-size:12px;color:var(--g500)}\u001b[39m\n\u001b[31m.sdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px}.sdot.on{background:var(--gn)}.sdot.off{background:var(--g300)}\u001b[39m\n\u001b[31m.set-item{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:8px}\u001b[39m\n\u001b[31m.set-lbl{font-size:14px;font-weight:600;color:var(--nv);margin-bottom:4px}\u001b[39m\n\u001b[31m.set-sub{font-size:12px;color:var(--g500);margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem{background:#fff;border-radius:var(--r);border:1.5px solid var(--g200);padding:14px;margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\u001b[39m\n\u001b[31m.bitem-title{font-size:14px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.dim-row{display:flex;gap:8px}.dim-row .field{flex:1}\u001b[39m\n\u001b[31m.sqft{display:inline-block;background:var(--g100);color:var(--g600);font-size:12px;padding:4px 10px;border-radius:20px;margin-top:6px}\u001b[39m\n\u001b[31m.divider{height:1px;background:var(--g100);margin:12px 0}\u001b[39m\n\u001b[31m.rev-lbl{font-size:12px;color:var(--g500);margin-bottom:2px}\u001b[39m\n\u001b[31m.rev-val{font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.rev-photos{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}\u001b[39m\n\u001b[31m.rev-thumb{width:56px;height:56px;object-fit:cover;border-radius:var(--rs)}\u001b[39m\n\u001b[31m.empty{text-align:center;padding:40px 20px;color:var(--g400)}.empty-ico{font-size:40px;margin-bottom:12px}.empty-txt{font-size:14px}\u001b[39m\n\u001b[31m/* store picker */\u001b[39m\n\u001b[31m.store-card{border:1.5px solid var(--g200);border-radius:var(--rs);padding:13px 14px;background:#fff;position:relative;cursor:pointer}\u001b[39m\n\u001b[31m.store-card:active{background:var(--g50)}\u001b[39m\n\u001b[31m.store-card-name{font-size:15px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.store-card-meta{font-size:13px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.store-card-change{position:absolute;top:11px;right:12px;background:none;border:none;color:var(--or);font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer}\u001b[39m\n\u001b[31m.brand-tag{display:inline-block;background:var(--nv);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-top:4px}\u001b[39m\n\u001b[31m.last-chip{display:inline-flex;align-items:center;gap:4px;background:#fef3c7;color:#92400e;font-size:11px;font-weight:500;padding:3px 9px;border-radius:20px;margin-left:6px}\u001b[39m\n\u001b[31m.pick-trigger{border:2px solid var(--or);border-radius:var(--rs);padding:14px 16px;background:#fff7ed;display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-size:15px;font-weight:600;color:var(--or)}\u001b[39m\n\u001b[31m.pick-trigger:active{background:#ffedd5;border-color:#ea6800}\u001b[39m\n\u001b[31m.manual-toggle{display:flex;align-items:center;gap:8px;padding:10px 14px;border:1.5px dashed var(--g300);border-radius:var(--rs);cursor:pointer;font-size:13px;color:var(--g600);margin-top:8px;user-select:none}\u001b[39m\n\u001b[31m/* client chip grid */\u001b[39m\n\u001b[31m.cl-chip-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}\u001b[39m\n\u001b[31m.cl-chip{padding:8px 14px;border-radius:20px;border:1.5px solid var(--g200);font-size:13px;font-weight:500;color:var(--g600);background:#fff;cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.cl-chip:active,.cl-chip.sel{background:var(--or);border-color:var(--or);color:#fff;font-weight:600}\u001b[39m\n\u001b[31m.cl-chip-other{border-style:dashed}\u001b[39m\n\u001b[31m.client-tag{display:inline-block;background:#e0f2fe;color:#0369a1;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-left:4px}\u001b[39m\n\u001b[31m.manual-toggle.on{border-color:var(--or);background:#fff7ed;color:var(--or)}\u001b[39m\n\u001b[31m/* picker overlay */\u001b[39m\n\u001b[31m.povl{display:none;position:fixed;inset:0;background:var(--g50);z-index:200;flex-direction:column}\u001b[39m\n\u001b[31m.povl.open{display:flex}\u001b[39m\n\u001b[31m.povl-hdr{background:var(--nv);padding:12px 16px;display:flex;align-items:center;gap:12px;flex-shrink:0}\u001b[39m\n\u001b[31m.psearch{flex:1;padding:10px 14px;border:none;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;background:rgba(255,255,255,.12);color:#fff;outline:none}\u001b[39m\n\u001b[31m.psearch::placeholder{color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.pcancel{background:none;border:none;color:rgba(255,255,255,.7);font-family:'DM Sans',sans-serif;font-size:14px;cursor:pointer;padding:4px;white-space:nowrap}\u001b[39m\n\u001b[31m.plist{overflow-y:auto;flex:1}\u001b[39m\n\u001b[31m.pitem{padding:14px 16px;border-bottom:.5px solid var(--g100);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px}\u001b[39m\n\u001b[31m.pitem:active{background:var(--g100)}\u001b[39m\n\u001b[31m.pi-name{font-size:15px;font-weight:600;color:var(--nv)}.pi-addr{font-size:12px;color:var(--g500);margin-top:2px}.pi-last{font-size:11px;color:var(--am);margin-top:2px}\u001b[39m\n\u001b[31m.pi-brand{font-size:11px;font-weight:700;padding:3px 8px;border-radius:20px;background:var(--nv);color:#fff;flex-shrink:0}\u001b[39m\n\u001b[31m.psec{padding:8px 16px 4px;font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;background:var(--g50)}\u001b[39m\n\u001b[31m.padd{padding:16px;text-align:center;font-size:14px;color:var(--or);font-weight:600;cursor:pointer;background:#fff7ed;border-top:1.5px dashed var(--or)}\u001b[39m\n\u001b[31m.gps-row{display:flex;gap:8px;margin-top:8px}\u001b[39m\n\u001b[31m.gps-btn{flex-shrink:0;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;color:var(--g500);display:flex;align-items:center;gap:6px}\u001b[39m\n\u001b[31m.gps-btn:active{background:var(--orl);border-color:var(--or);color:var(--or)}\u001b[39m\n\u001b[31m@keyframes spin{to{transform:rotate(360deg)}}.spin{animation:spin .7s linear infinite;display:inline-block}\u001b[39m\n\u001b[31m/* ANNOTATION TOOL */\u001b[39m\n\u001b[31m.annot-modal{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column}\u001b[39m\n\u001b[31m.annot-modal.open{display:flex}\u001b[39m\n\u001b[31m.annot-bar{background:var(--nv);padding:8px 12px;flex-shrink:0}\u001b[39m\n\u001b[31m.annot-row{display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap}\u001b[39m\n\u001b[31m.annot-row:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.atool{padding:6px 10px;background:rgba(255,255,255,.1);border:1.5px solid rgba(255,255,255,.2);border-radius:var(--rs);color:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:500;cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.atool.on{background:var(--or);border-color:var(--or)}\u001b[39m\n\u001b[31m.atool.sel-on{background:#7c3aed;border-color:#7c3aed}\u001b[39m\n\u001b[31m.acolor{width:24px;height:24px;border-radius:50%;border:2px solid rgba(255,255,255,.3);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.acolor.on{border-color:#fff;border-width:3px;transform:scale(1.15)}\u001b[39m\n\u001b[31m.annot-cvs-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#111;position:relative}\u001b[39m\n\u001b[31m#annot-cvs{max-width:100%;max-height:100%;display:block;touch-action:none;cursor:crosshair}\u001b[39m\n\u001b[31m.annot-foot{background:var(--nv);padding:10px 16px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.req-note{font-size:12px;color:var(--rd);margin-top:6px;font-weight:500}\u001b[39m\n\u001b[31m/* Bottom dialog */\u001b[39m\n\u001b[31m.bdialog-wrap{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:400;align-items:flex-end}\u001b[39m\n\u001b[31m.bdialog-wrap.open{display:flex}\u001b[39m\n\u001b[31m.bdialog{background:#fff;border-radius:var(--r) var(--r) 0 0;padding:20px 16px 32px;width:100%}\u001b[39m\n\u001b[31m.bdialog-title{font-size:16px;font-weight:700;color:var(--nv);margin-bottom:6px}\u001b[39m\n\u001b[31m.bdialog-sub{font-size:13px;color:var(--g500);margin-bottom:16px}\u001b[39m\n\u001b[31m.bdialog-btns{display:flex;gap:10px}\u001b[39m\n\u001b[31m/* Edit badge on sub-card */\u001b[39m\n\u001b[31m.edit-btn-sm{padding:5px 12px;background:var(--g50);border:1px solid var(--g200);border-radius:20px;font-family:'DM Sans',sans-serif;font-size:12px;color:var(--g600);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m/* Toggle switch */\u001b[39m\n\u001b[31m.tog{width:48px;height:26px;background:var(--g300);border-radius:13px;cursor:pointer;transition:background .2s;flex-shrink:0;position:relative;display:inline-block}\u001b[39m\n\u001b[31m.tog.on{background:var(--or)}\u001b[39m\n\u001b[31m.tog-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2);pointer-events:none}\u001b[39m\n\u001b[31m.tog.on .tog-knob{transform:translateX(22px)}\u001b[39m\n\u001b[31m/* ── ADMIN RECCE VIEW ── */\u001b[39m\n\u001b[31m.af-bar{background:var(--g100);padding:10px 16px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--g200);overflow:hidden}\u001b[39m\n\u001b[31m.af-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}\u001b[39m\n\u001b[31m.af-sel{width:100%;padding:8px 10px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv);cursor:pointer;\u001b[39m\n\u001b[31m  white-space:normal;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.af-sel:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.af-inp{width:100%;padding:8px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv)}\u001b[39m\n\u001b[31m.af-inp:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.grp-hdr{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;\u001b[39m\n\u001b[31m  letter-spacing:.5px;padding:14px 0 6px;border-bottom:1px solid var(--g200);margin-bottom:6px}\u001b[39m\n\u001b[31m.grp-hdr:first-child{padding-top:0}\u001b[39m\n\u001b[31m.asc{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:12px 14px;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;gap:6px;margin-bottom:8px;cursor:pointer;\u001b[39m\n\u001b[31m  transition:box-shadow .15s}\u001b[39m\n\u001b[31m.asc:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.asc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}\u001b[39m\n\u001b[31m.asc-name{font-size:14px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.asc-brand{display:inline-block;background:#fff7ed;color:var(--or);font-size:11px;\u001b[39m\n\u001b[31m  font-weight:600;padding:2px 8px;border-radius:20px;border:1px solid #fed7aa;white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chip{background:var(--g100);border-radius:20px;padding:2px 8px;font-size:11px;color:var(--g600);white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chips{display:flex;flex-wrap:wrap;gap:5px}\u001b[39m\n\u001b[31m.asc-agent{background:var(--nv);color:#fff;font-size:11px;font-weight:600;\u001b[39m\n\u001b[31m  padding:2px 8px;border-radius:20px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m/* Admin detail modal */\u001b[39m\n\u001b[31m.ardl-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:600;\u001b[39m\n\u001b[31m  display:flex;align-items:flex-end;justify-content:center}\u001b[39m\n\u001b[31m.ardl-box{background:#fff;border-radius:var(--r) var(--r) 0 0;width:100%;max-height:80vh;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ardl-hdr{display:flex;align-items:flex-start;justify-content:space-between;\u001b[39m\n\u001b[31m  padding:16px 16px 10px;border-bottom:1px solid var(--g200);gap:10px}\u001b[39m\n\u001b[31m.ardl-title{font-size:17px;font-weight:700;color:var(--nv);line-height:1.3}\u001b[39m\n\u001b[31m.ardl-body{flex:1;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:14px}\u001b[39m\n\u001b[31m.ardl-sec{display:flex;flex-direction:column;gap:6px}\u001b[39m\n\u001b[31m.ardl-lbl{font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.ardl-val{font-size:13px;color:var(--nv);line-height:1.5}\u001b[39m\n\u001b[31m.ardl-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\u001b[39m\n\u001b[31m/* Hub home button */\u001b[39m\n\u001b[31m.btn-hub{background:none;border:1px solid rgba(255,255,255,.25);color:rgba(255,255,255,.85);\u001b[39m\n\u001b[31m  font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;cursor:pointer;\u001b[39m\n\u001b[31m  display:flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-hub:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hdr-r{display:flex;align-items:center;gap:6px;margin-left:auto;flex-shrink:0}\u001b[39m\n\u001b[31m.hdr-user{font-size:11px;color:rgba(255,255,255,.7);white-space:nowrap;max-width:80px;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.btn-logout{background:none;border:1px solid rgba(255,255,255,.2);color:rgba(255,255,255,.7);font-size:11px;font-weight:600;padding:4px 8px;border-radius:20px;cursor:pointer;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-logout:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hero-ubar{display:flex;align-items:center;justify-content:space-between;padding-top:6px;margin-top:2px}\u001b[39m\n\u001b[31m.hero-uname{font-size:12px;color:rgba(255,255,255,.65)}\u001b[39m\n\u001b[31m.hi-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .en-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .hi-txt{display:inline}\u001b[39m\n\u001b[31m.lang-btn{background:none;border:1px solid rgba(255,255,255,.3);color:rgba(255,255,255,.8);font-size:12px;font-weight:700;padding:4px 10px;border-radius:20px;cursor:pointer;display:flex;align-items:center;gap:3px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.lang-btn:active{background:rgba(255,255,255,.15)}\u001b[39m\n\u001b[31m/* ── DELETE / AUDIT ── */\u001b[39m\n\u001b[31m.del-btn{background:none;border:none;padding:6px 8px;cursor:pointer;color:var(--g400);font-size:16px;flex-shrink:0;border-radius:var(--rs);transition:color .15s,background .15s}\u001b[39m\n\u001b[31m.del-btn:active{color:var(--rd);background:#fee2e2}\u001b[39m\n\u001b[31m.asc.deleted-row{background:#fff5f5;border:1px solid #fecaca;opacity:.85}\u001b[39m\n\u001b[31m.asc.deleted-row .asc-name{text-decoration:line-through;color:var(--g500)}\u001b[39m\n\u001b[31m.del-reason-tag{display:inline-block;background:#fee2e2;color:var(--rd);font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.del-by-txt{font-size:11px;color:var(--g400);margin-top:3px}\u001b[39m\n\u001b[31m.restore-btn{background:none;border:1.5px solid #bbf7d0;border-radius:20px;color:#16a34a;font-size:11px;font-weight:700;padding:3px 10px;cursor:pointer;white-space:nowrap;margin-top:5px}\u001b[39m\n\u001b[31m.restore-btn:active{background:#dcfce7}\u001b[39m\n\u001b[31m.sup-tile{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:20px 16px;cursor:pointer;display:flex;align-items:center;gap:14px;margin-bottom:12px;transition:box-shadow .15s}\u001b[39m\n\u001b[31m.sup-tile:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.sup-tile-ico{width:48px;height:48px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:26px;flex-shrink:0}\u001b[39m\n\u001b[31m.sup-tile-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.sup-tile-title{font-size:15px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.sup-tile-sub{font-size:12px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.del-toggle-btn{padding:6px 14px;border:1.5px solid var(--g200);border-radius:20px;background:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:600;color:var(--g500);cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.del-toggle-btn.active{background:#fee2e2;border-color:#fecaca;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1.5px solid var(--g200);border-radius:var(--r);margin-bottom:10px;cursor:pointer;transition:all .15s;font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.reason-opt:active{background:var(--g50)}\u001b[39m\n\u001b[31m.reason-opt.sel{border-color:var(--rd);background:#fff5f5;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt.danger{border-color:#fdba74;background:#fff7ed;color:#9a3412}\u001b[39m\n\u001b[31m.reason-opt.danger.sel{border-color:#c2410c;background:#fff1e6;color:#9a3412}\u001b[39m\n\u001b[31m#del-confirm-btn.no-reason{background:var(--g300)!important;cursor:default}\u001b[39m\n\u001b[31m@keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}\u001b[39m\n\u001b[31m.reason-opt-ico{font-size:22px;flex-shrink:0}\u001b[39m\n\u001b[31m/* ── APP UPDATE BANNER ── */\u001b[39m\n\u001b[31m.upd-banner{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);left:12px;right:12px;background:#16a34a;color:#fff;padding:11px 14px;border-radius:var(--r);display:flex;align-items:center;justify-content:space-between;gap:10px;z-index:550;box-shadow:0 4px 16px rgba(0,0,0,.18);transform:translateY(120px);opacity:0;transition:transform .35s ease,opacity .35s ease;pointer-events:none}\u001b[39m\n\u001b[31m.upd-banner.show{transform:translateY(0);opacity:1;pointer-events:auto}\u001b[39m\n\u001b[31m/* ── EDIT REQUEST ── */\u001b[39m\n\u001b[31m.req-edit-btn{padding:4px 10px;background:#fffbeb;border:1px solid #fde68a;border-radius:20px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:600;color:#92400e;cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.req-edit-btn:active{background:#fef3c7}\u001b[39m\n\u001b[31m.edit-req-badge{display:inline-block;background:#fef3c7;color:#92400e;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;white-space:nowrap}\u001b[39m\n\u001b[31m.edit-req-card{background:#fffbeb;border:1.5px solid #fde68a;border-radius:var(--r);padding:14px 16px;margin-bottom:10px;display:flex;align-items:flex-start;gap:12px}\u001b[39m\n\u001b[31m.edit-req-card-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.edit-req-card-name{font-size:14px;font-weight:600;color:var(--nv);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.edit-req-card-meta{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.edit-req-cmt{font-size:12px;color:#78350f;background:#fff;border:1px solid #fde68a;border-radius:var(--rs);padding:8px 10px;margin-top:8px;line-height:1.5}\u001b[39m\n\u001b[31m.edit-req-section-hdr{font-size:11px;font-weight:700;color:#92400e;text-transform:uppercase;letter-spacing:.5px;padding:10px 0 6px;border-bottom:1px solid #fde68a;margin-bottom:8px}\u001b[39m\n\u001b[31m.upd-banner-ok{background:rgba(255,255,255,.2);border:none;color:#fff;border-radius:20px;padding:5px 13px;font-size:12px;font-weight:600;cursor:pointer;font-family:'DM Sans',sans-serif;white-space:nowrap}\u001b[39m\n\u001b[31m.upd-banner-ok:active{background:rgba(255,255,255,.35)}\u001b[39m\n\u001b[31m/* ── FONT SIZE WIDGET ── */\u001b[39m\n\u001b[31m.fs-widget{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);right:12px;display:flex;align-items:center;gap:0;background:#fff;border:1.5px solid var(--g200);border-radius:24px;box-shadow:0 2px 8px rgba(0,0,0,.12);z-index:500;overflow:hidden;user-select:none}\u001b[39m\n\u001b[31m.fs-btn{background:none;border:none;cursor:pointer;padding:7px 11px;color:var(--g500);line-height:1;transition:background .15s}\u001b[39m\n\u001b[31m.fs-btn:active{background:var(--g100)}\u001b[39m\n\u001b[31m.fs-btn:disabled{color:var(--g300);cursor:default}\u001b[39m\n\u001b[31m.fs-label{font-size:11px;font-weight:700;color:var(--g500);padding:0 4px;pointer-events:none}\u001b[39m\n\u001b[31m/* Level 1 — Large (+15%) */\u001b[39m\n\u001b[31mbody.fs-1 .field label,body.fs-1 .card-title,body.fs-1 .set-lbl,body.fs-1 .set-sub,\u001b[39m\n\u001b[31mbody.fs-1 .hdr-title,body.fs-1 .hdr-sub,body.fs-1 .slbl,body.fs-1 .rev-lbl,body.fs-1 .rev-val,\u001b[39m\n\u001b[31mbody.fs-1 .rbtn,body.fs-1 .chip,body.fs-1 .btn-p,body.fs-1 .btn-s,body.fs-1 .btn-o,\u001b[39m\n\u001b[31mbody.fs-1 .bdialog-title,body.fs-1 .bdialog-sub,body.fs-1 .sub-name,body.fs-1 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-1 .pslot-lbl,body.fs-1 .bitem-title,body.fs-1 .pi-name,body.fs-1 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-1 .asc-name,body.fs-1 .new-btn,body.fs-1 .resume-btn,body.fs-1 .ardl-lbl,body.fs-1 .ardl-val{font-size:calc(1em * 1.15) !important}\u001b[39m\n\u001b[31m/* Level 2 — X-Large (+30%) */\u001b[39m\n\u001b[31mbody.fs-2 .field label,body.fs-2 .card-title,body.fs-2 .set-lbl,body.fs-2 .set-sub,\u001b[39m\n\u001b[31mbody.fs-2 .hdr-title,body.fs-2 .hdr-sub,body.fs-2 .slbl,body.fs-2 .rev-lbl,body.fs-2 .rev-val,\u001b[39m\n\u001b[31mbody.fs-2 .rbtn,body.fs-2 .chip,body.fs-2 .btn-p,body.fs-2 .btn-s,body.fs-2 .btn-o,\u001b[39m\n\u001b[31mbody.fs-2 .bdialog-title,body.fs-2 .bdialog-sub,body.fs-2 .sub-name,body.fs-2 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-2 .pslot-lbl,body.fs-2 .bitem-title,body.fs-2 .pi-name,body.fs-2 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-2 .asc-name,body.fs-2 .new-btn,body.fs-2 .resume-btn,body.fs-2 .ardl-lbl,body.fs-2 .ardl-val{font-size:calc(1em * 1.30) !important}\u001b[39m\n\u001b[31m/* Level 3 — XX-Large (+50%) */\u001b[39m\n\u001b[31mbody.fs-3 .field label,body.fs-3 .card-title,body.fs-3 .set-lbl,body.fs-3 .set-sub,\u001b[39m\n\u001b[31mbody.fs-3 .hdr-title,body.fs-3 .hdr-sub,body.fs-3 .slbl,body.fs-3 .rev-lbl,body.fs-3 .rev-val,\u001b[39m\n\u001b[31mbody.fs-3 .rbtn,body.fs-3 .chip,body.fs-3 .btn-p,body.fs-3 .btn-s,body.fs-3 .btn-o,\u001b[39m\n\u001b[31mbody.fs-3 .bdialog-title,body.fs-3 .bdialog-sub,body.fs-3 .sub-name,body.fs-3 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-3 .pslot-lbl,body.fs-3 .bitem-title,body.fs-3 .pi-name,body.fs-3 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-3 .asc-name,body.fs-3 .new-btn,body.fs-3 .resume-btn,body.fs-3 .ardl-lbl,body.fs-3 .ardl-val{font-size:calc(1em * 1.50) !important}\u001b[39m\n\u001b[31m/* Level 4 — Max (+70%) */\u001b[39m\n\u001b[31mbody.fs-4 .field label,body.fs-4 .card-title,body.fs-4 .set-lbl,body.fs-4 .set-sub,\u001b[39m\n\u001b[31mbody.fs-4 .hdr-title,body.fs-4 .hdr-sub,body.fs-4 .slbl,body.fs-4 .rev-lbl,body.fs-4 .rev-val,\u001b[39m\n\u001b[31mbody.fs-4 .rbtn,body.fs-4 .chip,body.fs-4 .btn-p,body.fs-4 .btn-s,body.fs-4 .btn-o,\u001b[39m\n\u001b[31mbody.fs-4 .bdialog-title,body.fs-4 .bdialog-sub,body.fs-4 .sub-name,body.fs-4 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-4 .pslot-lbl,body.fs-4 .bitem-title,body.fs-4 .pi-name,body.fs-4 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-4 .asc-name,body.fs-4 .new-btn,body.fs-4 .resume-btn,body.fs-4 .ardl-lbl,body.fs-4 .ardl-val{font-size:calc(1em * 1.70) !important}\u001b[39m\n\u001b[31m/* ── RECCE TILE ACTION BUTTONS ── */\u001b[39m\n\u001b[31m.rpt-btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid rgba(0,0,0,.06)}\u001b[39m\n\u001b[31m.rpt-btn{display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 14px;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;border:none;font-family:inherit;transition:background .15s,opacity .15s;flex:1;min-width:110px;letter-spacing:.1px;white-space:nowrap}\u001b[39m\n\u001b[31m.rpt-btn-report{background:#fff7ed;color:var(--or);border:1.5px solid var(--or)}\u001b[39m\n\u001b[31m.rpt-btn-report:active{background:#fed7aa}\u001b[39m\n\u001b[31m.rpt-btn-pdf{background:var(--g100);color:var(--g400);border:1.5px solid var(--g200)}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready{background:var(--or);color:#fff;border-color:transparent}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready:active{background:#ea6c00}\u001b[39m\n\u001b[31m/* PDF wait overlay */\u001b[39m\n\u001b[31m#pdf-wait-ov{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m</style>\u001b[39m\n\u001b[31m</head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<!-- PICKER OVERLAY -->\u001b[39m\n\u001b[31m<div class=\\\"povl\\\" id=\\\"povl\\\">\u001b[39m\n\u001b[31m  <div class=\\\"povl-hdr\\\">\u001b[39m\n\u001b[31m    <input class=\\\"psearch\\\" id=\\\"psearch\\\" type=\\\"text\\\" placeholder=\\\"Search store / दुकान खोजें…\\\" oninput=\\\"filterPicker(this.value)\\\" autocomplete=\\\"off\\\">\u001b[39m\n\u001b[31m    <button class=\\\"pcancel\\\" onclick=\\\"closePicker()\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"plist\\\" id=\\\"plist\\\"></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"app\\\">·\u001b[39m\n\u001b[31m<!-- HOME -->\u001b[39m\n\u001b[31m<div class=\\\"view active\\\" id=\\\"view-home\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hero\\\">\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;justify-content:space-between;align-items:center\\\">\u001b[39m\n\u001b[31m      <div><div class=\\\"hero-title\\\"><span class=\\\"en-txt\\\">Branding Recce</span><span class=\\\"hi-txt\\\">ब्रांडिंग रेकी</span></div><div class=\\\"hero-sub\\\" id=\\\"today-date\\\">—</div></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:6px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"lang-btn\\\" onclick=\\\"setLang(LANG==='en'?'hi':'en')\\\" id=\\\"lang-btn\\\" title=\\\"Switch language / भाषा बदलें\\\">EN | हि</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-hub\\\" onclick=\\\"goToHub()\\\">🏡 Hub</button>\u001b[39m\n\u001b[31m      <button class=\\\"icon-btn\\\" onclick=\\\"showView('settings')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12 15a3 3 0 100-6 3 3 0 000 6z\\\"/><path d=\\\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\\\"/></svg></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"hero-ubar\\\" id=\\\"recce-hero-ubar\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <span class=\\\"hero-uname\\\" id=\\\"recce-hero-name\\\"></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-logout\\\" onclick=\\\"recceLogout()\\\">Logout</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"stats\\\">\u001b[39m\n\u001b[31m      <div class=\\\"scard g\\\"><div class=\\\"snum\\\" id=\\\"stat-synced\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Synced</span><span class=\\\"hi-txt\\\">सिंक्ड</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard a\\\"><div class=\\\"snum\\\" id=\\\"stat-pending\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Pending</span><span class=\\\"hi-txt\\\">बाकी</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard\\\"><div class=\\\"snum\\\" id=\\\"stat-total\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Total</span><span class=\\\"hi-txt\\\">कुल</span></div></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <button class=\\\"new-btn\\\" onclick=\\\"startNewRecce()\\\"><svg width=\\\"20\\\" height=\\\"20\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">New Recce</span><span class=\\\"hi-txt\\\">नई रेकी</span></button>\u001b[39m\n\u001b[31m    <div id=\\\"resume-wrap\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"sh\\\"><span class=\\\"st\\\"><span class=\\\"en-txt\\\">Recent Submissions</span><span class=\\\"hi-txt\\\">हाल की सबमिशन</span></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"syncNow()\\\" id=\\\"sync-btn\\\" style=\\\"padding:7px 12px;font-size:12px\\\"><svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg><span class=\\\"en-txt\\\">Sync</span><span class=\\\"hi-txt\\\">सिंक</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"sub-list\\\"></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"srow\\\"><div><span class=\\\"sdot\\\" id=\\\"net-dot\\\"></span><span id=\\\"net-txt\\\"><span class=\\\"en-txt\\\">Checking…</span><span class=\\\"hi-txt\\\">जाँच…</span></span></div><span id=\\\"last-sync-txt\\\" style=\\\"font-size:11px\\\"><span class=\\\"en-txt\\\">Never synced</span><span class=\\\"hi-txt\\\">कभी सिंक नहीं</span></span></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- SETTINGS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-settings\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('home')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Settings</span><span class=\\\"hi-txt\\\">सेटिंग</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Brand List</span><span class=\\\"hi-txt\\\">ब्रांड सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Manage Brands</span><span class=\\\"hi-txt\\\">ब्रांड प्रबंधन</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">These appear in the brand dropdown and store picker. Add client brands as needed.</div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-manage-list\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-add-row\\\" style=\\\"display:none;gap:8px;align-items:center\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"brand-add-inp\\\" placeholder=\\\"Type brand name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addBrandToList()\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"addBrandToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Store Lists</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Supervisors can upload XLS/CSV store lists here. Updates sync to all devices via server.</span><span class=\\\"hi-txt\\\">सुपरवाइजर यहाँ XLS/CSV स्टोर सूची अपलोड कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m      <!-- Upload/Clear row — supervisor only -->\u001b[39m\n\u001b[31m      <div id=\\\"store-upload-row\\\" style=\\\"display:none;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;margin-top:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"document.getElementById('store-xl').click()\\\"><svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Add File</span><span class=\\\"hi-txt\\\">फ़ाइल जोड़ें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-d\\\" onclick=\\\"clearStoreList()\\\" style=\\\"font-size:12px\\\"><span class=\\\"en-txt\\\">Clear All Stores</span><span class=\\\"hi-txt\\\">सभी स्टोर हटाएं</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" id=\\\"store-push-btn\\\" onclick=\\\"pushStoresToServer()\\\" style=\\\"font-size:12px;display:none\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Push to Server</span><span class=\\\"hi-txt\\\">सर्वर पर पुश करें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"store-xl\\\" accept=\\\".xlsx,.xls,.csv\\\" onchange=\\\"handleStoreUpload(event)\\\">\u001b[39m\n\u001b[31m      <div id=\\\"store-count\\\" style=\\\"font-size:13px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"store-file-list\\\" style=\\\"margin-top:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Brand assignment dialog for files with no brand column -->\u001b[39m\n\u001b[31m    <div id=\\\"brand-assign-dialog\\\" style=\\\"display:none;margin-top:10px;padding:14px;background:#fff7ed;border:1.5px solid var(--or);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\">Which brand is this store list for?</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\" id=\\\"brand-assign-fname\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-assign-chips\\\" class=\\\"chip-grid\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"confirmBrandAssign()\\\" style=\\\"flex:2;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">Assign Brand</span><span class=\\\"hi-txt\\\">ब्रांड असाइन करें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"skipBrandAssign()\\\" style=\\\"flex:1;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">No Brand</span><span class=\\\"hi-txt\\\">कोई ब्रांड नहीं</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Server Store List URL (Admin)</span><span class=\\\"hi-txt\\\">सर्वर स्टोर सूची URL</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Admin pushes stores.json to any public URL. App auto-fetches on open and caches offline.</div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"srv-url\\\" placeholder=\\\"https://yourserver.com/stores.json\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"fetchServerStores()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Fetch Now</button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"saveServerUrl()\\\" style=\\\"padding:9px 14px;font-size:13px;width:auto\\\">Save URL</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Sync Endpoint</span><span class=\\\"hi-txt\\\">सिंक एंडपॉइंट</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Slides Generator</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Managed by admin. Deploy gas_slides.gs from /opt/slides-proxy/ to Google Apps Script and paste the URL here.</div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"slides-gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Not configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"slides-gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"saveSlidesGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Sheet Sync</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Legacy sync endpoint. Writes recce data to Google Sheet.</div>·\u001b[39m\n\u001b[31m      <!-- Locked state (default) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Endpoint configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Unlocked state (after admin login) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;align-items:center;gap:8px;margin-bottom:10px;padding:7px 12px;background:#dcfce7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          <span style=\\\"font-size:12px;color:#14532d;font-weight:600\\\">🔓 Admin mode active</span>\u001b[39m\n\u001b[31m          <button onclick=\\\"lockAdmin()\\\" style=\\\"margin-left:auto;background:none;border:none;color:#14532d;font-size:12px;cursor:pointer;font-weight:600\\\">Lock ×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"testEndpoint()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Test</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>·\u001b[39m\n\u001b[31m    <!-- Admin Login Modal -->\u001b[39m\n\u001b[31m    <div id=\\\"admin-login-modal\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m      <div style=\\\"background:#fff;border-radius:var(--r);padding:24px 20px;margin:20px;max-width:380px;width:100%;box-shadow:0 8px 32px rgba(0,0,0,.2)\\\">\u001b[39m\n\u001b[31m        <div style=\\\"font-size:17px;font-weight:700;color:var(--nv);margin-bottom:4px\\\">Admin Login</div>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:18px\\\">Enter admin password to unlock settings</div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m          <label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">Password</label>\u001b[39m\n\u001b[31m          <input type=\\\"password\\\" id=\\\"admin-pwd\\\" placeholder=\\\"Enter admin password\\\" style=\\\"width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px\\\" onkeydown=\\\"if(event.key==='Enter')verifyAdmin()\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div id=\\\"admin-error\\\" style=\\\"display:none;font-size:12px;color:var(--rd);margin-bottom:12px;padding:8px 12px;background:#fee2e2;border-radius:var(--rs)\\\">Incorrect password</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"verifyAdmin()\\\" style=\\\"flex:2;padding:13px\\\" id=\\\"admin-login-btn\\\">Login</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-s\\\" onclick=\\\"closeAdminLogin()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:14px;padding-top:14px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.4px;margin-bottom:8px\\\">Admin Password Config URL</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:8px\\\">URL to your admin.json file on server (contains hashed password)</div>\u001b[39m\n\u001b[31m          <input type=\\\"url\\\" id=\\\"admin-cfg-url\\\" placeholder=\\\"https://yourserver.com/admin.json\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px;margin-bottom:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveAdminCfgUrl()\\\" style=\\\"font-size:12px;padding:7px 12px;width:100%;justify-content:center\\\">Save Config URL</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Geolocation Stamp</span><span class=\\\"hi-txt\\\">जियोलोकेशन स्टैम्प</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;justify-content:space-between;gap:16px\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1\\\">\u001b[39m\n\u001b[31m          <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Stamp on Photos</span><span class=\\\"hi-txt\\\">फोटो पर स्टैम्प</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"set-sub\\\" style=\\\"margin-bottom:0\\\">Bakes GPS coordinates, store name and timestamp into every photo — visible in the image itself. Same as GPS Map Camera app. Default: On.</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"tog on\\\" id=\\\"geo-tog\\\" onclick=\\\"toggleGeoStamp()\\\"><div class=\\\"tog-knob\\\"></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"geo-status\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\">GPS not yet captured</div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Image Quality</span><span class=\\\"hi-txt\\\">फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Default Photo Quality</span><span class=\\\"hi-txt\\\">डिफ़ॉल्ट फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Applies to all photos — front view, inside view, branding, and additional. HD uses more storage and takes longer to sync on poor networks.</div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;gap:10px;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-compressed\\\" onclick=\\\"setImgQuality('compressed')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-compressed\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-compressed\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">Full Compression</span><span class=\\\"hi-txt\\\">पूर्ण कम्प्रेशन</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~150–200 KB · Max 1280px · Best for poor network</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-left:auto;font-size:11px;font-weight:700;color:var(--gn);background:#dcfce7;padding:3px 8px;border-radius:20px\\\"><span class=\\\"en-txt\\\">Recommended</span><span class=\\\"hi-txt\\\">अनुशंसित</span></div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-hd\\\" onclick=\\\"setImgQuality('hd')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-hd\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-hd\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">HD Quality</span><span class=\\\"hi-txt\\\">HD क्वालिटी</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~400–600 KB · Max 1920px · Better detail for print</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"q-current-badge\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Supervisor Config panel — shown only to supervisors via renderSupPanel() -->\u001b[39m\n\u001b[31m    <div id=\\\"sup-panel\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">🔐 Recce Access Config</span><span class=\\\"hi-txt\\\">🔐 रेकी एक्सेस कॉन्फ़िग</span></div>\u001b[39m\n\u001b[31m      <!-- Access mode — only H/P can change -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"mode-row\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Access Mode</span><span class=\\\"hi-txt\\\">एक्सेस मोड</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Public: any Hub user can submit Recces. Assigned: only Supervisors and Creators can access.</span><span class=\\\"hi-txt\\\">सार्वजनिक: कोई भी Hub यूजर। नियत: सिर्फ़ Supervisors और Creators।</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\" style=\\\"margin-bottom:8px;margin-top:8px\\\">\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-public\\\" onclick=\\\"setRecceMode('public')\\\"><span class=\\\"en-txt\\\">Public</span><span class=\\\"hi-txt\\\">सार्वजनिक</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-assigned\\\" onclick=\\\"setRecceMode('assigned')\\\"><span class=\\\"en-txt\\\">Assigned</span><span class=\\\"hi-txt\\\">नियत</span></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Supervisor list — view all + delete + create -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Supervisors</span><span class=\\\"hi-txt\\\">सुपरवाइजर</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can view all recces, delete with reason, and submit. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">सभी रेकी देख सकते हैं, कारण से हटा सकते हैं, और सबमिट कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"sup-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addSupervisor()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addSupervisor()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Creator list — creation only -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Creators</span><span class=\\\"hi-txt\\\">क्रिएटर्स</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can submit Recces only — no admin view or deletion rights. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">केवल रेकी सबमिट कर सकते हैं — एडमिन व्यू या डिलीट नहीं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"creator-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addCreator()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addCreator()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Client list — used for client portal scoping -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clients</span><span class=\\\"hi-txt\\\">क्लाइंट</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Names that appear as chips when submitting a recce. Add the brand or agency name (e.g. \\\"Marketing Vibe\\\"). These are used to scope what clients see in the Client Portal.</span><span class=\\\"hi-txt\\\">रेकी सबमिट करते समय दिखने वाले क्लाइंट नाम। ब्रांड या एजेंसी नाम जोड़ें।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-mgmt-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"client-add-inp\\\" placeholder=\\\"Client name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addClientToList()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addClientToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Sync to server — only H/P -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"cfg-sync-btn\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Sync Config to Server</span><span class=\\\"hi-txt\\\">सर्वर पर कॉन्फ़िग सिंक करें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Apply supervisor/creator/client lists and access mode to all devices.</span><span class=\\\"hi-txt\\\">सभी डिवाइस पर कॉन्फ़िग लागू करें।</span></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"syncCfgToServer()\\\" style=\\\"max-width:220px;font-size:14px;padding:12px;margin-top:8px\\\"><span class=\\\"en-txt\\\">Sync to Server</span><span class=\\\"hi-txt\\\">सर्वर पर सिंक करें</span></button>\u001b[39m\n\u001b[31m        <div id=\\\"cfg-sync-status\\\" style=\\\"margin-top:8px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Danger Zone</span><span class=\\\"hi-txt\\\">खतरनाक ज़ोन</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\"><div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clear All Local Data</span><span class=\\\"hi-txt\\\">सभी डेटा हटाएं</span></div><div class=\\\"set-sub\\\">Removes all submissions from this device.</div><button class=\\\"btn-d\\\" onclick=\\\"clearData()\\\" style=\\\"padding:9px 14px;font-size:13px\\\">Clear All</button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: STORE INFO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-store\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"exitForm()\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Details</span><span class=\\\"hi-txt\\\">दुकान विवरण</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 1 of 5</span><span class=\\\"hi-txt\\\">चरण 1 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:20%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Recce Info</span><span class=\\\"hi-txt\\\">रेकी जानकारी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Date of Recce</span><span class=\\\"hi-txt\\\">रेकी की तारीख</span> <span class=\\\"req\\\">*</span></label><input type=\\\"date\\\" id=\\\"f-date\\\" onchange=\\\"saveDraft()\\\" max=\\\"\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" id=\\\"campaign-field\\\">\u001b[39m\n\u001b[31m        <label><span class=\\\"en-txt\\\">Job / Campaign</span><span class=\\\"hi-txt\\\">जॉब / कैंपेन</span></label>\u001b[39m\n\u001b[31m        <select id=\\\"f-campaign-id\\\" onchange=\\\"onCampaignSelect()\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">Loading campaigns…</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <div id=\\\"campaign-notify-msg\\\" style=\\\"display:none;font-size:12px;color:#92400e;margin-top:6px;padding:8px 10px;background:#fef3c7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          ⚑ <span class=\\\"en-txt\\\">Recce will submit without a job ID. A notification will flag this for your supervisor to link it later.</span><span class=\\\"hi-txt\\\">रेकी बिना जॉब ID के सबमिट होगी। सुपरवाइजर बाद में लिंक करेगा।</span>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Store</span><span class=\\\"hi-txt\\\">दुकान</span> <span id=\\\"store-avail-tag\\\" style=\\\"font-size:11px;color:var(--g400);font-weight:400;text-transform:none;letter-spacing:0\\\"></span></div>·\u001b[39m\n\u001b[31m      <!-- When store is selected -->\u001b[39m\n\u001b[31m      <div id=\\\"store-selected\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"store-card\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:start;justify-content:space-between;gap:8px\\\">\u001b[39m\n\u001b[31m            <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m              <div class=\\\"store-card-name\\\" id=\\\"sc-name\\\">—</div>\u001b[39m\n\u001b[31m              <div style=\\\"display:flex;align-items:center;gap:6px;margin-top:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m                <span class=\\\"brand-tag\\\" id=\\\"sc-brand\\\">—</span>\u001b[39m\n\u001b[31m                <span class=\\\"last-chip\\\" id=\\\"sc-last\\\" style=\\\"display:none\\\">—</span>\u001b[39m\n\u001b[31m              </div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            <button class=\\\"store-card-change\\\" onclick=\\\"openPicker()\\\"><span class=\\\"en-txt\\\">Change ›</span><span class=\\\"hi-txt\\\">बदलें ›</span></button>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <!-- All fields from Excel shown here -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-details\\\" style=\\\"margin-top:10px;display:flex;flex-direction:column;gap:4px\\\"></div>\u001b[39m\n\u001b[31m          <!-- Missing required fields — editable inline -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-missing\\\" style=\\\"display:none;margin-top:12px;padding-top:12px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m            <div style=\\\"font-size:11px;font-weight:700;color:var(--rd);text-transform:uppercase;letter-spacing:.4px;margin-bottom:10px\\\">⚠ Please complete missing fields</div>\u001b[39m\n\u001b[31m            <div id=\\\"sc-missing-fields\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <!-- Brand selector — shown when store has no brand -->\u001b[39m\n\u001b[31m        <div id=\\\"brand-selector\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\"><span class=\\\"en-txt\\\">Select Brand</span><span class=\\\"hi-txt\\\">ब्रांड चुनें</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\">This store has no brand in the list — select one:</div>\u001b[39m\n\u001b[31m          <div id=\\\"brand-chips\\\" class=\\\"chip-grid\\\"></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Picker trigger (shown when stores loaded) -->\u001b[39m\n\u001b[31m      <div id=\\\"pick-trigger-wrap\\\">\u001b[39m\n\u001b[31m        <div class=\\\"pick-trigger\\\" onclick=\\\"openPicker()\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:center;gap:10px\\\">\u001b[39m\n\u001b[31m            <span style=\\\"font-size:20px\\\">🏪</span>\u001b[39m\n\u001b[31m            <div>\u001b[39m\n\u001b[31m              <div style=\\\"font-size:15px;font-weight:700;color:var(--or)\\\"><span class=\\\"en-txt\\\">Select Store from List</span><span class=\\\"hi-txt\\\">सूची से दुकान चुनें</span></div>\u001b[39m\n\u001b[31m              <div id=\\\"store-avail-count\\\" style=\\\"font-size:12px;font-weight:400;color:var(--am);margin-top:1px\\\"><span class=\\\"en-txt\\\">Tap to browse stores</span><span class=\\\"hi-txt\\\">दुकान खोजने के लिए दबाएं</span></div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual / new store toggle -->\u001b[39m\n\u001b[31m      <div class=\\\"manual-toggle\\\" id=\\\"manual-toggle\\\" onclick=\\\"toggleManual()\\\">\u001b[39m\n\u001b[31m        <svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\" id=\\\"mt-icon\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg>\u001b[39m\n\u001b[31m        <span id=\\\"mt-label\\\"><span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span></span>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual fields -->\u001b[39m\n\u001b[31m      <div id=\\\"manual-fields\\\" style=\\\"display:none;margin-top:14px\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\" style=\\\"margin-bottom:14px\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <select id=\\\"f-brand\\\" onchange=\\\"onManualBrandChange()\\\">\u001b[39m\n\u001b[31m            <option value=\\\"\\\">Select brand</option>\u001b[39m\n\u001b[31m          </select>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span> <span class=\\\"req\\\">*</span></label><input type=\\\"text\\\" id=\\\"f-store\\\" placeholder=\\\"Enter store name\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\">\u001b[39m\n\u001b[31m          <label><span class=\\\"en-txt\\\">Store Address</span><span class=\\\"hi-txt\\\">दुकान का पता</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <textarea id=\\\"f-addr\\\" rows=\\\"2\\\" placeholder=\\\"Full address\\\" onchange=\\\"saveDraft()\\\"></textarea>\u001b[39m\n\u001b[31m          <div class=\\\"gps-row\\\">\u001b[39m\n\u001b[31m            <button class=\\\"gps-btn\\\" onclick=\\\"captureGPS()\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\"/><path d=\\\"M12 2v3M12 19v3M2 12h3M19 12h3\\\"/></svg><span class=\\\"en-txt\\\">Capture GPS</span><span class=\\\"hi-txt\\\">GPS लें</span></button>\u001b[39m\n\u001b[31m            <span id=\\\"gps-status\\\" style=\\\"font-size:12px;color:var(--g500);align-self:center\\\"></span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Mobile No.</span><span class=\\\"hi-txt\\\">मोबाइल नंबर</span></label><input type=\\\"tel\\\" id=\\\"f-mobile\\\" placeholder=\\\"10-digit number\\\" maxlength=\\\"10\\\" inputmode=\\\"numeric\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Client card -->\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Client</span><span class=\\\"hi-txt\\\">क्लाइंट</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\"><span class=\\\"en-txt\\\">Select who this recce is for. Defaults to brand — change if work came via an agency.</span><span class=\\\"hi-txt\\\">यह रेकी किसके लिए है चुनें। ब्रांड से डिफ़ॉल्ट — एजेंसी के ज़रिए हो तो बदलें।</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"cl-chip-grid\\\" id=\\\"client-chips\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"client-other-wrap\\\" style=\\\"display:none;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"f-client-other\\\" placeholder=\\\"Type client name\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" oninput=\\\"onClientOtherInput()\\\">\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-p\\\" onclick=\\\"step2()\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: PHOTOS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-photos\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-store')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Photos</span><span class=\\\"hi-txt\\\">दुकान की फोटो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 2 of 5</span><span class=\\\"hi-txt\\\">चरण 2 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:40%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Front View</span><span class=\\\"hi-txt\\\">आगे का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(min 1, max 3)</span><span class=\\\"cnt-badge gray\\\" id=\\\"front-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"front-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-front\\\" onclick=\\\"addPhoto('front')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Front Photo</span><span class=\\\"hi-txt\\\">आगे की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Inside View</span><span class=\\\"hi-txt\\\">अंदर का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 5)</span><span class=\\\"cnt-badge gray\\\" id=\\\"inside-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"inside-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-inside\\\" onclick=\\\"addPhoto('inside')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Inside Photo</span><span class=\\\"hi-txt\\\">अंदर की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-store')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step3()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: VIDEO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-video\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-photos')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Recce Video</span><span class=\\\"hi-txt\\\">रेकी वीडियो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 3 of 5</span><span class=\\\"hi-txt\\\">चरण 3 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:60%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Video</span><span class=\\\"hi-txt\\\">वीडियो</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Recce video available?</span><span class=\\\"hi-txt\\\">रेकी वीडियो है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"vid-yes\\\" onclick=\\\"setVideo(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"vid-no\\\" onclick=\\\"setVideo(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"vid-sec\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Upload Video</span><span class=\\\"hi-txt\\\">वीडियो अपलोड करें</span></label>\u001b[39m\n\u001b[31m          <div class=\\\"pslot\\\" id=\\\"vid-slot\\\" onclick=\\\"document.getElementById('vid-inp').click()\\\"><div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div></div>\u001b[39m\n\u001b[31m          <input type=\\\"file\\\" id=\\\"vid-inp\\\" accept=\\\"video/*\\\" onchange=\\\"handleVideo(event)\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Video Comments</span><span class=\\\"hi-txt\\\">वीडियो टिप्पणी</span></label><input type=\\\"text\\\" id=\\\"f-vid-cmt\\\" placeholder=\\\"Optional\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-photos')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step4()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: BRANDING -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-branding\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-video')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Branding</span><span class=\\\"hi-txt\\\">ब्रांडिंग</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 4 of 5</span><span class=\\\"hi-txt\\\">चरण 4 / 5</span></div></div></div>\u001b[39m\n\u001b[31m    <span id=\\\"br-hdr-badge\\\" style=\\\"background:rgba(255,255,255,.2);color:#fff;font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px\\\"><span class=\\\"en-txt\\\">0 items</span><span class=\\\"hi-txt\\\">0 आइटम</span></span>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:80%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Branding Space</span><span class=\\\"hi-txt\\\">ब्रांडिंग स्थान</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Space available?</span><span class=\\\"hi-txt\\\">जगह उपलब्ध है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"br-yes\\\" onclick=\\\"setBranding(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"br-no\\\" onclick=\\\"setBranding(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"branding-lock-banner\\\" style=\\\"display:none;background:#fef3c7;border:1.5px solid #f59e0b;border-radius:10px;padding:12px 14px;margin-bottom:10px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:700;color:#92400e\\\">Client approval exists — branding locked</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:#78350f;margin-top:4px\\\"><span class=\\\"en-txt\\\">The client has reviewed this recce. Create a new recce to revise branding items.</span><span class=\\\"hi-txt\\\">क्लाइंट ने रेकी की समीक्षा की है। बदलाव के लिए नई रेकी बनाएं।</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"branding-override-wrap\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m        <button onclick=\\\"unlockBrandingOverride()\\\" style=\\\"background:#f59e0b;color:#000;border:none;border-radius:8px;padding:8px 14px;font-size:12px;font-weight:700;cursor:pointer\\\">Override Edit (H&amp;P only)</button>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:11px;color:#92400e;margin-top:5px\\\">Use only when client has verbally confirmed and app needs correction.</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"br-items\\\"></div>\u001b[39m\n\u001b[31m    <div id=\\\"br-add\\\" style=\\\"display:none;margin-bottom:80px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"addBranding()\\\" style=\\\"width:100%;justify-content:center\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Another Branding Item</span><span class=\\\"hi-txt\\\">एक और ब्रांडिंग जोड़ें</span></button>\u001b[39m\n\u001b[31m      <div style=\\\"text-align:center;font-size:12px;color:var(--g400);margin-top:8px\\\"><span class=\\\"en-txt\\\">Tap Continue below when done adding items</span><span class=\\\"hi-txt\\\">सभी आइटम जोड़ने के बाद आगे दबाएं</span></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-video')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step5()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: ADDITIONAL + SUBMIT -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-additional\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-branding')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Submit</span><span class=\\\"hi-txt\\\">सबमिट</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 5 of 5</span><span class=\\\"hi-txt\\\">चरण 5 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:100%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Mandatory Document</span><span class=\\\"hi-txt\\\">अनिवार्य दस्तावेज़</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"pslot\\\" id=\\\"doc-slot\\\" onclick=\\\"document.getElementById('doc-inp').click()\\\"><div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div></div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"doc-inp\\\" accept=\\\"image/*,.pdf\\\" onchange=\\\"handleDoc(event)\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Additional Photos</span><span class=\\\"hi-txt\\\">अतिरिक्त फोटो</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 8)</span><span class=\\\"cnt-badge gray\\\" id=\\\"addl-badge\\\">0 / 8</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"add-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-addl\\\" onclick=\\\"addAdditional()\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\"><div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Review</span><span class=\\\"hi-txt\\\">समीक्षा</span></div><div id=\\\"rev-body\\\"></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-branding')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"submitRecce()\\\" id=\\\"sub-btn\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Submit Recce ✓</span><span class=\\\"hi-txt\\\">रेकी सबमिट करें ✓</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- ANNOTATION MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"annot-modal\\\" id=\\\"annot-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"annot-bar\\\">\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Draw:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"at-rect\\\"    onclick=\\\"setATool('rect')\\\">▭ Rect</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-ellipse\\\" onclick=\\\"setATool('ellipse')\\\">◯ Ellipse</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-line\\\"    onclick=\\\"setATool('line')\\\">╱ Line</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-arrow\\\"   onclick=\\\"setATool('arrow')\\\">↗ Arrow</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-free\\\"    onclick=\\\"setATool('free')\\\">✏ Free</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool sel-on\\\" id=\\\"at-move\\\" onclick=\\\"setATool('move')\\\" style=\\\"margin-left:4px\\\">⊹ Move</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Color:</span>\u001b[39m\n\u001b[31m      <div class=\\\"acolor on\\\" id=\\\"ac-or\\\" style=\\\"background:#f97316\\\" onclick=\\\"setAColor('#f97316')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-rd\\\" style=\\\"background:#ef4444\\\" onclick=\\\"setAColor('#ef4444')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-wh\\\" style=\\\"background:#ffffff\\\" onclick=\\\"setAColor('#ffffff')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-yw\\\" style=\\\"background:#facc15\\\" onclick=\\\"setAColor('#facc15')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-gn\\\" style=\\\"background:#22c55e\\\" onclick=\\\"setAColor('#22c55e')\\\"></div>\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Width:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-2\\\" onclick=\\\"setAWidth(2)\\\" style=\\\"padding:5px 8px\\\">Thin</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"aw-4\\\" onclick=\\\"setAWidth(4)\\\" style=\\\"padding:5px 8px\\\">Med</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-7\\\" onclick=\\\"setAWidth(7)\\\" style=\\\"padding:5px 8px\\\">Thick</button>\u001b[39m\n\u001b[31m      <div style=\\\"flex:1\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"undoAnnot()\\\">↩</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"clearAnnot()\\\">✕</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"annot-sel-info\\\" style=\\\"display:none;font-size:11px;color:#facc15;padding:4px 0 2px\\\">\u001b[39m\n\u001b[31m      Shape selected — drag to move · drag corners to resize · tap elsewhere to deselect\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-cvs-wrap\\\"><canvas id=\\\"annot-cvs\\\"></canvas></div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-foot\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-s\\\" onclick=\\\"skipAnnot()\\\" style=\\\"flex:1;padding:12px;font-size:14px\\\"><span class=\\\"en-txt\\\">Skip markup</span><span class=\\\"hi-txt\\\">मार्कअप छोड़ें</span></button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" onclick=\\\"saveAnnot()\\\" style=\\\"flex:2;padding:12px\\\"><span class=\\\"en-txt\\\">Done — Save ✓</span><span class=\\\"hi-txt\\\">हो गया — सेव करें ✓</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EXIT DIALOG -->\u001b[39m\n\u001b[31m<!-- MODAL: Link Job to Recce (supervisor only) -->\u001b[39m\n\u001b[31m<div id=\\\"modal-link-job\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m  <div style=\\\"background:#fff;border-radius:14px;padding:20px;width:90%;max-width:380px;display:flex;flex-direction:column;gap:12px;box-shadow:0 8px 32px rgba(0,0,0,.35)\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:15px;font-weight:700;color:#1e293b\\\">&#x1F517; Link Job to Recce</div>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-store\\\" style=\\\"font-size:13px;color:#64748b\\\"></div>\u001b[39m\n\u001b[31m    <select id=\\\"link-job-sel\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m      <option value=\\\"\\\">&#x2014; Select campaign &#x2014;</option>\u001b[39m\n\u001b[31m    </select>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-err\\\" style=\\\"font-size:12px;color:#ef4444;min-height:14px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"closeLinkJobModal()\\\" style=\\\"flex:1;padding:12px;border:1px solid #cbd5e1;border-radius:8px;cursor:pointer;background:#f8fafc;font-size:14px\\\">Cancel</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"saveLinkJob()\\\" style=\\\"flex:2;padding:12px;background:#f59e0b;color:#000;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:700\\\">&#x1F517; Link Job</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"exit-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Exit Recce?</span><span class=\\\"hi-txt\\\">रेकी से बाहर?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Your progress and photos will be saved as a draft. Resume anytime from the home screen.</span><span class=\\\"hi-txt\\\">आपकी प्रगति और फोटो ड्राफ्ट में सेव होंगी। होम स्क्रीन से कभी भी जारी रखें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"exitSaveAndLeave()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">💾 Save Draft & Exit</span><span class=\\\"hi-txt\\\">💾 ड्राफ्ट सेव करें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-d\\\" onclick=\\\"exitDiscard()\\\" style=\\\"flex:1;padding:13px;font-size:13px\\\"><span class=\\\"en-txt\\\">Discard</span><span class=\\\"hi-txt\\\">हटाएं</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"exitCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">← Continue Recce</span><span class=\\\"hi-txt\\\">← रेकी जारी रखें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- PHOTO SOURCE PICKER -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"photo-src-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Camera photos get GPS stamp baked in. Gallery photos are added without stamp.</span><span class=\\\"hi-txt\\\">कैमरा फोटो में GPS स्टैम्प लगती है। गैलरी फोटो में नहीं।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"photoSrcCamera()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">📷 Use Camera</span><span class=\\\"hi-txt\\\">📷 कैमरा</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">GPS stamp applied</span><span class=\\\"hi-txt\\\">GPS स्टैम्प लगेगी</span></span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"photoSrcGallery()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">🖼 Choose from Gallery</span><span class=\\\"hi-txt\\\">🖼 गैलरी से चुनें</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">No stamp</span><span class=\\\"hi-txt\\\">स्टैम्प नहीं</span></span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"photoSrcCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- STORE PREVIEW DIALOG -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"store-preview-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:80vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"store-preview-title\\\"><span class=\\\"en-txt\\\">Preview Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची का प्रीव्यू</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Review before adding to your store list:</span><span class=\\\"hi-txt\\\">जोड़ने से पहले जाँचें:</span></div>\u001b[39m\n\u001b[31m    <div style=\\\"overflow-x:auto;margin-bottom:14px\\\">\u001b[39m\n\u001b[31m      <table style=\\\"width:100%;border-collapse:collapse;font-size:12px\\\">\u001b[39m\n\u001b[31m        <thead><tr style=\\\"background:var(--nv);color:#fff\\\">\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Address</span><span class=\\\"hi-txt\\\">पता</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Mobile</span><span class=\\\"hi-txt\\\">मोबाइल</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span></th>\u001b[39m\n\u001b[31m        </tr></thead>\u001b[39m\n\u001b[31m        <tbody id=\\\"store-preview-body\\\"></tbody>\u001b[39m\n\u001b[31m      </table>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"confirmStorePreview()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">✓ Confirm & Add Stores</span><span class=\\\"hi-txt\\\">✓ स्टोर जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"cancelStorePreview()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BOTTOM DIALOG (branding additional photo prompt) -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"bdialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add reference photos?</span><span class=\\\"hi-txt\\\">संदर्भ फोटो जोड़ें?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Add extra photos for this branding item for future reference.</span><span class=\\\"hi-txt\\\">इस ब्रांडिंग आइटम के लिए अतिरिक्त फोटो जोड़ें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"bdialogYes()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">Yes, add photos</span><span class=\\\"hi-txt\\\">हाँ, जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"bdialogNo()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Skip</span><span class=\\\"hi-txt\\\">छोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- DELETE REASON MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"delete-reason-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"padding-bottom:28px;max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">🗑 Delete Recce</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"del-modal-sub\\\">Select reason for deletion:</div>\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-wrong\\\" onclick=\\\"selectDeleteReason('wrong')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">❌</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Wrong</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Incorrect store / submission error</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-duplicate\\\" onclick=\\\"selectDeleteReason('duplicate')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">📋</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Duplicate</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Same store submitted more than once</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt danger\\\" id=\\\"reason-test\\\" onclick=\\\"selectDeleteReason('test')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">⚠️</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Test Recce</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:#9a3412;margin-top:2px\\\">Permanently deleted — no audit trail</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p no-reason\\\" id=\\\"del-confirm-btn\\\" onclick=\\\"confirmDelete()\\\" style=\\\"flex:2;padding:13px;background:var(--rd)\\\">Delete</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"closeDeleteModal()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EDIT REQUEST MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"edit-req-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Request Edit</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"er-store-name\\\" style=\\\"font-weight:600;color:var(--nv);margin-bottom:4px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:14px\\\">Add a note for the creator (optional)</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m      <textarea id=\\\"er-comment\\\" placeholder=\\\"e.g. Please re-check store address and re-upload front photo\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;color:var(--nv);resize:vertical;min-height:80px;background:#fff\\\"></textarea>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button id=\\\"er-assign-btn\\\" class=\\\"btn-p\\\" onclick=\\\"assignEditToCreator()\\\" style=\\\"padding:14px\\\">👤 Assign to Creator</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"supervisorEditMyself()\\\" style=\\\"padding:14px\\\">✏ Edit Myself</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"closeEditRequestModal()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BRAND EDIT MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"brand-edit-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Edit Brand</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Brand Name <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"text\\\" id=\\\"be-name\\\" placeholder=\\\"e.g. PHILIPS\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:600;text-transform:uppercase\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Logo URL <span style=\\\"font-size:11px;font-weight:400;color:var(--g400)\\\">(optional)</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"url\\\" id=\\\"be-logo\\\" placeholder=\\\"https://…/logo.svg\\\" oninput=\\\"previewBrandLogo()\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px\\\">\u001b[39m\n\u001b[31m      <div id=\\\"be-logo-preview\\\" style=\\\"margin-top:8px;min-height:36px;display:flex;align-items:center;gap:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"be-cascade-info\\\" style=\\\"display:none;font-size:12px;color:var(--g500);padding:8px 12px;background:var(--g50);border-radius:var(--rs);margin-bottom:12px\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"saveBrandEdit()\\\" style=\\\"padding:14px\\\">Save</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"closeBrandEditModal()\\\" style=\\\"width:100%;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FONT SIZE WIDGET -->\u001b[39m\n\u001b[31m<div class=\\\"fs-widget\\\" id=\\\"fs-widget\\\">\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-dec\\\" onclick=\\\"changeFontSize(-1)\\\" title=\\\"Decrease font size\\\" aria-label=\\\"Decrease font size\\\">A<sup style=\\\"font-size:9px\\\">−</sup></button>\u001b[39m\n\u001b[31m  <span class=\\\"fs-label\\\" id=\\\"fs-lbl\\\">A</span>\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-inc\\\" onclick=\\\"changeFontSize(1)\\\" title=\\\"Increase font size\\\" aria-label=\\\"Increase font size\\\"><strong>A</strong><sup style=\\\"font-size:9px\\\">+</sup></button>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"upd-banner\\\" id=\\\"upd-banner\\\">\u001b[39m\n\u001b[31m  <span style=\\\"font-size:13px;font-weight:600;line-height:1.4\\\"><span class=\\\"en-txt\\\">✓ App updated to latest version</span><span class=\\\"hi-txt\\\">✓ ऐप नया संस्करण अपडेट हुआ</span></span>\u001b[39m\n\u001b[31m  <button class=\\\"upd-banner-ok\\\" onclick=\\\"dismissUpdateBanner()\\\"><span class=\\\"en-txt\\\">OK</span><span class=\\\"hi-txt\\\">ठीक है</span></button>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m<div class=\\\"toast\\\" id=\\\"toast\\\"></div>\u001b[39m\n\u001b[31m<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js\\\"></script>\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m// LANGUAGE\u001b[39m\n\u001b[31mlet LANG = localStorage.getItem('recce-lang') || 'en';\u001b[39m\n\u001b[31mfunction setLang(l) {\u001b[39m\n\u001b[31m  LANG = l;\u001b[39m\n\u001b[31m  localStorage.setItem('recce-lang', l);\u001b[39m\n\u001b[31m  document.body.classList.toggle('lang-hi', l === 'hi');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction t(en, hi) { return LANG === 'hi' ? hi : en; }·\u001b[39m\n\u001b[31m// FONT SIZE\u001b[39m\n\u001b[31mlet FS_LEVEL = parseInt(localStorage.getItem('recce-fs') || '0', 10);\u001b[39m\n\u001b[31mconst FS_LABELS = ['A', 'A+', 'A++', 'A+++', 'A++++'];\u001b[39m\n\u001b[31mfunction applyFontSize() {\u001b[39m\n\u001b[31m  document.body.classList.remove('fs-0', 'fs-1', 'fs-2');\u001b[39m\n\u001b[31m  if (FS_LEVEL > 0) document.body.classList.add('fs-' + FS_LEVEL);\u001b[39m\n\u001b[31m  const lbl = document.getElementById('fs-lbl');\u001b[39m\n\u001b[31m  if (lbl) lbl.textContent = FS_LABELS[FS_LEVEL];\u001b[39m\n\u001b[31m  const dec = document.getElementById('fs-dec');\u001b[39m\n\u001b[31m  const inc = document.getElementById('fs-inc');\u001b[39m\n\u001b[31m  if (dec) dec.disabled = FS_LEVEL === 0;\u001b[39m\n\u001b[31m  if (inc) inc.disabled = FS_LEVEL === 4;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction changeFontSize(delta) {\u001b[39m\n\u001b[31m  FS_LEVEL = Math.min(4, Math.max(0, FS_LEVEL + delta));\u001b[39m\n\u001b[31m  localStorage.setItem('recce-fs', FS_LEVEL);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Hub auth gate\u001b[39m\n\u001b[31m(function() {\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (!s || !s.loginAt || Date.now() - new Date(s.loginAt).getTime() > 12 * 3600 * 1000) {\u001b[39m\n\u001b[31m      window.location.replace('/hub/');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) { window.location.replace('/hub/'); }\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31m// STATE\u001b[39m\n\u001b[31mlet F={},frontPhotos=[],insidePhotos=[],addlPhotos=[],brandings=[];\u001b[39m\n\u001b[31mlet videoBlob=null,submissionDoc=null,_docExistingUrl=null,gpsCoords=null;\u001b[39m\n\u001b[31mlet stores=[],selectedStore=null,manualMode=false,DB;\u001b[39m\n\u001b[31mlet imgQuality='compressed'; // 'compressed' | 'hd'\u001b[39m\n\u001b[31mlet geoStampEnabled=true;    // stamp GPS+timestamp on every photo\u001b[39m\n\u001b[31mlet brands=['PHILIPS']; // editable brand list\u001b[39m\n\u001b[31mlet _brandLogos={};   // name → logo_url, loaded from DB\u001b[39m\n\u001b[31mlet _selectedClient=''; // currently selected client chip value\u001b[39m\n\u001b[31mlet _clientOtherMode=false; // true when \\\"Other\\\" chip selected\u001b[39m\n\u001b[31mconst BTYPE=['Glow Sign Board','Inshop Branding','ACP Board','One Way Vision','Fabric Board','Lollypop','Non Lit Flex','Double Side GSB','Clip on Board','Translit','Vinyl Printing','Roll up Standee','Sunboard Standee'];\u001b[39m\n\u001b[31mconst CACHE_VER='recce-v37'; // campaign dropdown + pending job link tab·\u001b[39m\n\u001b[31m// DB\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',3);r.onupgradeneeded=e=>{const d=e.target.result;['subs','cfg','draft'].forEach(s=>{if(!d.objectStoreNames.contains(s))d.createObjectStore(s,{keyPath:'k'||'id'});});if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);});}\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',4);r.onupgradeneeded=e=>{const d=e.target.result;if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);})}\u001b[39m\n\u001b[31mfunction dbGet(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).get(k);r.onsuccess=()=>res(r.result);r.onerror=()=>res(null);}catch{res(null)}})}\u001b[39m\n\u001b[31mfunction dbPut(s,v){return new Promise((res,rej)=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).put(v);r.onsuccess=()=>res();r.onerror=()=>rej();}catch(e){rej(e)}})}\u001b[39m\n\u001b[31mfunction dbAll(s){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).getAll();r.onsuccess=()=>res(r.result);r.onerror=()=>res([]);}catch{res([])}})}\u001b[39m\n\u001b[31mfunction dbDel(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).delete(k);r.onsuccess=()=>res();r.onerror=()=>res();}catch{res()}})}\u001b[39m\n\u001b[31masync function cfg(k,v){if(v===undefined){const r=await dbGet('cfg',k);return r?r.v:null;}await dbPut('cfg',{k,v});}·\u001b[39m\n\u001b[31m// COMPRESS — respects imgQuality setting\u001b[39m\n\u001b[31mfunction compress(file, maxPxOverride, qOverride){\u001b[39m\n\u001b[31m  const maxPx = maxPxOverride || (imgQuality==='hd' ? 1920 : 1280);\u001b[39m\n\u001b[31m  const q     = qOverride     || (imgQuality==='hd' ? 0.90 : 0.78);\u001b[39m\n\u001b[31m  return new Promise(res=>{const img=new Image(),url=URL.createObjectURL(file);img.onload=()=>{const sc=Math.min(1,maxPx/Math.max(img.width,img.height));const c=document.createElement('canvas');c.width=Math.round(img.width*sc);c.height=Math.round(img.height*sc);c.getContext('2d').drawImage(img,0,0,c.width,c.height);URL.revokeObjectURL(url);c.toBlob(b=>res(b),'image/jpeg',q);};img.onerror=()=>{URL.revokeObjectURL(url);res(file)};img.src=url;});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction b64(blob){return new Promise(res=>{const r=new FileReader();r.onload=()=>res(r.result);r.readAsDataURL(blob)})}\u001b[39m\n\u001b[31mfunction fmtSz(b){if(b<1024)return b+'B';if(b<1048576)return(b/1024).toFixed(0)+'KB';return(b/1048576).toFixed(1)+'MB'}·\u001b[39m\n\u001b[31m// STORE LIST\u001b[39m\n\u001b[31mlet _storeFiles=[]; // track uploaded files {name, brand, count}\u001b[39m\n\u001b[31mlet _pendingParse=null; // parsed rows waiting for brand assignment·\u001b[39m\n\u001b[31mfunction parseStoreRow(row, keyFn){\u001b[39m\n\u001b[31m  const v=k=>{\u001b[39m\n\u001b[31m    // Try exact match first, then partial\u001b[39m\n\u001b[31m    const exactKey=Object.keys(row||{}).find(hk=>hk.toLowerCase()===k);\u001b[39m\n\u001b[31m    const partKey=Object.keys(row||{}).find(hk=>hk.toLowerCase().includes(k));\u001b[39m\n\u001b[31m    const useKey=exactKey||partKey;\u001b[39m\n\u001b[31m    if(useKey)return row[useKey]!=null?row[useKey].toString().trim():'';\u001b[39m\n\u001b[31m    // CSV path: keyFn provides value directly\u001b[39m\n\u001b[31m    const col=keyFn(k);return col!=null?col.toString().trim():'';\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const name    = v('sub dealer name')||v('sub dealer')||v('dealer name')||v('store name')||v('store')||v('name');\u001b[39m\n\u001b[31m  const address = v('address')||v('addr')||v('location')||v('area');\u001b[39m\n\u001b[31m  // Contact Detail often stored as a number — toString handles it\u001b[39m\n\u001b[31m  const rawMob  = v('contact detail')||v('contact no.')||v('contact no')||v('mobile no')||v('mobile')||v('phone')||v('mob')||v('contact');\u001b[39m\n\u001b[31m  const mobile  = rawMob.replace(/\\\\D/g,'').slice(-10);\u001b[39m\n\u001b[31m  // Brand: EXACT match only — \\\"Brand\\\" or \\\"Brand Name\\\" columns\u001b[39m\n\u001b[31m  // Partial match is intentionally avoided here because \\\"Inshop Branding\\\" contains \\\"brand\\\"\u001b[39m\n\u001b[31m  const brandKey=Object.keys(row||{}).find(hk=>{\u001b[39m\n\u001b[31m    const lk=hk.toLowerCase().trim();\u001b[39m\n\u001b[31m    return lk==='brand'||lk==='brand name'||lk==='brand_name'||lk==='brandname';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const brand=brandKey?(row[brandKey]||'').toString().trim().toUpperCase():'';\u001b[39m\n\u001b[31m  const distName= v('dist name')||v('distributor name')||v('distributor')||v('dist')||v('territory')||v('tsm')||v('asm');\u001b[39m\n\u001b[31m  const city    = v('city')||v('district')||v('town');\u001b[39m\n\u001b[31m  const sales   = v('2025 full year')||v('2025')||v('full year sales')||v('fy25')||v('sales');\u001b[39m\n\u001b[31m  const proj    = v('2026 projection')||v('2026')||v('projection')||v('fy26')||v('target');\u001b[39m\n\u001b[31m  const glowSign= v('glow sign')||v('glow');\u001b[39m\n\u001b[31m  const inshop  = v('inshop branding')||v('inshop')||v('in-shop')||v('in shop');\u001b[39m\n\u001b[31m  return {name, brand, address, mobile, distName, city, sales, proj, glowSign, inshop};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction dedupeStores(list){\u001b[39m\n\u001b[31m  const seen=new Map();\u001b[39m\n\u001b[31m  list.forEach(s=>{\u001b[39m\n\u001b[31m    // Include address in key — same store name at different locations = different stores\u001b[39m\n\u001b[31m    const key=(s.name.toLowerCase().trim())+'__'+(s.brand||'').toLowerCase()\u001b[39m\n\u001b[31m              +'__'+(s.address||'').toLowerCase().trim().slice(0,30);\u001b[39m\n\u001b[31m    if(!seen.has(key))seen.set(key,s);\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // True duplicate — merge missing fields from second record\u001b[39m\n\u001b[31m      const ex=seen.get(key);\u001b[39m\n\u001b[31m      Object.keys(s).forEach(k=>{ if(!ex[k]&&s[k])ex[k]=s[k]; });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  return Array.from(seen.values());\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderStoreFileList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-file-list');if(!el)return;\u001b[39m\n\u001b[31m  if(!_storeFiles.length){el.innerHTML='';return;}\u001b[39m\n\u001b[31m  el.innerHTML=_storeFiles.map((f,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:5px;font-size:12px\\\">\u001b[39m\n\u001b[31m      <div>\u001b[39m\n\u001b[31m        <span style=\\\"font-weight:600;color:var(--nv)\\\">${f.name}</span>\u001b[39m\n\u001b[31m        <span style=\\\"color:var(--g500);margin-left:6px\\\">${f.count} stores</span>\u001b[39m\n\u001b[31m        ${f.brand?`<span style=\\\"background:var(--nv);color:#fff;font-size:10px;font-weight:700;padding:1px 7px;border-radius:20px;margin-left:5px\\\">${f.brand}</span>`:'<span style=\\\"background:var(--g300);color:var(--g600);font-size:10px;padding:1px 7px;border-radius:20px;margin-left:5px\\\">Mixed brands</span>'}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <button onclick=\\\"removeStoreFile(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:17px;cursor:pointer;padding:0 4px;line-height:1\\\">×</button>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function removeStoreFile(i){\u001b[39m\n\u001b[31m  _storeFiles.splice(i,1);\u001b[39m\n\u001b[31m  // Rebuild stores from remaining files — re-parse from cache not possible, so just reload from DB and remove this file's contribution\u001b[39m\n\u001b[31m  // Simplest approach: clear and ask user to re-upload remaining files\u001b[39m\n\u001b[31m  if(!_storeFiles.length){stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    // Can't re-parse without original files; just note it and keep current store list\u001b[39m\n\u001b[31m    toast('Removed from list. Re-upload the remaining files to refresh store list.','info');\u001b[39m\n\u001b[31m    _storeFiles.splice(0); // clear tracking since we can't reconstruct\u001b[39m\n\u001b[31m    stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderStoreFileList();\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=stores.length?`✓ ${stores.length} stores`:'No stores loaded';\u001b[39m\n\u001b[31m  updAvailTag();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function clearStoreList(){\u001b[39m\n\u001b[31m  if(!confirm('Remove all loaded stores?'))return;\u001b[39m\n\u001b[31m  stores=[];_storeFiles=[];\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent='';\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast('Store list cleared','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function handleStoreUpload(e){\u001b[39m\n\u001b[31m  const file=e.target.files[0];if(!file)return;\u001b[39m\n\u001b[31m  e.target.value=''; // allow same file re-upload\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    let data=[];\u001b[39m\n\u001b[31m    if(file.name.toLowerCase().endsWith('.csv')){\u001b[39m\n\u001b[31m      const txt=await file.text();\u001b[39m\n\u001b[31m      const rows=txt.split('\\\\n').map(r=>r.split(',').map(c=>c.trim().replace(/^\\\"|\\\"$/g,'')));\u001b[39m\n\u001b[31m      if(!rows.length||!rows[0].length){toast('Empty CSV','error');return;}\u001b[39m\n\u001b[31m      const h=rows[0];\u001b[39m\n\u001b[31m      data=rows.slice(1).filter(r=>r.length>1&&r.some(c=>c)).map(r=>{\u001b[39m\n\u001b[31m        const rowObj={};h.forEach((hk,i)=>{rowObj[hk]=r[i]||'';});\u001b[39m\n\u001b[31m        return parseStoreRow(rowObj, ()=>'');\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }else{\u001b[39m\n\u001b[31m      const ab=await file.arrayBuffer();const wb=XLSX.read(ab,{type:'array'});\u001b[39m\n\u001b[31m      const js=XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]],{defval:''});\u001b[39m\n\u001b[31m      data=js.map(row=>parseStoreRow(row,()=>''));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    data=data.filter(d=>d.name.trim());\u001b[39m\n\u001b[31m    if(!data.length){toast('No valid rows found in file','error');return;}\u001b[39m\n\u001b[31m    // Check if any store has a brand\u001b[39m\n\u001b[31m    const hasBrand=data.some(d=>d.brand);\u001b[39m\n\u001b[31m    // Always show preview first before merging\u001b[39m\n\u001b[31m    _pendingParse={file:file.name,data,hasBrand};\u001b[39m\n\u001b[31m    showStorePreview(file.name, data, hasBrand);\u001b[39m\n\u001b[31m  }catch(err){toast('Failed: '+err.message,'error')}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mlet _pendingBrand='';\u001b[39m\n\u001b[31mfunction setPendingBrand(b){\u001b[39m\n\u001b[31m  _pendingBrand=b;\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-assign-chips .chip').forEach(c=>{\u001b[39m\n\u001b[31m    c.classList.toggle('sel',c.textContent===b);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  if(!_pendingBrand){toast('Select a brand first','error');return;}\u001b[39m\n\u001b[31m  // Assign brand to all rows in this file\u001b[39m\n\u001b[31m  const data=_pendingParse.data.map(s=>({...s,brand:_pendingBrand}));\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, data, _pendingBrand);\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function skipBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, _pendingParse.data, '');\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showStorePreview(filename, data, hasBrand){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-preview-dialog');\u001b[39m\n\u001b[31m  const tbody=document.getElementById('store-preview-body');\u001b[39m\n\u001b[31m  document.getElementById('store-preview-title').textContent=`${filename} · ${data.length} ${t('stores found','स्टोर मिले')}`;\u001b[39m\n\u001b[31m  // Show first 8 rows\u001b[39m\n\u001b[31m  const sample=data.slice(0,8);\u001b[39m\n\u001b[31m  tbody.innerHTML=sample.map(s=>`<tr>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;font-weight:500\\\">${s.name||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.address||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.mobile||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px\\\"><span style=\\\"background:${s.brand?'var(--nv)':'var(--rd)'};color:#fff;padding:1px 7px;border-radius:10px;font-size:10px\\\">${s.brand||'?'}</span></td>\u001b[39m\n\u001b[31m  </tr>`).join('');\u001b[39m\n\u001b[31m  if(data.length>8)tbody.innerHTML+=`<tr><td colspan=\\\"4\\\" style=\\\"text-align:center;padding:8px;font-size:12px;color:var(--g400)\\\">…and ${data.length-8} more stores</td></tr>`;\u001b[39m\n\u001b[31m  el.classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function confirmStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  const {file,data,hasBrand}=_pendingParse;\u001b[39m\n\u001b[31m  if(!hasBrand){\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-fname').textContent=`File: ${file} · ${data.length} stores found · No brand column detected`;\u001b[39m\n\u001b[31m    const chips=document.getElementById('brand-assign-chips');\u001b[39m\n\u001b[31m    chips.innerHTML=brands.map(b=>`<div class=\\\"chip\\\" onclick=\\\"setPendingBrand('${b}')\\\" id=\\\"bac-${b}\\\">${b}</div>`).join('');\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').style.display='block';\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    await mergeStores(file, data, '');\u001b[39m\n\u001b[31m    _pendingParse=null;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction cancelStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingParse=null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function mergeStores(filename, newData, assignedBrand){\u001b[39m\n\u001b[31m  const before=stores.length;\u001b[39m\n\u001b[31m  stores=[...stores,...newData];\u001b[39m\n\u001b[31m  stores=dedupeStores(stores);\u001b[39m\n\u001b[31m  const added=stores.length-before;\u001b[39m\n\u001b[31m  const dupes=newData.length-added;\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify(stores));\u001b[39m\n\u001b[31m  // Track file\u001b[39m\n\u001b[31m  _storeFiles.push({name:filename,count:newData.length,brand:assignedBrand||''});\u001b[39m\n\u001b[31m  await cfg('store-files',JSON.stringify(_storeFiles));\u001b[39m\n\u001b[31m  const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m    `✓ ${stores.length} total stores${dupes>0?` · ${dupes} duplicate${dupes>1?'s':''} removed`:''}${noBrand?` · ${noBrand} without brand`:' · All have brand'}`;\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast(`${added} stores added${dupes>0?`, ${dupes} duplicates skipped`:''}${assignedBrand?' as '+assignedBrand:''}`, 'success');\u001b[39m\n\u001b[31m  // Show server-push button for supervisors\u001b[39m\n\u001b[31m  const pb = document.getElementById('store-push-btn');\u001b[39m\n\u001b[31m  if (pb) pb.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function fetchServerStores(){const url=document.getElementById('srv-url').value.trim();if(!url){toast('Enter a URL first','error');return;}try{toast('Fetching…','info');const r=await fetch(url);const j=await r.json();const fetched=Array.isArray(j)?j:j.stores||[];await mergeStores('Server ('+url.split('/').pop()+')',fetched,'');await cfg('srv-url',url);}catch{toast('Fetch failed — check URL','error')}}\u001b[39m\n\u001b[31masync function saveServerUrl(){await cfg('srv-url',document.getElementById('srv-url').value.trim());toast('URL saved','success')}\u001b[39m\n\u001b[31mconst DEFAULT_GAS_URL='https://script.google.com/macros/s/AKfycbwyufC7gQyu1BErCxiDlbQUn0AWiIWv7nEmjk4UcAx3dvlV6bGk7q5fQOiv82CTbokbkA/exec';·\u001b[39m\n\u001b[31mconst DEFAULT_STORES_URL='/recce/stores.json';\u001b[39m\n\u001b[31mconst _RECCE_CFG_URL='/recce/recce-cfg.json';·\u001b[39m\n\u001b[31m// Admin auto-unlock for harish/pramod via hub session\u001b[39m\n\u001b[31mconst _RECCE_ADMIN_IDS = ['harish', 'pramod', 'rakesh'];\u001b[39m\n\u001b[31mconst _RECCE_CFG_ADMINS = ['harish', 'pramod'];\u001b[39m\n\u001b[31mlet _adminRows = [];\u001b[39m\n\u001b[31mlet _myServerRows = [];\u001b[39m\n\u001b[31mlet _adminUnlocked = false;\u001b[39m\n\u001b[31mlet _recceCfg = { version: 1, supervisors: ['harish','pramod','rakesh'], mode: 'public', creators: [], allowed_users: [] };\u001b[39m\n\u001b[31mfunction _isSupervisor() {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  return !!(hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId));\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _showDeletedView = false;\u001b[39m\n\u001b[31mlet _supCreateMode = false;\u001b[39m\n\u001b[31mlet _pendingDeleteId = null;\u001b[39m\n\u001b[31mlet _pendingDeleteReason = null;\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (s?.empId && _RECCE_ADMIN_IDS.includes(s.empId)) _adminUnlocked = true;\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31masync function loadRecceCfg(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(_RECCE_CFG_URL + '?t=' + Date.now());\u001b[39m\n\u001b[31m    if (r.ok) {\u001b[39m\n\u001b[31m      const j = await r.json();\u001b[39m\n\u001b[31m      if (j && j.version) {\u001b[39m\n\u001b[31m        _recceCfg = j;\u001b[39m\n\u001b[31m        if (Array.isArray(j.supervisors) && j.supervisors.length) {\u001b[39m\n\u001b[31m          _recceCfg.supervisors = j.supervisors;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.creators)) _recceCfg.creators = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.allowed_users)) _recceCfg.allowed_users = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.clients)) _recceCfg.clients = [];\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  // Re-check admin status against server supervisor list\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId)) {\u001b[39m\n\u001b[31m    _adminUnlocked = true;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _checkAccessMode(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (_recceCfg.mode !== 'assigned') return;\u001b[39m\n\u001b[31m  const allowed = [\u001b[39m\n\u001b[31m    ...(_recceCfg.supervisors || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.creators || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.allowed_users || []),\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  if (hub?.empId && allowed.includes(hub.empId)) return;\u001b[39m\n\u001b[31m  // Block access — show locked overlay\u001b[39m\n\u001b[31m  document.body.innerHTML = `<div style=\\\"min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0f172a;color:#fff;padding:32px;text-align:center\\\"><div style=\\\"font-size:48px;margin-bottom:16px\\\">🔒</div><div style=\\\"font-size:20px;font-weight:700;margin-bottom:8px\\\">${t('Access Restricted','एक्सेस प्रतिबंधित')}</div><div style=\\\"font-size:14px;color:#94a3b8\\\">${t('You are not authorised to use Branding Recce. Please contact your supervisor.','आप ब्रांडिंग रेक्की उपयोग के लिए अधिकृत नहीं हैं।')}</div></div>`;\u001b[39m\n\u001b[31m  throw new Error('access-restricted');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _recceHubUser() {\u001b[39m\n\u001b[31m  try { return JSON.parse(localStorage.getItem('lm360-session') || '{}'); }\u001b[39m\n\u001b[31m  catch(_) { return {}; }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── Supervisor config management ────────────────────────────────────\u001b[39m\n\u001b[31mfunction renderSupPanel(){\u001b[39m\n\u001b[31m  if (!_adminUnlocked) return;\u001b[39m\n\u001b[31m  const panel = document.getElementById('sup-panel');\u001b[39m\n\u001b[31m  if (panel) panel.style.display = 'block';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const modePublic = document.getElementById('mode-public');\u001b[39m\n\u001b[31m  const modeAssigned = document.getElementById('mode-assigned');\u001b[39m\n\u001b[31m  if (modePublic && modeAssigned) {\u001b[39m\n\u001b[31m    modePublic.classList.toggle('sel', _recceCfg.mode !== 'assigned');\u001b[39m\n\u001b[31m    modeAssigned.classList.toggle('sel', _recceCfg.mode === 'assigned');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  const addRow = document.getElementById('sup-add-row');\u001b[39m\n\u001b[31m  if (addRow) addRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const creatorAddRow = document.getElementById('creator-add-row');\u001b[39m\n\u001b[31m  if (creatorAddRow) creatorAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const clientAddRow = document.getElementById('client-add-row');\u001b[39m\n\u001b[31m  if (clientAddRow) clientAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const modeRow = document.getElementById('mode-row');\u001b[39m\n\u001b[31m  if (modeRow) {\u001b[39m\n\u001b[31m    modeRow.style.display = 'block';\u001b[39m\n\u001b[31m    // Non-cfg-admins see mode as read-only (toggles exist but setRecceMode guards them)\u001b[39m\n\u001b[31m    modeRow.style.opacity = isCfgAdmin ? '1' : '0.65';\u001b[39m\n\u001b[31m    modeRow.style.pointerEvents = isCfgAdmin ? '' : 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const syncBtn = document.getElementById('cfg-sync-btn');\u001b[39m\n\u001b[31m  if (syncBtn) syncBtn.style.display = isCfgAdmin ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('sup-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const sups = _recceCfg.supervisors || [];\u001b[39m\n\u001b[31m  el.innerHTML = sups.map((s,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${s}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin && sups.length > 1 ? `<button onclick=\\\"removeSupervisor(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderCreatorsList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('creator-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const creators = _recceCfg.creators || [];\u001b[39m\n\u001b[31m  el.innerHTML = creators.length ? creators.map((u,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${u}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeCreator(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No creators yet — any Hub user can submit in Public mode.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setRecceMode(mode){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.mode = mode;\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addSupervisor(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('sup-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.supervisors = [...(_recceCfg.supervisors || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeSupervisor(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.supervisors = (_recceCfg.supervisors || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addCreator(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('creator-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.creators || []).includes(val)) { toast(t('Already a creator','पहले से क्रिएटर है'), 'info'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor (includes creation rights)','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.creators = [...(_recceCfg.creators || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeCreator(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.creators = (_recceCfg.creators || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderClientMgmtList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('client-mgmt-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const list = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  el.innerHTML = list.length ? list.map((c,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${esc(c)}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeClientFromList(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No clients yet — add client or agency names to show them as chips in the form.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addClientToList(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('client-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter client name','क्लाइंट नाम दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.clients || []).includes(val)) { toast(t('Already in list','पहले से मौजूद है'), 'info'); return; }\u001b[39m\n\u001b[31m  if (!_recceCfg.clients) _recceCfg.clients = [];\u001b[39m\n\u001b[31m  _recceCfg.clients.push(val);\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeClientFromList(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.clients = (_recceCfg.clients || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncCfgToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast(t('Not authorised','अधिकृत नहीं'), 'error'); return; }\u001b[39m\n\u001b[31m  const st = document.getElementById('cfg-sync-status');\u001b[39m\n\u001b[31m  if (st) st.textContent = t('Syncing…','सिंक हो रहा है…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-cfg', empId: hub.empId, cfg: {\u001b[39m\n\u001b[31m        version: _recceCfg.version || 1,\u001b[39m\n\u001b[31m        supervisors: _recceCfg.supervisors || [],\u001b[39m\n\u001b[31m        mode: _recceCfg.mode || 'public',\u001b[39m\n\u001b[31m        creators: _recceCfg.creators || [],\u001b[39m\n\u001b[31m        allowed_users: _recceCfg.allowed_users || [],\u001b[39m\n\u001b[31m        clients: _recceCfg.clients || [],\u001b[39m\n\u001b[31m      }})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) {\u001b[39m\n\u001b[31m      toast(t('Config synced to server ✓','कॉन्फ़िग सर्वर पर सेव हुआ ✓'), 'success');\u001b[39m\n\u001b[31m      if (st) st.textContent = t('Last synced: just now','अभी सिंक हुआ');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast(j.error || t('Sync failed','सिंक विफल'), 'error');\u001b[39m\n\u001b[31m      if (st) st.textContent = j.error || '';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Network error','नेटवर्क त्रुटि'), 'error');\u001b[39m\n\u001b[31m    if (st) st.textContent = e.message;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function pushStoresToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!hub?.empId || !_adminUnlocked) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-stores', empId: hub.empId, stores })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) toast(`${t('Pushed to server','सर्वर पर पुश हुआ')} · ${j.count} ${t('stores','स्टोर')}`, 'success');\u001b[39m\n\u001b[31m    else toast(j.error || t('Server push failed','सर्वर पुश विफल'), 'error');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Could not reach server','सर्वर से संपर्क नहीं हो सका'), 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── End supervisor config management ────────────────────────────────·\u001b[39m\n\u001b[31m// PostgREST sync constants\u001b[39m\n\u001b[31mconst _RC_BASE      = '/db';\u001b[39m\n\u001b[31mconst _RC_READ      = { 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_WRITE     = { 'Content-Type': 'application/json', 'Content-Profile': 'recce', 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_UPSERT    = { ..._RC_WRITE, 'Prefer': 'resolution=merge-duplicates,return=minimal' };\u001b[39m\n\u001b[31mconst _INSTALL_RD   = { 'Content-Type': 'application/json', 'Accept-Profile': 'installation' };\u001b[39m\n\u001b[31mconst _INSTALL_WR   = { 'Content-Type': 'application/json', 'Content-Profile': 'installation', 'Accept-Profile': 'installation', 'Prefer': 'return=minimal' };·\u001b[39m\n\u001b[31m// ── Campaign selection state ──\u001b[39m\n\u001b[31mlet _selectedCampaignId = null;\u001b[39m\n\u001b[31mlet _notifySupervisor   = false;\u001b[39m\n\u001b[31mlet _campaignList       = [];\u001b[39m\n\u001b[31mlet _pendingJobFilter   = false;\u001b[39m\n\u001b[31mlet _linkJobSubId       = null;\u001b[39m\n\u001b[31mlet _brandingLocked     = false;·\u001b[39m\n\u001b[31mfunction _updateBrandingLock() {\u001b[39m\n\u001b[31m  const hub  = _recceHubUser();\u001b[39m\n\u001b[31m  const isHP = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const banner   = document.getElementById('branding-lock-banner');\u001b[39m\n\u001b[31m  const ovWrap   = document.getElementById('branding-override-wrap');\u001b[39m\n\u001b[31m  const brItems  = document.getElementById('br-items');\u001b[39m\n\u001b[31m  const brAdd    = document.getElementById('br-add');\u001b[39m\n\u001b[31m  const brYes    = document.getElementById('br-yes');\u001b[39m\n\u001b[31m  const brNo     = document.getElementById('br-no');\u001b[39m\n\u001b[31m  if (!banner) return;\u001b[39m\n\u001b[31m  if (_brandingLocked) {\u001b[39m\n\u001b[31m    banner.style.display   = '';\u001b[39m\n\u001b[31m    if (ovWrap)  ovWrap.style.display  = isHP ? '' : 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.pointerEvents = 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.opacity = '0.55';\u001b[39m\n\u001b[31m    if (brAdd)   brAdd.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='none'; brYes.style.opacity='0.5'; }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='none';  brNo.style.opacity='0.5';  }\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    banner.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brItems) { brItems.style.pointerEvents=''; brItems.style.opacity=''; }\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='';  brYes.style.opacity='';   }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='';   brNo.style.opacity='';    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction unlockBrandingOverride() {\u001b[39m\n\u001b[31m  if (!confirm(\u001b[39m\n\u001b[31m    'Client has already reviewed this recce.\\\\n' +\u001b[39m\n\u001b[31m    'Editing brandings will NOT remove their approval.\\\\n' +\u001b[39m\n\u001b[31m    'Continue ONLY if the client has verbally confirmed. Proceed?'\u001b[39m\n\u001b[31m  )) return;\u001b[39m\n\u001b[31m  _brandingLocked = false;\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  renderBrandings();\u001b[39m\n\u001b[31m  toast(t('Branding unlocked for this session', 'ब्रांडिंग इस सत्र के लिए अनलॉक'), 'info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadCampaignsForForm() {\u001b[39m\n\u001b[31m  const sel = document.getElementById('f-campaign-id');\u001b[39m\n\u001b[31m  if (!sel) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m    _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m  } catch(_) { _campaignList = []; }\u001b[39m\n\u001b[31m  sel.innerHTML =\u001b[39m\n\u001b[31m    '<option value=\\\"\\\">— Select job / campaign (optional) —</option>' +\u001b[39m\n\u001b[31m    _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('') +\u001b[39m\n\u001b[31m    '<option value=\\\"__NOTIFY__\\\">⚑ No campaign yet — notify supervisor</option>';\u001b[39m\n\u001b[31m  if (_selectedCampaignId) sel.value = _selectedCampaignId;\u001b[39m\n\u001b[31m  else if (_notifySupervisor) sel.value = '__NOTIFY__';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onCampaignSelect() {\u001b[39m\n\u001b[31m  const val = document.getElementById('f-campaign-id')?.value || '';\u001b[39m\n\u001b[31m  const noticeEl = document.getElementById('campaign-notify-msg');\u001b[39m\n\u001b[31m  if (val === '__NOTIFY__') {\u001b[39m\n\u001b[31m    _selectedCampaignId = null;\u001b[39m\n\u001b[31m    _notifySupervisor   = true;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'block';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    _selectedCampaignId = val || null;\u001b[39m\n\u001b[31m    _notifySupervisor   = false;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction generateRecceReportHtml(entry, photoUrls) {\u001b[39m\n\u001b[31m  const d    = entry.data || {};\u001b[39m\n\u001b[31m  const urls = photoUrls || {};\u001b[39m\n\u001b[31m  const agent = entry.submittedByName || entry.submittedBy || 'Field Agent';\u001b[39m\n\u001b[31m  const _safeId      = (entry.id||'').replace(/\\\\//g,'_').replace(/\\\\.\\\\./g,'');\u001b[39m\n\u001b[31m  const serverPdfUrl = _safeId ? `https://srv1111289.hstgr.cloud/screenshots/recce/views/${_safeId}.pdf` : '';\u001b[39m\n\u001b[31m  const brandLogoUrl = d.brandLogoUrl || _brandLogos[d.brand] || '';\u001b[39m\n\u001b[31m  const tsStr = new Date(entry.timestamp).toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric',hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\u001b[39m\n\u001b[31m  const gpsUrl = d.gpsCoords ? `https://maps.google.com/?q=${d.gpsCoords.lat},${d.gpsCoords.lng}` : null;·\u001b[39m\n\u001b[31m  const frontCount  = (urls.front||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const insideCount = (urls.inside||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const addlCount   = (urls.addl||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const brCount     = (d.brandings||[]).length;·\u001b[39m\n\u001b[31m  // pages: { id, url, bandHtml, cmt, dotLabel, dotColor }\u001b[39m\n\u001b[31m  const pages = [];·\u001b[39m\n\u001b[31m  (urls.front||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Front View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${frontCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.frontPhotos||[])[i]?.cmt||'', dotLabel:`FV${i+1}`, dotColor:'#3b82f6', catLabel:'Front View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.inside||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Inside View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${insideCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.insidePhotos||[])[i]?.cmt||'', dotLabel:`IV${i+1}`, dotColor:'#14b8a6', catLabel:'Inside View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (d.brandings||[]).forEach((b,i)=>{\u001b[39m\n\u001b[31m    const url=(urls.brandings||[])[i]; if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">${esc(b.type||'Branding')}</div><div class=\\\"ph-dims\\\">Width : ${esc(b.w||'?')}&Prime;&nbsp;&times;&nbsp;Height : ${esc(b.h||'?')}&Prime;&nbsp;&mdash;&nbsp;${esc(b.qty||1)} Nos</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${brCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:'', dotLabel:`B${i+1}`, dotColor:'#f97316', catLabel:b.type||'Branding',\u001b[39m\n\u001b[31m      tileDims:`${b.w||'?'}″×${b.h||'?'}″ — ${String(b.qty||1).padStart(2,'0')} Nos` });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.addl||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Additional</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${addlCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.addlPhotos||[])[i]?.desc||'', dotLabel:`A${i+1}`, dotColor:'#94a3b8', catLabel:'Additional', tileDims:'' });\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const sideItems = [\u001b[39m\n\u001b[31m    `<div class=\\\"si-item active\\\" data-tgt=\\\"pg-cover\\\" title=\\\"Cover\\\"><div class=\\\"si-dot\\\" style=\\\"background:#475569\\\">CV</div></div>`\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  pages.forEach(p => {\u001b[39m\n\u001b[31m    sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"${p.id}\\\" title=\\\"${p.dotLabel}\\\"><div class=\\\"si-dot\\\" style=\\\"background:${p.dotColor}\\\">${p.dotLabel}</div></div>`);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(d.hasVideo) sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-vid\\\" title=\\\"Video\\\"><div class=\\\"si-dot\\\" style=\\\"background:#a855f7\\\">VD</div></div>`);\u001b[39m\n\u001b[31m  if(urls.doc)   sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-doc\\\" title=\\\"Document\\\"><div class=\\\"si-dot\\\" style=\\\"background:#64748b\\\">DC</div></div>`);·\u001b[39m\n\u001b[31m  const thumbItems = [\u001b[39m\n\u001b[31m    ...pages,\u001b[39m\n\u001b[31m    ...(d.hasVideo?[{id:'pg-vid',url:null,catLabel:'Video',tileDims:'',dotLabel:'VD',dotColor:'#a855f7'}]:[]),\u001b[39m\n\u001b[31m    ...(urls.doc?[{id:'pg-doc',url:urls.doc,catLabel:'Document',tileDims:'',dotLabel:'DC',dotColor:'#64748b'}]:[])\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  const thumbsHtml = thumbItems.map(p=>`<div class=\\\"cov-thumb\\\" onclick=\\\"document.getElementById('${p.id}').scrollIntoView({behavior:'smooth'})\\\">${p.url?`<img src=\\\"${p.url}\\\" alt=\\\"\\\">`:(`<div class=\\\"cov-thumb-vid\\\">${p.catLabel==='Video'?'&#x25B6;&#xFE0F;':'&#x1F4C4;'}</div>`)}<div class=\\\"cov-thumb-ov\\\" style=\\\"border-top:3px solid ${p.dotColor}\\\"><div class=\\\"cov-thumb-cat\\\">${esc(p.catLabel)}</div>${p.tileDims?`<div class=\\\"cov-thumb-dims\\\">${esc(p.tileDims)}</div>`:''}<div class=\\\"cov-thumb-no\\\">${p.dotLabel}</div></div></div>`).join('');·\u001b[39m\n\u001b[31m  const pagesHtml = pages.map(p => `\u001b[39m\n\u001b[31m<div class=\\\"photo-page\\\" id=\\\"${p.id}\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\">${p.bandHtml}</div>\u001b[39m\n\u001b[31m  <div class=\\\"ph-img\\\"><a href=\\\"${p.url}\\\" target=\\\"_blank\\\"><img src=\\\"${p.url}\\\" loading=\\\"lazy\\\" alt=\\\"\\\"></a>${p.cmt?`<div class=\\\"ph-cmt\\\">${esc(p.cmt)}</div>`:''}</div>\u001b[39m\n\u001b[31m</div>`).join('');·\u001b[39m\n\u001b[31m  return `<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\"><head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m<title>Recce — ${esc(d.storeName||'Unknown')} · ${esc(d.brand||'')}</title>\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--dk:#0f172a;--nv2:#1a2f52;--or:#f97316;--g200:#e2e8f0;--g400:#94a3b8;--g600:#475569;--si:54px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0}\u001b[39m\n\u001b[31mhtml,body{height:100%;overflow:hidden}\u001b[39m\n\u001b[31mbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#111;color:var(--dk);display:flex}\u001b[39m\n\u001b[31ma{color:var(--or);text-decoration:none}\u001b[39m\n\u001b[31mimg{display:block}·\u001b[39m\n\u001b[31m/* ── Side index ── */\u001b[39m\n\u001b[31m.side-idx{width:var(--si);flex-shrink:0;background:var(--dk);overflow-y:auto;display:flex;flex-direction:column;align-items:center;padding:4px 0;scrollbar-width:none;z-index:50}\u001b[39m\n\u001b[31m.side-idx::-webkit-scrollbar{display:none}\u001b[39m\n\u001b[31m.si-item{width:100%;min-height:56px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s}\u001b[39m\n\u001b[31m.si-item:hover{background:rgba(255,255,255,.07)}\u001b[39m\n\u001b[31m.si-dot{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff;opacity:.4;transition:opacity .18s,transform .18s;line-height:1;text-align:center}\u001b[39m\n\u001b[31m.si-item.active .si-dot{opacity:1;transform:scale(1.15)}·\u001b[39m\n\u001b[31m/* ── Main scroll area ── */\u001b[39m\n\u001b[31m.main{flex:1;overflow-y:scroll;scroll-snap-type:y mandatory;scroll-behavior:smooth;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar{width:3px}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15)}·\u001b[39m\n\u001b[31m/* ── Cover ── */\u001b[39m\n\u001b[31m.cover{height:100vh;scroll-snap-align:start;flex-shrink:0;background:linear-gradient(135deg,#0f172a 0%,var(--nv2) 100%);color:#fff;display:flex;flex-direction:column;padding:24px 20px 20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.cover-badge{display:inline-flex;align-items:center;gap:5px;background:var(--or);color:#fff;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:1px;padding:3px 12px;border-radius:20px;margin-bottom:12px;align-self:flex-start}\u001b[39m\n\u001b[31m.cover h1{font-size:20px;font-weight:700;line-height:1.3;margin-bottom:4px}\u001b[39m\n\u001b[31m.cover-addr{color:rgba(255,255,255,.55);font-size:12px;margin-bottom:16px}\u001b[39m\n\u001b[31m.cg{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}\u001b[39m\n\u001b[31m.cm{background:rgba(255,255,255,.08);border-radius:8px;padding:8px 12px}\u001b[39m\n\u001b[31m.cm-l{font-size:9px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}\u001b[39m\n\u001b[31m.cm-v{font-size:13px;font-weight:600;color:#fff}\u001b[39m\n\u001b[31m.cm-v a{color:#fb923c}\u001b[39m\n\u001b[31m.cover-pbar{padding-top:8px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{background:var(--or);color:#fff;border:none;padding:10px 22px;border-radius:22px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}\u001b[39m\n\u001b[31m.btn-p:disabled{opacity:.4;cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-c{background:rgba(255,255,255,.1);color:rgba(255,255,255,.75);border:1px solid rgba(255,255,255,.2);padding:10px 18px;border-radius:22px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit}·\u001b[39m\n\u001b[31m/* ── Cover thumbnail grid ── */\u001b[39m\n\u001b[31m.cov-grid-hdr{font-size:10px;font-weight:700;color:rgba(255,255,255,.35);text-transform:uppercase;letter-spacing:1.2px;padding:10px 0 5px;flex-shrink:0}\u001b[39m\n\u001b[31m.cov-grid{flex:1;min-height:0;display:grid;gap:5px;overflow:hidden;align-content:start}\u001b[39m\n\u001b[31m.cov-thumb{position:relative;overflow:hidden;border-radius:7px;cursor:pointer;background:#1e293b;transition:transform .18s,box-shadow .18s}\u001b[39m\n\u001b[31m.cov-thumb:hover{transform:scale(1.05);box-shadow:0 4px 18px rgba(0,0,0,.55)}\u001b[39m\n\u001b[31m.cov-thumb img{width:100%;height:100%;object-fit:cover;display:block}\u001b[39m\n\u001b[31m.cov-thumb-vid{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:#0f172a}\u001b[39m\n\u001b[31m.cov-thumb-ov{position:absolute;inset:0;background:rgba(0,0,0,.28);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:5px;border-radius:7px}\u001b[39m\n\u001b[31m.cov-thumb-cat{color:rgba(255,255,255,.5);font-weight:900;text-align:center;text-transform:uppercase;letter-spacing:.8px;text-shadow:0 1px 6px rgba(0,0,0,.95);line-height:1.2;word-break:break-word}\u001b[39m\n\u001b[31m.cov-thumb-dims{color:rgba(255,255,255,.5);font-weight:700;text-align:center;text-shadow:0 1px 5px rgba(0,0,0,.95);letter-spacing:.3px;line-height:1.3}\u001b[39m\n\u001b[31m.cov-thumb-no{color:rgba(255,255,255,.5);font-weight:800;text-shadow:0 1px 4px rgba(0,0,0,.95);letter-spacing:.5px}\u001b[39m\n\u001b[31m#cover-btn{position:fixed;bottom:20px;right:16px;display:none;align-items:center;gap:6px;background:rgba(255,255,255,.15);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.25);color:#fff;padding:10px 22px;border-radius:50px;font-size:13px;font-weight:700;cursor:pointer;z-index:200;letter-spacing:.3px;box-shadow:0 2px 12px rgba(0,0,0,.3);font-family:inherit;transition:background .15s,transform .15s}\u001b[39m\n\u001b[31m#cover-btn:hover{background:rgba(255,255,255,.22);transform:scale(1.04)}·\u001b[39m\n\u001b[31m/* ── Print wait overlay ── */\u001b[39m\n\u001b[31m#print-overlay{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m@media print{#print-overlay{display:none!important}}·\u001b[39m\n\u001b[31m/* ── Loading progress bar ── */\u001b[39m\n\u001b[31m.load-bar{position:fixed;bottom:0;left:0;right:0;background:rgba(15,23,42,.95);padding:9px 16px;z-index:9999;display:flex;align-items:center;gap:12px;backdrop-filter:blur(6px)}\u001b[39m\n\u001b[31m.load-track{flex:1;height:5px;background:rgba(255,255,255,.12);border-radius:3px;overflow:hidden}\u001b[39m\n\u001b[31m.load-fill{height:100%;background:var(--or);width:0%;transition:width .35s ease;border-radius:3px}\u001b[39m\n\u001b[31m.load-txt{font-size:11px;color:rgba(255,255,255,.6);white-space:nowrap;min-width:160px}·\u001b[39m\n\u001b[31m/* ── Photo page ── */\u001b[39m\n\u001b[31m.photo-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ph-band{background:var(--dk);padding:16px 26px;flex-shrink:0;display:flex;align-items:center;gap:20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.ph-cat{font-size:35px;font-weight:800;color:#fff;letter-spacing:-.5px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.ph-dims{flex:1;font-size:18px;font-weight:600;color:var(--or);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}\u001b[39m\n\u001b[31m.ph-no{margin-left:auto;flex-shrink:0;font-size:21px;font-weight:700;color:rgba(255,255,255,.85);background:rgba(255,255,255,.1);padding:5px 20px;border-radius:24px;white-space:nowrap}\u001b[39m\n\u001b[31m.ph-of{font-size:18px;font-weight:400;color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.ph-img{flex:1;overflow:hidden;position:relative;background:#111}\u001b[39m\n\u001b[31m.ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m.ph-img img{width:100%;height:100%;object-fit:contain;display:block}\u001b[39m\n\u001b[31m.ph-cmt{position:absolute;bottom:0;left:0;right:0;padding:6px 14px;background:rgba(0,0,0,.62);font-size:11px;color:rgba(255,255,255,.75);font-style:italic;pointer-events:none}·\u001b[39m\n\u001b[31m/* ── Video / Doc pages ── */\u001b[39m\n\u001b[31m.vid-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;background:#fff}\u001b[39m\n\u001b[31m.vid-body{flex:1;padding:20px 24px;font-size:14px;color:var(--g600);border-left:4px solid var(--or)}\u001b[39m\n\u001b[31m.vid-body em{display:block;font-size:12px;color:var(--g400);margin-top:6px}\u001b[39m\n\u001b[31m.doc-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m.doc-wrap{flex:1;display:flex;align-items:center;justify-content:center;background:#111;overflow:hidden}\u001b[39m\n\u001b[31m.doc-img{max-width:100%;max-height:100%;object-fit:contain}·\u001b[39m\n\u001b[31m/* ── Cover header band ── */\u001b[39m\n\u001b[31m.cov-hdr{display:flex;gap:0;margin-bottom:12px;flex-shrink:0;border-radius:10px;overflow:hidden;border:1px solid rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.cov-hdr-l{flex:1;padding:14px 18px;display:flex;flex-direction:column;gap:5px;border-right:1px solid rgba(255,255,255,.1);min-width:0}\u001b[39m\n\u001b[31m.cov-hdr-r{width:170px;flex-shrink:0;padding:14px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:rgba(255,255,255,.04)}\u001b[39m\n\u001b[31m.cov-store{font-size:18px;font-weight:800;color:#fff;line-height:1.25;margin-bottom:2px}\u001b[39m\n\u001b[31m.cov-meta{font-size:12px;color:rgba(255,255,255,.55);display:flex;align-items:center;gap:5px;line-height:1.5}\u001b[39m\n\u001b[31m.cov-brand{background:var(--or);color:#fff;font-size:13px;font-weight:800;padding:5px 16px;border-radius:20px;text-align:center;letter-spacing:.3px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\u001b[39m\n\u001b[31m.cov-date-l{font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.8px;margin-bottom:2px;text-align:center}\u001b[39m\n\u001b[31m.cov-date-v{font-size:13px;font-weight:700;color:#fff;text-align:center}\u001b[39m\n\u001b[31m.cov-logo-box{background:#fff;border-radius:8px;padding:8px 14px;display:flex;align-items:center;justify-content:center;width:100%;max-width:138px}\u001b[39m\n\u001b[31m.cov-logo-box img{max-width:110px;max-height:44px;object-fit:contain;display:block}·\u001b[39m\n\u001b[31m/* ── Print ── */\u001b[39m\n\u001b[31m@page{size:A4 landscape;margin:12mm}\u001b[39m\n\u001b[31m@media print{\u001b[39m\n\u001b[31m  html,body{height:auto;overflow:visible;display:block}\u001b[39m\n\u001b[31m  .side-idx{display:none}\u001b[39m\n\u001b[31m  .main{overflow:visible;display:block;height:auto;scroll-snap-type:none}\u001b[39m\n\u001b[31m  .cover,.vid-page,.doc-page{height:auto;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m  .photo-page{height:186mm;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m  .cover{padding:20px 24px}\u001b[39m\n\u001b[31m  .cover-pbar{display:none}\u001b[39m\n\u001b[31m  .cov-hdr{margin-bottom:8px;border-radius:7px}\u001b[39m\n\u001b[31m  .cov-hdr-l{padding:10px 14px}\u001b[39m\n\u001b[31m  .cov-hdr-r{padding:10px 12px;width:150px}\u001b[39m\n\u001b[31m  .cov-store{font-size:15px}\u001b[39m\n\u001b[31m  .cov-meta{font-size:10px}\u001b[39m\n\u001b[31m  .cov-brand{font-size:11px;padding:3px 12px}\u001b[39m\n\u001b[31m  .cov-date-v{font-size:11px}\u001b[39m\n\u001b[31m  .ph-band{padding:5mm 13mm;gap:10mm}\u001b[39m\n\u001b[31m  .ph-cat{font-size:15mm}\u001b[39m\n\u001b[31m  .ph-dims{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-no{font-size:12mm;padding:2mm 8mm}\u001b[39m\n\u001b[31m  .ph-of{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-img{flex:1;display:flex;align-items:center;justify-content:center;background:#fff;overflow:hidden}\u001b[39m\n\u001b[31m  .ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m  .ph-img img{width:100%;height:100%;object-fit:contain}\u001b[39m\n\u001b[31m  .ph-cmt{position:static;background:transparent;color:#475569;padding:2mm 8mm;font-size:6mm}\u001b[39m\n\u001b[31m  .main>*:last-child{page-break-after:avoid;break-after:avoid}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m</style></head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<div class=\\\"side-idx\\\" id=\\\"side-idx\\\">${sideItems.join('')}</div>·\u001b[39m\n\u001b[31m<div class=\\\"main\\\" id=\\\"main\\\">·\u001b[39m\n\u001b[31m<div class=\\\"cover\\\" id=\\\"pg-cover\\\">\u001b[39m\n\u001b[31m  <div class=\\\"cov-hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-l\\\">\u001b[39m\n\u001b[31m      <div class=\\\"cov-store\\\">${esc(d.storeName||'Unknown Store')}</div>\u001b[39m\n\u001b[31m      ${(d.address||d.city)?`<div class=\\\"cov-meta\\\">&#x1F4CD; ${esc(d.address||'')}${d.city&&!(d.address||'').includes(d.city)?', '+esc(d.city):''}</div>`:''}\u001b[39m\n\u001b[31m      ${d.mobile?`<div class=\\\"cov-meta\\\">&#x1F4DE; ${esc(d.mobile)}</div>`:''}\u001b[39m\n\u001b[31m      ${d.email?`<div class=\\\"cov-meta\\\">&#x2709; ${esc(d.email)}</div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-r\\\">\u001b[39m\n\u001b[31m      ${brandLogoUrl\u001b[39m\n\u001b[31m        ? `<div class=\\\"cov-logo-box\\\"><img src=\\\"${brandLogoUrl}\\\" alt=\\\"${esc(d.brand||'')}\\\"></div>`\u001b[39m\n\u001b[31m        : (d.brand?`<div class=\\\"cov-brand\\\">${esc(d.brand)}</div>`:'')}\u001b[39m\n\u001b[31m      ${d.date?`<div><div class=\\\"cov-date-l\\\">Recce Date</div><div class=\\\"cov-date-v\\\">${esc(d.date)}</div></div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${thumbItems.length ? `<div class=\\\"cov-grid-hdr\\\">&#x1F4F7; ${thumbItems.length} page${thumbItems.length!==1?'s':''} &mdash; tap any to jump</div><div class=\\\"cov-grid\\\" id=\\\"cov-grid\\\">${thumbsHtml}</div>` : ''}\u001b[39m\n\u001b[31m  <div class=\\\"cover-pbar\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" id=\\\"btn-print\\\" onclick=\\\"doPDF()\\\">&#x1F4C4;&nbsp;PDF</button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-c\\\" onclick=\\\"window.close()\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m${pagesHtml}·\u001b[39m\n\u001b[31m${d.hasVideo?`\u001b[39m\n\u001b[31m<div class=\\\"vid-page\\\" id=\\\"pg-vid\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Video</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"vid-body\\\">${esc(d.videoNote||'Video recorded during visit')}${d.videoCmt?`<em>${esc(d.videoCmt)}</em>`:''}</div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m${urls.doc?`\u001b[39m\n\u001b[31m<div class=\\\"doc-page\\\" id=\\\"pg-doc\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Document</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"doc-wrap\\\"><a href=\\\"${urls.doc}\\\" target=\\\"_blank\\\"><img class=\\\"doc-img\\\" src=\\\"${urls.doc}\\\" loading=\\\"lazy\\\" alt=\\\"Document\\\"></a></div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"print-overlay\\\"><div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Preparing print&hellip;</div><div class=\\\"po-sub\\\" id=\\\"po-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"po-pfill\\\"></div></div></div>\u001b[39m\n\u001b[31m${pages.length ? `<div class=\\\"load-bar\\\" id=\\\"load-bar\\\"><div class=\\\"load-track\\\"><div class=\\\"load-fill\\\" id=\\\"load-fill\\\"></div></div><div class=\\\"load-txt\\\" id=\\\"load-txt\\\">Loading photos&#x2026;</div></div>` : ''}\u001b[39m\n\u001b[31m${thumbItems.length ? `<button id=\\\"cover-btn\\\" onclick=\\\"document.getElementById('pg-cover').scrollIntoView({behavior:'smooth'})\\\">&#x1F3E0;&nbsp;Cover Page</button>` : ''}·\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var main=document.getElementById('main');\u001b[39m\n\u001b[31m  var items=document.querySelectorAll('.si-item');\u001b[39m\n\u001b[31m  var covBtn=document.getElementById('cover-btn');\u001b[39m\n\u001b[31m  function setActive(id){\u001b[39m\n\u001b[31m    items.forEach(function(el){el.classList.toggle('active',el.dataset.tgt===id);});\u001b[39m\n\u001b[31m    var a=document.querySelector('.si-item[data-tgt=\\\"'+id+'\\\"]');\u001b[39m\n\u001b[31m    if(a) a.scrollIntoView({block:'nearest'});\u001b[39m\n\u001b[31m    if(covBtn) covBtn.style.display=id==='pg-cover'?'none':'flex';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  items.forEach(function(el){\u001b[39m\n\u001b[31m    el.addEventListener('click',function(){\u001b[39m\n\u001b[31m      var t=document.getElementById(el.dataset.tgt);\u001b[39m\n\u001b[31m      if(t) t.scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if('IntersectionObserver' in window){\u001b[39m\n\u001b[31m    var obs=new IntersectionObserver(function(entries){\u001b[39m\n\u001b[31m      entries.forEach(function(e){if(e.isIntersecting&&e.intersectionRatio>=0.45) setActive(e.target.id);});\u001b[39m\n\u001b[31m    },{root:main,threshold:0.45});\u001b[39m\n\u001b[31m    document.querySelectorAll('[id^=\\\"pg-\\\"]').forEach(function(p){obs.observe(p);});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  setActive('pg-cover');\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var imgs=Array.from(document.querySelectorAll('img'));\u001b[39m\n\u001b[31m  var total=imgs.length,loaded=0;\u001b[39m\n\u001b[31m  var bar=document.getElementById('load-bar');\u001b[39m\n\u001b[31m  var fill=document.getElementById('load-fill');\u001b[39m\n\u001b[31m  var txt=document.getElementById('load-txt');\u001b[39m\n\u001b[31m  var printPending=false,printShowTime=0;\u001b[39m\n\u001b[31m  var mm=96/25.4;\u001b[39m\n\u001b[31m  var SERVER_PDF='${serverPdfUrl}';\u001b[39m\n\u001b[31m  function updatePoBar(){\u001b[39m\n\u001b[31m    var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m    var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(poFill) poFill.style.width=(total?Math.round(loaded/total*100):100)+'%';\u001b[39m\n\u001b[31m    if(poSub) poSub.textContent=loaded+' / '+total+' photos ready';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function done(){\u001b[39m\n\u001b[31m    if(fill) fill.style.width='100%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='✓ All '+total+' photos ready';\u001b[39m\n\u001b[31m    setTimeout(function(){\u001b[39m\n\u001b[31m      if(bar){bar.style.transition='opacity .6s';bar.style.opacity='0';}\u001b[39m\n\u001b[31m      setTimeout(function(){if(bar)bar.style.display='none';},650);\u001b[39m\n\u001b[31m    },2000);\u001b[39m\n\u001b[31m    if(printPending){\u001b[39m\n\u001b[31m      printPending=false;\u001b[39m\n\u001b[31m      var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m      var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m      var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(poFill) poFill.style.width='100%';\u001b[39m\n\u001b[31m      if(poSub) poSub.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},Math.max(400,2000-(Date.now()-printShowTime)));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function onImg(){\u001b[39m\n\u001b[31m    loaded++;\u001b[39m\n\u001b[31m    if(fill) fill.style.width=Math.round(loaded/total*100)+'%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… '+loaded+' / '+total;\u001b[39m\n\u001b[31m    if(printPending) updatePoBar();\u001b[39m\n\u001b[31m    if(loaded>=total) done();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  /* ── PDF layout helpers ── */\u001b[39m\n\u001b[31m  function fitBandFonts(pageW){\u001b[39m\n\u001b[31m    var padH=2*13*mm,gapH=2*10*mm,noPadH=2*8*mm;\u001b[39m\n\u001b[31m    var avail=pageW-padH-gapH;\u001b[39m\n\u001b[31m    var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-band').forEach(function(band){\u001b[39m\n\u001b[31m      var cat=band.querySelector('.ph-cat');\u001b[39m\n\u001b[31m      var dims=band.querySelector('.ph-dims');\u001b[39m\n\u001b[31m      var no=band.querySelector('.ph-no');\u001b[39m\n\u001b[31m      if(!cat) return;\u001b[39m\n\u001b[31m      var catTxt=cat.textContent.trim();\u001b[39m\n\u001b[31m      var dimsTxt=dims?dims.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      var noTxt=no?no.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      function tw(sc){\u001b[39m\n\u001b[31m        var cf=15*sc*mm,df=10*sc*mm,nf=12*sc*mm;\u001b[39m\n\u001b[31m        ctx.font='800 '+cf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var cw=ctx.measureText(catTxt).width;\u001b[39m\n\u001b[31m        ctx.font='600 '+df+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var dw=dims?ctx.measureText(dimsTxt).width:0;\u001b[39m\n\u001b[31m        ctx.font='700 '+nf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var nw=no?ctx.measureText(noTxt).width+noPadH:0;\u001b[39m\n\u001b[31m        return cw+dw+nw;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      var scale=1.0;\u001b[39m\n\u001b[31m      if(tw(scale)>avail){\u001b[39m\n\u001b[31m        var lo=0.3,hi=1.0;\u001b[39m\n\u001b[31m        for(var i=0;i<10;i++){var mid=(lo+hi)/2;if(tw(mid)<=avail)lo=mid;else hi=mid;}\u001b[39m\n\u001b[31m        scale=lo*0.93;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      cat.style.setProperty('font-size',Math.round(15*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(dims) dims.style.setProperty('font-size',Math.round(10*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(no) no.style.setProperty('font-size',Math.round(12*scale*mm)+'px','important');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function sizePdfThumbs(pageW,pageH){\u001b[39m\n\u001b[31m    var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m    if(!grid||!grid.children.length) return;\u001b[39m\n\u001b[31m    var coverPage=document.getElementById('pg-cover');\u001b[39m\n\u001b[31m    var usedH=56;\u001b[39m\n\u001b[31m    if(coverPage){\u001b[39m\n\u001b[31m      Array.from(coverPage.children).forEach(function(el){\u001b[39m\n\u001b[31m        if(el!==grid) usedH+=el.offsetHeight||0;\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    var gridH=Math.max(80,pageH-usedH);\u001b[39m\n\u001b[31m    var n=grid.children.length,gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m    for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m      var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m      var w=(pageW-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m      var h=w*asp;\u001b[39m\n\u001b[31m      if(rows*h+(rows-1)*gap<=gridH&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m    grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m    grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m    var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m    var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m    var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function preparePdfLayout(){\u001b[39m\n\u001b[31m    var pageW=Math.round((297-24)*mm);\u001b[39m\n\u001b[31m    var pageH=Math.round((210-24)*mm);\u001b[39m\n\u001b[31m    fitBandFonts(pageW);\u001b[39m\n\u001b[31m    sizePdfThumbs(pageW,pageH);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.preparePdfLayout=preparePdfLayout;\u001b[39m\n\u001b[31m  function restorePdfLayout(){\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-cat,.ph-dims,.ph-no').forEach(function(el){\u001b[39m\n\u001b[31m      el.style.removeProperty('font-size');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(window._screenSizeThumbs) window._screenSizeThumbs();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.addEventListener('afterprint',restorePdfLayout);\u001b[39m\n\u001b[31m  function _doBrowserPrint(){\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    printShowTime=Date.now();\u001b[39m\n\u001b[31m    preparePdfLayout();\u001b[39m\n\u001b[31m    if(total===0||loaded>=total){\u001b[39m\n\u001b[31m      var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m      if(ps) ps.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},2000);\u001b[39m\n\u001b[31m      return;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    printPending=true;\u001b[39m\n\u001b[31m    updatePoBar();\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if((!img.complete||img.naturalWidth===0)&&img.getAttribute('loading')==='lazy'){\u001b[39m\n\u001b[31m        img.loading='eager';var s=img.src;img.src='';img.src=s;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.doPDF=async function(){\u001b[39m\n\u001b[31m    if(!SERVER_PDF){_doBrowserPrint();return;}\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      var r=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m      if(r.ok){window.open(SERVER_PDF,'_blank');return;}\u001b[39m\n\u001b[31m    }catch(_){}\u001b[39m\n\u001b[31m    // PDF not ready yet — show overlay and poll\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    if(pf) pf.style.width='0%';\u001b[39m\n\u001b[31m    if(ps) ps.textContent='Waiting for server PDF…';\u001b[39m\n\u001b[31m    var tries=0;\u001b[39m\n\u001b[31m    (async function poll(){\u001b[39m\n\u001b[31m      tries++;\u001b[39m\n\u001b[31m      if(pf) pf.style.width=Math.min(88,tries*8)+'%';\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        var r2=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m        if(r2.ok){\u001b[39m\n\u001b[31m          if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m          setTimeout(function(){if(ov)ov.style.display='none';window.open(SERVER_PDF,'_blank');},400);\u001b[39m\n\u001b[31m          return;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      }catch(_){}\u001b[39m\n\u001b[31m      if(tries>=12){if(ov)ov.style.display='none';_doBrowserPrint();return;}\u001b[39m\n\u001b[31m      setTimeout(poll,5000);\u001b[39m\n\u001b[31m    })();\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  if(total===0){if(bar)bar.style.display='none';}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… 0 / '+total;\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if(img.complete&&img.naturalWidth>0) onImg();\u001b[39m\n\u001b[31m      else{img.addEventListener('load',onImg);img.addEventListener('error',onImg);}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m  if(grid&&grid.children.length>0){\u001b[39m\n\u001b[31m    function sizeThumbs(){\u001b[39m\n\u001b[31m      var n=grid.children.length;\u001b[39m\n\u001b[31m      var gw=grid.clientWidth,gh=grid.clientHeight;\u001b[39m\n\u001b[31m      if(!gw||!gh) return;\u001b[39m\n\u001b[31m      var gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m      for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m        var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m        var w=(gw-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m        var h=w*asp;\u001b[39m\n\u001b[31m        if(rows*h+(rows-1)*gap<=gh&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m      grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m      grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m      var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m      var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m      var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    window._screenSizeThumbs=sizeThumbs;\u001b[39m\n\u001b[31m    requestAnimationFrame(function(){requestAnimationFrame(sizeThumbs);});\u001b[39m\n\u001b[31m    window.addEventListener('resize',sizeThumbs);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m</scr`+'ipt>'+`\u001b[39m\n\u001b[31m</body></html>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncToPostgres(entry) {\u001b[39m\n\u001b[31m  const d   = entry.data || {};\u001b[39m\n\u001b[31m  const hub = _recceHubUser();·\u001b[39m\n\u001b[31m  // Step 1 — upload all photos to VPS, get permanent server URLs\u001b[39m\n\u001b[31m  let photoUrls = { front:[], inside:[], brandings:[], addl:[], doc:null };\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const pResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type: 'save-photos', subId: entry.id,\u001b[39m\n\u001b[31m        photos: {\u001b[39m\n\u001b[31m          front:    (d.frontPhotos||[]).map(p=>({b64:p.b64,   cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64,  cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||null})),\u001b[39m\n\u001b[31m          addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64,   desc:p.desc||''})),\u001b[39m\n\u001b[31m          doc:      d.docB64 || null,\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (pResp.ok) { const r=await pResp.json(); if(r.success) {\u001b[39m\n\u001b[31m      photoUrls=r.photoUrls;\u001b[39m\n\u001b[31m      // Merge retained existing URLs for edit re-submits\u001b[39m\n\u001b[31m      if (entry.editedAt) {\u001b[39m\n\u001b[31m        photoUrls.front    =(photoUrls.front   ||[]).map((u,i)=>u||(d.frontPhotos  ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.inside   =(photoUrls.inside  ||[]).map((u,i)=>u||(d.insidePhotos ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.addl     =(photoUrls.addl    ||[]).map((u,i)=>u||(d.addlPhotos   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.brandings=(photoUrls.brandings||[]).map((u,i)=>u||(d.brandings   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        if(!photoUrls.doc) photoUrls.doc=d._docExistingUrl||null;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }}\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-photos] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 1.5 — trigger Google Slides via proxy using permanent photo URLs (fire-and-forget)\u001b[39m\n\u001b[31m  (async()=>{try{\u001b[39m\n\u001b[31m    const _hasPh=(photoUrls.front||[]).some(Boolean)||(photoUrls.inside||[]).some(Boolean)||(photoUrls.brandings||[]).some(Boolean);\u001b[39m\n\u001b[31m    if(!_hasPh)return;\u001b[39m\n\u001b[31m    const _gu=(await cfg('slides-gas-url'))||(await cfg('gas-url'))||DEFAULT_GAS_URL;if(!_gu)return;\u001b[39m\n\u001b[31m    await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({\u001b[39m\n\u001b[31m      type:'make-slides',gasUrl:_gu,subId:entry.id,\u001b[39m\n\u001b[31m      storeInfo:{storeName:d.storeName||'',brand:d.brand||'',address:d.address||'',mobile:d.mobile||'',date:d.date||'',city:d.city||'',gpsCoords:d.gpsCoords||null},\u001b[39m\n\u001b[31m      photoGroups:{\u001b[39m\n\u001b[31m        front:    (photoUrls.front   ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.frontPhotos  ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        inside:   (photoUrls.inside  ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.insidePhotos ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        brandings:(photoUrls.brandings||[]).filter(Boolean).map((url,i)=>({url,meta:{type:(d.brandings||[])[i]?.type,w:(d.brandings||[])[i]?.w,h:(d.brandings||[])[i]?.h,qty:(d.brandings||[])[i]?.qty,sqft:(d.brandings||[])[i]?.sqft}})),\u001b[39m\n\u001b[31m        addl:    (photoUrls.addl    ||[]).filter(Boolean).map((url,i)=>({url,desc:(d.addlPhotos  ||[])[i]?.desc||''})),\u001b[39m\n\u001b[31m      },\u001b[39m\n\u001b[31m    })});\u001b[39m\n\u001b[31m    entry.gasAt=new Date().toISOString();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[recce-slides]',e.message);}}\u001b[39m\n\u001b[31m  )();·\u001b[39m\n\u001b[31m  // Step 2 — generate rich HTML report using server URLs, save to VPS\u001b[39m\n\u001b[31m  let view_url = null;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const html  = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m    const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-view', subId: entry.id, html })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (vResp.ok) { const r=await vResp.json(); if(r.success) view_url=r.url; }\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-view] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 3 — upsert to PostgreSQL with photo URLs + view URL\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch(`${_RC_BASE}/submissions`, {\u001b[39m\n\u001b[31m      method: 'POST', headers: _RC_UPSERT,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        sub_id:         entry.id,\u001b[39m\n\u001b[31m        store_name:     d.storeName    || 'Unknown',\u001b[39m\n\u001b[31m        brand:          d.brand        || null,\u001b[39m\n\u001b[31m        client_name:    d.clientName   || null,\u001b[39m\n\u001b[31m        visit_date:     d.date         || new Date().toISOString().slice(0,10),\u001b[39m\n\u001b[31m        address:        d.address      || null,\u001b[39m\n\u001b[31m        mobile:         d.mobile       || null,\u001b[39m\n\u001b[31m        city:           d.city         || null,\u001b[39m\n\u001b[31m        has_branding:   !!(d.brandings?.length),\u001b[39m\n\u001b[31m        branding_count: d.brandings?.length || 0,\u001b[39m\n\u001b[31m        has_video:      !!d.hasVideo,\u001b[39m\n\u001b[31m        front_photos:   d.frontPhotos?.length  || 0,\u001b[39m\n\u001b[31m        inside_photos:  d.insidePhotos?.length || 0,\u001b[39m\n\u001b[31m        addl_photos:    d.addlPhotos?.length   || 0,\u001b[39m\n\u001b[31m        gps_lat:        d.gpsCoords?.lat       || null,\u001b[39m\n\u001b[31m        gps_lng:        d.gpsCoords?.lng       || null,\u001b[39m\n\u001b[31m        submitted_by:   hub.empId              || null,\u001b[39m\n\u001b[31m        submitted_at:   entry.timestamp,\u001b[39m\n\u001b[31m        campaign_id:    entry.campaignId       || null,\u001b[39m\n\u001b[31m        photo_urls:     photoUrls,\u001b[39m\n\u001b[31m        view_url,\u001b[39m\n\u001b[31m        meta: {\u001b[39m\n\u001b[31m          brandings: (d.brandings||[]).map(b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft})),\u001b[39m\n\u001b[31m          videoNote: d.videoNote || null,\u001b[39m\n\u001b[31m          videoCmt:  d.videoCmt  || null,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        status: 'submitted',\u001b[39m\n\u001b[31m        edit_assigned_to: null,\u001b[39m\n\u001b[31m        edit_comment: null,\u001b[39m\n\u001b[31m        edited_at: entry.editedAt || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    return { ok: true, viewUrl: view_url };\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    console.warn('[recce-db] sync error:', e.message);\u001b[39m\n\u001b[31m    return { ok: false, viewUrl: null };\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mconst DEFAULT_ADMIN_HASH='42d372e6110bee134990ac6881c3d5eb568482008add9a859f37f10d759430e8';·\u001b[39m\n\u001b[31masync function saveGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('gas-url',url||DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  toast('Endpoint saved','success');\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function testEndpoint(){\u001b[39m\n\u001b[31m  const url=(await cfg('gas-url'))||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  try{await fetch(url,{method:'POST',mode:'no-cors',body:JSON.stringify({test:true})});toast('Endpoint reachable ✓','success');}\u001b[39m\n\u001b[31m  catch{toast('Cannot reach endpoint','error')}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  cfg('gas-url').then(url=>{\u001b[39m\n\u001b[31m    const u=url||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    // Show last 30 chars only for privacy\u001b[39m\n\u001b[31m    el.textContent='Endpoint: …'+u.slice(-30);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── SLIDES GAS URL ────────────────────────────────────────────\u001b[39m\n\u001b[31masync function saveSlidesGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('slides-gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('slides-gas-url', url);\u001b[39m\n\u001b[31m  toast('Slides GAS URL saved','success');\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function updateSlidesGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('slides-gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  const u=await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  el.textContent=u?'Configured: …'+u.slice(-30):'Not configured';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── MAKE SLIDES ───────────────────────────────────────────────\u001b[39m\n\u001b[31masync function makeSlides(id){\u001b[39m\n\u001b[31m  const gasUrl = await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  if(!gasUrl){\u001b[39m\n\u001b[31m    toast('Configure Slides GAS URL in Settings first','error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const entry = await dbGet('subs', id);\u001b[39m\n\u001b[31m  if(!entry){ toast('Entry not found','error'); return; }\u001b[39m\n\u001b[31m  const d = entry.data;·\u001b[39m\n\u001b[31m  toast('Uploading photos & generating slides…','info');·\u001b[39m\n\u001b[31m  // Build photo groups payload\u001b[39m\n\u001b[31m  const photoGroups = {\u001b[39m\n\u001b[31m    front:    (d.frontPhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64, cmt:p.desc||''})),\u001b[39m\n\u001b[31m    brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||'', meta:{type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft}})),\u001b[39m\n\u001b[31m  };·\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type:       'recce',\u001b[39m\n\u001b[31m        subId:      id,\u001b[39m\n\u001b[31m        gasUrl:     gasUrl,\u001b[39m\n\u001b[31m        storeInfo:  {\u001b[39m\n\u001b[31m          storeName: d.storeName, brand: d.brand,\u001b[39m\n\u001b[31m          date: d.date, address: d.address,\u001b[39m\n\u001b[31m          mobile: d.mobile, gpsCoords: d.gpsCoords,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        photoGroups,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const result = await resp.json();\u001b[39m\n\u001b[31m    if(result.success && result.slideUrl){\u001b[39m\n\u001b[31m      // Store slide URL on the entry\u001b[39m\n\u001b[31m      entry.slideUrl = result.slideUrl;\u001b[39m\n\u001b[31m      await dbPut('subs', entry);\u001b[39m\n\u001b[31m      toast('✅ Slides ready!','success');\u001b[39m\n\u001b[31m      window.open(result.slideUrl, '_blank');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast('Slides error: '+(result.error||'Unknown'),'error');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e){\u001b[39m\n\u001b[31m    toast('Network error: '+e.message,'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN LOGIN ──────────────────────────────────────────────\u001b[39m\n\u001b[31mfunction showAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-error').style.display='none';\u001b[39m\n\u001b[31m  // Restore saved config URL\u001b[39m\n\u001b[31m  cfg('admin-cfg-url').then(u=>{if(u&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=u;});\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('admin-pwd').focus(),100);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveAdminCfgUrl(){\u001b[39m\n\u001b[31m  // Admin cfg URL can be saved without login (needed to set up auth itself)\u001b[39m\n\u001b[31m  // But we warn if saving while unlocked only\u001b[39m\n\u001b[31m  const url=document.getElementById('admin-cfg-url').value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  await cfg('admin-cfg-url',url);\u001b[39m\n\u001b[31m  toast('Config URL saved — will use on next login attempt','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function verifyAdmin(){\u001b[39m\n\u001b[31m  // Hub admins (harish/pramod) are auto-unlocked — no password needed\u001b[39m\n\u001b[31m  if (_adminUnlocked) { adminLoginSuccess(); return; }\u001b[39m\n\u001b[31m  const pwd=document.getElementById('admin-pwd').value;\u001b[39m\n\u001b[31m  if(!pwd){document.getElementById('admin-error').style.display='block';document.getElementById('admin-error').textContent='Enter password';return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('admin-login-btn');btn.disabled=true;btn.textContent='Verifying…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // Try server verification first\u001b[39m\n\u001b[31m    const cfgUrl=(await cfg('admin-cfg-url'))||'';\u001b[39m\n\u001b[31m    if(cfgUrl){\u001b[39m\n\u001b[31m      const r=await fetch(cfgUrl,{cache:'no-store'});\u001b[39m\n\u001b[31m      const j=await r.json();\u001b[39m\n\u001b[31m      // Server JSON format: {\\\"password\\\":\\\"plaintext\\\"} or {\\\"hash\\\":\\\"sha256hash\\\"}\u001b[39m\n\u001b[31m      let match=false;\u001b[39m\n\u001b[31m      if(j.password){match=(j.password===pwd);}\u001b[39m\n\u001b[31m      else if(j.hash){\u001b[39m\n\u001b[31m        // SHA-256 comparison\u001b[39m\n\u001b[31m        const enc=new TextEncoder();\u001b[39m\n\u001b[31m        const data=enc.encode(pwd);\u001b[39m\n\u001b[31m        const hashBuf=await crypto.subtle.digest('SHA-256',data);\u001b[39m\n\u001b[31m        const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m        match=(hashHex===j.hash);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      if(match){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m      else{showAdminError('Incorrect password');return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Fallback: local password stored in settings\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if(localHash){\u001b[39m\n\u001b[31m      const enc=new TextEncoder();\u001b[39m\n\u001b[31m      const hashBuf=await crypto.subtle.digest('SHA-256',enc.encode(pwd));\u001b[39m\n\u001b[31m      const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m      if(hashHex===localHash){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Final fallback: check against hardcoded default hash\u001b[39m\n\u001b[31m    const enc2=new TextEncoder();\u001b[39m\n\u001b[31m    const hb2=await crypto.subtle.digest('SHA-256',enc2.encode(pwd));\u001b[39m\n\u001b[31m    const hh2=Array.from(new Uint8Array(hb2)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    if(hh2===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }catch(err){\u001b[39m\n\u001b[31m    // Network error — try all local fallbacks\u001b[39m\n\u001b[31m    const enc3=new TextEncoder();\u001b[39m\n\u001b[31m    const hb3=await crypto.subtle.digest('SHA-256',enc3.encode(pwd));\u001b[39m\n\u001b[31m    const hh3=Array.from(new Uint8Array(hb3)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if((localHash&&hh3===localHash)||hh3===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }finally{btn.disabled=false;btn.textContent='Login';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showAdminError(msg){\u001b[39m\n\u001b[31m  const el=document.getElementById('admin-error');\u001b[39m\n\u001b[31m  el.textContent=msg;el.style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminLoginSuccess(){\u001b[39m\n\u001b[31m  _adminUnlocked=true;\u001b[39m\n\u001b[31m  closeAdminLogin();\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  cfg('gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  cfg('slides-gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('slides-gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||'';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  toast('Admin mode unlocked','success');\u001b[39m\n\u001b[31m  setTimeout(lockAdmin,10*60*1000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction lockAdmin(){\u001b[39m\n\u001b[31m  _adminUnlocked=false;\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  toast('Admin session ended','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updAvailTag(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-avail-tag');\u001b[39m\n\u001b[31m  const ct=document.getElementById('store-avail-count');\u001b[39m\n\u001b[31m  const txt=stores.length?`${stores.length} stores`:'No store list';\u001b[39m\n\u001b[31m  if(el)el.textContent=txt;\u001b[39m\n\u001b[31m  if(ct)ct.textContent=stores.length?t(`${stores.length} stores available — tap to browse`,`${stores.length} स्टोर उपलब्ध — दबाएं`):t('No store list loaded yet','कोई स्टोर सूची नहीं');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PICKER\u001b[39m\n\u001b[31mfunction openPicker(){\u001b[39m\n\u001b[31m  if(!stores.length){toast('Load a store list in Settings first','error');return;}\u001b[39m\n\u001b[31m  document.getElementById('povl').classList.add('open');\u001b[39m\n\u001b[31m  document.getElementById('psearch').value='';\u001b[39m\n\u001b[31m  filterPicker('');\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('psearch').focus(),150);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closePicker(){document.getElementById('povl').classList.remove('open');}\u001b[39m\n\u001b[31masync function filterPicker(q){\u001b[39m\n\u001b[31m  const list=document.getElementById('plist');\u001b[39m\n\u001b[31m  const words=q.toLowerCase().trim().split(/\\\\s+/).filter(Boolean);\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const lastVisit={};\u001b[39m\n\u001b[31m  subs.forEach(s=>{const nm=s.data?.storeName;if(nm&&(!lastVisit[nm]||s.timestamp>lastVisit[nm]))lastVisit[nm]=s.timestamp;});·\u001b[39m\n\u001b[31m  // Multi-word: ALL words must match somewhere in any field (search across both English and Hindi)\u001b[39m\n\u001b[31m  let fl=stores.filter(s=>{\u001b[39m\n\u001b[31m    if(!words.length)return true;\u001b[39m\n\u001b[31m    const hay=[s.name,s.nameHi,s.address,s.addressHi,s.mobile,s.city,s.cityHi,s.distName,s.distNameHi,s.brand,s.sales,s.proj,s.glowSign,s.inshop]\u001b[39m\n\u001b[31m               .map(x=>(x||'').toLowerCase()).join(' ');\u001b[39m\n\u001b[31m    return words.every(w=>hay.includes(w));\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(fl.length>100)fl=fl.slice(0,100);·\u001b[39m\n\u001b[31m  if(!fl.length){\u001b[39m\n\u001b[31m    const esc=q.replace(/'/g,\\\"\\\\\\\\'\\\");\u001b[39m\n\u001b[31m    list.innerHTML=`<div style=\\\"text-align:center;padding:32px 16px;color:var(--g400);font-size:14px\\\">No stores match \\\"${q}\\\"<br><span style=\\\"font-size:12px\\\">Try fewer or different words</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('${esc}')\\\">+ Add \\\"${q}\\\" as new store</div>`;\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Group by brand (including empty brand)\u001b[39m\n\u001b[31m  const g={};\u001b[39m\n\u001b[31m  fl.forEach(s=>{\u001b[39m\n\u001b[31m    const b=s.brand||'(No Brand — will ask)';\u001b[39m\n\u001b[31m    if(!g[b])g[b]=[];\u001b[39m\n\u001b[31m    g[b].push(s);\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html='';\u001b[39m\n\u001b[31m  Object.keys(g).sort().forEach(br=>{\u001b[39m\n\u001b[31m    html+=`<div class=\\\"psec\\\">${br}</div>`;\u001b[39m\n\u001b[31m    g[br].forEach(s=>{\u001b[39m\n\u001b[31m      const lv=lastVisit[s.name];\u001b[39m\n\u001b[31m      const lvStr=lv?`🕐 Last: ${new Date(lv).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'2-digit'})}`:'';\u001b[39m\n\u001b[31m      const chips=[];\u001b[39m\n\u001b[31m      if(s.glowSign&&s.glowSign.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dcfce7;color:#14532d;padding:2px 6px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m      if(s.inshop&&s.inshop.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dbeafe;color:#1e40af;padding:2px 6px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m      if(s.proj)chips.push(`<span style=\\\"font-size:10px;background:var(--g100);color:var(--g600);padding:2px 6px;border-radius:10px\\\">Target: ${s.proj}</span>`);\u001b[39m\n\u001b[31m      const enc=JSON.stringify(s).replace(/\\\"/g,'&quot;');\u001b[39m\n\u001b[31m      const mapsUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m      const waUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const telUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const dispName=LANG==='hi'&&s.nameHi?s.nameHi:s.name;\u001b[39m\n\u001b[31m      const dispAddr=LANG==='hi'&&s.addressHi?s.addressHi:s.address;\u001b[39m\n\u001b[31m      const dispDist=LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m      html+=`<div class=\\\"pitem\\\" onclick=\\\"pickStore(${enc})\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"pi-name\\\">${dispName}</div>\u001b[39m\n\u001b[31m          ${dispAddr?`<div class=\\\"pi-addr\\\">📍 ${dispAddr}</div>`:''}\u001b[39m\n\u001b[31m          ${s.mobile?`<div class=\\\"pi-addr\\\">📞 ${s.mobile}</div>`:''}\u001b[39m\n\u001b[31m          ${dispDist?`<div class=\\\"pi-addr\\\" style=\\\"color:var(--am)\\\">👤 ${dispDist}</div>`:''}\u001b[39m\n\u001b[31m          ${lvStr?`<div class=\\\"pi-last\\\">${lvStr}</div>`:''}\u001b[39m\n\u001b[31m          ${chips.length?`<div style=\\\"display:flex;gap:4px;flex-wrap:wrap;margin-top:4px\\\">${chips.join('')}</div>`:''}\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;gap:6px;margin-top:7px\\\" onclick=\\\"event.stopPropagation()\\\">\u001b[39m\n\u001b[31m            ${mapsUrl?`<a href=\\\"${mapsUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#e0f2fe;color:#0369a1;border-radius:20px;text-decoration:none;font-weight:600\\\">🗺 Maps</a>`:''}\u001b[39m\n\u001b[31m            ${waUrl?`<a href=\\\"${waUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#dcfce7;color:#15803d;border-radius:20px;text-decoration:none;font-weight:600\\\">💬 WhatsApp</a>`:''}\u001b[39m\n\u001b[31m            ${telUrl?`<a href=\\\"${telUrl}\\\" style=\\\"font-size:11px;padding:4px 10px;background:#f0fdf4;color:#166534;border-radius:20px;text-decoration:none;font-weight:600\\\">📞 Call</a>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        ${s.brand?`<div class=\\\"pi-brand\\\">${s.brand}</div>`:'<div class=\\\"pi-brand\\\" style=\\\"background:var(--rd)\\\">?</div>'}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html+=`<div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('')\\\">+ Not in list? Add new store</div>`;\u001b[39m\n\u001b[31m  list.innerHTML=html;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function pickStore(s){\u001b[39m\n\u001b[31m  selectedStore=s;manualMode=false;closePicker();\u001b[39m\n\u001b[31m  const _dn =LANG==='hi'&&s.nameHi    ?s.nameHi    :s.name;\u001b[39m\n\u001b[31m  const _da =LANG==='hi'&&s.addressHi ?s.addressHi :s.address;\u001b[39m\n\u001b[31m  const _dd =LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m  const _dc =LANG==='hi'&&s.cityHi    ?s.cityHi    :s.city;\u001b[39m\n\u001b[31m  document.getElementById('sc-name').textContent=_dn;\u001b[39m\n\u001b[31m  const brandEl=document.getElementById('sc-brand');\u001b[39m\n\u001b[31m  brandEl.textContent=s.brand||'No Brand';brandEl.style.background=s.brand?'var(--nv)':'var(--rd)';\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const prev=subs.filter(x=>x.data?.storeName===s.name).sort((a,b)=>new Date(b.timestamp)-new Date(a.timestamp))[0];\u001b[39m\n\u001b[31m  const lc=document.getElementById('sc-last');\u001b[39m\n\u001b[31m  if(prev){const d=new Date(prev.timestamp);lc.textContent='Last: '+d.toLocaleDateString('en-IN',{day:'numeric',month:'short'});lc.style.display='inline-flex';}\u001b[39m\n\u001b[31m  else lc.style.display='none';\u001b[39m\n\u001b[31m  // All Excel fields — display in active language\u001b[39m\n\u001b[31m  const mUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m  const wUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const tUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const details=[];\u001b[39m\n\u001b[31m  if(_da)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📍 ${_da}${mUrl?` <a href=\\\"${mUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#0369a1;margin-left:6px\\\">🗺 Navigate</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(s.mobile)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📞 ${s.mobile}${tUrl?` <a href=\\\"${tUrl}\\\" style=\\\"font-size:11px;color:#166534;margin-left:6px\\\">Call</a>`:''}${wUrl?` <a href=\\\"${wUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#15803d;margin-left:6px\\\">WhatsApp</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(_dd)details.push(`<div style=\\\"font-size:12px;color:var(--am)\\\">👤 ${_dd}</div>`);\u001b[39m\n\u001b[31m  if(_dc)details.push(`<div style=\\\"font-size:12px;color:var(--g500)\\\">🏙 ${_dc}</div>`);\u001b[39m\n\u001b[31m  const opp=[];\u001b[39m\n\u001b[31m  if(s.glowSign&&s.glowSign.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dcfce7;color:#14532d;padding:2px 7px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m  if(s.inshop&&s.inshop.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dbeafe;color:#1e40af;padding:2px 7px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m  if(s.proj)opp.push(`<span style=\\\"font-size:11px;background:var(--g100);color:var(--g600);padding:2px 7px;border-radius:10px\\\">Target 2026: ${s.proj}</span>`);\u001b[39m\n\u001b[31m  if(opp.length)details.push(`<div style=\\\"display:flex;gap:5px;flex-wrap:wrap;margin-top:3px\\\">${opp.join('')}</div>`);\u001b[39m\n\u001b[31m  document.getElementById('sc-details').innerHTML=details.join('');\u001b[39m\n\u001b[31m  // Missing fields\u001b[39m\n\u001b[31m  const missing=[];\u001b[39m\n\u001b[31m  if(!s.address)missing.push({key:'address',label:'Store Address',type:'textarea',placeholder:'Full address'});\u001b[39m\n\u001b[31m  if(!s.mobile)missing.push({key:'mobile',label:'Mobile No.',type:'tel',placeholder:'10-digit number',maxlen:'10'});\u001b[39m\n\u001b[31m  const mw=document.getElementById('sc-missing'),mf=document.getElementById('sc-missing-fields');\u001b[39m\n\u001b[31m  if(missing.length){\u001b[39m\n\u001b[31m    mf.innerHTML=missing.map(m=>`<div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\"><label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">${m.label} <span class=\\\"req\\\">*</span></label>${m.type==='textarea'?`<textarea id=\\\"sc-miss-${m.key}\\\" rows=\\\"2\\\" placeholder=\\\"${m.placeholder}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></textarea>`:`<input type=\\\"${m.type}\\\" id=\\\"sc-miss-${m.key}\\\" placeholder=\\\"${m.placeholder}\\\" ${m.maxlen?`maxlength=\\\"${m.maxlen}\\\"`:''}  inputmode=\\\"${m.type==='tel'?'numeric':'text'}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\">`}</div>`).join('');\u001b[39m\n\u001b[31m    mw.style.display='block';\u001b[39m\n\u001b[31m  } else {mw.style.display='none';}\u001b[39m\n\u001b[31m  // Brand selector\u001b[39m\n\u001b[31m  const bSel=document.getElementById('brand-selector'),bChips=document.getElementById('brand-chips');\u001b[39m\n\u001b[31m  if(!s.brand){\u001b[39m\n\u001b[31m    renderBrandChips();\u001b[39m\n\u001b[31m    bSel.style.display='block';\u001b[39m\n\u001b[31m  } else {bSel.style.display='none';}\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  F.storeName=s.name;F.brand=s.brand||'';F.address=s.address||'';F.mobile=s.mobile||'';\u001b[39m\n\u001b[31m  if(s.brand&&!_selectedClient&&!_clientOtherMode) autoSetClient(s.brand);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateMissingField(key,val){if(!selectedStore)return;selectedStore[key]=val.trim();F[key]=val.trim();saveDraft();}\u001b[39m\n\u001b[31mfunction selectStoreBrand(b){\u001b[39m\n\u001b[31m  F.brand=b;F.brandLogoUrl=_brandLogos[b]||'';\u001b[39m\n\u001b[31m  if(selectedStore)selectedStore.brand=b;\u001b[39m\n\u001b[31m  const el=document.getElementById('sc-brand');if(el){el.textContent=b;el.style.background='var(--nv)';}\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-chips .chip').forEach(c=>{c.classList.toggle('sel',c.querySelector('span')?.textContent===b||c.textContent.trim()===b);});\u001b[39m\n\u001b[31m  if(!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction onManualBrandChange(){\u001b[39m\n\u001b[31m  const b=document.getElementById('f-brand')?.value||'';\u001b[39m\n\u001b[31m  F.brandLogoUrl=b?(_brandLogos[b]||''):'';\u001b[39m\n\u001b[31m  if(b&&!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction openManual(prefill){\u001b[39m\n\u001b[31m  manualMode=true;\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').classList.add('on');\u001b[39m\n\u001b[31m  document.getElementById('mt-label').innerHTML='← Back to store list';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='block';\u001b[39m\n\u001b[31m  // Pre-fill from selectedStore if available (e.g. when toggling after picker selection)\u001b[39m\n\u001b[31m  const s=selectedStore;\u001b[39m\n\u001b[31m  if(s){\u001b[39m\n\u001b[31m    if(document.getElementById('f-brand'))document.getElementById('f-brand').value=s.brand||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-store'))document.getElementById('f-store').value=s.name||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-addr'))document.getElementById('f-addr').value=s.address||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-mobile'))document.getElementById('f-mobile').value=s.mobile||'';\u001b[39m\n\u001b[31m  } else if(prefill){\u001b[39m\n\u001b[31m    document.getElementById('f-store').value=prefill;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  selectedStore=null;\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction toggleManual(){\u001b[39m\n\u001b[31m  if(manualMode){\u001b[39m\n\u001b[31m    manualMode=false;\u001b[39m\n\u001b[31m    document.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31m    document.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31m    document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    openManual('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// GPS\u001b[39m\n\u001b[31mfunction captureGPS(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gps-status');el.textContent='Getting location…';el.style.color='var(--g500)';\u001b[39m\n\u001b[31m  if(!navigator.geolocation){el.textContent='GPS not available';return;}\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(pos=>{\u001b[39m\n\u001b[31m    gpsCoords={lat:pos.coords.latitude.toFixed(6),lng:pos.coords.longitude.toFixed(6),acc:Math.round(pos.coords.accuracy)};\u001b[39m\n\u001b[31m    el.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${gpsCoords.acc}m)`;el.style.color='var(--gn)';saveDraft();\u001b[39m\n\u001b[31m  },()=>{el.textContent='GPS failed — enter address manually';el.style.color='var(--rd)';},{enableHighAccuracy:true,timeout:10000});\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// DRAFT\u001b[39m\n\u001b[31mlet draftT;\u001b[39m\n\u001b[31mfunction saveDraft(){\u001b[39m\n\u001b[31m  clearTimeout(draftT);\u001b[39m\n\u001b[31m  draftT=setTimeout(async()=>{\u001b[39m\n\u001b[31m    const draft={k:'current',ts:Date.now(),F:{...F,date:document.getElementById('f-date')?.value||'',brand:manualMode?(document.getElementById('f-brand')?.value||''):(selectedStore?.brand||F.brand||''),storeName:selectedStore?selectedStore.name:(document.getElementById('f-store')?.value||''),address:manualMode?(document.getElementById('f-addr')?.value||''):(selectedStore?.address||F.address||''),mobile:manualMode?(document.getElementById('f-mobile')?.value||''):(selectedStore?.mobile||F.mobile||''),clientName:getClientName()},selectedStore,manualMode,gpsCoords,_selectedClient,_clientOtherMode,fCnt:frontPhotos.length,iCnt:insidePhotos.length,bCnt:brandings.length};\u001b[39m\n\u001b[31m    await dbPut('draft',draft);\u001b[39m\n\u001b[31m    // Also save photos as b64 blobs to draft so they survive exit\u001b[39m\n\u001b[31m    await saveDraftPhotos();\u001b[39m\n\u001b[31m  },500);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveDraftPhotos(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const photoData={\u001b[39m\n\u001b[31m      front:await Promise.all(frontPhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      inside:await Promise.all(insidePhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      addl:await Promise.all(addlPhotos.map(async p=>({b64:await b64(p.blob),desc:p.desc||''}))),\u001b[39m\n\u001b[31m      brand:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,b64:b.blob?await b64(b.blob):null})))\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    await dbPut('draft',{k:'photos',...photoData});\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function checkDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');const wrap=document.getElementById('resume-wrap');\u001b[39m\n\u001b[31m  if(!d||!d.F?.storeName){wrap.innerHTML='';return;}\u001b[39m\n\u001b[31m  const ago=Math.round((Date.now()-d.ts)/60000);\u001b[39m\n\u001b[31m  const agoStr=ago<1?'just now':ago<60?`${ago}m ago`:`${Math.round(ago/60)}h ago`;\u001b[39m\n\u001b[31m  wrap.innerHTML=`<button class=\\\"resume-btn\\\" onclick=\\\"resumeDraft()\\\">\u001b[39m\n\u001b[31m    <div><div style=\\\"font-size:12px;color:rgba(255,255,255,.5);margin-bottom:3px\\\">Resume draft · ${agoStr}</div><div>${d.F.storeName} · ${d.F.brand||'No brand'}</div></div>\u001b[39m\n\u001b[31m    <div style=\\\"text-align:right\\\"><div style=\\\"font-size:13px;color:var(--or)\\\">${d.fCnt||0} photos · ${d.bCnt||0} brandings →</div></div>\u001b[39m\n\u001b[31m  </button>`;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function resumeDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');if(!d)return;\u001b[39m\n\u001b[31m  F=d.F||{};gpsCoords=d.gpsCoords||null;\u001b[39m\n\u001b[31m  if(d.selectedStore){await pickStore(d.selectedStore);}\u001b[39m\n\u001b[31m  else if(d.manualMode){openManual('');if(F.brand)document.getElementById('f-brand').value=F.brand;if(F.storeName)document.getElementById('f-store').value=F.storeName;if(F.address)document.getElementById('f-addr').value=F.address;if(F.mobile)document.getElementById('f-mobile').value=F.mobile;}\u001b[39m\n\u001b[31m  if(F.date)document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  // Restore client chip state\u001b[39m\n\u001b[31m  if(d._clientOtherMode){_clientOtherMode=true;_selectedClient='';const inp=document.getElementById('f-client-other');if(inp&&F.clientName)inp.value=F.clientName;}\u001b[39m\n\u001b[31m  else if(d._selectedClient){_selectedClient=d._selectedClient;_clientOtherMode=false;}\u001b[39m\n\u001b[31m  else if(F.clientName){autoSetClient(F.clientName);}\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  // Restore photos from draft\u001b[39m\n\u001b[31m  const pd=await dbGet('draft','photos');\u001b[39m\n\u001b[31m  if(pd){\u001b[39m\n\u001b[31m    async function b64ToBlob(b64str){if(!b64str)return null;try{const r=await fetch(b64str);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m    for(const p of(pd.front||[])){const bl=await b64ToBlob(p.b64);if(bl)frontPhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.inside||[])){const bl=await b64ToBlob(p.b64);if(bl)insidePhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.addl||[])){const bl=await b64ToBlob(p.b64);if(bl)addlPhotos.push({blob:bl,prev:URL.createObjectURL(bl),desc:p.desc||''});}\u001b[39m\n\u001b[31m    for(const b of(pd.brand||[])){const bl=await b64ToBlob(b.b64);brandings.push({type:b.type,w:b.w,h:b.h,qty:b.qty,blob:bl,prev:bl?URL.createObjectURL(bl):null});}\u001b[39m\n\u001b[31m    toast('Draft restored with '+frontPhotos.length+' photos ✓','success');\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    toast('Draft restored — photos could not be recovered','info');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PHOTOS\u001b[39m\n\u001b[31mfunction updPhotoBadge(type){const arr=type==='front'?frontPhotos:insidePhotos;const el=document.getElementById(type+'-badge');if(el){el.textContent=arr.length;el.className='cnt-badge '+(arr.length?'':'gray');}}\u001b[39m\n\u001b[31mfunction renderPhotos(type){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  const cont=document.getElementById(type+'-cont');const addBtn=document.getElementById('add-'+type);\u001b[39m\n\u001b[31m  updPhotoBadge(type);\u001b[39m\n\u001b[31m  if(arr.length===0){cont.innerHTML=`<div class=\\\"pslot\\\" onclick=\\\"addPhoto('${type}')\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to capture or upload</span><span class=\\\"hi-txt\\\">फोटो खींचें या अपलोड करें</span></div></div>`;addBtn.style.display='none';return;}\u001b[39m\n\u001b[31m  cont.innerHTML=arr.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const badge=isRetained?`<span class=\\\"pbadge\\\" style=\\\"background:#475569\\\">Existing</span>`:`<span class=\\\"pbadge\\\">${fmtSz(p.blob.size)}</span>`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replacePhoto('${type}',${i})\\\" style=\\\"right:36px;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"margin-bottom:12px\\\"><div class=\\\"pslot filled\\\" style=\\\"margin-bottom:8px\\\"><img src=\\\"${p.prev}\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmPhoto('${type}',${i})\\\">×</button>${badge}</div><input type=\\\"text\\\" placeholder=\\\"Comments (optional)\\\" value=\\\"${p.cmt||''}\\\" onchange=\\\"${type==='front'?'frontPhotos':'insidePhotos'}[${i}].cmt=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  addBtn.style.display=arr.length<(type==='inside'?5:3)?'inline-flex':'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// Photo source: 'camera' stamps geo, 'gallery' does not\u001b[39m\n\u001b[31mlet _photoSourceCb=null,_photoSourceQuality=null;·\u001b[39m\n\u001b[31mfunction capPhoto(cb,forceSource,quality){\u001b[39m\n\u001b[31m  // quality override: null=use setting, 'hd', 'compressed'\u001b[39m\n\u001b[31m  _photoSourceCb=cb;_photoSourceQuality=quality||null;\u001b[39m\n\u001b[31m  if(forceSource==='camera'){_doCapture(cb,'camera',quality);return;}\u001b[39m\n\u001b[31m  if(forceSource==='gallery'){_doCapture(cb,'gallery',quality);return;}\u001b[39m\n\u001b[31m  // Show picker\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _doCapture(cb,src,quality){\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  const i=document.createElement('input');\u001b[39m\n\u001b[31m  i.type='file';i.accept='image/*';\u001b[39m\n\u001b[31m  if(src==='camera')i.setAttribute('capture','environment');\u001b[39m\n\u001b[31m  i.style.display='none';\u001b[39m\n\u001b[31m  i.onchange=async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f)return;\u001b[39m\n\u001b[31m    const q=quality||_photoSourceQuality||null;\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      const blob=await compress(f,q==='hd'?1920:q==='compressed'?1280:null,q==='hd'?0.90:q==='compressed'?0.78:null);\u001b[39m\n\u001b[31m      // Only stamp if from camera (live photo)\u001b[39m\n\u001b[31m      const stamped=(src==='camera')?await stampPhoto(blob):blob;\u001b[39m\n\u001b[31m      // Save to device (auto-download trigger)\u001b[39m\n\u001b[31m      savePhotoToDevice(stamped);\u001b[39m\n\u001b[31m      cb({target:{files:[f]},_blob:stamped,_src:src});\u001b[39m\n\u001b[31m    }catch(err){toast('Photo processing failed — try again','error');console.error('_doCapture error:',err);}\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  document.body.appendChild(i);i.click();setTimeout(()=>i.remove(),8000);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction photoSrcCamera(){_doCapture(_photoSourceCb,'camera',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcGallery(){_doCapture(_photoSourceCb,'gallery',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcCancel(){document.getElementById('photo-src-dialog').classList.remove('open');_photoSourceCb=null;}·\u001b[39m\n\u001b[31m// Save photo to device gallery/downloads\u001b[39m\n\u001b[31mfunction savePhotoToDevice(blob){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    const a=document.createElement('a');\u001b[39m\n\u001b[31m    a.href=url;\u001b[39m\n\u001b[31m    a.download='Recce_'+Date.now()+'.jpg';\u001b[39m\n\u001b[31m    a.style.display='none';\u001b[39m\n\u001b[31m    document.body.appendChild(a);a.click();\u001b[39m\n\u001b[31m    setTimeout(()=>{URL.revokeObjectURL(url);a.remove();},1000);\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addPhoto(type){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}${e._src==='camera'&&geoStampEnabled?' · Stamped':''}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31masync function handleCapture(e,type){\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmPhoto(type,i){(type==='front'?frontPhotos:insidePhotos).splice(i,1);renderPhotos(type);saveDraft();}\u001b[39m\n\u001b[31mfunction replacePhoto(type,idx){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m    arr[idx]={...arr[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAddl(){\u001b[39m\n\u001b[31m  const cont=document.getElementById('add-cont');const btn=document.getElementById('add-addl');\u001b[39m\n\u001b[31m  const badge=document.getElementById('addl-badge');if(badge){badge.textContent=`${addlPhotos.length} / 8`;badge.className='cnt-badge '+(addlPhotos.length?'':'gray');}\u001b[39m\n\u001b[31m  cont.innerHTML=addlPhotos.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const sizeInfo=isRetained?'<span style=\\\"color:#475569\\\">Existing</span>':`${fmtSz(p.blob.size)}`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replaceAddl(${i})\\\" style=\\\"top:3px;left:3px;right:auto;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;gap:10px;align-items:start;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--g100)\\\"><div style=\\\"position:relative;flex-shrink:0\\\"><img src=\\\"${p.prev}\\\" style=\\\"width:80px;height:80px;object-fit:cover;border-radius:var(--rs)\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmAddl(${i})\\\" style=\\\"top:3px;right:3px\\\">×</button></div><div style=\\\"flex:1\\\"><input type=\\\"text\\\" placeholder=\\\"Description (optional)\\\" value=\\\"${p.desc||''}\\\" onchange=\\\"addlPhotos[${i}].desc=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"><div style=\\\"font-size:11px;color:var(--g400);margin-top:4px\\\">${sizeInfo}</div></div></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  btn.style.display=addlPhotos.length>=8?'none':'inline-flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction addAdditional(){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  addlPhotos.push({blob:bs,prev:URL.createObjectURL(bs),desc:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderAddl();saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31mfunction rmAddl(i){addlPhotos.splice(i,1);renderAddl();saveDraft();}\u001b[39m\n\u001b[31mfunction replaceAddl(idx){\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m    addlPhotos[idx]={...addlPhotos[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderAddl();saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// BRANDING\u001b[39m\n\u001b[31mfunction calcSqft(w,h){const wf=parseFloat(w),hf=parseFloat(h);if(!wf||!hf)return '';return `${(wf*hf).toFixed(0)} sq.in = ${(wf*hf/144).toFixed(2)} sq.ft`;}\u001b[39m\n\u001b[31mfunction renderBrandings(){\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  const cont=document.getElementById('br-items');\u001b[39m\n\u001b[31m  const hb=document.getElementById('br-hdr-badge');if(hb)hb.textContent=`${brandings.length} ${t(brandings.length!==1?'items':'item',brandings.length!==1?'आइटम':'आइटम')}`;\u001b[39m\n\u001b[31m  cont.innerHTML=brandings.map((b,i)=>`<div class=\\\"bitem\\\"><div class=\\\"bitem-hdr\\\"><div class=\\\"bitem-title\\\">${t('Branding','ब्रांडिंग')} ${i+1}${b.type?' — '+b.type:''}</div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:6px\\\">${i>0?`<button class=\\\"btn-d\\\" onclick=\\\"dupBr(${i})\\\" style=\\\"color:var(--or);border-color:var(--orl)\\\">${t('Dup ↑','डुप ↑')}</button>`:''}<button class=\\\"btn-d\\\" onclick=\\\"rmBr(${i})\\\">${t('Remove','हटाएं')}</button></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\"><label>${t('Type','प्रकार')} <span class=\\\"req\\\">*</span></label><div class=\\\"chip-grid\\\">${BTYPE.map(tp=>`<div class=\\\"chip${b.type===tp?' sel':''}\\\" onclick=\\\"setBType(${i},'${tp.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\"> ${tp}</div>`).join('')}</div></div>\u001b[39m\n\u001b[31m    <div class=\\\"dim-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Width (in)','चौड़ाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.w||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].w=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Height (in)','ऊंचाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.h||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].h=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"max-width:74px\\\"><label>${t('Qty','मात्रा')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.qty||''}\\\" placeholder=\\\"1\\\" inputmode=\\\"numeric\\\" onchange=\\\"brandings[${i}].qty=this.value;saveDraft()\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <span class=\\\"sqft\\\" id=\\\"sf${i}\\\">${calcSqft(b.w,b.h)||t('Enter W × H','W × H दर्ज करें')}</span>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-top:12px\\\"><label>${t('Photo','फोटो')} <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      ${b.prev?`<div class=\\\"pslot filled\\\" onclick=\\\"capBr(${i})\\\"><img src=\\\"${b.prev}\\\"><button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();rmBrPh(${i})\\\">×</button><span class=\\\"pbadge\\\">${b.blob?fmtSz(b.blob.size):'Existing'}</span></div>`:`<div><div class=\\\"pslot\\\" onclick=\\\"capBr(${i})\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\">${t('Tap to capture','दबाकर कैप्चर करें')}</div></div><div style=\\\"display:flex;gap:6px;margin-top:6px\\\"><button class=\\\"atool${(b.quality||imgQuality)==='compressed'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'compressed');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">${t('Compressed','कम्प्रेस्ड')}</button><button class=\\\"atool${(b.quality||imgQuality)==='hd'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'hd');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">HD</button></div></div>`}\u001b[39m\n\u001b[31m    </div></div>`).join('');\u001b[39m\n\u001b[31m  // Only show \\\"Add Another\\\" when last item is fully complete\u001b[39m\n\u001b[31m  const addDiv=document.getElementById('br-add');\u001b[39m\n\u001b[31m  if(addDiv&&brandings.length>0){\u001b[39m\n\u001b[31m    const last=brandings[brandings.length-1];\u001b[39m\n\u001b[31m    const lastComplete=last.type&&last.w&&last.h&&last.qty&&last.prev;\u001b[39m\n\u001b[31m    addDiv.style.display=(lastComplete&&brandings.length<15)?'block':'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updSqft(i){const el=document.getElementById('sf'+i);if(el)el.textContent=calcSqft(brandings[i].w,brandings[i].h)||t('Enter W × H','W × H दर्ज करें');saveDraft();}\u001b[39m\n\u001b[31mfunction setBType(i,tp){brandings[i].type=tp;renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction addBranding(){if(brandings.length>=15){toast(t('Max 15 items','अधिकतम 15 आइटम'),'error');return;}brandings.push({type:'',w:'',h:'',qty:'1',blob:null,prev:null});renderBrandings();}\u001b[39m\n\u001b[31mfunction dupBr(i){if(brandings.length>=10){toast(t('Max 10 items','अधिकतम 10 आइटम'),'error');return;}const s=brandings[i-1];brandings.splice(i,0,{type:s.type,w:s.w,h:s.h,qty:s.qty,blob:null,prev:null});renderBrandings();toast(t('Duplicated — add photo','डुप्लीकेट — फोटो जोड़ें'),'info');}\u001b[39m\n\u001b[31mfunction rmBr(i){brandings.splice(i,1);renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction capBr(i){\u001b[39m\n\u001b[31m  const q=brandings[i]?.quality||imgQuality;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f,q==='hd'?1920:1280,q==='hd'?0.90:0.78));\u001b[39m\n\u001b[31m    brandings[i].blob=bs;brandings[i].prev=URL.createObjectURL(bs);\u001b[39m\n\u001b[31m    brandings[i].fromCamera=(e._src==='camera');\u001b[39m\n\u001b[31m    openAnnot(i);\u001b[39m\n\u001b[31m  },null,q);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmBrPh(i){brandings[i].blob=null;brandings[i].prev=null;renderBrandings();}\u001b[39m\n\u001b[31mfunction setBrQuality(i,q){brandings[i].quality=q;renderBrandings();}·\u001b[39m\n\u001b[31m// VIDEO / DOC\u001b[39m\n\u001b[31mfunction setVideo(v){F.hasVideo=v;document.getElementById('vid-yes').classList.toggle('sel',v);document.getElementById('vid-no').classList.toggle('sel',!v);document.getElementById('vid-sec').style.display=v?'block':'none';saveDraft();}\u001b[39m\n\u001b[31masync function handleVideo(e){videoBlob=e.target.files[0];if(!videoBlob)return;document.getElementById('vid-slot').innerHTML=`<div style=\\\"padding:14px;font-size:13px;color:var(--gn)\\\">✓ ${videoBlob.name} (${fmtSz(videoBlob.size)})</div>`;}\u001b[39m\n\u001b[31mfunction setBranding(v){F.hasBranding=v;document.getElementById('br-yes').classList.toggle('sel',v);document.getElementById('br-no').classList.toggle('sel',!v);document.getElementById('br-add').style.display=v?'block':'none';if(v&&brandings.length===0)addBranding();saveDraft();}\u001b[39m\n\u001b[31masync function handleDoc(e){const f=e.target.files[0];if(!f)return;submissionDoc=f.type.startsWith('image/')?await compress(f,1600,.85):f;const slot=document.getElementById('doc-slot');if(f.type.startsWith('image/')){slot.classList.add('filled');slot.innerHTML=`<img src=\\\"${URL.createObjectURL(submissionDoc)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}else{slot.innerHTML=`<div style=\\\"padding:16px;font-size:13px;color:var(--gn)\\\">✓ ${f.name} (${fmtSz(f.size)})</div>`;}buildReview();}·\u001b[39m\n\u001b[31m// CLIENT CHIPS\u001b[39m\n\u001b[31mfunction renderClientChips(){\u001b[39m\n\u001b[31m  const grid = document.getElementById('client-chips'); if (!grid) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  clientList.forEach(c => {\u001b[39m\n\u001b[31m    const sel = !_clientOtherMode && _selectedClient === c;\u001b[39m\n\u001b[31m    html += `<div class=\\\"cl-chip${sel?' sel':''}\\\" onclick=\\\"selectClientChip('${esc(c)}')\\\">${esc(c)}</div>`;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html += `<div class=\\\"cl-chip cl-chip-other${_clientOtherMode?' sel':''}\\\" onclick=\\\"selectClientOther()\\\"><span class=\\\"en-txt\\\">Other…</span><span class=\\\"hi-txt\\\">अन्य…</span></div>`;\u001b[39m\n\u001b[31m  grid.innerHTML = html;\u001b[39m\n\u001b[31m  document.getElementById('client-other-wrap').style.display = _clientOtherMode ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientChip(name){\u001b[39m\n\u001b[31m  _selectedClient = name; _clientOtherMode = false;\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').value = '';\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientOther(){\u001b[39m\n\u001b[31m  _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onClientOtherInput(){\u001b[39m\n\u001b[31m  _selectedClient = document.getElementById('f-client-other').value.trim();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction getClientName(){\u001b[39m\n\u001b[31m  if (_clientOtherMode) return (document.getElementById('f-client-other')?.value||'').trim();\u001b[39m\n\u001b[31m  return _selectedClient;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction autoSetClient(brandName){\u001b[39m\n\u001b[31m  if (!brandName) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  if (clientList.includes(brandName)){\u001b[39m\n\u001b[31m    _selectedClient = brandName; _clientOtherMode = false;\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    // Not in list — pre-fill the Other field\u001b[39m\n\u001b[31m    _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m    const inp = document.getElementById('f-client-other');\u001b[39m\n\u001b[31m    if (inp && !inp.value) inp.value = brandName;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// STEP VALIDATION\u001b[39m\n\u001b[31mfunction getSD(){if(selectedStore&&!manualMode)return{storeName:selectedStore.name,brand:selectedStore.brand||'',address:selectedStore.address||'',mobile:selectedStore.mobile||''};return{storeName:(document.getElementById('f-store')?.value||'').trim(),brand:document.getElementById('f-brand')?.value||'',address:(document.getElementById('f-addr')?.value||'').trim(),mobile:(document.getElementById('f-mobile')?.value||'').trim()};}\u001b[39m\n\u001b[31mfunction step2(){\u001b[39m\n\u001b[31m  const d=document.getElementById('f-date').value;\u001b[39m\n\u001b[31m  if(!d){toast('Select date','error');return;}\u001b[39m\n\u001b[31m  const sd=getSD();\u001b[39m\n\u001b[31m  if(!sd.storeName){toast('Select or enter store name','error');return;}\u001b[39m\n\u001b[31m  if(!sd.brand){toast('Select a brand','error');document.getElementById('brand-selector').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  if(!sd.address){toast('Enter store address','error');return;}\u001b[39m\n\u001b[31m  const clientName=getClientName();\u001b[39m\n\u001b[31m  if(!clientName){toast(t('Select a client','क्लाइंट चुनें'),'error');document.getElementById('client-chips').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  // Check missing fields filled\u001b[39m\n\u001b[31m  const missAddr=document.getElementById('sc-miss-address');\u001b[39m\n\u001b[31m  if(missAddr&&!missAddr.value.trim()){toast('Enter store address in the highlighted field','error');missAddr.focus();return;}\u001b[39m\n\u001b[31m  const missMob=document.getElementById('sc-miss-mobile');\u001b[39m\n\u001b[31m  // mobile not required — just copy if filled\u001b[39m\n\u001b[31m  if(missMob&&missMob.value.trim()&&!F.mobile)F.mobile=missMob.value.trim();\u001b[39m\n\u001b[31m  Object.assign(F,{date:d,...sd,clientName});saveDraft();\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');showView('form-photos');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction step3(){if(!frontPhotos.length){toast('Add at least 1 front view photo','error');return;}showView('form-video');}\u001b[39m\n\u001b[31mfunction step4(){if(F.hasVideo===undefined||F.hasVideo===null){toast('Select Yes or No for video','error');return;}renderBrandings();showView('form-branding');}\u001b[39m\n\u001b[31mfunction step5(){if(F.hasBranding===undefined||F.hasBranding===null){toast('Select Yes or No for branding space','error');return;}if(F.hasBranding){for(let i=0;i<brandings.length;i++){const b=brandings[i];if(!b.type){toast(`Select branding type for item ${i+1}`,'error');return;}if(!b.w||!b.h){toast(`Enter W and H dimensions for item ${i+1}`,'error');return;}if(!b.qty){toast(`Enter qty for item ${i+1}`,'error');return;}if(!b.blob&&!b.prev){toast(`Add photo for item ${i+1}`,'error');return;}}}renderAddl();buildReview();showView('form-additional');}·\u001b[39m\n\u001b[31m// REVIEW\u001b[39m\n\u001b[31mfunction buildReview(){const el=document.getElementById('rev-body');if(!el)return;const sd=getSD();const cn=getClientName();el.innerHTML=`<div><div class=\\\"rev-lbl\\\">Store</div><div class=\\\"rev-val\\\">${sd.storeName||'—'} · ${sd.brand||'—'}</div><div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">${sd.address||'—'}${sd.mobile?' · '+sd.mobile:''}</div>${gpsCoords?`<div style=\\\"font-size:11px;color:var(--gn);margin-top:3px\\\">📍 ${gpsCoords.lat}, ${gpsCoords.lng} ±${gpsCoords.acc}m</div>`:''}</div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Client</div><div class=\\\"rev-val\\\" style=\\\"color:${cn?'var(--nv)':'var(--rd)'}\\\">${cn||'⚠ Not selected — required'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Photos — Front · Inside · Additional</div><div class=\\\"rev-val\\\">${frontPhotos.length} · ${insidePhotos.length} · ${addlPhotos.length}</div><div class=\\\"rev-photos\\\">${[...frontPhotos,...insidePhotos].slice(0,6).map(p=>`<img class=\\\"rev-thumb\\\" src=\\\"${p.prev}\\\">`).join('')}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Video · Branding items</div><div class=\\\"rev-val\\\">${F.hasVideo?'Yes':'No'} · ${brandings.length} item(s)</div></div>${F.hasBranding&&brandings.length?`<div style=\\\"margin-top:8px\\\">${brandings.map((b,i)=>`<div style=\\\"font-size:12px;color:var(--g600);padding:4px 0;border-bottom:1px solid var(--g100)\\\">${i+1}. ${b.type||'No type'} — ${b.w||'?'}×${b.h||'?'}\\\" × ${b.qty||'?'} — ${calcSqft(b.w,b.h)||'?'}</div>`).join('')}</div>`:''}<div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Additional photos <span style=\\\"font-size:11px;color:var(--g400)\\\">(optional)</span></div><div class=\\\"rev-val\\\" style=\\\"color:${addlPhotos.length?'var(--gn)':'var(--g500)'}\\\">${addlPhotos.length?`✓ ${addlPhotos.length} photo(s) added`:'None added'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Mandatory document</div><div class=\\\"rev-val\\\" style=\\\"color:${(submissionDoc||_docExistingUrl)?'var(--gn)':'var(--rd)'}\\\">${(submissionDoc||_docExistingUrl)?'✓ Uploaded':'⚠ Missing — required'}</div></div>`;}·\u001b[39m\n\u001b[31m// SUBMIT\u001b[39m\n\u001b[31masync function submitRecce(){\u001b[39m\n\u001b[31m  if(!submissionDoc&&!_docExistingUrl){toast('Upload mandatory doc first','error');return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('sub-btn');btn.disabled=true;btn.textContent='Saving…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const isEdit=!!(F.editingId);\u001b[39m\n\u001b[31m    const id=isEdit?F.editingId:('RC_'+Date.now()+'_'+Math.random().toString(36).slice(2,6).toUpperCase());\u001b[39m\n\u001b[31m    const sd=getSD();\u001b[39m\n\u001b[31m    const _hub=_recceHubUser();\u001b[39m\n\u001b[31m    const entry={id,timestamp:isEdit?(await dbGet('subs',id))?.timestamp||new Date().toISOString():new Date().toISOString(),editedAt:isEdit?new Date().toISOString():undefined,status:'pending',submittedBy:_hub.empId||null,submittedByName:_hub.name||null,data:{...F,...sd,gpsCoords,frontPhotos:await Promise.all(frontPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),insidePhotos:await Promise.all(insidePhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),videoNote:F.hasVideo&&videoBlob?`Video local (${fmtSz(videoBlob.size)}) — share via WhatsApp`:null,videoCmt:document.getElementById('f-vid-cmt')?.value||'',brandings:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:calcSqft(b.w,b.h),photoB64:b.blob?await b64(b.blob):null,existingUrl:b.existingUrl||null}))),addlPhotos:await Promise.all(addlPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,desc:p.desc,existingUrl:p.existingUrl||null}))),docB64:submissionDoc?await b64(submissionDoc):null,_docExistingUrl:_docExistingUrl||null}};\u001b[39m\n\u001b[31m    entry.campaignId       = _selectedCampaignId || null;\u001b[39m\n\u001b[31m    entry.notifySupervisor = _notifySupervisor   || false;\u001b[39m\n\u001b[31m    await dbPut('subs',entry);\u001b[39m\n\u001b[31m    await dbDel('draft','current');\u001b[39m\n\u001b[31m    toast(isEdit?'Recce updated ✓':'Recce saved ✓','success');\u001b[39m\n\u001b[31m    if(navigator.onLine)syncNow();\u001b[39m\n\u001b[31m    showView('home');loadHome();checkDraft();\u001b[39m\n\u001b[31m  }catch(err){toast('Error: '+err.message,'error');}\u001b[39m\n\u001b[31m  finally{btn.disabled=false;btn.textContent='Submit Recce ✓';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// SYNC\u001b[39m\n\u001b[31masync function syncNow() {\u001b[39m\n\u001b[31m  if (!navigator.onLine) { toast('Offline — sync when back online', 'info'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('sync-btn');\u001b[39m\n\u001b[31m  const SYNC_ICON = '<svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg>Sync';\u001b[39m\n\u001b[31m  if (btn) { btn.innerHTML = '<span class=\\\"spin\\\">↻</span> Syncing'; btn.disabled = true; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const all      = await dbAll('subs');\u001b[39m\n\u001b[31m    const pend     = all.filter(s => s.status === 'pending' || s.status === 'failed');\u001b[39m\n\u001b[31m    const backfill = all.filter(s => s.status === 'synced' && !s.gasAt);\u001b[39m\n\u001b[31m    if (!pend.length && !backfill.length) { toast('All synced ✓', 'success'); return; }·\u001b[39m\n\u001b[31m    const gasUrl = (await cfg('gas-url')) || DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    function fireGas(s) {\u001b[39m\n\u001b[31m      if (!gasUrl) return;\u001b[39m\n\u001b[31m      fetch(gasUrl, { method:'POST', mode:'no-cors',\u001b[39m\n\u001b[31m        body: JSON.stringify({ action:'syncSheet', submission: s }) })\u001b[39m\n\u001b[31m        .catch(() => {});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    let ok = 0;\u001b[39m\n\u001b[31m    for (const s of pend) {\u001b[39m\n\u001b[31m      // Fire Sheet sync (no-cors fire-and-forget — writes row to Google Sheet)\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      // Primary: upload photos → auto-trigger slides → generate report → store in PostgreSQL\u001b[39m\n\u001b[31m      const { ok: pgOk, viewUrl } = await syncToPostgres(s);\u001b[39m\n\u001b[31m      if (pgOk) {\u001b[39m\n\u001b[31m        s.status = 'synced'; s.syncedAt = new Date().toISOString();\u001b[39m\n\u001b[31m        if (viewUrl) s.viewUrl = viewUrl;\u001b[39m\n\u001b[31m        await dbPut('subs', s); ok++;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        s.status = 'failed'; await dbPut('subs', s);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Backfill: entries synced to Postgres but never reached Sheet GAS\u001b[39m\n\u001b[31m    for (const s of backfill) {\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      await dbPut('subs', s);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if (backfill.length) toast(`Sent ${backfill.length} older entries to Sheet`, 'info');·\u001b[39m\n\u001b[31m    await cfg('last-sync', new Date().toISOString());\u001b[39m\n\u001b[31m    if (pend.length) toast(`Synced ${ok}/${pend.length}`, ok === pend.length ? 'success' : 'error');\u001b[39m\n\u001b[31m    loadHome();\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.innerHTML = SYNC_ICON; btn.disabled = false; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN HOME ──────────────────────────────────────────────\u001b[39m\n\u001b[31masync function loadHomeAdmin() {\u001b[39m\n\u001b[31m  // Adapt UI for admin view\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const _sh = document.querySelector('.sh'); if (_sh) _sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = 'All Submissions';\u001b[39m\n\u001b[31m  const slbls = document.querySelectorAll('.slbl');\u001b[39m\n\u001b[31m  if (slbls[0]) slbls[0].textContent = 'Showing';\u001b[39m\n\u001b[31m  if (slbls[1]) slbls[1].textContent = 'Agents';·\u001b[39m\n\u001b[31m  // Back-to-menu button for supervisors\u001b[39m\n\u001b[31m  if (_isSupervisor() && !document.getElementById('sup-back-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => { document.getElementById('sup-back-btn').remove(); renderSupLanding(); };\u001b[39m\n\u001b[31m    const content = document.querySelector('#view-home .content');\u001b[39m\n\u001b[31m    content.prepend(bb);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Show filter bar — restore if hidden by renderSupLanding, else inject fresh\u001b[39m\n\u001b[31m  const _existingFb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (_existingFb) { _existingFb.style.display = ''; }\u001b[39m\n\u001b[31m  if (!_existingFb) {\u001b[39m\n\u001b[31m    const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m    const fb = document.createElement('div');\u001b[39m\n\u001b[31m    fb.id = 'admin-filter-bar';\u001b[39m\n\u001b[31m    fb.className = 'af-bar';\u001b[39m\n\u001b[31m    fb.innerHTML =\u001b[39m\n\u001b[31m      `<div class=\\\"af-grid\\\">\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-agent\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Agents</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-brand\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Brands</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-client\\\" onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Clients</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-period\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">All Time</option>\u001b[39m\n\u001b[31m          <option value=\\\"7\\\">Last 7 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"30\\\">Last 30 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"90\\\">Last 3 months</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-group\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"date\\\">Sort: Recent</option>\u001b[39m\n\u001b[31m          <option value=\\\"agent\\\">Group: Agent</option>\u001b[39m\n\u001b[31m          <option value=\\\"brand\\\">Group: Brand</option>\u001b[39m\n\u001b[31m          <option value=\\\"client\\\">Group: Client</option>\u001b[39m\n\u001b[31m          <option value=\\\"city\\\">Group: City</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m        <input class=\\\"af-inp\\\" id=\\\"af-search\\\" type=\\\"text\\\" placeholder=\\\"🔍 Search store or city…\\\" oninput=\\\"renderAdminList()\\\" style=\\\"flex:1;min-width:120px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"del-toggle-btn\\\" id=\\\"del-toggle-btn\\\" onclick=\\\"toggleDeletedView()\\\" style=\\\"flex-shrink:0\\\">📋 View Deleted</button>\u001b[39m\n\u001b[31m        ${_isSupervisor() ? `<button class=\\\"del-toggle-btn\\\" id=\\\"pending-job-btn\\\" onclick=\\\"togglePendingJobView()\\\" style=\\\"flex-shrink:0;background:#fef3c7;color:#92400e;border-color:#f59e0b\\\">⚑ Unlinked <span id=\\\"pending-job-count\\\" style=\\\"font-weight:900\\\"></span></button>` : ''}\u001b[39m\n\u001b[31m        ${_adminUnlocked ? `<button class=\\\"del-toggle-btn\\\" id=\\\"regen-rpt-btn\\\" onclick=\\\"regenAllReports()\\\" style=\\\"flex-shrink:0\\\">&#x21BB; Regen Reports</button>` : ''}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    sh.parentNode.insertBefore(fb, sh);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Fetch\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  list.innerHTML = '<div style=\\\"text-align:center;padding:40px\\\"><div class=\\\"spinner\\\"></div></div>';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?order=submitted_at.desc&limit=500`, { headers: _RC_READ });\u001b[39m\n\u001b[31m    _adminRows = resp.ok ? await resp.json() : [];\u001b[39m\n\u001b[31m    document.getElementById('stat-total').textContent = _adminRows.length;\u001b[39m\n\u001b[31m    if (resp.ok) {\u001b[39m\n\u001b[31m      const now = new Date();\u001b[39m\n\u001b[31m      document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m        'Loaded ' + now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Populate agent dropdown\u001b[39m\n\u001b[31m    const agents = [...new Set(_adminRows.map(r => r.submitted_by).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-agent').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Agents (${agents.length})</option>` +\u001b[39m\n\u001b[31m      agents.map(a => `<option value=\\\"${a}\\\">${a}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate brand dropdown\u001b[39m\n\u001b[31m    const brands = [...new Set(_adminRows.map(r => r.brand).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-brand').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Brands (${brands.length})</option>` +\u001b[39m\n\u001b[31m      brands.map(b => `<option value=\\\"${b}\\\">${b}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate client dropdown\u001b[39m\n\u001b[31m    const clients = [...new Set(_adminRows.map(r => r.client_name).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-client').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Clients (${clients.length})</option>` +\u001b[39m\n\u001b[31m      clients.map(c => `<option value=\\\"${c}\\\">${c}</option>`).join('');·\u001b[39m\n\u001b[31m    // Update pending-job count badge\u001b[39m\n\u001b[31m    const unlinkedCount = _adminRows.filter(r => !r.deleted_at && !r.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinkedCount ? `(${unlinkedCount})` : '';·\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">⚠️</div><div class=\\\"empty-txt\\\">Could not load — check connection</div></div>';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction togglePendingJobView() {\u001b[39m\n\u001b[31m  _pendingJobFilter = !_pendingJobFilter;\u001b[39m\n\u001b[31m  _showDeletedView  = false;\u001b[39m\n\u001b[31m  const btn = document.getElementById('pending-job-btn');\u001b[39m\n\u001b[31m  if (btn) btn.style.background = _pendingJobFilter ? '#f59e0b' : '#fef3c7';\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function openLinkJobModal(subId, storeName) {\u001b[39m\n\u001b[31m  _linkJobSubId = subId;\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  const storeEl = document.getElementById('link-job-store');\u001b[39m\n\u001b[31m  const sel = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  if (!modal) return;\u001b[39m\n\u001b[31m  if (storeEl) storeEl.textContent = storeName || subId;\u001b[39m\n\u001b[31m  if (errEl) errEl.textContent = '';\u001b[39m\n\u001b[31m  // Load campaigns into dropdown\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (!_campaignList.length) {\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m      _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  if (sel) {\u001b[39m\n\u001b[31m    sel.innerHTML = '<option value=\\\"\\\">— Select campaign —</option>' +\u001b[39m\n\u001b[31m      _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  modal.style.display = 'flex';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeLinkJobModal() {\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  if (modal) modal.style.display = 'none';\u001b[39m\n\u001b[31m  _linkJobSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function saveLinkJob() {\u001b[39m\n\u001b[31m  const sel    = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl  = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  const campId = sel?.value || '';\u001b[39m\n\u001b[31m  if (!campId) { if (errEl) errEl.textContent = 'Select a campaign'; return; }\u001b[39m\n\u001b[31m  if (!_linkJobSubId) return;\u001b[39m\n\u001b[31m  const btn = document.querySelector('#modal-link-job button[onclick=\\\"saveLinkJob()\\\"]');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Linking…'; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(_linkJobSubId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ campaign_id: campId }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Patch failed');\u001b[39m\n\u001b[31m    // Update local cache\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === _linkJobSubId);\u001b[39m\n\u001b[31m    if (idx >= 0) _adminRows[idx].campaign_id = campId;\u001b[39m\n\u001b[31m    // Update pending count badge\u001b[39m\n\u001b[31m    const unlinked = _adminRows.filter(x => !x.deleted_at && !x.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinked ? `(${unlinked})` : '';\u001b[39m\n\u001b[31m    closeLinkJobModal();\u001b[39m\n\u001b[31m    toast('Job linked ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    if (errEl) errEl.textContent = 'Failed to link — try again';\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.disabled = false; btn.textContent = '🔗 Link Job'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAdminList() {\u001b[39m\n\u001b[31m  const agent  = document.getElementById('af-agent')?.value  || '';\u001b[39m\n\u001b[31m  const brand  = document.getElementById('af-brand')?.value  || '';\u001b[39m\n\u001b[31m  const period = document.getElementById('af-period')?.value || '';\u001b[39m\n\u001b[31m  const search = (document.getElementById('af-search')?.value || '').toLowerCase().trim();\u001b[39m\n\u001b[31m  const group  = document.getElementById('af-group')?.value  || 'date';·\u001b[39m\n\u001b[31m  // Pending-job filter overrides deleted/normal modes\u001b[39m\n\u001b[31m  let rows;\u001b[39m\n\u001b[31m  if (_pendingJobFilter) {\u001b[39m\n\u001b[31m    rows = _adminRows.filter(r => !r.deleted_at && !r.campaign_id);\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows = _showDeletedView\u001b[39m\n\u001b[31m      ? _adminRows.filter(r => r.deleted_at)\u001b[39m\n\u001b[31m      : _adminRows.filter(r => !r.deleted_at);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const client = document.getElementById('af-client')?.value || '';\u001b[39m\n\u001b[31m  if (agent)  rows = rows.filter(r => r.submitted_by === agent);\u001b[39m\n\u001b[31m  if (brand)  rows = rows.filter(r => r.brand === brand);\u001b[39m\n\u001b[31m  if (client) rows = rows.filter(r => r.client_name === client);\u001b[39m\n\u001b[31m  if (search) rows = rows.filter(r => (r.store_name||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.city||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.client_name||'').toLowerCase().includes(search));\u001b[39m\n\u001b[31m  if (period && !_showDeletedView) {\u001b[39m\n\u001b[31m    const cut = new Date(); cut.setDate(cut.getDate() - parseInt(period));\u001b[39m\n\u001b[31m    rows = rows.filter(r => new Date(r.submitted_at) >= cut);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const uniqueAgents = new Set(rows.map(r => r.submitted_by).filter(Boolean)).size;\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = rows.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = uniqueAgents;\u001b[39m\n\u001b[31m  const deletedCount = _adminRows.filter(r => r.deleted_at).length;\u001b[39m\n\u001b[31m  const delBtn = document.getElementById('del-toggle-btn');\u001b[39m\n\u001b[31m  if (delBtn) {\u001b[39m\n\u001b[31m    if (_showDeletedView) {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 Hide Deleted (${deletedCount})` : '📋 Hide Deleted';\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 View Deleted (${deletedCount})` : '📋 View Deleted';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    delBtn.classList.toggle('active', _showDeletedView);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!rows.length) {\u001b[39m\n\u001b[31m    list.innerHTML = _showDeletedView\u001b[39m\n\u001b[31m      ? '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">✅</div><div class=\\\"empty-txt\\\">No deleted recces</div></div>'\u001b[39m\n\u001b[31m      : '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">🔍</div><div class=\\\"empty-txt\\\">No matching submissions</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (group === 'agent') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.submitted_by||'').localeCompare(b.submitted_by||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.submitted_by || 'Unknown';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">👤 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'brand') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.brand||'').localeCompare(b.brand||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.brand || 'No Brand';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🏷 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'client') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.client_name||'').localeCompare(b.client_name||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.client_name || 'No Client';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🤝 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'city') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.city||'').localeCompare(b.city||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.city || 'No City';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">📍 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows.sort((a,b) => new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    rows.forEach(r => { html += adminCard(r); });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminCard(r) {\u001b[39m\n\u001b[31m  const dt    = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds    = dt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m  const tm    = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const photos = (r.front_photos||0) + (r.inside_photos||0) + (r.addl_photos||0);\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const canDelete  = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const canArchive = _RECCE_CFG_ADMINS.includes(hub?.empId) && !r.client_archived;·\u001b[39m\n\u001b[31m  // Client status badge\u001b[39m\n\u001b[31m  const clientStatusMap = {\u001b[39m\n\u001b[31m    approved:              {t:'✓ Approved',    s:'color:#166534;background:#dcfce7;border:1px solid #86efac'},\u001b[39m\n\u001b[31m    rejected:              {t:'✕ Rejected',    s:'color:#991b1b;background:#fee2e2;border:1px solid #fca5a5'},\u001b[39m\n\u001b[31m    approved_with_changes: {t:'✎ Approved w/ Comments', s:'color:#92400e;background:#fef3c7;border:1px solid #fcd34d'},\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const csCfg = clientStatusMap[r.client_status];\u001b[39m\n\u001b[31m  const clientStatusBadge = csCfg\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;${csCfg.s}\\\">${csCfg.t}</span>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const archiveBadge = r.client_archived\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;color:#475569;background:#f1f5f9;border:1px solid #cbd5e1\\\">⬚ Client hidden</span>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  if (r.deleted_at) {\u001b[39m\n\u001b[31m    const delDt = new Date(r.deleted_at);\u001b[39m\n\u001b[31m    const delDs = delDt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m    const reasonLabel = r.deletion_reason === 'wrong' ? 'Wrong' : r.deletion_reason === 'duplicate' ? 'Duplicate' : 'Test';\u001b[39m\n\u001b[31m    return `<div class=\\\"asc deleted-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m        <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m            <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds}</span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m          <span class=\\\"del-reason-tag\\\">❌ ${reasonLabel}</span>\u001b[39m\n\u001b[31m          <div class=\\\"del-by-txt\\\">by ${r.deleted_by||'?'} · ${delDs}</div>\u001b[39m\n\u001b[31m          ${canDelete ? `<button class=\\\"restore-btn\\\" onclick=\\\"event.stopPropagation();restoreRecce('${r.sub_id}')\\\">↩ Restore</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Submitted by ${r.submitted_by||'?'}</div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const chips = [\u001b[39m\n\u001b[31m    photos > 0   ? `📷 ${photos} photo${photos!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.has_video  ? '🎥 Video' : null,\u001b[39m\n\u001b[31m    r.has_branding ? `🪧 ${r.branding_count} branding${r.branding_count!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.city       ? `📍 ${r.city}` : (r.address ? `📍 ${r.address}` : null),\u001b[39m\n\u001b[31m    r.view_url   ? '👁 View available' : null,\u001b[39m\n\u001b[31m  ].filter(Boolean);·\u001b[39m\n\u001b[31m  const delBtnHtml = canDelete\u001b[39m\n\u001b[31m    ? `<button class=\\\"del-btn\\\" onclick=\\\"event.stopPropagation();openDeleteModal('${r.sub_id}')\\\" title=\\\"Delete recce\\\">🗑</button>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const editReqHtml = r.edit_assigned_to\u001b[39m\n\u001b[31m    ? `<span class=\\\"edit-req-badge\\\">✏ Edit sent to ${r.edit_assigned_to}</span>`\u001b[39m\n\u001b[31m    : (_isSupervisor()\u001b[39m\n\u001b[31m        ? `<button class=\\\"req-edit-btn\\\" onclick=\\\"event.stopPropagation();openEditRequestModal('${r.sub_id}')\\\">✏ Request Edit</button>`\u001b[39m\n\u001b[31m        : '');·\u001b[39m\n\u001b[31m  const editRow = editReqHtml\u001b[39m\n\u001b[31m    ? `<div style=\\\"margin-top:6px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">${editReqHtml}</div>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const showPdfBtn = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m  const pdfClass = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m  const pdfLabel = '📄 PDF';\u001b[39m\n\u001b[31m  const linkJobBtn = (_pendingJobFilter && _isSupervisor() && !r.campaign_id)\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:#f59e0b;color:#000;border-color:#f59e0b;font-weight:700\\\" onclick=\\\"event.stopPropagation();openLinkJobModal('${r.sub_id}','${(r.store_name||'Unknown').replace(/'/g,'\\\\\\\\\\\\'')}')\\\">🔗 Link Job</button>`\u001b[39m\n\u001b[31m    : (r.campaign_id ? `<span style=\\\"font-size:10px;color:var(--g400);align-self:center\\\">🔗 ${r.campaign_id}</span>` : '');\u001b[39m\n\u001b[31m  const archiveBtn = canArchive\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:rgba(99,102,241,.08);border-color:var(--nv);color:var(--nv)\\\" onclick=\\\"event.stopPropagation();archiveRecce('${r.sub_id}')\\\">⛚ Archive</button>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const btnsRow = `<div class=\\\"rpt-btns\\\">\u001b[39m\n\u001b[31m    <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openAdminRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m    ${showPdfBtn ? `<button class=\\\"${pdfClass}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">${pdfLabel}</button>` : ''}\u001b[39m\n\u001b[31m    ${linkJobBtn}\u001b[39m\n\u001b[31m    ${archiveBtn}\u001b[39m\n\u001b[31m  </div>`;·\u001b[39m\n\u001b[31m  return `<div class=\\\"asc\\\">\u001b[39m\n\u001b[31m    <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m      <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m          ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          ${r.client_name&&r.client_name!==r.brand?`<span class=\\\"client-tag\\\">🤝 ${r.client_name}</span>`:''}\u001b[39m\n\u001b[31m          <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds} · ${tm}</span>\u001b[39m\n\u001b[31m          ${clientStatusBadge}\u001b[39m\n\u001b[31m          ${archiveBadge}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <span class=\\\"asc-agent\\\">👤 ${r.submitted_by||'?'}</span>\u001b[39m\n\u001b[31m        ${delBtnHtml}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    ${chips.length?`<div class=\\\"asc-chips\\\">${chips.map(c=>`<span class=\\\"asc-chip\\\">${c}</span>`).join('')}</div>`:''}\u001b[39m\n\u001b[31m    ${editRow}\u001b[39m\n\u001b[31m    ${btnsRow}\u001b[39m\n\u001b[31m  </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _ensurePdfOverlay() {\u001b[39m\n\u001b[31m  if (document.getElementById('pdf-wait-ov')) return;\u001b[39m\n\u001b[31m  const ov = document.createElement('div');\u001b[39m\n\u001b[31m  ov.id = 'pdf-wait-ov';\u001b[39m\n\u001b[31m  ov.innerHTML = '<div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Generating PDF…</div><div class=\\\"po-sub\\\" id=\\\"pw-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"pw-pfill\\\"></div></div>';\u001b[39m\n\u001b[31m  document.body.appendChild(ov);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _showPdfOverlay(msg) {\u001b[39m\n\u001b[31m  _ensurePdfOverlay();\u001b[39m\n\u001b[31m  document.getElementById('pw-sub').textContent = msg || '';\u001b[39m\n\u001b[31m  document.getElementById('pw-pfill').style.width = '0%';\u001b[39m\n\u001b[31m  document.getElementById('pdf-wait-ov').style.display = 'flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _hidePdfOverlay() {\u001b[39m\n\u001b[31m  const ov = document.getElementById('pdf-wait-ov');\u001b[39m\n\u001b[31m  if (ov) ov.style.display = 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function openPdf(subId, pdfUrl, viewUrl) {\u001b[39m\n\u001b[31m  if (pdfUrl) { window.open(pdfUrl, '_blank'); return; }\u001b[39m\n\u001b[31m  if (!viewUrl) {\u001b[39m\n\u001b[31m    toast('Report view not available yet — please try after the report is generated.', 'info');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _showPdfOverlay('Requesting PDF generation…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type': 'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({type: 'regen-pdf', subId, viewUrl})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  let attempts = 0;\u001b[39m\n\u001b[31m  const MAX = 24;\u001b[39m\n\u001b[31m  const poll = async () => {\u001b[39m\n\u001b[31m    attempts++;\u001b[39m\n\u001b[31m    const pct = Math.min(88, Math.round(attempts / MAX * 88));\u001b[39m\n\u001b[31m    document.getElementById('pw-pfill').style.width = pct + '%';\u001b[39m\n\u001b[31m    const left = Math.ceil((MAX - attempts) * 5);\u001b[39m\n\u001b[31m    document.getElementById('pw-sub').textContent = 'Checking… (' + left + 's remaining)';\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const res = await fetch('/db/submissions?sub_id=eq.' + subId + '&select=pdf_url', {\u001b[39m\n\u001b[31m        headers: {'Content-Profile': 'recce', 'Accept-Profile': 'recce'}\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      const rows = await res.json();\u001b[39m\n\u001b[31m      if (rows && rows[0] && rows[0].pdf_url) {\u001b[39m\n\u001b[31m        document.getElementById('pw-pfill').style.width = '100%';\u001b[39m\n\u001b[31m        setTimeout(() => { _hidePdfOverlay(); window.open(rows[0].pdf_url, '_blank'); }, 400);\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(_) {}\u001b[39m\n\u001b[31m    if (attempts >= MAX) { _hidePdfOverlay(); toast('PDF generation timed out. Please try again later.', 'error'); return; }\u001b[39m\n\u001b[31m    setTimeout(poll, 5000);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  setTimeout(poll, 4000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openAdminRecce(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];·\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">\u001b[39m\n\u001b[31m         📍 View on Google Maps (${Number(r.gps_lat).toFixed(4)}, ${Number(r.gps_lng).toFixed(4)})\u001b[39m\n\u001b[31m       </a>` : '';·\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} ft × ${b.h||'?'} ft · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos not yet available — field agent must re-sync from their device to upload view\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Submission Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">👤 ${r.submitted_by||'Unknown'}</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            ${meta.videoCmt?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500);font-size:12px\\\">${meta.videoCmt}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m          ${(()=>{\u001b[39m\n\u001b[31m            const hub2 = _recceHubUser();\u001b[39m\n\u001b[31m            const isHP = _RECCE_CFG_ADMINS.includes(hub2?.empId);\u001b[39m\n\u001b[31m            const csMap = {\u001b[39m\n\u001b[31m              approved:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#166534;background:#dcfce7\\\">✓ Approved</span>',\u001b[39m\n\u001b[31m              rejected:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#991b1b;background:#fee2e2\\\">✕ Rejected</span>',\u001b[39m\n\u001b[31m              approved_with_changes: '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#92400e;background:#fef3c7\\\">✎ Approved w/ Comments</span>',\u001b[39m\n\u001b[31m            };\u001b[39m\n\u001b[31m            const csBadge = csMap[r.client_status] || '';\u001b[39m\n\u001b[31m            const approvedAt = r.client_approved_at\u001b[39m\n\u001b[31m              ? new Date(r.client_approved_at).toLocaleString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit',timeZone:'Asia/Kolkata'})\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const pdfLink = r.client_approval_pdf_url\u001b[39m\n\u001b[31m              ? `<a href=\\\"${r.client_approval_pdf_url}\\\" target=\\\"_blank\\\" style=\\\"font-size:12px;color:var(--or);text-decoration:none\\\">⬇ Approval PDF</a>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const archAct = isHP && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveRecce('${r.sub_id}')\\\" style=\\\"font-size:12px;color:var(--nv);background:none;border:1px solid var(--nv);border-radius:6px;padding:4px 10px;cursor:pointer\\\">⦽ Archive from client</button>`\u001b[39m\n\u001b[31m              : (r.client_archived ? '<span style=\\\"font-size:11px;color:var(--g400)\\\">⦽ Hidden from client</span>' : '');\u001b[39m\n\u001b[31m            const campAct = isHP && r.campaign_id && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveAllForCampaign('${r.campaign_id}')\\\" style=\\\"font-size:11px;color:#991b1b;background:none;border:1px solid #fca5a5;border-radius:6px;padding:3px 8px;cursor:pointer\\\">Archive ALL for ${r.campaign_id}</button>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            if (!csBadge && !pdfLink && !archAct) return '';\u001b[39m\n\u001b[31m            return `<div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m              <div class=\\\"ardl-lbl\\\">Client Approval</div>\u001b[39m\n\u001b[31m              ${csBadge ? `<div style=\\\"margin-bottom:5px\\\">${csBadge}${approvedAt ? ' <span style=\\\"font-size:11px;color:var(--g400)\\\">' + approvedAt + '</span>' : ''}</div>` : ''}\u001b[39m\n\u001b[31m              ${r.client_comment ? `<div style=\\\"font-size:12px;color:var(--g600);background:var(--g50);border-radius:6px;padding:7px 10px;margin-bottom:5px\\\">\\\"${r.client_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m              ${pdfLink ? `<div style=\\\"margin-bottom:4px\\\">${pdfLink}</div>` : ''}\u001b[39m\n\u001b[31m              ${archAct ? `<div style=\\\"margin-bottom:4px\\\">${archAct}</div>` : ''}\u001b[39m\n\u001b[31m              ${campAct ? `<div>${campAct}</div>` : ''}\u001b[39m\n\u001b[31m            </div>`;\u001b[39m\n\u001b[31m          })()}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeAdminDetail() {\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveRecce(subId) {\u001b[39m\n\u001b[31m  if (!confirm('Archive this recce from client view? The client will no longer see it.')) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(subId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) Object.assign(_adminRows[idx], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    toast('Archived from client view ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveAllForCampaign(campaignId) {\u001b[39m\n\u001b[31m  if (!confirm(`Archive ALL recces for campaign \\\"${campaignId}\\\" from client view?\\\\nClients will no longer see any recce from this campaign.`)) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?campaign_id=eq.${encodeURIComponent(campaignId)}&client_archived=eq.false`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    _adminRows.forEach((row, i) => {\u001b[39m\n\u001b[31m      if (row.campaign_id === campaignId) Object.assign(_adminRows[i], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    toast(`All recces for ${campaignId} archived ✓`, 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function regenAllReports() {\u001b[39m\n\u001b[31m  if (!_adminUnlocked) { toast('Admin access required', 'error'); return; }\u001b[39m\n\u001b[31m  const rows = _adminRows.filter(r => !r.deleted_at && r.photo_urls);\u001b[39m\n\u001b[31m  if (!rows.length) { toast('No synced rows with photos found', 'error'); return; }·\u001b[39m\n\u001b[31m  const btn = document.getElementById('regen-rpt-btn');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Regenerating…'; }\u001b[39m\n\u001b[31m  toast(`Regenerating ${rows.length} reports…`, 'info');·\u001b[39m\n\u001b[31m  let done = 0, failed = 0;\u001b[39m\n\u001b[31m  for (const r of rows) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const photoUrls = typeof r.photo_urls === 'string' ? JSON.parse(r.photo_urls) : (r.photo_urls || {});\u001b[39m\n\u001b[31m      let meta = {};\u001b[39m\n\u001b[31m      try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m      const entry = {\u001b[39m\n\u001b[31m        id: r.sub_id,\u001b[39m\n\u001b[31m        timestamp: r.submitted_at,\u001b[39m\n\u001b[31m        submittedBy: r.submitted_by,\u001b[39m\n\u001b[31m        data: {\u001b[39m\n\u001b[31m          storeName:    r.store_name,\u001b[39m\n\u001b[31m          brand:        r.brand,\u001b[39m\n\u001b[31m          clientName:   r.client_name,\u001b[39m\n\u001b[31m          date:         r.visit_date,\u001b[39m\n\u001b[31m          address:      r.address,\u001b[39m\n\u001b[31m          city:         r.city,\u001b[39m\n\u001b[31m          mobile:       r.mobile,\u001b[39m\n\u001b[31m          gpsCoords:    (r.gps_lat && r.gps_lng) ? { lat: r.gps_lat, lng: r.gps_lng } : null,\u001b[39m\n\u001b[31m          hasVideo:     r.has_video,\u001b[39m\n\u001b[31m          videoNote:    meta.videoNote || '',\u001b[39m\n\u001b[31m          videoCmt:     meta.videoCmt  || '',\u001b[39m\n\u001b[31m          frontPhotos:  (photoUrls.front   || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          insidePhotos: (photoUrls.inside  || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          addlPhotos:   (photoUrls.addl    || []).map(() => ({ desc: '' })),\u001b[39m\n\u001b[31m          brandings:    (meta.brandings    || []),\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      };·\u001b[39m\n\u001b[31m      const html = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m      const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m        method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m        body: JSON.stringify({ type: 'save-view', subId: r.sub_id, html })\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!vResp.ok) { failed++; continue; }\u001b[39m\n\u001b[31m      const vr = await vResp.json();\u001b[39m\n\u001b[31m      if (!vr.success) { failed++; continue; }·\u001b[39m\n\u001b[31m      if (vr.url && vr.url !== r.view_url) {\u001b[39m\n\u001b[31m        await fetch(`${_RC_BASE}/submissions?sub_id=eq.${r.sub_id}`, {\u001b[39m\n\u001b[31m          method: 'PATCH', headers: _RC_WRITE,\u001b[39m\n\u001b[31m          body: JSON.stringify({ view_url: vr.url })\u001b[39m\n\u001b[31m        });\u001b[39m\n\u001b[31m        const idx = _adminRows.findIndex(x => x.sub_id === r.sub_id);\u001b[39m\n\u001b[31m        if (idx >= 0) _adminRows[idx].view_url = vr.url;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      done++;\u001b[39m\n\u001b[31m    } catch(e) { failed++; }\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = false; btn.textContent = '↻ Regen Reports'; }\u001b[39m\n\u001b[31m  toast(`Done: ${done} regenerated${failed ? `, ${failed} failed` : ''}`, done > 0 ? 'success' : 'error');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction toggleDeletedView() {\u001b[39m\n\u001b[31m  _showDeletedView = !_showDeletedView;\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openDeleteModal(subId) {\u001b[39m\n\u001b[31m  _pendingDeleteId = subId;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  const sub = document.getElementById('del-modal-sub');\u001b[39m\n\u001b[31m  if (sub) sub.textContent = r ? `Delete: \\\"${r.store_name||'Unknown'}\\\"` : 'Select reason for deletion:';\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectDeleteReason(reason) {\u001b[39m\n\u001b[31m  _pendingDeleteReason = reason;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  document.getElementById('reason-' + reason)?.classList.add('sel');\u001b[39m\n\u001b[31m  document.getElementById('del-confirm-btn').classList.remove('no-reason');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeDeleteModal() {\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingDeleteId = null;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  clearTimeout(_tt);\u001b[39m\n\u001b[31m  document.getElementById('toast').classList.remove('show');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function restoreRecce(subId) {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({ deleted_at: null, deleted_by: null, deletion_reason: null }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Restore failed: ' + r.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_at = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_by = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deletion_reason = null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    toast('Recce restored ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Restore failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmDelete() {\u001b[39m\n\u001b[31m  if (!_pendingDeleteReason) {\u001b[39m\n\u001b[31m    const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m    btn.style.animation = 'none';\u001b[39m\n\u001b[31m    btn.offsetHeight; // reflow\u001b[39m\n\u001b[31m    btn.style.animation = 'shake .35s ease';\u001b[39m\n\u001b[31m    toast('Select a reason first', 'error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if (!_pendingDeleteId) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Deleting…';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      // Hard delete — no audit trail\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'DELETE',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Delete failed: ' + r.status);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Soft delete — stamp deleted_at, deleted_by, deletion_reason\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'PATCH',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m        body: JSON.stringify({\u001b[39m\n\u001b[31m          deleted_at: new Date().toISOString(),\u001b[39m\n\u001b[31m          deleted_by: hub.empId,\u001b[39m\n\u001b[31m          deletion_reason: _pendingDeleteReason,\u001b[39m\n\u001b[31m        }),\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Update failed: ' + r.status);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Remove or update in local cache\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      _adminRows = _adminRows.filter(x => x.sub_id !== _pendingDeleteId);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      const idx = _adminRows.findIndex(x => x.sub_id === _pendingDeleteId);\u001b[39m\n\u001b[31m      if (idx >= 0) {\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_at = new Date().toISOString();\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_by = hub.empId;\u001b[39m\n\u001b[31m        _adminRows[idx].deletion_reason = _pendingDeleteReason;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeDeleteModal();\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast('Recce deleted', 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Delete failed', 'error');\u001b[39m\n\u001b[31m    btn.classList.remove('no-reason');\u001b[39m\n\u001b[31m    btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openMyServerRecce(subId) {\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  // No view yet — show metadata modal (same layout as admin detail)\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta==='string' ? JSON.parse(r.meta) : (r.meta||{}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">📍 View on Google Maps</a>` : '';\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} × ${b.h||'?'} in · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos will appear after next sync from original device\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Visit Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupLanding() {\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = 'none';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = 'none';\u001b[39m\n\u001b[31m  // Clean up admin + create-mode UI\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('sup-back-btn')?.remove();\u001b[39m\n\u001b[31m  document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m  _supCreateMode = false;\u001b[39m\n\u001b[31m  // Resume-wrap may have been hidden by loadHomeAdmin() — restore it so draft banner shows\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = '';\u001b[39m\n\u001b[31m  document.getElementById('sub-list').innerHTML = `\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorViewAll()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0f9ff\\\">📋</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">View All Recces</span><span class=\\\"hi-txt\\\">सभी रेकी देखें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">Browse & review submissions from all agents</span><span class=\\\"hi-txt\\\">सभी एजेंट की सबमिशन देखें</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorCreateView()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0fdf4\\\">✍️</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">Create Recce</span><span class=\\\"hi-txt\\\">नई रेकी बनाएं</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">My submissions + New Recce button</span><span class=\\\"hi-txt\\\">मेरी सबमिशन + नई रेकी</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorViewAll() {\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  await loadHomeAdmin();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorCreateView() {\u001b[39m\n\u001b[31m  _supCreateMode = true;\u001b[39m\n\u001b[31m  // Restore field-agent UI\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh'); if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = t('My Submissions','मेरी सबमिशन');\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar'); if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  // Add Back to Menu button (once)\u001b[39m\n\u001b[31m  if (!document.getElementById('sup-back-create-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-create-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => {\u001b[39m\n\u001b[31m      _supCreateMode = false;\u001b[39m\n\u001b[31m      document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m      renderSupLanding();\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    document.querySelector('#view-home .content').prepend(bb);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  await loadHome();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadHome() {\u001b[39m\n\u001b[31m  if (_isSupervisor() && !_supCreateMode) { renderSupLanding(); return; }\u001b[39m\n\u001b[31m  if (_adminUnlocked && !_supCreateMode) { await loadHomeAdmin(); return; }·\u001b[39m\n\u001b[31m  const all  = await dbAll('subs');\u001b[39m\n\u001b[31m  const sy   = all.filter(s => s.status === 'synced').length;\u001b[39m\n\u001b[31m  const pe   = all.filter(s => s.status !== 'synced').length;·\u001b[39m\n\u001b[31m  // Fetch this agent's submissions from server — works on any device\u001b[39m\n\u001b[31m  let serverOnly = [];\u001b[39m\n\u001b[31m  let editAssigned = [];\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (navigator.onLine && hub?.empId) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?submitted_by=eq.${encodeURIComponent(hub.empId)}&order=submitted_at.desc&limit=200`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp.ok) {\u001b[39m\n\u001b[31m        const rows = await resp.json();\u001b[39m\n\u001b[31m        const localIds = new Set(all.map(s => s.id));\u001b[39m\n\u001b[31m        serverOnly = rows.filter(r => !localIds.has(r.sub_id));\u001b[39m\n\u001b[31m        _myServerRows = serverOnly;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m    // Fetch edit-assigned recces (supervisor assigned this creator to edit)\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp2 = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?edit_assigned_to=eq.${encodeURIComponent(hub.empId)}&deleted_at=is.null&order=submitted_at.desc`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp2.ok) editAssigned = await resp2.json();\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = sy + serverOnly.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = pe;\u001b[39m\n\u001b[31m  document.getElementById('stat-total').textContent   = all.length + serverOnly.length;·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!all.length && !serverOnly.length && !editAssigned.length) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">📋</div><div class=\\\"empty-txt\\\">No submissions yet</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const icos   = { synced:'✅', pending:'⏳', failed:'❌' };\u001b[39m\n\u001b[31m  const sorted = [...all].sort((a,b) => new Date(b.timestamp) - new Date(a.timestamp)).slice(0, 50);·\u001b[39m\n\u001b[31m  const localCards = sorted.map(s => {\u001b[39m\n\u001b[31m    const dt = new Date(s.timestamp);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const viewBtn = s.viewUrl\u001b[39m\n\u001b[31m      ? `<button class=\\\"edit-btn-sm\\\" onclick=\\\"window.open('${s.viewUrl}','_blank')\\\">👁 View</button>`\u001b[39m\n\u001b[31m      : `<button class=\\\"edit-btn-sm\\\" onclick=\\\"viewRecce('${s.id}')\\\">👁 View</button>`;\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico ${s.status}\\\">${icos[s.status]||'📋'}</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${s.data.storeName||'Unknown'} · ${s.data.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${s.data.address||''}</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge ${s.status}\\\">${s.status}</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          ${viewBtn}\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"editRecce('${s.id}')\\\" style=\\\"background:#fff7ed;border-color:var(--or);color:var(--or)\\\">✏ Edit</button>\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"makeSlides('${s.id}')\\\" style=\\\"background:#eff6ff;border-color:#3b82f6;color:#1d4ed8\\\">📊 Slides</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const serverCards = serverOnly.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const showPdf = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m    const pdfCls = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico synced\\\">✅</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\" style=\\\"min-width:0;flex:1\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"rpt-btns\\\" style=\\\"margin-top:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openMyServerRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m          ${showPdf ? `<button class=\\\"${pdfCls}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">📄 PDF</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge synced\\\">synced</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const editAssignedCards = editAssigned.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    return `<div class=\\\"edit-req-card\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:26px;flex-shrink:0\\\">✏</div>\u001b[39m\n\u001b[31m      <div class=\\\"edit-req-card-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-meta\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        ${r.edit_comment ? `<div class=\\\"edit-req-cmt\\\">\\\"${r.edit_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:10px;display:flex;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"startCreatorEdit('${r.sub_id}')\\\" style=\\\"padding:9px 16px;font-size:13px;font-weight:600\\\">✏ Edit this Recce</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (editAssignedCards.length) {\u001b[39m\n\u001b[31m    html += `<div class=\\\"edit-req-section-hdr\\\">✏ Edit Requested (${editAssignedCards.length})</div>`;\u001b[39m\n\u001b[31m    html += editAssignedCards.join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  html += localCards.join('') + serverCards.join('');\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m  const ls = await cfg('last-sync');\u001b[39m\n\u001b[31m  if (ls) {\u001b[39m\n\u001b[31m    const d = new Date(ls);\u001b[39m\n\u001b[31m    document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m      'Synced ' + d.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// RESET\u001b[39m\n\u001b[31mfunction startNewRecce(){F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  if(geoStampEnabled)autoRequestGPS();\u001b[39m\n\u001b[31m['f-date','f-brand','f-store','f-addr','f-mobile','f-client-other'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';});\u001b[39m\n\u001b[31m_selectedClient='';_clientOtherMode=false;\u001b[39m\n\u001b[31m_selectedCampaignId=null;_notifySupervisor=false;_brandingLocked=false;\u001b[39m\n\u001b[31mconst _camSel=document.getElementById('f-campaign-id');if(_camSel)_camSel.value='';\u001b[39m\n\u001b[31mconst _camNotice=document.getElementById('campaign-notify-msg');if(_camNotice)_camNotice.style.display='none';\u001b[39m\n\u001b[31mloadCampaignsForForm();\u001b[39m\n\u001b[31mrenderClientChips();\u001b[39m\n\u001b[31mdocument.getElementById('f-date').value=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31m// Block future dates\u001b[39m\n\u001b[31mdocument.getElementById('f-date').max=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31mdocument.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('pick-trigger-wrap').style.display=stores.length?'block':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').style.display=stores.length?'flex':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31mdocument.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31mdocument.getElementById('manual-fields').style.display=stores.length?'none':'block';\u001b[39m\n\u001b[31mdocument.getElementById('gps-status').textContent='';\u001b[39m\n\u001b[31m['vid-yes','vid-no','br-yes','br-no'].forEach(id=>document.getElementById(id).classList.remove('sel'));\u001b[39m\n\u001b[31mdocument.getElementById('vid-sec').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('vid-slot').innerHTML=`<div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('br-add').style.display='none';document.getElementById('br-items').innerHTML='';\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').classList.remove('filled');\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').innerHTML=`<div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('brand-selector').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('sc-missing').style.display='none';\u001b[39m\n\u001b[31mpopulateBrandDropdown();\u001b[39m\n\u001b[31mrenderPhotos('front');renderPhotos('inside');renderAddl();updAvailTag();showView('form-store');}\u001b[39m\n\u001b[31mfunction exitForm(){\u001b[39m\n\u001b[31m  // Show safe exit dialog instead of confirm\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitSaveAndLeave(){\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m  checkDraft();\u001b[39m\n\u001b[31m  toast('Draft saved — tap Resume to continue','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitDiscard(){\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];\u001b[39m\n\u001b[31m  videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  dbDel('draft','current');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitCancel(){document.getElementById('exit-dialog').classList.remove('open');}\u001b[39m\n\u001b[31mfunction showView(n){document.querySelectorAll('.view').forEach(v=>v.classList.remove('active'));const t=document.getElementById('view-'+n);if(t){t.classList.add('active');window.scrollTo(0,0);}}\u001b[39m\n\u001b[31mlet _tt;\u001b[39m\n\u001b[31mfunction toast(msg,type='info'){const el=document.getElementById('toast');el.textContent=msg;el.className='toast show '+type;clearTimeout(_tt);_tt=setTimeout(()=>el.classList.remove('show'),3000);}\u001b[39m\n\u001b[31mfunction netStatus(){const on=navigator.onLine;const dot=document.getElementById('net-dot');const txt=document.getElementById('net-txt');if(dot)dot.className='sdot '+(on?'on':'off');if(txt)txt.textContent=on?t('Online','ऑनलाइन'):t('Offline — saves locally','ऑफलाइन — स्थानीय रूप से सेव');}\u001b[39m\n\u001b[31masync function loadSettings(){\u001b[39m\n\u001b[31m  // Gas URL: pre-load default if none saved, update preview\u001b[39m\n\u001b[31m  const gu=await cfg('gas-url');\u001b[39m\n\u001b[31m  if(!gu)await cfg('gas-url',DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m  // Admin cfg url\u001b[39m\n\u001b[31m  const acu=await cfg('admin-cfg-url');if(acu&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=acu;\u001b[39m\n\u001b[31m  const su=await cfg('srv-url')||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su)document.getElementById('srv-url').value=su;\u001b[39m\n\u001b[31m  const sc=await cfg('stores');\u001b[39m\n\u001b[31m  if(sc){\u001b[39m\n\u001b[31m    stores=JSON.parse(sc);\u001b[39m\n\u001b[31m    const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m    document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m      `✓ ${stores.length} stores in cache${noBrand?` · ${noBrand} without brand`:''}`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const sf=await cfg('store-files');if(sf){_storeFiles=JSON.parse(sf);renderStoreFileList();}\u001b[39m\n\u001b[31m  const iq=await cfg('img-quality');imgQuality=iq||'compressed';applyQualityUI(imgQuality);\u001b[39m\n\u001b[31m  const gs=await cfg('geo-stamp');geoStampEnabled=(gs===null||gs==='1');applyGeoStampUI();\u001b[39m\n\u001b[31m  const bl=await cfg('brands');if(bl)brands=JSON.parse(bl);\u001b[39m\n\u001b[31m  loadBrandsFromDb();  // async — updates brands + logos from DB in background\u001b[39m\n\u001b[31m  renderBrandManageList();\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m  // Show store upload row + brand add row to supervisors only\u001b[39m\n\u001b[31m  const sur = document.getElementById('store-upload-row');\u001b[39m\n\u001b[31m  if (sur) sur.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const bar = document.getElementById('brand-add-row');\u001b[39m\n\u001b[31m  if (bar) bar.style.display = _isSupervisor() ? 'flex' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction populateBrandDropdown(){\u001b[39m\n\u001b[31m  const sel=document.getElementById('f-brand');if(!sel)return;\u001b[39m\n\u001b[31m  const cur=sel.value;\u001b[39m\n\u001b[31m  sel.innerHTML='<option value=\\\"\\\">Select brand</option>'+brands.map(b=>`<option${cur===b?' selected':''}>${b}</option>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderBrandManageList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('brand-manage-list');if(!el)return;\u001b[39m\n\u001b[31m  const isSup=_isSupervisor();\u001b[39m\n\u001b[31m  el.innerHTML=brands.map((b,i)=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    const logoHtml=logo?`<img src=\\\"${logo}\\\" style=\\\"height:20px;max-width:48px;object-fit:contain;flex-shrink:0;border-radius:3px\\\">`:'';\u001b[39m\n\u001b[31m    const ctrlHtml=isSup?`<div style=\\\"display:flex;gap:2px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"openEditBrandDialog(${i})\\\" style=\\\"background:none;border:none;color:var(--nv);font-size:15px;cursor:pointer;padding:2px 6px\\\" title=\\\"Edit\\\">✏</button>\u001b[39m\n\u001b[31m      ${brands.length>1?`<button onclick=\\\"confirmRemoveBrand(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:2px 4px\\\">×</button>`:'<span style=\\\"font-size:11px;color:var(--g400);padding:0 6px\\\">Last</span>'}\u001b[39m\n\u001b[31m    </div>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;min-width:0\\\">${logoHtml}<span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${b}</span></div>\u001b[39m\n\u001b[31m      ${ctrlHtml}\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function addBrandToList(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const inp=document.getElementById('brand-add-inp');\u001b[39m\n\u001b[31m  const val=(inp.value.trim()||'').toUpperCase();\u001b[39m\n\u001b[31m  if(!val){toast('Enter a brand name','error');return;}\u001b[39m\n\u001b[31m  if(brands.some(b=>b.toLowerCase()===val.toLowerCase())){toast(`${val} already in list`,'error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands`,{method:'POST',headers:{..._RC_WRITE,'Prefer':'return=minimal'},body:JSON.stringify({name:val,sort_order:99})});\u001b[39m\n\u001b[31m    if(resp.status===409){toast(`${val} already exists in DB`,'error');return;}\u001b[39m\n\u001b[31m    if(!resp.ok){const e=await resp.json().catch(()=>({}));throw new Error(e.message||resp.status);}\u001b[39m\n\u001b[31m    inp.value='';\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${val} added ✓`,'success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Add failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmRemoveBrand(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const name=brands[idx];\u001b[39m\n\u001b[31m  if(brands.length<=1){toast('Need at least one brand','error');return;}\u001b[39m\n\u001b[31m  let count=0;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(name)}&select=sub_id`,{headers:_RC_READ});\u001b[39m\n\u001b[31m    if(r.ok){const rows=await r.json();count=rows.length;}\u001b[39m\n\u001b[31m  }catch(_){}\u001b[39m\n\u001b[31m  const msg=count>0?`Delete \\\"${name}\\\" from brand list?\\\\n(${count} submission${count!==1?'s':''} reference this brand — they keep the name as text.)`:`Delete \\\"${name}\\\" from brand list?`;\u001b[39m\n\u001b[31m  if(!confirm(msg))return;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(name)}`,{method:'DELETE',headers:{'Content-Profile':'recce','Accept-Profile':'recce'}});\u001b[39m\n\u001b[31m    if(!resp.ok&&resp.status!==204){throw new Error(resp.status);}\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${name} removed ✓`,'info');\u001b[39m\n\u001b[31m  }catch(e){toast(`Remove failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadBrandsFromDb(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch('/db/brands?select=name,logo_url&order=sort_order',{\u001b[39m\n\u001b[31m      headers:{'Content-Profile':'recce','Accept-Profile':'recce'}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(!r.ok) return;\u001b[39m\n\u001b[31m    const rows=await r.json();\u001b[39m\n\u001b[31m    if(!rows||!rows.length) return;\u001b[39m\n\u001b[31m    const dbNames=rows.map(r=>r.name);\u001b[39m\n\u001b[31m    const logos={};rows.forEach(r=>{if(r.logo_url)logos[r.name]=r.logo_url;});\u001b[39m\n\u001b[31m    // Merge: DB brands canonical, keep locally-added extras\u001b[39m\n\u001b[31m    const extras=brands.filter(b=>!dbNames.some(n=>n.toLowerCase()===b.toLowerCase()));\u001b[39m\n\u001b[31m    brands=[...dbNames,...extras];\u001b[39m\n\u001b[31m    _brandLogos=logos;\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    // Refresh brand chips if brand-selector is visible\u001b[39m\n\u001b[31m    const bSel=document.getElementById('brand-selector');\u001b[39m\n\u001b[31m    if(bSel&&bSel.style.display!=='none') renderBrandChips();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[brands-db]',e.message);}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction renderBrandChips(){\u001b[39m\n\u001b[31m  const bChips=document.getElementById('brand-chips');if(!bChips)return;\u001b[39m\n\u001b[31m  bChips.innerHTML=brands.map(b=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    return `<div class=\\\"chip brand-chip${F.brand===b?' sel':''}\\\" onclick=\\\"selectStoreBrand('${b.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\">` +\u001b[39m\n\u001b[31m      (logo?`<img src=\\\"${logo}\\\" class=\\\"brand-chip-logo\\\" alt=\\\"\\\">`:'') +\u001b[39m\n\u001b[31m      `<span>${b}</span></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _editBrandIdx=null,_editBrandOld=null;\u001b[39m\n\u001b[31mfunction openEditBrandDialog(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor())return;\u001b[39m\n\u001b[31m  _editBrandIdx=idx;_editBrandOld=brands[idx];\u001b[39m\n\u001b[31m  document.getElementById('be-name').value=brands[idx];\u001b[39m\n\u001b[31m  const logo=_brandLogos[brands[idx]]||'';\u001b[39m\n\u001b[31m  document.getElementById('be-logo').value=logo;\u001b[39m\n\u001b[31m  document.getElementById('be-logo-preview').innerHTML=logo?`<img src=\\\"${logo}\\\" style=\\\"height:28px;object-fit:contain\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Current logo</span>`:'';\u001b[39m\n\u001b[31m  document.getElementById('be-cascade-info').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('brand-edit-modal').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeBrandEditModal(){document.getElementById('brand-edit-modal').classList.remove('open');_editBrandIdx=null;_editBrandOld=null;}\u001b[39m\n\u001b[31mfunction previewBrandLogo(){\u001b[39m\n\u001b[31m  const url=(document.getElementById('be-logo')?.value||'').trim();\u001b[39m\n\u001b[31m  const prev=document.getElementById('be-logo-preview');\u001b[39m\n\u001b[31m  if(prev)prev.innerHTML=url?`<img src=\\\"${url}\\\" style=\\\"height:28px;object-fit:contain\\\" onerror=\\\"this.style.display='none'\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Preview</span>`:'';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveBrandEdit(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const oldName=_editBrandOld;\u001b[39m\n\u001b[31m  const newName=(document.getElementById('be-name').value||'').trim().toUpperCase();\u001b[39m\n\u001b[31m  const newLogo=(document.getElementById('be-logo').value||'').trim();\u001b[39m\n\u001b[31m  if(!newName){toast('Brand name required','error');return;}\u001b[39m\n\u001b[31m  const isRename=newName!==oldName;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // 1. Update recce.brands\u001b[39m\n\u001b[31m    const pResp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m      method:'PATCH',headers:{..._RC_WRITE,'Prefer':'return=minimal'},\u001b[39m\n\u001b[31m      body:JSON.stringify({name:newName,logo_url:newLogo||null})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(pResp.status===409){toast(`\\\"${newName}\\\" already exists`,'error');return;}\u001b[39m\n\u001b[31m    if(!pResp.ok&&pResp.status!==204){const e=await pResp.json().catch(()=>({}));throw new Error(e.message||pResp.status);}\u001b[39m\n\u001b[31m    if(isRename){\u001b[39m\n\u001b[31m      const hub=_recceHubUser();\u001b[39m\n\u001b[31m      // 2. Cascade to submissions\u001b[39m\n\u001b[31m      await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m        method:'PATCH',headers:_RC_WRITE,body:JSON.stringify({brand:newName})\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      // 3. Cascade to stores.json + view HTML files + PDFs\u001b[39m\n\u001b[31m      toast('Cascading rename to reports…','info');\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        const cResp=await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},\u001b[39m\n\u001b[31m          body:JSON.stringify({type:'cascade-rename-brand',oldName,newName,empId:hub?.empId||''})});\u001b[39m\n\u001b[31m        const cRes=cResp.ok?await cResp.json():{};\u001b[39m\n\u001b[31m        const msg=`Brand renamed ✓${cRes.viewsUpdated?` · ${cRes.viewsUpdated} reports re-queued`:''}`;\u001b[39m\n\u001b[31m        closeBrandEditModal();\u001b[39m\n\u001b[31m        await loadBrandsFromDb();\u001b[39m\n\u001b[31m        toast(msg,'success');\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }catch(e){console.warn('[cascade-rename]',e.message);}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeBrandEditModal();\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast('Brand updated ✓','success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Save failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function fetchServerBrands(){\u001b[39m\n\u001b[31m  const url=document.getElementById('brands-url')?.value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    toast('Fetching brands…','info');\u001b[39m\n\u001b[31m    const r=await fetch(url);const j=await r.json();\u001b[39m\n\u001b[31m    const list=Array.isArray(j)?j:j.brands||[];\u001b[39m\n\u001b[31m    if(!list.length){toast('No brands found in response','error');return;}\u001b[39m\n\u001b[31m    brands=list.map(b=>b.toString().toUpperCase());\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    toast(`${brands.length} brands loaded from server`,'success');\u001b[39m\n\u001b[31m  }catch{toast('Failed to fetch — check URL','error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setImgQuality(q){\u001b[39m\n\u001b[31m  imgQuality=q;\u001b[39m\n\u001b[31m  cfg('img-quality',q);\u001b[39m\n\u001b[31m  applyQualityUI(q);\u001b[39m\n\u001b[31m  toast(q==='hd'?'HD Quality selected (~400–600 KB per photo)':'Full Compression selected (~150–200 KB per photo)','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction applyQualityUI(q){\u001b[39m\n\u001b[31m  ['compressed','hd'].forEach(opt=>{\u001b[39m\n\u001b[31m    const label=document.getElementById('q-opt-'+opt);\u001b[39m\n\u001b[31m    const radio=document.getElementById('q-radio-'+opt);\u001b[39m\n\u001b[31m    const dot  =document.getElementById('q-dot-'+opt);\u001b[39m\n\u001b[31m    if(!label)return;\u001b[39m\n\u001b[31m    const active=opt===q;\u001b[39m\n\u001b[31m    label.style.borderColor=active?'var(--or)':'var(--g200)';\u001b[39m\n\u001b[31m    label.style.background=active?'#fff7ed':'var(--g50)';\u001b[39m\n\u001b[31m    if(radio)radio.style.borderColor=active?'var(--or)':'var(--g300)';\u001b[39m\n\u001b[31m    if(dot)dot.style.display=active?'block':'none';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const badge=document.getElementById('q-current-badge');\u001b[39m\n\u001b[31m  if(badge){\u001b[39m\n\u001b[31m    const label=q==='hd'?'HD Quality (~400–600 KB)':'Full Compression (~150–200 KB)';\u001b[39m\n\u001b[31m    badge.innerHTML=`Active: <strong>${label}</strong>`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function clearData(){if(!confirm('Delete ALL local data?'))return;const all=await dbAll('subs');for(const s of all)await dbDel('subs',s.id);stores=[];await cfg('stores',null);toast('All cleared','success');loadHome();}\u001b[39m\n\u001b[31mif('serviceWorker' in navigator){const sw=`const C='recce-v37';self.addEventListener('install',e=>{e.waitUntil(caches.open(C).then(c=>c.add('/')));self.skipWaiting();});self.addEventListener('activate',e=>e.waitUntil(clients.claim()));self.addEventListener('fetch',e=>{if(e.request.method!=='GET')return;e.respondWith(caches.match(e.request).then(r=>{if(r)return r;return fetch(e.request).then(res=>{if(res&&res.status===200&&res.type==='basic'){const cl=res.clone();caches.open(C).then(c=>c.put(e.request,cl));}return res;}).catch(()=>caches.match('/'));}))}); `;const blob=new Blob([sw],{type:'application/javascript'});navigator.serviceWorker.register(URL.createObjectURL(blob),{scope:'/'}).catch(()=>{});}·\u001b[39m\n\u001b[31m// ── GEOLOCATION STAMP ────────────────────────────────────────\u001b[39m\n\u001b[31mfunction applyGeoStampUI(){\u001b[39m\n\u001b[31m  const tog=document.getElementById('geo-tog');\u001b[39m\n\u001b[31m  if(tog)tog.classList.toggle('on',geoStampEnabled);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function toggleGeoStamp(){\u001b[39m\n\u001b[31m  geoStampEnabled=!geoStampEnabled;\u001b[39m\n\u001b[31m  await cfg('geo-stamp',geoStampEnabled?'1':'0');\u001b[39m\n\u001b[31m  applyGeoStampUI();\u001b[39m\n\u001b[31m  toast(geoStampEnabled?'Geolocation stamp enabled':'Geolocation stamp disabled','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Auto-request GPS silently when a new recce starts\u001b[39m\n\u001b[31mfunction autoRequestGPS(){\u001b[39m\n\u001b[31m  if(!navigator.geolocation)return;\u001b[39m\n\u001b[31m  const statusEl=document.getElementById('geo-status');\u001b[39m\n\u001b[31m  if(statusEl)statusEl.textContent='Acquiring GPS…';\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(\u001b[39m\n\u001b[31m    pos=>{\u001b[39m\n\u001b[31m      gpsCoords={\u001b[39m\n\u001b[31m        lat:pos.coords.latitude.toFixed(6),\u001b[39m\n\u001b[31m        lng:pos.coords.longitude.toFixed(6),\u001b[39m\n\u001b[31m        acc:Math.round(pos.coords.accuracy)\u001b[39m\n\u001b[31m      };\u001b[39m\n\u001b[31m      const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m      const quality=acc<=15?'Excellent':acc<=50?'Good':acc<=200?'Fair':'Poor (cell tower)';\u001b[39m\n\u001b[31m      const color=acc<=15?'var(--gn)':acc<=50?'#16a34a':acc<=200?'var(--am)':'var(--rd)';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.innerHTML=`GPS: ${gpsCoords.lat}, ${gpsCoords.lng} · ±${acc}m · <span style=\\\"color:${color};font-weight:600\\\">${quality}</span>`;\u001b[39m\n\u001b[31m      // Update form GPS status too\u001b[39m\n\u001b[31m      const fs=document.getElementById('gps-status');\u001b[39m\n\u001b[31m      if(fs){fs.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${acc}m)`;fs.style.color='var(--gn)';}\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    err=>{\u001b[39m\n\u001b[31m      const msgs={1:'Location permission denied in Chrome',2:'GPS signal unavailable',3:'GPS timed out'};\u001b[39m\n\u001b[31m      const msg=msgs[err.code]||'GPS unavailable';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.textContent=msg+' — stamp will use store address';\u001b[39m\n\u001b[31m      if(err.code===1)toast('Tap the lock icon in Chrome address bar → allow Location','info');\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    {enableHighAccuracy:true,timeout:20000,maximumAge:60000}\u001b[39m\n\u001b[31m  );\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Draw stamp on a photo blob — returns new blob with stamp baked in\u001b[39m\n\u001b[31mfunction roundRectPath(ctx,x,y,w,h,r){\u001b[39m\n\u001b[31m  ctx.beginPath();ctx.moveTo(x+r,y);ctx.lineTo(x+w-r,y);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y,x+w,y+r);ctx.lineTo(x+w,y+h-r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);ctx.lineTo(x+r,y+h);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y+h,x,y+h-r);ctx.lineTo(x,y+r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y,x+r,y);ctx.closePath();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction fitText(ctx,text,maxW){\u001b[39m\n\u001b[31m  if(ctx.measureText(text).width<=maxW)return text;\u001b[39m\n\u001b[31m  while(text.length>1&&ctx.measureText(text+'…').width>maxW)text=text.slice(0,-1);\u001b[39m\n\u001b[31m  return text+'…';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction stampPhoto(blob){\u001b[39m\n\u001b[31m  if(!geoStampEnabled)return Promise.resolve(blob);\u001b[39m\n\u001b[31m  return new Promise(res=>{\u001b[39m\n\u001b[31m    const img=new Image(),url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    img.onload=()=>{\u001b[39m\n\u001b[31m      URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m      const W=img.width,H=img.height;\u001b[39m\n\u001b[31m      const c=document.createElement('canvas');c.width=W;c.height=H;\u001b[39m\n\u001b[31m      const ctx=c.getContext('2d');\u001b[39m\n\u001b[31m      ctx.drawImage(img,0,0);·\u001b[39m\n\u001b[31m      // Stamp dimensions — 18% of image height\u001b[39m\n\u001b[31m      const SH=Math.round(H*0.18);\u001b[39m\n\u001b[31m      const pad=Math.round(W*0.03);\u001b[39m\n\u001b[31m      const SY=H-SH;·\u001b[39m\n\u001b[31m      // Semi-transparent background\u001b[39m\n\u001b[31m      ctx.fillStyle='rgba(10,18,35,0.78)';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,SH);·\u001b[39m\n\u001b[31m      // Orange top accent line\u001b[39m\n\u001b[31m      ctx.fillStyle='#f97316';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,Math.max(3,Math.round(H*0.004)));·\u001b[39m\n\u001b[31m      // Font sizes scaled to image\u001b[39m\n\u001b[31m      const f1=Math.round(SH*0.26); // store name\u001b[39m\n\u001b[31m      const f2=Math.round(SH*0.22); // coords / address\u001b[39m\n\u001b[31m      const f3=Math.round(SH*0.20); // timestamp·\u001b[39m\n\u001b[31m      // Row Y centres\u001b[39m\n\u001b[31m      const r1=SY+SH*0.26;\u001b[39m\n\u001b[31m      const r2=SY+SH*0.55;\u001b[39m\n\u001b[31m      const r3=SY+SH*0.82;·\u001b[39m\n\u001b[31m      // Get stamp data\u001b[39m\n\u001b[31m      const storeName=F.storeName||selectedStore?.name||'';\u001b[39m\n\u001b[31m      const brand=F.brand||selectedStore?.brand||'';\u001b[39m\n\u001b[31m      const addr=F.address||selectedStore?.address||'';\u001b[39m\n\u001b[31m      const now=new Date();\u001b[39m\n\u001b[31m      const dateStr=now.toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m      const timeStr=now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit',hour12:true});·\u001b[39m\n\u001b[31m      // Badge (right side — GPS quality)\u001b[39m\n\u001b[31m      let badgeLabel='',badgeColor='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m        if(acc<=15){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=50){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=200){badgeLabel='~'+acc+'m';badgeColor='#d97706';}\u001b[39m\n\u001b[31m        else{badgeLabel='Cell ~'+acc+'m';badgeColor='#dc2626';}\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        badgeLabel='No GPS';badgeColor='#64748b';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      const bFontSz=Math.round(SH*0.18);\u001b[39m\n\u001b[31m      ctx.font=`bold ${bFontSz}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      const bW=Math.round(ctx.measureText(badgeLabel).width+pad);\u001b[39m\n\u001b[31m      const bH=Math.round(SH*0.32);\u001b[39m\n\u001b[31m      const bX=W-bW-pad;const bY=SY+(SH-bH)/2;\u001b[39m\n\u001b[31m      ctx.fillStyle=badgeColor+'cc';\u001b[39m\n\u001b[31m      roundRectPath(ctx,bX,bY,bW,bH,4);ctx.fill();\u001b[39m\n\u001b[31m      ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';\u001b[39m\n\u001b[31m      ctx.fillText(badgeLabel,bX+bW/2,bY+bH/2);\u001b[39m\n\u001b[31m      ctx.textAlign='left';ctx.textBaseline='alphabetic';·\u001b[39m\n\u001b[31m      const textMaxW=bX-pad*2;·\u001b[39m\n\u001b[31m      // Row 1 — store name + brand\u001b[39m\n\u001b[31m      ctx.font=`bold ${f1}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#ffffff';\u001b[39m\n\u001b[31m      const nameText=storeName+(brand?' · '+brand:'');\u001b[39m\n\u001b[31m      ctx.fillText('📍 '+fitText(ctx,nameText,textMaxW-f1*1.4),pad,r1);·\u001b[39m\n\u001b[31m      // Row 2 — GPS coords OR address\u001b[39m\n\u001b[31m      ctx.font=`${f2}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#cbd5e1';\u001b[39m\n\u001b[31m      let row2='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        row2=`Lat ${gpsCoords.lat}°   Long ${gpsCoords.lng}°`;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        row2=addr?fitText(ctx,addr,textMaxW):'GPS coordinates unavailable';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      ctx.fillText(row2,pad,r2);·\u001b[39m\n\u001b[31m      // Row 3 — date and time\u001b[39m\n\u001b[31m      ctx.font=`${f3}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#94a3b8';\u001b[39m\n\u001b[31m      ctx.fillText(`${dateStr}   ${timeStr}`,pad,r3);·\u001b[39m\n\u001b[31m      c.toBlob(b=>res(b||blob),'image/jpeg',imgQuality==='hd'?0.88:0.82);\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    img.onerror=()=>{URL.revokeObjectURL(url);res(blob);};\u001b[39m\n\u001b[31m    img.src=url;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _aTool='rect',_aColor='#f97316',_aWidth=4,_aTarget=-1;\u001b[39m\n\u001b[31mlet _aImg=null,_aHistory=[],_aDrawing=false,_aStart={},_aPts=[];\u001b[39m\n\u001b[31mlet _aSel=-1,_aDragMode=null,_aDragOff={x:0,y:0};\u001b[39m\n\u001b[31m// Larger hit radius on touch devices for easier finger selection\u001b[39m\n\u001b[31mconst HIT_R=()=>('ontouchstart' in window)?32:16;·\u001b[39m\n\u001b[31mfunction setATool(t){\u001b[39m\n\u001b[31m  _aTool=t;\u001b[39m\n\u001b[31m  ['rect','ellipse','line','arrow','free'].forEach(id=>{const el=document.getElementById('at-'+id);if(el)el.classList.toggle('on',id===t&&t!=='move');});\u001b[39m\n\u001b[31m  const mv=document.getElementById('at-move');if(mv)mv.classList.toggle('sel-on',t==='move');\u001b[39m\n\u001b[31m  const info=document.getElementById('annot-sel-info');if(info)info.style.display=t==='move'?'block':'none';\u001b[39m\n\u001b[31m  if(t!=='move'){_aSel=-1;redrawAnnot();}\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(cvs)cvs.style.cursor=t==='move'?'default':'crosshair';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAColor(c){\u001b[39m\n\u001b[31m  _aColor=c;\u001b[39m\n\u001b[31m  const m={'#f97316':'or','#ef4444':'rd','#ffffff':'wh','#facc15':'yw','#22c55e':'gn'};\u001b[39m\n\u001b[31m  Object.entries(m).forEach(([col,id])=>{const el=document.getElementById('ac-'+id);if(el)el.classList.toggle('on',col===c);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAWidth(w){_aWidth=w;[2,4,7].forEach(v=>{const el=document.getElementById('aw-'+v);if(el)el.classList.toggle('on',v===w);});}·\u001b[39m\n\u001b[31mfunction openAnnot(idx){\u001b[39m\n\u001b[31m  _aTarget=idx;_aHistory=[];_aDrawing=false;_aPts=[];_aSel=-1;_aDragMode=null;\u001b[39m\n\u001b[31m  document.getElementById('annot-modal').classList.add('open');\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');\u001b[39m\n\u001b[31m  const img=new Image(),url=URL.createObjectURL(brandings[idx].blob);\u001b[39m\n\u001b[31m  img.onload=()=>{\u001b[39m\n\u001b[31m    const sc=Math.min(1,window.innerWidth/img.width,(window.innerHeight-185)/img.height);\u001b[39m\n\u001b[31m    cvs.width=Math.round(img.width*sc);cvs.height=Math.round(img.height*sc);\u001b[39m\n\u001b[31m    _aImg=img;redrawAnnot();URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  img.src=url;\u001b[39m\n\u001b[31m  cvs.ontouchstart=aDown;cvs.ontouchmove=aMove;cvs.ontouchend=aUp;\u001b[39m\n\u001b[31m  cvs.onmousedown=aDown;cvs.onmousemove=aMove;cvs.onmouseup=aUp;\u001b[39m\n\u001b[31m  setATool('rect');setAColor('#f97316');setAWidth(4);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aPos(e){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const r=cvs.getBoundingClientRect();\u001b[39m\n\u001b[31m  const src=e.touches?e.touches[0]:e;\u001b[39m\n\u001b[31m  return{x:(src.clientX-r.left)*(cvs.width/r.width),y:(src.clientY-r.top)*(cvs.height/r.height)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Always return normalised (positive w,h) bounds\u001b[39m\n\u001b[31mfunction sBounds(s){\u001b[39m\n\u001b[31m  if(s.type==='free'){\u001b[39m\n\u001b[31m    if(!s.pts||!s.pts.length)return null;\u001b[39m\n\u001b[31m    const xs=s.pts.map(p=>p.x),ys=s.pts.map(p=>p.y);\u001b[39m\n\u001b[31m    const x=Math.min(...xs),y=Math.min(...ys);\u001b[39m\n\u001b[31m    return{x,y,w:Math.max(...xs)-x,h:Math.max(...ys)-y};\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  return{x:Math.min(s.x,s.x+s.w),y:Math.min(s.y,s.y+s.h),w:Math.abs(s.w),h:Math.abs(s.h)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction hitHandle(px,py,s){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return null;\u001b[39m\n\u001b[31m  const b=sBounds(s);const hr=HIT_R();\u001b[39m\n\u001b[31m  for(const[n,x,y]of[['tl',b.x,b.y],['tr',b.x+b.w,b.y],['bl',b.x,b.y+b.h],['br',b.x+b.w,b.y+b.h]])\u001b[39m\n\u001b[31m    if(Math.hypot(px-x,py-y)<hr)return n;\u001b[39m\n\u001b[31m  return null;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction hitShape(px,py,s){\u001b[39m\n\u001b[31m  const b=sBounds(s);if(!b)return false;\u001b[39m\n\u001b[31m  const pad=HIT_R();\u001b[39m\n\u001b[31m  return px>=b.x-pad&&px<=b.x+b.w+pad&&py>=b.y-pad&&py<=b.y+b.h+pad;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aDown(e){\u001b[39m\n\u001b[31m  e.preventDefault();const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'){\u001b[39m\n\u001b[31m    // Check handles of selected shape first\u001b[39m\n\u001b[31m    if(_aSel>=0&&_aSel<_aHistory.length){\u001b[39m\n\u001b[31m      const h=hitHandle(p.x,p.y,_aHistory[_aSel]);\u001b[39m\n\u001b[31m      if(h){_aDragMode='r-'+h;_aDragOff={x:p.x,y:p.y};_aDrawing=true;return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Hit test all shapes topmost first\u001b[39m\n\u001b[31m    for(let i=_aHistory.length-1;i>=0;i--){\u001b[39m\n\u001b[31m      if(hitShape(p.x,p.y,_aHistory[i])){\u001b[39m\n\u001b[31m        _aSel=i;_aDragMode='move';\u001b[39m\n\u001b[31m        const s=_aHistory[i];\u001b[39m\n\u001b[31m        const b=sBounds(s);\u001b[39m\n\u001b[31m        // Store offset from shape top-left corner (normalised)\u001b[39m\n\u001b[31m        _aDragOff={x:p.x-b.x,y:p.y-b.y};\u001b[39m\n\u001b[31m        _aDrawing=true;redrawAnnot();return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    _aSel=-1;redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _aDrawing=true;_aStart={x:p.x,y:p.y};if(_aTool==='free')_aPts=[{x:p.x,y:p.y}];\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aMove(e){\u001b[39m\n\u001b[31m  e.preventDefault();if(!_aDrawing)return;const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'&&_aDragMode){\u001b[39m\n\u001b[31m    const s=_aHistory[_aSel];if(!s)return;\u001b[39m\n\u001b[31m    if(_aDragMode==='move'){\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      // New top-left position\u001b[39m\n\u001b[31m      const nx=p.x-_aDragOff.x;\u001b[39m\n\u001b[31m      const ny=p.y-_aDragOff.y;\u001b[39m\n\u001b[31m      const dx=nx-b.x,dy=ny-b.y;\u001b[39m\n\u001b[31m      if(s.type==='free'){\u001b[39m\n\u001b[31m        s.pts=s.pts.map(pt=>({x:pt.x+dx,y:pt.y+dy}));\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        // Move preserving w/h sign (don't normalise — keep original drawing direction)\u001b[39m\n\u001b[31m        s.x+=dx;s.y+=dy;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Resize from corner — always work on normalised bounds then re-apply\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      const n=_aDragMode.slice(2);\u001b[39m\n\u001b[31m      let nx=b.x,ny=b.y,nw=b.w,nh=b.h;\u001b[39m\n\u001b[31m      if(n==='br'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,p.y-b.y);}\u001b[39m\n\u001b[31m      else if(n==='tl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,b.y+b.h-p.y);nx=p.x;ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='tr'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,b.y+b.h-p.y);ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='bl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,p.y-b.y);nx=p.x;}\u001b[39m\n\u001b[31m      s.x=nx;s.y=ny;s.w=nw;s.h=nh; // store as normalised going forward\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if(_aTool==='free'){_aPts.push({x:p.x,y:p.y});redrawAnnot();drawSh({type:'free',pts:[..._aPts],color:_aColor,lw:_aWidth},true);return;}\u001b[39m\n\u001b[31m  redrawAnnot();drawSh({type:_aTool,x:_aStart.x,y:_aStart.y,w:p.x-_aStart.x,h:p.y-_aStart.y,color:_aColor,lw:_aWidth},true);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction aUp(e){\u001b[39m\n\u001b[31m  if(!_aDrawing)return;_aDrawing=false;\u001b[39m\n\u001b[31m  if(_aTool==='move'){_aDragMode=null;return;}\u001b[39m\n\u001b[31m  const p=aPos(e||{touches:[{clientX:0,clientY:0}]});\u001b[39m\n\u001b[31m  if(_aTool==='free'){if(_aPts.length>2){_aHistory.push({type:'free',pts:[..._aPts],x:_aPts[0].x,y:_aPts[0].y,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  else{const w=p.x-_aStart.x,h=p.y-_aStart.y;if(Math.abs(w)>4||Math.abs(h)>4){_aHistory.push({type:_aTool,x:_aStart.x,y:_aStart.y,w,h,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  _aPts=[];redrawAnnot();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction redrawAnnot(){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.clearRect(0,0,cvs.width,cvs.height);if(_aImg)ctx.drawImage(_aImg,0,0,cvs.width,cvs.height);\u001b[39m\n\u001b[31m  _aHistory.forEach((s,i)=>{drawSh(s,false,ctx);if(_aTool==='move'&&i===_aSel)drawHandles(s,ctx);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawHandles(s,ctx){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return;const b=sBounds(s);ctx.save();\u001b[39m\n\u001b[31m  ctx.setLineDash([5,3]);ctx.strokeStyle='#facc15';ctx.lineWidth=1.5;ctx.strokeRect(b.x-2,b.y-2,b.w+4,b.h+4);ctx.setLineDash([]);\u001b[39m\n\u001b[31m  [[b.x,b.y],[b.x+b.w,b.y],[b.x,b.y+b.h],[b.x+b.w,b.y+b.h]].forEach(([x,y])=>{ctx.beginPath();ctx.arc(x,y,7,0,2*Math.PI);ctx.fillStyle='#f97316';ctx.fill();ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();});\u001b[39m\n\u001b[31m  ctx.restore();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawSh(s,preview=false,ctx){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(!ctx)ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.save();ctx.strokeStyle=s.color;ctx.lineWidth=preview?Math.max(s.lw||4,2):s.lw||4;\u001b[39m\n\u001b[31m  ctx.lineCap='round';ctx.lineJoin='round';ctx.setLineDash(preview?[6,3]:[]);\u001b[39m\n\u001b[31m  if(s.type==='rect'){ctx.strokeRect(s.x,s.y,s.w,s.h);ctx.fillStyle=s.color+'28';ctx.fillRect(s.x,s.y,s.w,s.h);}\u001b[39m\n\u001b[31m  else if(s.type==='ellipse'){const cx=s.x+s.w/2,cy=s.y+s.h/2;ctx.beginPath();ctx.ellipse(cx,cy,Math.abs(s.w/2),Math.abs(s.h/2),0,0,2*Math.PI);ctx.stroke();ctx.fillStyle=s.color+'28';ctx.fill();}\u001b[39m\n\u001b[31m  else if(s.type==='line'){ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(s.x+s.w,s.y+s.h);ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='arrow'){const ex=s.x+s.w,ey=s.y+s.h;ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(ex,ey);ctx.stroke();const a=Math.atan2(s.h,s.w),al=20,aa=0.4;ctx.setLineDash([]);ctx.beginPath();ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a-aa),ey-al*Math.sin(a-aa));ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a+aa),ey-al*Math.sin(a+aa));ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='free'){if(s.pts.length<2){ctx.restore();return;}ctx.beginPath();s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));ctx.stroke();}\u001b[39m\n\u001b[31m  ctx.setLineDash([]);ctx.restore();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction undoAnnot(){if(_aHistory.length){_aHistory.pop();_aSel=Math.min(_aSel,_aHistory.length-1);redrawAnnot();}}\u001b[39m\n\u001b[31mfunction clearAnnot(){_aHistory=[];_aSel=-1;redrawAnnot();}·\u001b[39m\n\u001b[31m// Bottom dialog\u001b[39m\n\u001b[31mlet _bdCb=null;\u001b[39m\n\u001b[31mfunction showBDialog(title,sub,onYes){\u001b[39m\n\u001b[31m  document.getElementById('bdialog-title').textContent=title;\u001b[39m\n\u001b[31m  document.getElementById('bdialog-sub').textContent=sub;\u001b[39m\n\u001b[31m  _bdCb=onYes;document.getElementById('bdialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction bdialogYes(){document.getElementById('bdialog').classList.remove('open');if(_bdCb)_bdCb();_bdCb=null;}\u001b[39m\n\u001b[31mfunction bdialogNo(){document.getElementById('bdialog').classList.remove('open');_bdCb=null;}·\u001b[39m\n\u001b[31mfunction _afterBrandingPhoto(){\u001b[39m\n\u001b[31m  const idx=_aTarget;\u001b[39m\n\u001b[31m  showBDialog(t(`Add reference photos for Branding ${idx+1}?`,`ब्रांडिंग ${idx+1} के लिए अतिरिक्त फोटो?`),t('Optional extra photos for future reference.','वैकल्पिक — भविष्य के लिए अतिरिक्त फोटो।'),()=>{showView('form-additional');setTimeout(()=>addAdditional(),200);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction skipAnnot(){document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo added (${fmtSz(brandings[_aTarget].blob.size)})`,'success');_afterBrandingPhoto();}\u001b[39m\n\u001b[31mfunction saveAnnot(){const cvs=document.getElementById('annot-cvs');cvs.toBlob(blob=>{brandings[_aTarget].blob=blob;brandings[_aTarget].prev=URL.createObjectURL(blob);document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo + markup saved (${fmtSz(blob.size)})`,'success');_afterBrandingPhoto();},'image/jpeg',0.88);}·\u001b[39m\n\u001b[31m// ── VIEW RECCE (read-only) ──────────────────────────────────\u001b[39m\n\u001b[31masync function viewRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  // Synced entries have a server-side rich report — open it directly\u001b[39m\n\u001b[31m  if(entry.viewUrl){window.open(entry.viewUrl,'_blank');return;}\u001b[39m\n\u001b[31m  // Offline / not-yet-synced fallback: generate from local base64 data\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  const ts=new Date(entry.timestamp).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'});·\u001b[39m\n\u001b[31m  async function b64ToUrl(b64){if(!b64)return'';try{const r=await fetch(b64);const bl=await r.blob();return URL.createObjectURL(bl);}catch{return'';}}·\u001b[39m\n\u001b[31m  const fvUrls=await Promise.all((d.frontPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const ivUrls=await Promise.all((d.insidePhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const brUrls=await Promise.all((d.brandings||[]).map(b=>b64ToUrl(b.photoB64)));\u001b[39m\n\u001b[31m  const adUrls=await Promise.all((d.addlPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const docUrl=await b64ToUrl(d.docB64);·\u001b[39m\n\u001b[31m  const brRows=(d.brandings||[]).map((b,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:16px;padding:12px;background:#f8fafc;border-radius:8px;border-left:3px solid #f97316\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-weight:600;font-size:14px;color:#0f172a;margin-bottom:6px\\\">${i+1}. ${b.type||'—'}: ${b.w||'?'}\\\"×${b.h||'?'}\\\" · Qty: ${b.qty||'?'} · ${b.sqft||'?'}</div>\u001b[39m\n\u001b[31m      ${brUrls[i]?`<img src=\\\"${brUrls[i]}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:6px\\\">`:'<div style=\\\"color:#94a3b8;font-size:12px\\\">No photo</div>'}\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  const html=`<!DOCTYPE html><html><head><meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m  <title>Recce — ${d.storeName||'Unknown'}</title>\u001b[39m\n\u001b[31m  <style>body{font-family:Arial,sans-serif;margin:0;padding:16px;background:#f1f5f9}\u001b[39m\n\u001b[31m  .card{background:#fff;border-radius:12px;padding:16px;margin-bottom:14px;box-shadow:0 1px 4px rgba(0,0,0,.08)}\u001b[39m\n\u001b[31m  h1{font-size:18px;color:#0f172a;margin:0 0 4px}h2{font-size:14px;color:#f97316;text-transform:uppercase;letter-spacing:.5px;margin:0 0 10px}\u001b[39m\n\u001b[31m  .meta{font-size:12px;color:#64748b;margin-bottom:12px}.photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}\u001b[39m\n\u001b[31m  img{width:100%;border-radius:8px;object-fit:cover}\u001b[39m\n\u001b[31m  .tag{display:inline-block;background:#0f172a;color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-right:4px}\u001b[39m\n\u001b[31m  @media print{body{background:#fff}.card{box-shadow:none}}</style></head><body>\u001b[39m\n\u001b[31m  <div class=\\\"card\\\">\u001b[39m\n\u001b[31m    <h1>${d.storeName||'Unknown Store'}</h1>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\"><span class=\\\"tag\\\">${d.brand||'No Brand'}</span>${d.address||''}</div>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\">📞 ${d.mobile||'—'} &nbsp;|&nbsp; 📅 ${d.date||'—'} &nbsp;|&nbsp; Submitted: ${ts}</div>\u001b[39m\n\u001b[31m    ${d.gpsCoords?`<div class=\\\"meta\\\">📍 ${d.gpsCoords.lat}, ${d.gpsCoords.lng} ±${d.gpsCoords.acc}m</div>`:''}\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${fvUrls.length?`<div class=\\\"card\\\"><h2>Front View Photos</h2><div class=\\\"photos\\\">${fvUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${ivUrls.length?`<div class=\\\"card\\\"><h2>Inside View Photos</h2><div class=\\\"photos\\\">${ivUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${d.hasVideo?`<div class=\\\"card\\\"><h2>Video</h2><div>${d.videoNote||'Video recorded'}</div></div>`:''}\u001b[39m\n\u001b[31m  ${(d.brandings||[]).length?`<div class=\\\"card\\\"><h2>Branding Items (${(d.brandings||[]).length})</h2>${brRows}</div>`:''}\u001b[39m\n\u001b[31m  ${adUrls.length?`<div class=\\\"card\\\"><h2>Additional Photos</h2><div class=\\\"photos\\\">${adUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${docUrl?`<div class=\\\"card\\\"><h2>Submission Document</h2><img src=\\\"${docUrl}\\\" style=\\\"width:100%;max-height:300px;object-fit:contain\\\"></div>`:''}\u001b[39m\n\u001b[31m  <div style=\\\"text-align:center;margin:16px 0\\\">\u001b[39m\n\u001b[31m    <button onclick=\\\"window.print()\\\" style=\\\"background:#f97316;color:#fff;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer\\\">🖨 Print / Save as PDF</button>\u001b[39m\n\u001b[31m    <button onclick=\\\"window.close()\\\" style=\\\"background:#e2e8f0;color:#475569;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer;margin-left:10px\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  </body></html>`;\u001b[39m\n\u001b[31m  const blob=new Blob([html],{type:'text/html'});\u001b[39m\n\u001b[31m  const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m  window.open(url,'_blank');\u001b[39m\n\u001b[31m  setTimeout(()=>URL.revokeObjectURL(url),30000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── EDIT OLD RECCE ───────────────────────────────────────────\u001b[39m\n\u001b[31masync function editRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=d.gpsCoords||null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  F.editingId=id;F.date=d.date||'';F.brand=d.brand||'';F.storeName=d.storeName||'';F.address=d.address||'';F.mobile=d.mobile||'';F.hasVideo=d.hasVideo;F.hasBranding=d.hasBranding;\u001b[39m\n\u001b[31m  async function b64ToBlob(b64){if(!b64)return null;try{const r=await fetch(b64);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m  toast('Loading recce data…','info');\u001b[39m\n\u001b[31m  for(const p of(d.frontPhotos||[])){const b=await b64ToBlob(p.b64);if(b)frontPhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const p of(d.insidePhotos||[])){const b=await b64ToBlob(p.b64);if(b)insidePhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const br of(d.brandings||[])){const b=await b64ToBlob(br.photoB64);brandings.push({type:br.type,w:br.w,h:br.h,qty:br.qty,blob:b,prev:b?URL.createObjectURL(b):null});}\u001b[39m\n\u001b[31m  for(const p of(d.addlPhotos||[])){const b=await b64ToBlob(p.b64);if(b)addlPhotos.push({blob:b,prev:URL.createObjectURL(b),desc:p.desc||''});}\u001b[39m\n\u001b[31m  if(d.docB64){const b=await b64ToBlob(d.docB64);if(b){submissionDoc=b;const sl=document.getElementById('doc-slot');sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${URL.createObjectURL(b)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}}\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  if(F.brand)document.getElementById('f-brand').value=F.brand;\u001b[39m\n\u001b[31m  if(F.storeName)document.getElementById('f-store').value=F.storeName;\u001b[39m\n\u001b[31m  if(F.address)document.getElementById('f-addr').value=F.address;\u001b[39m\n\u001b[31m  if(F.mobile)document.getElementById('f-mobile').value=F.mobile;\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();updAvailTag();\u001b[39m\n\u001b[31m  toast('Recce loaded — make changes and re-submit','success');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── EDIT REQUEST ────────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mlet _editReqSubId = null;·\u001b[39m\n\u001b[31mfunction _hydratePhotosFromRow(r) {\u001b[39m\n\u001b[31m  let pu={};\u001b[39m\n\u001b[31m  try{pu=typeof r.photo_urls==='string'?JSON.parse(r.photo_urls):(r.photo_urls||{});}catch(_){}\u001b[39m\n\u001b[31m  let meta={};\u001b[39m\n\u001b[31m  try{meta=typeof r.meta==='string'?JSON.parse(r.meta):(r.meta||{});}catch(_){}\u001b[39m\n\u001b[31m  frontPhotos =(pu.front   ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  insidePhotos=(pu.inside  ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  addlPhotos  =(pu.addl    ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,desc:''}));\u001b[39m\n\u001b[31m  brandings   =(meta.brandings||[]).map((b,i)=>({type:b.type,w:b.w,h:b.h,qty:b.qty,existingUrl:(pu.brandings||[])[i]||null,blob:null,prev:(pu.brandings||[])[i]||null}));\u001b[39m\n\u001b[31m  _docExistingUrl=pu.doc||null;\u001b[39m\n\u001b[31m  // Show retained doc in slot\u001b[39m\n\u001b[31m  const sl=document.getElementById('doc-slot');\u001b[39m\n\u001b[31m  if(sl&&_docExistingUrl){sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${_docExistingUrl}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openEditRequestModal(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  _editReqSubId = subId;\u001b[39m\n\u001b[31m  document.getElementById('er-store-name').textContent = r.store_name || 'Unknown';\u001b[39m\n\u001b[31m  document.getElementById('er-comment').value = '';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const assignBtn = document.getElementById('er-assign-btn');\u001b[39m\n\u001b[31m  if (r.submitted_by && r.submitted_by !== hub?.empId) {\u001b[39m\n\u001b[31m    assignBtn.textContent = `👤 Assign to ${r.submitted_by}`;\u001b[39m\n\u001b[31m    assignBtn.style.display = '';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    assignBtn.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeEditRequestModal() {\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _editReqSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorEditMyself() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  // Lock branding if client has reviewed (preserve their approval)\u001b[39m\n\u001b[31m  _brandingLocked = !!(r.client_status && r.client_status !== 'pending');\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function assignEditToCreator() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r || !r.submitted_by) { toast('No creator found for this recce', 'error'); return; }\u001b[39m\n\u001b[31m  const comment = (document.getElementById('er-comment').value || '').trim();\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        status: 'edit_requested',\u001b[39m\n\u001b[31m        edit_assigned_to: r.submitted_by,\u001b[39m\n\u001b[31m        edit_comment: comment || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!resp.ok) throw new Error('Update failed: ' + resp.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].status = 'edit_requested';\u001b[39m\n\u001b[31m      _adminRows[idx].edit_assigned_to = r.submitted_by;\u001b[39m\n\u001b[31m      _adminRows[idx].edit_comment = comment || null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Push notification to creator\u001b[39m\n\u001b[31m    const notifBody = comment || `Please review and re-submit: ${r.store_name || 'your recce'}`;\u001b[39m\n\u001b[31m    fetch('/push-server/notify', {\u001b[39m\n\u001b[31m      method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        user_id: r.submitted_by, title: '✏ Edit Requested',\u001b[39m\n\u001b[31m        body: notifBody, tag: `recce-edit-${subId}`, url: '/recce/',\u001b[39m\n\u001b[31m        icon: '/hub/icons/icon-192.png', badge: '/hub/icons/icon-192.png',\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    }).catch(() => {});\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast(`Edit assigned to ${r.submitted_by} ✓`, 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Assign failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function startCreatorEdit(subId) {\u001b[39m\n\u001b[31m  // Try local IndexedDB first (has photos)\u001b[39m\n\u001b[31m  const local = await dbGet('subs', subId);\u001b[39m\n\u001b[31m  if (local) { await editRecce(subId); return; }\u001b[39m\n\u001b[31m  // Fallback: load text fields from server row\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId)\u001b[39m\n\u001b[31m         || (await (async () => {\u001b[39m\n\u001b[31m              try {\u001b[39m\n\u001b[31m                const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, { headers: _RC_READ });\u001b[39m\n\u001b[31m                if (resp.ok) { const arr = await resp.json(); return arr[0]; }\u001b[39m\n\u001b[31m              } catch(_) {} return null;\u001b[39m\n\u001b[31m            })());\u001b[39m\n\u001b[31m  if (!r) { toast('Record not found', 'error'); return; }\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── End edit request ─────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mfunction goToHub() { window.location.href = '/hub/'; }\u001b[39m\n\u001b[31mfunction recceLogout() {\u001b[39m\n\u001b[31m  if (!confirm('Log out?')) return;\u001b[39m\n\u001b[31m  localStorage.removeItem('lm360-session');\u001b[39m\n\u001b[31m  localStorage.removeItem('360exp-session');\u001b[39m\n\u001b[31m  window.location.href = '/hub/';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction injectHubButtons() {\u001b[39m\n\u001b[31m  const u = _recceHubUser();\u001b[39m\n\u001b[31m  const name = u ? (u.name || '') : '';\u001b[39m\n\u001b[31m  if (name) {\u001b[39m\n\u001b[31m    const bar = document.getElementById('recce-hero-ubar');\u001b[39m\n\u001b[31m    const nm  = document.getElementById('recce-hero-name');\u001b[39m\n\u001b[31m    if (bar) { nm.textContent = name; bar.style.display = 'flex'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.querySelectorAll('.hdr').forEach(hdr => {\u001b[39m\n\u001b[31m    const r = document.createElement('div');\u001b[39m\n\u001b[31m    r.className = 'hdr-r';\u001b[39m\n\u001b[31m    if (name) {\u001b[39m\n\u001b[31m      const un = document.createElement('span');\u001b[39m\n\u001b[31m      un.className = 'hdr-user';\u001b[39m\n\u001b[31m      un.textContent = name;\u001b[39m\n\u001b[31m      r.appendChild(un);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    const hub = document.createElement('button');\u001b[39m\n\u001b[31m    hub.className = 'btn-hub';\u001b[39m\n\u001b[31m    hub.innerHTML = '🏡 Hub';\u001b[39m\n\u001b[31m    hub.addEventListener('click', goToHub);\u001b[39m\n\u001b[31m    r.appendChild(hub);\u001b[39m\n\u001b[31m    const lo = document.createElement('button');\u001b[39m\n\u001b[31m    lo.className = 'btn-logout';\u001b[39m\n\u001b[31m    lo.textContent = 'Logout';\u001b[39m\n\u001b[31m    lo.addEventListener('click', recceLogout);\u001b[39m\n\u001b[31m    r.appendChild(lo);\u001b[39m\n\u001b[31m    hdr.appendChild(r);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction checkAppUpdate(){\u001b[39m\n\u001b[31m  const seen=localStorage.getItem('recce-ver-seen');\u001b[39m\n\u001b[31m  localStorage.setItem('recce-ver-seen',CACHE_VER);\u001b[39m\n\u001b[31m  if(seen&&seen!==CACHE_VER){\u001b[39m\n\u001b[31m    const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m    if(b){b.classList.add('show');setTimeout(()=>b.classList.remove('show'),5000);}\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction dismissUpdateBanner(){\u001b[39m\n\u001b[31m  const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m  if(b)b.classList.remove('show');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function init(){\u001b[39m\n\u001b[31m  // Detect host banners (tiiny.host, etc) and raise bnav above them\u001b[39m\n\u001b[31m  (function detectHostBar(){\u001b[39m\n\u001b[31m    const h=window.location.hostname;\u001b[39m\n\u001b[31m    let extra=0;\u001b[39m\n\u001b[31m    if(h.includes('tiiny'))extra=58;\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // Generic detection: check if window is shorter than expected (host injected a bar)\u001b[39m\n\u001b[31m      const gap=screen.height - window.innerHeight;\u001b[39m\n\u001b[31m      if(gap>100&&gap<200)extra=58; // a fixed bar is roughly 56-60px\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if(extra>0){\u001b[39m\n\u001b[31m      document.documentElement.style.setProperty('--host-bar',extra+'px');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  })();\u001b[39m\n\u001b[31m  setLang(LANG);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m  checkAppUpdate();\u001b[39m\n\u001b[31m  await loadRecceCfg();\u001b[39m\n\u001b[31m  _checkAccessMode();\u001b[39m\n\u001b[31m  await initDB();await loadSettings();await loadHome();await checkDraft();netStatus();window.addEventListener('online',()=>{netStatus();syncNow();});window.addEventListener('offline',netStatus);injectHubButtons();document.getElementById('today-date').textContent=new Date().toLocaleDateString('en-IN',{weekday:'long',day:'numeric',month:'long',year:'numeric'});updAvailTag();\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m  // Auto-fetch stores from server on every startup (uses default Netlify URL if none saved)\u001b[39m\n\u001b[31m  const su=(await cfg('srv-url'))||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su&&navigator.onLine){\u001b[39m\n\u001b[31m    fetch(su).then(r=>r.json()).then(async j=>{\u001b[39m\n\u001b[31m      const d=Array.isArray(j)?j:j.stores||[];\u001b[39m\n\u001b[31m      if(d.length){stores=d;await cfg('stores',JSON.stringify(d));await cfg('srv-url',su);updAvailTag();\u001b[39m\n\u001b[31m        document.getElementById('srv-url').value=su;}\u001b[39m\n\u001b[31m    }).catch(()=>{});\u001b[39m\n\u001b[31m  }}init();\u001b[39m\n\u001b[31m</script>\u001b[39m\n\u001b[31m</body>\u001b[39m\n\u001b[31m</html>\u001b[39m\n\u001b[31m\"\u001b[39m",
                        "stack": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoContain\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // indexOf\u001b[22m\n\nExpected substring: \u001b[32m\"recce-v15\"\u001b[39m\nReceived string:    \u001b[31m\"<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\">\u001b[39m\n\u001b[31m<head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\">\u001b[39m\n\u001b[31m<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\\\">\u001b[39m\n\u001b[31m<meta name=\\\"theme-color\\\" content=\\\"#0f172a\\\">\u001b[39m\n\u001b[31m<meta name=\\\"apple-mobile-web-app-capable\\\" content=\\\"yes\\\">\u001b[39m\n\u001b[31m<title>Branding Recce</title>\u001b[39m\n\u001b[31m<link rel=\\\"manifest\\\" href=\\\"manifest.json\\\">\u001b[39m\n\u001b[31m<link rel=\\\"preconnect\\\" href=\\\"https://fonts.googleapis.com\\\">\u001b[39m\n\u001b[31m<link href=\\\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap\\\" rel=\\\"stylesheet\\\">\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--nv:#0f172a;--nv2:#1e293b;--or:#f97316;--orl:#fed7aa;--gn:#16a34a;--rd:#dc2626;--am:#d97706;--g50:#f8fafc;--g100:#f1f5f9;--g200:#e2e8f0;--g300:#cbd5e1;--g400:#94a3b8;--g500:#64748b;--g600:#475569;--r:12px;--rs:8px;--sh:0 1px 3px rgba(0,0,0,.1),0 1px 2px rgba(0,0,0,.06);--bnav-h:72px;--host-bar:0px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}\u001b[39m\n\u001b[31mbody{font-family:'DM Sans',sans-serif;background:var(--g50);color:var(--nv);min-height:100vh;overflow-x:hidden}\u001b[39m\n\u001b[31m.hdr{background:var(--nv);color:#fff;padding:0 16px;height:56px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}\u001b[39m\n\u001b[31m.hdr-l{display:flex;align-items:center;gap:10px}\u001b[39m\n\u001b[31m.hdr-title{font-size:16px;font-weight:600}.hdr-sub{font-size:11px;color:var(--g400)}\u001b[39m\n\u001b[31m.back-btn,.icon-btn{background:none;border:none;color:#fff;padding:8px;cursor:pointer;display:flex;align-items:center}\u001b[39m\n\u001b[31m.back-btn{margin-left:-8px}\u001b[39m\n\u001b[31m.pgbar{height:3px;background:var(--g200)}.pgfill{height:100%;background:var(--or);transition:width .3s}\u001b[39m\n\u001b[31m.view{display:none;min-height:calc(100vh - 56px);padding-bottom:calc(var(--bnav-h) + var(--host-bar) + 24px)}.view.active{display:block}\u001b[39m\n\u001b[31m.content{padding:16px}\u001b[39m\n\u001b[31m.card{background:#fff;border-radius:var(--r);padding:16px;box-shadow:var(--sh);margin-bottom:12px}\u001b[39m\n\u001b[31m.card-title{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;letter-spacing:.6px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between}\u001b[39m\n\u001b[31m.cnt-badge{background:var(--or);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;min-width:22px;text-align:center}\u001b[39m\n\u001b[31m.cnt-badge.gray{background:var(--g400)}\u001b[39m\n\u001b[31m.field{margin-bottom:16px}.field:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.field label{display:block;font-size:13px;font-weight:500;color:var(--g600);margin-bottom:6px}\u001b[39m\n\u001b[31m.req{color:var(--or);margin-left:2px}\u001b[39m\n\u001b[31m.field input,.field select,.field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;color:var(--nv);background:#fff;transition:border-color .15s;-webkit-appearance:none;appearance:none}\u001b[39m\n\u001b[31m.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--or)}\u001b[39m\n\u001b[31m.field input:read-only{background:var(--g50);color:var(--g600)}\u001b[39m\n\u001b[31m.field textarea{resize:vertical;min-height:68px}\u001b[39m\n\u001b[31m.field select{background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}\u001b[39m\n\u001b[31m.pslot{border:2px dashed var(--g300);border-radius:var(--r);min-height:110px;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all .15s;position:relative;overflow:hidden;text-align:center;padding:16px}\u001b[39m\n\u001b[31m.pslot:active{border-color:var(--or);background:var(--g50)}\u001b[39m\n\u001b[31m.pslot.filled{border-style:solid;border-color:var(--or);padding:0;min-height:0}\u001b[39m\n\u001b[31m.pslot img{width:100%;height:150px;object-fit:cover;border-radius:calc(var(--r) - 2px);display:block}\u001b[39m\n\u001b[31m.pslot-lbl{font-size:13px;color:var(--g400);margin-top:6px}.pslot-ico{font-size:28px;color:var(--g300)}\u001b[39m\n\u001b[31m.pbadge{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.premove{position:absolute;top:6px;right:6px;background:var(--rd);color:#fff;border:none;border-radius:50%;width:26px;height:26px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;z-index:5}\u001b[39m\n\u001b[31minput[type=file]{display:none}\u001b[39m\n\u001b[31m.rgroup{display:flex;gap:10px}\u001b[39m\n\u001b[31m.rbtn{flex:1;padding:13px;border:1.5px solid var(--g200);border-radius:var(--rs);text-align:center;cursor:pointer;font-size:14px;font-weight:500;color:var(--g500);transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.rbtn.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.chip-grid{display:flex;flex-wrap:wrap;gap:8px}\u001b[39m\n\u001b[31m.chip{padding:7px 12px;border:1.5px solid var(--g200);border-radius:20px;font-size:13px;color:var(--g600);cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.chip.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.brand-chip{display:flex;align-items:center;gap:6px;padding:5px 12px}\u001b[39m\n\u001b[31m.brand-chip-logo{width:28px;height:18px;object-fit:contain;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{display:block;width:100%;padding:15px;background:var(--or);color:#fff;border:none;border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:700;cursor:pointer;text-align:center;transition:background .15s}\u001b[39m\n\u001b[31m.btn-p:active{background:#ea6c05}.btn-p:disabled{background:var(--g300);cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-s{display:block;width:100%;padding:14px;background:#fff;color:var(--nv);border:1.5px solid var(--g200);border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:500;cursor:pointer;text-align:center}\u001b[39m\n\u001b[31m.btn-s:active{background:var(--g100)}\u001b[39m\n\u001b[31m.btn-o{display:inline-flex;align-items:center;gap:6px;padding:10px 16px;background:#fff;color:var(--or);border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer}\u001b[39m\n\u001b[31m.btn-o:active{background:var(--orl)}\u001b[39m\n\u001b[31m.btn-d{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;background:#fff;color:var(--rd);border:1.5px solid #fecaca;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:12px;cursor:pointer}\u001b[39m\n\u001b[31m.bnav{position:fixed;bottom:var(--host-bar);left:0;right:0;background:#fff;border-top:1px solid var(--g200);display:flex;padding:10px 16px;gap:10px;z-index:100}\u001b[39m\n\u001b[31m.hero{background:var(--nv);color:#fff;padding:20px 16px 24px}\u001b[39m\n\u001b[31m.hero-title{font-size:22px;font-weight:700;margin-bottom:2px}.hero-sub{font-size:13px;color:var(--g400)}\u001b[39m\n\u001b[31m.stats{display:flex;gap:10px;margin-top:16px}\u001b[39m\n\u001b[31m.scard{flex:1;background:rgba(255,255,255,.08);border-radius:var(--rs);padding:12px;text-align:center}\u001b[39m\n\u001b[31m.snum{font-size:22px;font-weight:700}.slbl{font-size:11px;color:var(--g400);margin-top:2px}\u001b[39m\n\u001b[31m.scard.g .snum{color:#4ade80}.scard.a .snum{color:#fbbf24}\u001b[39m\n\u001b[31m.new-btn{background:var(--or);color:#fff;border:none;border-radius:var(--r);padding:16px;font-family:'DM Sans',sans-serif;font-size:16px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:10px;cursor:pointer;width:100%;margin-bottom:10px}\u001b[39m\n\u001b[31m.new-btn:active{background:#ea6c05}\u001b[39m\n\u001b[31m.resume-btn{background:var(--nv2);color:#fff;border:none;border-radius:var(--r);padding:13px 16px;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;display:flex;align-items:center;justify-content:space-between;cursor:pointer;width:100%;margin-bottom:18px}\u001b[39m\n\u001b[31m.sub-card{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:10px;display:flex;align-items:center;gap:12px}\u001b[39m\n\u001b[31m.sub-ico{width:40px;height:40px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}\u001b[39m\n\u001b[31m.sub-ico.pending{background:#fef3c7}.sub-ico.synced{background:#dcfce7}.sub-ico.failed{background:#fee2e2}\u001b[39m\n\u001b[31m.sub-meta{flex:1;min-width:0}.sub-name{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.sub-dtl{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.sbadge{font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;flex-shrink:0}\u001b[39m\n\u001b[31m.sbadge.pending{background:#fef3c7;color:#92400e}.sbadge.synced{background:#dcfce7;color:#14532d}.sbadge.failed{background:#fee2e2;color:#991b1b}\u001b[39m\n\u001b[31m.sh{display:flex;align-items:center;justify-content:space-between;margin:20px 0 12px}\u001b[39m\n\u001b[31m.st{font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.toast{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 8px);left:16px;right:16px;background:var(--nv);color:#fff;padding:12px 16px;border-radius:var(--r);font-size:14px;z-index:1000;transform:translateY(120px);opacity:0;transition:all .3s;pointer-events:none}\u001b[39m\n\u001b[31m.toast.show{transform:translateY(0);opacity:1}.toast.success{background:#16a34a}.toast.error{background:var(--rd)}.toast.info{background:var(--nv2)}\u001b[39m\n\u001b[31m.srow{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:#fff;border-top:1px solid var(--g100);font-size:12px;color:var(--g500)}\u001b[39m\n\u001b[31m.sdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px}.sdot.on{background:var(--gn)}.sdot.off{background:var(--g300)}\u001b[39m\n\u001b[31m.set-item{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:8px}\u001b[39m\n\u001b[31m.set-lbl{font-size:14px;font-weight:600;color:var(--nv);margin-bottom:4px}\u001b[39m\n\u001b[31m.set-sub{font-size:12px;color:var(--g500);margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem{background:#fff;border-radius:var(--r);border:1.5px solid var(--g200);padding:14px;margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\u001b[39m\n\u001b[31m.bitem-title{font-size:14px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.dim-row{display:flex;gap:8px}.dim-row .field{flex:1}\u001b[39m\n\u001b[31m.sqft{display:inline-block;background:var(--g100);color:var(--g600);font-size:12px;padding:4px 10px;border-radius:20px;margin-top:6px}\u001b[39m\n\u001b[31m.divider{height:1px;background:var(--g100);margin:12px 0}\u001b[39m\n\u001b[31m.rev-lbl{font-size:12px;color:var(--g500);margin-bottom:2px}\u001b[39m\n\u001b[31m.rev-val{font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.rev-photos{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}\u001b[39m\n\u001b[31m.rev-thumb{width:56px;height:56px;object-fit:cover;border-radius:var(--rs)}\u001b[39m\n\u001b[31m.empty{text-align:center;padding:40px 20px;color:var(--g400)}.empty-ico{font-size:40px;margin-bottom:12px}.empty-txt{font-size:14px}\u001b[39m\n\u001b[31m/* store picker */\u001b[39m\n\u001b[31m.store-card{border:1.5px solid var(--g200);border-radius:var(--rs);padding:13px 14px;background:#fff;position:relative;cursor:pointer}\u001b[39m\n\u001b[31m.store-card:active{background:var(--g50)}\u001b[39m\n\u001b[31m.store-card-name{font-size:15px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.store-card-meta{font-size:13px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.store-card-change{position:absolute;top:11px;right:12px;background:none;border:none;color:var(--or);font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer}\u001b[39m\n\u001b[31m.brand-tag{display:inline-block;background:var(--nv);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-top:4px}\u001b[39m\n\u001b[31m.last-chip{display:inline-flex;align-items:center;gap:4px;background:#fef3c7;color:#92400e;font-size:11px;font-weight:500;padding:3px 9px;border-radius:20px;margin-left:6px}\u001b[39m\n\u001b[31m.pick-trigger{border:2px solid var(--or);border-radius:var(--rs);padding:14px 16px;background:#fff7ed;display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-size:15px;font-weight:600;color:var(--or)}\u001b[39m\n\u001b[31m.pick-trigger:active{background:#ffedd5;border-color:#ea6800}\u001b[39m\n\u001b[31m.manual-toggle{display:flex;align-items:center;gap:8px;padding:10px 14px;border:1.5px dashed var(--g300);border-radius:var(--rs);cursor:pointer;font-size:13px;color:var(--g600);margin-top:8px;user-select:none}\u001b[39m\n\u001b[31m/* client chip grid */\u001b[39m\n\u001b[31m.cl-chip-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}\u001b[39m\n\u001b[31m.cl-chip{padding:8px 14px;border-radius:20px;border:1.5px solid var(--g200);font-size:13px;font-weight:500;color:var(--g600);background:#fff;cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.cl-chip:active,.cl-chip.sel{background:var(--or);border-color:var(--or);color:#fff;font-weight:600}\u001b[39m\n\u001b[31m.cl-chip-other{border-style:dashed}\u001b[39m\n\u001b[31m.client-tag{display:inline-block;background:#e0f2fe;color:#0369a1;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-left:4px}\u001b[39m\n\u001b[31m.manual-toggle.on{border-color:var(--or);background:#fff7ed;color:var(--or)}\u001b[39m\n\u001b[31m/* picker overlay */\u001b[39m\n\u001b[31m.povl{display:none;position:fixed;inset:0;background:var(--g50);z-index:200;flex-direction:column}\u001b[39m\n\u001b[31m.povl.open{display:flex}\u001b[39m\n\u001b[31m.povl-hdr{background:var(--nv);padding:12px 16px;display:flex;align-items:center;gap:12px;flex-shrink:0}\u001b[39m\n\u001b[31m.psearch{flex:1;padding:10px 14px;border:none;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;background:rgba(255,255,255,.12);color:#fff;outline:none}\u001b[39m\n\u001b[31m.psearch::placeholder{color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.pcancel{background:none;border:none;color:rgba(255,255,255,.7);font-family:'DM Sans',sans-serif;font-size:14px;cursor:pointer;padding:4px;white-space:nowrap}\u001b[39m\n\u001b[31m.plist{overflow-y:auto;flex:1}\u001b[39m\n\u001b[31m.pitem{padding:14px 16px;border-bottom:.5px solid var(--g100);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px}\u001b[39m\n\u001b[31m.pitem:active{background:var(--g100)}\u001b[39m\n\u001b[31m.pi-name{font-size:15px;font-weight:600;color:var(--nv)}.pi-addr{font-size:12px;color:var(--g500);margin-top:2px}.pi-last{font-size:11px;color:var(--am);margin-top:2px}\u001b[39m\n\u001b[31m.pi-brand{font-size:11px;font-weight:700;padding:3px 8px;border-radius:20px;background:var(--nv);color:#fff;flex-shrink:0}\u001b[39m\n\u001b[31m.psec{padding:8px 16px 4px;font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;background:var(--g50)}\u001b[39m\n\u001b[31m.padd{padding:16px;text-align:center;font-size:14px;color:var(--or);font-weight:600;cursor:pointer;background:#fff7ed;border-top:1.5px dashed var(--or)}\u001b[39m\n\u001b[31m.gps-row{display:flex;gap:8px;margin-top:8px}\u001b[39m\n\u001b[31m.gps-btn{flex-shrink:0;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;color:var(--g500);display:flex;align-items:center;gap:6px}\u001b[39m\n\u001b[31m.gps-btn:active{background:var(--orl);border-color:var(--or);color:var(--or)}\u001b[39m\n\u001b[31m@keyframes spin{to{transform:rotate(360deg)}}.spin{animation:spin .7s linear infinite;display:inline-block}\u001b[39m\n\u001b[31m/* ANNOTATION TOOL */\u001b[39m\n\u001b[31m.annot-modal{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column}\u001b[39m\n\u001b[31m.annot-modal.open{display:flex}\u001b[39m\n\u001b[31m.annot-bar{background:var(--nv);padding:8px 12px;flex-shrink:0}\u001b[39m\n\u001b[31m.annot-row{display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap}\u001b[39m\n\u001b[31m.annot-row:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.atool{padding:6px 10px;background:rgba(255,255,255,.1);border:1.5px solid rgba(255,255,255,.2);border-radius:var(--rs);color:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:500;cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.atool.on{background:var(--or);border-color:var(--or)}\u001b[39m\n\u001b[31m.atool.sel-on{background:#7c3aed;border-color:#7c3aed}\u001b[39m\n\u001b[31m.acolor{width:24px;height:24px;border-radius:50%;border:2px solid rgba(255,255,255,.3);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.acolor.on{border-color:#fff;border-width:3px;transform:scale(1.15)}\u001b[39m\n\u001b[31m.annot-cvs-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#111;position:relative}\u001b[39m\n\u001b[31m#annot-cvs{max-width:100%;max-height:100%;display:block;touch-action:none;cursor:crosshair}\u001b[39m\n\u001b[31m.annot-foot{background:var(--nv);padding:10px 16px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.req-note{font-size:12px;color:var(--rd);margin-top:6px;font-weight:500}\u001b[39m\n\u001b[31m/* Bottom dialog */\u001b[39m\n\u001b[31m.bdialog-wrap{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:400;align-items:flex-end}\u001b[39m\n\u001b[31m.bdialog-wrap.open{display:flex}\u001b[39m\n\u001b[31m.bdialog{background:#fff;border-radius:var(--r) var(--r) 0 0;padding:20px 16px 32px;width:100%}\u001b[39m\n\u001b[31m.bdialog-title{font-size:16px;font-weight:700;color:var(--nv);margin-bottom:6px}\u001b[39m\n\u001b[31m.bdialog-sub{font-size:13px;color:var(--g500);margin-bottom:16px}\u001b[39m\n\u001b[31m.bdialog-btns{display:flex;gap:10px}\u001b[39m\n\u001b[31m/* Edit badge on sub-card */\u001b[39m\n\u001b[31m.edit-btn-sm{padding:5px 12px;background:var(--g50);border:1px solid var(--g200);border-radius:20px;font-family:'DM Sans',sans-serif;font-size:12px;color:var(--g600);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m/* Toggle switch */\u001b[39m\n\u001b[31m.tog{width:48px;height:26px;background:var(--g300);border-radius:13px;cursor:pointer;transition:background .2s;flex-shrink:0;position:relative;display:inline-block}\u001b[39m\n\u001b[31m.tog.on{background:var(--or)}\u001b[39m\n\u001b[31m.tog-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2);pointer-events:none}\u001b[39m\n\u001b[31m.tog.on .tog-knob{transform:translateX(22px)}\u001b[39m\n\u001b[31m/* ── ADMIN RECCE VIEW ── */\u001b[39m\n\u001b[31m.af-bar{background:var(--g100);padding:10px 16px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--g200);overflow:hidden}\u001b[39m\n\u001b[31m.af-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}\u001b[39m\n\u001b[31m.af-sel{width:100%;padding:8px 10px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv);cursor:pointer;\u001b[39m\n\u001b[31m  white-space:normal;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.af-sel:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.af-inp{width:100%;padding:8px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv)}\u001b[39m\n\u001b[31m.af-inp:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.grp-hdr{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;\u001b[39m\n\u001b[31m  letter-spacing:.5px;padding:14px 0 6px;border-bottom:1px solid var(--g200);margin-bottom:6px}\u001b[39m\n\u001b[31m.grp-hdr:first-child{padding-top:0}\u001b[39m\n\u001b[31m.asc{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:12px 14px;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;gap:6px;margin-bottom:8px;cursor:pointer;\u001b[39m\n\u001b[31m  transition:box-shadow .15s}\u001b[39m\n\u001b[31m.asc:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.asc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}\u001b[39m\n\u001b[31m.asc-name{font-size:14px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.asc-brand{display:inline-block;background:#fff7ed;color:var(--or);font-size:11px;\u001b[39m\n\u001b[31m  font-weight:600;padding:2px 8px;border-radius:20px;border:1px solid #fed7aa;white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chip{background:var(--g100);border-radius:20px;padding:2px 8px;font-size:11px;color:var(--g600);white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chips{display:flex;flex-wrap:wrap;gap:5px}\u001b[39m\n\u001b[31m.asc-agent{background:var(--nv);color:#fff;font-size:11px;font-weight:600;\u001b[39m\n\u001b[31m  padding:2px 8px;border-radius:20px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m/* Admin detail modal */\u001b[39m\n\u001b[31m.ardl-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:600;\u001b[39m\n\u001b[31m  display:flex;align-items:flex-end;justify-content:center}\u001b[39m\n\u001b[31m.ardl-box{background:#fff;border-radius:var(--r) var(--r) 0 0;width:100%;max-height:80vh;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ardl-hdr{display:flex;align-items:flex-start;justify-content:space-between;\u001b[39m\n\u001b[31m  padding:16px 16px 10px;border-bottom:1px solid var(--g200);gap:10px}\u001b[39m\n\u001b[31m.ardl-title{font-size:17px;font-weight:700;color:var(--nv);line-height:1.3}\u001b[39m\n\u001b[31m.ardl-body{flex:1;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:14px}\u001b[39m\n\u001b[31m.ardl-sec{display:flex;flex-direction:column;gap:6px}\u001b[39m\n\u001b[31m.ardl-lbl{font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.ardl-val{font-size:13px;color:var(--nv);line-height:1.5}\u001b[39m\n\u001b[31m.ardl-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\u001b[39m\n\u001b[31m/* Hub home button */\u001b[39m\n\u001b[31m.btn-hub{background:none;border:1px solid rgba(255,255,255,.25);color:rgba(255,255,255,.85);\u001b[39m\n\u001b[31m  font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;cursor:pointer;\u001b[39m\n\u001b[31m  display:flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-hub:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hdr-r{display:flex;align-items:center;gap:6px;margin-left:auto;flex-shrink:0}\u001b[39m\n\u001b[31m.hdr-user{font-size:11px;color:rgba(255,255,255,.7);white-space:nowrap;max-width:80px;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.btn-logout{background:none;border:1px solid rgba(255,255,255,.2);color:rgba(255,255,255,.7);font-size:11px;font-weight:600;padding:4px 8px;border-radius:20px;cursor:pointer;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-logout:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hero-ubar{display:flex;align-items:center;justify-content:space-between;padding-top:6px;margin-top:2px}\u001b[39m\n\u001b[31m.hero-uname{font-size:12px;color:rgba(255,255,255,.65)}\u001b[39m\n\u001b[31m.hi-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .en-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .hi-txt{display:inline}\u001b[39m\n\u001b[31m.lang-btn{background:none;border:1px solid rgba(255,255,255,.3);color:rgba(255,255,255,.8);font-size:12px;font-weight:700;padding:4px 10px;border-radius:20px;cursor:pointer;display:flex;align-items:center;gap:3px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.lang-btn:active{background:rgba(255,255,255,.15)}\u001b[39m\n\u001b[31m/* ── DELETE / AUDIT ── */\u001b[39m\n\u001b[31m.del-btn{background:none;border:none;padding:6px 8px;cursor:pointer;color:var(--g400);font-size:16px;flex-shrink:0;border-radius:var(--rs);transition:color .15s,background .15s}\u001b[39m\n\u001b[31m.del-btn:active{color:var(--rd);background:#fee2e2}\u001b[39m\n\u001b[31m.asc.deleted-row{background:#fff5f5;border:1px solid #fecaca;opacity:.85}\u001b[39m\n\u001b[31m.asc.deleted-row .asc-name{text-decoration:line-through;color:var(--g500)}\u001b[39m\n\u001b[31m.del-reason-tag{display:inline-block;background:#fee2e2;color:var(--rd);font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.del-by-txt{font-size:11px;color:var(--g400);margin-top:3px}\u001b[39m\n\u001b[31m.restore-btn{background:none;border:1.5px solid #bbf7d0;border-radius:20px;color:#16a34a;font-size:11px;font-weight:700;padding:3px 10px;cursor:pointer;white-space:nowrap;margin-top:5px}\u001b[39m\n\u001b[31m.restore-btn:active{background:#dcfce7}\u001b[39m\n\u001b[31m.sup-tile{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:20px 16px;cursor:pointer;display:flex;align-items:center;gap:14px;margin-bottom:12px;transition:box-shadow .15s}\u001b[39m\n\u001b[31m.sup-tile:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.sup-tile-ico{width:48px;height:48px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:26px;flex-shrink:0}\u001b[39m\n\u001b[31m.sup-tile-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.sup-tile-title{font-size:15px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.sup-tile-sub{font-size:12px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.del-toggle-btn{padding:6px 14px;border:1.5px solid var(--g200);border-radius:20px;background:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:600;color:var(--g500);cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.del-toggle-btn.active{background:#fee2e2;border-color:#fecaca;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1.5px solid var(--g200);border-radius:var(--r);margin-bottom:10px;cursor:pointer;transition:all .15s;font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.reason-opt:active{background:var(--g50)}\u001b[39m\n\u001b[31m.reason-opt.sel{border-color:var(--rd);background:#fff5f5;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt.danger{border-color:#fdba74;background:#fff7ed;color:#9a3412}\u001b[39m\n\u001b[31m.reason-opt.danger.sel{border-color:#c2410c;background:#fff1e6;color:#9a3412}\u001b[39m\n\u001b[31m#del-confirm-btn.no-reason{background:var(--g300)!important;cursor:default}\u001b[39m\n\u001b[31m@keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}\u001b[39m\n\u001b[31m.reason-opt-ico{font-size:22px;flex-shrink:0}\u001b[39m\n\u001b[31m/* ── APP UPDATE BANNER ── */\u001b[39m\n\u001b[31m.upd-banner{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);left:12px;right:12px;background:#16a34a;color:#fff;padding:11px 14px;border-radius:var(--r);display:flex;align-items:center;justify-content:space-between;gap:10px;z-index:550;box-shadow:0 4px 16px rgba(0,0,0,.18);transform:translateY(120px);opacity:0;transition:transform .35s ease,opacity .35s ease;pointer-events:none}\u001b[39m\n\u001b[31m.upd-banner.show{transform:translateY(0);opacity:1;pointer-events:auto}\u001b[39m\n\u001b[31m/* ── EDIT REQUEST ── */\u001b[39m\n\u001b[31m.req-edit-btn{padding:4px 10px;background:#fffbeb;border:1px solid #fde68a;border-radius:20px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:600;color:#92400e;cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.req-edit-btn:active{background:#fef3c7}\u001b[39m\n\u001b[31m.edit-req-badge{display:inline-block;background:#fef3c7;color:#92400e;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;white-space:nowrap}\u001b[39m\n\u001b[31m.edit-req-card{background:#fffbeb;border:1.5px solid #fde68a;border-radius:var(--r);padding:14px 16px;margin-bottom:10px;display:flex;align-items:flex-start;gap:12px}\u001b[39m\n\u001b[31m.edit-req-card-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.edit-req-card-name{font-size:14px;font-weight:600;color:var(--nv);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.edit-req-card-meta{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.edit-req-cmt{font-size:12px;color:#78350f;background:#fff;border:1px solid #fde68a;border-radius:var(--rs);padding:8px 10px;margin-top:8px;line-height:1.5}\u001b[39m\n\u001b[31m.edit-req-section-hdr{font-size:11px;font-weight:700;color:#92400e;text-transform:uppercase;letter-spacing:.5px;padding:10px 0 6px;border-bottom:1px solid #fde68a;margin-bottom:8px}\u001b[39m\n\u001b[31m.upd-banner-ok{background:rgba(255,255,255,.2);border:none;color:#fff;border-radius:20px;padding:5px 13px;font-size:12px;font-weight:600;cursor:pointer;font-family:'DM Sans',sans-serif;white-space:nowrap}\u001b[39m\n\u001b[31m.upd-banner-ok:active{background:rgba(255,255,255,.35)}\u001b[39m\n\u001b[31m/* ── FONT SIZE WIDGET ── */\u001b[39m\n\u001b[31m.fs-widget{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);right:12px;display:flex;align-items:center;gap:0;background:#fff;border:1.5px solid var(--g200);border-radius:24px;box-shadow:0 2px 8px rgba(0,0,0,.12);z-index:500;overflow:hidden;user-select:none}\u001b[39m\n\u001b[31m.fs-btn{background:none;border:none;cursor:pointer;padding:7px 11px;color:var(--g500);line-height:1;transition:background .15s}\u001b[39m\n\u001b[31m.fs-btn:active{background:var(--g100)}\u001b[39m\n\u001b[31m.fs-btn:disabled{color:var(--g300);cursor:default}\u001b[39m\n\u001b[31m.fs-label{font-size:11px;font-weight:700;color:var(--g500);padding:0 4px;pointer-events:none}\u001b[39m\n\u001b[31m/* Level 1 — Large (+15%) */\u001b[39m\n\u001b[31mbody.fs-1 .field label,body.fs-1 .card-title,body.fs-1 .set-lbl,body.fs-1 .set-sub,\u001b[39m\n\u001b[31mbody.fs-1 .hdr-title,body.fs-1 .hdr-sub,body.fs-1 .slbl,body.fs-1 .rev-lbl,body.fs-1 .rev-val,\u001b[39m\n\u001b[31mbody.fs-1 .rbtn,body.fs-1 .chip,body.fs-1 .btn-p,body.fs-1 .btn-s,body.fs-1 .btn-o,\u001b[39m\n\u001b[31mbody.fs-1 .bdialog-title,body.fs-1 .bdialog-sub,body.fs-1 .sub-name,body.fs-1 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-1 .pslot-lbl,body.fs-1 .bitem-title,body.fs-1 .pi-name,body.fs-1 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-1 .asc-name,body.fs-1 .new-btn,body.fs-1 .resume-btn,body.fs-1 .ardl-lbl,body.fs-1 .ardl-val{font-size:calc(1em * 1.15) !important}\u001b[39m\n\u001b[31m/* Level 2 — X-Large (+30%) */\u001b[39m\n\u001b[31mbody.fs-2 .field label,body.fs-2 .card-title,body.fs-2 .set-lbl,body.fs-2 .set-sub,\u001b[39m\n\u001b[31mbody.fs-2 .hdr-title,body.fs-2 .hdr-sub,body.fs-2 .slbl,body.fs-2 .rev-lbl,body.fs-2 .rev-val,\u001b[39m\n\u001b[31mbody.fs-2 .rbtn,body.fs-2 .chip,body.fs-2 .btn-p,body.fs-2 .btn-s,body.fs-2 .btn-o,\u001b[39m\n\u001b[31mbody.fs-2 .bdialog-title,body.fs-2 .bdialog-sub,body.fs-2 .sub-name,body.fs-2 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-2 .pslot-lbl,body.fs-2 .bitem-title,body.fs-2 .pi-name,body.fs-2 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-2 .asc-name,body.fs-2 .new-btn,body.fs-2 .resume-btn,body.fs-2 .ardl-lbl,body.fs-2 .ardl-val{font-size:calc(1em * 1.30) !important}\u001b[39m\n\u001b[31m/* Level 3 — XX-Large (+50%) */\u001b[39m\n\u001b[31mbody.fs-3 .field label,body.fs-3 .card-title,body.fs-3 .set-lbl,body.fs-3 .set-sub,\u001b[39m\n\u001b[31mbody.fs-3 .hdr-title,body.fs-3 .hdr-sub,body.fs-3 .slbl,body.fs-3 .rev-lbl,body.fs-3 .rev-val,\u001b[39m\n\u001b[31mbody.fs-3 .rbtn,body.fs-3 .chip,body.fs-3 .btn-p,body.fs-3 .btn-s,body.fs-3 .btn-o,\u001b[39m\n\u001b[31mbody.fs-3 .bdialog-title,body.fs-3 .bdialog-sub,body.fs-3 .sub-name,body.fs-3 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-3 .pslot-lbl,body.fs-3 .bitem-title,body.fs-3 .pi-name,body.fs-3 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-3 .asc-name,body.fs-3 .new-btn,body.fs-3 .resume-btn,body.fs-3 .ardl-lbl,body.fs-3 .ardl-val{font-size:calc(1em * 1.50) !important}\u001b[39m\n\u001b[31m/* Level 4 — Max (+70%) */\u001b[39m\n\u001b[31mbody.fs-4 .field label,body.fs-4 .card-title,body.fs-4 .set-lbl,body.fs-4 .set-sub,\u001b[39m\n\u001b[31mbody.fs-4 .hdr-title,body.fs-4 .hdr-sub,body.fs-4 .slbl,body.fs-4 .rev-lbl,body.fs-4 .rev-val,\u001b[39m\n\u001b[31mbody.fs-4 .rbtn,body.fs-4 .chip,body.fs-4 .btn-p,body.fs-4 .btn-s,body.fs-4 .btn-o,\u001b[39m\n\u001b[31mbody.fs-4 .bdialog-title,body.fs-4 .bdialog-sub,body.fs-4 .sub-name,body.fs-4 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-4 .pslot-lbl,body.fs-4 .bitem-title,body.fs-4 .pi-name,body.fs-4 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-4 .asc-name,body.fs-4 .new-btn,body.fs-4 .resume-btn,body.fs-4 .ardl-lbl,body.fs-4 .ardl-val{font-size:calc(1em * 1.70) !important}\u001b[39m\n\u001b[31m/* ── RECCE TILE ACTION BUTTONS ── */\u001b[39m\n\u001b[31m.rpt-btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid rgba(0,0,0,.06)}\u001b[39m\n\u001b[31m.rpt-btn{display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 14px;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;border:none;font-family:inherit;transition:background .15s,opacity .15s;flex:1;min-width:110px;letter-spacing:.1px;white-space:nowrap}\u001b[39m\n\u001b[31m.rpt-btn-report{background:#fff7ed;color:var(--or);border:1.5px solid var(--or)}\u001b[39m\n\u001b[31m.rpt-btn-report:active{background:#fed7aa}\u001b[39m\n\u001b[31m.rpt-btn-pdf{background:var(--g100);color:var(--g400);border:1.5px solid var(--g200)}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready{background:var(--or);color:#fff;border-color:transparent}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready:active{background:#ea6c00}\u001b[39m\n\u001b[31m/* PDF wait overlay */\u001b[39m\n\u001b[31m#pdf-wait-ov{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m</style>\u001b[39m\n\u001b[31m</head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<!-- PICKER OVERLAY -->\u001b[39m\n\u001b[31m<div class=\\\"povl\\\" id=\\\"povl\\\">\u001b[39m\n\u001b[31m  <div class=\\\"povl-hdr\\\">\u001b[39m\n\u001b[31m    <input class=\\\"psearch\\\" id=\\\"psearch\\\" type=\\\"text\\\" placeholder=\\\"Search store / दुकान खोजें…\\\" oninput=\\\"filterPicker(this.value)\\\" autocomplete=\\\"off\\\">\u001b[39m\n\u001b[31m    <button class=\\\"pcancel\\\" onclick=\\\"closePicker()\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"plist\\\" id=\\\"plist\\\"></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"app\\\">·\u001b[39m\n\u001b[31m<!-- HOME -->\u001b[39m\n\u001b[31m<div class=\\\"view active\\\" id=\\\"view-home\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hero\\\">\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;justify-content:space-between;align-items:center\\\">\u001b[39m\n\u001b[31m      <div><div class=\\\"hero-title\\\"><span class=\\\"en-txt\\\">Branding Recce</span><span class=\\\"hi-txt\\\">ब्रांडिंग रेकी</span></div><div class=\\\"hero-sub\\\" id=\\\"today-date\\\">—</div></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:6px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"lang-btn\\\" onclick=\\\"setLang(LANG==='en'?'hi':'en')\\\" id=\\\"lang-btn\\\" title=\\\"Switch language / भाषा बदलें\\\">EN | हि</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-hub\\\" onclick=\\\"goToHub()\\\">🏡 Hub</button>\u001b[39m\n\u001b[31m      <button class=\\\"icon-btn\\\" onclick=\\\"showView('settings')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12 15a3 3 0 100-6 3 3 0 000 6z\\\"/><path d=\\\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\\\"/></svg></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"hero-ubar\\\" id=\\\"recce-hero-ubar\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <span class=\\\"hero-uname\\\" id=\\\"recce-hero-name\\\"></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-logout\\\" onclick=\\\"recceLogout()\\\">Logout</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"stats\\\">\u001b[39m\n\u001b[31m      <div class=\\\"scard g\\\"><div class=\\\"snum\\\" id=\\\"stat-synced\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Synced</span><span class=\\\"hi-txt\\\">सिंक्ड</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard a\\\"><div class=\\\"snum\\\" id=\\\"stat-pending\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Pending</span><span class=\\\"hi-txt\\\">बाकी</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard\\\"><div class=\\\"snum\\\" id=\\\"stat-total\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Total</span><span class=\\\"hi-txt\\\">कुल</span></div></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <button class=\\\"new-btn\\\" onclick=\\\"startNewRecce()\\\"><svg width=\\\"20\\\" height=\\\"20\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">New Recce</span><span class=\\\"hi-txt\\\">नई रेकी</span></button>\u001b[39m\n\u001b[31m    <div id=\\\"resume-wrap\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"sh\\\"><span class=\\\"st\\\"><span class=\\\"en-txt\\\">Recent Submissions</span><span class=\\\"hi-txt\\\">हाल की सबमिशन</span></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"syncNow()\\\" id=\\\"sync-btn\\\" style=\\\"padding:7px 12px;font-size:12px\\\"><svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg><span class=\\\"en-txt\\\">Sync</span><span class=\\\"hi-txt\\\">सिंक</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"sub-list\\\"></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"srow\\\"><div><span class=\\\"sdot\\\" id=\\\"net-dot\\\"></span><span id=\\\"net-txt\\\"><span class=\\\"en-txt\\\">Checking…</span><span class=\\\"hi-txt\\\">जाँच…</span></span></div><span id=\\\"last-sync-txt\\\" style=\\\"font-size:11px\\\"><span class=\\\"en-txt\\\">Never synced</span><span class=\\\"hi-txt\\\">कभी सिंक नहीं</span></span></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- SETTINGS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-settings\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('home')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Settings</span><span class=\\\"hi-txt\\\">सेटिंग</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Brand List</span><span class=\\\"hi-txt\\\">ब्रांड सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Manage Brands</span><span class=\\\"hi-txt\\\">ब्रांड प्रबंधन</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">These appear in the brand dropdown and store picker. Add client brands as needed.</div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-manage-list\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-add-row\\\" style=\\\"display:none;gap:8px;align-items:center\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"brand-add-inp\\\" placeholder=\\\"Type brand name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addBrandToList()\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"addBrandToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Store Lists</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Supervisors can upload XLS/CSV store lists here. Updates sync to all devices via server.</span><span class=\\\"hi-txt\\\">सुपरवाइजर यहाँ XLS/CSV स्टोर सूची अपलोड कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m      <!-- Upload/Clear row — supervisor only -->\u001b[39m\n\u001b[31m      <div id=\\\"store-upload-row\\\" style=\\\"display:none;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;margin-top:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"document.getElementById('store-xl').click()\\\"><svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Add File</span><span class=\\\"hi-txt\\\">फ़ाइल जोड़ें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-d\\\" onclick=\\\"clearStoreList()\\\" style=\\\"font-size:12px\\\"><span class=\\\"en-txt\\\">Clear All Stores</span><span class=\\\"hi-txt\\\">सभी स्टोर हटाएं</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" id=\\\"store-push-btn\\\" onclick=\\\"pushStoresToServer()\\\" style=\\\"font-size:12px;display:none\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Push to Server</span><span class=\\\"hi-txt\\\">सर्वर पर पुश करें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"store-xl\\\" accept=\\\".xlsx,.xls,.csv\\\" onchange=\\\"handleStoreUpload(event)\\\">\u001b[39m\n\u001b[31m      <div id=\\\"store-count\\\" style=\\\"font-size:13px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"store-file-list\\\" style=\\\"margin-top:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Brand assignment dialog for files with no brand column -->\u001b[39m\n\u001b[31m    <div id=\\\"brand-assign-dialog\\\" style=\\\"display:none;margin-top:10px;padding:14px;background:#fff7ed;border:1.5px solid var(--or);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\">Which brand is this store list for?</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\" id=\\\"brand-assign-fname\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-assign-chips\\\" class=\\\"chip-grid\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"confirmBrandAssign()\\\" style=\\\"flex:2;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">Assign Brand</span><span class=\\\"hi-txt\\\">ब्रांड असाइन करें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"skipBrandAssign()\\\" style=\\\"flex:1;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">No Brand</span><span class=\\\"hi-txt\\\">कोई ब्रांड नहीं</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Server Store List URL (Admin)</span><span class=\\\"hi-txt\\\">सर्वर स्टोर सूची URL</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Admin pushes stores.json to any public URL. App auto-fetches on open and caches offline.</div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"srv-url\\\" placeholder=\\\"https://yourserver.com/stores.json\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"fetchServerStores()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Fetch Now</button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"saveServerUrl()\\\" style=\\\"padding:9px 14px;font-size:13px;width:auto\\\">Save URL</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Sync Endpoint</span><span class=\\\"hi-txt\\\">सिंक एंडपॉइंट</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Slides Generator</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Managed by admin. Deploy gas_slides.gs from /opt/slides-proxy/ to Google Apps Script and paste the URL here.</div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"slides-gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Not configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"slides-gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"saveSlidesGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Sheet Sync</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Legacy sync endpoint. Writes recce data to Google Sheet.</div>·\u001b[39m\n\u001b[31m      <!-- Locked state (default) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Endpoint configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Unlocked state (after admin login) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;align-items:center;gap:8px;margin-bottom:10px;padding:7px 12px;background:#dcfce7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          <span style=\\\"font-size:12px;color:#14532d;font-weight:600\\\">🔓 Admin mode active</span>\u001b[39m\n\u001b[31m          <button onclick=\\\"lockAdmin()\\\" style=\\\"margin-left:auto;background:none;border:none;color:#14532d;font-size:12px;cursor:pointer;font-weight:600\\\">Lock ×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"testEndpoint()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Test</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>·\u001b[39m\n\u001b[31m    <!-- Admin Login Modal -->\u001b[39m\n\u001b[31m    <div id=\\\"admin-login-modal\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m      <div style=\\\"background:#fff;border-radius:var(--r);padding:24px 20px;margin:20px;max-width:380px;width:100%;box-shadow:0 8px 32px rgba(0,0,0,.2)\\\">\u001b[39m\n\u001b[31m        <div style=\\\"font-size:17px;font-weight:700;color:var(--nv);margin-bottom:4px\\\">Admin Login</div>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:18px\\\">Enter admin password to unlock settings</div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m          <label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">Password</label>\u001b[39m\n\u001b[31m          <input type=\\\"password\\\" id=\\\"admin-pwd\\\" placeholder=\\\"Enter admin password\\\" style=\\\"width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px\\\" onkeydown=\\\"if(event.key==='Enter')verifyAdmin()\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div id=\\\"admin-error\\\" style=\\\"display:none;font-size:12px;color:var(--rd);margin-bottom:12px;padding:8px 12px;background:#fee2e2;border-radius:var(--rs)\\\">Incorrect password</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"verifyAdmin()\\\" style=\\\"flex:2;padding:13px\\\" id=\\\"admin-login-btn\\\">Login</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-s\\\" onclick=\\\"closeAdminLogin()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:14px;padding-top:14px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.4px;margin-bottom:8px\\\">Admin Password Config URL</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:8px\\\">URL to your admin.json file on server (contains hashed password)</div>\u001b[39m\n\u001b[31m          <input type=\\\"url\\\" id=\\\"admin-cfg-url\\\" placeholder=\\\"https://yourserver.com/admin.json\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px;margin-bottom:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveAdminCfgUrl()\\\" style=\\\"font-size:12px;padding:7px 12px;width:100%;justify-content:center\\\">Save Config URL</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Geolocation Stamp</span><span class=\\\"hi-txt\\\">जियोलोकेशन स्टैम्प</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;justify-content:space-between;gap:16px\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1\\\">\u001b[39m\n\u001b[31m          <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Stamp on Photos</span><span class=\\\"hi-txt\\\">फोटो पर स्टैम्प</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"set-sub\\\" style=\\\"margin-bottom:0\\\">Bakes GPS coordinates, store name and timestamp into every photo — visible in the image itself. Same as GPS Map Camera app. Default: On.</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"tog on\\\" id=\\\"geo-tog\\\" onclick=\\\"toggleGeoStamp()\\\"><div class=\\\"tog-knob\\\"></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"geo-status\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\">GPS not yet captured</div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Image Quality</span><span class=\\\"hi-txt\\\">फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Default Photo Quality</span><span class=\\\"hi-txt\\\">डिफ़ॉल्ट फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Applies to all photos — front view, inside view, branding, and additional. HD uses more storage and takes longer to sync on poor networks.</div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;gap:10px;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-compressed\\\" onclick=\\\"setImgQuality('compressed')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-compressed\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-compressed\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">Full Compression</span><span class=\\\"hi-txt\\\">पूर्ण कम्प्रेशन</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~150–200 KB · Max 1280px · Best for poor network</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-left:auto;font-size:11px;font-weight:700;color:var(--gn);background:#dcfce7;padding:3px 8px;border-radius:20px\\\"><span class=\\\"en-txt\\\">Recommended</span><span class=\\\"hi-txt\\\">अनुशंसित</span></div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-hd\\\" onclick=\\\"setImgQuality('hd')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-hd\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-hd\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">HD Quality</span><span class=\\\"hi-txt\\\">HD क्वालिटी</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~400–600 KB · Max 1920px · Better detail for print</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"q-current-badge\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Supervisor Config panel — shown only to supervisors via renderSupPanel() -->\u001b[39m\n\u001b[31m    <div id=\\\"sup-panel\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">🔐 Recce Access Config</span><span class=\\\"hi-txt\\\">🔐 रेकी एक्सेस कॉन्फ़िग</span></div>\u001b[39m\n\u001b[31m      <!-- Access mode — only H/P can change -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"mode-row\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Access Mode</span><span class=\\\"hi-txt\\\">एक्सेस मोड</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Public: any Hub user can submit Recces. Assigned: only Supervisors and Creators can access.</span><span class=\\\"hi-txt\\\">सार्वजनिक: कोई भी Hub यूजर। नियत: सिर्फ़ Supervisors और Creators।</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\" style=\\\"margin-bottom:8px;margin-top:8px\\\">\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-public\\\" onclick=\\\"setRecceMode('public')\\\"><span class=\\\"en-txt\\\">Public</span><span class=\\\"hi-txt\\\">सार्वजनिक</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-assigned\\\" onclick=\\\"setRecceMode('assigned')\\\"><span class=\\\"en-txt\\\">Assigned</span><span class=\\\"hi-txt\\\">नियत</span></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Supervisor list — view all + delete + create -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Supervisors</span><span class=\\\"hi-txt\\\">सुपरवाइजर</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can view all recces, delete with reason, and submit. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">सभी रेकी देख सकते हैं, कारण से हटा सकते हैं, और सबमिट कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"sup-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addSupervisor()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addSupervisor()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Creator list — creation only -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Creators</span><span class=\\\"hi-txt\\\">क्रिएटर्स</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can submit Recces only — no admin view or deletion rights. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">केवल रेकी सबमिट कर सकते हैं — एडमिन व्यू या डिलीट नहीं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"creator-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addCreator()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addCreator()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Client list — used for client portal scoping -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clients</span><span class=\\\"hi-txt\\\">क्लाइंट</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Names that appear as chips when submitting a recce. Add the brand or agency name (e.g. \\\"Marketing Vibe\\\"). These are used to scope what clients see in the Client Portal.</span><span class=\\\"hi-txt\\\">रेकी सबमिट करते समय दिखने वाले क्लाइंट नाम। ब्रांड या एजेंसी नाम जोड़ें।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-mgmt-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"client-add-inp\\\" placeholder=\\\"Client name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addClientToList()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addClientToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Sync to server — only H/P -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"cfg-sync-btn\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Sync Config to Server</span><span class=\\\"hi-txt\\\">सर्वर पर कॉन्फ़िग सिंक करें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Apply supervisor/creator/client lists and access mode to all devices.</span><span class=\\\"hi-txt\\\">सभी डिवाइस पर कॉन्फ़िग लागू करें।</span></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"syncCfgToServer()\\\" style=\\\"max-width:220px;font-size:14px;padding:12px;margin-top:8px\\\"><span class=\\\"en-txt\\\">Sync to Server</span><span class=\\\"hi-txt\\\">सर्वर पर सिंक करें</span></button>\u001b[39m\n\u001b[31m        <div id=\\\"cfg-sync-status\\\" style=\\\"margin-top:8px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Danger Zone</span><span class=\\\"hi-txt\\\">खतरनाक ज़ोन</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\"><div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clear All Local Data</span><span class=\\\"hi-txt\\\">सभी डेटा हटाएं</span></div><div class=\\\"set-sub\\\">Removes all submissions from this device.</div><button class=\\\"btn-d\\\" onclick=\\\"clearData()\\\" style=\\\"padding:9px 14px;font-size:13px\\\">Clear All</button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: STORE INFO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-store\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"exitForm()\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Details</span><span class=\\\"hi-txt\\\">दुकान विवरण</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 1 of 5</span><span class=\\\"hi-txt\\\">चरण 1 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:20%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Recce Info</span><span class=\\\"hi-txt\\\">रेकी जानकारी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Date of Recce</span><span class=\\\"hi-txt\\\">रेकी की तारीख</span> <span class=\\\"req\\\">*</span></label><input type=\\\"date\\\" id=\\\"f-date\\\" onchange=\\\"saveDraft()\\\" max=\\\"\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" id=\\\"campaign-field\\\">\u001b[39m\n\u001b[31m        <label><span class=\\\"en-txt\\\">Job / Campaign</span><span class=\\\"hi-txt\\\">जॉब / कैंपेन</span></label>\u001b[39m\n\u001b[31m        <select id=\\\"f-campaign-id\\\" onchange=\\\"onCampaignSelect()\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">Loading campaigns…</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <div id=\\\"campaign-notify-msg\\\" style=\\\"display:none;font-size:12px;color:#92400e;margin-top:6px;padding:8px 10px;background:#fef3c7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          ⚑ <span class=\\\"en-txt\\\">Recce will submit without a job ID. A notification will flag this for your supervisor to link it later.</span><span class=\\\"hi-txt\\\">रेकी बिना जॉब ID के सबमिट होगी। सुपरवाइजर बाद में लिंक करेगा।</span>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Store</span><span class=\\\"hi-txt\\\">दुकान</span> <span id=\\\"store-avail-tag\\\" style=\\\"font-size:11px;color:var(--g400);font-weight:400;text-transform:none;letter-spacing:0\\\"></span></div>·\u001b[39m\n\u001b[31m      <!-- When store is selected -->\u001b[39m\n\u001b[31m      <div id=\\\"store-selected\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"store-card\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:start;justify-content:space-between;gap:8px\\\">\u001b[39m\n\u001b[31m            <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m              <div class=\\\"store-card-name\\\" id=\\\"sc-name\\\">—</div>\u001b[39m\n\u001b[31m              <div style=\\\"display:flex;align-items:center;gap:6px;margin-top:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m                <span class=\\\"brand-tag\\\" id=\\\"sc-brand\\\">—</span>\u001b[39m\n\u001b[31m                <span class=\\\"last-chip\\\" id=\\\"sc-last\\\" style=\\\"display:none\\\">—</span>\u001b[39m\n\u001b[31m              </div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            <button class=\\\"store-card-change\\\" onclick=\\\"openPicker()\\\"><span class=\\\"en-txt\\\">Change ›</span><span class=\\\"hi-txt\\\">बदलें ›</span></button>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <!-- All fields from Excel shown here -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-details\\\" style=\\\"margin-top:10px;display:flex;flex-direction:column;gap:4px\\\"></div>\u001b[39m\n\u001b[31m          <!-- Missing required fields — editable inline -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-missing\\\" style=\\\"display:none;margin-top:12px;padding-top:12px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m            <div style=\\\"font-size:11px;font-weight:700;color:var(--rd);text-transform:uppercase;letter-spacing:.4px;margin-bottom:10px\\\">⚠ Please complete missing fields</div>\u001b[39m\n\u001b[31m            <div id=\\\"sc-missing-fields\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <!-- Brand selector — shown when store has no brand -->\u001b[39m\n\u001b[31m        <div id=\\\"brand-selector\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\"><span class=\\\"en-txt\\\">Select Brand</span><span class=\\\"hi-txt\\\">ब्रांड चुनें</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\">This store has no brand in the list — select one:</div>\u001b[39m\n\u001b[31m          <div id=\\\"brand-chips\\\" class=\\\"chip-grid\\\"></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Picker trigger (shown when stores loaded) -->\u001b[39m\n\u001b[31m      <div id=\\\"pick-trigger-wrap\\\">\u001b[39m\n\u001b[31m        <div class=\\\"pick-trigger\\\" onclick=\\\"openPicker()\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:center;gap:10px\\\">\u001b[39m\n\u001b[31m            <span style=\\\"font-size:20px\\\">🏪</span>\u001b[39m\n\u001b[31m            <div>\u001b[39m\n\u001b[31m              <div style=\\\"font-size:15px;font-weight:700;color:var(--or)\\\"><span class=\\\"en-txt\\\">Select Store from List</span><span class=\\\"hi-txt\\\">सूची से दुकान चुनें</span></div>\u001b[39m\n\u001b[31m              <div id=\\\"store-avail-count\\\" style=\\\"font-size:12px;font-weight:400;color:var(--am);margin-top:1px\\\"><span class=\\\"en-txt\\\">Tap to browse stores</span><span class=\\\"hi-txt\\\">दुकान खोजने के लिए दबाएं</span></div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual / new store toggle -->\u001b[39m\n\u001b[31m      <div class=\\\"manual-toggle\\\" id=\\\"manual-toggle\\\" onclick=\\\"toggleManual()\\\">\u001b[39m\n\u001b[31m        <svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\" id=\\\"mt-icon\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg>\u001b[39m\n\u001b[31m        <span id=\\\"mt-label\\\"><span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span></span>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual fields -->\u001b[39m\n\u001b[31m      <div id=\\\"manual-fields\\\" style=\\\"display:none;margin-top:14px\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\" style=\\\"margin-bottom:14px\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <select id=\\\"f-brand\\\" onchange=\\\"onManualBrandChange()\\\">\u001b[39m\n\u001b[31m            <option value=\\\"\\\">Select brand</option>\u001b[39m\n\u001b[31m          </select>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span> <span class=\\\"req\\\">*</span></label><input type=\\\"text\\\" id=\\\"f-store\\\" placeholder=\\\"Enter store name\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\">\u001b[39m\n\u001b[31m          <label><span class=\\\"en-txt\\\">Store Address</span><span class=\\\"hi-txt\\\">दुकान का पता</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <textarea id=\\\"f-addr\\\" rows=\\\"2\\\" placeholder=\\\"Full address\\\" onchange=\\\"saveDraft()\\\"></textarea>\u001b[39m\n\u001b[31m          <div class=\\\"gps-row\\\">\u001b[39m\n\u001b[31m            <button class=\\\"gps-btn\\\" onclick=\\\"captureGPS()\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\"/><path d=\\\"M12 2v3M12 19v3M2 12h3M19 12h3\\\"/></svg><span class=\\\"en-txt\\\">Capture GPS</span><span class=\\\"hi-txt\\\">GPS लें</span></button>\u001b[39m\n\u001b[31m            <span id=\\\"gps-status\\\" style=\\\"font-size:12px;color:var(--g500);align-self:center\\\"></span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Mobile No.</span><span class=\\\"hi-txt\\\">मोबाइल नंबर</span></label><input type=\\\"tel\\\" id=\\\"f-mobile\\\" placeholder=\\\"10-digit number\\\" maxlength=\\\"10\\\" inputmode=\\\"numeric\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Client card -->\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Client</span><span class=\\\"hi-txt\\\">क्लाइंट</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\"><span class=\\\"en-txt\\\">Select who this recce is for. Defaults to brand — change if work came via an agency.</span><span class=\\\"hi-txt\\\">यह रेकी किसके लिए है चुनें। ब्रांड से डिफ़ॉल्ट — एजेंसी के ज़रिए हो तो बदलें।</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"cl-chip-grid\\\" id=\\\"client-chips\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"client-other-wrap\\\" style=\\\"display:none;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"f-client-other\\\" placeholder=\\\"Type client name\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" oninput=\\\"onClientOtherInput()\\\">\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-p\\\" onclick=\\\"step2()\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: PHOTOS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-photos\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-store')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Photos</span><span class=\\\"hi-txt\\\">दुकान की फोटो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 2 of 5</span><span class=\\\"hi-txt\\\">चरण 2 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:40%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Front View</span><span class=\\\"hi-txt\\\">आगे का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(min 1, max 3)</span><span class=\\\"cnt-badge gray\\\" id=\\\"front-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"front-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-front\\\" onclick=\\\"addPhoto('front')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Front Photo</span><span class=\\\"hi-txt\\\">आगे की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Inside View</span><span class=\\\"hi-txt\\\">अंदर का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 5)</span><span class=\\\"cnt-badge gray\\\" id=\\\"inside-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"inside-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-inside\\\" onclick=\\\"addPhoto('inside')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Inside Photo</span><span class=\\\"hi-txt\\\">अंदर की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-store')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step3()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: VIDEO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-video\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-photos')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Recce Video</span><span class=\\\"hi-txt\\\">रेकी वीडियो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 3 of 5</span><span class=\\\"hi-txt\\\">चरण 3 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:60%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Video</span><span class=\\\"hi-txt\\\">वीडियो</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Recce video available?</span><span class=\\\"hi-txt\\\">रेकी वीडियो है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"vid-yes\\\" onclick=\\\"setVideo(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"vid-no\\\" onclick=\\\"setVideo(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"vid-sec\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Upload Video</span><span class=\\\"hi-txt\\\">वीडियो अपलोड करें</span></label>\u001b[39m\n\u001b[31m          <div class=\\\"pslot\\\" id=\\\"vid-slot\\\" onclick=\\\"document.getElementById('vid-inp').click()\\\"><div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div></div>\u001b[39m\n\u001b[31m          <input type=\\\"file\\\" id=\\\"vid-inp\\\" accept=\\\"video/*\\\" onchange=\\\"handleVideo(event)\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Video Comments</span><span class=\\\"hi-txt\\\">वीडियो टिप्पणी</span></label><input type=\\\"text\\\" id=\\\"f-vid-cmt\\\" placeholder=\\\"Optional\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-photos')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step4()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: BRANDING -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-branding\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-video')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Branding</span><span class=\\\"hi-txt\\\">ब्रांडिंग</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 4 of 5</span><span class=\\\"hi-txt\\\">चरण 4 / 5</span></div></div></div>\u001b[39m\n\u001b[31m    <span id=\\\"br-hdr-badge\\\" style=\\\"background:rgba(255,255,255,.2);color:#fff;font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px\\\"><span class=\\\"en-txt\\\">0 items</span><span class=\\\"hi-txt\\\">0 आइटम</span></span>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:80%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Branding Space</span><span class=\\\"hi-txt\\\">ब्रांडिंग स्थान</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Space available?</span><span class=\\\"hi-txt\\\">जगह उपलब्ध है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"br-yes\\\" onclick=\\\"setBranding(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"br-no\\\" onclick=\\\"setBranding(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"branding-lock-banner\\\" style=\\\"display:none;background:#fef3c7;border:1.5px solid #f59e0b;border-radius:10px;padding:12px 14px;margin-bottom:10px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:700;color:#92400e\\\">Client approval exists — branding locked</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:#78350f;margin-top:4px\\\"><span class=\\\"en-txt\\\">The client has reviewed this recce. Create a new recce to revise branding items.</span><span class=\\\"hi-txt\\\">क्लाइंट ने रेकी की समीक्षा की है। बदलाव के लिए नई रेकी बनाएं।</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"branding-override-wrap\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m        <button onclick=\\\"unlockBrandingOverride()\\\" style=\\\"background:#f59e0b;color:#000;border:none;border-radius:8px;padding:8px 14px;font-size:12px;font-weight:700;cursor:pointer\\\">Override Edit (H&amp;P only)</button>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:11px;color:#92400e;margin-top:5px\\\">Use only when client has verbally confirmed and app needs correction.</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"br-items\\\"></div>\u001b[39m\n\u001b[31m    <div id=\\\"br-add\\\" style=\\\"display:none;margin-bottom:80px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"addBranding()\\\" style=\\\"width:100%;justify-content:center\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Another Branding Item</span><span class=\\\"hi-txt\\\">एक और ब्रांडिंग जोड़ें</span></button>\u001b[39m\n\u001b[31m      <div style=\\\"text-align:center;font-size:12px;color:var(--g400);margin-top:8px\\\"><span class=\\\"en-txt\\\">Tap Continue below when done adding items</span><span class=\\\"hi-txt\\\">सभी आइटम जोड़ने के बाद आगे दबाएं</span></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-video')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step5()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: ADDITIONAL + SUBMIT -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-additional\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-branding')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Submit</span><span class=\\\"hi-txt\\\">सबमिट</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 5 of 5</span><span class=\\\"hi-txt\\\">चरण 5 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:100%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Mandatory Document</span><span class=\\\"hi-txt\\\">अनिवार्य दस्तावेज़</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"pslot\\\" id=\\\"doc-slot\\\" onclick=\\\"document.getElementById('doc-inp').click()\\\"><div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div></div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"doc-inp\\\" accept=\\\"image/*,.pdf\\\" onchange=\\\"handleDoc(event)\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Additional Photos</span><span class=\\\"hi-txt\\\">अतिरिक्त फोटो</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 8)</span><span class=\\\"cnt-badge gray\\\" id=\\\"addl-badge\\\">0 / 8</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"add-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-addl\\\" onclick=\\\"addAdditional()\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\"><div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Review</span><span class=\\\"hi-txt\\\">समीक्षा</span></div><div id=\\\"rev-body\\\"></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-branding')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"submitRecce()\\\" id=\\\"sub-btn\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Submit Recce ✓</span><span class=\\\"hi-txt\\\">रेकी सबमिट करें ✓</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- ANNOTATION MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"annot-modal\\\" id=\\\"annot-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"annot-bar\\\">\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Draw:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"at-rect\\\"    onclick=\\\"setATool('rect')\\\">▭ Rect</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-ellipse\\\" onclick=\\\"setATool('ellipse')\\\">◯ Ellipse</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-line\\\"    onclick=\\\"setATool('line')\\\">╱ Line</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-arrow\\\"   onclick=\\\"setATool('arrow')\\\">↗ Arrow</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-free\\\"    onclick=\\\"setATool('free')\\\">✏ Free</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool sel-on\\\" id=\\\"at-move\\\" onclick=\\\"setATool('move')\\\" style=\\\"margin-left:4px\\\">⊹ Move</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Color:</span>\u001b[39m\n\u001b[31m      <div class=\\\"acolor on\\\" id=\\\"ac-or\\\" style=\\\"background:#f97316\\\" onclick=\\\"setAColor('#f97316')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-rd\\\" style=\\\"background:#ef4444\\\" onclick=\\\"setAColor('#ef4444')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-wh\\\" style=\\\"background:#ffffff\\\" onclick=\\\"setAColor('#ffffff')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-yw\\\" style=\\\"background:#facc15\\\" onclick=\\\"setAColor('#facc15')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-gn\\\" style=\\\"background:#22c55e\\\" onclick=\\\"setAColor('#22c55e')\\\"></div>\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Width:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-2\\\" onclick=\\\"setAWidth(2)\\\" style=\\\"padding:5px 8px\\\">Thin</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"aw-4\\\" onclick=\\\"setAWidth(4)\\\" style=\\\"padding:5px 8px\\\">Med</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-7\\\" onclick=\\\"setAWidth(7)\\\" style=\\\"padding:5px 8px\\\">Thick</button>\u001b[39m\n\u001b[31m      <div style=\\\"flex:1\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"undoAnnot()\\\">↩</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"clearAnnot()\\\">✕</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"annot-sel-info\\\" style=\\\"display:none;font-size:11px;color:#facc15;padding:4px 0 2px\\\">\u001b[39m\n\u001b[31m      Shape selected — drag to move · drag corners to resize · tap elsewhere to deselect\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-cvs-wrap\\\"><canvas id=\\\"annot-cvs\\\"></canvas></div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-foot\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-s\\\" onclick=\\\"skipAnnot()\\\" style=\\\"flex:1;padding:12px;font-size:14px\\\"><span class=\\\"en-txt\\\">Skip markup</span><span class=\\\"hi-txt\\\">मार्कअप छोड़ें</span></button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" onclick=\\\"saveAnnot()\\\" style=\\\"flex:2;padding:12px\\\"><span class=\\\"en-txt\\\">Done — Save ✓</span><span class=\\\"hi-txt\\\">हो गया — सेव करें ✓</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EXIT DIALOG -->\u001b[39m\n\u001b[31m<!-- MODAL: Link Job to Recce (supervisor only) -->\u001b[39m\n\u001b[31m<div id=\\\"modal-link-job\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m  <div style=\\\"background:#fff;border-radius:14px;padding:20px;width:90%;max-width:380px;display:flex;flex-direction:column;gap:12px;box-shadow:0 8px 32px rgba(0,0,0,.35)\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:15px;font-weight:700;color:#1e293b\\\">&#x1F517; Link Job to Recce</div>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-store\\\" style=\\\"font-size:13px;color:#64748b\\\"></div>\u001b[39m\n\u001b[31m    <select id=\\\"link-job-sel\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m      <option value=\\\"\\\">&#x2014; Select campaign &#x2014;</option>\u001b[39m\n\u001b[31m    </select>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-err\\\" style=\\\"font-size:12px;color:#ef4444;min-height:14px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"closeLinkJobModal()\\\" style=\\\"flex:1;padding:12px;border:1px solid #cbd5e1;border-radius:8px;cursor:pointer;background:#f8fafc;font-size:14px\\\">Cancel</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"saveLinkJob()\\\" style=\\\"flex:2;padding:12px;background:#f59e0b;color:#000;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:700\\\">&#x1F517; Link Job</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"exit-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Exit Recce?</span><span class=\\\"hi-txt\\\">रेकी से बाहर?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Your progress and photos will be saved as a draft. Resume anytime from the home screen.</span><span class=\\\"hi-txt\\\">आपकी प्रगति और फोटो ड्राफ्ट में सेव होंगी। होम स्क्रीन से कभी भी जारी रखें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"exitSaveAndLeave()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">💾 Save Draft & Exit</span><span class=\\\"hi-txt\\\">💾 ड्राफ्ट सेव करें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-d\\\" onclick=\\\"exitDiscard()\\\" style=\\\"flex:1;padding:13px;font-size:13px\\\"><span class=\\\"en-txt\\\">Discard</span><span class=\\\"hi-txt\\\">हटाएं</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"exitCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">← Continue Recce</span><span class=\\\"hi-txt\\\">← रेकी जारी रखें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- PHOTO SOURCE PICKER -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"photo-src-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Camera photos get GPS stamp baked in. Gallery photos are added without stamp.</span><span class=\\\"hi-txt\\\">कैमरा फोटो में GPS स्टैम्प लगती है। गैलरी फोटो में नहीं।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"photoSrcCamera()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">📷 Use Camera</span><span class=\\\"hi-txt\\\">📷 कैमरा</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">GPS stamp applied</span><span class=\\\"hi-txt\\\">GPS स्टैम्प लगेगी</span></span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"photoSrcGallery()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">🖼 Choose from Gallery</span><span class=\\\"hi-txt\\\">🖼 गैलरी से चुनें</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">No stamp</span><span class=\\\"hi-txt\\\">स्टैम्प नहीं</span></span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"photoSrcCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- STORE PREVIEW DIALOG -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"store-preview-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:80vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"store-preview-title\\\"><span class=\\\"en-txt\\\">Preview Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची का प्रीव्यू</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Review before adding to your store list:</span><span class=\\\"hi-txt\\\">जोड़ने से पहले जाँचें:</span></div>\u001b[39m\n\u001b[31m    <div style=\\\"overflow-x:auto;margin-bottom:14px\\\">\u001b[39m\n\u001b[31m      <table style=\\\"width:100%;border-collapse:collapse;font-size:12px\\\">\u001b[39m\n\u001b[31m        <thead><tr style=\\\"background:var(--nv);color:#fff\\\">\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Address</span><span class=\\\"hi-txt\\\">पता</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Mobile</span><span class=\\\"hi-txt\\\">मोबाइल</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span></th>\u001b[39m\n\u001b[31m        </tr></thead>\u001b[39m\n\u001b[31m        <tbody id=\\\"store-preview-body\\\"></tbody>\u001b[39m\n\u001b[31m      </table>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"confirmStorePreview()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">✓ Confirm & Add Stores</span><span class=\\\"hi-txt\\\">✓ स्टोर जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"cancelStorePreview()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BOTTOM DIALOG (branding additional photo prompt) -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"bdialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add reference photos?</span><span class=\\\"hi-txt\\\">संदर्भ फोटो जोड़ें?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Add extra photos for this branding item for future reference.</span><span class=\\\"hi-txt\\\">इस ब्रांडिंग आइटम के लिए अतिरिक्त फोटो जोड़ें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"bdialogYes()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">Yes, add photos</span><span class=\\\"hi-txt\\\">हाँ, जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"bdialogNo()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Skip</span><span class=\\\"hi-txt\\\">छोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- DELETE REASON MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"delete-reason-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"padding-bottom:28px;max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">🗑 Delete Recce</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"del-modal-sub\\\">Select reason for deletion:</div>\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-wrong\\\" onclick=\\\"selectDeleteReason('wrong')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">❌</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Wrong</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Incorrect store / submission error</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-duplicate\\\" onclick=\\\"selectDeleteReason('duplicate')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">📋</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Duplicate</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Same store submitted more than once</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt danger\\\" id=\\\"reason-test\\\" onclick=\\\"selectDeleteReason('test')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">⚠️</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Test Recce</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:#9a3412;margin-top:2px\\\">Permanently deleted — no audit trail</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p no-reason\\\" id=\\\"del-confirm-btn\\\" onclick=\\\"confirmDelete()\\\" style=\\\"flex:2;padding:13px;background:var(--rd)\\\">Delete</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"closeDeleteModal()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EDIT REQUEST MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"edit-req-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Request Edit</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"er-store-name\\\" style=\\\"font-weight:600;color:var(--nv);margin-bottom:4px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:14px\\\">Add a note for the creator (optional)</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m      <textarea id=\\\"er-comment\\\" placeholder=\\\"e.g. Please re-check store address and re-upload front photo\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;color:var(--nv);resize:vertical;min-height:80px;background:#fff\\\"></textarea>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button id=\\\"er-assign-btn\\\" class=\\\"btn-p\\\" onclick=\\\"assignEditToCreator()\\\" style=\\\"padding:14px\\\">👤 Assign to Creator</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"supervisorEditMyself()\\\" style=\\\"padding:14px\\\">✏ Edit Myself</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"closeEditRequestModal()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BRAND EDIT MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"brand-edit-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Edit Brand</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Brand Name <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"text\\\" id=\\\"be-name\\\" placeholder=\\\"e.g. PHILIPS\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:600;text-transform:uppercase\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Logo URL <span style=\\\"font-size:11px;font-weight:400;color:var(--g400)\\\">(optional)</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"url\\\" id=\\\"be-logo\\\" placeholder=\\\"https://…/logo.svg\\\" oninput=\\\"previewBrandLogo()\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px\\\">\u001b[39m\n\u001b[31m      <div id=\\\"be-logo-preview\\\" style=\\\"margin-top:8px;min-height:36px;display:flex;align-items:center;gap:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"be-cascade-info\\\" style=\\\"display:none;font-size:12px;color:var(--g500);padding:8px 12px;background:var(--g50);border-radius:var(--rs);margin-bottom:12px\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"saveBrandEdit()\\\" style=\\\"padding:14px\\\">Save</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"closeBrandEditModal()\\\" style=\\\"width:100%;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FONT SIZE WIDGET -->\u001b[39m\n\u001b[31m<div class=\\\"fs-widget\\\" id=\\\"fs-widget\\\">\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-dec\\\" onclick=\\\"changeFontSize(-1)\\\" title=\\\"Decrease font size\\\" aria-label=\\\"Decrease font size\\\">A<sup style=\\\"font-size:9px\\\">−</sup></button>\u001b[39m\n\u001b[31m  <span class=\\\"fs-label\\\" id=\\\"fs-lbl\\\">A</span>\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-inc\\\" onclick=\\\"changeFontSize(1)\\\" title=\\\"Increase font size\\\" aria-label=\\\"Increase font size\\\"><strong>A</strong><sup style=\\\"font-size:9px\\\">+</sup></button>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"upd-banner\\\" id=\\\"upd-banner\\\">\u001b[39m\n\u001b[31m  <span style=\\\"font-size:13px;font-weight:600;line-height:1.4\\\"><span class=\\\"en-txt\\\">✓ App updated to latest version</span><span class=\\\"hi-txt\\\">✓ ऐप नया संस्करण अपडेट हुआ</span></span>\u001b[39m\n\u001b[31m  <button class=\\\"upd-banner-ok\\\" onclick=\\\"dismissUpdateBanner()\\\"><span class=\\\"en-txt\\\">OK</span><span class=\\\"hi-txt\\\">ठीक है</span></button>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m<div class=\\\"toast\\\" id=\\\"toast\\\"></div>\u001b[39m\n\u001b[31m<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js\\\"></script>\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m// LANGUAGE\u001b[39m\n\u001b[31mlet LANG = localStorage.getItem('recce-lang') || 'en';\u001b[39m\n\u001b[31mfunction setLang(l) {\u001b[39m\n\u001b[31m  LANG = l;\u001b[39m\n\u001b[31m  localStorage.setItem('recce-lang', l);\u001b[39m\n\u001b[31m  document.body.classList.toggle('lang-hi', l === 'hi');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction t(en, hi) { return LANG === 'hi' ? hi : en; }·\u001b[39m\n\u001b[31m// FONT SIZE\u001b[39m\n\u001b[31mlet FS_LEVEL = parseInt(localStorage.getItem('recce-fs') || '0', 10);\u001b[39m\n\u001b[31mconst FS_LABELS = ['A', 'A+', 'A++', 'A+++', 'A++++'];\u001b[39m\n\u001b[31mfunction applyFontSize() {\u001b[39m\n\u001b[31m  document.body.classList.remove('fs-0', 'fs-1', 'fs-2');\u001b[39m\n\u001b[31m  if (FS_LEVEL > 0) document.body.classList.add('fs-' + FS_LEVEL);\u001b[39m\n\u001b[31m  const lbl = document.getElementById('fs-lbl');\u001b[39m\n\u001b[31m  if (lbl) lbl.textContent = FS_LABELS[FS_LEVEL];\u001b[39m\n\u001b[31m  const dec = document.getElementById('fs-dec');\u001b[39m\n\u001b[31m  const inc = document.getElementById('fs-inc');\u001b[39m\n\u001b[31m  if (dec) dec.disabled = FS_LEVEL === 0;\u001b[39m\n\u001b[31m  if (inc) inc.disabled = FS_LEVEL === 4;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction changeFontSize(delta) {\u001b[39m\n\u001b[31m  FS_LEVEL = Math.min(4, Math.max(0, FS_LEVEL + delta));\u001b[39m\n\u001b[31m  localStorage.setItem('recce-fs', FS_LEVEL);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Hub auth gate\u001b[39m\n\u001b[31m(function() {\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (!s || !s.loginAt || Date.now() - new Date(s.loginAt).getTime() > 12 * 3600 * 1000) {\u001b[39m\n\u001b[31m      window.location.replace('/hub/');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) { window.location.replace('/hub/'); }\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31m// STATE\u001b[39m\n\u001b[31mlet F={},frontPhotos=[],insidePhotos=[],addlPhotos=[],brandings=[];\u001b[39m\n\u001b[31mlet videoBlob=null,submissionDoc=null,_docExistingUrl=null,gpsCoords=null;\u001b[39m\n\u001b[31mlet stores=[],selectedStore=null,manualMode=false,DB;\u001b[39m\n\u001b[31mlet imgQuality='compressed'; // 'compressed' | 'hd'\u001b[39m\n\u001b[31mlet geoStampEnabled=true;    // stamp GPS+timestamp on every photo\u001b[39m\n\u001b[31mlet brands=['PHILIPS']; // editable brand list\u001b[39m\n\u001b[31mlet _brandLogos={};   // name → logo_url, loaded from DB\u001b[39m\n\u001b[31mlet _selectedClient=''; // currently selected client chip value\u001b[39m\n\u001b[31mlet _clientOtherMode=false; // true when \\\"Other\\\" chip selected\u001b[39m\n\u001b[31mconst BTYPE=['Glow Sign Board','Inshop Branding','ACP Board','One Way Vision','Fabric Board','Lollypop','Non Lit Flex','Double Side GSB','Clip on Board','Translit','Vinyl Printing','Roll up Standee','Sunboard Standee'];\u001b[39m\n\u001b[31mconst CACHE_VER='recce-v37'; // campaign dropdown + pending job link tab·\u001b[39m\n\u001b[31m// DB\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',3);r.onupgradeneeded=e=>{const d=e.target.result;['subs','cfg','draft'].forEach(s=>{if(!d.objectStoreNames.contains(s))d.createObjectStore(s,{keyPath:'k'||'id'});});if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);});}\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',4);r.onupgradeneeded=e=>{const d=e.target.result;if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);})}\u001b[39m\n\u001b[31mfunction dbGet(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).get(k);r.onsuccess=()=>res(r.result);r.onerror=()=>res(null);}catch{res(null)}})}\u001b[39m\n\u001b[31mfunction dbPut(s,v){return new Promise((res,rej)=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).put(v);r.onsuccess=()=>res();r.onerror=()=>rej();}catch(e){rej(e)}})}\u001b[39m\n\u001b[31mfunction dbAll(s){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).getAll();r.onsuccess=()=>res(r.result);r.onerror=()=>res([]);}catch{res([])}})}\u001b[39m\n\u001b[31mfunction dbDel(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).delete(k);r.onsuccess=()=>res();r.onerror=()=>res();}catch{res()}})}\u001b[39m\n\u001b[31masync function cfg(k,v){if(v===undefined){const r=await dbGet('cfg',k);return r?r.v:null;}await dbPut('cfg',{k,v});}·\u001b[39m\n\u001b[31m// COMPRESS — respects imgQuality setting\u001b[39m\n\u001b[31mfunction compress(file, maxPxOverride, qOverride){\u001b[39m\n\u001b[31m  const maxPx = maxPxOverride || (imgQuality==='hd' ? 1920 : 1280);\u001b[39m\n\u001b[31m  const q     = qOverride     || (imgQuality==='hd' ? 0.90 : 0.78);\u001b[39m\n\u001b[31m  return new Promise(res=>{const img=new Image(),url=URL.createObjectURL(file);img.onload=()=>{const sc=Math.min(1,maxPx/Math.max(img.width,img.height));const c=document.createElement('canvas');c.width=Math.round(img.width*sc);c.height=Math.round(img.height*sc);c.getContext('2d').drawImage(img,0,0,c.width,c.height);URL.revokeObjectURL(url);c.toBlob(b=>res(b),'image/jpeg',q);};img.onerror=()=>{URL.revokeObjectURL(url);res(file)};img.src=url;});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction b64(blob){return new Promise(res=>{const r=new FileReader();r.onload=()=>res(r.result);r.readAsDataURL(blob)})}\u001b[39m\n\u001b[31mfunction fmtSz(b){if(b<1024)return b+'B';if(b<1048576)return(b/1024).toFixed(0)+'KB';return(b/1048576).toFixed(1)+'MB'}·\u001b[39m\n\u001b[31m// STORE LIST\u001b[39m\n\u001b[31mlet _storeFiles=[]; // track uploaded files {name, brand, count}\u001b[39m\n\u001b[31mlet _pendingParse=null; // parsed rows waiting for brand assignment·\u001b[39m\n\u001b[31mfunction parseStoreRow(row, keyFn){\u001b[39m\n\u001b[31m  const v=k=>{\u001b[39m\n\u001b[31m    // Try exact match first, then partial\u001b[39m\n\u001b[31m    const exactKey=Object.keys(row||{}).find(hk=>hk.toLowerCase()===k);\u001b[39m\n\u001b[31m    const partKey=Object.keys(row||{}).find(hk=>hk.toLowerCase().includes(k));\u001b[39m\n\u001b[31m    const useKey=exactKey||partKey;\u001b[39m\n\u001b[31m    if(useKey)return row[useKey]!=null?row[useKey].toString().trim():'';\u001b[39m\n\u001b[31m    // CSV path: keyFn provides value directly\u001b[39m\n\u001b[31m    const col=keyFn(k);return col!=null?col.toString().trim():'';\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const name    = v('sub dealer name')||v('sub dealer')||v('dealer name')||v('store name')||v('store')||v('name');\u001b[39m\n\u001b[31m  const address = v('address')||v('addr')||v('location')||v('area');\u001b[39m\n\u001b[31m  // Contact Detail often stored as a number — toString handles it\u001b[39m\n\u001b[31m  const rawMob  = v('contact detail')||v('contact no.')||v('contact no')||v('mobile no')||v('mobile')||v('phone')||v('mob')||v('contact');\u001b[39m\n\u001b[31m  const mobile  = rawMob.replace(/\\\\D/g,'').slice(-10);\u001b[39m\n\u001b[31m  // Brand: EXACT match only — \\\"Brand\\\" or \\\"Brand Name\\\" columns\u001b[39m\n\u001b[31m  // Partial match is intentionally avoided here because \\\"Inshop Branding\\\" contains \\\"brand\\\"\u001b[39m\n\u001b[31m  const brandKey=Object.keys(row||{}).find(hk=>{\u001b[39m\n\u001b[31m    const lk=hk.toLowerCase().trim();\u001b[39m\n\u001b[31m    return lk==='brand'||lk==='brand name'||lk==='brand_name'||lk==='brandname';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const brand=brandKey?(row[brandKey]||'').toString().trim().toUpperCase():'';\u001b[39m\n\u001b[31m  const distName= v('dist name')||v('distributor name')||v('distributor')||v('dist')||v('territory')||v('tsm')||v('asm');\u001b[39m\n\u001b[31m  const city    = v('city')||v('district')||v('town');\u001b[39m\n\u001b[31m  const sales   = v('2025 full year')||v('2025')||v('full year sales')||v('fy25')||v('sales');\u001b[39m\n\u001b[31m  const proj    = v('2026 projection')||v('2026')||v('projection')||v('fy26')||v('target');\u001b[39m\n\u001b[31m  const glowSign= v('glow sign')||v('glow');\u001b[39m\n\u001b[31m  const inshop  = v('inshop branding')||v('inshop')||v('in-shop')||v('in shop');\u001b[39m\n\u001b[31m  return {name, brand, address, mobile, distName, city, sales, proj, glowSign, inshop};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction dedupeStores(list){\u001b[39m\n\u001b[31m  const seen=new Map();\u001b[39m\n\u001b[31m  list.forEach(s=>{\u001b[39m\n\u001b[31m    // Include address in key — same store name at different locations = different stores\u001b[39m\n\u001b[31m    const key=(s.name.toLowerCase().trim())+'__'+(s.brand||'').toLowerCase()\u001b[39m\n\u001b[31m              +'__'+(s.address||'').toLowerCase().trim().slice(0,30);\u001b[39m\n\u001b[31m    if(!seen.has(key))seen.set(key,s);\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // True duplicate — merge missing fields from second record\u001b[39m\n\u001b[31m      const ex=seen.get(key);\u001b[39m\n\u001b[31m      Object.keys(s).forEach(k=>{ if(!ex[k]&&s[k])ex[k]=s[k]; });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  return Array.from(seen.values());\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderStoreFileList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-file-list');if(!el)return;\u001b[39m\n\u001b[31m  if(!_storeFiles.length){el.innerHTML='';return;}\u001b[39m\n\u001b[31m  el.innerHTML=_storeFiles.map((f,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:5px;font-size:12px\\\">\u001b[39m\n\u001b[31m      <div>\u001b[39m\n\u001b[31m        <span style=\\\"font-weight:600;color:var(--nv)\\\">${f.name}</span>\u001b[39m\n\u001b[31m        <span style=\\\"color:var(--g500);margin-left:6px\\\">${f.count} stores</span>\u001b[39m\n\u001b[31m        ${f.brand?`<span style=\\\"background:var(--nv);color:#fff;font-size:10px;font-weight:700;padding:1px 7px;border-radius:20px;margin-left:5px\\\">${f.brand}</span>`:'<span style=\\\"background:var(--g300);color:var(--g600);font-size:10px;padding:1px 7px;border-radius:20px;margin-left:5px\\\">Mixed brands</span>'}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <button onclick=\\\"removeStoreFile(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:17px;cursor:pointer;padding:0 4px;line-height:1\\\">×</button>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function removeStoreFile(i){\u001b[39m\n\u001b[31m  _storeFiles.splice(i,1);\u001b[39m\n\u001b[31m  // Rebuild stores from remaining files — re-parse from cache not possible, so just reload from DB and remove this file's contribution\u001b[39m\n\u001b[31m  // Simplest approach: clear and ask user to re-upload remaining files\u001b[39m\n\u001b[31m  if(!_storeFiles.length){stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    // Can't re-parse without original files; just note it and keep current store list\u001b[39m\n\u001b[31m    toast('Removed from list. Re-upload the remaining files to refresh store list.','info');\u001b[39m\n\u001b[31m    _storeFiles.splice(0); // clear tracking since we can't reconstruct\u001b[39m\n\u001b[31m    stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderStoreFileList();\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=stores.length?`✓ ${stores.length} stores`:'No stores loaded';\u001b[39m\n\u001b[31m  updAvailTag();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function clearStoreList(){\u001b[39m\n\u001b[31m  if(!confirm('Remove all loaded stores?'))return;\u001b[39m\n\u001b[31m  stores=[];_storeFiles=[];\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent='';\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast('Store list cleared','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function handleStoreUpload(e){\u001b[39m\n\u001b[31m  const file=e.target.files[0];if(!file)return;\u001b[39m\n\u001b[31m  e.target.value=''; // allow same file re-upload\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    let data=[];\u001b[39m\n\u001b[31m    if(file.name.toLowerCase().endsWith('.csv')){\u001b[39m\n\u001b[31m      const txt=await file.text();\u001b[39m\n\u001b[31m      const rows=txt.split('\\\\n').map(r=>r.split(',').map(c=>c.trim().replace(/^\\\"|\\\"$/g,'')));\u001b[39m\n\u001b[31m      if(!rows.length||!rows[0].length){toast('Empty CSV','error');return;}\u001b[39m\n\u001b[31m      const h=rows[0];\u001b[39m\n\u001b[31m      data=rows.slice(1).filter(r=>r.length>1&&r.some(c=>c)).map(r=>{\u001b[39m\n\u001b[31m        const rowObj={};h.forEach((hk,i)=>{rowObj[hk]=r[i]||'';});\u001b[39m\n\u001b[31m        return parseStoreRow(rowObj, ()=>'');\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }else{\u001b[39m\n\u001b[31m      const ab=await file.arrayBuffer();const wb=XLSX.read(ab,{type:'array'});\u001b[39m\n\u001b[31m      const js=XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]],{defval:''});\u001b[39m\n\u001b[31m      data=js.map(row=>parseStoreRow(row,()=>''));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    data=data.filter(d=>d.name.trim());\u001b[39m\n\u001b[31m    if(!data.length){toast('No valid rows found in file','error');return;}\u001b[39m\n\u001b[31m    // Check if any store has a brand\u001b[39m\n\u001b[31m    const hasBrand=data.some(d=>d.brand);\u001b[39m\n\u001b[31m    // Always show preview first before merging\u001b[39m\n\u001b[31m    _pendingParse={file:file.name,data,hasBrand};\u001b[39m\n\u001b[31m    showStorePreview(file.name, data, hasBrand);\u001b[39m\n\u001b[31m  }catch(err){toast('Failed: '+err.message,'error')}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mlet _pendingBrand='';\u001b[39m\n\u001b[31mfunction setPendingBrand(b){\u001b[39m\n\u001b[31m  _pendingBrand=b;\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-assign-chips .chip').forEach(c=>{\u001b[39m\n\u001b[31m    c.classList.toggle('sel',c.textContent===b);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  if(!_pendingBrand){toast('Select a brand first','error');return;}\u001b[39m\n\u001b[31m  // Assign brand to all rows in this file\u001b[39m\n\u001b[31m  const data=_pendingParse.data.map(s=>({...s,brand:_pendingBrand}));\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, data, _pendingBrand);\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function skipBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, _pendingParse.data, '');\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showStorePreview(filename, data, hasBrand){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-preview-dialog');\u001b[39m\n\u001b[31m  const tbody=document.getElementById('store-preview-body');\u001b[39m\n\u001b[31m  document.getElementById('store-preview-title').textContent=`${filename} · ${data.length} ${t('stores found','स्टोर मिले')}`;\u001b[39m\n\u001b[31m  // Show first 8 rows\u001b[39m\n\u001b[31m  const sample=data.slice(0,8);\u001b[39m\n\u001b[31m  tbody.innerHTML=sample.map(s=>`<tr>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;font-weight:500\\\">${s.name||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.address||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.mobile||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px\\\"><span style=\\\"background:${s.brand?'var(--nv)':'var(--rd)'};color:#fff;padding:1px 7px;border-radius:10px;font-size:10px\\\">${s.brand||'?'}</span></td>\u001b[39m\n\u001b[31m  </tr>`).join('');\u001b[39m\n\u001b[31m  if(data.length>8)tbody.innerHTML+=`<tr><td colspan=\\\"4\\\" style=\\\"text-align:center;padding:8px;font-size:12px;color:var(--g400)\\\">…and ${data.length-8} more stores</td></tr>`;\u001b[39m\n\u001b[31m  el.classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function confirmStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  const {file,data,hasBrand}=_pendingParse;\u001b[39m\n\u001b[31m  if(!hasBrand){\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-fname').textContent=`File: ${file} · ${data.length} stores found · No brand column detected`;\u001b[39m\n\u001b[31m    const chips=document.getElementById('brand-assign-chips');\u001b[39m\n\u001b[31m    chips.innerHTML=brands.map(b=>`<div class=\\\"chip\\\" onclick=\\\"setPendingBrand('${b}')\\\" id=\\\"bac-${b}\\\">${b}</div>`).join('');\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').style.display='block';\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    await mergeStores(file, data, '');\u001b[39m\n\u001b[31m    _pendingParse=null;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction cancelStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingParse=null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function mergeStores(filename, newData, assignedBrand){\u001b[39m\n\u001b[31m  const before=stores.length;\u001b[39m\n\u001b[31m  stores=[...stores,...newData];\u001b[39m\n\u001b[31m  stores=dedupeStores(stores);\u001b[39m\n\u001b[31m  const added=stores.length-before;\u001b[39m\n\u001b[31m  const dupes=newData.length-added;\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify(stores));\u001b[39m\n\u001b[31m  // Track file\u001b[39m\n\u001b[31m  _storeFiles.push({name:filename,count:newData.length,brand:assignedBrand||''});\u001b[39m\n\u001b[31m  await cfg('store-files',JSON.stringify(_storeFiles));\u001b[39m\n\u001b[31m  const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m    `✓ ${stores.length} total stores${dupes>0?` · ${dupes} duplicate${dupes>1?'s':''} removed`:''}${noBrand?` · ${noBrand} without brand`:' · All have brand'}`;\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast(`${added} stores added${dupes>0?`, ${dupes} duplicates skipped`:''}${assignedBrand?' as '+assignedBrand:''}`, 'success');\u001b[39m\n\u001b[31m  // Show server-push button for supervisors\u001b[39m\n\u001b[31m  const pb = document.getElementById('store-push-btn');\u001b[39m\n\u001b[31m  if (pb) pb.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function fetchServerStores(){const url=document.getElementById('srv-url').value.trim();if(!url){toast('Enter a URL first','error');return;}try{toast('Fetching…','info');const r=await fetch(url);const j=await r.json();const fetched=Array.isArray(j)?j:j.stores||[];await mergeStores('Server ('+url.split('/').pop()+')',fetched,'');await cfg('srv-url',url);}catch{toast('Fetch failed — check URL','error')}}\u001b[39m\n\u001b[31masync function saveServerUrl(){await cfg('srv-url',document.getElementById('srv-url').value.trim());toast('URL saved','success')}\u001b[39m\n\u001b[31mconst DEFAULT_GAS_URL='https://script.google.com/macros/s/AKfycbwyufC7gQyu1BErCxiDlbQUn0AWiIWv7nEmjk4UcAx3dvlV6bGk7q5fQOiv82CTbokbkA/exec';·\u001b[39m\n\u001b[31mconst DEFAULT_STORES_URL='/recce/stores.json';\u001b[39m\n\u001b[31mconst _RECCE_CFG_URL='/recce/recce-cfg.json';·\u001b[39m\n\u001b[31m// Admin auto-unlock for harish/pramod via hub session\u001b[39m\n\u001b[31mconst _RECCE_ADMIN_IDS = ['harish', 'pramod', 'rakesh'];\u001b[39m\n\u001b[31mconst _RECCE_CFG_ADMINS = ['harish', 'pramod'];\u001b[39m\n\u001b[31mlet _adminRows = [];\u001b[39m\n\u001b[31mlet _myServerRows = [];\u001b[39m\n\u001b[31mlet _adminUnlocked = false;\u001b[39m\n\u001b[31mlet _recceCfg = { version: 1, supervisors: ['harish','pramod','rakesh'], mode: 'public', creators: [], allowed_users: [] };\u001b[39m\n\u001b[31mfunction _isSupervisor() {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  return !!(hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId));\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _showDeletedView = false;\u001b[39m\n\u001b[31mlet _supCreateMode = false;\u001b[39m\n\u001b[31mlet _pendingDeleteId = null;\u001b[39m\n\u001b[31mlet _pendingDeleteReason = null;\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (s?.empId && _RECCE_ADMIN_IDS.includes(s.empId)) _adminUnlocked = true;\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31masync function loadRecceCfg(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(_RECCE_CFG_URL + '?t=' + Date.now());\u001b[39m\n\u001b[31m    if (r.ok) {\u001b[39m\n\u001b[31m      const j = await r.json();\u001b[39m\n\u001b[31m      if (j && j.version) {\u001b[39m\n\u001b[31m        _recceCfg = j;\u001b[39m\n\u001b[31m        if (Array.isArray(j.supervisors) && j.supervisors.length) {\u001b[39m\n\u001b[31m          _recceCfg.supervisors = j.supervisors;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.creators)) _recceCfg.creators = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.allowed_users)) _recceCfg.allowed_users = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.clients)) _recceCfg.clients = [];\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  // Re-check admin status against server supervisor list\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId)) {\u001b[39m\n\u001b[31m    _adminUnlocked = true;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _checkAccessMode(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (_recceCfg.mode !== 'assigned') return;\u001b[39m\n\u001b[31m  const allowed = [\u001b[39m\n\u001b[31m    ...(_recceCfg.supervisors || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.creators || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.allowed_users || []),\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  if (hub?.empId && allowed.includes(hub.empId)) return;\u001b[39m\n\u001b[31m  // Block access — show locked overlay\u001b[39m\n\u001b[31m  document.body.innerHTML = `<div style=\\\"min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0f172a;color:#fff;padding:32px;text-align:center\\\"><div style=\\\"font-size:48px;margin-bottom:16px\\\">🔒</div><div style=\\\"font-size:20px;font-weight:700;margin-bottom:8px\\\">${t('Access Restricted','एक्सेस प्रतिबंधित')}</div><div style=\\\"font-size:14px;color:#94a3b8\\\">${t('You are not authorised to use Branding Recce. Please contact your supervisor.','आप ब्रांडिंग रेक्की उपयोग के लिए अधिकृत नहीं हैं।')}</div></div>`;\u001b[39m\n\u001b[31m  throw new Error('access-restricted');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _recceHubUser() {\u001b[39m\n\u001b[31m  try { return JSON.parse(localStorage.getItem('lm360-session') || '{}'); }\u001b[39m\n\u001b[31m  catch(_) { return {}; }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── Supervisor config management ────────────────────────────────────\u001b[39m\n\u001b[31mfunction renderSupPanel(){\u001b[39m\n\u001b[31m  if (!_adminUnlocked) return;\u001b[39m\n\u001b[31m  const panel = document.getElementById('sup-panel');\u001b[39m\n\u001b[31m  if (panel) panel.style.display = 'block';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const modePublic = document.getElementById('mode-public');\u001b[39m\n\u001b[31m  const modeAssigned = document.getElementById('mode-assigned');\u001b[39m\n\u001b[31m  if (modePublic && modeAssigned) {\u001b[39m\n\u001b[31m    modePublic.classList.toggle('sel', _recceCfg.mode !== 'assigned');\u001b[39m\n\u001b[31m    modeAssigned.classList.toggle('sel', _recceCfg.mode === 'assigned');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  const addRow = document.getElementById('sup-add-row');\u001b[39m\n\u001b[31m  if (addRow) addRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const creatorAddRow = document.getElementById('creator-add-row');\u001b[39m\n\u001b[31m  if (creatorAddRow) creatorAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const clientAddRow = document.getElementById('client-add-row');\u001b[39m\n\u001b[31m  if (clientAddRow) clientAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const modeRow = document.getElementById('mode-row');\u001b[39m\n\u001b[31m  if (modeRow) {\u001b[39m\n\u001b[31m    modeRow.style.display = 'block';\u001b[39m\n\u001b[31m    // Non-cfg-admins see mode as read-only (toggles exist but setRecceMode guards them)\u001b[39m\n\u001b[31m    modeRow.style.opacity = isCfgAdmin ? '1' : '0.65';\u001b[39m\n\u001b[31m    modeRow.style.pointerEvents = isCfgAdmin ? '' : 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const syncBtn = document.getElementById('cfg-sync-btn');\u001b[39m\n\u001b[31m  if (syncBtn) syncBtn.style.display = isCfgAdmin ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('sup-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const sups = _recceCfg.supervisors || [];\u001b[39m\n\u001b[31m  el.innerHTML = sups.map((s,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${s}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin && sups.length > 1 ? `<button onclick=\\\"removeSupervisor(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderCreatorsList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('creator-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const creators = _recceCfg.creators || [];\u001b[39m\n\u001b[31m  el.innerHTML = creators.length ? creators.map((u,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${u}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeCreator(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No creators yet — any Hub user can submit in Public mode.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setRecceMode(mode){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.mode = mode;\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addSupervisor(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('sup-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.supervisors = [...(_recceCfg.supervisors || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeSupervisor(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.supervisors = (_recceCfg.supervisors || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addCreator(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('creator-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.creators || []).includes(val)) { toast(t('Already a creator','पहले से क्रिएटर है'), 'info'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor (includes creation rights)','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.creators = [...(_recceCfg.creators || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeCreator(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.creators = (_recceCfg.creators || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderClientMgmtList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('client-mgmt-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const list = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  el.innerHTML = list.length ? list.map((c,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${esc(c)}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeClientFromList(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No clients yet — add client or agency names to show them as chips in the form.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addClientToList(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('client-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter client name','क्लाइंट नाम दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.clients || []).includes(val)) { toast(t('Already in list','पहले से मौजूद है'), 'info'); return; }\u001b[39m\n\u001b[31m  if (!_recceCfg.clients) _recceCfg.clients = [];\u001b[39m\n\u001b[31m  _recceCfg.clients.push(val);\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeClientFromList(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.clients = (_recceCfg.clients || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncCfgToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast(t('Not authorised','अधिकृत नहीं'), 'error'); return; }\u001b[39m\n\u001b[31m  const st = document.getElementById('cfg-sync-status');\u001b[39m\n\u001b[31m  if (st) st.textContent = t('Syncing…','सिंक हो रहा है…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-cfg', empId: hub.empId, cfg: {\u001b[39m\n\u001b[31m        version: _recceCfg.version || 1,\u001b[39m\n\u001b[31m        supervisors: _recceCfg.supervisors || [],\u001b[39m\n\u001b[31m        mode: _recceCfg.mode || 'public',\u001b[39m\n\u001b[31m        creators: _recceCfg.creators || [],\u001b[39m\n\u001b[31m        allowed_users: _recceCfg.allowed_users || [],\u001b[39m\n\u001b[31m        clients: _recceCfg.clients || [],\u001b[39m\n\u001b[31m      }})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) {\u001b[39m\n\u001b[31m      toast(t('Config synced to server ✓','कॉन्फ़िग सर्वर पर सेव हुआ ✓'), 'success');\u001b[39m\n\u001b[31m      if (st) st.textContent = t('Last synced: just now','अभी सिंक हुआ');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast(j.error || t('Sync failed','सिंक विफल'), 'error');\u001b[39m\n\u001b[31m      if (st) st.textContent = j.error || '';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Network error','नेटवर्क त्रुटि'), 'error');\u001b[39m\n\u001b[31m    if (st) st.textContent = e.message;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function pushStoresToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!hub?.empId || !_adminUnlocked) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-stores', empId: hub.empId, stores })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) toast(`${t('Pushed to server','सर्वर पर पुश हुआ')} · ${j.count} ${t('stores','स्टोर')}`, 'success');\u001b[39m\n\u001b[31m    else toast(j.error || t('Server push failed','सर्वर पुश विफल'), 'error');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Could not reach server','सर्वर से संपर्क नहीं हो सका'), 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── End supervisor config management ────────────────────────────────·\u001b[39m\n\u001b[31m// PostgREST sync constants\u001b[39m\n\u001b[31mconst _RC_BASE      = '/db';\u001b[39m\n\u001b[31mconst _RC_READ      = { 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_WRITE     = { 'Content-Type': 'application/json', 'Content-Profile': 'recce', 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_UPSERT    = { ..._RC_WRITE, 'Prefer': 'resolution=merge-duplicates,return=minimal' };\u001b[39m\n\u001b[31mconst _INSTALL_RD   = { 'Content-Type': 'application/json', 'Accept-Profile': 'installation' };\u001b[39m\n\u001b[31mconst _INSTALL_WR   = { 'Content-Type': 'application/json', 'Content-Profile': 'installation', 'Accept-Profile': 'installation', 'Prefer': 'return=minimal' };·\u001b[39m\n\u001b[31m// ── Campaign selection state ──\u001b[39m\n\u001b[31mlet _selectedCampaignId = null;\u001b[39m\n\u001b[31mlet _notifySupervisor   = false;\u001b[39m\n\u001b[31mlet _campaignList       = [];\u001b[39m\n\u001b[31mlet _pendingJobFilter   = false;\u001b[39m\n\u001b[31mlet _linkJobSubId       = null;\u001b[39m\n\u001b[31mlet _brandingLocked     = false;·\u001b[39m\n\u001b[31mfunction _updateBrandingLock() {\u001b[39m\n\u001b[31m  const hub  = _recceHubUser();\u001b[39m\n\u001b[31m  const isHP = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const banner   = document.getElementById('branding-lock-banner');\u001b[39m\n\u001b[31m  const ovWrap   = document.getElementById('branding-override-wrap');\u001b[39m\n\u001b[31m  const brItems  = document.getElementById('br-items');\u001b[39m\n\u001b[31m  const brAdd    = document.getElementById('br-add');\u001b[39m\n\u001b[31m  const brYes    = document.getElementById('br-yes');\u001b[39m\n\u001b[31m  const brNo     = document.getElementById('br-no');\u001b[39m\n\u001b[31m  if (!banner) return;\u001b[39m\n\u001b[31m  if (_brandingLocked) {\u001b[39m\n\u001b[31m    banner.style.display   = '';\u001b[39m\n\u001b[31m    if (ovWrap)  ovWrap.style.display  = isHP ? '' : 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.pointerEvents = 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.opacity = '0.55';\u001b[39m\n\u001b[31m    if (brAdd)   brAdd.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='none'; brYes.style.opacity='0.5'; }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='none';  brNo.style.opacity='0.5';  }\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    banner.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brItems) { brItems.style.pointerEvents=''; brItems.style.opacity=''; }\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='';  brYes.style.opacity='';   }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='';   brNo.style.opacity='';    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction unlockBrandingOverride() {\u001b[39m\n\u001b[31m  if (!confirm(\u001b[39m\n\u001b[31m    'Client has already reviewed this recce.\\\\n' +\u001b[39m\n\u001b[31m    'Editing brandings will NOT remove their approval.\\\\n' +\u001b[39m\n\u001b[31m    'Continue ONLY if the client has verbally confirmed. Proceed?'\u001b[39m\n\u001b[31m  )) return;\u001b[39m\n\u001b[31m  _brandingLocked = false;\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  renderBrandings();\u001b[39m\n\u001b[31m  toast(t('Branding unlocked for this session', 'ब्रांडिंग इस सत्र के लिए अनलॉक'), 'info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadCampaignsForForm() {\u001b[39m\n\u001b[31m  const sel = document.getElementById('f-campaign-id');\u001b[39m\n\u001b[31m  if (!sel) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m    _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m  } catch(_) { _campaignList = []; }\u001b[39m\n\u001b[31m  sel.innerHTML =\u001b[39m\n\u001b[31m    '<option value=\\\"\\\">— Select job / campaign (optional) —</option>' +\u001b[39m\n\u001b[31m    _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('') +\u001b[39m\n\u001b[31m    '<option value=\\\"__NOTIFY__\\\">⚑ No campaign yet — notify supervisor</option>';\u001b[39m\n\u001b[31m  if (_selectedCampaignId) sel.value = _selectedCampaignId;\u001b[39m\n\u001b[31m  else if (_notifySupervisor) sel.value = '__NOTIFY__';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onCampaignSelect() {\u001b[39m\n\u001b[31m  const val = document.getElementById('f-campaign-id')?.value || '';\u001b[39m\n\u001b[31m  const noticeEl = document.getElementById('campaign-notify-msg');\u001b[39m\n\u001b[31m  if (val === '__NOTIFY__') {\u001b[39m\n\u001b[31m    _selectedCampaignId = null;\u001b[39m\n\u001b[31m    _notifySupervisor   = true;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'block';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    _selectedCampaignId = val || null;\u001b[39m\n\u001b[31m    _notifySupervisor   = false;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction generateRecceReportHtml(entry, photoUrls) {\u001b[39m\n\u001b[31m  const d    = entry.data || {};\u001b[39m\n\u001b[31m  const urls = photoUrls || {};\u001b[39m\n\u001b[31m  const agent = entry.submittedByName || entry.submittedBy || 'Field Agent';\u001b[39m\n\u001b[31m  const _safeId      = (entry.id||'').replace(/\\\\//g,'_').replace(/\\\\.\\\\./g,'');\u001b[39m\n\u001b[31m  const serverPdfUrl = _safeId ? `https://srv1111289.hstgr.cloud/screenshots/recce/views/${_safeId}.pdf` : '';\u001b[39m\n\u001b[31m  const brandLogoUrl = d.brandLogoUrl || _brandLogos[d.brand] || '';\u001b[39m\n\u001b[31m  const tsStr = new Date(entry.timestamp).toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric',hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\u001b[39m\n\u001b[31m  const gpsUrl = d.gpsCoords ? `https://maps.google.com/?q=${d.gpsCoords.lat},${d.gpsCoords.lng}` : null;·\u001b[39m\n\u001b[31m  const frontCount  = (urls.front||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const insideCount = (urls.inside||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const addlCount   = (urls.addl||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const brCount     = (d.brandings||[]).length;·\u001b[39m\n\u001b[31m  // pages: { id, url, bandHtml, cmt, dotLabel, dotColor }\u001b[39m\n\u001b[31m  const pages = [];·\u001b[39m\n\u001b[31m  (urls.front||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Front View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${frontCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.frontPhotos||[])[i]?.cmt||'', dotLabel:`FV${i+1}`, dotColor:'#3b82f6', catLabel:'Front View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.inside||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Inside View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${insideCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.insidePhotos||[])[i]?.cmt||'', dotLabel:`IV${i+1}`, dotColor:'#14b8a6', catLabel:'Inside View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (d.brandings||[]).forEach((b,i)=>{\u001b[39m\n\u001b[31m    const url=(urls.brandings||[])[i]; if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">${esc(b.type||'Branding')}</div><div class=\\\"ph-dims\\\">Width : ${esc(b.w||'?')}&Prime;&nbsp;&times;&nbsp;Height : ${esc(b.h||'?')}&Prime;&nbsp;&mdash;&nbsp;${esc(b.qty||1)} Nos</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${brCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:'', dotLabel:`B${i+1}`, dotColor:'#f97316', catLabel:b.type||'Branding',\u001b[39m\n\u001b[31m      tileDims:`${b.w||'?'}″×${b.h||'?'}″ — ${String(b.qty||1).padStart(2,'0')} Nos` });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.addl||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Additional</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${addlCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.addlPhotos||[])[i]?.desc||'', dotLabel:`A${i+1}`, dotColor:'#94a3b8', catLabel:'Additional', tileDims:'' });\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const sideItems = [\u001b[39m\n\u001b[31m    `<div class=\\\"si-item active\\\" data-tgt=\\\"pg-cover\\\" title=\\\"Cover\\\"><div class=\\\"si-dot\\\" style=\\\"background:#475569\\\">CV</div></div>`\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  pages.forEach(p => {\u001b[39m\n\u001b[31m    sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"${p.id}\\\" title=\\\"${p.dotLabel}\\\"><div class=\\\"si-dot\\\" style=\\\"background:${p.dotColor}\\\">${p.dotLabel}</div></div>`);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(d.hasVideo) sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-vid\\\" title=\\\"Video\\\"><div class=\\\"si-dot\\\" style=\\\"background:#a855f7\\\">VD</div></div>`);\u001b[39m\n\u001b[31m  if(urls.doc)   sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-doc\\\" title=\\\"Document\\\"><div class=\\\"si-dot\\\" style=\\\"background:#64748b\\\">DC</div></div>`);·\u001b[39m\n\u001b[31m  const thumbItems = [\u001b[39m\n\u001b[31m    ...pages,\u001b[39m\n\u001b[31m    ...(d.hasVideo?[{id:'pg-vid',url:null,catLabel:'Video',tileDims:'',dotLabel:'VD',dotColor:'#a855f7'}]:[]),\u001b[39m\n\u001b[31m    ...(urls.doc?[{id:'pg-doc',url:urls.doc,catLabel:'Document',tileDims:'',dotLabel:'DC',dotColor:'#64748b'}]:[])\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  const thumbsHtml = thumbItems.map(p=>`<div class=\\\"cov-thumb\\\" onclick=\\\"document.getElementById('${p.id}').scrollIntoView({behavior:'smooth'})\\\">${p.url?`<img src=\\\"${p.url}\\\" alt=\\\"\\\">`:(`<div class=\\\"cov-thumb-vid\\\">${p.catLabel==='Video'?'&#x25B6;&#xFE0F;':'&#x1F4C4;'}</div>`)}<div class=\\\"cov-thumb-ov\\\" style=\\\"border-top:3px solid ${p.dotColor}\\\"><div class=\\\"cov-thumb-cat\\\">${esc(p.catLabel)}</div>${p.tileDims?`<div class=\\\"cov-thumb-dims\\\">${esc(p.tileDims)}</div>`:''}<div class=\\\"cov-thumb-no\\\">${p.dotLabel}</div></div></div>`).join('');·\u001b[39m\n\u001b[31m  const pagesHtml = pages.map(p => `\u001b[39m\n\u001b[31m<div class=\\\"photo-page\\\" id=\\\"${p.id}\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\">${p.bandHtml}</div>\u001b[39m\n\u001b[31m  <div class=\\\"ph-img\\\"><a href=\\\"${p.url}\\\" target=\\\"_blank\\\"><img src=\\\"${p.url}\\\" loading=\\\"lazy\\\" alt=\\\"\\\"></a>${p.cmt?`<div class=\\\"ph-cmt\\\">${esc(p.cmt)}</div>`:''}</div>\u001b[39m\n\u001b[31m</div>`).join('');·\u001b[39m\n\u001b[31m  return `<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\"><head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m<title>Recce — ${esc(d.storeName||'Unknown')} · ${esc(d.brand||'')}</title>\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--dk:#0f172a;--nv2:#1a2f52;--or:#f97316;--g200:#e2e8f0;--g400:#94a3b8;--g600:#475569;--si:54px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0}\u001b[39m\n\u001b[31mhtml,body{height:100%;overflow:hidden}\u001b[39m\n\u001b[31mbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#111;color:var(--dk);display:flex}\u001b[39m\n\u001b[31ma{color:var(--or);text-decoration:none}\u001b[39m\n\u001b[31mimg{display:block}·\u001b[39m\n\u001b[31m/* ── Side index ── */\u001b[39m\n\u001b[31m.side-idx{width:var(--si);flex-shrink:0;background:var(--dk);overflow-y:auto;display:flex;flex-direction:column;align-items:center;padding:4px 0;scrollbar-width:none;z-index:50}\u001b[39m\n\u001b[31m.side-idx::-webkit-scrollbar{display:none}\u001b[39m\n\u001b[31m.si-item{width:100%;min-height:56px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s}\u001b[39m\n\u001b[31m.si-item:hover{background:rgba(255,255,255,.07)}\u001b[39m\n\u001b[31m.si-dot{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff;opacity:.4;transition:opacity .18s,transform .18s;line-height:1;text-align:center}\u001b[39m\n\u001b[31m.si-item.active .si-dot{opacity:1;transform:scale(1.15)}·\u001b[39m\n\u001b[31m/* ── Main scroll area ── */\u001b[39m\n\u001b[31m.main{flex:1;overflow-y:scroll;scroll-snap-type:y mandatory;scroll-behavior:smooth;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar{width:3px}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15)}·\u001b[39m\n\u001b[31m/* ── Cover ── */\u001b[39m\n\u001b[31m.cover{height:100vh;scroll-snap-align:start;flex-shrink:0;background:linear-gradient(135deg,#0f172a 0%,var(--nv2) 100%);color:#fff;display:flex;flex-direction:column;padding:24px 20px 20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.cover-badge{display:inline-flex;align-items:center;gap:5px;background:var(--or);color:#fff;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:1px;padding:3px 12px;border-radius:20px;margin-bottom:12px;align-self:flex-start}\u001b[39m\n\u001b[31m.cover h1{font-size:20px;font-weight:700;line-height:1.3;margin-bottom:4px}\u001b[39m\n\u001b[31m.cover-addr{color:rgba(255,255,255,.55);font-size:12px;margin-bottom:16px}\u001b[39m\n\u001b[31m.cg{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}\u001b[39m\n\u001b[31m.cm{background:rgba(255,255,255,.08);border-radius:8px;padding:8px 12px}\u001b[39m\n\u001b[31m.cm-l{font-size:9px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}\u001b[39m\n\u001b[31m.cm-v{font-size:13px;font-weight:600;color:#fff}\u001b[39m\n\u001b[31m.cm-v a{color:#fb923c}\u001b[39m\n\u001b[31m.cover-pbar{padding-top:8px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{background:var(--or);color:#fff;border:none;padding:10px 22px;border-radius:22px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}\u001b[39m\n\u001b[31m.btn-p:disabled{opacity:.4;cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-c{background:rgba(255,255,255,.1);color:rgba(255,255,255,.75);border:1px solid rgba(255,255,255,.2);padding:10px 18px;border-radius:22px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit}·\u001b[39m\n\u001b[31m/* ── Cover thumbnail grid ── */\u001b[39m\n\u001b[31m.cov-grid-hdr{font-size:10px;font-weight:700;color:rgba(255,255,255,.35);text-transform:uppercase;letter-spacing:1.2px;padding:10px 0 5px;flex-shrink:0}\u001b[39m\n\u001b[31m.cov-grid{flex:1;min-height:0;display:grid;gap:5px;overflow:hidden;align-content:start}\u001b[39m\n\u001b[31m.cov-thumb{position:relative;overflow:hidden;border-radius:7px;cursor:pointer;background:#1e293b;transition:transform .18s,box-shadow .18s}\u001b[39m\n\u001b[31m.cov-thumb:hover{transform:scale(1.05);box-shadow:0 4px 18px rgba(0,0,0,.55)}\u001b[39m\n\u001b[31m.cov-thumb img{width:100%;height:100%;object-fit:cover;display:block}\u001b[39m\n\u001b[31m.cov-thumb-vid{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:#0f172a}\u001b[39m\n\u001b[31m.cov-thumb-ov{position:absolute;inset:0;background:rgba(0,0,0,.28);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:5px;border-radius:7px}\u001b[39m\n\u001b[31m.cov-thumb-cat{color:rgba(255,255,255,.5);font-weight:900;text-align:center;text-transform:uppercase;letter-spacing:.8px;text-shadow:0 1px 6px rgba(0,0,0,.95);line-height:1.2;word-break:break-word}\u001b[39m\n\u001b[31m.cov-thumb-dims{color:rgba(255,255,255,.5);font-weight:700;text-align:center;text-shadow:0 1px 5px rgba(0,0,0,.95);letter-spacing:.3px;line-height:1.3}\u001b[39m\n\u001b[31m.cov-thumb-no{color:rgba(255,255,255,.5);font-weight:800;text-shadow:0 1px 4px rgba(0,0,0,.95);letter-spacing:.5px}\u001b[39m\n\u001b[31m#cover-btn{position:fixed;bottom:20px;right:16px;display:none;align-items:center;gap:6px;background:rgba(255,255,255,.15);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.25);color:#fff;padding:10px 22px;border-radius:50px;font-size:13px;font-weight:700;cursor:pointer;z-index:200;letter-spacing:.3px;box-shadow:0 2px 12px rgba(0,0,0,.3);font-family:inherit;transition:background .15s,transform .15s}\u001b[39m\n\u001b[31m#cover-btn:hover{background:rgba(255,255,255,.22);transform:scale(1.04)}·\u001b[39m\n\u001b[31m/* ── Print wait overlay ── */\u001b[39m\n\u001b[31m#print-overlay{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m@media print{#print-overlay{display:none!important}}·\u001b[39m\n\u001b[31m/* ── Loading progress bar ── */\u001b[39m\n\u001b[31m.load-bar{position:fixed;bottom:0;left:0;right:0;background:rgba(15,23,42,.95);padding:9px 16px;z-index:9999;display:flex;align-items:center;gap:12px;backdrop-filter:blur(6px)}\u001b[39m\n\u001b[31m.load-track{flex:1;height:5px;background:rgba(255,255,255,.12);border-radius:3px;overflow:hidden}\u001b[39m\n\u001b[31m.load-fill{height:100%;background:var(--or);width:0%;transition:width .35s ease;border-radius:3px}\u001b[39m\n\u001b[31m.load-txt{font-size:11px;color:rgba(255,255,255,.6);white-space:nowrap;min-width:160px}·\u001b[39m\n\u001b[31m/* ── Photo page ── */\u001b[39m\n\u001b[31m.photo-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ph-band{background:var(--dk);padding:16px 26px;flex-shrink:0;display:flex;align-items:center;gap:20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.ph-cat{font-size:35px;font-weight:800;color:#fff;letter-spacing:-.5px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.ph-dims{flex:1;font-size:18px;font-weight:600;color:var(--or);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}\u001b[39m\n\u001b[31m.ph-no{margin-left:auto;flex-shrink:0;font-size:21px;font-weight:700;color:rgba(255,255,255,.85);background:rgba(255,255,255,.1);padding:5px 20px;border-radius:24px;white-space:nowrap}\u001b[39m\n\u001b[31m.ph-of{font-size:18px;font-weight:400;color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.ph-img{flex:1;overflow:hidden;position:relative;background:#111}\u001b[39m\n\u001b[31m.ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m.ph-img img{width:100%;height:100%;object-fit:contain;display:block}\u001b[39m\n\u001b[31m.ph-cmt{position:absolute;bottom:0;left:0;right:0;padding:6px 14px;background:rgba(0,0,0,.62);font-size:11px;color:rgba(255,255,255,.75);font-style:italic;pointer-events:none}·\u001b[39m\n\u001b[31m/* ── Video / Doc pages ── */\u001b[39m\n\u001b[31m.vid-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;background:#fff}\u001b[39m\n\u001b[31m.vid-body{flex:1;padding:20px 24px;font-size:14px;color:var(--g600);border-left:4px solid var(--or)}\u001b[39m\n\u001b[31m.vid-body em{display:block;font-size:12px;color:var(--g400);margin-top:6px}\u001b[39m\n\u001b[31m.doc-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m.doc-wrap{flex:1;display:flex;align-items:center;justify-content:center;background:#111;overflow:hidden}\u001b[39m\n\u001b[31m.doc-img{max-width:100%;max-height:100%;object-fit:contain}·\u001b[39m\n\u001b[31m/* ── Cover header band ── */\u001b[39m\n\u001b[31m.cov-hdr{display:flex;gap:0;margin-bottom:12px;flex-shrink:0;border-radius:10px;overflow:hidden;border:1px solid rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.cov-hdr-l{flex:1;padding:14px 18px;display:flex;flex-direction:column;gap:5px;border-right:1px solid rgba(255,255,255,.1);min-width:0}\u001b[39m\n\u001b[31m.cov-hdr-r{width:170px;flex-shrink:0;padding:14px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:rgba(255,255,255,.04)}\u001b[39m\n\u001b[31m.cov-store{font-size:18px;font-weight:800;color:#fff;line-height:1.25;margin-bottom:2px}\u001b[39m\n\u001b[31m.cov-meta{font-size:12px;color:rgba(255,255,255,.55);display:flex;align-items:center;gap:5px;line-height:1.5}\u001b[39m\n\u001b[31m.cov-brand{background:var(--or);color:#fff;font-size:13px;font-weight:800;padding:5px 16px;border-radius:20px;text-align:center;letter-spacing:.3px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\u001b[39m\n\u001b[31m.cov-date-l{font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.8px;margin-bottom:2px;text-align:center}\u001b[39m\n\u001b[31m.cov-date-v{font-size:13px;font-weight:700;color:#fff;text-align:center}\u001b[39m\n\u001b[31m.cov-logo-box{background:#fff;border-radius:8px;padding:8px 14px;display:flex;align-items:center;justify-content:center;width:100%;max-width:138px}\u001b[39m\n\u001b[31m.cov-logo-box img{max-width:110px;max-height:44px;object-fit:contain;display:block}·\u001b[39m\n\u001b[31m/* ── Print ── */\u001b[39m\n\u001b[31m@page{size:A4 landscape;margin:12mm}\u001b[39m\n\u001b[31m@media print{\u001b[39m\n\u001b[31m  html,body{height:auto;overflow:visible;display:block}\u001b[39m\n\u001b[31m  .side-idx{display:none}\u001b[39m\n\u001b[31m  .main{overflow:visible;display:block;height:auto;scroll-snap-type:none}\u001b[39m\n\u001b[31m  .cover,.vid-page,.doc-page{height:auto;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m  .photo-page{height:186mm;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m  .cover{padding:20px 24px}\u001b[39m\n\u001b[31m  .cover-pbar{display:none}\u001b[39m\n\u001b[31m  .cov-hdr{margin-bottom:8px;border-radius:7px}\u001b[39m\n\u001b[31m  .cov-hdr-l{padding:10px 14px}\u001b[39m\n\u001b[31m  .cov-hdr-r{padding:10px 12px;width:150px}\u001b[39m\n\u001b[31m  .cov-store{font-size:15px}\u001b[39m\n\u001b[31m  .cov-meta{font-size:10px}\u001b[39m\n\u001b[31m  .cov-brand{font-size:11px;padding:3px 12px}\u001b[39m\n\u001b[31m  .cov-date-v{font-size:11px}\u001b[39m\n\u001b[31m  .ph-band{padding:5mm 13mm;gap:10mm}\u001b[39m\n\u001b[31m  .ph-cat{font-size:15mm}\u001b[39m\n\u001b[31m  .ph-dims{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-no{font-size:12mm;padding:2mm 8mm}\u001b[39m\n\u001b[31m  .ph-of{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-img{flex:1;display:flex;align-items:center;justify-content:center;background:#fff;overflow:hidden}\u001b[39m\n\u001b[31m  .ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m  .ph-img img{width:100%;height:100%;object-fit:contain}\u001b[39m\n\u001b[31m  .ph-cmt{position:static;background:transparent;color:#475569;padding:2mm 8mm;font-size:6mm}\u001b[39m\n\u001b[31m  .main>*:last-child{page-break-after:avoid;break-after:avoid}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m</style></head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<div class=\\\"side-idx\\\" id=\\\"side-idx\\\">${sideItems.join('')}</div>·\u001b[39m\n\u001b[31m<div class=\\\"main\\\" id=\\\"main\\\">·\u001b[39m\n\u001b[31m<div class=\\\"cover\\\" id=\\\"pg-cover\\\">\u001b[39m\n\u001b[31m  <div class=\\\"cov-hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-l\\\">\u001b[39m\n\u001b[31m      <div class=\\\"cov-store\\\">${esc(d.storeName||'Unknown Store')}</div>\u001b[39m\n\u001b[31m      ${(d.address||d.city)?`<div class=\\\"cov-meta\\\">&#x1F4CD; ${esc(d.address||'')}${d.city&&!(d.address||'').includes(d.city)?', '+esc(d.city):''}</div>`:''}\u001b[39m\n\u001b[31m      ${d.mobile?`<div class=\\\"cov-meta\\\">&#x1F4DE; ${esc(d.mobile)}</div>`:''}\u001b[39m\n\u001b[31m      ${d.email?`<div class=\\\"cov-meta\\\">&#x2709; ${esc(d.email)}</div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-r\\\">\u001b[39m\n\u001b[31m      ${brandLogoUrl\u001b[39m\n\u001b[31m        ? `<div class=\\\"cov-logo-box\\\"><img src=\\\"${brandLogoUrl}\\\" alt=\\\"${esc(d.brand||'')}\\\"></div>`\u001b[39m\n\u001b[31m        : (d.brand?`<div class=\\\"cov-brand\\\">${esc(d.brand)}</div>`:'')}\u001b[39m\n\u001b[31m      ${d.date?`<div><div class=\\\"cov-date-l\\\">Recce Date</div><div class=\\\"cov-date-v\\\">${esc(d.date)}</div></div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${thumbItems.length ? `<div class=\\\"cov-grid-hdr\\\">&#x1F4F7; ${thumbItems.length} page${thumbItems.length!==1?'s':''} &mdash; tap any to jump</div><div class=\\\"cov-grid\\\" id=\\\"cov-grid\\\">${thumbsHtml}</div>` : ''}\u001b[39m\n\u001b[31m  <div class=\\\"cover-pbar\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" id=\\\"btn-print\\\" onclick=\\\"doPDF()\\\">&#x1F4C4;&nbsp;PDF</button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-c\\\" onclick=\\\"window.close()\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m${pagesHtml}·\u001b[39m\n\u001b[31m${d.hasVideo?`\u001b[39m\n\u001b[31m<div class=\\\"vid-page\\\" id=\\\"pg-vid\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Video</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"vid-body\\\">${esc(d.videoNote||'Video recorded during visit')}${d.videoCmt?`<em>${esc(d.videoCmt)}</em>`:''}</div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m${urls.doc?`\u001b[39m\n\u001b[31m<div class=\\\"doc-page\\\" id=\\\"pg-doc\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Document</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"doc-wrap\\\"><a href=\\\"${urls.doc}\\\" target=\\\"_blank\\\"><img class=\\\"doc-img\\\" src=\\\"${urls.doc}\\\" loading=\\\"lazy\\\" alt=\\\"Document\\\"></a></div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"print-overlay\\\"><div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Preparing print&hellip;</div><div class=\\\"po-sub\\\" id=\\\"po-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"po-pfill\\\"></div></div></div>\u001b[39m\n\u001b[31m${pages.length ? `<div class=\\\"load-bar\\\" id=\\\"load-bar\\\"><div class=\\\"load-track\\\"><div class=\\\"load-fill\\\" id=\\\"load-fill\\\"></div></div><div class=\\\"load-txt\\\" id=\\\"load-txt\\\">Loading photos&#x2026;</div></div>` : ''}\u001b[39m\n\u001b[31m${thumbItems.length ? `<button id=\\\"cover-btn\\\" onclick=\\\"document.getElementById('pg-cover').scrollIntoView({behavior:'smooth'})\\\">&#x1F3E0;&nbsp;Cover Page</button>` : ''}·\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var main=document.getElementById('main');\u001b[39m\n\u001b[31m  var items=document.querySelectorAll('.si-item');\u001b[39m\n\u001b[31m  var covBtn=document.getElementById('cover-btn');\u001b[39m\n\u001b[31m  function setActive(id){\u001b[39m\n\u001b[31m    items.forEach(function(el){el.classList.toggle('active',el.dataset.tgt===id);});\u001b[39m\n\u001b[31m    var a=document.querySelector('.si-item[data-tgt=\\\"'+id+'\\\"]');\u001b[39m\n\u001b[31m    if(a) a.scrollIntoView({block:'nearest'});\u001b[39m\n\u001b[31m    if(covBtn) covBtn.style.display=id==='pg-cover'?'none':'flex';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  items.forEach(function(el){\u001b[39m\n\u001b[31m    el.addEventListener('click',function(){\u001b[39m\n\u001b[31m      var t=document.getElementById(el.dataset.tgt);\u001b[39m\n\u001b[31m      if(t) t.scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if('IntersectionObserver' in window){\u001b[39m\n\u001b[31m    var obs=new IntersectionObserver(function(entries){\u001b[39m\n\u001b[31m      entries.forEach(function(e){if(e.isIntersecting&&e.intersectionRatio>=0.45) setActive(e.target.id);});\u001b[39m\n\u001b[31m    },{root:main,threshold:0.45});\u001b[39m\n\u001b[31m    document.querySelectorAll('[id^=\\\"pg-\\\"]').forEach(function(p){obs.observe(p);});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  setActive('pg-cover');\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var imgs=Array.from(document.querySelectorAll('img'));\u001b[39m\n\u001b[31m  var total=imgs.length,loaded=0;\u001b[39m\n\u001b[31m  var bar=document.getElementById('load-bar');\u001b[39m\n\u001b[31m  var fill=document.getElementById('load-fill');\u001b[39m\n\u001b[31m  var txt=document.getElementById('load-txt');\u001b[39m\n\u001b[31m  var printPending=false,printShowTime=0;\u001b[39m\n\u001b[31m  var mm=96/25.4;\u001b[39m\n\u001b[31m  var SERVER_PDF='${serverPdfUrl}';\u001b[39m\n\u001b[31m  function updatePoBar(){\u001b[39m\n\u001b[31m    var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m    var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(poFill) poFill.style.width=(total?Math.round(loaded/total*100):100)+'%';\u001b[39m\n\u001b[31m    if(poSub) poSub.textContent=loaded+' / '+total+' photos ready';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function done(){\u001b[39m\n\u001b[31m    if(fill) fill.style.width='100%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='✓ All '+total+' photos ready';\u001b[39m\n\u001b[31m    setTimeout(function(){\u001b[39m\n\u001b[31m      if(bar){bar.style.transition='opacity .6s';bar.style.opacity='0';}\u001b[39m\n\u001b[31m      setTimeout(function(){if(bar)bar.style.display='none';},650);\u001b[39m\n\u001b[31m    },2000);\u001b[39m\n\u001b[31m    if(printPending){\u001b[39m\n\u001b[31m      printPending=false;\u001b[39m\n\u001b[31m      var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m      var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m      var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(poFill) poFill.style.width='100%';\u001b[39m\n\u001b[31m      if(poSub) poSub.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},Math.max(400,2000-(Date.now()-printShowTime)));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function onImg(){\u001b[39m\n\u001b[31m    loaded++;\u001b[39m\n\u001b[31m    if(fill) fill.style.width=Math.round(loaded/total*100)+'%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… '+loaded+' / '+total;\u001b[39m\n\u001b[31m    if(printPending) updatePoBar();\u001b[39m\n\u001b[31m    if(loaded>=total) done();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  /* ── PDF layout helpers ── */\u001b[39m\n\u001b[31m  function fitBandFonts(pageW){\u001b[39m\n\u001b[31m    var padH=2*13*mm,gapH=2*10*mm,noPadH=2*8*mm;\u001b[39m\n\u001b[31m    var avail=pageW-padH-gapH;\u001b[39m\n\u001b[31m    var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-band').forEach(function(band){\u001b[39m\n\u001b[31m      var cat=band.querySelector('.ph-cat');\u001b[39m\n\u001b[31m      var dims=band.querySelector('.ph-dims');\u001b[39m\n\u001b[31m      var no=band.querySelector('.ph-no');\u001b[39m\n\u001b[31m      if(!cat) return;\u001b[39m\n\u001b[31m      var catTxt=cat.textContent.trim();\u001b[39m\n\u001b[31m      var dimsTxt=dims?dims.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      var noTxt=no?no.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      function tw(sc){\u001b[39m\n\u001b[31m        var cf=15*sc*mm,df=10*sc*mm,nf=12*sc*mm;\u001b[39m\n\u001b[31m        ctx.font='800 '+cf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var cw=ctx.measureText(catTxt).width;\u001b[39m\n\u001b[31m        ctx.font='600 '+df+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var dw=dims?ctx.measureText(dimsTxt).width:0;\u001b[39m\n\u001b[31m        ctx.font='700 '+nf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var nw=no?ctx.measureText(noTxt).width+noPadH:0;\u001b[39m\n\u001b[31m        return cw+dw+nw;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      var scale=1.0;\u001b[39m\n\u001b[31m      if(tw(scale)>avail){\u001b[39m\n\u001b[31m        var lo=0.3,hi=1.0;\u001b[39m\n\u001b[31m        for(var i=0;i<10;i++){var mid=(lo+hi)/2;if(tw(mid)<=avail)lo=mid;else hi=mid;}\u001b[39m\n\u001b[31m        scale=lo*0.93;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      cat.style.setProperty('font-size',Math.round(15*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(dims) dims.style.setProperty('font-size',Math.round(10*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(no) no.style.setProperty('font-size',Math.round(12*scale*mm)+'px','important');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function sizePdfThumbs(pageW,pageH){\u001b[39m\n\u001b[31m    var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m    if(!grid||!grid.children.length) return;\u001b[39m\n\u001b[31m    var coverPage=document.getElementById('pg-cover');\u001b[39m\n\u001b[31m    var usedH=56;\u001b[39m\n\u001b[31m    if(coverPage){\u001b[39m\n\u001b[31m      Array.from(coverPage.children).forEach(function(el){\u001b[39m\n\u001b[31m        if(el!==grid) usedH+=el.offsetHeight||0;\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    var gridH=Math.max(80,pageH-usedH);\u001b[39m\n\u001b[31m    var n=grid.children.length,gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m    for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m      var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m      var w=(pageW-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m      var h=w*asp;\u001b[39m\n\u001b[31m      if(rows*h+(rows-1)*gap<=gridH&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m    grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m    grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m    var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m    var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m    var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function preparePdfLayout(){\u001b[39m\n\u001b[31m    var pageW=Math.round((297-24)*mm);\u001b[39m\n\u001b[31m    var pageH=Math.round((210-24)*mm);\u001b[39m\n\u001b[31m    fitBandFonts(pageW);\u001b[39m\n\u001b[31m    sizePdfThumbs(pageW,pageH);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.preparePdfLayout=preparePdfLayout;\u001b[39m\n\u001b[31m  function restorePdfLayout(){\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-cat,.ph-dims,.ph-no').forEach(function(el){\u001b[39m\n\u001b[31m      el.style.removeProperty('font-size');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(window._screenSizeThumbs) window._screenSizeThumbs();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.addEventListener('afterprint',restorePdfLayout);\u001b[39m\n\u001b[31m  function _doBrowserPrint(){\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    printShowTime=Date.now();\u001b[39m\n\u001b[31m    preparePdfLayout();\u001b[39m\n\u001b[31m    if(total===0||loaded>=total){\u001b[39m\n\u001b[31m      var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m      if(ps) ps.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},2000);\u001b[39m\n\u001b[31m      return;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    printPending=true;\u001b[39m\n\u001b[31m    updatePoBar();\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if((!img.complete||img.naturalWidth===0)&&img.getAttribute('loading')==='lazy'){\u001b[39m\n\u001b[31m        img.loading='eager';var s=img.src;img.src='';img.src=s;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.doPDF=async function(){\u001b[39m\n\u001b[31m    if(!SERVER_PDF){_doBrowserPrint();return;}\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      var r=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m      if(r.ok){window.open(SERVER_PDF,'_blank');return;}\u001b[39m\n\u001b[31m    }catch(_){}\u001b[39m\n\u001b[31m    // PDF not ready yet — show overlay and poll\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    if(pf) pf.style.width='0%';\u001b[39m\n\u001b[31m    if(ps) ps.textContent='Waiting for server PDF…';\u001b[39m\n\u001b[31m    var tries=0;\u001b[39m\n\u001b[31m    (async function poll(){\u001b[39m\n\u001b[31m      tries++;\u001b[39m\n\u001b[31m      if(pf) pf.style.width=Math.min(88,tries*8)+'%';\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        var r2=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m        if(r2.ok){\u001b[39m\n\u001b[31m          if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m          setTimeout(function(){if(ov)ov.style.display='none';window.open(SERVER_PDF,'_blank');},400);\u001b[39m\n\u001b[31m          return;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      }catch(_){}\u001b[39m\n\u001b[31m      if(tries>=12){if(ov)ov.style.display='none';_doBrowserPrint();return;}\u001b[39m\n\u001b[31m      setTimeout(poll,5000);\u001b[39m\n\u001b[31m    })();\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  if(total===0){if(bar)bar.style.display='none';}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… 0 / '+total;\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if(img.complete&&img.naturalWidth>0) onImg();\u001b[39m\n\u001b[31m      else{img.addEventListener('load',onImg);img.addEventListener('error',onImg);}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m  if(grid&&grid.children.length>0){\u001b[39m\n\u001b[31m    function sizeThumbs(){\u001b[39m\n\u001b[31m      var n=grid.children.length;\u001b[39m\n\u001b[31m      var gw=grid.clientWidth,gh=grid.clientHeight;\u001b[39m\n\u001b[31m      if(!gw||!gh) return;\u001b[39m\n\u001b[31m      var gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m      for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m        var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m        var w=(gw-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m        var h=w*asp;\u001b[39m\n\u001b[31m        if(rows*h+(rows-1)*gap<=gh&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m      grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m      grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m      var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m      var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m      var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    window._screenSizeThumbs=sizeThumbs;\u001b[39m\n\u001b[31m    requestAnimationFrame(function(){requestAnimationFrame(sizeThumbs);});\u001b[39m\n\u001b[31m    window.addEventListener('resize',sizeThumbs);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m</scr`+'ipt>'+`\u001b[39m\n\u001b[31m</body></html>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncToPostgres(entry) {\u001b[39m\n\u001b[31m  const d   = entry.data || {};\u001b[39m\n\u001b[31m  const hub = _recceHubUser();·\u001b[39m\n\u001b[31m  // Step 1 — upload all photos to VPS, get permanent server URLs\u001b[39m\n\u001b[31m  let photoUrls = { front:[], inside:[], brandings:[], addl:[], doc:null };\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const pResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type: 'save-photos', subId: entry.id,\u001b[39m\n\u001b[31m        photos: {\u001b[39m\n\u001b[31m          front:    (d.frontPhotos||[]).map(p=>({b64:p.b64,   cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64,  cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||null})),\u001b[39m\n\u001b[31m          addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64,   desc:p.desc||''})),\u001b[39m\n\u001b[31m          doc:      d.docB64 || null,\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (pResp.ok) { const r=await pResp.json(); if(r.success) {\u001b[39m\n\u001b[31m      photoUrls=r.photoUrls;\u001b[39m\n\u001b[31m      // Merge retained existing URLs for edit re-submits\u001b[39m\n\u001b[31m      if (entry.editedAt) {\u001b[39m\n\u001b[31m        photoUrls.front    =(photoUrls.front   ||[]).map((u,i)=>u||(d.frontPhotos  ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.inside   =(photoUrls.inside  ||[]).map((u,i)=>u||(d.insidePhotos ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.addl     =(photoUrls.addl    ||[]).map((u,i)=>u||(d.addlPhotos   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.brandings=(photoUrls.brandings||[]).map((u,i)=>u||(d.brandings   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        if(!photoUrls.doc) photoUrls.doc=d._docExistingUrl||null;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }}\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-photos] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 1.5 — trigger Google Slides via proxy using permanent photo URLs (fire-and-forget)\u001b[39m\n\u001b[31m  (async()=>{try{\u001b[39m\n\u001b[31m    const _hasPh=(photoUrls.front||[]).some(Boolean)||(photoUrls.inside||[]).some(Boolean)||(photoUrls.brandings||[]).some(Boolean);\u001b[39m\n\u001b[31m    if(!_hasPh)return;\u001b[39m\n\u001b[31m    const _gu=(await cfg('slides-gas-url'))||(await cfg('gas-url'))||DEFAULT_GAS_URL;if(!_gu)return;\u001b[39m\n\u001b[31m    await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({\u001b[39m\n\u001b[31m      type:'make-slides',gasUrl:_gu,subId:entry.id,\u001b[39m\n\u001b[31m      storeInfo:{storeName:d.storeName||'',brand:d.brand||'',address:d.address||'',mobile:d.mobile||'',date:d.date||'',city:d.city||'',gpsCoords:d.gpsCoords||null},\u001b[39m\n\u001b[31m      photoGroups:{\u001b[39m\n\u001b[31m        front:    (photoUrls.front   ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.frontPhotos  ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        inside:   (photoUrls.inside  ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.insidePhotos ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        brandings:(photoUrls.brandings||[]).filter(Boolean).map((url,i)=>({url,meta:{type:(d.brandings||[])[i]?.type,w:(d.brandings||[])[i]?.w,h:(d.brandings||[])[i]?.h,qty:(d.brandings||[])[i]?.qty,sqft:(d.brandings||[])[i]?.sqft}})),\u001b[39m\n\u001b[31m        addl:    (photoUrls.addl    ||[]).filter(Boolean).map((url,i)=>({url,desc:(d.addlPhotos  ||[])[i]?.desc||''})),\u001b[39m\n\u001b[31m      },\u001b[39m\n\u001b[31m    })});\u001b[39m\n\u001b[31m    entry.gasAt=new Date().toISOString();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[recce-slides]',e.message);}}\u001b[39m\n\u001b[31m  )();·\u001b[39m\n\u001b[31m  // Step 2 — generate rich HTML report using server URLs, save to VPS\u001b[39m\n\u001b[31m  let view_url = null;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const html  = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m    const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-view', subId: entry.id, html })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (vResp.ok) { const r=await vResp.json(); if(r.success) view_url=r.url; }\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-view] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 3 — upsert to PostgreSQL with photo URLs + view URL\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch(`${_RC_BASE}/submissions`, {\u001b[39m\n\u001b[31m      method: 'POST', headers: _RC_UPSERT,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        sub_id:         entry.id,\u001b[39m\n\u001b[31m        store_name:     d.storeName    || 'Unknown',\u001b[39m\n\u001b[31m        brand:          d.brand        || null,\u001b[39m\n\u001b[31m        client_name:    d.clientName   || null,\u001b[39m\n\u001b[31m        visit_date:     d.date         || new Date().toISOString().slice(0,10),\u001b[39m\n\u001b[31m        address:        d.address      || null,\u001b[39m\n\u001b[31m        mobile:         d.mobile       || null,\u001b[39m\n\u001b[31m        city:           d.city         || null,\u001b[39m\n\u001b[31m        has_branding:   !!(d.brandings?.length),\u001b[39m\n\u001b[31m        branding_count: d.brandings?.length || 0,\u001b[39m\n\u001b[31m        has_video:      !!d.hasVideo,\u001b[39m\n\u001b[31m        front_photos:   d.frontPhotos?.length  || 0,\u001b[39m\n\u001b[31m        inside_photos:  d.insidePhotos?.length || 0,\u001b[39m\n\u001b[31m        addl_photos:    d.addlPhotos?.length   || 0,\u001b[39m\n\u001b[31m        gps_lat:        d.gpsCoords?.lat       || null,\u001b[39m\n\u001b[31m        gps_lng:        d.gpsCoords?.lng       || null,\u001b[39m\n\u001b[31m        submitted_by:   hub.empId              || null,\u001b[39m\n\u001b[31m        submitted_at:   entry.timestamp,\u001b[39m\n\u001b[31m        campaign_id:    entry.campaignId       || null,\u001b[39m\n\u001b[31m        photo_urls:     photoUrls,\u001b[39m\n\u001b[31m        view_url,\u001b[39m\n\u001b[31m        meta: {\u001b[39m\n\u001b[31m          brandings: (d.brandings||[]).map(b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft})),\u001b[39m\n\u001b[31m          videoNote: d.videoNote || null,\u001b[39m\n\u001b[31m          videoCmt:  d.videoCmt  || null,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        status: 'submitted',\u001b[39m\n\u001b[31m        edit_assigned_to: null,\u001b[39m\n\u001b[31m        edit_comment: null,\u001b[39m\n\u001b[31m        edited_at: entry.editedAt || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    return { ok: true, viewUrl: view_url };\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    console.warn('[recce-db] sync error:', e.message);\u001b[39m\n\u001b[31m    return { ok: false, viewUrl: null };\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mconst DEFAULT_ADMIN_HASH='42d372e6110bee134990ac6881c3d5eb568482008add9a859f37f10d759430e8';·\u001b[39m\n\u001b[31masync function saveGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('gas-url',url||DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  toast('Endpoint saved','success');\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function testEndpoint(){\u001b[39m\n\u001b[31m  const url=(await cfg('gas-url'))||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  try{await fetch(url,{method:'POST',mode:'no-cors',body:JSON.stringify({test:true})});toast('Endpoint reachable ✓','success');}\u001b[39m\n\u001b[31m  catch{toast('Cannot reach endpoint','error')}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  cfg('gas-url').then(url=>{\u001b[39m\n\u001b[31m    const u=url||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    // Show last 30 chars only for privacy\u001b[39m\n\u001b[31m    el.textContent='Endpoint: …'+u.slice(-30);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── SLIDES GAS URL ────────────────────────────────────────────\u001b[39m\n\u001b[31masync function saveSlidesGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('slides-gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('slides-gas-url', url);\u001b[39m\n\u001b[31m  toast('Slides GAS URL saved','success');\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function updateSlidesGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('slides-gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  const u=await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  el.textContent=u?'Configured: …'+u.slice(-30):'Not configured';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── MAKE SLIDES ───────────────────────────────────────────────\u001b[39m\n\u001b[31masync function makeSlides(id){\u001b[39m\n\u001b[31m  const gasUrl = await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  if(!gasUrl){\u001b[39m\n\u001b[31m    toast('Configure Slides GAS URL in Settings first','error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const entry = await dbGet('subs', id);\u001b[39m\n\u001b[31m  if(!entry){ toast('Entry not found','error'); return; }\u001b[39m\n\u001b[31m  const d = entry.data;·\u001b[39m\n\u001b[31m  toast('Uploading photos & generating slides…','info');·\u001b[39m\n\u001b[31m  // Build photo groups payload\u001b[39m\n\u001b[31m  const photoGroups = {\u001b[39m\n\u001b[31m    front:    (d.frontPhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64, cmt:p.desc||''})),\u001b[39m\n\u001b[31m    brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||'', meta:{type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft}})),\u001b[39m\n\u001b[31m  };·\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type:       'recce',\u001b[39m\n\u001b[31m        subId:      id,\u001b[39m\n\u001b[31m        gasUrl:     gasUrl,\u001b[39m\n\u001b[31m        storeInfo:  {\u001b[39m\n\u001b[31m          storeName: d.storeName, brand: d.brand,\u001b[39m\n\u001b[31m          date: d.date, address: d.address,\u001b[39m\n\u001b[31m          mobile: d.mobile, gpsCoords: d.gpsCoords,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        photoGroups,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const result = await resp.json();\u001b[39m\n\u001b[31m    if(result.success && result.slideUrl){\u001b[39m\n\u001b[31m      // Store slide URL on the entry\u001b[39m\n\u001b[31m      entry.slideUrl = result.slideUrl;\u001b[39m\n\u001b[31m      await dbPut('subs', entry);\u001b[39m\n\u001b[31m      toast('✅ Slides ready!','success');\u001b[39m\n\u001b[31m      window.open(result.slideUrl, '_blank');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast('Slides error: '+(result.error||'Unknown'),'error');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e){\u001b[39m\n\u001b[31m    toast('Network error: '+e.message,'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN LOGIN ──────────────────────────────────────────────\u001b[39m\n\u001b[31mfunction showAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-error').style.display='none';\u001b[39m\n\u001b[31m  // Restore saved config URL\u001b[39m\n\u001b[31m  cfg('admin-cfg-url').then(u=>{if(u&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=u;});\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('admin-pwd').focus(),100);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveAdminCfgUrl(){\u001b[39m\n\u001b[31m  // Admin cfg URL can be saved without login (needed to set up auth itself)\u001b[39m\n\u001b[31m  // But we warn if saving while unlocked only\u001b[39m\n\u001b[31m  const url=document.getElementById('admin-cfg-url').value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  await cfg('admin-cfg-url',url);\u001b[39m\n\u001b[31m  toast('Config URL saved — will use on next login attempt','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function verifyAdmin(){\u001b[39m\n\u001b[31m  // Hub admins (harish/pramod) are auto-unlocked — no password needed\u001b[39m\n\u001b[31m  if (_adminUnlocked) { adminLoginSuccess(); return; }\u001b[39m\n\u001b[31m  const pwd=document.getElementById('admin-pwd').value;\u001b[39m\n\u001b[31m  if(!pwd){document.getElementById('admin-error').style.display='block';document.getElementById('admin-error').textContent='Enter password';return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('admin-login-btn');btn.disabled=true;btn.textContent='Verifying…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // Try server verification first\u001b[39m\n\u001b[31m    const cfgUrl=(await cfg('admin-cfg-url'))||'';\u001b[39m\n\u001b[31m    if(cfgUrl){\u001b[39m\n\u001b[31m      const r=await fetch(cfgUrl,{cache:'no-store'});\u001b[39m\n\u001b[31m      const j=await r.json();\u001b[39m\n\u001b[31m      // Server JSON format: {\\\"password\\\":\\\"plaintext\\\"} or {\\\"hash\\\":\\\"sha256hash\\\"}\u001b[39m\n\u001b[31m      let match=false;\u001b[39m\n\u001b[31m      if(j.password){match=(j.password===pwd);}\u001b[39m\n\u001b[31m      else if(j.hash){\u001b[39m\n\u001b[31m        // SHA-256 comparison\u001b[39m\n\u001b[31m        const enc=new TextEncoder();\u001b[39m\n\u001b[31m        const data=enc.encode(pwd);\u001b[39m\n\u001b[31m        const hashBuf=await crypto.subtle.digest('SHA-256',data);\u001b[39m\n\u001b[31m        const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m        match=(hashHex===j.hash);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      if(match){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m      else{showAdminError('Incorrect password');return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Fallback: local password stored in settings\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if(localHash){\u001b[39m\n\u001b[31m      const enc=new TextEncoder();\u001b[39m\n\u001b[31m      const hashBuf=await crypto.subtle.digest('SHA-256',enc.encode(pwd));\u001b[39m\n\u001b[31m      const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m      if(hashHex===localHash){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Final fallback: check against hardcoded default hash\u001b[39m\n\u001b[31m    const enc2=new TextEncoder();\u001b[39m\n\u001b[31m    const hb2=await crypto.subtle.digest('SHA-256',enc2.encode(pwd));\u001b[39m\n\u001b[31m    const hh2=Array.from(new Uint8Array(hb2)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    if(hh2===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }catch(err){\u001b[39m\n\u001b[31m    // Network error — try all local fallbacks\u001b[39m\n\u001b[31m    const enc3=new TextEncoder();\u001b[39m\n\u001b[31m    const hb3=await crypto.subtle.digest('SHA-256',enc3.encode(pwd));\u001b[39m\n\u001b[31m    const hh3=Array.from(new Uint8Array(hb3)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if((localHash&&hh3===localHash)||hh3===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }finally{btn.disabled=false;btn.textContent='Login';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showAdminError(msg){\u001b[39m\n\u001b[31m  const el=document.getElementById('admin-error');\u001b[39m\n\u001b[31m  el.textContent=msg;el.style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminLoginSuccess(){\u001b[39m\n\u001b[31m  _adminUnlocked=true;\u001b[39m\n\u001b[31m  closeAdminLogin();\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  cfg('gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  cfg('slides-gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('slides-gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||'';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  toast('Admin mode unlocked','success');\u001b[39m\n\u001b[31m  setTimeout(lockAdmin,10*60*1000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction lockAdmin(){\u001b[39m\n\u001b[31m  _adminUnlocked=false;\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  toast('Admin session ended','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updAvailTag(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-avail-tag');\u001b[39m\n\u001b[31m  const ct=document.getElementById('store-avail-count');\u001b[39m\n\u001b[31m  const txt=stores.length?`${stores.length} stores`:'No store list';\u001b[39m\n\u001b[31m  if(el)el.textContent=txt;\u001b[39m\n\u001b[31m  if(ct)ct.textContent=stores.length?t(`${stores.length} stores available — tap to browse`,`${stores.length} स्टोर उपलब्ध — दबाएं`):t('No store list loaded yet','कोई स्टोर सूची नहीं');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PICKER\u001b[39m\n\u001b[31mfunction openPicker(){\u001b[39m\n\u001b[31m  if(!stores.length){toast('Load a store list in Settings first','error');return;}\u001b[39m\n\u001b[31m  document.getElementById('povl').classList.add('open');\u001b[39m\n\u001b[31m  document.getElementById('psearch').value='';\u001b[39m\n\u001b[31m  filterPicker('');\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('psearch').focus(),150);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closePicker(){document.getElementById('povl').classList.remove('open');}\u001b[39m\n\u001b[31masync function filterPicker(q){\u001b[39m\n\u001b[31m  const list=document.getElementById('plist');\u001b[39m\n\u001b[31m  const words=q.toLowerCase().trim().split(/\\\\s+/).filter(Boolean);\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const lastVisit={};\u001b[39m\n\u001b[31m  subs.forEach(s=>{const nm=s.data?.storeName;if(nm&&(!lastVisit[nm]||s.timestamp>lastVisit[nm]))lastVisit[nm]=s.timestamp;});·\u001b[39m\n\u001b[31m  // Multi-word: ALL words must match somewhere in any field (search across both English and Hindi)\u001b[39m\n\u001b[31m  let fl=stores.filter(s=>{\u001b[39m\n\u001b[31m    if(!words.length)return true;\u001b[39m\n\u001b[31m    const hay=[s.name,s.nameHi,s.address,s.addressHi,s.mobile,s.city,s.cityHi,s.distName,s.distNameHi,s.brand,s.sales,s.proj,s.glowSign,s.inshop]\u001b[39m\n\u001b[31m               .map(x=>(x||'').toLowerCase()).join(' ');\u001b[39m\n\u001b[31m    return words.every(w=>hay.includes(w));\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(fl.length>100)fl=fl.slice(0,100);·\u001b[39m\n\u001b[31m  if(!fl.length){\u001b[39m\n\u001b[31m    const esc=q.replace(/'/g,\\\"\\\\\\\\'\\\");\u001b[39m\n\u001b[31m    list.innerHTML=`<div style=\\\"text-align:center;padding:32px 16px;color:var(--g400);font-size:14px\\\">No stores match \\\"${q}\\\"<br><span style=\\\"font-size:12px\\\">Try fewer or different words</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('${esc}')\\\">+ Add \\\"${q}\\\" as new store</div>`;\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Group by brand (including empty brand)\u001b[39m\n\u001b[31m  const g={};\u001b[39m\n\u001b[31m  fl.forEach(s=>{\u001b[39m\n\u001b[31m    const b=s.brand||'(No Brand — will ask)';\u001b[39m\n\u001b[31m    if(!g[b])g[b]=[];\u001b[39m\n\u001b[31m    g[b].push(s);\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html='';\u001b[39m\n\u001b[31m  Object.keys(g).sort().forEach(br=>{\u001b[39m\n\u001b[31m    html+=`<div class=\\\"psec\\\">${br}</div>`;\u001b[39m\n\u001b[31m    g[br].forEach(s=>{\u001b[39m\n\u001b[31m      const lv=lastVisit[s.name];\u001b[39m\n\u001b[31m      const lvStr=lv?`🕐 Last: ${new Date(lv).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'2-digit'})}`:'';\u001b[39m\n\u001b[31m      const chips=[];\u001b[39m\n\u001b[31m      if(s.glowSign&&s.glowSign.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dcfce7;color:#14532d;padding:2px 6px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m      if(s.inshop&&s.inshop.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dbeafe;color:#1e40af;padding:2px 6px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m      if(s.proj)chips.push(`<span style=\\\"font-size:10px;background:var(--g100);color:var(--g600);padding:2px 6px;border-radius:10px\\\">Target: ${s.proj}</span>`);\u001b[39m\n\u001b[31m      const enc=JSON.stringify(s).replace(/\\\"/g,'&quot;');\u001b[39m\n\u001b[31m      const mapsUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m      const waUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const telUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const dispName=LANG==='hi'&&s.nameHi?s.nameHi:s.name;\u001b[39m\n\u001b[31m      const dispAddr=LANG==='hi'&&s.addressHi?s.addressHi:s.address;\u001b[39m\n\u001b[31m      const dispDist=LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m      html+=`<div class=\\\"pitem\\\" onclick=\\\"pickStore(${enc})\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"pi-name\\\">${dispName}</div>\u001b[39m\n\u001b[31m          ${dispAddr?`<div class=\\\"pi-addr\\\">📍 ${dispAddr}</div>`:''}\u001b[39m\n\u001b[31m          ${s.mobile?`<div class=\\\"pi-addr\\\">📞 ${s.mobile}</div>`:''}\u001b[39m\n\u001b[31m          ${dispDist?`<div class=\\\"pi-addr\\\" style=\\\"color:var(--am)\\\">👤 ${dispDist}</div>`:''}\u001b[39m\n\u001b[31m          ${lvStr?`<div class=\\\"pi-last\\\">${lvStr}</div>`:''}\u001b[39m\n\u001b[31m          ${chips.length?`<div style=\\\"display:flex;gap:4px;flex-wrap:wrap;margin-top:4px\\\">${chips.join('')}</div>`:''}\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;gap:6px;margin-top:7px\\\" onclick=\\\"event.stopPropagation()\\\">\u001b[39m\n\u001b[31m            ${mapsUrl?`<a href=\\\"${mapsUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#e0f2fe;color:#0369a1;border-radius:20px;text-decoration:none;font-weight:600\\\">🗺 Maps</a>`:''}\u001b[39m\n\u001b[31m            ${waUrl?`<a href=\\\"${waUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#dcfce7;color:#15803d;border-radius:20px;text-decoration:none;font-weight:600\\\">💬 WhatsApp</a>`:''}\u001b[39m\n\u001b[31m            ${telUrl?`<a href=\\\"${telUrl}\\\" style=\\\"font-size:11px;padding:4px 10px;background:#f0fdf4;color:#166534;border-radius:20px;text-decoration:none;font-weight:600\\\">📞 Call</a>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        ${s.brand?`<div class=\\\"pi-brand\\\">${s.brand}</div>`:'<div class=\\\"pi-brand\\\" style=\\\"background:var(--rd)\\\">?</div>'}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html+=`<div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('')\\\">+ Not in list? Add new store</div>`;\u001b[39m\n\u001b[31m  list.innerHTML=html;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function pickStore(s){\u001b[39m\n\u001b[31m  selectedStore=s;manualMode=false;closePicker();\u001b[39m\n\u001b[31m  const _dn =LANG==='hi'&&s.nameHi    ?s.nameHi    :s.name;\u001b[39m\n\u001b[31m  const _da =LANG==='hi'&&s.addressHi ?s.addressHi :s.address;\u001b[39m\n\u001b[31m  const _dd =LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m  const _dc =LANG==='hi'&&s.cityHi    ?s.cityHi    :s.city;\u001b[39m\n\u001b[31m  document.getElementById('sc-name').textContent=_dn;\u001b[39m\n\u001b[31m  const brandEl=document.getElementById('sc-brand');\u001b[39m\n\u001b[31m  brandEl.textContent=s.brand||'No Brand';brandEl.style.background=s.brand?'var(--nv)':'var(--rd)';\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const prev=subs.filter(x=>x.data?.storeName===s.name).sort((a,b)=>new Date(b.timestamp)-new Date(a.timestamp))[0];\u001b[39m\n\u001b[31m  const lc=document.getElementById('sc-last');\u001b[39m\n\u001b[31m  if(prev){const d=new Date(prev.timestamp);lc.textContent='Last: '+d.toLocaleDateString('en-IN',{day:'numeric',month:'short'});lc.style.display='inline-flex';}\u001b[39m\n\u001b[31m  else lc.style.display='none';\u001b[39m\n\u001b[31m  // All Excel fields — display in active language\u001b[39m\n\u001b[31m  const mUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m  const wUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const tUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const details=[];\u001b[39m\n\u001b[31m  if(_da)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📍 ${_da}${mUrl?` <a href=\\\"${mUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#0369a1;margin-left:6px\\\">🗺 Navigate</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(s.mobile)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📞 ${s.mobile}${tUrl?` <a href=\\\"${tUrl}\\\" style=\\\"font-size:11px;color:#166534;margin-left:6px\\\">Call</a>`:''}${wUrl?` <a href=\\\"${wUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#15803d;margin-left:6px\\\">WhatsApp</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(_dd)details.push(`<div style=\\\"font-size:12px;color:var(--am)\\\">👤 ${_dd}</div>`);\u001b[39m\n\u001b[31m  if(_dc)details.push(`<div style=\\\"font-size:12px;color:var(--g500)\\\">🏙 ${_dc}</div>`);\u001b[39m\n\u001b[31m  const opp=[];\u001b[39m\n\u001b[31m  if(s.glowSign&&s.glowSign.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dcfce7;color:#14532d;padding:2px 7px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m  if(s.inshop&&s.inshop.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dbeafe;color:#1e40af;padding:2px 7px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m  if(s.proj)opp.push(`<span style=\\\"font-size:11px;background:var(--g100);color:var(--g600);padding:2px 7px;border-radius:10px\\\">Target 2026: ${s.proj}</span>`);\u001b[39m\n\u001b[31m  if(opp.length)details.push(`<div style=\\\"display:flex;gap:5px;flex-wrap:wrap;margin-top:3px\\\">${opp.join('')}</div>`);\u001b[39m\n\u001b[31m  document.getElementById('sc-details').innerHTML=details.join('');\u001b[39m\n\u001b[31m  // Missing fields\u001b[39m\n\u001b[31m  const missing=[];\u001b[39m\n\u001b[31m  if(!s.address)missing.push({key:'address',label:'Store Address',type:'textarea',placeholder:'Full address'});\u001b[39m\n\u001b[31m  if(!s.mobile)missing.push({key:'mobile',label:'Mobile No.',type:'tel',placeholder:'10-digit number',maxlen:'10'});\u001b[39m\n\u001b[31m  const mw=document.getElementById('sc-missing'),mf=document.getElementById('sc-missing-fields');\u001b[39m\n\u001b[31m  if(missing.length){\u001b[39m\n\u001b[31m    mf.innerHTML=missing.map(m=>`<div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\"><label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">${m.label} <span class=\\\"req\\\">*</span></label>${m.type==='textarea'?`<textarea id=\\\"sc-miss-${m.key}\\\" rows=\\\"2\\\" placeholder=\\\"${m.placeholder}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></textarea>`:`<input type=\\\"${m.type}\\\" id=\\\"sc-miss-${m.key}\\\" placeholder=\\\"${m.placeholder}\\\" ${m.maxlen?`maxlength=\\\"${m.maxlen}\\\"`:''}  inputmode=\\\"${m.type==='tel'?'numeric':'text'}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\">`}</div>`).join('');\u001b[39m\n\u001b[31m    mw.style.display='block';\u001b[39m\n\u001b[31m  } else {mw.style.display='none';}\u001b[39m\n\u001b[31m  // Brand selector\u001b[39m\n\u001b[31m  const bSel=document.getElementById('brand-selector'),bChips=document.getElementById('brand-chips');\u001b[39m\n\u001b[31m  if(!s.brand){\u001b[39m\n\u001b[31m    renderBrandChips();\u001b[39m\n\u001b[31m    bSel.style.display='block';\u001b[39m\n\u001b[31m  } else {bSel.style.display='none';}\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  F.storeName=s.name;F.brand=s.brand||'';F.address=s.address||'';F.mobile=s.mobile||'';\u001b[39m\n\u001b[31m  if(s.brand&&!_selectedClient&&!_clientOtherMode) autoSetClient(s.brand);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateMissingField(key,val){if(!selectedStore)return;selectedStore[key]=val.trim();F[key]=val.trim();saveDraft();}\u001b[39m\n\u001b[31mfunction selectStoreBrand(b){\u001b[39m\n\u001b[31m  F.brand=b;F.brandLogoUrl=_brandLogos[b]||'';\u001b[39m\n\u001b[31m  if(selectedStore)selectedStore.brand=b;\u001b[39m\n\u001b[31m  const el=document.getElementById('sc-brand');if(el){el.textContent=b;el.style.background='var(--nv)';}\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-chips .chip').forEach(c=>{c.classList.toggle('sel',c.querySelector('span')?.textContent===b||c.textContent.trim()===b);});\u001b[39m\n\u001b[31m  if(!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction onManualBrandChange(){\u001b[39m\n\u001b[31m  const b=document.getElementById('f-brand')?.value||'';\u001b[39m\n\u001b[31m  F.brandLogoUrl=b?(_brandLogos[b]||''):'';\u001b[39m\n\u001b[31m  if(b&&!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction openManual(prefill){\u001b[39m\n\u001b[31m  manualMode=true;\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').classList.add('on');\u001b[39m\n\u001b[31m  document.getElementById('mt-label').innerHTML='← Back to store list';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='block';\u001b[39m\n\u001b[31m  // Pre-fill from selectedStore if available (e.g. when toggling after picker selection)\u001b[39m\n\u001b[31m  const s=selectedStore;\u001b[39m\n\u001b[31m  if(s){\u001b[39m\n\u001b[31m    if(document.getElementById('f-brand'))document.getElementById('f-brand').value=s.brand||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-store'))document.getElementById('f-store').value=s.name||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-addr'))document.getElementById('f-addr').value=s.address||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-mobile'))document.getElementById('f-mobile').value=s.mobile||'';\u001b[39m\n\u001b[31m  } else if(prefill){\u001b[39m\n\u001b[31m    document.getElementById('f-store').value=prefill;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  selectedStore=null;\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction toggleManual(){\u001b[39m\n\u001b[31m  if(manualMode){\u001b[39m\n\u001b[31m    manualMode=false;\u001b[39m\n\u001b[31m    document.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31m    document.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31m    document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    openManual('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// GPS\u001b[39m\n\u001b[31mfunction captureGPS(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gps-status');el.textContent='Getting location…';el.style.color='var(--g500)';\u001b[39m\n\u001b[31m  if(!navigator.geolocation){el.textContent='GPS not available';return;}\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(pos=>{\u001b[39m\n\u001b[31m    gpsCoords={lat:pos.coords.latitude.toFixed(6),lng:pos.coords.longitude.toFixed(6),acc:Math.round(pos.coords.accuracy)};\u001b[39m\n\u001b[31m    el.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${gpsCoords.acc}m)`;el.style.color='var(--gn)';saveDraft();\u001b[39m\n\u001b[31m  },()=>{el.textContent='GPS failed — enter address manually';el.style.color='var(--rd)';},{enableHighAccuracy:true,timeout:10000});\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// DRAFT\u001b[39m\n\u001b[31mlet draftT;\u001b[39m\n\u001b[31mfunction saveDraft(){\u001b[39m\n\u001b[31m  clearTimeout(draftT);\u001b[39m\n\u001b[31m  draftT=setTimeout(async()=>{\u001b[39m\n\u001b[31m    const draft={k:'current',ts:Date.now(),F:{...F,date:document.getElementById('f-date')?.value||'',brand:manualMode?(document.getElementById('f-brand')?.value||''):(selectedStore?.brand||F.brand||''),storeName:selectedStore?selectedStore.name:(document.getElementById('f-store')?.value||''),address:manualMode?(document.getElementById('f-addr')?.value||''):(selectedStore?.address||F.address||''),mobile:manualMode?(document.getElementById('f-mobile')?.value||''):(selectedStore?.mobile||F.mobile||''),clientName:getClientName()},selectedStore,manualMode,gpsCoords,_selectedClient,_clientOtherMode,fCnt:frontPhotos.length,iCnt:insidePhotos.length,bCnt:brandings.length};\u001b[39m\n\u001b[31m    await dbPut('draft',draft);\u001b[39m\n\u001b[31m    // Also save photos as b64 blobs to draft so they survive exit\u001b[39m\n\u001b[31m    await saveDraftPhotos();\u001b[39m\n\u001b[31m  },500);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveDraftPhotos(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const photoData={\u001b[39m\n\u001b[31m      front:await Promise.all(frontPhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      inside:await Promise.all(insidePhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      addl:await Promise.all(addlPhotos.map(async p=>({b64:await b64(p.blob),desc:p.desc||''}))),\u001b[39m\n\u001b[31m      brand:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,b64:b.blob?await b64(b.blob):null})))\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    await dbPut('draft',{k:'photos',...photoData});\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function checkDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');const wrap=document.getElementById('resume-wrap');\u001b[39m\n\u001b[31m  if(!d||!d.F?.storeName){wrap.innerHTML='';return;}\u001b[39m\n\u001b[31m  const ago=Math.round((Date.now()-d.ts)/60000);\u001b[39m\n\u001b[31m  const agoStr=ago<1?'just now':ago<60?`${ago}m ago`:`${Math.round(ago/60)}h ago`;\u001b[39m\n\u001b[31m  wrap.innerHTML=`<button class=\\\"resume-btn\\\" onclick=\\\"resumeDraft()\\\">\u001b[39m\n\u001b[31m    <div><div style=\\\"font-size:12px;color:rgba(255,255,255,.5);margin-bottom:3px\\\">Resume draft · ${agoStr}</div><div>${d.F.storeName} · ${d.F.brand||'No brand'}</div></div>\u001b[39m\n\u001b[31m    <div style=\\\"text-align:right\\\"><div style=\\\"font-size:13px;color:var(--or)\\\">${d.fCnt||0} photos · ${d.bCnt||0} brandings →</div></div>\u001b[39m\n\u001b[31m  </button>`;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function resumeDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');if(!d)return;\u001b[39m\n\u001b[31m  F=d.F||{};gpsCoords=d.gpsCoords||null;\u001b[39m\n\u001b[31m  if(d.selectedStore){await pickStore(d.selectedStore);}\u001b[39m\n\u001b[31m  else if(d.manualMode){openManual('');if(F.brand)document.getElementById('f-brand').value=F.brand;if(F.storeName)document.getElementById('f-store').value=F.storeName;if(F.address)document.getElementById('f-addr').value=F.address;if(F.mobile)document.getElementById('f-mobile').value=F.mobile;}\u001b[39m\n\u001b[31m  if(F.date)document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  // Restore client chip state\u001b[39m\n\u001b[31m  if(d._clientOtherMode){_clientOtherMode=true;_selectedClient='';const inp=document.getElementById('f-client-other');if(inp&&F.clientName)inp.value=F.clientName;}\u001b[39m\n\u001b[31m  else if(d._selectedClient){_selectedClient=d._selectedClient;_clientOtherMode=false;}\u001b[39m\n\u001b[31m  else if(F.clientName){autoSetClient(F.clientName);}\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  // Restore photos from draft\u001b[39m\n\u001b[31m  const pd=await dbGet('draft','photos');\u001b[39m\n\u001b[31m  if(pd){\u001b[39m\n\u001b[31m    async function b64ToBlob(b64str){if(!b64str)return null;try{const r=await fetch(b64str);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m    for(const p of(pd.front||[])){const bl=await b64ToBlob(p.b64);if(bl)frontPhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.inside||[])){const bl=await b64ToBlob(p.b64);if(bl)insidePhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.addl||[])){const bl=await b64ToBlob(p.b64);if(bl)addlPhotos.push({blob:bl,prev:URL.createObjectURL(bl),desc:p.desc||''});}\u001b[39m\n\u001b[31m    for(const b of(pd.brand||[])){const bl=await b64ToBlob(b.b64);brandings.push({type:b.type,w:b.w,h:b.h,qty:b.qty,blob:bl,prev:bl?URL.createObjectURL(bl):null});}\u001b[39m\n\u001b[31m    toast('Draft restored with '+frontPhotos.length+' photos ✓','success');\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    toast('Draft restored — photos could not be recovered','info');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PHOTOS\u001b[39m\n\u001b[31mfunction updPhotoBadge(type){const arr=type==='front'?frontPhotos:insidePhotos;const el=document.getElementById(type+'-badge');if(el){el.textContent=arr.length;el.className='cnt-badge '+(arr.length?'':'gray');}}\u001b[39m\n\u001b[31mfunction renderPhotos(type){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  const cont=document.getElementById(type+'-cont');const addBtn=document.getElementById('add-'+type);\u001b[39m\n\u001b[31m  updPhotoBadge(type);\u001b[39m\n\u001b[31m  if(arr.length===0){cont.innerHTML=`<div class=\\\"pslot\\\" onclick=\\\"addPhoto('${type}')\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to capture or upload</span><span class=\\\"hi-txt\\\">फोटो खींचें या अपलोड करें</span></div></div>`;addBtn.style.display='none';return;}\u001b[39m\n\u001b[31m  cont.innerHTML=arr.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const badge=isRetained?`<span class=\\\"pbadge\\\" style=\\\"background:#475569\\\">Existing</span>`:`<span class=\\\"pbadge\\\">${fmtSz(p.blob.size)}</span>`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replacePhoto('${type}',${i})\\\" style=\\\"right:36px;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"margin-bottom:12px\\\"><div class=\\\"pslot filled\\\" style=\\\"margin-bottom:8px\\\"><img src=\\\"${p.prev}\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmPhoto('${type}',${i})\\\">×</button>${badge}</div><input type=\\\"text\\\" placeholder=\\\"Comments (optional)\\\" value=\\\"${p.cmt||''}\\\" onchange=\\\"${type==='front'?'frontPhotos':'insidePhotos'}[${i}].cmt=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  addBtn.style.display=arr.length<(type==='inside'?5:3)?'inline-flex':'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// Photo source: 'camera' stamps geo, 'gallery' does not\u001b[39m\n\u001b[31mlet _photoSourceCb=null,_photoSourceQuality=null;·\u001b[39m\n\u001b[31mfunction capPhoto(cb,forceSource,quality){\u001b[39m\n\u001b[31m  // quality override: null=use setting, 'hd', 'compressed'\u001b[39m\n\u001b[31m  _photoSourceCb=cb;_photoSourceQuality=quality||null;\u001b[39m\n\u001b[31m  if(forceSource==='camera'){_doCapture(cb,'camera',quality);return;}\u001b[39m\n\u001b[31m  if(forceSource==='gallery'){_doCapture(cb,'gallery',quality);return;}\u001b[39m\n\u001b[31m  // Show picker\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _doCapture(cb,src,quality){\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  const i=document.createElement('input');\u001b[39m\n\u001b[31m  i.type='file';i.accept='image/*';\u001b[39m\n\u001b[31m  if(src==='camera')i.setAttribute('capture','environment');\u001b[39m\n\u001b[31m  i.style.display='none';\u001b[39m\n\u001b[31m  i.onchange=async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f)return;\u001b[39m\n\u001b[31m    const q=quality||_photoSourceQuality||null;\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      const blob=await compress(f,q==='hd'?1920:q==='compressed'?1280:null,q==='hd'?0.90:q==='compressed'?0.78:null);\u001b[39m\n\u001b[31m      // Only stamp if from camera (live photo)\u001b[39m\n\u001b[31m      const stamped=(src==='camera')?await stampPhoto(blob):blob;\u001b[39m\n\u001b[31m      // Save to device (auto-download trigger)\u001b[39m\n\u001b[31m      savePhotoToDevice(stamped);\u001b[39m\n\u001b[31m      cb({target:{files:[f]},_blob:stamped,_src:src});\u001b[39m\n\u001b[31m    }catch(err){toast('Photo processing failed — try again','error');console.error('_doCapture error:',err);}\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  document.body.appendChild(i);i.click();setTimeout(()=>i.remove(),8000);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction photoSrcCamera(){_doCapture(_photoSourceCb,'camera',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcGallery(){_doCapture(_photoSourceCb,'gallery',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcCancel(){document.getElementById('photo-src-dialog').classList.remove('open');_photoSourceCb=null;}·\u001b[39m\n\u001b[31m// Save photo to device gallery/downloads\u001b[39m\n\u001b[31mfunction savePhotoToDevice(blob){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    const a=document.createElement('a');\u001b[39m\n\u001b[31m    a.href=url;\u001b[39m\n\u001b[31m    a.download='Recce_'+Date.now()+'.jpg';\u001b[39m\n\u001b[31m    a.style.display='none';\u001b[39m\n\u001b[31m    document.body.appendChild(a);a.click();\u001b[39m\n\u001b[31m    setTimeout(()=>{URL.revokeObjectURL(url);a.remove();},1000);\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addPhoto(type){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}${e._src==='camera'&&geoStampEnabled?' · Stamped':''}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31masync function handleCapture(e,type){\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmPhoto(type,i){(type==='front'?frontPhotos:insidePhotos).splice(i,1);renderPhotos(type);saveDraft();}\u001b[39m\n\u001b[31mfunction replacePhoto(type,idx){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m    arr[idx]={...arr[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAddl(){\u001b[39m\n\u001b[31m  const cont=document.getElementById('add-cont');const btn=document.getElementById('add-addl');\u001b[39m\n\u001b[31m  const badge=document.getElementById('addl-badge');if(badge){badge.textContent=`${addlPhotos.length} / 8`;badge.className='cnt-badge '+(addlPhotos.length?'':'gray');}\u001b[39m\n\u001b[31m  cont.innerHTML=addlPhotos.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const sizeInfo=isRetained?'<span style=\\\"color:#475569\\\">Existing</span>':`${fmtSz(p.blob.size)}`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replaceAddl(${i})\\\" style=\\\"top:3px;left:3px;right:auto;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;gap:10px;align-items:start;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--g100)\\\"><div style=\\\"position:relative;flex-shrink:0\\\"><img src=\\\"${p.prev}\\\" style=\\\"width:80px;height:80px;object-fit:cover;border-radius:var(--rs)\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmAddl(${i})\\\" style=\\\"top:3px;right:3px\\\">×</button></div><div style=\\\"flex:1\\\"><input type=\\\"text\\\" placeholder=\\\"Description (optional)\\\" value=\\\"${p.desc||''}\\\" onchange=\\\"addlPhotos[${i}].desc=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"><div style=\\\"font-size:11px;color:var(--g400);margin-top:4px\\\">${sizeInfo}</div></div></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  btn.style.display=addlPhotos.length>=8?'none':'inline-flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction addAdditional(){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  addlPhotos.push({blob:bs,prev:URL.createObjectURL(bs),desc:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderAddl();saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31mfunction rmAddl(i){addlPhotos.splice(i,1);renderAddl();saveDraft();}\u001b[39m\n\u001b[31mfunction replaceAddl(idx){\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m    addlPhotos[idx]={...addlPhotos[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderAddl();saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// BRANDING\u001b[39m\n\u001b[31mfunction calcSqft(w,h){const wf=parseFloat(w),hf=parseFloat(h);if(!wf||!hf)return '';return `${(wf*hf).toFixed(0)} sq.in = ${(wf*hf/144).toFixed(2)} sq.ft`;}\u001b[39m\n\u001b[31mfunction renderBrandings(){\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  const cont=document.getElementById('br-items');\u001b[39m\n\u001b[31m  const hb=document.getElementById('br-hdr-badge');if(hb)hb.textContent=`${brandings.length} ${t(brandings.length!==1?'items':'item',brandings.length!==1?'आइटम':'आइटम')}`;\u001b[39m\n\u001b[31m  cont.innerHTML=brandings.map((b,i)=>`<div class=\\\"bitem\\\"><div class=\\\"bitem-hdr\\\"><div class=\\\"bitem-title\\\">${t('Branding','ब्रांडिंग')} ${i+1}${b.type?' — '+b.type:''}</div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:6px\\\">${i>0?`<button class=\\\"btn-d\\\" onclick=\\\"dupBr(${i})\\\" style=\\\"color:var(--or);border-color:var(--orl)\\\">${t('Dup ↑','डुप ↑')}</button>`:''}<button class=\\\"btn-d\\\" onclick=\\\"rmBr(${i})\\\">${t('Remove','हटाएं')}</button></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\"><label>${t('Type','प्रकार')} <span class=\\\"req\\\">*</span></label><div class=\\\"chip-grid\\\">${BTYPE.map(tp=>`<div class=\\\"chip${b.type===tp?' sel':''}\\\" onclick=\\\"setBType(${i},'${tp.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\"> ${tp}</div>`).join('')}</div></div>\u001b[39m\n\u001b[31m    <div class=\\\"dim-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Width (in)','चौड़ाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.w||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].w=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Height (in)','ऊंचाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.h||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].h=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"max-width:74px\\\"><label>${t('Qty','मात्रा')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.qty||''}\\\" placeholder=\\\"1\\\" inputmode=\\\"numeric\\\" onchange=\\\"brandings[${i}].qty=this.value;saveDraft()\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <span class=\\\"sqft\\\" id=\\\"sf${i}\\\">${calcSqft(b.w,b.h)||t('Enter W × H','W × H दर्ज करें')}</span>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-top:12px\\\"><label>${t('Photo','फोटो')} <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      ${b.prev?`<div class=\\\"pslot filled\\\" onclick=\\\"capBr(${i})\\\"><img src=\\\"${b.prev}\\\"><button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();rmBrPh(${i})\\\">×</button><span class=\\\"pbadge\\\">${b.blob?fmtSz(b.blob.size):'Existing'}</span></div>`:`<div><div class=\\\"pslot\\\" onclick=\\\"capBr(${i})\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\">${t('Tap to capture','दबाकर कैप्चर करें')}</div></div><div style=\\\"display:flex;gap:6px;margin-top:6px\\\"><button class=\\\"atool${(b.quality||imgQuality)==='compressed'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'compressed');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">${t('Compressed','कम्प्रेस्ड')}</button><button class=\\\"atool${(b.quality||imgQuality)==='hd'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'hd');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">HD</button></div></div>`}\u001b[39m\n\u001b[31m    </div></div>`).join('');\u001b[39m\n\u001b[31m  // Only show \\\"Add Another\\\" when last item is fully complete\u001b[39m\n\u001b[31m  const addDiv=document.getElementById('br-add');\u001b[39m\n\u001b[31m  if(addDiv&&brandings.length>0){\u001b[39m\n\u001b[31m    const last=brandings[brandings.length-1];\u001b[39m\n\u001b[31m    const lastComplete=last.type&&last.w&&last.h&&last.qty&&last.prev;\u001b[39m\n\u001b[31m    addDiv.style.display=(lastComplete&&brandings.length<15)?'block':'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updSqft(i){const el=document.getElementById('sf'+i);if(el)el.textContent=calcSqft(brandings[i].w,brandings[i].h)||t('Enter W × H','W × H दर्ज करें');saveDraft();}\u001b[39m\n\u001b[31mfunction setBType(i,tp){brandings[i].type=tp;renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction addBranding(){if(brandings.length>=15){toast(t('Max 15 items','अधिकतम 15 आइटम'),'error');return;}brandings.push({type:'',w:'',h:'',qty:'1',blob:null,prev:null});renderBrandings();}\u001b[39m\n\u001b[31mfunction dupBr(i){if(brandings.length>=10){toast(t('Max 10 items','अधिकतम 10 आइटम'),'error');return;}const s=brandings[i-1];brandings.splice(i,0,{type:s.type,w:s.w,h:s.h,qty:s.qty,blob:null,prev:null});renderBrandings();toast(t('Duplicated — add photo','डुप्लीकेट — फोटो जोड़ें'),'info');}\u001b[39m\n\u001b[31mfunction rmBr(i){brandings.splice(i,1);renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction capBr(i){\u001b[39m\n\u001b[31m  const q=brandings[i]?.quality||imgQuality;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f,q==='hd'?1920:1280,q==='hd'?0.90:0.78));\u001b[39m\n\u001b[31m    brandings[i].blob=bs;brandings[i].prev=URL.createObjectURL(bs);\u001b[39m\n\u001b[31m    brandings[i].fromCamera=(e._src==='camera');\u001b[39m\n\u001b[31m    openAnnot(i);\u001b[39m\n\u001b[31m  },null,q);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmBrPh(i){brandings[i].blob=null;brandings[i].prev=null;renderBrandings();}\u001b[39m\n\u001b[31mfunction setBrQuality(i,q){brandings[i].quality=q;renderBrandings();}·\u001b[39m\n\u001b[31m// VIDEO / DOC\u001b[39m\n\u001b[31mfunction setVideo(v){F.hasVideo=v;document.getElementById('vid-yes').classList.toggle('sel',v);document.getElementById('vid-no').classList.toggle('sel',!v);document.getElementById('vid-sec').style.display=v?'block':'none';saveDraft();}\u001b[39m\n\u001b[31masync function handleVideo(e){videoBlob=e.target.files[0];if(!videoBlob)return;document.getElementById('vid-slot').innerHTML=`<div style=\\\"padding:14px;font-size:13px;color:var(--gn)\\\">✓ ${videoBlob.name} (${fmtSz(videoBlob.size)})</div>`;}\u001b[39m\n\u001b[31mfunction setBranding(v){F.hasBranding=v;document.getElementById('br-yes').classList.toggle('sel',v);document.getElementById('br-no').classList.toggle('sel',!v);document.getElementById('br-add').style.display=v?'block':'none';if(v&&brandings.length===0)addBranding();saveDraft();}\u001b[39m\n\u001b[31masync function handleDoc(e){const f=e.target.files[0];if(!f)return;submissionDoc=f.type.startsWith('image/')?await compress(f,1600,.85):f;const slot=document.getElementById('doc-slot');if(f.type.startsWith('image/')){slot.classList.add('filled');slot.innerHTML=`<img src=\\\"${URL.createObjectURL(submissionDoc)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}else{slot.innerHTML=`<div style=\\\"padding:16px;font-size:13px;color:var(--gn)\\\">✓ ${f.name} (${fmtSz(f.size)})</div>`;}buildReview();}·\u001b[39m\n\u001b[31m// CLIENT CHIPS\u001b[39m\n\u001b[31mfunction renderClientChips(){\u001b[39m\n\u001b[31m  const grid = document.getElementById('client-chips'); if (!grid) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  clientList.forEach(c => {\u001b[39m\n\u001b[31m    const sel = !_clientOtherMode && _selectedClient === c;\u001b[39m\n\u001b[31m    html += `<div class=\\\"cl-chip${sel?' sel':''}\\\" onclick=\\\"selectClientChip('${esc(c)}')\\\">${esc(c)}</div>`;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html += `<div class=\\\"cl-chip cl-chip-other${_clientOtherMode?' sel':''}\\\" onclick=\\\"selectClientOther()\\\"><span class=\\\"en-txt\\\">Other…</span><span class=\\\"hi-txt\\\">अन्य…</span></div>`;\u001b[39m\n\u001b[31m  grid.innerHTML = html;\u001b[39m\n\u001b[31m  document.getElementById('client-other-wrap').style.display = _clientOtherMode ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientChip(name){\u001b[39m\n\u001b[31m  _selectedClient = name; _clientOtherMode = false;\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').value = '';\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientOther(){\u001b[39m\n\u001b[31m  _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onClientOtherInput(){\u001b[39m\n\u001b[31m  _selectedClient = document.getElementById('f-client-other').value.trim();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction getClientName(){\u001b[39m\n\u001b[31m  if (_clientOtherMode) return (document.getElementById('f-client-other')?.value||'').trim();\u001b[39m\n\u001b[31m  return _selectedClient;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction autoSetClient(brandName){\u001b[39m\n\u001b[31m  if (!brandName) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  if (clientList.includes(brandName)){\u001b[39m\n\u001b[31m    _selectedClient = brandName; _clientOtherMode = false;\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    // Not in list — pre-fill the Other field\u001b[39m\n\u001b[31m    _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m    const inp = document.getElementById('f-client-other');\u001b[39m\n\u001b[31m    if (inp && !inp.value) inp.value = brandName;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// STEP VALIDATION\u001b[39m\n\u001b[31mfunction getSD(){if(selectedStore&&!manualMode)return{storeName:selectedStore.name,brand:selectedStore.brand||'',address:selectedStore.address||'',mobile:selectedStore.mobile||''};return{storeName:(document.getElementById('f-store')?.value||'').trim(),brand:document.getElementById('f-brand')?.value||'',address:(document.getElementById('f-addr')?.value||'').trim(),mobile:(document.getElementById('f-mobile')?.value||'').trim()};}\u001b[39m\n\u001b[31mfunction step2(){\u001b[39m\n\u001b[31m  const d=document.getElementById('f-date').value;\u001b[39m\n\u001b[31m  if(!d){toast('Select date','error');return;}\u001b[39m\n\u001b[31m  const sd=getSD();\u001b[39m\n\u001b[31m  if(!sd.storeName){toast('Select or enter store name','error');return;}\u001b[39m\n\u001b[31m  if(!sd.brand){toast('Select a brand','error');document.getElementById('brand-selector').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  if(!sd.address){toast('Enter store address','error');return;}\u001b[39m\n\u001b[31m  const clientName=getClientName();\u001b[39m\n\u001b[31m  if(!clientName){toast(t('Select a client','क्लाइंट चुनें'),'error');document.getElementById('client-chips').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  // Check missing fields filled\u001b[39m\n\u001b[31m  const missAddr=document.getElementById('sc-miss-address');\u001b[39m\n\u001b[31m  if(missAddr&&!missAddr.value.trim()){toast('Enter store address in the highlighted field','error');missAddr.focus();return;}\u001b[39m\n\u001b[31m  const missMob=document.getElementById('sc-miss-mobile');\u001b[39m\n\u001b[31m  // mobile not required — just copy if filled\u001b[39m\n\u001b[31m  if(missMob&&missMob.value.trim()&&!F.mobile)F.mobile=missMob.value.trim();\u001b[39m\n\u001b[31m  Object.assign(F,{date:d,...sd,clientName});saveDraft();\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');showView('form-photos');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction step3(){if(!frontPhotos.length){toast('Add at least 1 front view photo','error');return;}showView('form-video');}\u001b[39m\n\u001b[31mfunction step4(){if(F.hasVideo===undefined||F.hasVideo===null){toast('Select Yes or No for video','error');return;}renderBrandings();showView('form-branding');}\u001b[39m\n\u001b[31mfunction step5(){if(F.hasBranding===undefined||F.hasBranding===null){toast('Select Yes or No for branding space','error');return;}if(F.hasBranding){for(let i=0;i<brandings.length;i++){const b=brandings[i];if(!b.type){toast(`Select branding type for item ${i+1}`,'error');return;}if(!b.w||!b.h){toast(`Enter W and H dimensions for item ${i+1}`,'error');return;}if(!b.qty){toast(`Enter qty for item ${i+1}`,'error');return;}if(!b.blob&&!b.prev){toast(`Add photo for item ${i+1}`,'error');return;}}}renderAddl();buildReview();showView('form-additional');}·\u001b[39m\n\u001b[31m// REVIEW\u001b[39m\n\u001b[31mfunction buildReview(){const el=document.getElementById('rev-body');if(!el)return;const sd=getSD();const cn=getClientName();el.innerHTML=`<div><div class=\\\"rev-lbl\\\">Store</div><div class=\\\"rev-val\\\">${sd.storeName||'—'} · ${sd.brand||'—'}</div><div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">${sd.address||'—'}${sd.mobile?' · '+sd.mobile:''}</div>${gpsCoords?`<div style=\\\"font-size:11px;color:var(--gn);margin-top:3px\\\">📍 ${gpsCoords.lat}, ${gpsCoords.lng} ±${gpsCoords.acc}m</div>`:''}</div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Client</div><div class=\\\"rev-val\\\" style=\\\"color:${cn?'var(--nv)':'var(--rd)'}\\\">${cn||'⚠ Not selected — required'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Photos — Front · Inside · Additional</div><div class=\\\"rev-val\\\">${frontPhotos.length} · ${insidePhotos.length} · ${addlPhotos.length}</div><div class=\\\"rev-photos\\\">${[...frontPhotos,...insidePhotos].slice(0,6).map(p=>`<img class=\\\"rev-thumb\\\" src=\\\"${p.prev}\\\">`).join('')}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Video · Branding items</div><div class=\\\"rev-val\\\">${F.hasVideo?'Yes':'No'} · ${brandings.length} item(s)</div></div>${F.hasBranding&&brandings.length?`<div style=\\\"margin-top:8px\\\">${brandings.map((b,i)=>`<div style=\\\"font-size:12px;color:var(--g600);padding:4px 0;border-bottom:1px solid var(--g100)\\\">${i+1}. ${b.type||'No type'} — ${b.w||'?'}×${b.h||'?'}\\\" × ${b.qty||'?'} — ${calcSqft(b.w,b.h)||'?'}</div>`).join('')}</div>`:''}<div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Additional photos <span style=\\\"font-size:11px;color:var(--g400)\\\">(optional)</span></div><div class=\\\"rev-val\\\" style=\\\"color:${addlPhotos.length?'var(--gn)':'var(--g500)'}\\\">${addlPhotos.length?`✓ ${addlPhotos.length} photo(s) added`:'None added'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Mandatory document</div><div class=\\\"rev-val\\\" style=\\\"color:${(submissionDoc||_docExistingUrl)?'var(--gn)':'var(--rd)'}\\\">${(submissionDoc||_docExistingUrl)?'✓ Uploaded':'⚠ Missing — required'}</div></div>`;}·\u001b[39m\n\u001b[31m// SUBMIT\u001b[39m\n\u001b[31masync function submitRecce(){\u001b[39m\n\u001b[31m  if(!submissionDoc&&!_docExistingUrl){toast('Upload mandatory doc first','error');return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('sub-btn');btn.disabled=true;btn.textContent='Saving…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const isEdit=!!(F.editingId);\u001b[39m\n\u001b[31m    const id=isEdit?F.editingId:('RC_'+Date.now()+'_'+Math.random().toString(36).slice(2,6).toUpperCase());\u001b[39m\n\u001b[31m    const sd=getSD();\u001b[39m\n\u001b[31m    const _hub=_recceHubUser();\u001b[39m\n\u001b[31m    const entry={id,timestamp:isEdit?(await dbGet('subs',id))?.timestamp||new Date().toISOString():new Date().toISOString(),editedAt:isEdit?new Date().toISOString():undefined,status:'pending',submittedBy:_hub.empId||null,submittedByName:_hub.name||null,data:{...F,...sd,gpsCoords,frontPhotos:await Promise.all(frontPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),insidePhotos:await Promise.all(insidePhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),videoNote:F.hasVideo&&videoBlob?`Video local (${fmtSz(videoBlob.size)}) — share via WhatsApp`:null,videoCmt:document.getElementById('f-vid-cmt')?.value||'',brandings:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:calcSqft(b.w,b.h),photoB64:b.blob?await b64(b.blob):null,existingUrl:b.existingUrl||null}))),addlPhotos:await Promise.all(addlPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,desc:p.desc,existingUrl:p.existingUrl||null}))),docB64:submissionDoc?await b64(submissionDoc):null,_docExistingUrl:_docExistingUrl||null}};\u001b[39m\n\u001b[31m    entry.campaignId       = _selectedCampaignId || null;\u001b[39m\n\u001b[31m    entry.notifySupervisor = _notifySupervisor   || false;\u001b[39m\n\u001b[31m    await dbPut('subs',entry);\u001b[39m\n\u001b[31m    await dbDel('draft','current');\u001b[39m\n\u001b[31m    toast(isEdit?'Recce updated ✓':'Recce saved ✓','success');\u001b[39m\n\u001b[31m    if(navigator.onLine)syncNow();\u001b[39m\n\u001b[31m    showView('home');loadHome();checkDraft();\u001b[39m\n\u001b[31m  }catch(err){toast('Error: '+err.message,'error');}\u001b[39m\n\u001b[31m  finally{btn.disabled=false;btn.textContent='Submit Recce ✓';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// SYNC\u001b[39m\n\u001b[31masync function syncNow() {\u001b[39m\n\u001b[31m  if (!navigator.onLine) { toast('Offline — sync when back online', 'info'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('sync-btn');\u001b[39m\n\u001b[31m  const SYNC_ICON = '<svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg>Sync';\u001b[39m\n\u001b[31m  if (btn) { btn.innerHTML = '<span class=\\\"spin\\\">↻</span> Syncing'; btn.disabled = true; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const all      = await dbAll('subs');\u001b[39m\n\u001b[31m    const pend     = all.filter(s => s.status === 'pending' || s.status === 'failed');\u001b[39m\n\u001b[31m    const backfill = all.filter(s => s.status === 'synced' && !s.gasAt);\u001b[39m\n\u001b[31m    if (!pend.length && !backfill.length) { toast('All synced ✓', 'success'); return; }·\u001b[39m\n\u001b[31m    const gasUrl = (await cfg('gas-url')) || DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    function fireGas(s) {\u001b[39m\n\u001b[31m      if (!gasUrl) return;\u001b[39m\n\u001b[31m      fetch(gasUrl, { method:'POST', mode:'no-cors',\u001b[39m\n\u001b[31m        body: JSON.stringify({ action:'syncSheet', submission: s }) })\u001b[39m\n\u001b[31m        .catch(() => {});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    let ok = 0;\u001b[39m\n\u001b[31m    for (const s of pend) {\u001b[39m\n\u001b[31m      // Fire Sheet sync (no-cors fire-and-forget — writes row to Google Sheet)\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      // Primary: upload photos → auto-trigger slides → generate report → store in PostgreSQL\u001b[39m\n\u001b[31m      const { ok: pgOk, viewUrl } = await syncToPostgres(s);\u001b[39m\n\u001b[31m      if (pgOk) {\u001b[39m\n\u001b[31m        s.status = 'synced'; s.syncedAt = new Date().toISOString();\u001b[39m\n\u001b[31m        if (viewUrl) s.viewUrl = viewUrl;\u001b[39m\n\u001b[31m        await dbPut('subs', s); ok++;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        s.status = 'failed'; await dbPut('subs', s);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Backfill: entries synced to Postgres but never reached Sheet GAS\u001b[39m\n\u001b[31m    for (const s of backfill) {\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      await dbPut('subs', s);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if (backfill.length) toast(`Sent ${backfill.length} older entries to Sheet`, 'info');·\u001b[39m\n\u001b[31m    await cfg('last-sync', new Date().toISOString());\u001b[39m\n\u001b[31m    if (pend.length) toast(`Synced ${ok}/${pend.length}`, ok === pend.length ? 'success' : 'error');\u001b[39m\n\u001b[31m    loadHome();\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.innerHTML = SYNC_ICON; btn.disabled = false; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN HOME ──────────────────────────────────────────────\u001b[39m\n\u001b[31masync function loadHomeAdmin() {\u001b[39m\n\u001b[31m  // Adapt UI for admin view\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const _sh = document.querySelector('.sh'); if (_sh) _sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = 'All Submissions';\u001b[39m\n\u001b[31m  const slbls = document.querySelectorAll('.slbl');\u001b[39m\n\u001b[31m  if (slbls[0]) slbls[0].textContent = 'Showing';\u001b[39m\n\u001b[31m  if (slbls[1]) slbls[1].textContent = 'Agents';·\u001b[39m\n\u001b[31m  // Back-to-menu button for supervisors\u001b[39m\n\u001b[31m  if (_isSupervisor() && !document.getElementById('sup-back-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => { document.getElementById('sup-back-btn').remove(); renderSupLanding(); };\u001b[39m\n\u001b[31m    const content = document.querySelector('#view-home .content');\u001b[39m\n\u001b[31m    content.prepend(bb);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Show filter bar — restore if hidden by renderSupLanding, else inject fresh\u001b[39m\n\u001b[31m  const _existingFb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (_existingFb) { _existingFb.style.display = ''; }\u001b[39m\n\u001b[31m  if (!_existingFb) {\u001b[39m\n\u001b[31m    const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m    const fb = document.createElement('div');\u001b[39m\n\u001b[31m    fb.id = 'admin-filter-bar';\u001b[39m\n\u001b[31m    fb.className = 'af-bar';\u001b[39m\n\u001b[31m    fb.innerHTML =\u001b[39m\n\u001b[31m      `<div class=\\\"af-grid\\\">\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-agent\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Agents</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-brand\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Brands</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-client\\\" onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Clients</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-period\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">All Time</option>\u001b[39m\n\u001b[31m          <option value=\\\"7\\\">Last 7 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"30\\\">Last 30 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"90\\\">Last 3 months</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-group\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"date\\\">Sort: Recent</option>\u001b[39m\n\u001b[31m          <option value=\\\"agent\\\">Group: Agent</option>\u001b[39m\n\u001b[31m          <option value=\\\"brand\\\">Group: Brand</option>\u001b[39m\n\u001b[31m          <option value=\\\"client\\\">Group: Client</option>\u001b[39m\n\u001b[31m          <option value=\\\"city\\\">Group: City</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m        <input class=\\\"af-inp\\\" id=\\\"af-search\\\" type=\\\"text\\\" placeholder=\\\"🔍 Search store or city…\\\" oninput=\\\"renderAdminList()\\\" style=\\\"flex:1;min-width:120px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"del-toggle-btn\\\" id=\\\"del-toggle-btn\\\" onclick=\\\"toggleDeletedView()\\\" style=\\\"flex-shrink:0\\\">📋 View Deleted</button>\u001b[39m\n\u001b[31m        ${_isSupervisor() ? `<button class=\\\"del-toggle-btn\\\" id=\\\"pending-job-btn\\\" onclick=\\\"togglePendingJobView()\\\" style=\\\"flex-shrink:0;background:#fef3c7;color:#92400e;border-color:#f59e0b\\\">⚑ Unlinked <span id=\\\"pending-job-count\\\" style=\\\"font-weight:900\\\"></span></button>` : ''}\u001b[39m\n\u001b[31m        ${_adminUnlocked ? `<button class=\\\"del-toggle-btn\\\" id=\\\"regen-rpt-btn\\\" onclick=\\\"regenAllReports()\\\" style=\\\"flex-shrink:0\\\">&#x21BB; Regen Reports</button>` : ''}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    sh.parentNode.insertBefore(fb, sh);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Fetch\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  list.innerHTML = '<div style=\\\"text-align:center;padding:40px\\\"><div class=\\\"spinner\\\"></div></div>';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?order=submitted_at.desc&limit=500`, { headers: _RC_READ });\u001b[39m\n\u001b[31m    _adminRows = resp.ok ? await resp.json() : [];\u001b[39m\n\u001b[31m    document.getElementById('stat-total').textContent = _adminRows.length;\u001b[39m\n\u001b[31m    if (resp.ok) {\u001b[39m\n\u001b[31m      const now = new Date();\u001b[39m\n\u001b[31m      document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m        'Loaded ' + now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Populate agent dropdown\u001b[39m\n\u001b[31m    const agents = [...new Set(_adminRows.map(r => r.submitted_by).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-agent').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Agents (${agents.length})</option>` +\u001b[39m\n\u001b[31m      agents.map(a => `<option value=\\\"${a}\\\">${a}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate brand dropdown\u001b[39m\n\u001b[31m    const brands = [...new Set(_adminRows.map(r => r.brand).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-brand').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Brands (${brands.length})</option>` +\u001b[39m\n\u001b[31m      brands.map(b => `<option value=\\\"${b}\\\">${b}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate client dropdown\u001b[39m\n\u001b[31m    const clients = [...new Set(_adminRows.map(r => r.client_name).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-client').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Clients (${clients.length})</option>` +\u001b[39m\n\u001b[31m      clients.map(c => `<option value=\\\"${c}\\\">${c}</option>`).join('');·\u001b[39m\n\u001b[31m    // Update pending-job count badge\u001b[39m\n\u001b[31m    const unlinkedCount = _adminRows.filter(r => !r.deleted_at && !r.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinkedCount ? `(${unlinkedCount})` : '';·\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">⚠️</div><div class=\\\"empty-txt\\\">Could not load — check connection</div></div>';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction togglePendingJobView() {\u001b[39m\n\u001b[31m  _pendingJobFilter = !_pendingJobFilter;\u001b[39m\n\u001b[31m  _showDeletedView  = false;\u001b[39m\n\u001b[31m  const btn = document.getElementById('pending-job-btn');\u001b[39m\n\u001b[31m  if (btn) btn.style.background = _pendingJobFilter ? '#f59e0b' : '#fef3c7';\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function openLinkJobModal(subId, storeName) {\u001b[39m\n\u001b[31m  _linkJobSubId = subId;\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  const storeEl = document.getElementById('link-job-store');\u001b[39m\n\u001b[31m  const sel = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  if (!modal) return;\u001b[39m\n\u001b[31m  if (storeEl) storeEl.textContent = storeName || subId;\u001b[39m\n\u001b[31m  if (errEl) errEl.textContent = '';\u001b[39m\n\u001b[31m  // Load campaigns into dropdown\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (!_campaignList.length) {\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m      _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  if (sel) {\u001b[39m\n\u001b[31m    sel.innerHTML = '<option value=\\\"\\\">— Select campaign —</option>' +\u001b[39m\n\u001b[31m      _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  modal.style.display = 'flex';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeLinkJobModal() {\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  if (modal) modal.style.display = 'none';\u001b[39m\n\u001b[31m  _linkJobSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function saveLinkJob() {\u001b[39m\n\u001b[31m  const sel    = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl  = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  const campId = sel?.value || '';\u001b[39m\n\u001b[31m  if (!campId) { if (errEl) errEl.textContent = 'Select a campaign'; return; }\u001b[39m\n\u001b[31m  if (!_linkJobSubId) return;\u001b[39m\n\u001b[31m  const btn = document.querySelector('#modal-link-job button[onclick=\\\"saveLinkJob()\\\"]');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Linking…'; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(_linkJobSubId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ campaign_id: campId }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Patch failed');\u001b[39m\n\u001b[31m    // Update local cache\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === _linkJobSubId);\u001b[39m\n\u001b[31m    if (idx >= 0) _adminRows[idx].campaign_id = campId;\u001b[39m\n\u001b[31m    // Update pending count badge\u001b[39m\n\u001b[31m    const unlinked = _adminRows.filter(x => !x.deleted_at && !x.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinked ? `(${unlinked})` : '';\u001b[39m\n\u001b[31m    closeLinkJobModal();\u001b[39m\n\u001b[31m    toast('Job linked ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    if (errEl) errEl.textContent = 'Failed to link — try again';\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.disabled = false; btn.textContent = '🔗 Link Job'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAdminList() {\u001b[39m\n\u001b[31m  const agent  = document.getElementById('af-agent')?.value  || '';\u001b[39m\n\u001b[31m  const brand  = document.getElementById('af-brand')?.value  || '';\u001b[39m\n\u001b[31m  const period = document.getElementById('af-period')?.value || '';\u001b[39m\n\u001b[31m  const search = (document.getElementById('af-search')?.value || '').toLowerCase().trim();\u001b[39m\n\u001b[31m  const group  = document.getElementById('af-group')?.value  || 'date';·\u001b[39m\n\u001b[31m  // Pending-job filter overrides deleted/normal modes\u001b[39m\n\u001b[31m  let rows;\u001b[39m\n\u001b[31m  if (_pendingJobFilter) {\u001b[39m\n\u001b[31m    rows = _adminRows.filter(r => !r.deleted_at && !r.campaign_id);\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows = _showDeletedView\u001b[39m\n\u001b[31m      ? _adminRows.filter(r => r.deleted_at)\u001b[39m\n\u001b[31m      : _adminRows.filter(r => !r.deleted_at);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const client = document.getElementById('af-client')?.value || '';\u001b[39m\n\u001b[31m  if (agent)  rows = rows.filter(r => r.submitted_by === agent);\u001b[39m\n\u001b[31m  if (brand)  rows = rows.filter(r => r.brand === brand);\u001b[39m\n\u001b[31m  if (client) rows = rows.filter(r => r.client_name === client);\u001b[39m\n\u001b[31m  if (search) rows = rows.filter(r => (r.store_name||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.city||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.client_name||'').toLowerCase().includes(search));\u001b[39m\n\u001b[31m  if (period && !_showDeletedView) {\u001b[39m\n\u001b[31m    const cut = new Date(); cut.setDate(cut.getDate() - parseInt(period));\u001b[39m\n\u001b[31m    rows = rows.filter(r => new Date(r.submitted_at) >= cut);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const uniqueAgents = new Set(rows.map(r => r.submitted_by).filter(Boolean)).size;\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = rows.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = uniqueAgents;\u001b[39m\n\u001b[31m  const deletedCount = _adminRows.filter(r => r.deleted_at).length;\u001b[39m\n\u001b[31m  const delBtn = document.getElementById('del-toggle-btn');\u001b[39m\n\u001b[31m  if (delBtn) {\u001b[39m\n\u001b[31m    if (_showDeletedView) {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 Hide Deleted (${deletedCount})` : '📋 Hide Deleted';\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 View Deleted (${deletedCount})` : '📋 View Deleted';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    delBtn.classList.toggle('active', _showDeletedView);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!rows.length) {\u001b[39m\n\u001b[31m    list.innerHTML = _showDeletedView\u001b[39m\n\u001b[31m      ? '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">✅</div><div class=\\\"empty-txt\\\">No deleted recces</div></div>'\u001b[39m\n\u001b[31m      : '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">🔍</div><div class=\\\"empty-txt\\\">No matching submissions</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (group === 'agent') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.submitted_by||'').localeCompare(b.submitted_by||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.submitted_by || 'Unknown';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">👤 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'brand') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.brand||'').localeCompare(b.brand||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.brand || 'No Brand';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🏷 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'client') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.client_name||'').localeCompare(b.client_name||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.client_name || 'No Client';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🤝 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'city') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.city||'').localeCompare(b.city||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.city || 'No City';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">📍 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows.sort((a,b) => new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    rows.forEach(r => { html += adminCard(r); });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminCard(r) {\u001b[39m\n\u001b[31m  const dt    = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds    = dt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m  const tm    = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const photos = (r.front_photos||0) + (r.inside_photos||0) + (r.addl_photos||0);\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const canDelete  = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const canArchive = _RECCE_CFG_ADMINS.includes(hub?.empId) && !r.client_archived;·\u001b[39m\n\u001b[31m  // Client status badge\u001b[39m\n\u001b[31m  const clientStatusMap = {\u001b[39m\n\u001b[31m    approved:              {t:'✓ Approved',    s:'color:#166534;background:#dcfce7;border:1px solid #86efac'},\u001b[39m\n\u001b[31m    rejected:              {t:'✕ Rejected',    s:'color:#991b1b;background:#fee2e2;border:1px solid #fca5a5'},\u001b[39m\n\u001b[31m    approved_with_changes: {t:'✎ Approved w/ Comments', s:'color:#92400e;background:#fef3c7;border:1px solid #fcd34d'},\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const csCfg = clientStatusMap[r.client_status];\u001b[39m\n\u001b[31m  const clientStatusBadge = csCfg\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;${csCfg.s}\\\">${csCfg.t}</span>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const archiveBadge = r.client_archived\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;color:#475569;background:#f1f5f9;border:1px solid #cbd5e1\\\">⬚ Client hidden</span>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  if (r.deleted_at) {\u001b[39m\n\u001b[31m    const delDt = new Date(r.deleted_at);\u001b[39m\n\u001b[31m    const delDs = delDt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m    const reasonLabel = r.deletion_reason === 'wrong' ? 'Wrong' : r.deletion_reason === 'duplicate' ? 'Duplicate' : 'Test';\u001b[39m\n\u001b[31m    return `<div class=\\\"asc deleted-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m        <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m            <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds}</span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m          <span class=\\\"del-reason-tag\\\">❌ ${reasonLabel}</span>\u001b[39m\n\u001b[31m          <div class=\\\"del-by-txt\\\">by ${r.deleted_by||'?'} · ${delDs}</div>\u001b[39m\n\u001b[31m          ${canDelete ? `<button class=\\\"restore-btn\\\" onclick=\\\"event.stopPropagation();restoreRecce('${r.sub_id}')\\\">↩ Restore</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Submitted by ${r.submitted_by||'?'}</div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const chips = [\u001b[39m\n\u001b[31m    photos > 0   ? `📷 ${photos} photo${photos!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.has_video  ? '🎥 Video' : null,\u001b[39m\n\u001b[31m    r.has_branding ? `🪧 ${r.branding_count} branding${r.branding_count!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.city       ? `📍 ${r.city}` : (r.address ? `📍 ${r.address}` : null),\u001b[39m\n\u001b[31m    r.view_url   ? '👁 View available' : null,\u001b[39m\n\u001b[31m  ].filter(Boolean);·\u001b[39m\n\u001b[31m  const delBtnHtml = canDelete\u001b[39m\n\u001b[31m    ? `<button class=\\\"del-btn\\\" onclick=\\\"event.stopPropagation();openDeleteModal('${r.sub_id}')\\\" title=\\\"Delete recce\\\">🗑</button>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const editReqHtml = r.edit_assigned_to\u001b[39m\n\u001b[31m    ? `<span class=\\\"edit-req-badge\\\">✏ Edit sent to ${r.edit_assigned_to}</span>`\u001b[39m\n\u001b[31m    : (_isSupervisor()\u001b[39m\n\u001b[31m        ? `<button class=\\\"req-edit-btn\\\" onclick=\\\"event.stopPropagation();openEditRequestModal('${r.sub_id}')\\\">✏ Request Edit</button>`\u001b[39m\n\u001b[31m        : '');·\u001b[39m\n\u001b[31m  const editRow = editReqHtml\u001b[39m\n\u001b[31m    ? `<div style=\\\"margin-top:6px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">${editReqHtml}</div>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const showPdfBtn = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m  const pdfClass = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m  const pdfLabel = '📄 PDF';\u001b[39m\n\u001b[31m  const linkJobBtn = (_pendingJobFilter && _isSupervisor() && !r.campaign_id)\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:#f59e0b;color:#000;border-color:#f59e0b;font-weight:700\\\" onclick=\\\"event.stopPropagation();openLinkJobModal('${r.sub_id}','${(r.store_name||'Unknown').replace(/'/g,'\\\\\\\\\\\\'')}')\\\">🔗 Link Job</button>`\u001b[39m\n\u001b[31m    : (r.campaign_id ? `<span style=\\\"font-size:10px;color:var(--g400);align-self:center\\\">🔗 ${r.campaign_id}</span>` : '');\u001b[39m\n\u001b[31m  const archiveBtn = canArchive\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:rgba(99,102,241,.08);border-color:var(--nv);color:var(--nv)\\\" onclick=\\\"event.stopPropagation();archiveRecce('${r.sub_id}')\\\">⛚ Archive</button>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const btnsRow = `<div class=\\\"rpt-btns\\\">\u001b[39m\n\u001b[31m    <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openAdminRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m    ${showPdfBtn ? `<button class=\\\"${pdfClass}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">${pdfLabel}</button>` : ''}\u001b[39m\n\u001b[31m    ${linkJobBtn}\u001b[39m\n\u001b[31m    ${archiveBtn}\u001b[39m\n\u001b[31m  </div>`;·\u001b[39m\n\u001b[31m  return `<div class=\\\"asc\\\">\u001b[39m\n\u001b[31m    <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m      <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m          ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          ${r.client_name&&r.client_name!==r.brand?`<span class=\\\"client-tag\\\">🤝 ${r.client_name}</span>`:''}\u001b[39m\n\u001b[31m          <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds} · ${tm}</span>\u001b[39m\n\u001b[31m          ${clientStatusBadge}\u001b[39m\n\u001b[31m          ${archiveBadge}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <span class=\\\"asc-agent\\\">👤 ${r.submitted_by||'?'}</span>\u001b[39m\n\u001b[31m        ${delBtnHtml}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    ${chips.length?`<div class=\\\"asc-chips\\\">${chips.map(c=>`<span class=\\\"asc-chip\\\">${c}</span>`).join('')}</div>`:''}\u001b[39m\n\u001b[31m    ${editRow}\u001b[39m\n\u001b[31m    ${btnsRow}\u001b[39m\n\u001b[31m  </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _ensurePdfOverlay() {\u001b[39m\n\u001b[31m  if (document.getElementById('pdf-wait-ov')) return;\u001b[39m\n\u001b[31m  const ov = document.createElement('div');\u001b[39m\n\u001b[31m  ov.id = 'pdf-wait-ov';\u001b[39m\n\u001b[31m  ov.innerHTML = '<div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Generating PDF…</div><div class=\\\"po-sub\\\" id=\\\"pw-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"pw-pfill\\\"></div></div>';\u001b[39m\n\u001b[31m  document.body.appendChild(ov);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _showPdfOverlay(msg) {\u001b[39m\n\u001b[31m  _ensurePdfOverlay();\u001b[39m\n\u001b[31m  document.getElementById('pw-sub').textContent = msg || '';\u001b[39m\n\u001b[31m  document.getElementById('pw-pfill').style.width = '0%';\u001b[39m\n\u001b[31m  document.getElementById('pdf-wait-ov').style.display = 'flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _hidePdfOverlay() {\u001b[39m\n\u001b[31m  const ov = document.getElementById('pdf-wait-ov');\u001b[39m\n\u001b[31m  if (ov) ov.style.display = 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function openPdf(subId, pdfUrl, viewUrl) {\u001b[39m\n\u001b[31m  if (pdfUrl) { window.open(pdfUrl, '_blank'); return; }\u001b[39m\n\u001b[31m  if (!viewUrl) {\u001b[39m\n\u001b[31m    toast('Report view not available yet — please try after the report is generated.', 'info');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _showPdfOverlay('Requesting PDF generation…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type': 'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({type: 'regen-pdf', subId, viewUrl})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  let attempts = 0;\u001b[39m\n\u001b[31m  const MAX = 24;\u001b[39m\n\u001b[31m  const poll = async () => {\u001b[39m\n\u001b[31m    attempts++;\u001b[39m\n\u001b[31m    const pct = Math.min(88, Math.round(attempts / MAX * 88));\u001b[39m\n\u001b[31m    document.getElementById('pw-pfill').style.width = pct + '%';\u001b[39m\n\u001b[31m    const left = Math.ceil((MAX - attempts) * 5);\u001b[39m\n\u001b[31m    document.getElementById('pw-sub').textContent = 'Checking… (' + left + 's remaining)';\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const res = await fetch('/db/submissions?sub_id=eq.' + subId + '&select=pdf_url', {\u001b[39m\n\u001b[31m        headers: {'Content-Profile': 'recce', 'Accept-Profile': 'recce'}\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      const rows = await res.json();\u001b[39m\n\u001b[31m      if (rows && rows[0] && rows[0].pdf_url) {\u001b[39m\n\u001b[31m        document.getElementById('pw-pfill').style.width = '100%';\u001b[39m\n\u001b[31m        setTimeout(() => { _hidePdfOverlay(); window.open(rows[0].pdf_url, '_blank'); }, 400);\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(_) {}\u001b[39m\n\u001b[31m    if (attempts >= MAX) { _hidePdfOverlay(); toast('PDF generation timed out. Please try again later.', 'error'); return; }\u001b[39m\n\u001b[31m    setTimeout(poll, 5000);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  setTimeout(poll, 4000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openAdminRecce(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];·\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">\u001b[39m\n\u001b[31m         📍 View on Google Maps (${Number(r.gps_lat).toFixed(4)}, ${Number(r.gps_lng).toFixed(4)})\u001b[39m\n\u001b[31m       </a>` : '';·\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} ft × ${b.h||'?'} ft · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos not yet available — field agent must re-sync from their device to upload view\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Submission Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">👤 ${r.submitted_by||'Unknown'}</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            ${meta.videoCmt?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500);font-size:12px\\\">${meta.videoCmt}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m          ${(()=>{\u001b[39m\n\u001b[31m            const hub2 = _recceHubUser();\u001b[39m\n\u001b[31m            const isHP = _RECCE_CFG_ADMINS.includes(hub2?.empId);\u001b[39m\n\u001b[31m            const csMap = {\u001b[39m\n\u001b[31m              approved:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#166534;background:#dcfce7\\\">✓ Approved</span>',\u001b[39m\n\u001b[31m              rejected:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#991b1b;background:#fee2e2\\\">✕ Rejected</span>',\u001b[39m\n\u001b[31m              approved_with_changes: '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#92400e;background:#fef3c7\\\">✎ Approved w/ Comments</span>',\u001b[39m\n\u001b[31m            };\u001b[39m\n\u001b[31m            const csBadge = csMap[r.client_status] || '';\u001b[39m\n\u001b[31m            const approvedAt = r.client_approved_at\u001b[39m\n\u001b[31m              ? new Date(r.client_approved_at).toLocaleString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit',timeZone:'Asia/Kolkata'})\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const pdfLink = r.client_approval_pdf_url\u001b[39m\n\u001b[31m              ? `<a href=\\\"${r.client_approval_pdf_url}\\\" target=\\\"_blank\\\" style=\\\"font-size:12px;color:var(--or);text-decoration:none\\\">⬇ Approval PDF</a>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const archAct = isHP && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveRecce('${r.sub_id}')\\\" style=\\\"font-size:12px;color:var(--nv);background:none;border:1px solid var(--nv);border-radius:6px;padding:4px 10px;cursor:pointer\\\">⦽ Archive from client</button>`\u001b[39m\n\u001b[31m              : (r.client_archived ? '<span style=\\\"font-size:11px;color:var(--g400)\\\">⦽ Hidden from client</span>' : '');\u001b[39m\n\u001b[31m            const campAct = isHP && r.campaign_id && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveAllForCampaign('${r.campaign_id}')\\\" style=\\\"font-size:11px;color:#991b1b;background:none;border:1px solid #fca5a5;border-radius:6px;padding:3px 8px;cursor:pointer\\\">Archive ALL for ${r.campaign_id}</button>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            if (!csBadge && !pdfLink && !archAct) return '';\u001b[39m\n\u001b[31m            return `<div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m              <div class=\\\"ardl-lbl\\\">Client Approval</div>\u001b[39m\n\u001b[31m              ${csBadge ? `<div style=\\\"margin-bottom:5px\\\">${csBadge}${approvedAt ? ' <span style=\\\"font-size:11px;color:var(--g400)\\\">' + approvedAt + '</span>' : ''}</div>` : ''}\u001b[39m\n\u001b[31m              ${r.client_comment ? `<div style=\\\"font-size:12px;color:var(--g600);background:var(--g50);border-radius:6px;padding:7px 10px;margin-bottom:5px\\\">\\\"${r.client_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m              ${pdfLink ? `<div style=\\\"margin-bottom:4px\\\">${pdfLink}</div>` : ''}\u001b[39m\n\u001b[31m              ${archAct ? `<div style=\\\"margin-bottom:4px\\\">${archAct}</div>` : ''}\u001b[39m\n\u001b[31m              ${campAct ? `<div>${campAct}</div>` : ''}\u001b[39m\n\u001b[31m            </div>`;\u001b[39m\n\u001b[31m          })()}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeAdminDetail() {\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveRecce(subId) {\u001b[39m\n\u001b[31m  if (!confirm('Archive this recce from client view? The client will no longer see it.')) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(subId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) Object.assign(_adminRows[idx], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    toast('Archived from client view ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveAllForCampaign(campaignId) {\u001b[39m\n\u001b[31m  if (!confirm(`Archive ALL recces for campaign \\\"${campaignId}\\\" from client view?\\\\nClients will no longer see any recce from this campaign.`)) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?campaign_id=eq.${encodeURIComponent(campaignId)}&client_archived=eq.false`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    _adminRows.forEach((row, i) => {\u001b[39m\n\u001b[31m      if (row.campaign_id === campaignId) Object.assign(_adminRows[i], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    toast(`All recces for ${campaignId} archived ✓`, 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function regenAllReports() {\u001b[39m\n\u001b[31m  if (!_adminUnlocked) { toast('Admin access required', 'error'); return; }\u001b[39m\n\u001b[31m  const rows = _adminRows.filter(r => !r.deleted_at && r.photo_urls);\u001b[39m\n\u001b[31m  if (!rows.length) { toast('No synced rows with photos found', 'error'); return; }·\u001b[39m\n\u001b[31m  const btn = document.getElementById('regen-rpt-btn');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Regenerating…'; }\u001b[39m\n\u001b[31m  toast(`Regenerating ${rows.length} reports…`, 'info');·\u001b[39m\n\u001b[31m  let done = 0, failed = 0;\u001b[39m\n\u001b[31m  for (const r of rows) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const photoUrls = typeof r.photo_urls === 'string' ? JSON.parse(r.photo_urls) : (r.photo_urls || {});\u001b[39m\n\u001b[31m      let meta = {};\u001b[39m\n\u001b[31m      try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m      const entry = {\u001b[39m\n\u001b[31m        id: r.sub_id,\u001b[39m\n\u001b[31m        timestamp: r.submitted_at,\u001b[39m\n\u001b[31m        submittedBy: r.submitted_by,\u001b[39m\n\u001b[31m        data: {\u001b[39m\n\u001b[31m          storeName:    r.store_name,\u001b[39m\n\u001b[31m          brand:        r.brand,\u001b[39m\n\u001b[31m          clientName:   r.client_name,\u001b[39m\n\u001b[31m          date:         r.visit_date,\u001b[39m\n\u001b[31m          address:      r.address,\u001b[39m\n\u001b[31m          city:         r.city,\u001b[39m\n\u001b[31m          mobile:       r.mobile,\u001b[39m\n\u001b[31m          gpsCoords:    (r.gps_lat && r.gps_lng) ? { lat: r.gps_lat, lng: r.gps_lng } : null,\u001b[39m\n\u001b[31m          hasVideo:     r.has_video,\u001b[39m\n\u001b[31m          videoNote:    meta.videoNote || '',\u001b[39m\n\u001b[31m          videoCmt:     meta.videoCmt  || '',\u001b[39m\n\u001b[31m          frontPhotos:  (photoUrls.front   || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          insidePhotos: (photoUrls.inside  || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          addlPhotos:   (photoUrls.addl    || []).map(() => ({ desc: '' })),\u001b[39m\n\u001b[31m          brandings:    (meta.brandings    || []),\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      };·\u001b[39m\n\u001b[31m      const html = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m      const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m        method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m        body: JSON.stringify({ type: 'save-view', subId: r.sub_id, html })\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!vResp.ok) { failed++; continue; }\u001b[39m\n\u001b[31m      const vr = await vResp.json();\u001b[39m\n\u001b[31m      if (!vr.success) { failed++; continue; }·\u001b[39m\n\u001b[31m      if (vr.url && vr.url !== r.view_url) {\u001b[39m\n\u001b[31m        await fetch(`${_RC_BASE}/submissions?sub_id=eq.${r.sub_id}`, {\u001b[39m\n\u001b[31m          method: 'PATCH', headers: _RC_WRITE,\u001b[39m\n\u001b[31m          body: JSON.stringify({ view_url: vr.url })\u001b[39m\n\u001b[31m        });\u001b[39m\n\u001b[31m        const idx = _adminRows.findIndex(x => x.sub_id === r.sub_id);\u001b[39m\n\u001b[31m        if (idx >= 0) _adminRows[idx].view_url = vr.url;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      done++;\u001b[39m\n\u001b[31m    } catch(e) { failed++; }\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = false; btn.textContent = '↻ Regen Reports'; }\u001b[39m\n\u001b[31m  toast(`Done: ${done} regenerated${failed ? `, ${failed} failed` : ''}`, done > 0 ? 'success' : 'error');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction toggleDeletedView() {\u001b[39m\n\u001b[31m  _showDeletedView = !_showDeletedView;\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openDeleteModal(subId) {\u001b[39m\n\u001b[31m  _pendingDeleteId = subId;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  const sub = document.getElementById('del-modal-sub');\u001b[39m\n\u001b[31m  if (sub) sub.textContent = r ? `Delete: \\\"${r.store_name||'Unknown'}\\\"` : 'Select reason for deletion:';\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectDeleteReason(reason) {\u001b[39m\n\u001b[31m  _pendingDeleteReason = reason;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  document.getElementById('reason-' + reason)?.classList.add('sel');\u001b[39m\n\u001b[31m  document.getElementById('del-confirm-btn').classList.remove('no-reason');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeDeleteModal() {\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingDeleteId = null;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  clearTimeout(_tt);\u001b[39m\n\u001b[31m  document.getElementById('toast').classList.remove('show');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function restoreRecce(subId) {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({ deleted_at: null, deleted_by: null, deletion_reason: null }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Restore failed: ' + r.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_at = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_by = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deletion_reason = null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    toast('Recce restored ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Restore failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmDelete() {\u001b[39m\n\u001b[31m  if (!_pendingDeleteReason) {\u001b[39m\n\u001b[31m    const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m    btn.style.animation = 'none';\u001b[39m\n\u001b[31m    btn.offsetHeight; // reflow\u001b[39m\n\u001b[31m    btn.style.animation = 'shake .35s ease';\u001b[39m\n\u001b[31m    toast('Select a reason first', 'error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if (!_pendingDeleteId) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Deleting…';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      // Hard delete — no audit trail\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'DELETE',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Delete failed: ' + r.status);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Soft delete — stamp deleted_at, deleted_by, deletion_reason\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'PATCH',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m        body: JSON.stringify({\u001b[39m\n\u001b[31m          deleted_at: new Date().toISOString(),\u001b[39m\n\u001b[31m          deleted_by: hub.empId,\u001b[39m\n\u001b[31m          deletion_reason: _pendingDeleteReason,\u001b[39m\n\u001b[31m        }),\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Update failed: ' + r.status);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Remove or update in local cache\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      _adminRows = _adminRows.filter(x => x.sub_id !== _pendingDeleteId);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      const idx = _adminRows.findIndex(x => x.sub_id === _pendingDeleteId);\u001b[39m\n\u001b[31m      if (idx >= 0) {\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_at = new Date().toISOString();\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_by = hub.empId;\u001b[39m\n\u001b[31m        _adminRows[idx].deletion_reason = _pendingDeleteReason;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeDeleteModal();\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast('Recce deleted', 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Delete failed', 'error');\u001b[39m\n\u001b[31m    btn.classList.remove('no-reason');\u001b[39m\n\u001b[31m    btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openMyServerRecce(subId) {\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  // No view yet — show metadata modal (same layout as admin detail)\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta==='string' ? JSON.parse(r.meta) : (r.meta||{}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">📍 View on Google Maps</a>` : '';\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} × ${b.h||'?'} in · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos will appear after next sync from original device\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Visit Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupLanding() {\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = 'none';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = 'none';\u001b[39m\n\u001b[31m  // Clean up admin + create-mode UI\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('sup-back-btn')?.remove();\u001b[39m\n\u001b[31m  document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m  _supCreateMode = false;\u001b[39m\n\u001b[31m  // Resume-wrap may have been hidden by loadHomeAdmin() — restore it so draft banner shows\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = '';\u001b[39m\n\u001b[31m  document.getElementById('sub-list').innerHTML = `\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorViewAll()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0f9ff\\\">📋</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">View All Recces</span><span class=\\\"hi-txt\\\">सभी रेकी देखें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">Browse & review submissions from all agents</span><span class=\\\"hi-txt\\\">सभी एजेंट की सबमिशन देखें</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorCreateView()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0fdf4\\\">✍️</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">Create Recce</span><span class=\\\"hi-txt\\\">नई रेकी बनाएं</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">My submissions + New Recce button</span><span class=\\\"hi-txt\\\">मेरी सबमिशन + नई रेकी</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorViewAll() {\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  await loadHomeAdmin();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorCreateView() {\u001b[39m\n\u001b[31m  _supCreateMode = true;\u001b[39m\n\u001b[31m  // Restore field-agent UI\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh'); if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = t('My Submissions','मेरी सबमिशन');\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar'); if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  // Add Back to Menu button (once)\u001b[39m\n\u001b[31m  if (!document.getElementById('sup-back-create-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-create-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => {\u001b[39m\n\u001b[31m      _supCreateMode = false;\u001b[39m\n\u001b[31m      document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m      renderSupLanding();\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    document.querySelector('#view-home .content').prepend(bb);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  await loadHome();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadHome() {\u001b[39m\n\u001b[31m  if (_isSupervisor() && !_supCreateMode) { renderSupLanding(); return; }\u001b[39m\n\u001b[31m  if (_adminUnlocked && !_supCreateMode) { await loadHomeAdmin(); return; }·\u001b[39m\n\u001b[31m  const all  = await dbAll('subs');\u001b[39m\n\u001b[31m  const sy   = all.filter(s => s.status === 'synced').length;\u001b[39m\n\u001b[31m  const pe   = all.filter(s => s.status !== 'synced').length;·\u001b[39m\n\u001b[31m  // Fetch this agent's submissions from server — works on any device\u001b[39m\n\u001b[31m  let serverOnly = [];\u001b[39m\n\u001b[31m  let editAssigned = [];\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (navigator.onLine && hub?.empId) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?submitted_by=eq.${encodeURIComponent(hub.empId)}&order=submitted_at.desc&limit=200`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp.ok) {\u001b[39m\n\u001b[31m        const rows = await resp.json();\u001b[39m\n\u001b[31m        const localIds = new Set(all.map(s => s.id));\u001b[39m\n\u001b[31m        serverOnly = rows.filter(r => !localIds.has(r.sub_id));\u001b[39m\n\u001b[31m        _myServerRows = serverOnly;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m    // Fetch edit-assigned recces (supervisor assigned this creator to edit)\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp2 = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?edit_assigned_to=eq.${encodeURIComponent(hub.empId)}&deleted_at=is.null&order=submitted_at.desc`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp2.ok) editAssigned = await resp2.json();\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = sy + serverOnly.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = pe;\u001b[39m\n\u001b[31m  document.getElementById('stat-total').textContent   = all.length + serverOnly.length;·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!all.length && !serverOnly.length && !editAssigned.length) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">📋</div><div class=\\\"empty-txt\\\">No submissions yet</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const icos   = { synced:'✅', pending:'⏳', failed:'❌' };\u001b[39m\n\u001b[31m  const sorted = [...all].sort((a,b) => new Date(b.timestamp) - new Date(a.timestamp)).slice(0, 50);·\u001b[39m\n\u001b[31m  const localCards = sorted.map(s => {\u001b[39m\n\u001b[31m    const dt = new Date(s.timestamp);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const viewBtn = s.viewUrl\u001b[39m\n\u001b[31m      ? `<button class=\\\"edit-btn-sm\\\" onclick=\\\"window.open('${s.viewUrl}','_blank')\\\">👁 View</button>`\u001b[39m\n\u001b[31m      : `<button class=\\\"edit-btn-sm\\\" onclick=\\\"viewRecce('${s.id}')\\\">👁 View</button>`;\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico ${s.status}\\\">${icos[s.status]||'📋'}</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${s.data.storeName||'Unknown'} · ${s.data.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${s.data.address||''}</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge ${s.status}\\\">${s.status}</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          ${viewBtn}\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"editRecce('${s.id}')\\\" style=\\\"background:#fff7ed;border-color:var(--or);color:var(--or)\\\">✏ Edit</button>\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"makeSlides('${s.id}')\\\" style=\\\"background:#eff6ff;border-color:#3b82f6;color:#1d4ed8\\\">📊 Slides</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const serverCards = serverOnly.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const showPdf = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m    const pdfCls = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico synced\\\">✅</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\" style=\\\"min-width:0;flex:1\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"rpt-btns\\\" style=\\\"margin-top:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openMyServerRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m          ${showPdf ? `<button class=\\\"${pdfCls}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">📄 PDF</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge synced\\\">synced</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const editAssignedCards = editAssigned.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    return `<div class=\\\"edit-req-card\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:26px;flex-shrink:0\\\">✏</div>\u001b[39m\n\u001b[31m      <div class=\\\"edit-req-card-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-meta\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        ${r.edit_comment ? `<div class=\\\"edit-req-cmt\\\">\\\"${r.edit_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:10px;display:flex;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"startCreatorEdit('${r.sub_id}')\\\" style=\\\"padding:9px 16px;font-size:13px;font-weight:600\\\">✏ Edit this Recce</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (editAssignedCards.length) {\u001b[39m\n\u001b[31m    html += `<div class=\\\"edit-req-section-hdr\\\">✏ Edit Requested (${editAssignedCards.length})</div>`;\u001b[39m\n\u001b[31m    html += editAssignedCards.join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  html += localCards.join('') + serverCards.join('');\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m  const ls = await cfg('last-sync');\u001b[39m\n\u001b[31m  if (ls) {\u001b[39m\n\u001b[31m    const d = new Date(ls);\u001b[39m\n\u001b[31m    document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m      'Synced ' + d.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// RESET\u001b[39m\n\u001b[31mfunction startNewRecce(){F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  if(geoStampEnabled)autoRequestGPS();\u001b[39m\n\u001b[31m['f-date','f-brand','f-store','f-addr','f-mobile','f-client-other'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';});\u001b[39m\n\u001b[31m_selectedClient='';_clientOtherMode=false;\u001b[39m\n\u001b[31m_selectedCampaignId=null;_notifySupervisor=false;_brandingLocked=false;\u001b[39m\n\u001b[31mconst _camSel=document.getElementById('f-campaign-id');if(_camSel)_camSel.value='';\u001b[39m\n\u001b[31mconst _camNotice=document.getElementById('campaign-notify-msg');if(_camNotice)_camNotice.style.display='none';\u001b[39m\n\u001b[31mloadCampaignsForForm();\u001b[39m\n\u001b[31mrenderClientChips();\u001b[39m\n\u001b[31mdocument.getElementById('f-date').value=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31m// Block future dates\u001b[39m\n\u001b[31mdocument.getElementById('f-date').max=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31mdocument.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('pick-trigger-wrap').style.display=stores.length?'block':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').style.display=stores.length?'flex':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31mdocument.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31mdocument.getElementById('manual-fields').style.display=stores.length?'none':'block';\u001b[39m\n\u001b[31mdocument.getElementById('gps-status').textContent='';\u001b[39m\n\u001b[31m['vid-yes','vid-no','br-yes','br-no'].forEach(id=>document.getElementById(id).classList.remove('sel'));\u001b[39m\n\u001b[31mdocument.getElementById('vid-sec').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('vid-slot').innerHTML=`<div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('br-add').style.display='none';document.getElementById('br-items').innerHTML='';\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').classList.remove('filled');\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').innerHTML=`<div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('brand-selector').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('sc-missing').style.display='none';\u001b[39m\n\u001b[31mpopulateBrandDropdown();\u001b[39m\n\u001b[31mrenderPhotos('front');renderPhotos('inside');renderAddl();updAvailTag();showView('form-store');}\u001b[39m\n\u001b[31mfunction exitForm(){\u001b[39m\n\u001b[31m  // Show safe exit dialog instead of confirm\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitSaveAndLeave(){\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m  checkDraft();\u001b[39m\n\u001b[31m  toast('Draft saved — tap Resume to continue','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitDiscard(){\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];\u001b[39m\n\u001b[31m  videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  dbDel('draft','current');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitCancel(){document.getElementById('exit-dialog').classList.remove('open');}\u001b[39m\n\u001b[31mfunction showView(n){document.querySelectorAll('.view').forEach(v=>v.classList.remove('active'));const t=document.getElementById('view-'+n);if(t){t.classList.add('active');window.scrollTo(0,0);}}\u001b[39m\n\u001b[31mlet _tt;\u001b[39m\n\u001b[31mfunction toast(msg,type='info'){const el=document.getElementById('toast');el.textContent=msg;el.className='toast show '+type;clearTimeout(_tt);_tt=setTimeout(()=>el.classList.remove('show'),3000);}\u001b[39m\n\u001b[31mfunction netStatus(){const on=navigator.onLine;const dot=document.getElementById('net-dot');const txt=document.getElementById('net-txt');if(dot)dot.className='sdot '+(on?'on':'off');if(txt)txt.textContent=on?t('Online','ऑनलाइन'):t('Offline — saves locally','ऑफलाइन — स्थानीय रूप से सेव');}\u001b[39m\n\u001b[31masync function loadSettings(){\u001b[39m\n\u001b[31m  // Gas URL: pre-load default if none saved, update preview\u001b[39m\n\u001b[31m  const gu=await cfg('gas-url');\u001b[39m\n\u001b[31m  if(!gu)await cfg('gas-url',DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m  // Admin cfg url\u001b[39m\n\u001b[31m  const acu=await cfg('admin-cfg-url');if(acu&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=acu;\u001b[39m\n\u001b[31m  const su=await cfg('srv-url')||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su)document.getElementById('srv-url').value=su;\u001b[39m\n\u001b[31m  const sc=await cfg('stores');\u001b[39m\n\u001b[31m  if(sc){\u001b[39m\n\u001b[31m    stores=JSON.parse(sc);\u001b[39m\n\u001b[31m    const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m    document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m      `✓ ${stores.length} stores in cache${noBrand?` · ${noBrand} without brand`:''}`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const sf=await cfg('store-files');if(sf){_storeFiles=JSON.parse(sf);renderStoreFileList();}\u001b[39m\n\u001b[31m  const iq=await cfg('img-quality');imgQuality=iq||'compressed';applyQualityUI(imgQuality);\u001b[39m\n\u001b[31m  const gs=await cfg('geo-stamp');geoStampEnabled=(gs===null||gs==='1');applyGeoStampUI();\u001b[39m\n\u001b[31m  const bl=await cfg('brands');if(bl)brands=JSON.parse(bl);\u001b[39m\n\u001b[31m  loadBrandsFromDb();  // async — updates brands + logos from DB in background\u001b[39m\n\u001b[31m  renderBrandManageList();\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m  // Show store upload row + brand add row to supervisors only\u001b[39m\n\u001b[31m  const sur = document.getElementById('store-upload-row');\u001b[39m\n\u001b[31m  if (sur) sur.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const bar = document.getElementById('brand-add-row');\u001b[39m\n\u001b[31m  if (bar) bar.style.display = _isSupervisor() ? 'flex' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction populateBrandDropdown(){\u001b[39m\n\u001b[31m  const sel=document.getElementById('f-brand');if(!sel)return;\u001b[39m\n\u001b[31m  const cur=sel.value;\u001b[39m\n\u001b[31m  sel.innerHTML='<option value=\\\"\\\">Select brand</option>'+brands.map(b=>`<option${cur===b?' selected':''}>${b}</option>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderBrandManageList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('brand-manage-list');if(!el)return;\u001b[39m\n\u001b[31m  const isSup=_isSupervisor();\u001b[39m\n\u001b[31m  el.innerHTML=brands.map((b,i)=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    const logoHtml=logo?`<img src=\\\"${logo}\\\" style=\\\"height:20px;max-width:48px;object-fit:contain;flex-shrink:0;border-radius:3px\\\">`:'';\u001b[39m\n\u001b[31m    const ctrlHtml=isSup?`<div style=\\\"display:flex;gap:2px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"openEditBrandDialog(${i})\\\" style=\\\"background:none;border:none;color:var(--nv);font-size:15px;cursor:pointer;padding:2px 6px\\\" title=\\\"Edit\\\">✏</button>\u001b[39m\n\u001b[31m      ${brands.length>1?`<button onclick=\\\"confirmRemoveBrand(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:2px 4px\\\">×</button>`:'<span style=\\\"font-size:11px;color:var(--g400);padding:0 6px\\\">Last</span>'}\u001b[39m\n\u001b[31m    </div>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;min-width:0\\\">${logoHtml}<span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${b}</span></div>\u001b[39m\n\u001b[31m      ${ctrlHtml}\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function addBrandToList(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const inp=document.getElementById('brand-add-inp');\u001b[39m\n\u001b[31m  const val=(inp.value.trim()||'').toUpperCase();\u001b[39m\n\u001b[31m  if(!val){toast('Enter a brand name','error');return;}\u001b[39m\n\u001b[31m  if(brands.some(b=>b.toLowerCase()===val.toLowerCase())){toast(`${val} already in list`,'error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands`,{method:'POST',headers:{..._RC_WRITE,'Prefer':'return=minimal'},body:JSON.stringify({name:val,sort_order:99})});\u001b[39m\n\u001b[31m    if(resp.status===409){toast(`${val} already exists in DB`,'error');return;}\u001b[39m\n\u001b[31m    if(!resp.ok){const e=await resp.json().catch(()=>({}));throw new Error(e.message||resp.status);}\u001b[39m\n\u001b[31m    inp.value='';\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${val} added ✓`,'success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Add failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmRemoveBrand(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const name=brands[idx];\u001b[39m\n\u001b[31m  if(brands.length<=1){toast('Need at least one brand','error');return;}\u001b[39m\n\u001b[31m  let count=0;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(name)}&select=sub_id`,{headers:_RC_READ});\u001b[39m\n\u001b[31m    if(r.ok){const rows=await r.json();count=rows.length;}\u001b[39m\n\u001b[31m  }catch(_){}\u001b[39m\n\u001b[31m  const msg=count>0?`Delete \\\"${name}\\\" from brand list?\\\\n(${count} submission${count!==1?'s':''} reference this brand — they keep the name as text.)`:`Delete \\\"${name}\\\" from brand list?`;\u001b[39m\n\u001b[31m  if(!confirm(msg))return;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(name)}`,{method:'DELETE',headers:{'Content-Profile':'recce','Accept-Profile':'recce'}});\u001b[39m\n\u001b[31m    if(!resp.ok&&resp.status!==204){throw new Error(resp.status);}\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${name} removed ✓`,'info');\u001b[39m\n\u001b[31m  }catch(e){toast(`Remove failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadBrandsFromDb(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch('/db/brands?select=name,logo_url&order=sort_order',{\u001b[39m\n\u001b[31m      headers:{'Content-Profile':'recce','Accept-Profile':'recce'}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(!r.ok) return;\u001b[39m\n\u001b[31m    const rows=await r.json();\u001b[39m\n\u001b[31m    if(!rows||!rows.length) return;\u001b[39m\n\u001b[31m    const dbNames=rows.map(r=>r.name);\u001b[39m\n\u001b[31m    const logos={};rows.forEach(r=>{if(r.logo_url)logos[r.name]=r.logo_url;});\u001b[39m\n\u001b[31m    // Merge: DB brands canonical, keep locally-added extras\u001b[39m\n\u001b[31m    const extras=brands.filter(b=>!dbNames.some(n=>n.toLowerCase()===b.toLowerCase()));\u001b[39m\n\u001b[31m    brands=[...dbNames,...extras];\u001b[39m\n\u001b[31m    _brandLogos=logos;\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    // Refresh brand chips if brand-selector is visible\u001b[39m\n\u001b[31m    const bSel=document.getElementById('brand-selector');\u001b[39m\n\u001b[31m    if(bSel&&bSel.style.display!=='none') renderBrandChips();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[brands-db]',e.message);}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction renderBrandChips(){\u001b[39m\n\u001b[31m  const bChips=document.getElementById('brand-chips');if(!bChips)return;\u001b[39m\n\u001b[31m  bChips.innerHTML=brands.map(b=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    return `<div class=\\\"chip brand-chip${F.brand===b?' sel':''}\\\" onclick=\\\"selectStoreBrand('${b.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\">` +\u001b[39m\n\u001b[31m      (logo?`<img src=\\\"${logo}\\\" class=\\\"brand-chip-logo\\\" alt=\\\"\\\">`:'') +\u001b[39m\n\u001b[31m      `<span>${b}</span></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _editBrandIdx=null,_editBrandOld=null;\u001b[39m\n\u001b[31mfunction openEditBrandDialog(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor())return;\u001b[39m\n\u001b[31m  _editBrandIdx=idx;_editBrandOld=brands[idx];\u001b[39m\n\u001b[31m  document.getElementById('be-name').value=brands[idx];\u001b[39m\n\u001b[31m  const logo=_brandLogos[brands[idx]]||'';\u001b[39m\n\u001b[31m  document.getElementById('be-logo').value=logo;\u001b[39m\n\u001b[31m  document.getElementById('be-logo-preview').innerHTML=logo?`<img src=\\\"${logo}\\\" style=\\\"height:28px;object-fit:contain\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Current logo</span>`:'';\u001b[39m\n\u001b[31m  document.getElementById('be-cascade-info').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('brand-edit-modal').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeBrandEditModal(){document.getElementById('brand-edit-modal').classList.remove('open');_editBrandIdx=null;_editBrandOld=null;}\u001b[39m\n\u001b[31mfunction previewBrandLogo(){\u001b[39m\n\u001b[31m  const url=(document.getElementById('be-logo')?.value||'').trim();\u001b[39m\n\u001b[31m  const prev=document.getElementById('be-logo-preview');\u001b[39m\n\u001b[31m  if(prev)prev.innerHTML=url?`<img src=\\\"${url}\\\" style=\\\"height:28px;object-fit:contain\\\" onerror=\\\"this.style.display='none'\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Preview</span>`:'';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveBrandEdit(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const oldName=_editBrandOld;\u001b[39m\n\u001b[31m  const newName=(document.getElementById('be-name').value||'').trim().toUpperCase();\u001b[39m\n\u001b[31m  const newLogo=(document.getElementById('be-logo').value||'').trim();\u001b[39m\n\u001b[31m  if(!newName){toast('Brand name required','error');return;}\u001b[39m\n\u001b[31m  const isRename=newName!==oldName;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // 1. Update recce.brands\u001b[39m\n\u001b[31m    const pResp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m      method:'PATCH',headers:{..._RC_WRITE,'Prefer':'return=minimal'},\u001b[39m\n\u001b[31m      body:JSON.stringify({name:newName,logo_url:newLogo||null})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(pResp.status===409){toast(`\\\"${newName}\\\" already exists`,'error');return;}\u001b[39m\n\u001b[31m    if(!pResp.ok&&pResp.status!==204){const e=await pResp.json().catch(()=>({}));throw new Error(e.message||pResp.status);}\u001b[39m\n\u001b[31m    if(isRename){\u001b[39m\n\u001b[31m      const hub=_recceHubUser();\u001b[39m\n\u001b[31m      // 2. Cascade to submissions\u001b[39m\n\u001b[31m      await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m        method:'PATCH',headers:_RC_WRITE,body:JSON.stringify({brand:newName})\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      // 3. Cascade to stores.json + view HTML files + PDFs\u001b[39m\n\u001b[31m      toast('Cascading rename to reports…','info');\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        const cResp=await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},\u001b[39m\n\u001b[31m          body:JSON.stringify({type:'cascade-rename-brand',oldName,newName,empId:hub?.empId||''})});\u001b[39m\n\u001b[31m        const cRes=cResp.ok?await cResp.json():{};\u001b[39m\n\u001b[31m        const msg=`Brand renamed ✓${cRes.viewsUpdated?` · ${cRes.viewsUpdated} reports re-queued`:''}`;\u001b[39m\n\u001b[31m        closeBrandEditModal();\u001b[39m\n\u001b[31m        await loadBrandsFromDb();\u001b[39m\n\u001b[31m        toast(msg,'success');\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }catch(e){console.warn('[cascade-rename]',e.message);}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeBrandEditModal();\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast('Brand updated ✓','success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Save failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function fetchServerBrands(){\u001b[39m\n\u001b[31m  const url=document.getElementById('brands-url')?.value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    toast('Fetching brands…','info');\u001b[39m\n\u001b[31m    const r=await fetch(url);const j=await r.json();\u001b[39m\n\u001b[31m    const list=Array.isArray(j)?j:j.brands||[];\u001b[39m\n\u001b[31m    if(!list.length){toast('No brands found in response','error');return;}\u001b[39m\n\u001b[31m    brands=list.map(b=>b.toString().toUpperCase());\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    toast(`${brands.length} brands loaded from server`,'success');\u001b[39m\n\u001b[31m  }catch{toast('Failed to fetch — check URL','error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setImgQuality(q){\u001b[39m\n\u001b[31m  imgQuality=q;\u001b[39m\n\u001b[31m  cfg('img-quality',q);\u001b[39m\n\u001b[31m  applyQualityUI(q);\u001b[39m\n\u001b[31m  toast(q==='hd'?'HD Quality selected (~400–600 KB per photo)':'Full Compression selected (~150–200 KB per photo)','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction applyQualityUI(q){\u001b[39m\n\u001b[31m  ['compressed','hd'].forEach(opt=>{\u001b[39m\n\u001b[31m    const label=document.getElementById('q-opt-'+opt);\u001b[39m\n\u001b[31m    const radio=document.getElementById('q-radio-'+opt);\u001b[39m\n\u001b[31m    const dot  =document.getElementById('q-dot-'+opt);\u001b[39m\n\u001b[31m    if(!label)return;\u001b[39m\n\u001b[31m    const active=opt===q;\u001b[39m\n\u001b[31m    label.style.borderColor=active?'var(--or)':'var(--g200)';\u001b[39m\n\u001b[31m    label.style.background=active?'#fff7ed':'var(--g50)';\u001b[39m\n\u001b[31m    if(radio)radio.style.borderColor=active?'var(--or)':'var(--g300)';\u001b[39m\n\u001b[31m    if(dot)dot.style.display=active?'block':'none';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const badge=document.getElementById('q-current-badge');\u001b[39m\n\u001b[31m  if(badge){\u001b[39m\n\u001b[31m    const label=q==='hd'?'HD Quality (~400–600 KB)':'Full Compression (~150–200 KB)';\u001b[39m\n\u001b[31m    badge.innerHTML=`Active: <strong>${label}</strong>`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function clearData(){if(!confirm('Delete ALL local data?'))return;const all=await dbAll('subs');for(const s of all)await dbDel('subs',s.id);stores=[];await cfg('stores',null);toast('All cleared','success');loadHome();}\u001b[39m\n\u001b[31mif('serviceWorker' in navigator){const sw=`const C='recce-v37';self.addEventListener('install',e=>{e.waitUntil(caches.open(C).then(c=>c.add('/')));self.skipWaiting();});self.addEventListener('activate',e=>e.waitUntil(clients.claim()));self.addEventListener('fetch',e=>{if(e.request.method!=='GET')return;e.respondWith(caches.match(e.request).then(r=>{if(r)return r;return fetch(e.request).then(res=>{if(res&&res.status===200&&res.type==='basic'){const cl=res.clone();caches.open(C).then(c=>c.put(e.request,cl));}return res;}).catch(()=>caches.match('/'));}))}); `;const blob=new Blob([sw],{type:'application/javascript'});navigator.serviceWorker.register(URL.createObjectURL(blob),{scope:'/'}).catch(()=>{});}·\u001b[39m\n\u001b[31m// ── GEOLOCATION STAMP ────────────────────────────────────────\u001b[39m\n\u001b[31mfunction applyGeoStampUI(){\u001b[39m\n\u001b[31m  const tog=document.getElementById('geo-tog');\u001b[39m\n\u001b[31m  if(tog)tog.classList.toggle('on',geoStampEnabled);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function toggleGeoStamp(){\u001b[39m\n\u001b[31m  geoStampEnabled=!geoStampEnabled;\u001b[39m\n\u001b[31m  await cfg('geo-stamp',geoStampEnabled?'1':'0');\u001b[39m\n\u001b[31m  applyGeoStampUI();\u001b[39m\n\u001b[31m  toast(geoStampEnabled?'Geolocation stamp enabled':'Geolocation stamp disabled','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Auto-request GPS silently when a new recce starts\u001b[39m\n\u001b[31mfunction autoRequestGPS(){\u001b[39m\n\u001b[31m  if(!navigator.geolocation)return;\u001b[39m\n\u001b[31m  const statusEl=document.getElementById('geo-status');\u001b[39m\n\u001b[31m  if(statusEl)statusEl.textContent='Acquiring GPS…';\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(\u001b[39m\n\u001b[31m    pos=>{\u001b[39m\n\u001b[31m      gpsCoords={\u001b[39m\n\u001b[31m        lat:pos.coords.latitude.toFixed(6),\u001b[39m\n\u001b[31m        lng:pos.coords.longitude.toFixed(6),\u001b[39m\n\u001b[31m        acc:Math.round(pos.coords.accuracy)\u001b[39m\n\u001b[31m      };\u001b[39m\n\u001b[31m      const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m      const quality=acc<=15?'Excellent':acc<=50?'Good':acc<=200?'Fair':'Poor (cell tower)';\u001b[39m\n\u001b[31m      const color=acc<=15?'var(--gn)':acc<=50?'#16a34a':acc<=200?'var(--am)':'var(--rd)';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.innerHTML=`GPS: ${gpsCoords.lat}, ${gpsCoords.lng} · ±${acc}m · <span style=\\\"color:${color};font-weight:600\\\">${quality}</span>`;\u001b[39m\n\u001b[31m      // Update form GPS status too\u001b[39m\n\u001b[31m      const fs=document.getElementById('gps-status');\u001b[39m\n\u001b[31m      if(fs){fs.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${acc}m)`;fs.style.color='var(--gn)';}\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    err=>{\u001b[39m\n\u001b[31m      const msgs={1:'Location permission denied in Chrome',2:'GPS signal unavailable',3:'GPS timed out'};\u001b[39m\n\u001b[31m      const msg=msgs[err.code]||'GPS unavailable';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.textContent=msg+' — stamp will use store address';\u001b[39m\n\u001b[31m      if(err.code===1)toast('Tap the lock icon in Chrome address bar → allow Location','info');\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    {enableHighAccuracy:true,timeout:20000,maximumAge:60000}\u001b[39m\n\u001b[31m  );\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Draw stamp on a photo blob — returns new blob with stamp baked in\u001b[39m\n\u001b[31mfunction roundRectPath(ctx,x,y,w,h,r){\u001b[39m\n\u001b[31m  ctx.beginPath();ctx.moveTo(x+r,y);ctx.lineTo(x+w-r,y);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y,x+w,y+r);ctx.lineTo(x+w,y+h-r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);ctx.lineTo(x+r,y+h);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y+h,x,y+h-r);ctx.lineTo(x,y+r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y,x+r,y);ctx.closePath();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction fitText(ctx,text,maxW){\u001b[39m\n\u001b[31m  if(ctx.measureText(text).width<=maxW)return text;\u001b[39m\n\u001b[31m  while(text.length>1&&ctx.measureText(text+'…').width>maxW)text=text.slice(0,-1);\u001b[39m\n\u001b[31m  return text+'…';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction stampPhoto(blob){\u001b[39m\n\u001b[31m  if(!geoStampEnabled)return Promise.resolve(blob);\u001b[39m\n\u001b[31m  return new Promise(res=>{\u001b[39m\n\u001b[31m    const img=new Image(),url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    img.onload=()=>{\u001b[39m\n\u001b[31m      URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m      const W=img.width,H=img.height;\u001b[39m\n\u001b[31m      const c=document.createElement('canvas');c.width=W;c.height=H;\u001b[39m\n\u001b[31m      const ctx=c.getContext('2d');\u001b[39m\n\u001b[31m      ctx.drawImage(img,0,0);·\u001b[39m\n\u001b[31m      // Stamp dimensions — 18% of image height\u001b[39m\n\u001b[31m      const SH=Math.round(H*0.18);\u001b[39m\n\u001b[31m      const pad=Math.round(W*0.03);\u001b[39m\n\u001b[31m      const SY=H-SH;·\u001b[39m\n\u001b[31m      // Semi-transparent background\u001b[39m\n\u001b[31m      ctx.fillStyle='rgba(10,18,35,0.78)';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,SH);·\u001b[39m\n\u001b[31m      // Orange top accent line\u001b[39m\n\u001b[31m      ctx.fillStyle='#f97316';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,Math.max(3,Math.round(H*0.004)));·\u001b[39m\n\u001b[31m      // Font sizes scaled to image\u001b[39m\n\u001b[31m      const f1=Math.round(SH*0.26); // store name\u001b[39m\n\u001b[31m      const f2=Math.round(SH*0.22); // coords / address\u001b[39m\n\u001b[31m      const f3=Math.round(SH*0.20); // timestamp·\u001b[39m\n\u001b[31m      // Row Y centres\u001b[39m\n\u001b[31m      const r1=SY+SH*0.26;\u001b[39m\n\u001b[31m      const r2=SY+SH*0.55;\u001b[39m\n\u001b[31m      const r3=SY+SH*0.82;·\u001b[39m\n\u001b[31m      // Get stamp data\u001b[39m\n\u001b[31m      const storeName=F.storeName||selectedStore?.name||'';\u001b[39m\n\u001b[31m      const brand=F.brand||selectedStore?.brand||'';\u001b[39m\n\u001b[31m      const addr=F.address||selectedStore?.address||'';\u001b[39m\n\u001b[31m      const now=new Date();\u001b[39m\n\u001b[31m      const dateStr=now.toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m      const timeStr=now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit',hour12:true});·\u001b[39m\n\u001b[31m      // Badge (right side — GPS quality)\u001b[39m\n\u001b[31m      let badgeLabel='',badgeColor='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m        if(acc<=15){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=50){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=200){badgeLabel='~'+acc+'m';badgeColor='#d97706';}\u001b[39m\n\u001b[31m        else{badgeLabel='Cell ~'+acc+'m';badgeColor='#dc2626';}\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        badgeLabel='No GPS';badgeColor='#64748b';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      const bFontSz=Math.round(SH*0.18);\u001b[39m\n\u001b[31m      ctx.font=`bold ${bFontSz}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      const bW=Math.round(ctx.measureText(badgeLabel).width+pad);\u001b[39m\n\u001b[31m      const bH=Math.round(SH*0.32);\u001b[39m\n\u001b[31m      const bX=W-bW-pad;const bY=SY+(SH-bH)/2;\u001b[39m\n\u001b[31m      ctx.fillStyle=badgeColor+'cc';\u001b[39m\n\u001b[31m      roundRectPath(ctx,bX,bY,bW,bH,4);ctx.fill();\u001b[39m\n\u001b[31m      ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';\u001b[39m\n\u001b[31m      ctx.fillText(badgeLabel,bX+bW/2,bY+bH/2);\u001b[39m\n\u001b[31m      ctx.textAlign='left';ctx.textBaseline='alphabetic';·\u001b[39m\n\u001b[31m      const textMaxW=bX-pad*2;·\u001b[39m\n\u001b[31m      // Row 1 — store name + brand\u001b[39m\n\u001b[31m      ctx.font=`bold ${f1}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#ffffff';\u001b[39m\n\u001b[31m      const nameText=storeName+(brand?' · '+brand:'');\u001b[39m\n\u001b[31m      ctx.fillText('📍 '+fitText(ctx,nameText,textMaxW-f1*1.4),pad,r1);·\u001b[39m\n\u001b[31m      // Row 2 — GPS coords OR address\u001b[39m\n\u001b[31m      ctx.font=`${f2}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#cbd5e1';\u001b[39m\n\u001b[31m      let row2='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        row2=`Lat ${gpsCoords.lat}°   Long ${gpsCoords.lng}°`;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        row2=addr?fitText(ctx,addr,textMaxW):'GPS coordinates unavailable';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      ctx.fillText(row2,pad,r2);·\u001b[39m\n\u001b[31m      // Row 3 — date and time\u001b[39m\n\u001b[31m      ctx.font=`${f3}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#94a3b8';\u001b[39m\n\u001b[31m      ctx.fillText(`${dateStr}   ${timeStr}`,pad,r3);·\u001b[39m\n\u001b[31m      c.toBlob(b=>res(b||blob),'image/jpeg',imgQuality==='hd'?0.88:0.82);\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    img.onerror=()=>{URL.revokeObjectURL(url);res(blob);};\u001b[39m\n\u001b[31m    img.src=url;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _aTool='rect',_aColor='#f97316',_aWidth=4,_aTarget=-1;\u001b[39m\n\u001b[31mlet _aImg=null,_aHistory=[],_aDrawing=false,_aStart={},_aPts=[];\u001b[39m\n\u001b[31mlet _aSel=-1,_aDragMode=null,_aDragOff={x:0,y:0};\u001b[39m\n\u001b[31m// Larger hit radius on touch devices for easier finger selection\u001b[39m\n\u001b[31mconst HIT_R=()=>('ontouchstart' in window)?32:16;·\u001b[39m\n\u001b[31mfunction setATool(t){\u001b[39m\n\u001b[31m  _aTool=t;\u001b[39m\n\u001b[31m  ['rect','ellipse','line','arrow','free'].forEach(id=>{const el=document.getElementById('at-'+id);if(el)el.classList.toggle('on',id===t&&t!=='move');});\u001b[39m\n\u001b[31m  const mv=document.getElementById('at-move');if(mv)mv.classList.toggle('sel-on',t==='move');\u001b[39m\n\u001b[31m  const info=document.getElementById('annot-sel-info');if(info)info.style.display=t==='move'?'block':'none';\u001b[39m\n\u001b[31m  if(t!=='move'){_aSel=-1;redrawAnnot();}\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(cvs)cvs.style.cursor=t==='move'?'default':'crosshair';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAColor(c){\u001b[39m\n\u001b[31m  _aColor=c;\u001b[39m\n\u001b[31m  const m={'#f97316':'or','#ef4444':'rd','#ffffff':'wh','#facc15':'yw','#22c55e':'gn'};\u001b[39m\n\u001b[31m  Object.entries(m).forEach(([col,id])=>{const el=document.getElementById('ac-'+id);if(el)el.classList.toggle('on',col===c);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAWidth(w){_aWidth=w;[2,4,7].forEach(v=>{const el=document.getElementById('aw-'+v);if(el)el.classList.toggle('on',v===w);});}·\u001b[39m\n\u001b[31mfunction openAnnot(idx){\u001b[39m\n\u001b[31m  _aTarget=idx;_aHistory=[];_aDrawing=false;_aPts=[];_aSel=-1;_aDragMode=null;\u001b[39m\n\u001b[31m  document.getElementById('annot-modal').classList.add('open');\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');\u001b[39m\n\u001b[31m  const img=new Image(),url=URL.createObjectURL(brandings[idx].blob);\u001b[39m\n\u001b[31m  img.onload=()=>{\u001b[39m\n\u001b[31m    const sc=Math.min(1,window.innerWidth/img.width,(window.innerHeight-185)/img.height);\u001b[39m\n\u001b[31m    cvs.width=Math.round(img.width*sc);cvs.height=Math.round(img.height*sc);\u001b[39m\n\u001b[31m    _aImg=img;redrawAnnot();URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  img.src=url;\u001b[39m\n\u001b[31m  cvs.ontouchstart=aDown;cvs.ontouchmove=aMove;cvs.ontouchend=aUp;\u001b[39m\n\u001b[31m  cvs.onmousedown=aDown;cvs.onmousemove=aMove;cvs.onmouseup=aUp;\u001b[39m\n\u001b[31m  setATool('rect');setAColor('#f97316');setAWidth(4);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aPos(e){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const r=cvs.getBoundingClientRect();\u001b[39m\n\u001b[31m  const src=e.touches?e.touches[0]:e;\u001b[39m\n\u001b[31m  return{x:(src.clientX-r.left)*(cvs.width/r.width),y:(src.clientY-r.top)*(cvs.height/r.height)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Always return normalised (positive w,h) bounds\u001b[39m\n\u001b[31mfunction sBounds(s){\u001b[39m\n\u001b[31m  if(s.type==='free'){\u001b[39m\n\u001b[31m    if(!s.pts||!s.pts.length)return null;\u001b[39m\n\u001b[31m    const xs=s.pts.map(p=>p.x),ys=s.pts.map(p=>p.y);\u001b[39m\n\u001b[31m    const x=Math.min(...xs),y=Math.min(...ys);\u001b[39m\n\u001b[31m    return{x,y,w:Math.max(...xs)-x,h:Math.max(...ys)-y};\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  return{x:Math.min(s.x,s.x+s.w),y:Math.min(s.y,s.y+s.h),w:Math.abs(s.w),h:Math.abs(s.h)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction hitHandle(px,py,s){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return null;\u001b[39m\n\u001b[31m  const b=sBounds(s);const hr=HIT_R();\u001b[39m\n\u001b[31m  for(const[n,x,y]of[['tl',b.x,b.y],['tr',b.x+b.w,b.y],['bl',b.x,b.y+b.h],['br',b.x+b.w,b.y+b.h]])\u001b[39m\n\u001b[31m    if(Math.hypot(px-x,py-y)<hr)return n;\u001b[39m\n\u001b[31m  return null;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction hitShape(px,py,s){\u001b[39m\n\u001b[31m  const b=sBounds(s);if(!b)return false;\u001b[39m\n\u001b[31m  const pad=HIT_R();\u001b[39m\n\u001b[31m  return px>=b.x-pad&&px<=b.x+b.w+pad&&py>=b.y-pad&&py<=b.y+b.h+pad;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aDown(e){\u001b[39m\n\u001b[31m  e.preventDefault();const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'){\u001b[39m\n\u001b[31m    // Check handles of selected shape first\u001b[39m\n\u001b[31m    if(_aSel>=0&&_aSel<_aHistory.length){\u001b[39m\n\u001b[31m      const h=hitHandle(p.x,p.y,_aHistory[_aSel]);\u001b[39m\n\u001b[31m      if(h){_aDragMode='r-'+h;_aDragOff={x:p.x,y:p.y};_aDrawing=true;return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Hit test all shapes topmost first\u001b[39m\n\u001b[31m    for(let i=_aHistory.length-1;i>=0;i--){\u001b[39m\n\u001b[31m      if(hitShape(p.x,p.y,_aHistory[i])){\u001b[39m\n\u001b[31m        _aSel=i;_aDragMode='move';\u001b[39m\n\u001b[31m        const s=_aHistory[i];\u001b[39m\n\u001b[31m        const b=sBounds(s);\u001b[39m\n\u001b[31m        // Store offset from shape top-left corner (normalised)\u001b[39m\n\u001b[31m        _aDragOff={x:p.x-b.x,y:p.y-b.y};\u001b[39m\n\u001b[31m        _aDrawing=true;redrawAnnot();return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    _aSel=-1;redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _aDrawing=true;_aStart={x:p.x,y:p.y};if(_aTool==='free')_aPts=[{x:p.x,y:p.y}];\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aMove(e){\u001b[39m\n\u001b[31m  e.preventDefault();if(!_aDrawing)return;const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'&&_aDragMode){\u001b[39m\n\u001b[31m    const s=_aHistory[_aSel];if(!s)return;\u001b[39m\n\u001b[31m    if(_aDragMode==='move'){\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      // New top-left position\u001b[39m\n\u001b[31m      const nx=p.x-_aDragOff.x;\u001b[39m\n\u001b[31m      const ny=p.y-_aDragOff.y;\u001b[39m\n\u001b[31m      const dx=nx-b.x,dy=ny-b.y;\u001b[39m\n\u001b[31m      if(s.type==='free'){\u001b[39m\n\u001b[31m        s.pts=s.pts.map(pt=>({x:pt.x+dx,y:pt.y+dy}));\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        // Move preserving w/h sign (don't normalise — keep original drawing direction)\u001b[39m\n\u001b[31m        s.x+=dx;s.y+=dy;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Resize from corner — always work on normalised bounds then re-apply\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      const n=_aDragMode.slice(2);\u001b[39m\n\u001b[31m      let nx=b.x,ny=b.y,nw=b.w,nh=b.h;\u001b[39m\n\u001b[31m      if(n==='br'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,p.y-b.y);}\u001b[39m\n\u001b[31m      else if(n==='tl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,b.y+b.h-p.y);nx=p.x;ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='tr'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,b.y+b.h-p.y);ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='bl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,p.y-b.y);nx=p.x;}\u001b[39m\n\u001b[31m      s.x=nx;s.y=ny;s.w=nw;s.h=nh; // store as normalised going forward\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if(_aTool==='free'){_aPts.push({x:p.x,y:p.y});redrawAnnot();drawSh({type:'free',pts:[..._aPts],color:_aColor,lw:_aWidth},true);return;}\u001b[39m\n\u001b[31m  redrawAnnot();drawSh({type:_aTool,x:_aStart.x,y:_aStart.y,w:p.x-_aStart.x,h:p.y-_aStart.y,color:_aColor,lw:_aWidth},true);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction aUp(e){\u001b[39m\n\u001b[31m  if(!_aDrawing)return;_aDrawing=false;\u001b[39m\n\u001b[31m  if(_aTool==='move'){_aDragMode=null;return;}\u001b[39m\n\u001b[31m  const p=aPos(e||{touches:[{clientX:0,clientY:0}]});\u001b[39m\n\u001b[31m  if(_aTool==='free'){if(_aPts.length>2){_aHistory.push({type:'free',pts:[..._aPts],x:_aPts[0].x,y:_aPts[0].y,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  else{const w=p.x-_aStart.x,h=p.y-_aStart.y;if(Math.abs(w)>4||Math.abs(h)>4){_aHistory.push({type:_aTool,x:_aStart.x,y:_aStart.y,w,h,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  _aPts=[];redrawAnnot();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction redrawAnnot(){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.clearRect(0,0,cvs.width,cvs.height);if(_aImg)ctx.drawImage(_aImg,0,0,cvs.width,cvs.height);\u001b[39m\n\u001b[31m  _aHistory.forEach((s,i)=>{drawSh(s,false,ctx);if(_aTool==='move'&&i===_aSel)drawHandles(s,ctx);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawHandles(s,ctx){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return;const b=sBounds(s);ctx.save();\u001b[39m\n\u001b[31m  ctx.setLineDash([5,3]);ctx.strokeStyle='#facc15';ctx.lineWidth=1.5;ctx.strokeRect(b.x-2,b.y-2,b.w+4,b.h+4);ctx.setLineDash([]);\u001b[39m\n\u001b[31m  [[b.x,b.y],[b.x+b.w,b.y],[b.x,b.y+b.h],[b.x+b.w,b.y+b.h]].forEach(([x,y])=>{ctx.beginPath();ctx.arc(x,y,7,0,2*Math.PI);ctx.fillStyle='#f97316';ctx.fill();ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();});\u001b[39m\n\u001b[31m  ctx.restore();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawSh(s,preview=false,ctx){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(!ctx)ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.save();ctx.strokeStyle=s.color;ctx.lineWidth=preview?Math.max(s.lw||4,2):s.lw||4;\u001b[39m\n\u001b[31m  ctx.lineCap='round';ctx.lineJoin='round';ctx.setLineDash(preview?[6,3]:[]);\u001b[39m\n\u001b[31m  if(s.type==='rect'){ctx.strokeRect(s.x,s.y,s.w,s.h);ctx.fillStyle=s.color+'28';ctx.fillRect(s.x,s.y,s.w,s.h);}\u001b[39m\n\u001b[31m  else if(s.type==='ellipse'){const cx=s.x+s.w/2,cy=s.y+s.h/2;ctx.beginPath();ctx.ellipse(cx,cy,Math.abs(s.w/2),Math.abs(s.h/2),0,0,2*Math.PI);ctx.stroke();ctx.fillStyle=s.color+'28';ctx.fill();}\u001b[39m\n\u001b[31m  else if(s.type==='line'){ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(s.x+s.w,s.y+s.h);ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='arrow'){const ex=s.x+s.w,ey=s.y+s.h;ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(ex,ey);ctx.stroke();const a=Math.atan2(s.h,s.w),al=20,aa=0.4;ctx.setLineDash([]);ctx.beginPath();ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a-aa),ey-al*Math.sin(a-aa));ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a+aa),ey-al*Math.sin(a+aa));ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='free'){if(s.pts.length<2){ctx.restore();return;}ctx.beginPath();s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));ctx.stroke();}\u001b[39m\n\u001b[31m  ctx.setLineDash([]);ctx.restore();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction undoAnnot(){if(_aHistory.length){_aHistory.pop();_aSel=Math.min(_aSel,_aHistory.length-1);redrawAnnot();}}\u001b[39m\n\u001b[31mfunction clearAnnot(){_aHistory=[];_aSel=-1;redrawAnnot();}·\u001b[39m\n\u001b[31m// Bottom dialog\u001b[39m\n\u001b[31mlet _bdCb=null;\u001b[39m\n\u001b[31mfunction showBDialog(title,sub,onYes){\u001b[39m\n\u001b[31m  document.getElementById('bdialog-title').textContent=title;\u001b[39m\n\u001b[31m  document.getElementById('bdialog-sub').textContent=sub;\u001b[39m\n\u001b[31m  _bdCb=onYes;document.getElementById('bdialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction bdialogYes(){document.getElementById('bdialog').classList.remove('open');if(_bdCb)_bdCb();_bdCb=null;}\u001b[39m\n\u001b[31mfunction bdialogNo(){document.getElementById('bdialog').classList.remove('open');_bdCb=null;}·\u001b[39m\n\u001b[31mfunction _afterBrandingPhoto(){\u001b[39m\n\u001b[31m  const idx=_aTarget;\u001b[39m\n\u001b[31m  showBDialog(t(`Add reference photos for Branding ${idx+1}?`,`ब्रांडिंग ${idx+1} के लिए अतिरिक्त फोटो?`),t('Optional extra photos for future reference.','वैकल्पिक — भविष्य के लिए अतिरिक्त फोटो।'),()=>{showView('form-additional');setTimeout(()=>addAdditional(),200);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction skipAnnot(){document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo added (${fmtSz(brandings[_aTarget].blob.size)})`,'success');_afterBrandingPhoto();}\u001b[39m\n\u001b[31mfunction saveAnnot(){const cvs=document.getElementById('annot-cvs');cvs.toBlob(blob=>{brandings[_aTarget].blob=blob;brandings[_aTarget].prev=URL.createObjectURL(blob);document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo + markup saved (${fmtSz(blob.size)})`,'success');_afterBrandingPhoto();},'image/jpeg',0.88);}·\u001b[39m\n\u001b[31m// ── VIEW RECCE (read-only) ──────────────────────────────────\u001b[39m\n\u001b[31masync function viewRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  // Synced entries have a server-side rich report — open it directly\u001b[39m\n\u001b[31m  if(entry.viewUrl){window.open(entry.viewUrl,'_blank');return;}\u001b[39m\n\u001b[31m  // Offline / not-yet-synced fallback: generate from local base64 data\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  const ts=new Date(entry.timestamp).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'});·\u001b[39m\n\u001b[31m  async function b64ToUrl(b64){if(!b64)return'';try{const r=await fetch(b64);const bl=await r.blob();return URL.createObjectURL(bl);}catch{return'';}}·\u001b[39m\n\u001b[31m  const fvUrls=await Promise.all((d.frontPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const ivUrls=await Promise.all((d.insidePhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const brUrls=await Promise.all((d.brandings||[]).map(b=>b64ToUrl(b.photoB64)));\u001b[39m\n\u001b[31m  const adUrls=await Promise.all((d.addlPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const docUrl=await b64ToUrl(d.docB64);·\u001b[39m\n\u001b[31m  const brRows=(d.brandings||[]).map((b,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:16px;padding:12px;background:#f8fafc;border-radius:8px;border-left:3px solid #f97316\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-weight:600;font-size:14px;color:#0f172a;margin-bottom:6px\\\">${i+1}. ${b.type||'—'}: ${b.w||'?'}\\\"×${b.h||'?'}\\\" · Qty: ${b.qty||'?'} · ${b.sqft||'?'}</div>\u001b[39m\n\u001b[31m      ${brUrls[i]?`<img src=\\\"${brUrls[i]}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:6px\\\">`:'<div style=\\\"color:#94a3b8;font-size:12px\\\">No photo</div>'}\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  const html=`<!DOCTYPE html><html><head><meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m  <title>Recce — ${d.storeName||'Unknown'}</title>\u001b[39m\n\u001b[31m  <style>body{font-family:Arial,sans-serif;margin:0;padding:16px;background:#f1f5f9}\u001b[39m\n\u001b[31m  .card{background:#fff;border-radius:12px;padding:16px;margin-bottom:14px;box-shadow:0 1px 4px rgba(0,0,0,.08)}\u001b[39m\n\u001b[31m  h1{font-size:18px;color:#0f172a;margin:0 0 4px}h2{font-size:14px;color:#f97316;text-transform:uppercase;letter-spacing:.5px;margin:0 0 10px}\u001b[39m\n\u001b[31m  .meta{font-size:12px;color:#64748b;margin-bottom:12px}.photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}\u001b[39m\n\u001b[31m  img{width:100%;border-radius:8px;object-fit:cover}\u001b[39m\n\u001b[31m  .tag{display:inline-block;background:#0f172a;color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-right:4px}\u001b[39m\n\u001b[31m  @media print{body{background:#fff}.card{box-shadow:none}}</style></head><body>\u001b[39m\n\u001b[31m  <div class=\\\"card\\\">\u001b[39m\n\u001b[31m    <h1>${d.storeName||'Unknown Store'}</h1>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\"><span class=\\\"tag\\\">${d.brand||'No Brand'}</span>${d.address||''}</div>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\">📞 ${d.mobile||'—'} &nbsp;|&nbsp; 📅 ${d.date||'—'} &nbsp;|&nbsp; Submitted: ${ts}</div>\u001b[39m\n\u001b[31m    ${d.gpsCoords?`<div class=\\\"meta\\\">📍 ${d.gpsCoords.lat}, ${d.gpsCoords.lng} ±${d.gpsCoords.acc}m</div>`:''}\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${fvUrls.length?`<div class=\\\"card\\\"><h2>Front View Photos</h2><div class=\\\"photos\\\">${fvUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${ivUrls.length?`<div class=\\\"card\\\"><h2>Inside View Photos</h2><div class=\\\"photos\\\">${ivUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${d.hasVideo?`<div class=\\\"card\\\"><h2>Video</h2><div>${d.videoNote||'Video recorded'}</div></div>`:''}\u001b[39m\n\u001b[31m  ${(d.brandings||[]).length?`<div class=\\\"card\\\"><h2>Branding Items (${(d.brandings||[]).length})</h2>${brRows}</div>`:''}\u001b[39m\n\u001b[31m  ${adUrls.length?`<div class=\\\"card\\\"><h2>Additional Photos</h2><div class=\\\"photos\\\">${adUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${docUrl?`<div class=\\\"card\\\"><h2>Submission Document</h2><img src=\\\"${docUrl}\\\" style=\\\"width:100%;max-height:300px;object-fit:contain\\\"></div>`:''}\u001b[39m\n\u001b[31m  <div style=\\\"text-align:center;margin:16px 0\\\">\u001b[39m\n\u001b[31m    <button onclick=\\\"window.print()\\\" style=\\\"background:#f97316;color:#fff;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer\\\">🖨 Print / Save as PDF</button>\u001b[39m\n\u001b[31m    <button onclick=\\\"window.close()\\\" style=\\\"background:#e2e8f0;color:#475569;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer;margin-left:10px\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  </body></html>`;\u001b[39m\n\u001b[31m  const blob=new Blob([html],{type:'text/html'});\u001b[39m\n\u001b[31m  const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m  window.open(url,'_blank');\u001b[39m\n\u001b[31m  setTimeout(()=>URL.revokeObjectURL(url),30000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── EDIT OLD RECCE ───────────────────────────────────────────\u001b[39m\n\u001b[31masync function editRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=d.gpsCoords||null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  F.editingId=id;F.date=d.date||'';F.brand=d.brand||'';F.storeName=d.storeName||'';F.address=d.address||'';F.mobile=d.mobile||'';F.hasVideo=d.hasVideo;F.hasBranding=d.hasBranding;\u001b[39m\n\u001b[31m  async function b64ToBlob(b64){if(!b64)return null;try{const r=await fetch(b64);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m  toast('Loading recce data…','info');\u001b[39m\n\u001b[31m  for(const p of(d.frontPhotos||[])){const b=await b64ToBlob(p.b64);if(b)frontPhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const p of(d.insidePhotos||[])){const b=await b64ToBlob(p.b64);if(b)insidePhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const br of(d.brandings||[])){const b=await b64ToBlob(br.photoB64);brandings.push({type:br.type,w:br.w,h:br.h,qty:br.qty,blob:b,prev:b?URL.createObjectURL(b):null});}\u001b[39m\n\u001b[31m  for(const p of(d.addlPhotos||[])){const b=await b64ToBlob(p.b64);if(b)addlPhotos.push({blob:b,prev:URL.createObjectURL(b),desc:p.desc||''});}\u001b[39m\n\u001b[31m  if(d.docB64){const b=await b64ToBlob(d.docB64);if(b){submissionDoc=b;const sl=document.getElementById('doc-slot');sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${URL.createObjectURL(b)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}}\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  if(F.brand)document.getElementById('f-brand').value=F.brand;\u001b[39m\n\u001b[31m  if(F.storeName)document.getElementById('f-store').value=F.storeName;\u001b[39m\n\u001b[31m  if(F.address)document.getElementById('f-addr').value=F.address;\u001b[39m\n\u001b[31m  if(F.mobile)document.getElementById('f-mobile').value=F.mobile;\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();updAvailTag();\u001b[39m\n\u001b[31m  toast('Recce loaded — make changes and re-submit','success');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── EDIT REQUEST ────────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mlet _editReqSubId = null;·\u001b[39m\n\u001b[31mfunction _hydratePhotosFromRow(r) {\u001b[39m\n\u001b[31m  let pu={};\u001b[39m\n\u001b[31m  try{pu=typeof r.photo_urls==='string'?JSON.parse(r.photo_urls):(r.photo_urls||{});}catch(_){}\u001b[39m\n\u001b[31m  let meta={};\u001b[39m\n\u001b[31m  try{meta=typeof r.meta==='string'?JSON.parse(r.meta):(r.meta||{});}catch(_){}\u001b[39m\n\u001b[31m  frontPhotos =(pu.front   ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  insidePhotos=(pu.inside  ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  addlPhotos  =(pu.addl    ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,desc:''}));\u001b[39m\n\u001b[31m  brandings   =(meta.brandings||[]).map((b,i)=>({type:b.type,w:b.w,h:b.h,qty:b.qty,existingUrl:(pu.brandings||[])[i]||null,blob:null,prev:(pu.brandings||[])[i]||null}));\u001b[39m\n\u001b[31m  _docExistingUrl=pu.doc||null;\u001b[39m\n\u001b[31m  // Show retained doc in slot\u001b[39m\n\u001b[31m  const sl=document.getElementById('doc-slot');\u001b[39m\n\u001b[31m  if(sl&&_docExistingUrl){sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${_docExistingUrl}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openEditRequestModal(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  _editReqSubId = subId;\u001b[39m\n\u001b[31m  document.getElementById('er-store-name').textContent = r.store_name || 'Unknown';\u001b[39m\n\u001b[31m  document.getElementById('er-comment').value = '';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const assignBtn = document.getElementById('er-assign-btn');\u001b[39m\n\u001b[31m  if (r.submitted_by && r.submitted_by !== hub?.empId) {\u001b[39m\n\u001b[31m    assignBtn.textContent = `👤 Assign to ${r.submitted_by}`;\u001b[39m\n\u001b[31m    assignBtn.style.display = '';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    assignBtn.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeEditRequestModal() {\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _editReqSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorEditMyself() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  // Lock branding if client has reviewed (preserve their approval)\u001b[39m\n\u001b[31m  _brandingLocked = !!(r.client_status && r.client_status !== 'pending');\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function assignEditToCreator() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r || !r.submitted_by) { toast('No creator found for this recce', 'error'); return; }\u001b[39m\n\u001b[31m  const comment = (document.getElementById('er-comment').value || '').trim();\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        status: 'edit_requested',\u001b[39m\n\u001b[31m        edit_assigned_to: r.submitted_by,\u001b[39m\n\u001b[31m        edit_comment: comment || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!resp.ok) throw new Error('Update failed: ' + resp.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].status = 'edit_requested';\u001b[39m\n\u001b[31m      _adminRows[idx].edit_assigned_to = r.submitted_by;\u001b[39m\n\u001b[31m      _adminRows[idx].edit_comment = comment || null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Push notification to creator\u001b[39m\n\u001b[31m    const notifBody = comment || `Please review and re-submit: ${r.store_name || 'your recce'}`;\u001b[39m\n\u001b[31m    fetch('/push-server/notify', {\u001b[39m\n\u001b[31m      method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        user_id: r.submitted_by, title: '✏ Edit Requested',\u001b[39m\n\u001b[31m        body: notifBody, tag: `recce-edit-${subId}`, url: '/recce/',\u001b[39m\n\u001b[31m        icon: '/hub/icons/icon-192.png', badge: '/hub/icons/icon-192.png',\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    }).catch(() => {});\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast(`Edit assigned to ${r.submitted_by} ✓`, 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Assign failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function startCreatorEdit(subId) {\u001b[39m\n\u001b[31m  // Try local IndexedDB first (has photos)\u001b[39m\n\u001b[31m  const local = await dbGet('subs', subId);\u001b[39m\n\u001b[31m  if (local) { await editRecce(subId); return; }\u001b[39m\n\u001b[31m  // Fallback: load text fields from server row\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId)\u001b[39m\n\u001b[31m         || (await (async () => {\u001b[39m\n\u001b[31m              try {\u001b[39m\n\u001b[31m                const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, { headers: _RC_READ });\u001b[39m\n\u001b[31m                if (resp.ok) { const arr = await resp.json(); return arr[0]; }\u001b[39m\n\u001b[31m              } catch(_) {} return null;\u001b[39m\n\u001b[31m            })());\u001b[39m\n\u001b[31m  if (!r) { toast('Record not found', 'error'); return; }\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── End edit request ─────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mfunction goToHub() { window.location.href = '/hub/'; }\u001b[39m\n\u001b[31mfunction recceLogout() {\u001b[39m\n\u001b[31m  if (!confirm('Log out?')) return;\u001b[39m\n\u001b[31m  localStorage.removeItem('lm360-session');\u001b[39m\n\u001b[31m  localStorage.removeItem('360exp-session');\u001b[39m\n\u001b[31m  window.location.href = '/hub/';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction injectHubButtons() {\u001b[39m\n\u001b[31m  const u = _recceHubUser();\u001b[39m\n\u001b[31m  const name = u ? (u.name || '') : '';\u001b[39m\n\u001b[31m  if (name) {\u001b[39m\n\u001b[31m    const bar = document.getElementById('recce-hero-ubar');\u001b[39m\n\u001b[31m    const nm  = document.getElementById('recce-hero-name');\u001b[39m\n\u001b[31m    if (bar) { nm.textContent = name; bar.style.display = 'flex'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.querySelectorAll('.hdr').forEach(hdr => {\u001b[39m\n\u001b[31m    const r = document.createElement('div');\u001b[39m\n\u001b[31m    r.className = 'hdr-r';\u001b[39m\n\u001b[31m    if (name) {\u001b[39m\n\u001b[31m      const un = document.createElement('span');\u001b[39m\n\u001b[31m      un.className = 'hdr-user';\u001b[39m\n\u001b[31m      un.textContent = name;\u001b[39m\n\u001b[31m      r.appendChild(un);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    const hub = document.createElement('button');\u001b[39m\n\u001b[31m    hub.className = 'btn-hub';\u001b[39m\n\u001b[31m    hub.innerHTML = '🏡 Hub';\u001b[39m\n\u001b[31m    hub.addEventListener('click', goToHub);\u001b[39m\n\u001b[31m    r.appendChild(hub);\u001b[39m\n\u001b[31m    const lo = document.createElement('button');\u001b[39m\n\u001b[31m    lo.className = 'btn-logout';\u001b[39m\n\u001b[31m    lo.textContent = 'Logout';\u001b[39m\n\u001b[31m    lo.addEventListener('click', recceLogout);\u001b[39m\n\u001b[31m    r.appendChild(lo);\u001b[39m\n\u001b[31m    hdr.appendChild(r);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction checkAppUpdate(){\u001b[39m\n\u001b[31m  const seen=localStorage.getItem('recce-ver-seen');\u001b[39m\n\u001b[31m  localStorage.setItem('recce-ver-seen',CACHE_VER);\u001b[39m\n\u001b[31m  if(seen&&seen!==CACHE_VER){\u001b[39m\n\u001b[31m    const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m    if(b){b.classList.add('show');setTimeout(()=>b.classList.remove('show'),5000);}\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction dismissUpdateBanner(){\u001b[39m\n\u001b[31m  const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m  if(b)b.classList.remove('show');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function init(){\u001b[39m\n\u001b[31m  // Detect host banners (tiiny.host, etc) and raise bnav above them\u001b[39m\n\u001b[31m  (function detectHostBar(){\u001b[39m\n\u001b[31m    const h=window.location.hostname;\u001b[39m\n\u001b[31m    let extra=0;\u001b[39m\n\u001b[31m    if(h.includes('tiiny'))extra=58;\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // Generic detection: check if window is shorter than expected (host injected a bar)\u001b[39m\n\u001b[31m      const gap=screen.height - window.innerHeight;\u001b[39m\n\u001b[31m      if(gap>100&&gap<200)extra=58; // a fixed bar is roughly 56-60px\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if(extra>0){\u001b[39m\n\u001b[31m      document.documentElement.style.setProperty('--host-bar',extra+'px');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  })();\u001b[39m\n\u001b[31m  setLang(LANG);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m  checkAppUpdate();\u001b[39m\n\u001b[31m  await loadRecceCfg();\u001b[39m\n\u001b[31m  _checkAccessMode();\u001b[39m\n\u001b[31m  await initDB();await loadSettings();await loadHome();await checkDraft();netStatus();window.addEventListener('online',()=>{netStatus();syncNow();});window.addEventListener('offline',netStatus);injectHubButtons();document.getElementById('today-date').textContent=new Date().toLocaleDateString('en-IN',{weekday:'long',day:'numeric',month:'long',year:'numeric'});updAvailTag();\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m  // Auto-fetch stores from server on every startup (uses default Netlify URL if none saved)\u001b[39m\n\u001b[31m  const su=(await cfg('srv-url'))||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su&&navigator.onLine){\u001b[39m\n\u001b[31m    fetch(su).then(r=>r.json()).then(async j=>{\u001b[39m\n\u001b[31m      const d=Array.isArray(j)?j:j.stores||[];\u001b[39m\n\u001b[31m      if(d.length){stores=d;await cfg('stores',JSON.stringify(d));await cfg('srv-url',su);updAvailTag();\u001b[39m\n\u001b[31m        document.getElementById('srv-url').value=su;}\u001b[39m\n\u001b[31m    }).catch(()=>{});\u001b[39m\n\u001b[31m  }}init();\u001b[39m\n\u001b[31m</script>\u001b[39m\n\u001b[31m</body>\u001b[39m\n\u001b[31m</html>\u001b[39m\n\u001b[31m\"\u001b[39m\n    at /var/www/360lm/tests/recce.spec.js:337:17",
                        "location": {
                          "file": "/var/www/360lm/tests/recce.spec.js",
                          "column": 17,
                          "line": 337
                        },
                        "snippet": "  335 |     const resp = await page.request.get(BASE_URL);\n  336 |     const src = await resp.text();\n> 337 |     expect(src).toContain('recce-v15');\n      |                 ^\n  338 |     expect(src).not.toContain('recce-v14');\n  339 |   });\n  340 | });"
                      },
                      "errors": [
                        {
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "column": 17,
                            "line": 337
                          },
                          "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoContain\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // indexOf\u001b[22m\n\nExpected substring: \u001b[32m\"recce-v15\"\u001b[39m\nReceived string:    \u001b[31m\"<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\">\u001b[39m\n\u001b[31m<head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\">\u001b[39m\n\u001b[31m<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\\\">\u001b[39m\n\u001b[31m<meta name=\\\"theme-color\\\" content=\\\"#0f172a\\\">\u001b[39m\n\u001b[31m<meta name=\\\"apple-mobile-web-app-capable\\\" content=\\\"yes\\\">\u001b[39m\n\u001b[31m<title>Branding Recce</title>\u001b[39m\n\u001b[31m<link rel=\\\"manifest\\\" href=\\\"manifest.json\\\">\u001b[39m\n\u001b[31m<link rel=\\\"preconnect\\\" href=\\\"https://fonts.googleapis.com\\\">\u001b[39m\n\u001b[31m<link href=\\\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap\\\" rel=\\\"stylesheet\\\">\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--nv:#0f172a;--nv2:#1e293b;--or:#f97316;--orl:#fed7aa;--gn:#16a34a;--rd:#dc2626;--am:#d97706;--g50:#f8fafc;--g100:#f1f5f9;--g200:#e2e8f0;--g300:#cbd5e1;--g400:#94a3b8;--g500:#64748b;--g600:#475569;--r:12px;--rs:8px;--sh:0 1px 3px rgba(0,0,0,.1),0 1px 2px rgba(0,0,0,.06);--bnav-h:72px;--host-bar:0px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}\u001b[39m\n\u001b[31mbody{font-family:'DM Sans',sans-serif;background:var(--g50);color:var(--nv);min-height:100vh;overflow-x:hidden}\u001b[39m\n\u001b[31m.hdr{background:var(--nv);color:#fff;padding:0 16px;height:56px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}\u001b[39m\n\u001b[31m.hdr-l{display:flex;align-items:center;gap:10px}\u001b[39m\n\u001b[31m.hdr-title{font-size:16px;font-weight:600}.hdr-sub{font-size:11px;color:var(--g400)}\u001b[39m\n\u001b[31m.back-btn,.icon-btn{background:none;border:none;color:#fff;padding:8px;cursor:pointer;display:flex;align-items:center}\u001b[39m\n\u001b[31m.back-btn{margin-left:-8px}\u001b[39m\n\u001b[31m.pgbar{height:3px;background:var(--g200)}.pgfill{height:100%;background:var(--or);transition:width .3s}\u001b[39m\n\u001b[31m.view{display:none;min-height:calc(100vh - 56px);padding-bottom:calc(var(--bnav-h) + var(--host-bar) + 24px)}.view.active{display:block}\u001b[39m\n\u001b[31m.content{padding:16px}\u001b[39m\n\u001b[31m.card{background:#fff;border-radius:var(--r);padding:16px;box-shadow:var(--sh);margin-bottom:12px}\u001b[39m\n\u001b[31m.card-title{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;letter-spacing:.6px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between}\u001b[39m\n\u001b[31m.cnt-badge{background:var(--or);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;min-width:22px;text-align:center}\u001b[39m\n\u001b[31m.cnt-badge.gray{background:var(--g400)}\u001b[39m\n\u001b[31m.field{margin-bottom:16px}.field:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.field label{display:block;font-size:13px;font-weight:500;color:var(--g600);margin-bottom:6px}\u001b[39m\n\u001b[31m.req{color:var(--or);margin-left:2px}\u001b[39m\n\u001b[31m.field input,.field select,.field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;color:var(--nv);background:#fff;transition:border-color .15s;-webkit-appearance:none;appearance:none}\u001b[39m\n\u001b[31m.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--or)}\u001b[39m\n\u001b[31m.field input:read-only{background:var(--g50);color:var(--g600)}\u001b[39m\n\u001b[31m.field textarea{resize:vertical;min-height:68px}\u001b[39m\n\u001b[31m.field select{background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}\u001b[39m\n\u001b[31m.pslot{border:2px dashed var(--g300);border-radius:var(--r);min-height:110px;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all .15s;position:relative;overflow:hidden;text-align:center;padding:16px}\u001b[39m\n\u001b[31m.pslot:active{border-color:var(--or);background:var(--g50)}\u001b[39m\n\u001b[31m.pslot.filled{border-style:solid;border-color:var(--or);padding:0;min-height:0}\u001b[39m\n\u001b[31m.pslot img{width:100%;height:150px;object-fit:cover;border-radius:calc(var(--r) - 2px);display:block}\u001b[39m\n\u001b[31m.pslot-lbl{font-size:13px;color:var(--g400);margin-top:6px}.pslot-ico{font-size:28px;color:var(--g300)}\u001b[39m\n\u001b[31m.pbadge{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.premove{position:absolute;top:6px;right:6px;background:var(--rd);color:#fff;border:none;border-radius:50%;width:26px;height:26px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;z-index:5}\u001b[39m\n\u001b[31minput[type=file]{display:none}\u001b[39m\n\u001b[31m.rgroup{display:flex;gap:10px}\u001b[39m\n\u001b[31m.rbtn{flex:1;padding:13px;border:1.5px solid var(--g200);border-radius:var(--rs);text-align:center;cursor:pointer;font-size:14px;font-weight:500;color:var(--g500);transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.rbtn.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.chip-grid{display:flex;flex-wrap:wrap;gap:8px}\u001b[39m\n\u001b[31m.chip{padding:7px 12px;border:1.5px solid var(--g200);border-radius:20px;font-size:13px;color:var(--g600);cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.chip.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.brand-chip{display:flex;align-items:center;gap:6px;padding:5px 12px}\u001b[39m\n\u001b[31m.brand-chip-logo{width:28px;height:18px;object-fit:contain;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{display:block;width:100%;padding:15px;background:var(--or);color:#fff;border:none;border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:700;cursor:pointer;text-align:center;transition:background .15s}\u001b[39m\n\u001b[31m.btn-p:active{background:#ea6c05}.btn-p:disabled{background:var(--g300);cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-s{display:block;width:100%;padding:14px;background:#fff;color:var(--nv);border:1.5px solid var(--g200);border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:500;cursor:pointer;text-align:center}\u001b[39m\n\u001b[31m.btn-s:active{background:var(--g100)}\u001b[39m\n\u001b[31m.btn-o{display:inline-flex;align-items:center;gap:6px;padding:10px 16px;background:#fff;color:var(--or);border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer}\u001b[39m\n\u001b[31m.btn-o:active{background:var(--orl)}\u001b[39m\n\u001b[31m.btn-d{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;background:#fff;color:var(--rd);border:1.5px solid #fecaca;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:12px;cursor:pointer}\u001b[39m\n\u001b[31m.bnav{position:fixed;bottom:var(--host-bar);left:0;right:0;background:#fff;border-top:1px solid var(--g200);display:flex;padding:10px 16px;gap:10px;z-index:100}\u001b[39m\n\u001b[31m.hero{background:var(--nv);color:#fff;padding:20px 16px 24px}\u001b[39m\n\u001b[31m.hero-title{font-size:22px;font-weight:700;margin-bottom:2px}.hero-sub{font-size:13px;color:var(--g400)}\u001b[39m\n\u001b[31m.stats{display:flex;gap:10px;margin-top:16px}\u001b[39m\n\u001b[31m.scard{flex:1;background:rgba(255,255,255,.08);border-radius:var(--rs);padding:12px;text-align:center}\u001b[39m\n\u001b[31m.snum{font-size:22px;font-weight:700}.slbl{font-size:11px;color:var(--g400);margin-top:2px}\u001b[39m\n\u001b[31m.scard.g .snum{color:#4ade80}.scard.a .snum{color:#fbbf24}\u001b[39m\n\u001b[31m.new-btn{background:var(--or);color:#fff;border:none;border-radius:var(--r);padding:16px;font-family:'DM Sans',sans-serif;font-size:16px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:10px;cursor:pointer;width:100%;margin-bottom:10px}\u001b[39m\n\u001b[31m.new-btn:active{background:#ea6c05}\u001b[39m\n\u001b[31m.resume-btn{background:var(--nv2);color:#fff;border:none;border-radius:var(--r);padding:13px 16px;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;display:flex;align-items:center;justify-content:space-between;cursor:pointer;width:100%;margin-bottom:18px}\u001b[39m\n\u001b[31m.sub-card{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:10px;display:flex;align-items:center;gap:12px}\u001b[39m\n\u001b[31m.sub-ico{width:40px;height:40px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}\u001b[39m\n\u001b[31m.sub-ico.pending{background:#fef3c7}.sub-ico.synced{background:#dcfce7}.sub-ico.failed{background:#fee2e2}\u001b[39m\n\u001b[31m.sub-meta{flex:1;min-width:0}.sub-name{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.sub-dtl{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.sbadge{font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;flex-shrink:0}\u001b[39m\n\u001b[31m.sbadge.pending{background:#fef3c7;color:#92400e}.sbadge.synced{background:#dcfce7;color:#14532d}.sbadge.failed{background:#fee2e2;color:#991b1b}\u001b[39m\n\u001b[31m.sh{display:flex;align-items:center;justify-content:space-between;margin:20px 0 12px}\u001b[39m\n\u001b[31m.st{font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.toast{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 8px);left:16px;right:16px;background:var(--nv);color:#fff;padding:12px 16px;border-radius:var(--r);font-size:14px;z-index:1000;transform:translateY(120px);opacity:0;transition:all .3s;pointer-events:none}\u001b[39m\n\u001b[31m.toast.show{transform:translateY(0);opacity:1}.toast.success{background:#16a34a}.toast.error{background:var(--rd)}.toast.info{background:var(--nv2)}\u001b[39m\n\u001b[31m.srow{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:#fff;border-top:1px solid var(--g100);font-size:12px;color:var(--g500)}\u001b[39m\n\u001b[31m.sdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px}.sdot.on{background:var(--gn)}.sdot.off{background:var(--g300)}\u001b[39m\n\u001b[31m.set-item{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:8px}\u001b[39m\n\u001b[31m.set-lbl{font-size:14px;font-weight:600;color:var(--nv);margin-bottom:4px}\u001b[39m\n\u001b[31m.set-sub{font-size:12px;color:var(--g500);margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem{background:#fff;border-radius:var(--r);border:1.5px solid var(--g200);padding:14px;margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\u001b[39m\n\u001b[31m.bitem-title{font-size:14px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.dim-row{display:flex;gap:8px}.dim-row .field{flex:1}\u001b[39m\n\u001b[31m.sqft{display:inline-block;background:var(--g100);color:var(--g600);font-size:12px;padding:4px 10px;border-radius:20px;margin-top:6px}\u001b[39m\n\u001b[31m.divider{height:1px;background:var(--g100);margin:12px 0}\u001b[39m\n\u001b[31m.rev-lbl{font-size:12px;color:var(--g500);margin-bottom:2px}\u001b[39m\n\u001b[31m.rev-val{font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.rev-photos{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}\u001b[39m\n\u001b[31m.rev-thumb{width:56px;height:56px;object-fit:cover;border-radius:var(--rs)}\u001b[39m\n\u001b[31m.empty{text-align:center;padding:40px 20px;color:var(--g400)}.empty-ico{font-size:40px;margin-bottom:12px}.empty-txt{font-size:14px}\u001b[39m\n\u001b[31m/* store picker */\u001b[39m\n\u001b[31m.store-card{border:1.5px solid var(--g200);border-radius:var(--rs);padding:13px 14px;background:#fff;position:relative;cursor:pointer}\u001b[39m\n\u001b[31m.store-card:active{background:var(--g50)}\u001b[39m\n\u001b[31m.store-card-name{font-size:15px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.store-card-meta{font-size:13px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.store-card-change{position:absolute;top:11px;right:12px;background:none;border:none;color:var(--or);font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer}\u001b[39m\n\u001b[31m.brand-tag{display:inline-block;background:var(--nv);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-top:4px}\u001b[39m\n\u001b[31m.last-chip{display:inline-flex;align-items:center;gap:4px;background:#fef3c7;color:#92400e;font-size:11px;font-weight:500;padding:3px 9px;border-radius:20px;margin-left:6px}\u001b[39m\n\u001b[31m.pick-trigger{border:2px solid var(--or);border-radius:var(--rs);padding:14px 16px;background:#fff7ed;display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-size:15px;font-weight:600;color:var(--or)}\u001b[39m\n\u001b[31m.pick-trigger:active{background:#ffedd5;border-color:#ea6800}\u001b[39m\n\u001b[31m.manual-toggle{display:flex;align-items:center;gap:8px;padding:10px 14px;border:1.5px dashed var(--g300);border-radius:var(--rs);cursor:pointer;font-size:13px;color:var(--g600);margin-top:8px;user-select:none}\u001b[39m\n\u001b[31m/* client chip grid */\u001b[39m\n\u001b[31m.cl-chip-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}\u001b[39m\n\u001b[31m.cl-chip{padding:8px 14px;border-radius:20px;border:1.5px solid var(--g200);font-size:13px;font-weight:500;color:var(--g600);background:#fff;cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.cl-chip:active,.cl-chip.sel{background:var(--or);border-color:var(--or);color:#fff;font-weight:600}\u001b[39m\n\u001b[31m.cl-chip-other{border-style:dashed}\u001b[39m\n\u001b[31m.client-tag{display:inline-block;background:#e0f2fe;color:#0369a1;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-left:4px}\u001b[39m\n\u001b[31m.manual-toggle.on{border-color:var(--or);background:#fff7ed;color:var(--or)}\u001b[39m\n\u001b[31m/* picker overlay */\u001b[39m\n\u001b[31m.povl{display:none;position:fixed;inset:0;background:var(--g50);z-index:200;flex-direction:column}\u001b[39m\n\u001b[31m.povl.open{display:flex}\u001b[39m\n\u001b[31m.povl-hdr{background:var(--nv);padding:12px 16px;display:flex;align-items:center;gap:12px;flex-shrink:0}\u001b[39m\n\u001b[31m.psearch{flex:1;padding:10px 14px;border:none;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;background:rgba(255,255,255,.12);color:#fff;outline:none}\u001b[39m\n\u001b[31m.psearch::placeholder{color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.pcancel{background:none;border:none;color:rgba(255,255,255,.7);font-family:'DM Sans',sans-serif;font-size:14px;cursor:pointer;padding:4px;white-space:nowrap}\u001b[39m\n\u001b[31m.plist{overflow-y:auto;flex:1}\u001b[39m\n\u001b[31m.pitem{padding:14px 16px;border-bottom:.5px solid var(--g100);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px}\u001b[39m\n\u001b[31m.pitem:active{background:var(--g100)}\u001b[39m\n\u001b[31m.pi-name{font-size:15px;font-weight:600;color:var(--nv)}.pi-addr{font-size:12px;color:var(--g500);margin-top:2px}.pi-last{font-size:11px;color:var(--am);margin-top:2px}\u001b[39m\n\u001b[31m.pi-brand{font-size:11px;font-weight:700;padding:3px 8px;border-radius:20px;background:var(--nv);color:#fff;flex-shrink:0}\u001b[39m\n\u001b[31m.psec{padding:8px 16px 4px;font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;background:var(--g50)}\u001b[39m\n\u001b[31m.padd{padding:16px;text-align:center;font-size:14px;color:var(--or);font-weight:600;cursor:pointer;background:#fff7ed;border-top:1.5px dashed var(--or)}\u001b[39m\n\u001b[31m.gps-row{display:flex;gap:8px;margin-top:8px}\u001b[39m\n\u001b[31m.gps-btn{flex-shrink:0;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;color:var(--g500);display:flex;align-items:center;gap:6px}\u001b[39m\n\u001b[31m.gps-btn:active{background:var(--orl);border-color:var(--or);color:var(--or)}\u001b[39m\n\u001b[31m@keyframes spin{to{transform:rotate(360deg)}}.spin{animation:spin .7s linear infinite;display:inline-block}\u001b[39m\n\u001b[31m/* ANNOTATION TOOL */\u001b[39m\n\u001b[31m.annot-modal{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column}\u001b[39m\n\u001b[31m.annot-modal.open{display:flex}\u001b[39m\n\u001b[31m.annot-bar{background:var(--nv);padding:8px 12px;flex-shrink:0}\u001b[39m\n\u001b[31m.annot-row{display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap}\u001b[39m\n\u001b[31m.annot-row:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.atool{padding:6px 10px;background:rgba(255,255,255,.1);border:1.5px solid rgba(255,255,255,.2);border-radius:var(--rs);color:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:500;cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.atool.on{background:var(--or);border-color:var(--or)}\u001b[39m\n\u001b[31m.atool.sel-on{background:#7c3aed;border-color:#7c3aed}\u001b[39m\n\u001b[31m.acolor{width:24px;height:24px;border-radius:50%;border:2px solid rgba(255,255,255,.3);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.acolor.on{border-color:#fff;border-width:3px;transform:scale(1.15)}\u001b[39m\n\u001b[31m.annot-cvs-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#111;position:relative}\u001b[39m\n\u001b[31m#annot-cvs{max-width:100%;max-height:100%;display:block;touch-action:none;cursor:crosshair}\u001b[39m\n\u001b[31m.annot-foot{background:var(--nv);padding:10px 16px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.req-note{font-size:12px;color:var(--rd);margin-top:6px;font-weight:500}\u001b[39m\n\u001b[31m/* Bottom dialog */\u001b[39m\n\u001b[31m.bdialog-wrap{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:400;align-items:flex-end}\u001b[39m\n\u001b[31m.bdialog-wrap.open{display:flex}\u001b[39m\n\u001b[31m.bdialog{background:#fff;border-radius:var(--r) var(--r) 0 0;padding:20px 16px 32px;width:100%}\u001b[39m\n\u001b[31m.bdialog-title{font-size:16px;font-weight:700;color:var(--nv);margin-bottom:6px}\u001b[39m\n\u001b[31m.bdialog-sub{font-size:13px;color:var(--g500);margin-bottom:16px}\u001b[39m\n\u001b[31m.bdialog-btns{display:flex;gap:10px}\u001b[39m\n\u001b[31m/* Edit badge on sub-card */\u001b[39m\n\u001b[31m.edit-btn-sm{padding:5px 12px;background:var(--g50);border:1px solid var(--g200);border-radius:20px;font-family:'DM Sans',sans-serif;font-size:12px;color:var(--g600);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m/* Toggle switch */\u001b[39m\n\u001b[31m.tog{width:48px;height:26px;background:var(--g300);border-radius:13px;cursor:pointer;transition:background .2s;flex-shrink:0;position:relative;display:inline-block}\u001b[39m\n\u001b[31m.tog.on{background:var(--or)}\u001b[39m\n\u001b[31m.tog-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2);pointer-events:none}\u001b[39m\n\u001b[31m.tog.on .tog-knob{transform:translateX(22px)}\u001b[39m\n\u001b[31m/* ── ADMIN RECCE VIEW ── */\u001b[39m\n\u001b[31m.af-bar{background:var(--g100);padding:10px 16px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--g200);overflow:hidden}\u001b[39m\n\u001b[31m.af-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}\u001b[39m\n\u001b[31m.af-sel{width:100%;padding:8px 10px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv);cursor:pointer;\u001b[39m\n\u001b[31m  white-space:normal;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.af-sel:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.af-inp{width:100%;padding:8px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv)}\u001b[39m\n\u001b[31m.af-inp:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.grp-hdr{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;\u001b[39m\n\u001b[31m  letter-spacing:.5px;padding:14px 0 6px;border-bottom:1px solid var(--g200);margin-bottom:6px}\u001b[39m\n\u001b[31m.grp-hdr:first-child{padding-top:0}\u001b[39m\n\u001b[31m.asc{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:12px 14px;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;gap:6px;margin-bottom:8px;cursor:pointer;\u001b[39m\n\u001b[31m  transition:box-shadow .15s}\u001b[39m\n\u001b[31m.asc:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.asc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}\u001b[39m\n\u001b[31m.asc-name{font-size:14px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.asc-brand{display:inline-block;background:#fff7ed;color:var(--or);font-size:11px;\u001b[39m\n\u001b[31m  font-weight:600;padding:2px 8px;border-radius:20px;border:1px solid #fed7aa;white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chip{background:var(--g100);border-radius:20px;padding:2px 8px;font-size:11px;color:var(--g600);white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chips{display:flex;flex-wrap:wrap;gap:5px}\u001b[39m\n\u001b[31m.asc-agent{background:var(--nv);color:#fff;font-size:11px;font-weight:600;\u001b[39m\n\u001b[31m  padding:2px 8px;border-radius:20px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m/* Admin detail modal */\u001b[39m\n\u001b[31m.ardl-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:600;\u001b[39m\n\u001b[31m  display:flex;align-items:flex-end;justify-content:center}\u001b[39m\n\u001b[31m.ardl-box{background:#fff;border-radius:var(--r) var(--r) 0 0;width:100%;max-height:80vh;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ardl-hdr{display:flex;align-items:flex-start;justify-content:space-between;\u001b[39m\n\u001b[31m  padding:16px 16px 10px;border-bottom:1px solid var(--g200);gap:10px}\u001b[39m\n\u001b[31m.ardl-title{font-size:17px;font-weight:700;color:var(--nv);line-height:1.3}\u001b[39m\n\u001b[31m.ardl-body{flex:1;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:14px}\u001b[39m\n\u001b[31m.ardl-sec{display:flex;flex-direction:column;gap:6px}\u001b[39m\n\u001b[31m.ardl-lbl{font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.ardl-val{font-size:13px;color:var(--nv);line-height:1.5}\u001b[39m\n\u001b[31m.ardl-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\u001b[39m\n\u001b[31m/* Hub home button */\u001b[39m\n\u001b[31m.btn-hub{background:none;border:1px solid rgba(255,255,255,.25);color:rgba(255,255,255,.85);\u001b[39m\n\u001b[31m  font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;cursor:pointer;\u001b[39m\n\u001b[31m  display:flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-hub:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hdr-r{display:flex;align-items:center;gap:6px;margin-left:auto;flex-shrink:0}\u001b[39m\n\u001b[31m.hdr-user{font-size:11px;color:rgba(255,255,255,.7);white-space:nowrap;max-width:80px;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.btn-logout{background:none;border:1px solid rgba(255,255,255,.2);color:rgba(255,255,255,.7);font-size:11px;font-weight:600;padding:4px 8px;border-radius:20px;cursor:pointer;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-logout:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hero-ubar{display:flex;align-items:center;justify-content:space-between;padding-top:6px;margin-top:2px}\u001b[39m\n\u001b[31m.hero-uname{font-size:12px;color:rgba(255,255,255,.65)}\u001b[39m\n\u001b[31m.hi-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .en-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .hi-txt{display:inline}\u001b[39m\n\u001b[31m.lang-btn{background:none;border:1px solid rgba(255,255,255,.3);color:rgba(255,255,255,.8);font-size:12px;font-weight:700;padding:4px 10px;border-radius:20px;cursor:pointer;display:flex;align-items:center;gap:3px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.lang-btn:active{background:rgba(255,255,255,.15)}\u001b[39m\n\u001b[31m/* ── DELETE / AUDIT ── */\u001b[39m\n\u001b[31m.del-btn{background:none;border:none;padding:6px 8px;cursor:pointer;color:var(--g400);font-size:16px;flex-shrink:0;border-radius:var(--rs);transition:color .15s,background .15s}\u001b[39m\n\u001b[31m.del-btn:active{color:var(--rd);background:#fee2e2}\u001b[39m\n\u001b[31m.asc.deleted-row{background:#fff5f5;border:1px solid #fecaca;opacity:.85}\u001b[39m\n\u001b[31m.asc.deleted-row .asc-name{text-decoration:line-through;color:var(--g500)}\u001b[39m\n\u001b[31m.del-reason-tag{display:inline-block;background:#fee2e2;color:var(--rd);font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.del-by-txt{font-size:11px;color:var(--g400);margin-top:3px}\u001b[39m\n\u001b[31m.restore-btn{background:none;border:1.5px solid #bbf7d0;border-radius:20px;color:#16a34a;font-size:11px;font-weight:700;padding:3px 10px;cursor:pointer;white-space:nowrap;margin-top:5px}\u001b[39m\n\u001b[31m.restore-btn:active{background:#dcfce7}\u001b[39m\n\u001b[31m.sup-tile{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:20px 16px;cursor:pointer;display:flex;align-items:center;gap:14px;margin-bottom:12px;transition:box-shadow .15s}\u001b[39m\n\u001b[31m.sup-tile:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.sup-tile-ico{width:48px;height:48px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:26px;flex-shrink:0}\u001b[39m\n\u001b[31m.sup-tile-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.sup-tile-title{font-size:15px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.sup-tile-sub{font-size:12px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.del-toggle-btn{padding:6px 14px;border:1.5px solid var(--g200);border-radius:20px;background:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:600;color:var(--g500);cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.del-toggle-btn.active{background:#fee2e2;border-color:#fecaca;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1.5px solid var(--g200);border-radius:var(--r);margin-bottom:10px;cursor:pointer;transition:all .15s;font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.reason-opt:active{background:var(--g50)}\u001b[39m\n\u001b[31m.reason-opt.sel{border-color:var(--rd);background:#fff5f5;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt.danger{border-color:#fdba74;background:#fff7ed;color:#9a3412}\u001b[39m\n\u001b[31m.reason-opt.danger.sel{border-color:#c2410c;background:#fff1e6;color:#9a3412}\u001b[39m\n\u001b[31m#del-confirm-btn.no-reason{background:var(--g300)!important;cursor:default}\u001b[39m\n\u001b[31m@keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}\u001b[39m\n\u001b[31m.reason-opt-ico{font-size:22px;flex-shrink:0}\u001b[39m\n\u001b[31m/* ── APP UPDATE BANNER ── */\u001b[39m\n\u001b[31m.upd-banner{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);left:12px;right:12px;background:#16a34a;color:#fff;padding:11px 14px;border-radius:var(--r);display:flex;align-items:center;justify-content:space-between;gap:10px;z-index:550;box-shadow:0 4px 16px rgba(0,0,0,.18);transform:translateY(120px);opacity:0;transition:transform .35s ease,opacity .35s ease;pointer-events:none}\u001b[39m\n\u001b[31m.upd-banner.show{transform:translateY(0);opacity:1;pointer-events:auto}\u001b[39m\n\u001b[31m/* ── EDIT REQUEST ── */\u001b[39m\n\u001b[31m.req-edit-btn{padding:4px 10px;background:#fffbeb;border:1px solid #fde68a;border-radius:20px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:600;color:#92400e;cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.req-edit-btn:active{background:#fef3c7}\u001b[39m\n\u001b[31m.edit-req-badge{display:inline-block;background:#fef3c7;color:#92400e;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;white-space:nowrap}\u001b[39m\n\u001b[31m.edit-req-card{background:#fffbeb;border:1.5px solid #fde68a;border-radius:var(--r);padding:14px 16px;margin-bottom:10px;display:flex;align-items:flex-start;gap:12px}\u001b[39m\n\u001b[31m.edit-req-card-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.edit-req-card-name{font-size:14px;font-weight:600;color:var(--nv);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.edit-req-card-meta{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.edit-req-cmt{font-size:12px;color:#78350f;background:#fff;border:1px solid #fde68a;border-radius:var(--rs);padding:8px 10px;margin-top:8px;line-height:1.5}\u001b[39m\n\u001b[31m.edit-req-section-hdr{font-size:11px;font-weight:700;color:#92400e;text-transform:uppercase;letter-spacing:.5px;padding:10px 0 6px;border-bottom:1px solid #fde68a;margin-bottom:8px}\u001b[39m\n\u001b[31m.upd-banner-ok{background:rgba(255,255,255,.2);border:none;color:#fff;border-radius:20px;padding:5px 13px;font-size:12px;font-weight:600;cursor:pointer;font-family:'DM Sans',sans-serif;white-space:nowrap}\u001b[39m\n\u001b[31m.upd-banner-ok:active{background:rgba(255,255,255,.35)}\u001b[39m\n\u001b[31m/* ── FONT SIZE WIDGET ── */\u001b[39m\n\u001b[31m.fs-widget{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);right:12px;display:flex;align-items:center;gap:0;background:#fff;border:1.5px solid var(--g200);border-radius:24px;box-shadow:0 2px 8px rgba(0,0,0,.12);z-index:500;overflow:hidden;user-select:none}\u001b[39m\n\u001b[31m.fs-btn{background:none;border:none;cursor:pointer;padding:7px 11px;color:var(--g500);line-height:1;transition:background .15s}\u001b[39m\n\u001b[31m.fs-btn:active{background:var(--g100)}\u001b[39m\n\u001b[31m.fs-btn:disabled{color:var(--g300);cursor:default}\u001b[39m\n\u001b[31m.fs-label{font-size:11px;font-weight:700;color:var(--g500);padding:0 4px;pointer-events:none}\u001b[39m\n\u001b[31m/* Level 1 — Large (+15%) */\u001b[39m\n\u001b[31mbody.fs-1 .field label,body.fs-1 .card-title,body.fs-1 .set-lbl,body.fs-1 .set-sub,\u001b[39m\n\u001b[31mbody.fs-1 .hdr-title,body.fs-1 .hdr-sub,body.fs-1 .slbl,body.fs-1 .rev-lbl,body.fs-1 .rev-val,\u001b[39m\n\u001b[31mbody.fs-1 .rbtn,body.fs-1 .chip,body.fs-1 .btn-p,body.fs-1 .btn-s,body.fs-1 .btn-o,\u001b[39m\n\u001b[31mbody.fs-1 .bdialog-title,body.fs-1 .bdialog-sub,body.fs-1 .sub-name,body.fs-1 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-1 .pslot-lbl,body.fs-1 .bitem-title,body.fs-1 .pi-name,body.fs-1 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-1 .asc-name,body.fs-1 .new-btn,body.fs-1 .resume-btn,body.fs-1 .ardl-lbl,body.fs-1 .ardl-val{font-size:calc(1em * 1.15) !important}\u001b[39m\n\u001b[31m/* Level 2 — X-Large (+30%) */\u001b[39m\n\u001b[31mbody.fs-2 .field label,body.fs-2 .card-title,body.fs-2 .set-lbl,body.fs-2 .set-sub,\u001b[39m\n\u001b[31mbody.fs-2 .hdr-title,body.fs-2 .hdr-sub,body.fs-2 .slbl,body.fs-2 .rev-lbl,body.fs-2 .rev-val,\u001b[39m\n\u001b[31mbody.fs-2 .rbtn,body.fs-2 .chip,body.fs-2 .btn-p,body.fs-2 .btn-s,body.fs-2 .btn-o,\u001b[39m\n\u001b[31mbody.fs-2 .bdialog-title,body.fs-2 .bdialog-sub,body.fs-2 .sub-name,body.fs-2 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-2 .pslot-lbl,body.fs-2 .bitem-title,body.fs-2 .pi-name,body.fs-2 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-2 .asc-name,body.fs-2 .new-btn,body.fs-2 .resume-btn,body.fs-2 .ardl-lbl,body.fs-2 .ardl-val{font-size:calc(1em * 1.30) !important}\u001b[39m\n\u001b[31m/* Level 3 — XX-Large (+50%) */\u001b[39m\n\u001b[31mbody.fs-3 .field label,body.fs-3 .card-title,body.fs-3 .set-lbl,body.fs-3 .set-sub,\u001b[39m\n\u001b[31mbody.fs-3 .hdr-title,body.fs-3 .hdr-sub,body.fs-3 .slbl,body.fs-3 .rev-lbl,body.fs-3 .rev-val,\u001b[39m\n\u001b[31mbody.fs-3 .rbtn,body.fs-3 .chip,body.fs-3 .btn-p,body.fs-3 .btn-s,body.fs-3 .btn-o,\u001b[39m\n\u001b[31mbody.fs-3 .bdialog-title,body.fs-3 .bdialog-sub,body.fs-3 .sub-name,body.fs-3 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-3 .pslot-lbl,body.fs-3 .bitem-title,body.fs-3 .pi-name,body.fs-3 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-3 .asc-name,body.fs-3 .new-btn,body.fs-3 .resume-btn,body.fs-3 .ardl-lbl,body.fs-3 .ardl-val{font-size:calc(1em * 1.50) !important}\u001b[39m\n\u001b[31m/* Level 4 — Max (+70%) */\u001b[39m\n\u001b[31mbody.fs-4 .field label,body.fs-4 .card-title,body.fs-4 .set-lbl,body.fs-4 .set-sub,\u001b[39m\n\u001b[31mbody.fs-4 .hdr-title,body.fs-4 .hdr-sub,body.fs-4 .slbl,body.fs-4 .rev-lbl,body.fs-4 .rev-val,\u001b[39m\n\u001b[31mbody.fs-4 .rbtn,body.fs-4 .chip,body.fs-4 .btn-p,body.fs-4 .btn-s,body.fs-4 .btn-o,\u001b[39m\n\u001b[31mbody.fs-4 .bdialog-title,body.fs-4 .bdialog-sub,body.fs-4 .sub-name,body.fs-4 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-4 .pslot-lbl,body.fs-4 .bitem-title,body.fs-4 .pi-name,body.fs-4 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-4 .asc-name,body.fs-4 .new-btn,body.fs-4 .resume-btn,body.fs-4 .ardl-lbl,body.fs-4 .ardl-val{font-size:calc(1em * 1.70) !important}\u001b[39m\n\u001b[31m/* ── RECCE TILE ACTION BUTTONS ── */\u001b[39m\n\u001b[31m.rpt-btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid rgba(0,0,0,.06)}\u001b[39m\n\u001b[31m.rpt-btn{display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 14px;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;border:none;font-family:inherit;transition:background .15s,opacity .15s;flex:1;min-width:110px;letter-spacing:.1px;white-space:nowrap}\u001b[39m\n\u001b[31m.rpt-btn-report{background:#fff7ed;color:var(--or);border:1.5px solid var(--or)}\u001b[39m\n\u001b[31m.rpt-btn-report:active{background:#fed7aa}\u001b[39m\n\u001b[31m.rpt-btn-pdf{background:var(--g100);color:var(--g400);border:1.5px solid var(--g200)}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready{background:var(--or);color:#fff;border-color:transparent}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready:active{background:#ea6c00}\u001b[39m\n\u001b[31m/* PDF wait overlay */\u001b[39m\n\u001b[31m#pdf-wait-ov{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m</style>\u001b[39m\n\u001b[31m</head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<!-- PICKER OVERLAY -->\u001b[39m\n\u001b[31m<div class=\\\"povl\\\" id=\\\"povl\\\">\u001b[39m\n\u001b[31m  <div class=\\\"povl-hdr\\\">\u001b[39m\n\u001b[31m    <input class=\\\"psearch\\\" id=\\\"psearch\\\" type=\\\"text\\\" placeholder=\\\"Search store / दुकान खोजें…\\\" oninput=\\\"filterPicker(this.value)\\\" autocomplete=\\\"off\\\">\u001b[39m\n\u001b[31m    <button class=\\\"pcancel\\\" onclick=\\\"closePicker()\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"plist\\\" id=\\\"plist\\\"></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"app\\\">·\u001b[39m\n\u001b[31m<!-- HOME -->\u001b[39m\n\u001b[31m<div class=\\\"view active\\\" id=\\\"view-home\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hero\\\">\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;justify-content:space-between;align-items:center\\\">\u001b[39m\n\u001b[31m      <div><div class=\\\"hero-title\\\"><span class=\\\"en-txt\\\">Branding Recce</span><span class=\\\"hi-txt\\\">ब्रांडिंग रेकी</span></div><div class=\\\"hero-sub\\\" id=\\\"today-date\\\">—</div></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:6px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"lang-btn\\\" onclick=\\\"setLang(LANG==='en'?'hi':'en')\\\" id=\\\"lang-btn\\\" title=\\\"Switch language / भाषा बदलें\\\">EN | हि</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-hub\\\" onclick=\\\"goToHub()\\\">🏡 Hub</button>\u001b[39m\n\u001b[31m      <button class=\\\"icon-btn\\\" onclick=\\\"showView('settings')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12 15a3 3 0 100-6 3 3 0 000 6z\\\"/><path d=\\\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\\\"/></svg></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"hero-ubar\\\" id=\\\"recce-hero-ubar\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <span class=\\\"hero-uname\\\" id=\\\"recce-hero-name\\\"></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-logout\\\" onclick=\\\"recceLogout()\\\">Logout</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"stats\\\">\u001b[39m\n\u001b[31m      <div class=\\\"scard g\\\"><div class=\\\"snum\\\" id=\\\"stat-synced\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Synced</span><span class=\\\"hi-txt\\\">सिंक्ड</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard a\\\"><div class=\\\"snum\\\" id=\\\"stat-pending\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Pending</span><span class=\\\"hi-txt\\\">बाकी</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard\\\"><div class=\\\"snum\\\" id=\\\"stat-total\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Total</span><span class=\\\"hi-txt\\\">कुल</span></div></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <button class=\\\"new-btn\\\" onclick=\\\"startNewRecce()\\\"><svg width=\\\"20\\\" height=\\\"20\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">New Recce</span><span class=\\\"hi-txt\\\">नई रेकी</span></button>\u001b[39m\n\u001b[31m    <div id=\\\"resume-wrap\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"sh\\\"><span class=\\\"st\\\"><span class=\\\"en-txt\\\">Recent Submissions</span><span class=\\\"hi-txt\\\">हाल की सबमिशन</span></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"syncNow()\\\" id=\\\"sync-btn\\\" style=\\\"padding:7px 12px;font-size:12px\\\"><svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg><span class=\\\"en-txt\\\">Sync</span><span class=\\\"hi-txt\\\">सिंक</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"sub-list\\\"></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"srow\\\"><div><span class=\\\"sdot\\\" id=\\\"net-dot\\\"></span><span id=\\\"net-txt\\\"><span class=\\\"en-txt\\\">Checking…</span><span class=\\\"hi-txt\\\">जाँच…</span></span></div><span id=\\\"last-sync-txt\\\" style=\\\"font-size:11px\\\"><span class=\\\"en-txt\\\">Never synced</span><span class=\\\"hi-txt\\\">कभी सिंक नहीं</span></span></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- SETTINGS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-settings\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('home')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Settings</span><span class=\\\"hi-txt\\\">सेटिंग</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Brand List</span><span class=\\\"hi-txt\\\">ब्रांड सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Manage Brands</span><span class=\\\"hi-txt\\\">ब्रांड प्रबंधन</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">These appear in the brand dropdown and store picker. Add client brands as needed.</div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-manage-list\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-add-row\\\" style=\\\"display:none;gap:8px;align-items:center\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"brand-add-inp\\\" placeholder=\\\"Type brand name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addBrandToList()\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"addBrandToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Store Lists</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Supervisors can upload XLS/CSV store lists here. Updates sync to all devices via server.</span><span class=\\\"hi-txt\\\">सुपरवाइजर यहाँ XLS/CSV स्टोर सूची अपलोड कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m      <!-- Upload/Clear row — supervisor only -->\u001b[39m\n\u001b[31m      <div id=\\\"store-upload-row\\\" style=\\\"display:none;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;margin-top:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"document.getElementById('store-xl').click()\\\"><svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Add File</span><span class=\\\"hi-txt\\\">फ़ाइल जोड़ें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-d\\\" onclick=\\\"clearStoreList()\\\" style=\\\"font-size:12px\\\"><span class=\\\"en-txt\\\">Clear All Stores</span><span class=\\\"hi-txt\\\">सभी स्टोर हटाएं</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" id=\\\"store-push-btn\\\" onclick=\\\"pushStoresToServer()\\\" style=\\\"font-size:12px;display:none\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Push to Server</span><span class=\\\"hi-txt\\\">सर्वर पर पुश करें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"store-xl\\\" accept=\\\".xlsx,.xls,.csv\\\" onchange=\\\"handleStoreUpload(event)\\\">\u001b[39m\n\u001b[31m      <div id=\\\"store-count\\\" style=\\\"font-size:13px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"store-file-list\\\" style=\\\"margin-top:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Brand assignment dialog for files with no brand column -->\u001b[39m\n\u001b[31m    <div id=\\\"brand-assign-dialog\\\" style=\\\"display:none;margin-top:10px;padding:14px;background:#fff7ed;border:1.5px solid var(--or);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\">Which brand is this store list for?</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\" id=\\\"brand-assign-fname\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-assign-chips\\\" class=\\\"chip-grid\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"confirmBrandAssign()\\\" style=\\\"flex:2;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">Assign Brand</span><span class=\\\"hi-txt\\\">ब्रांड असाइन करें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"skipBrandAssign()\\\" style=\\\"flex:1;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">No Brand</span><span class=\\\"hi-txt\\\">कोई ब्रांड नहीं</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Server Store List URL (Admin)</span><span class=\\\"hi-txt\\\">सर्वर स्टोर सूची URL</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Admin pushes stores.json to any public URL. App auto-fetches on open and caches offline.</div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"srv-url\\\" placeholder=\\\"https://yourserver.com/stores.json\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"fetchServerStores()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Fetch Now</button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"saveServerUrl()\\\" style=\\\"padding:9px 14px;font-size:13px;width:auto\\\">Save URL</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Sync Endpoint</span><span class=\\\"hi-txt\\\">सिंक एंडपॉइंट</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Slides Generator</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Managed by admin. Deploy gas_slides.gs from /opt/slides-proxy/ to Google Apps Script and paste the URL here.</div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"slides-gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Not configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"slides-gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"saveSlidesGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Sheet Sync</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Legacy sync endpoint. Writes recce data to Google Sheet.</div>·\u001b[39m\n\u001b[31m      <!-- Locked state (default) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Endpoint configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Unlocked state (after admin login) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;align-items:center;gap:8px;margin-bottom:10px;padding:7px 12px;background:#dcfce7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          <span style=\\\"font-size:12px;color:#14532d;font-weight:600\\\">🔓 Admin mode active</span>\u001b[39m\n\u001b[31m          <button onclick=\\\"lockAdmin()\\\" style=\\\"margin-left:auto;background:none;border:none;color:#14532d;font-size:12px;cursor:pointer;font-weight:600\\\">Lock ×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"testEndpoint()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Test</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>·\u001b[39m\n\u001b[31m    <!-- Admin Login Modal -->\u001b[39m\n\u001b[31m    <div id=\\\"admin-login-modal\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m      <div style=\\\"background:#fff;border-radius:var(--r);padding:24px 20px;margin:20px;max-width:380px;width:100%;box-shadow:0 8px 32px rgba(0,0,0,.2)\\\">\u001b[39m\n\u001b[31m        <div style=\\\"font-size:17px;font-weight:700;color:var(--nv);margin-bottom:4px\\\">Admin Login</div>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:18px\\\">Enter admin password to unlock settings</div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m          <label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">Password</label>\u001b[39m\n\u001b[31m          <input type=\\\"password\\\" id=\\\"admin-pwd\\\" placeholder=\\\"Enter admin password\\\" style=\\\"width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px\\\" onkeydown=\\\"if(event.key==='Enter')verifyAdmin()\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div id=\\\"admin-error\\\" style=\\\"display:none;font-size:12px;color:var(--rd);margin-bottom:12px;padding:8px 12px;background:#fee2e2;border-radius:var(--rs)\\\">Incorrect password</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"verifyAdmin()\\\" style=\\\"flex:2;padding:13px\\\" id=\\\"admin-login-btn\\\">Login</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-s\\\" onclick=\\\"closeAdminLogin()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:14px;padding-top:14px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.4px;margin-bottom:8px\\\">Admin Password Config URL</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:8px\\\">URL to your admin.json file on server (contains hashed password)</div>\u001b[39m\n\u001b[31m          <input type=\\\"url\\\" id=\\\"admin-cfg-url\\\" placeholder=\\\"https://yourserver.com/admin.json\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px;margin-bottom:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveAdminCfgUrl()\\\" style=\\\"font-size:12px;padding:7px 12px;width:100%;justify-content:center\\\">Save Config URL</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Geolocation Stamp</span><span class=\\\"hi-txt\\\">जियोलोकेशन स्टैम्प</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;justify-content:space-between;gap:16px\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1\\\">\u001b[39m\n\u001b[31m          <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Stamp on Photos</span><span class=\\\"hi-txt\\\">फोटो पर स्टैम्प</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"set-sub\\\" style=\\\"margin-bottom:0\\\">Bakes GPS coordinates, store name and timestamp into every photo — visible in the image itself. Same as GPS Map Camera app. Default: On.</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"tog on\\\" id=\\\"geo-tog\\\" onclick=\\\"toggleGeoStamp()\\\"><div class=\\\"tog-knob\\\"></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"geo-status\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\">GPS not yet captured</div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Image Quality</span><span class=\\\"hi-txt\\\">फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Default Photo Quality</span><span class=\\\"hi-txt\\\">डिफ़ॉल्ट फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Applies to all photos — front view, inside view, branding, and additional. HD uses more storage and takes longer to sync on poor networks.</div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;gap:10px;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-compressed\\\" onclick=\\\"setImgQuality('compressed')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-compressed\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-compressed\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">Full Compression</span><span class=\\\"hi-txt\\\">पूर्ण कम्प्रेशन</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~150–200 KB · Max 1280px · Best for poor network</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-left:auto;font-size:11px;font-weight:700;color:var(--gn);background:#dcfce7;padding:3px 8px;border-radius:20px\\\"><span class=\\\"en-txt\\\">Recommended</span><span class=\\\"hi-txt\\\">अनुशंसित</span></div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-hd\\\" onclick=\\\"setImgQuality('hd')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-hd\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-hd\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">HD Quality</span><span class=\\\"hi-txt\\\">HD क्वालिटी</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~400–600 KB · Max 1920px · Better detail for print</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"q-current-badge\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Supervisor Config panel — shown only to supervisors via renderSupPanel() -->\u001b[39m\n\u001b[31m    <div id=\\\"sup-panel\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">🔐 Recce Access Config</span><span class=\\\"hi-txt\\\">🔐 रेकी एक्सेस कॉन्फ़िग</span></div>\u001b[39m\n\u001b[31m      <!-- Access mode — only H/P can change -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"mode-row\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Access Mode</span><span class=\\\"hi-txt\\\">एक्सेस मोड</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Public: any Hub user can submit Recces. Assigned: only Supervisors and Creators can access.</span><span class=\\\"hi-txt\\\">सार्वजनिक: कोई भी Hub यूजर। नियत: सिर्फ़ Supervisors और Creators।</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\" style=\\\"margin-bottom:8px;margin-top:8px\\\">\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-public\\\" onclick=\\\"setRecceMode('public')\\\"><span class=\\\"en-txt\\\">Public</span><span class=\\\"hi-txt\\\">सार्वजनिक</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-assigned\\\" onclick=\\\"setRecceMode('assigned')\\\"><span class=\\\"en-txt\\\">Assigned</span><span class=\\\"hi-txt\\\">नियत</span></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Supervisor list — view all + delete + create -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Supervisors</span><span class=\\\"hi-txt\\\">सुपरवाइजर</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can view all recces, delete with reason, and submit. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">सभी रेकी देख सकते हैं, कारण से हटा सकते हैं, और सबमिट कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"sup-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addSupervisor()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addSupervisor()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Creator list — creation only -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Creators</span><span class=\\\"hi-txt\\\">क्रिएटर्स</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can submit Recces only — no admin view or deletion rights. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">केवल रेकी सबमिट कर सकते हैं — एडमिन व्यू या डिलीट नहीं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"creator-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addCreator()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addCreator()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Client list — used for client portal scoping -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clients</span><span class=\\\"hi-txt\\\">क्लाइंट</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Names that appear as chips when submitting a recce. Add the brand or agency name (e.g. \\\"Marketing Vibe\\\"). These are used to scope what clients see in the Client Portal.</span><span class=\\\"hi-txt\\\">रेकी सबमिट करते समय दिखने वाले क्लाइंट नाम। ब्रांड या एजेंसी नाम जोड़ें।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-mgmt-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"client-add-inp\\\" placeholder=\\\"Client name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addClientToList()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addClientToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Sync to server — only H/P -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"cfg-sync-btn\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Sync Config to Server</span><span class=\\\"hi-txt\\\">सर्वर पर कॉन्फ़िग सिंक करें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Apply supervisor/creator/client lists and access mode to all devices.</span><span class=\\\"hi-txt\\\">सभी डिवाइस पर कॉन्फ़िग लागू करें।</span></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"syncCfgToServer()\\\" style=\\\"max-width:220px;font-size:14px;padding:12px;margin-top:8px\\\"><span class=\\\"en-txt\\\">Sync to Server</span><span class=\\\"hi-txt\\\">सर्वर पर सिंक करें</span></button>\u001b[39m\n\u001b[31m        <div id=\\\"cfg-sync-status\\\" style=\\\"margin-top:8px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Danger Zone</span><span class=\\\"hi-txt\\\">खतरनाक ज़ोन</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\"><div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clear All Local Data</span><span class=\\\"hi-txt\\\">सभी डेटा हटाएं</span></div><div class=\\\"set-sub\\\">Removes all submissions from this device.</div><button class=\\\"btn-d\\\" onclick=\\\"clearData()\\\" style=\\\"padding:9px 14px;font-size:13px\\\">Clear All</button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: STORE INFO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-store\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"exitForm()\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Details</span><span class=\\\"hi-txt\\\">दुकान विवरण</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 1 of 5</span><span class=\\\"hi-txt\\\">चरण 1 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:20%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Recce Info</span><span class=\\\"hi-txt\\\">रेकी जानकारी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Date of Recce</span><span class=\\\"hi-txt\\\">रेकी की तारीख</span> <span class=\\\"req\\\">*</span></label><input type=\\\"date\\\" id=\\\"f-date\\\" onchange=\\\"saveDraft()\\\" max=\\\"\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" id=\\\"campaign-field\\\">\u001b[39m\n\u001b[31m        <label><span class=\\\"en-txt\\\">Job / Campaign</span><span class=\\\"hi-txt\\\">जॉब / कैंपेन</span></label>\u001b[39m\n\u001b[31m        <select id=\\\"f-campaign-id\\\" onchange=\\\"onCampaignSelect()\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">Loading campaigns…</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <div id=\\\"campaign-notify-msg\\\" style=\\\"display:none;font-size:12px;color:#92400e;margin-top:6px;padding:8px 10px;background:#fef3c7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          ⚑ <span class=\\\"en-txt\\\">Recce will submit without a job ID. A notification will flag this for your supervisor to link it later.</span><span class=\\\"hi-txt\\\">रेकी बिना जॉब ID के सबमिट होगी। सुपरवाइजर बाद में लिंक करेगा।</span>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Store</span><span class=\\\"hi-txt\\\">दुकान</span> <span id=\\\"store-avail-tag\\\" style=\\\"font-size:11px;color:var(--g400);font-weight:400;text-transform:none;letter-spacing:0\\\"></span></div>·\u001b[39m\n\u001b[31m      <!-- When store is selected -->\u001b[39m\n\u001b[31m      <div id=\\\"store-selected\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"store-card\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:start;justify-content:space-between;gap:8px\\\">\u001b[39m\n\u001b[31m            <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m              <div class=\\\"store-card-name\\\" id=\\\"sc-name\\\">—</div>\u001b[39m\n\u001b[31m              <div style=\\\"display:flex;align-items:center;gap:6px;margin-top:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m                <span class=\\\"brand-tag\\\" id=\\\"sc-brand\\\">—</span>\u001b[39m\n\u001b[31m                <span class=\\\"last-chip\\\" id=\\\"sc-last\\\" style=\\\"display:none\\\">—</span>\u001b[39m\n\u001b[31m              </div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            <button class=\\\"store-card-change\\\" onclick=\\\"openPicker()\\\"><span class=\\\"en-txt\\\">Change ›</span><span class=\\\"hi-txt\\\">बदलें ›</span></button>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <!-- All fields from Excel shown here -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-details\\\" style=\\\"margin-top:10px;display:flex;flex-direction:column;gap:4px\\\"></div>\u001b[39m\n\u001b[31m          <!-- Missing required fields — editable inline -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-missing\\\" style=\\\"display:none;margin-top:12px;padding-top:12px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m            <div style=\\\"font-size:11px;font-weight:700;color:var(--rd);text-transform:uppercase;letter-spacing:.4px;margin-bottom:10px\\\">⚠ Please complete missing fields</div>\u001b[39m\n\u001b[31m            <div id=\\\"sc-missing-fields\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <!-- Brand selector — shown when store has no brand -->\u001b[39m\n\u001b[31m        <div id=\\\"brand-selector\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\"><span class=\\\"en-txt\\\">Select Brand</span><span class=\\\"hi-txt\\\">ब्रांड चुनें</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\">This store has no brand in the list — select one:</div>\u001b[39m\n\u001b[31m          <div id=\\\"brand-chips\\\" class=\\\"chip-grid\\\"></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Picker trigger (shown when stores loaded) -->\u001b[39m\n\u001b[31m      <div id=\\\"pick-trigger-wrap\\\">\u001b[39m\n\u001b[31m        <div class=\\\"pick-trigger\\\" onclick=\\\"openPicker()\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:center;gap:10px\\\">\u001b[39m\n\u001b[31m            <span style=\\\"font-size:20px\\\">🏪</span>\u001b[39m\n\u001b[31m            <div>\u001b[39m\n\u001b[31m              <div style=\\\"font-size:15px;font-weight:700;color:var(--or)\\\"><span class=\\\"en-txt\\\">Select Store from List</span><span class=\\\"hi-txt\\\">सूची से दुकान चुनें</span></div>\u001b[39m\n\u001b[31m              <div id=\\\"store-avail-count\\\" style=\\\"font-size:12px;font-weight:400;color:var(--am);margin-top:1px\\\"><span class=\\\"en-txt\\\">Tap to browse stores</span><span class=\\\"hi-txt\\\">दुकान खोजने के लिए दबाएं</span></div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual / new store toggle -->\u001b[39m\n\u001b[31m      <div class=\\\"manual-toggle\\\" id=\\\"manual-toggle\\\" onclick=\\\"toggleManual()\\\">\u001b[39m\n\u001b[31m        <svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\" id=\\\"mt-icon\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg>\u001b[39m\n\u001b[31m        <span id=\\\"mt-label\\\"><span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span></span>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual fields -->\u001b[39m\n\u001b[31m      <div id=\\\"manual-fields\\\" style=\\\"display:none;margin-top:14px\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\" style=\\\"margin-bottom:14px\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <select id=\\\"f-brand\\\" onchange=\\\"onManualBrandChange()\\\">\u001b[39m\n\u001b[31m            <option value=\\\"\\\">Select brand</option>\u001b[39m\n\u001b[31m          </select>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span> <span class=\\\"req\\\">*</span></label><input type=\\\"text\\\" id=\\\"f-store\\\" placeholder=\\\"Enter store name\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\">\u001b[39m\n\u001b[31m          <label><span class=\\\"en-txt\\\">Store Address</span><span class=\\\"hi-txt\\\">दुकान का पता</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <textarea id=\\\"f-addr\\\" rows=\\\"2\\\" placeholder=\\\"Full address\\\" onchange=\\\"saveDraft()\\\"></textarea>\u001b[39m\n\u001b[31m          <div class=\\\"gps-row\\\">\u001b[39m\n\u001b[31m            <button class=\\\"gps-btn\\\" onclick=\\\"captureGPS()\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\"/><path d=\\\"M12 2v3M12 19v3M2 12h3M19 12h3\\\"/></svg><span class=\\\"en-txt\\\">Capture GPS</span><span class=\\\"hi-txt\\\">GPS लें</span></button>\u001b[39m\n\u001b[31m            <span id=\\\"gps-status\\\" style=\\\"font-size:12px;color:var(--g500);align-self:center\\\"></span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Mobile No.</span><span class=\\\"hi-txt\\\">मोबाइल नंबर</span></label><input type=\\\"tel\\\" id=\\\"f-mobile\\\" placeholder=\\\"10-digit number\\\" maxlength=\\\"10\\\" inputmode=\\\"numeric\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Client card -->\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Client</span><span class=\\\"hi-txt\\\">क्लाइंट</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\"><span class=\\\"en-txt\\\">Select who this recce is for. Defaults to brand — change if work came via an agency.</span><span class=\\\"hi-txt\\\">यह रेकी किसके लिए है चुनें। ब्रांड से डिफ़ॉल्ट — एजेंसी के ज़रिए हो तो बदलें।</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"cl-chip-grid\\\" id=\\\"client-chips\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"client-other-wrap\\\" style=\\\"display:none;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"f-client-other\\\" placeholder=\\\"Type client name\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" oninput=\\\"onClientOtherInput()\\\">\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-p\\\" onclick=\\\"step2()\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: PHOTOS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-photos\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-store')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Photos</span><span class=\\\"hi-txt\\\">दुकान की फोटो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 2 of 5</span><span class=\\\"hi-txt\\\">चरण 2 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:40%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Front View</span><span class=\\\"hi-txt\\\">आगे का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(min 1, max 3)</span><span class=\\\"cnt-badge gray\\\" id=\\\"front-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"front-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-front\\\" onclick=\\\"addPhoto('front')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Front Photo</span><span class=\\\"hi-txt\\\">आगे की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Inside View</span><span class=\\\"hi-txt\\\">अंदर का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 5)</span><span class=\\\"cnt-badge gray\\\" id=\\\"inside-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"inside-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-inside\\\" onclick=\\\"addPhoto('inside')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Inside Photo</span><span class=\\\"hi-txt\\\">अंदर की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-store')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step3()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: VIDEO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-video\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-photos')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Recce Video</span><span class=\\\"hi-txt\\\">रेकी वीडियो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 3 of 5</span><span class=\\\"hi-txt\\\">चरण 3 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:60%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Video</span><span class=\\\"hi-txt\\\">वीडियो</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Recce video available?</span><span class=\\\"hi-txt\\\">रेकी वीडियो है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"vid-yes\\\" onclick=\\\"setVideo(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"vid-no\\\" onclick=\\\"setVideo(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"vid-sec\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Upload Video</span><span class=\\\"hi-txt\\\">वीडियो अपलोड करें</span></label>\u001b[39m\n\u001b[31m          <div class=\\\"pslot\\\" id=\\\"vid-slot\\\" onclick=\\\"document.getElementById('vid-inp').click()\\\"><div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div></div>\u001b[39m\n\u001b[31m          <input type=\\\"file\\\" id=\\\"vid-inp\\\" accept=\\\"video/*\\\" onchange=\\\"handleVideo(event)\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Video Comments</span><span class=\\\"hi-txt\\\">वीडियो टिप्पणी</span></label><input type=\\\"text\\\" id=\\\"f-vid-cmt\\\" placeholder=\\\"Optional\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-photos')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step4()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: BRANDING -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-branding\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-video')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Branding</span><span class=\\\"hi-txt\\\">ब्रांडिंग</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 4 of 5</span><span class=\\\"hi-txt\\\">चरण 4 / 5</span></div></div></div>\u001b[39m\n\u001b[31m    <span id=\\\"br-hdr-badge\\\" style=\\\"background:rgba(255,255,255,.2);color:#fff;font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px\\\"><span class=\\\"en-txt\\\">0 items</span><span class=\\\"hi-txt\\\">0 आइटम</span></span>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:80%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Branding Space</span><span class=\\\"hi-txt\\\">ब्रांडिंग स्थान</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Space available?</span><span class=\\\"hi-txt\\\">जगह उपलब्ध है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"br-yes\\\" onclick=\\\"setBranding(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"br-no\\\" onclick=\\\"setBranding(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"branding-lock-banner\\\" style=\\\"display:none;background:#fef3c7;border:1.5px solid #f59e0b;border-radius:10px;padding:12px 14px;margin-bottom:10px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:700;color:#92400e\\\">Client approval exists — branding locked</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:#78350f;margin-top:4px\\\"><span class=\\\"en-txt\\\">The client has reviewed this recce. Create a new recce to revise branding items.</span><span class=\\\"hi-txt\\\">क्लाइंट ने रेकी की समीक्षा की है। बदलाव के लिए नई रेकी बनाएं।</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"branding-override-wrap\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m        <button onclick=\\\"unlockBrandingOverride()\\\" style=\\\"background:#f59e0b;color:#000;border:none;border-radius:8px;padding:8px 14px;font-size:12px;font-weight:700;cursor:pointer\\\">Override Edit (H&amp;P only)</button>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:11px;color:#92400e;margin-top:5px\\\">Use only when client has verbally confirmed and app needs correction.</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"br-items\\\"></div>\u001b[39m\n\u001b[31m    <div id=\\\"br-add\\\" style=\\\"display:none;margin-bottom:80px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"addBranding()\\\" style=\\\"width:100%;justify-content:center\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Another Branding Item</span><span class=\\\"hi-txt\\\">एक और ब्रांडिंग जोड़ें</span></button>\u001b[39m\n\u001b[31m      <div style=\\\"text-align:center;font-size:12px;color:var(--g400);margin-top:8px\\\"><span class=\\\"en-txt\\\">Tap Continue below when done adding items</span><span class=\\\"hi-txt\\\">सभी आइटम जोड़ने के बाद आगे दबाएं</span></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-video')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step5()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: ADDITIONAL + SUBMIT -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-additional\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-branding')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Submit</span><span class=\\\"hi-txt\\\">सबमिट</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 5 of 5</span><span class=\\\"hi-txt\\\">चरण 5 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:100%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Mandatory Document</span><span class=\\\"hi-txt\\\">अनिवार्य दस्तावेज़</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"pslot\\\" id=\\\"doc-slot\\\" onclick=\\\"document.getElementById('doc-inp').click()\\\"><div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div></div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"doc-inp\\\" accept=\\\"image/*,.pdf\\\" onchange=\\\"handleDoc(event)\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Additional Photos</span><span class=\\\"hi-txt\\\">अतिरिक्त फोटो</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 8)</span><span class=\\\"cnt-badge gray\\\" id=\\\"addl-badge\\\">0 / 8</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"add-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-addl\\\" onclick=\\\"addAdditional()\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\"><div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Review</span><span class=\\\"hi-txt\\\">समीक्षा</span></div><div id=\\\"rev-body\\\"></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-branding')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"submitRecce()\\\" id=\\\"sub-btn\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Submit Recce ✓</span><span class=\\\"hi-txt\\\">रेकी सबमिट करें ✓</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- ANNOTATION MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"annot-modal\\\" id=\\\"annot-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"annot-bar\\\">\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Draw:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"at-rect\\\"    onclick=\\\"setATool('rect')\\\">▭ Rect</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-ellipse\\\" onclick=\\\"setATool('ellipse')\\\">◯ Ellipse</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-line\\\"    onclick=\\\"setATool('line')\\\">╱ Line</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-arrow\\\"   onclick=\\\"setATool('arrow')\\\">↗ Arrow</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-free\\\"    onclick=\\\"setATool('free')\\\">✏ Free</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool sel-on\\\" id=\\\"at-move\\\" onclick=\\\"setATool('move')\\\" style=\\\"margin-left:4px\\\">⊹ Move</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Color:</span>\u001b[39m\n\u001b[31m      <div class=\\\"acolor on\\\" id=\\\"ac-or\\\" style=\\\"background:#f97316\\\" onclick=\\\"setAColor('#f97316')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-rd\\\" style=\\\"background:#ef4444\\\" onclick=\\\"setAColor('#ef4444')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-wh\\\" style=\\\"background:#ffffff\\\" onclick=\\\"setAColor('#ffffff')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-yw\\\" style=\\\"background:#facc15\\\" onclick=\\\"setAColor('#facc15')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-gn\\\" style=\\\"background:#22c55e\\\" onclick=\\\"setAColor('#22c55e')\\\"></div>\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Width:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-2\\\" onclick=\\\"setAWidth(2)\\\" style=\\\"padding:5px 8px\\\">Thin</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"aw-4\\\" onclick=\\\"setAWidth(4)\\\" style=\\\"padding:5px 8px\\\">Med</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-7\\\" onclick=\\\"setAWidth(7)\\\" style=\\\"padding:5px 8px\\\">Thick</button>\u001b[39m\n\u001b[31m      <div style=\\\"flex:1\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"undoAnnot()\\\">↩</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"clearAnnot()\\\">✕</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"annot-sel-info\\\" style=\\\"display:none;font-size:11px;color:#facc15;padding:4px 0 2px\\\">\u001b[39m\n\u001b[31m      Shape selected — drag to move · drag corners to resize · tap elsewhere to deselect\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-cvs-wrap\\\"><canvas id=\\\"annot-cvs\\\"></canvas></div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-foot\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-s\\\" onclick=\\\"skipAnnot()\\\" style=\\\"flex:1;padding:12px;font-size:14px\\\"><span class=\\\"en-txt\\\">Skip markup</span><span class=\\\"hi-txt\\\">मार्कअप छोड़ें</span></button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" onclick=\\\"saveAnnot()\\\" style=\\\"flex:2;padding:12px\\\"><span class=\\\"en-txt\\\">Done — Save ✓</span><span class=\\\"hi-txt\\\">हो गया — सेव करें ✓</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EXIT DIALOG -->\u001b[39m\n\u001b[31m<!-- MODAL: Link Job to Recce (supervisor only) -->\u001b[39m\n\u001b[31m<div id=\\\"modal-link-job\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m  <div style=\\\"background:#fff;border-radius:14px;padding:20px;width:90%;max-width:380px;display:flex;flex-direction:column;gap:12px;box-shadow:0 8px 32px rgba(0,0,0,.35)\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:15px;font-weight:700;color:#1e293b\\\">&#x1F517; Link Job to Recce</div>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-store\\\" style=\\\"font-size:13px;color:#64748b\\\"></div>\u001b[39m\n\u001b[31m    <select id=\\\"link-job-sel\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m      <option value=\\\"\\\">&#x2014; Select campaign &#x2014;</option>\u001b[39m\n\u001b[31m    </select>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-err\\\" style=\\\"font-size:12px;color:#ef4444;min-height:14px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"closeLinkJobModal()\\\" style=\\\"flex:1;padding:12px;border:1px solid #cbd5e1;border-radius:8px;cursor:pointer;background:#f8fafc;font-size:14px\\\">Cancel</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"saveLinkJob()\\\" style=\\\"flex:2;padding:12px;background:#f59e0b;color:#000;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:700\\\">&#x1F517; Link Job</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"exit-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Exit Recce?</span><span class=\\\"hi-txt\\\">रेकी से बाहर?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Your progress and photos will be saved as a draft. Resume anytime from the home screen.</span><span class=\\\"hi-txt\\\">आपकी प्रगति और फोटो ड्राफ्ट में सेव होंगी। होम स्क्रीन से कभी भी जारी रखें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"exitSaveAndLeave()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">💾 Save Draft & Exit</span><span class=\\\"hi-txt\\\">💾 ड्राफ्ट सेव करें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-d\\\" onclick=\\\"exitDiscard()\\\" style=\\\"flex:1;padding:13px;font-size:13px\\\"><span class=\\\"en-txt\\\">Discard</span><span class=\\\"hi-txt\\\">हटाएं</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"exitCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">← Continue Recce</span><span class=\\\"hi-txt\\\">← रेकी जारी रखें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- PHOTO SOURCE PICKER -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"photo-src-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Camera photos get GPS stamp baked in. Gallery photos are added without stamp.</span><span class=\\\"hi-txt\\\">कैमरा फोटो में GPS स्टैम्प लगती है। गैलरी फोटो में नहीं।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"photoSrcCamera()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">📷 Use Camera</span><span class=\\\"hi-txt\\\">📷 कैमरा</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">GPS stamp applied</span><span class=\\\"hi-txt\\\">GPS स्टैम्प लगेगी</span></span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"photoSrcGallery()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">🖼 Choose from Gallery</span><span class=\\\"hi-txt\\\">🖼 गैलरी से चुनें</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">No stamp</span><span class=\\\"hi-txt\\\">स्टैम्प नहीं</span></span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"photoSrcCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- STORE PREVIEW DIALOG -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"store-preview-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:80vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"store-preview-title\\\"><span class=\\\"en-txt\\\">Preview Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची का प्रीव्यू</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Review before adding to your store list:</span><span class=\\\"hi-txt\\\">जोड़ने से पहले जाँचें:</span></div>\u001b[39m\n\u001b[31m    <div style=\\\"overflow-x:auto;margin-bottom:14px\\\">\u001b[39m\n\u001b[31m      <table style=\\\"width:100%;border-collapse:collapse;font-size:12px\\\">\u001b[39m\n\u001b[31m        <thead><tr style=\\\"background:var(--nv);color:#fff\\\">\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Address</span><span class=\\\"hi-txt\\\">पता</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Mobile</span><span class=\\\"hi-txt\\\">मोबाइल</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span></th>\u001b[39m\n\u001b[31m        </tr></thead>\u001b[39m\n\u001b[31m        <tbody id=\\\"store-preview-body\\\"></tbody>\u001b[39m\n\u001b[31m      </table>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"confirmStorePreview()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">✓ Confirm & Add Stores</span><span class=\\\"hi-txt\\\">✓ स्टोर जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"cancelStorePreview()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BOTTOM DIALOG (branding additional photo prompt) -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"bdialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add reference photos?</span><span class=\\\"hi-txt\\\">संदर्भ फोटो जोड़ें?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Add extra photos for this branding item for future reference.</span><span class=\\\"hi-txt\\\">इस ब्रांडिंग आइटम के लिए अतिरिक्त फोटो जोड़ें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"bdialogYes()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">Yes, add photos</span><span class=\\\"hi-txt\\\">हाँ, जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"bdialogNo()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Skip</span><span class=\\\"hi-txt\\\">छोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- DELETE REASON MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"delete-reason-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"padding-bottom:28px;max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">🗑 Delete Recce</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"del-modal-sub\\\">Select reason for deletion:</div>\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-wrong\\\" onclick=\\\"selectDeleteReason('wrong')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">❌</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Wrong</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Incorrect store / submission error</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-duplicate\\\" onclick=\\\"selectDeleteReason('duplicate')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">📋</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Duplicate</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Same store submitted more than once</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt danger\\\" id=\\\"reason-test\\\" onclick=\\\"selectDeleteReason('test')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">⚠️</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Test Recce</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:#9a3412;margin-top:2px\\\">Permanently deleted — no audit trail</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p no-reason\\\" id=\\\"del-confirm-btn\\\" onclick=\\\"confirmDelete()\\\" style=\\\"flex:2;padding:13px;background:var(--rd)\\\">Delete</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"closeDeleteModal()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EDIT REQUEST MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"edit-req-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Request Edit</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"er-store-name\\\" style=\\\"font-weight:600;color:var(--nv);margin-bottom:4px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:14px\\\">Add a note for the creator (optional)</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m      <textarea id=\\\"er-comment\\\" placeholder=\\\"e.g. Please re-check store address and re-upload front photo\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;color:var(--nv);resize:vertical;min-height:80px;background:#fff\\\"></textarea>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button id=\\\"er-assign-btn\\\" class=\\\"btn-p\\\" onclick=\\\"assignEditToCreator()\\\" style=\\\"padding:14px\\\">👤 Assign to Creator</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"supervisorEditMyself()\\\" style=\\\"padding:14px\\\">✏ Edit Myself</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"closeEditRequestModal()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BRAND EDIT MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"brand-edit-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Edit Brand</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Brand Name <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"text\\\" id=\\\"be-name\\\" placeholder=\\\"e.g. PHILIPS\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:600;text-transform:uppercase\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Logo URL <span style=\\\"font-size:11px;font-weight:400;color:var(--g400)\\\">(optional)</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"url\\\" id=\\\"be-logo\\\" placeholder=\\\"https://…/logo.svg\\\" oninput=\\\"previewBrandLogo()\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px\\\">\u001b[39m\n\u001b[31m      <div id=\\\"be-logo-preview\\\" style=\\\"margin-top:8px;min-height:36px;display:flex;align-items:center;gap:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"be-cascade-info\\\" style=\\\"display:none;font-size:12px;color:var(--g500);padding:8px 12px;background:var(--g50);border-radius:var(--rs);margin-bottom:12px\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"saveBrandEdit()\\\" style=\\\"padding:14px\\\">Save</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"closeBrandEditModal()\\\" style=\\\"width:100%;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FONT SIZE WIDGET -->\u001b[39m\n\u001b[31m<div class=\\\"fs-widget\\\" id=\\\"fs-widget\\\">\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-dec\\\" onclick=\\\"changeFontSize(-1)\\\" title=\\\"Decrease font size\\\" aria-label=\\\"Decrease font size\\\">A<sup style=\\\"font-size:9px\\\">−</sup></button>\u001b[39m\n\u001b[31m  <span class=\\\"fs-label\\\" id=\\\"fs-lbl\\\">A</span>\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-inc\\\" onclick=\\\"changeFontSize(1)\\\" title=\\\"Increase font size\\\" aria-label=\\\"Increase font size\\\"><strong>A</strong><sup style=\\\"font-size:9px\\\">+</sup></button>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"upd-banner\\\" id=\\\"upd-banner\\\">\u001b[39m\n\u001b[31m  <span style=\\\"font-size:13px;font-weight:600;line-height:1.4\\\"><span class=\\\"en-txt\\\">✓ App updated to latest version</span><span class=\\\"hi-txt\\\">✓ ऐप नया संस्करण अपडेट हुआ</span></span>\u001b[39m\n\u001b[31m  <button class=\\\"upd-banner-ok\\\" onclick=\\\"dismissUpdateBanner()\\\"><span class=\\\"en-txt\\\">OK</span><span class=\\\"hi-txt\\\">ठीक है</span></button>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m<div class=\\\"toast\\\" id=\\\"toast\\\"></div>\u001b[39m\n\u001b[31m<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js\\\"></script>\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m// LANGUAGE\u001b[39m\n\u001b[31mlet LANG = localStorage.getItem('recce-lang') || 'en';\u001b[39m\n\u001b[31mfunction setLang(l) {\u001b[39m\n\u001b[31m  LANG = l;\u001b[39m\n\u001b[31m  localStorage.setItem('recce-lang', l);\u001b[39m\n\u001b[31m  document.body.classList.toggle('lang-hi', l === 'hi');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction t(en, hi) { return LANG === 'hi' ? hi : en; }·\u001b[39m\n\u001b[31m// FONT SIZE\u001b[39m\n\u001b[31mlet FS_LEVEL = parseInt(localStorage.getItem('recce-fs') || '0', 10);\u001b[39m\n\u001b[31mconst FS_LABELS = ['A', 'A+', 'A++', 'A+++', 'A++++'];\u001b[39m\n\u001b[31mfunction applyFontSize() {\u001b[39m\n\u001b[31m  document.body.classList.remove('fs-0', 'fs-1', 'fs-2');\u001b[39m\n\u001b[31m  if (FS_LEVEL > 0) document.body.classList.add('fs-' + FS_LEVEL);\u001b[39m\n\u001b[31m  const lbl = document.getElementById('fs-lbl');\u001b[39m\n\u001b[31m  if (lbl) lbl.textContent = FS_LABELS[FS_LEVEL];\u001b[39m\n\u001b[31m  const dec = document.getElementById('fs-dec');\u001b[39m\n\u001b[31m  const inc = document.getElementById('fs-inc');\u001b[39m\n\u001b[31m  if (dec) dec.disabled = FS_LEVEL === 0;\u001b[39m\n\u001b[31m  if (inc) inc.disabled = FS_LEVEL === 4;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction changeFontSize(delta) {\u001b[39m\n\u001b[31m  FS_LEVEL = Math.min(4, Math.max(0, FS_LEVEL + delta));\u001b[39m\n\u001b[31m  localStorage.setItem('recce-fs', FS_LEVEL);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Hub auth gate\u001b[39m\n\u001b[31m(function() {\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (!s || !s.loginAt || Date.now() - new Date(s.loginAt).getTime() > 12 * 3600 * 1000) {\u001b[39m\n\u001b[31m      window.location.replace('/hub/');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) { window.location.replace('/hub/'); }\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31m// STATE\u001b[39m\n\u001b[31mlet F={},frontPhotos=[],insidePhotos=[],addlPhotos=[],brandings=[];\u001b[39m\n\u001b[31mlet videoBlob=null,submissionDoc=null,_docExistingUrl=null,gpsCoords=null;\u001b[39m\n\u001b[31mlet stores=[],selectedStore=null,manualMode=false,DB;\u001b[39m\n\u001b[31mlet imgQuality='compressed'; // 'compressed' | 'hd'\u001b[39m\n\u001b[31mlet geoStampEnabled=true;    // stamp GPS+timestamp on every photo\u001b[39m\n\u001b[31mlet brands=['PHILIPS']; // editable brand list\u001b[39m\n\u001b[31mlet _brandLogos={};   // name → logo_url, loaded from DB\u001b[39m\n\u001b[31mlet _selectedClient=''; // currently selected client chip value\u001b[39m\n\u001b[31mlet _clientOtherMode=false; // true when \\\"Other\\\" chip selected\u001b[39m\n\u001b[31mconst BTYPE=['Glow Sign Board','Inshop Branding','ACP Board','One Way Vision','Fabric Board','Lollypop','Non Lit Flex','Double Side GSB','Clip on Board','Translit','Vinyl Printing','Roll up Standee','Sunboard Standee'];\u001b[39m\n\u001b[31mconst CACHE_VER='recce-v37'; // campaign dropdown + pending job link tab·\u001b[39m\n\u001b[31m// DB\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',3);r.onupgradeneeded=e=>{const d=e.target.result;['subs','cfg','draft'].forEach(s=>{if(!d.objectStoreNames.contains(s))d.createObjectStore(s,{keyPath:'k'||'id'});});if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);});}\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',4);r.onupgradeneeded=e=>{const d=e.target.result;if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);})}\u001b[39m\n\u001b[31mfunction dbGet(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).get(k);r.onsuccess=()=>res(r.result);r.onerror=()=>res(null);}catch{res(null)}})}\u001b[39m\n\u001b[31mfunction dbPut(s,v){return new Promise((res,rej)=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).put(v);r.onsuccess=()=>res();r.onerror=()=>rej();}catch(e){rej(e)}})}\u001b[39m\n\u001b[31mfunction dbAll(s){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).getAll();r.onsuccess=()=>res(r.result);r.onerror=()=>res([]);}catch{res([])}})}\u001b[39m\n\u001b[31mfunction dbDel(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).delete(k);r.onsuccess=()=>res();r.onerror=()=>res();}catch{res()}})}\u001b[39m\n\u001b[31masync function cfg(k,v){if(v===undefined){const r=await dbGet('cfg',k);return r?r.v:null;}await dbPut('cfg',{k,v});}·\u001b[39m\n\u001b[31m// COMPRESS — respects imgQuality setting\u001b[39m\n\u001b[31mfunction compress(file, maxPxOverride, qOverride){\u001b[39m\n\u001b[31m  const maxPx = maxPxOverride || (imgQuality==='hd' ? 1920 : 1280);\u001b[39m\n\u001b[31m  const q     = qOverride     || (imgQuality==='hd' ? 0.90 : 0.78);\u001b[39m\n\u001b[31m  return new Promise(res=>{const img=new Image(),url=URL.createObjectURL(file);img.onload=()=>{const sc=Math.min(1,maxPx/Math.max(img.width,img.height));const c=document.createElement('canvas');c.width=Math.round(img.width*sc);c.height=Math.round(img.height*sc);c.getContext('2d').drawImage(img,0,0,c.width,c.height);URL.revokeObjectURL(url);c.toBlob(b=>res(b),'image/jpeg',q);};img.onerror=()=>{URL.revokeObjectURL(url);res(file)};img.src=url;});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction b64(blob){return new Promise(res=>{const r=new FileReader();r.onload=()=>res(r.result);r.readAsDataURL(blob)})}\u001b[39m\n\u001b[31mfunction fmtSz(b){if(b<1024)return b+'B';if(b<1048576)return(b/1024).toFixed(0)+'KB';return(b/1048576).toFixed(1)+'MB'}·\u001b[39m\n\u001b[31m// STORE LIST\u001b[39m\n\u001b[31mlet _storeFiles=[]; // track uploaded files {name, brand, count}\u001b[39m\n\u001b[31mlet _pendingParse=null; // parsed rows waiting for brand assignment·\u001b[39m\n\u001b[31mfunction parseStoreRow(row, keyFn){\u001b[39m\n\u001b[31m  const v=k=>{\u001b[39m\n\u001b[31m    // Try exact match first, then partial\u001b[39m\n\u001b[31m    const exactKey=Object.keys(row||{}).find(hk=>hk.toLowerCase()===k);\u001b[39m\n\u001b[31m    const partKey=Object.keys(row||{}).find(hk=>hk.toLowerCase().includes(k));\u001b[39m\n\u001b[31m    const useKey=exactKey||partKey;\u001b[39m\n\u001b[31m    if(useKey)return row[useKey]!=null?row[useKey].toString().trim():'';\u001b[39m\n\u001b[31m    // CSV path: keyFn provides value directly\u001b[39m\n\u001b[31m    const col=keyFn(k);return col!=null?col.toString().trim():'';\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const name    = v('sub dealer name')||v('sub dealer')||v('dealer name')||v('store name')||v('store')||v('name');\u001b[39m\n\u001b[31m  const address = v('address')||v('addr')||v('location')||v('area');\u001b[39m\n\u001b[31m  // Contact Detail often stored as a number — toString handles it\u001b[39m\n\u001b[31m  const rawMob  = v('contact detail')||v('contact no.')||v('contact no')||v('mobile no')||v('mobile')||v('phone')||v('mob')||v('contact');\u001b[39m\n\u001b[31m  const mobile  = rawMob.replace(/\\\\D/g,'').slice(-10);\u001b[39m\n\u001b[31m  // Brand: EXACT match only — \\\"Brand\\\" or \\\"Brand Name\\\" columns\u001b[39m\n\u001b[31m  // Partial match is intentionally avoided here because \\\"Inshop Branding\\\" contains \\\"brand\\\"\u001b[39m\n\u001b[31m  const brandKey=Object.keys(row||{}).find(hk=>{\u001b[39m\n\u001b[31m    const lk=hk.toLowerCase().trim();\u001b[39m\n\u001b[31m    return lk==='brand'||lk==='brand name'||lk==='brand_name'||lk==='brandname';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const brand=brandKey?(row[brandKey]||'').toString().trim().toUpperCase():'';\u001b[39m\n\u001b[31m  const distName= v('dist name')||v('distributor name')||v('distributor')||v('dist')||v('territory')||v('tsm')||v('asm');\u001b[39m\n\u001b[31m  const city    = v('city')||v('district')||v('town');\u001b[39m\n\u001b[31m  const sales   = v('2025 full year')||v('2025')||v('full year sales')||v('fy25')||v('sales');\u001b[39m\n\u001b[31m  const proj    = v('2026 projection')||v('2026')||v('projection')||v('fy26')||v('target');\u001b[39m\n\u001b[31m  const glowSign= v('glow sign')||v('glow');\u001b[39m\n\u001b[31m  const inshop  = v('inshop branding')||v('inshop')||v('in-shop')||v('in shop');\u001b[39m\n\u001b[31m  return {name, brand, address, mobile, distName, city, sales, proj, glowSign, inshop};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction dedupeStores(list){\u001b[39m\n\u001b[31m  const seen=new Map();\u001b[39m\n\u001b[31m  list.forEach(s=>{\u001b[39m\n\u001b[31m    // Include address in key — same store name at different locations = different stores\u001b[39m\n\u001b[31m    const key=(s.name.toLowerCase().trim())+'__'+(s.brand||'').toLowerCase()\u001b[39m\n\u001b[31m              +'__'+(s.address||'').toLowerCase().trim().slice(0,30);\u001b[39m\n\u001b[31m    if(!seen.has(key))seen.set(key,s);\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // True duplicate — merge missing fields from second record\u001b[39m\n\u001b[31m      const ex=seen.get(key);\u001b[39m\n\u001b[31m      Object.keys(s).forEach(k=>{ if(!ex[k]&&s[k])ex[k]=s[k]; });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  return Array.from(seen.values());\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderStoreFileList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-file-list');if(!el)return;\u001b[39m\n\u001b[31m  if(!_storeFiles.length){el.innerHTML='';return;}\u001b[39m\n\u001b[31m  el.innerHTML=_storeFiles.map((f,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:5px;font-size:12px\\\">\u001b[39m\n\u001b[31m      <div>\u001b[39m\n\u001b[31m        <span style=\\\"font-weight:600;color:var(--nv)\\\">${f.name}</span>\u001b[39m\n\u001b[31m        <span style=\\\"color:var(--g500);margin-left:6px\\\">${f.count} stores</span>\u001b[39m\n\u001b[31m        ${f.brand?`<span style=\\\"background:var(--nv);color:#fff;font-size:10px;font-weight:700;padding:1px 7px;border-radius:20px;margin-left:5px\\\">${f.brand}</span>`:'<span style=\\\"background:var(--g300);color:var(--g600);font-size:10px;padding:1px 7px;border-radius:20px;margin-left:5px\\\">Mixed brands</span>'}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <button onclick=\\\"removeStoreFile(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:17px;cursor:pointer;padding:0 4px;line-height:1\\\">×</button>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function removeStoreFile(i){\u001b[39m\n\u001b[31m  _storeFiles.splice(i,1);\u001b[39m\n\u001b[31m  // Rebuild stores from remaining files — re-parse from cache not possible, so just reload from DB and remove this file's contribution\u001b[39m\n\u001b[31m  // Simplest approach: clear and ask user to re-upload remaining files\u001b[39m\n\u001b[31m  if(!_storeFiles.length){stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    // Can't re-parse without original files; just note it and keep current store list\u001b[39m\n\u001b[31m    toast('Removed from list. Re-upload the remaining files to refresh store list.','info');\u001b[39m\n\u001b[31m    _storeFiles.splice(0); // clear tracking since we can't reconstruct\u001b[39m\n\u001b[31m    stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderStoreFileList();\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=stores.length?`✓ ${stores.length} stores`:'No stores loaded';\u001b[39m\n\u001b[31m  updAvailTag();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function clearStoreList(){\u001b[39m\n\u001b[31m  if(!confirm('Remove all loaded stores?'))return;\u001b[39m\n\u001b[31m  stores=[];_storeFiles=[];\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent='';\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast('Store list cleared','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function handleStoreUpload(e){\u001b[39m\n\u001b[31m  const file=e.target.files[0];if(!file)return;\u001b[39m\n\u001b[31m  e.target.value=''; // allow same file re-upload\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    let data=[];\u001b[39m\n\u001b[31m    if(file.name.toLowerCase().endsWith('.csv')){\u001b[39m\n\u001b[31m      const txt=await file.text();\u001b[39m\n\u001b[31m      const rows=txt.split('\\\\n').map(r=>r.split(',').map(c=>c.trim().replace(/^\\\"|\\\"$/g,'')));\u001b[39m\n\u001b[31m      if(!rows.length||!rows[0].length){toast('Empty CSV','error');return;}\u001b[39m\n\u001b[31m      const h=rows[0];\u001b[39m\n\u001b[31m      data=rows.slice(1).filter(r=>r.length>1&&r.some(c=>c)).map(r=>{\u001b[39m\n\u001b[31m        const rowObj={};h.forEach((hk,i)=>{rowObj[hk]=r[i]||'';});\u001b[39m\n\u001b[31m        return parseStoreRow(rowObj, ()=>'');\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }else{\u001b[39m\n\u001b[31m      const ab=await file.arrayBuffer();const wb=XLSX.read(ab,{type:'array'});\u001b[39m\n\u001b[31m      const js=XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]],{defval:''});\u001b[39m\n\u001b[31m      data=js.map(row=>parseStoreRow(row,()=>''));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    data=data.filter(d=>d.name.trim());\u001b[39m\n\u001b[31m    if(!data.length){toast('No valid rows found in file','error');return;}\u001b[39m\n\u001b[31m    // Check if any store has a brand\u001b[39m\n\u001b[31m    const hasBrand=data.some(d=>d.brand);\u001b[39m\n\u001b[31m    // Always show preview first before merging\u001b[39m\n\u001b[31m    _pendingParse={file:file.name,data,hasBrand};\u001b[39m\n\u001b[31m    showStorePreview(file.name, data, hasBrand);\u001b[39m\n\u001b[31m  }catch(err){toast('Failed: '+err.message,'error')}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mlet _pendingBrand='';\u001b[39m\n\u001b[31mfunction setPendingBrand(b){\u001b[39m\n\u001b[31m  _pendingBrand=b;\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-assign-chips .chip').forEach(c=>{\u001b[39m\n\u001b[31m    c.classList.toggle('sel',c.textContent===b);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  if(!_pendingBrand){toast('Select a brand first','error');return;}\u001b[39m\n\u001b[31m  // Assign brand to all rows in this file\u001b[39m\n\u001b[31m  const data=_pendingParse.data.map(s=>({...s,brand:_pendingBrand}));\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, data, _pendingBrand);\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function skipBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, _pendingParse.data, '');\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showStorePreview(filename, data, hasBrand){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-preview-dialog');\u001b[39m\n\u001b[31m  const tbody=document.getElementById('store-preview-body');\u001b[39m\n\u001b[31m  document.getElementById('store-preview-title').textContent=`${filename} · ${data.length} ${t('stores found','स्टोर मिले')}`;\u001b[39m\n\u001b[31m  // Show first 8 rows\u001b[39m\n\u001b[31m  const sample=data.slice(0,8);\u001b[39m\n\u001b[31m  tbody.innerHTML=sample.map(s=>`<tr>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;font-weight:500\\\">${s.name||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.address||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.mobile||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px\\\"><span style=\\\"background:${s.brand?'var(--nv)':'var(--rd)'};color:#fff;padding:1px 7px;border-radius:10px;font-size:10px\\\">${s.brand||'?'}</span></td>\u001b[39m\n\u001b[31m  </tr>`).join('');\u001b[39m\n\u001b[31m  if(data.length>8)tbody.innerHTML+=`<tr><td colspan=\\\"4\\\" style=\\\"text-align:center;padding:8px;font-size:12px;color:var(--g400)\\\">…and ${data.length-8} more stores</td></tr>`;\u001b[39m\n\u001b[31m  el.classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function confirmStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  const {file,data,hasBrand}=_pendingParse;\u001b[39m\n\u001b[31m  if(!hasBrand){\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-fname').textContent=`File: ${file} · ${data.length} stores found · No brand column detected`;\u001b[39m\n\u001b[31m    const chips=document.getElementById('brand-assign-chips');\u001b[39m\n\u001b[31m    chips.innerHTML=brands.map(b=>`<div class=\\\"chip\\\" onclick=\\\"setPendingBrand('${b}')\\\" id=\\\"bac-${b}\\\">${b}</div>`).join('');\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').style.display='block';\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    await mergeStores(file, data, '');\u001b[39m\n\u001b[31m    _pendingParse=null;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction cancelStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingParse=null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function mergeStores(filename, newData, assignedBrand){\u001b[39m\n\u001b[31m  const before=stores.length;\u001b[39m\n\u001b[31m  stores=[...stores,...newData];\u001b[39m\n\u001b[31m  stores=dedupeStores(stores);\u001b[39m\n\u001b[31m  const added=stores.length-before;\u001b[39m\n\u001b[31m  const dupes=newData.length-added;\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify(stores));\u001b[39m\n\u001b[31m  // Track file\u001b[39m\n\u001b[31m  _storeFiles.push({name:filename,count:newData.length,brand:assignedBrand||''});\u001b[39m\n\u001b[31m  await cfg('store-files',JSON.stringify(_storeFiles));\u001b[39m\n\u001b[31m  const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m    `✓ ${stores.length} total stores${dupes>0?` · ${dupes} duplicate${dupes>1?'s':''} removed`:''}${noBrand?` · ${noBrand} without brand`:' · All have brand'}`;\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast(`${added} stores added${dupes>0?`, ${dupes} duplicates skipped`:''}${assignedBrand?' as '+assignedBrand:''}`, 'success');\u001b[39m\n\u001b[31m  // Show server-push button for supervisors\u001b[39m\n\u001b[31m  const pb = document.getElementById('store-push-btn');\u001b[39m\n\u001b[31m  if (pb) pb.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function fetchServerStores(){const url=document.getElementById('srv-url').value.trim();if(!url){toast('Enter a URL first','error');return;}try{toast('Fetching…','info');const r=await fetch(url);const j=await r.json();const fetched=Array.isArray(j)?j:j.stores||[];await mergeStores('Server ('+url.split('/').pop()+')',fetched,'');await cfg('srv-url',url);}catch{toast('Fetch failed — check URL','error')}}\u001b[39m\n\u001b[31masync function saveServerUrl(){await cfg('srv-url',document.getElementById('srv-url').value.trim());toast('URL saved','success')}\u001b[39m\n\u001b[31mconst DEFAULT_GAS_URL='https://script.google.com/macros/s/AKfycbwyufC7gQyu1BErCxiDlbQUn0AWiIWv7nEmjk4UcAx3dvlV6bGk7q5fQOiv82CTbokbkA/exec';·\u001b[39m\n\u001b[31mconst DEFAULT_STORES_URL='/recce/stores.json';\u001b[39m\n\u001b[31mconst _RECCE_CFG_URL='/recce/recce-cfg.json';·\u001b[39m\n\u001b[31m// Admin auto-unlock for harish/pramod via hub session\u001b[39m\n\u001b[31mconst _RECCE_ADMIN_IDS = ['harish', 'pramod', 'rakesh'];\u001b[39m\n\u001b[31mconst _RECCE_CFG_ADMINS = ['harish', 'pramod'];\u001b[39m\n\u001b[31mlet _adminRows = [];\u001b[39m\n\u001b[31mlet _myServerRows = [];\u001b[39m\n\u001b[31mlet _adminUnlocked = false;\u001b[39m\n\u001b[31mlet _recceCfg = { version: 1, supervisors: ['harish','pramod','rakesh'], mode: 'public', creators: [], allowed_users: [] };\u001b[39m\n\u001b[31mfunction _isSupervisor() {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  return !!(hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId));\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _showDeletedView = false;\u001b[39m\n\u001b[31mlet _supCreateMode = false;\u001b[39m\n\u001b[31mlet _pendingDeleteId = null;\u001b[39m\n\u001b[31mlet _pendingDeleteReason = null;\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (s?.empId && _RECCE_ADMIN_IDS.includes(s.empId)) _adminUnlocked = true;\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31masync function loadRecceCfg(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(_RECCE_CFG_URL + '?t=' + Date.now());\u001b[39m\n\u001b[31m    if (r.ok) {\u001b[39m\n\u001b[31m      const j = await r.json();\u001b[39m\n\u001b[31m      if (j && j.version) {\u001b[39m\n\u001b[31m        _recceCfg = j;\u001b[39m\n\u001b[31m        if (Array.isArray(j.supervisors) && j.supervisors.length) {\u001b[39m\n\u001b[31m          _recceCfg.supervisors = j.supervisors;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.creators)) _recceCfg.creators = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.allowed_users)) _recceCfg.allowed_users = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.clients)) _recceCfg.clients = [];\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  // Re-check admin status against server supervisor list\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId)) {\u001b[39m\n\u001b[31m    _adminUnlocked = true;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _checkAccessMode(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (_recceCfg.mode !== 'assigned') return;\u001b[39m\n\u001b[31m  const allowed = [\u001b[39m\n\u001b[31m    ...(_recceCfg.supervisors || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.creators || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.allowed_users || []),\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  if (hub?.empId && allowed.includes(hub.empId)) return;\u001b[39m\n\u001b[31m  // Block access — show locked overlay\u001b[39m\n\u001b[31m  document.body.innerHTML = `<div style=\\\"min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0f172a;color:#fff;padding:32px;text-align:center\\\"><div style=\\\"font-size:48px;margin-bottom:16px\\\">🔒</div><div style=\\\"font-size:20px;font-weight:700;margin-bottom:8px\\\">${t('Access Restricted','एक्सेस प्रतिबंधित')}</div><div style=\\\"font-size:14px;color:#94a3b8\\\">${t('You are not authorised to use Branding Recce. Please contact your supervisor.','आप ब्रांडिंग रेक्की उपयोग के लिए अधिकृत नहीं हैं।')}</div></div>`;\u001b[39m\n\u001b[31m  throw new Error('access-restricted');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _recceHubUser() {\u001b[39m\n\u001b[31m  try { return JSON.parse(localStorage.getItem('lm360-session') || '{}'); }\u001b[39m\n\u001b[31m  catch(_) { return {}; }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── Supervisor config management ────────────────────────────────────\u001b[39m\n\u001b[31mfunction renderSupPanel(){\u001b[39m\n\u001b[31m  if (!_adminUnlocked) return;\u001b[39m\n\u001b[31m  const panel = document.getElementById('sup-panel');\u001b[39m\n\u001b[31m  if (panel) panel.style.display = 'block';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const modePublic = document.getElementById('mode-public');\u001b[39m\n\u001b[31m  const modeAssigned = document.getElementById('mode-assigned');\u001b[39m\n\u001b[31m  if (modePublic && modeAssigned) {\u001b[39m\n\u001b[31m    modePublic.classList.toggle('sel', _recceCfg.mode !== 'assigned');\u001b[39m\n\u001b[31m    modeAssigned.classList.toggle('sel', _recceCfg.mode === 'assigned');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  const addRow = document.getElementById('sup-add-row');\u001b[39m\n\u001b[31m  if (addRow) addRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const creatorAddRow = document.getElementById('creator-add-row');\u001b[39m\n\u001b[31m  if (creatorAddRow) creatorAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const clientAddRow = document.getElementById('client-add-row');\u001b[39m\n\u001b[31m  if (clientAddRow) clientAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const modeRow = document.getElementById('mode-row');\u001b[39m\n\u001b[31m  if (modeRow) {\u001b[39m\n\u001b[31m    modeRow.style.display = 'block';\u001b[39m\n\u001b[31m    // Non-cfg-admins see mode as read-only (toggles exist but setRecceMode guards them)\u001b[39m\n\u001b[31m    modeRow.style.opacity = isCfgAdmin ? '1' : '0.65';\u001b[39m\n\u001b[31m    modeRow.style.pointerEvents = isCfgAdmin ? '' : 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const syncBtn = document.getElementById('cfg-sync-btn');\u001b[39m\n\u001b[31m  if (syncBtn) syncBtn.style.display = isCfgAdmin ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('sup-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const sups = _recceCfg.supervisors || [];\u001b[39m\n\u001b[31m  el.innerHTML = sups.map((s,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${s}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin && sups.length > 1 ? `<button onclick=\\\"removeSupervisor(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderCreatorsList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('creator-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const creators = _recceCfg.creators || [];\u001b[39m\n\u001b[31m  el.innerHTML = creators.length ? creators.map((u,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${u}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeCreator(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No creators yet — any Hub user can submit in Public mode.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setRecceMode(mode){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.mode = mode;\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addSupervisor(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('sup-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.supervisors = [...(_recceCfg.supervisors || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeSupervisor(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.supervisors = (_recceCfg.supervisors || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addCreator(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('creator-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.creators || []).includes(val)) { toast(t('Already a creator','पहले से क्रिएटर है'), 'info'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor (includes creation rights)','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.creators = [...(_recceCfg.creators || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeCreator(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.creators = (_recceCfg.creators || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderClientMgmtList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('client-mgmt-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const list = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  el.innerHTML = list.length ? list.map((c,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${esc(c)}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeClientFromList(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No clients yet — add client or agency names to show them as chips in the form.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addClientToList(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('client-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter client name','क्लाइंट नाम दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.clients || []).includes(val)) { toast(t('Already in list','पहले से मौजूद है'), 'info'); return; }\u001b[39m\n\u001b[31m  if (!_recceCfg.clients) _recceCfg.clients = [];\u001b[39m\n\u001b[31m  _recceCfg.clients.push(val);\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeClientFromList(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.clients = (_recceCfg.clients || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncCfgToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast(t('Not authorised','अधिकृत नहीं'), 'error'); return; }\u001b[39m\n\u001b[31m  const st = document.getElementById('cfg-sync-status');\u001b[39m\n\u001b[31m  if (st) st.textContent = t('Syncing…','सिंक हो रहा है…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-cfg', empId: hub.empId, cfg: {\u001b[39m\n\u001b[31m        version: _recceCfg.version || 1,\u001b[39m\n\u001b[31m        supervisors: _recceCfg.supervisors || [],\u001b[39m\n\u001b[31m        mode: _recceCfg.mode || 'public',\u001b[39m\n\u001b[31m        creators: _recceCfg.creators || [],\u001b[39m\n\u001b[31m        allowed_users: _recceCfg.allowed_users || [],\u001b[39m\n\u001b[31m        clients: _recceCfg.clients || [],\u001b[39m\n\u001b[31m      }})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) {\u001b[39m\n\u001b[31m      toast(t('Config synced to server ✓','कॉन्फ़िग सर्वर पर सेव हुआ ✓'), 'success');\u001b[39m\n\u001b[31m      if (st) st.textContent = t('Last synced: just now','अभी सिंक हुआ');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast(j.error || t('Sync failed','सिंक विफल'), 'error');\u001b[39m\n\u001b[31m      if (st) st.textContent = j.error || '';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Network error','नेटवर्क त्रुटि'), 'error');\u001b[39m\n\u001b[31m    if (st) st.textContent = e.message;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function pushStoresToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!hub?.empId || !_adminUnlocked) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-stores', empId: hub.empId, stores })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) toast(`${t('Pushed to server','सर्वर पर पुश हुआ')} · ${j.count} ${t('stores','स्टोर')}`, 'success');\u001b[39m\n\u001b[31m    else toast(j.error || t('Server push failed','सर्वर पुश विफल'), 'error');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Could not reach server','सर्वर से संपर्क नहीं हो सका'), 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── End supervisor config management ────────────────────────────────·\u001b[39m\n\u001b[31m// PostgREST sync constants\u001b[39m\n\u001b[31mconst _RC_BASE      = '/db';\u001b[39m\n\u001b[31mconst _RC_READ      = { 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_WRITE     = { 'Content-Type': 'application/json', 'Content-Profile': 'recce', 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_UPSERT    = { ..._RC_WRITE, 'Prefer': 'resolution=merge-duplicates,return=minimal' };\u001b[39m\n\u001b[31mconst _INSTALL_RD   = { 'Content-Type': 'application/json', 'Accept-Profile': 'installation' };\u001b[39m\n\u001b[31mconst _INSTALL_WR   = { 'Content-Type': 'application/json', 'Content-Profile': 'installation', 'Accept-Profile': 'installation', 'Prefer': 'return=minimal' };·\u001b[39m\n\u001b[31m// ── Campaign selection state ──\u001b[39m\n\u001b[31mlet _selectedCampaignId = null;\u001b[39m\n\u001b[31mlet _notifySupervisor   = false;\u001b[39m\n\u001b[31mlet _campaignList       = [];\u001b[39m\n\u001b[31mlet _pendingJobFilter   = false;\u001b[39m\n\u001b[31mlet _linkJobSubId       = null;\u001b[39m\n\u001b[31mlet _brandingLocked     = false;·\u001b[39m\n\u001b[31mfunction _updateBrandingLock() {\u001b[39m\n\u001b[31m  const hub  = _recceHubUser();\u001b[39m\n\u001b[31m  const isHP = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const banner   = document.getElementById('branding-lock-banner');\u001b[39m\n\u001b[31m  const ovWrap   = document.getElementById('branding-override-wrap');\u001b[39m\n\u001b[31m  const brItems  = document.getElementById('br-items');\u001b[39m\n\u001b[31m  const brAdd    = document.getElementById('br-add');\u001b[39m\n\u001b[31m  const brYes    = document.getElementById('br-yes');\u001b[39m\n\u001b[31m  const brNo     = document.getElementById('br-no');\u001b[39m\n\u001b[31m  if (!banner) return;\u001b[39m\n\u001b[31m  if (_brandingLocked) {\u001b[39m\n\u001b[31m    banner.style.display   = '';\u001b[39m\n\u001b[31m    if (ovWrap)  ovWrap.style.display  = isHP ? '' : 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.pointerEvents = 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.opacity = '0.55';\u001b[39m\n\u001b[31m    if (brAdd)   brAdd.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='none'; brYes.style.opacity='0.5'; }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='none';  brNo.style.opacity='0.5';  }\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    banner.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brItems) { brItems.style.pointerEvents=''; brItems.style.opacity=''; }\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='';  brYes.style.opacity='';   }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='';   brNo.style.opacity='';    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction unlockBrandingOverride() {\u001b[39m\n\u001b[31m  if (!confirm(\u001b[39m\n\u001b[31m    'Client has already reviewed this recce.\\\\n' +\u001b[39m\n\u001b[31m    'Editing brandings will NOT remove their approval.\\\\n' +\u001b[39m\n\u001b[31m    'Continue ONLY if the client has verbally confirmed. Proceed?'\u001b[39m\n\u001b[31m  )) return;\u001b[39m\n\u001b[31m  _brandingLocked = false;\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  renderBrandings();\u001b[39m\n\u001b[31m  toast(t('Branding unlocked for this session', 'ब्रांडिंग इस सत्र के लिए अनलॉक'), 'info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadCampaignsForForm() {\u001b[39m\n\u001b[31m  const sel = document.getElementById('f-campaign-id');\u001b[39m\n\u001b[31m  if (!sel) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m    _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m  } catch(_) { _campaignList = []; }\u001b[39m\n\u001b[31m  sel.innerHTML =\u001b[39m\n\u001b[31m    '<option value=\\\"\\\">— Select job / campaign (optional) —</option>' +\u001b[39m\n\u001b[31m    _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('') +\u001b[39m\n\u001b[31m    '<option value=\\\"__NOTIFY__\\\">⚑ No campaign yet — notify supervisor</option>';\u001b[39m\n\u001b[31m  if (_selectedCampaignId) sel.value = _selectedCampaignId;\u001b[39m\n\u001b[31m  else if (_notifySupervisor) sel.value = '__NOTIFY__';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onCampaignSelect() {\u001b[39m\n\u001b[31m  const val = document.getElementById('f-campaign-id')?.value || '';\u001b[39m\n\u001b[31m  const noticeEl = document.getElementById('campaign-notify-msg');\u001b[39m\n\u001b[31m  if (val === '__NOTIFY__') {\u001b[39m\n\u001b[31m    _selectedCampaignId = null;\u001b[39m\n\u001b[31m    _notifySupervisor   = true;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'block';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    _selectedCampaignId = val || null;\u001b[39m\n\u001b[31m    _notifySupervisor   = false;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction generateRecceReportHtml(entry, photoUrls) {\u001b[39m\n\u001b[31m  const d    = entry.data || {};\u001b[39m\n\u001b[31m  const urls = photoUrls || {};\u001b[39m\n\u001b[31m  const agent = entry.submittedByName || entry.submittedBy || 'Field Agent';\u001b[39m\n\u001b[31m  const _safeId      = (entry.id||'').replace(/\\\\//g,'_').replace(/\\\\.\\\\./g,'');\u001b[39m\n\u001b[31m  const serverPdfUrl = _safeId ? `https://srv1111289.hstgr.cloud/screenshots/recce/views/${_safeId}.pdf` : '';\u001b[39m\n\u001b[31m  const brandLogoUrl = d.brandLogoUrl || _brandLogos[d.brand] || '';\u001b[39m\n\u001b[31m  const tsStr = new Date(entry.timestamp).toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric',hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\u001b[39m\n\u001b[31m  const gpsUrl = d.gpsCoords ? `https://maps.google.com/?q=${d.gpsCoords.lat},${d.gpsCoords.lng}` : null;·\u001b[39m\n\u001b[31m  const frontCount  = (urls.front||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const insideCount = (urls.inside||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const addlCount   = (urls.addl||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const brCount     = (d.brandings||[]).length;·\u001b[39m\n\u001b[31m  // pages: { id, url, bandHtml, cmt, dotLabel, dotColor }\u001b[39m\n\u001b[31m  const pages = [];·\u001b[39m\n\u001b[31m  (urls.front||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Front View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${frontCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.frontPhotos||[])[i]?.cmt||'', dotLabel:`FV${i+1}`, dotColor:'#3b82f6', catLabel:'Front View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.inside||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Inside View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${insideCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.insidePhotos||[])[i]?.cmt||'', dotLabel:`IV${i+1}`, dotColor:'#14b8a6', catLabel:'Inside View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (d.brandings||[]).forEach((b,i)=>{\u001b[39m\n\u001b[31m    const url=(urls.brandings||[])[i]; if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">${esc(b.type||'Branding')}</div><div class=\\\"ph-dims\\\">Width : ${esc(b.w||'?')}&Prime;&nbsp;&times;&nbsp;Height : ${esc(b.h||'?')}&Prime;&nbsp;&mdash;&nbsp;${esc(b.qty||1)} Nos</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${brCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:'', dotLabel:`B${i+1}`, dotColor:'#f97316', catLabel:b.type||'Branding',\u001b[39m\n\u001b[31m      tileDims:`${b.w||'?'}″×${b.h||'?'}″ — ${String(b.qty||1).padStart(2,'0')} Nos` });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.addl||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Additional</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${addlCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.addlPhotos||[])[i]?.desc||'', dotLabel:`A${i+1}`, dotColor:'#94a3b8', catLabel:'Additional', tileDims:'' });\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const sideItems = [\u001b[39m\n\u001b[31m    `<div class=\\\"si-item active\\\" data-tgt=\\\"pg-cover\\\" title=\\\"Cover\\\"><div class=\\\"si-dot\\\" style=\\\"background:#475569\\\">CV</div></div>`\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  pages.forEach(p => {\u001b[39m\n\u001b[31m    sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"${p.id}\\\" title=\\\"${p.dotLabel}\\\"><div class=\\\"si-dot\\\" style=\\\"background:${p.dotColor}\\\">${p.dotLabel}</div></div>`);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(d.hasVideo) sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-vid\\\" title=\\\"Video\\\"><div class=\\\"si-dot\\\" style=\\\"background:#a855f7\\\">VD</div></div>`);\u001b[39m\n\u001b[31m  if(urls.doc)   sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-doc\\\" title=\\\"Document\\\"><div class=\\\"si-dot\\\" style=\\\"background:#64748b\\\">DC</div></div>`);·\u001b[39m\n\u001b[31m  const thumbItems = [\u001b[39m\n\u001b[31m    ...pages,\u001b[39m\n\u001b[31m    ...(d.hasVideo?[{id:'pg-vid',url:null,catLabel:'Video',tileDims:'',dotLabel:'VD',dotColor:'#a855f7'}]:[]),\u001b[39m\n\u001b[31m    ...(urls.doc?[{id:'pg-doc',url:urls.doc,catLabel:'Document',tileDims:'',dotLabel:'DC',dotColor:'#64748b'}]:[])\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  const thumbsHtml = thumbItems.map(p=>`<div class=\\\"cov-thumb\\\" onclick=\\\"document.getElementById('${p.id}').scrollIntoView({behavior:'smooth'})\\\">${p.url?`<img src=\\\"${p.url}\\\" alt=\\\"\\\">`:(`<div class=\\\"cov-thumb-vid\\\">${p.catLabel==='Video'?'&#x25B6;&#xFE0F;':'&#x1F4C4;'}</div>`)}<div class=\\\"cov-thumb-ov\\\" style=\\\"border-top:3px solid ${p.dotColor}\\\"><div class=\\\"cov-thumb-cat\\\">${esc(p.catLabel)}</div>${p.tileDims?`<div class=\\\"cov-thumb-dims\\\">${esc(p.tileDims)}</div>`:''}<div class=\\\"cov-thumb-no\\\">${p.dotLabel}</div></div></div>`).join('');·\u001b[39m\n\u001b[31m  const pagesHtml = pages.map(p => `\u001b[39m\n\u001b[31m<div class=\\\"photo-page\\\" id=\\\"${p.id}\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\">${p.bandHtml}</div>\u001b[39m\n\u001b[31m  <div class=\\\"ph-img\\\"><a href=\\\"${p.url}\\\" target=\\\"_blank\\\"><img src=\\\"${p.url}\\\" loading=\\\"lazy\\\" alt=\\\"\\\"></a>${p.cmt?`<div class=\\\"ph-cmt\\\">${esc(p.cmt)}</div>`:''}</div>\u001b[39m\n\u001b[31m</div>`).join('');·\u001b[39m\n\u001b[31m  return `<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\"><head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m<title>Recce — ${esc(d.storeName||'Unknown')} · ${esc(d.brand||'')}</title>\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--dk:#0f172a;--nv2:#1a2f52;--or:#f97316;--g200:#e2e8f0;--g400:#94a3b8;--g600:#475569;--si:54px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0}\u001b[39m\n\u001b[31mhtml,body{height:100%;overflow:hidden}\u001b[39m\n\u001b[31mbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#111;color:var(--dk);display:flex}\u001b[39m\n\u001b[31ma{color:var(--or);text-decoration:none}\u001b[39m\n\u001b[31mimg{display:block}·\u001b[39m\n\u001b[31m/* ── Side index ── */\u001b[39m\n\u001b[31m.side-idx{width:var(--si);flex-shrink:0;background:var(--dk);overflow-y:auto;display:flex;flex-direction:column;align-items:center;padding:4px 0;scrollbar-width:none;z-index:50}\u001b[39m\n\u001b[31m.side-idx::-webkit-scrollbar{display:none}\u001b[39m\n\u001b[31m.si-item{width:100%;min-height:56px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s}\u001b[39m\n\u001b[31m.si-item:hover{background:rgba(255,255,255,.07)}\u001b[39m\n\u001b[31m.si-dot{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff;opacity:.4;transition:opacity .18s,transform .18s;line-height:1;text-align:center}\u001b[39m\n\u001b[31m.si-item.active .si-dot{opacity:1;transform:scale(1.15)}·\u001b[39m\n\u001b[31m/* ── Main scroll area ── */\u001b[39m\n\u001b[31m.main{flex:1;overflow-y:scroll;scroll-snap-type:y mandatory;scroll-behavior:smooth;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar{width:3px}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15)}·\u001b[39m\n\u001b[31m/* ── Cover ── */\u001b[39m\n\u001b[31m.cover{height:100vh;scroll-snap-align:start;flex-shrink:0;background:linear-gradient(135deg,#0f172a 0%,var(--nv2) 100%);color:#fff;display:flex;flex-direction:column;padding:24px 20px 20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.cover-badge{display:inline-flex;align-items:center;gap:5px;background:var(--or);color:#fff;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:1px;padding:3px 12px;border-radius:20px;margin-bottom:12px;align-self:flex-start}\u001b[39m\n\u001b[31m.cover h1{font-size:20px;font-weight:700;line-height:1.3;margin-bottom:4px}\u001b[39m\n\u001b[31m.cover-addr{color:rgba(255,255,255,.55);font-size:12px;margin-bottom:16px}\u001b[39m\n\u001b[31m.cg{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}\u001b[39m\n\u001b[31m.cm{background:rgba(255,255,255,.08);border-radius:8px;padding:8px 12px}\u001b[39m\n\u001b[31m.cm-l{font-size:9px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}\u001b[39m\n\u001b[31m.cm-v{font-size:13px;font-weight:600;color:#fff}\u001b[39m\n\u001b[31m.cm-v a{color:#fb923c}\u001b[39m\n\u001b[31m.cover-pbar{padding-top:8px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{background:var(--or);color:#fff;border:none;padding:10px 22px;border-radius:22px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}\u001b[39m\n\u001b[31m.btn-p:disabled{opacity:.4;cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-c{background:rgba(255,255,255,.1);color:rgba(255,255,255,.75);border:1px solid rgba(255,255,255,.2);padding:10px 18px;border-radius:22px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit}·\u001b[39m\n\u001b[31m/* ── Cover thumbnail grid ── */\u001b[39m\n\u001b[31m.cov-grid-hdr{font-size:10px;font-weight:700;color:rgba(255,255,255,.35);text-transform:uppercase;letter-spacing:1.2px;padding:10px 0 5px;flex-shrink:0}\u001b[39m\n\u001b[31m.cov-grid{flex:1;min-height:0;display:grid;gap:5px;overflow:hidden;align-content:start}\u001b[39m\n\u001b[31m.cov-thumb{position:relative;overflow:hidden;border-radius:7px;cursor:pointer;background:#1e293b;transition:transform .18s,box-shadow .18s}\u001b[39m\n\u001b[31m.cov-thumb:hover{transform:scale(1.05);box-shadow:0 4px 18px rgba(0,0,0,.55)}\u001b[39m\n\u001b[31m.cov-thumb img{width:100%;height:100%;object-fit:cover;display:block}\u001b[39m\n\u001b[31m.cov-thumb-vid{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:#0f172a}\u001b[39m\n\u001b[31m.cov-thumb-ov{position:absolute;inset:0;background:rgba(0,0,0,.28);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:5px;border-radius:7px}\u001b[39m\n\u001b[31m.cov-thumb-cat{color:rgba(255,255,255,.5);font-weight:900;text-align:center;text-transform:uppercase;letter-spacing:.8px;text-shadow:0 1px 6px rgba(0,0,0,.95);line-height:1.2;word-break:break-word}\u001b[39m\n\u001b[31m.cov-thumb-dims{color:rgba(255,255,255,.5);font-weight:700;text-align:center;text-shadow:0 1px 5px rgba(0,0,0,.95);letter-spacing:.3px;line-height:1.3}\u001b[39m\n\u001b[31m.cov-thumb-no{color:rgba(255,255,255,.5);font-weight:800;text-shadow:0 1px 4px rgba(0,0,0,.95);letter-spacing:.5px}\u001b[39m\n\u001b[31m#cover-btn{position:fixed;bottom:20px;right:16px;display:none;align-items:center;gap:6px;background:rgba(255,255,255,.15);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.25);color:#fff;padding:10px 22px;border-radius:50px;font-size:13px;font-weight:700;cursor:pointer;z-index:200;letter-spacing:.3px;box-shadow:0 2px 12px rgba(0,0,0,.3);font-family:inherit;transition:background .15s,transform .15s}\u001b[39m\n\u001b[31m#cover-btn:hover{background:rgba(255,255,255,.22);transform:scale(1.04)}·\u001b[39m\n\u001b[31m/* ── Print wait overlay ── */\u001b[39m\n\u001b[31m#print-overlay{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m@media print{#print-overlay{display:none!important}}·\u001b[39m\n\u001b[31m/* ── Loading progress bar ── */\u001b[39m\n\u001b[31m.load-bar{position:fixed;bottom:0;left:0;right:0;background:rgba(15,23,42,.95);padding:9px 16px;z-index:9999;display:flex;align-items:center;gap:12px;backdrop-filter:blur(6px)}\u001b[39m\n\u001b[31m.load-track{flex:1;height:5px;background:rgba(255,255,255,.12);border-radius:3px;overflow:hidden}\u001b[39m\n\u001b[31m.load-fill{height:100%;background:var(--or);width:0%;transition:width .35s ease;border-radius:3px}\u001b[39m\n\u001b[31m.load-txt{font-size:11px;color:rgba(255,255,255,.6);white-space:nowrap;min-width:160px}·\u001b[39m\n\u001b[31m/* ── Photo page ── */\u001b[39m\n\u001b[31m.photo-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ph-band{background:var(--dk);padding:16px 26px;flex-shrink:0;display:flex;align-items:center;gap:20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.ph-cat{font-size:35px;font-weight:800;color:#fff;letter-spacing:-.5px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.ph-dims{flex:1;font-size:18px;font-weight:600;color:var(--or);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}\u001b[39m\n\u001b[31m.ph-no{margin-left:auto;flex-shrink:0;font-size:21px;font-weight:700;color:rgba(255,255,255,.85);background:rgba(255,255,255,.1);padding:5px 20px;border-radius:24px;white-space:nowrap}\u001b[39m\n\u001b[31m.ph-of{font-size:18px;font-weight:400;color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.ph-img{flex:1;overflow:hidden;position:relative;background:#111}\u001b[39m\n\u001b[31m.ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m.ph-img img{width:100%;height:100%;object-fit:contain;display:block}\u001b[39m\n\u001b[31m.ph-cmt{position:absolute;bottom:0;left:0;right:0;padding:6px 14px;background:rgba(0,0,0,.62);font-size:11px;color:rgba(255,255,255,.75);font-style:italic;pointer-events:none}·\u001b[39m\n\u001b[31m/* ── Video / Doc pages ── */\u001b[39m\n\u001b[31m.vid-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;background:#fff}\u001b[39m\n\u001b[31m.vid-body{flex:1;padding:20px 24px;font-size:14px;color:var(--g600);border-left:4px solid var(--or)}\u001b[39m\n\u001b[31m.vid-body em{display:block;font-size:12px;color:var(--g400);margin-top:6px}\u001b[39m\n\u001b[31m.doc-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m.doc-wrap{flex:1;display:flex;align-items:center;justify-content:center;background:#111;overflow:hidden}\u001b[39m\n\u001b[31m.doc-img{max-width:100%;max-height:100%;object-fit:contain}·\u001b[39m\n\u001b[31m/* ── Cover header band ── */\u001b[39m\n\u001b[31m.cov-hdr{display:flex;gap:0;margin-bottom:12px;flex-shrink:0;border-radius:10px;overflow:hidden;border:1px solid rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.cov-hdr-l{flex:1;padding:14px 18px;display:flex;flex-direction:column;gap:5px;border-right:1px solid rgba(255,255,255,.1);min-width:0}\u001b[39m\n\u001b[31m.cov-hdr-r{width:170px;flex-shrink:0;padding:14px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:rgba(255,255,255,.04)}\u001b[39m\n\u001b[31m.cov-store{font-size:18px;font-weight:800;color:#fff;line-height:1.25;margin-bottom:2px}\u001b[39m\n\u001b[31m.cov-meta{font-size:12px;color:rgba(255,255,255,.55);display:flex;align-items:center;gap:5px;line-height:1.5}\u001b[39m\n\u001b[31m.cov-brand{background:var(--or);color:#fff;font-size:13px;font-weight:800;padding:5px 16px;border-radius:20px;text-align:center;letter-spacing:.3px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\u001b[39m\n\u001b[31m.cov-date-l{font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.8px;margin-bottom:2px;text-align:center}\u001b[39m\n\u001b[31m.cov-date-v{font-size:13px;font-weight:700;color:#fff;text-align:center}\u001b[39m\n\u001b[31m.cov-logo-box{background:#fff;border-radius:8px;padding:8px 14px;display:flex;align-items:center;justify-content:center;width:100%;max-width:138px}\u001b[39m\n\u001b[31m.cov-logo-box img{max-width:110px;max-height:44px;object-fit:contain;display:block}·\u001b[39m\n\u001b[31m/* ── Print ── */\u001b[39m\n\u001b[31m@page{size:A4 landscape;margin:12mm}\u001b[39m\n\u001b[31m@media print{\u001b[39m\n\u001b[31m  html,body{height:auto;overflow:visible;display:block}\u001b[39m\n\u001b[31m  .side-idx{display:none}\u001b[39m\n\u001b[31m  .main{overflow:visible;display:block;height:auto;scroll-snap-type:none}\u001b[39m\n\u001b[31m  .cover,.vid-page,.doc-page{height:auto;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m  .photo-page{height:186mm;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m  .cover{padding:20px 24px}\u001b[39m\n\u001b[31m  .cover-pbar{display:none}\u001b[39m\n\u001b[31m  .cov-hdr{margin-bottom:8px;border-radius:7px}\u001b[39m\n\u001b[31m  .cov-hdr-l{padding:10px 14px}\u001b[39m\n\u001b[31m  .cov-hdr-r{padding:10px 12px;width:150px}\u001b[39m\n\u001b[31m  .cov-store{font-size:15px}\u001b[39m\n\u001b[31m  .cov-meta{font-size:10px}\u001b[39m\n\u001b[31m  .cov-brand{font-size:11px;padding:3px 12px}\u001b[39m\n\u001b[31m  .cov-date-v{font-size:11px}\u001b[39m\n\u001b[31m  .ph-band{padding:5mm 13mm;gap:10mm}\u001b[39m\n\u001b[31m  .ph-cat{font-size:15mm}\u001b[39m\n\u001b[31m  .ph-dims{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-no{font-size:12mm;padding:2mm 8mm}\u001b[39m\n\u001b[31m  .ph-of{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-img{flex:1;display:flex;align-items:center;justify-content:center;background:#fff;overflow:hidden}\u001b[39m\n\u001b[31m  .ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m  .ph-img img{width:100%;height:100%;object-fit:contain}\u001b[39m\n\u001b[31m  .ph-cmt{position:static;background:transparent;color:#475569;padding:2mm 8mm;font-size:6mm}\u001b[39m\n\u001b[31m  .main>*:last-child{page-break-after:avoid;break-after:avoid}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m</style></head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<div class=\\\"side-idx\\\" id=\\\"side-idx\\\">${sideItems.join('')}</div>·\u001b[39m\n\u001b[31m<div class=\\\"main\\\" id=\\\"main\\\">·\u001b[39m\n\u001b[31m<div class=\\\"cover\\\" id=\\\"pg-cover\\\">\u001b[39m\n\u001b[31m  <div class=\\\"cov-hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-l\\\">\u001b[39m\n\u001b[31m      <div class=\\\"cov-store\\\">${esc(d.storeName||'Unknown Store')}</div>\u001b[39m\n\u001b[31m      ${(d.address||d.city)?`<div class=\\\"cov-meta\\\">&#x1F4CD; ${esc(d.address||'')}${d.city&&!(d.address||'').includes(d.city)?', '+esc(d.city):''}</div>`:''}\u001b[39m\n\u001b[31m      ${d.mobile?`<div class=\\\"cov-meta\\\">&#x1F4DE; ${esc(d.mobile)}</div>`:''}\u001b[39m\n\u001b[31m      ${d.email?`<div class=\\\"cov-meta\\\">&#x2709; ${esc(d.email)}</div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-r\\\">\u001b[39m\n\u001b[31m      ${brandLogoUrl\u001b[39m\n\u001b[31m        ? `<div class=\\\"cov-logo-box\\\"><img src=\\\"${brandLogoUrl}\\\" alt=\\\"${esc(d.brand||'')}\\\"></div>`\u001b[39m\n\u001b[31m        : (d.brand?`<div class=\\\"cov-brand\\\">${esc(d.brand)}</div>`:'')}\u001b[39m\n\u001b[31m      ${d.date?`<div><div class=\\\"cov-date-l\\\">Recce Date</div><div class=\\\"cov-date-v\\\">${esc(d.date)}</div></div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${thumbItems.length ? `<div class=\\\"cov-grid-hdr\\\">&#x1F4F7; ${thumbItems.length} page${thumbItems.length!==1?'s':''} &mdash; tap any to jump</div><div class=\\\"cov-grid\\\" id=\\\"cov-grid\\\">${thumbsHtml}</div>` : ''}\u001b[39m\n\u001b[31m  <div class=\\\"cover-pbar\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" id=\\\"btn-print\\\" onclick=\\\"doPDF()\\\">&#x1F4C4;&nbsp;PDF</button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-c\\\" onclick=\\\"window.close()\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m${pagesHtml}·\u001b[39m\n\u001b[31m${d.hasVideo?`\u001b[39m\n\u001b[31m<div class=\\\"vid-page\\\" id=\\\"pg-vid\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Video</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"vid-body\\\">${esc(d.videoNote||'Video recorded during visit')}${d.videoCmt?`<em>${esc(d.videoCmt)}</em>`:''}</div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m${urls.doc?`\u001b[39m\n\u001b[31m<div class=\\\"doc-page\\\" id=\\\"pg-doc\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Document</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"doc-wrap\\\"><a href=\\\"${urls.doc}\\\" target=\\\"_blank\\\"><img class=\\\"doc-img\\\" src=\\\"${urls.doc}\\\" loading=\\\"lazy\\\" alt=\\\"Document\\\"></a></div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"print-overlay\\\"><div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Preparing print&hellip;</div><div class=\\\"po-sub\\\" id=\\\"po-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"po-pfill\\\"></div></div></div>\u001b[39m\n\u001b[31m${pages.length ? `<div class=\\\"load-bar\\\" id=\\\"load-bar\\\"><div class=\\\"load-track\\\"><div class=\\\"load-fill\\\" id=\\\"load-fill\\\"></div></div><div class=\\\"load-txt\\\" id=\\\"load-txt\\\">Loading photos&#x2026;</div></div>` : ''}\u001b[39m\n\u001b[31m${thumbItems.length ? `<button id=\\\"cover-btn\\\" onclick=\\\"document.getElementById('pg-cover').scrollIntoView({behavior:'smooth'})\\\">&#x1F3E0;&nbsp;Cover Page</button>` : ''}·\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var main=document.getElementById('main');\u001b[39m\n\u001b[31m  var items=document.querySelectorAll('.si-item');\u001b[39m\n\u001b[31m  var covBtn=document.getElementById('cover-btn');\u001b[39m\n\u001b[31m  function setActive(id){\u001b[39m\n\u001b[31m    items.forEach(function(el){el.classList.toggle('active',el.dataset.tgt===id);});\u001b[39m\n\u001b[31m    var a=document.querySelector('.si-item[data-tgt=\\\"'+id+'\\\"]');\u001b[39m\n\u001b[31m    if(a) a.scrollIntoView({block:'nearest'});\u001b[39m\n\u001b[31m    if(covBtn) covBtn.style.display=id==='pg-cover'?'none':'flex';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  items.forEach(function(el){\u001b[39m\n\u001b[31m    el.addEventListener('click',function(){\u001b[39m\n\u001b[31m      var t=document.getElementById(el.dataset.tgt);\u001b[39m\n\u001b[31m      if(t) t.scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if('IntersectionObserver' in window){\u001b[39m\n\u001b[31m    var obs=new IntersectionObserver(function(entries){\u001b[39m\n\u001b[31m      entries.forEach(function(e){if(e.isIntersecting&&e.intersectionRatio>=0.45) setActive(e.target.id);});\u001b[39m\n\u001b[31m    },{root:main,threshold:0.45});\u001b[39m\n\u001b[31m    document.querySelectorAll('[id^=\\\"pg-\\\"]').forEach(function(p){obs.observe(p);});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  setActive('pg-cover');\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var imgs=Array.from(document.querySelectorAll('img'));\u001b[39m\n\u001b[31m  var total=imgs.length,loaded=0;\u001b[39m\n\u001b[31m  var bar=document.getElementById('load-bar');\u001b[39m\n\u001b[31m  var fill=document.getElementById('load-fill');\u001b[39m\n\u001b[31m  var txt=document.getElementById('load-txt');\u001b[39m\n\u001b[31m  var printPending=false,printShowTime=0;\u001b[39m\n\u001b[31m  var mm=96/25.4;\u001b[39m\n\u001b[31m  var SERVER_PDF='${serverPdfUrl}';\u001b[39m\n\u001b[31m  function updatePoBar(){\u001b[39m\n\u001b[31m    var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m    var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(poFill) poFill.style.width=(total?Math.round(loaded/total*100):100)+'%';\u001b[39m\n\u001b[31m    if(poSub) poSub.textContent=loaded+' / '+total+' photos ready';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function done(){\u001b[39m\n\u001b[31m    if(fill) fill.style.width='100%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='✓ All '+total+' photos ready';\u001b[39m\n\u001b[31m    setTimeout(function(){\u001b[39m\n\u001b[31m      if(bar){bar.style.transition='opacity .6s';bar.style.opacity='0';}\u001b[39m\n\u001b[31m      setTimeout(function(){if(bar)bar.style.display='none';},650);\u001b[39m\n\u001b[31m    },2000);\u001b[39m\n\u001b[31m    if(printPending){\u001b[39m\n\u001b[31m      printPending=false;\u001b[39m\n\u001b[31m      var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m      var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m      var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(poFill) poFill.style.width='100%';\u001b[39m\n\u001b[31m      if(poSub) poSub.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},Math.max(400,2000-(Date.now()-printShowTime)));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function onImg(){\u001b[39m\n\u001b[31m    loaded++;\u001b[39m\n\u001b[31m    if(fill) fill.style.width=Math.round(loaded/total*100)+'%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… '+loaded+' / '+total;\u001b[39m\n\u001b[31m    if(printPending) updatePoBar();\u001b[39m\n\u001b[31m    if(loaded>=total) done();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  /* ── PDF layout helpers ── */\u001b[39m\n\u001b[31m  function fitBandFonts(pageW){\u001b[39m\n\u001b[31m    var padH=2*13*mm,gapH=2*10*mm,noPadH=2*8*mm;\u001b[39m\n\u001b[31m    var avail=pageW-padH-gapH;\u001b[39m\n\u001b[31m    var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-band').forEach(function(band){\u001b[39m\n\u001b[31m      var cat=band.querySelector('.ph-cat');\u001b[39m\n\u001b[31m      var dims=band.querySelector('.ph-dims');\u001b[39m\n\u001b[31m      var no=band.querySelector('.ph-no');\u001b[39m\n\u001b[31m      if(!cat) return;\u001b[39m\n\u001b[31m      var catTxt=cat.textContent.trim();\u001b[39m\n\u001b[31m      var dimsTxt=dims?dims.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      var noTxt=no?no.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      function tw(sc){\u001b[39m\n\u001b[31m        var cf=15*sc*mm,df=10*sc*mm,nf=12*sc*mm;\u001b[39m\n\u001b[31m        ctx.font='800 '+cf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var cw=ctx.measureText(catTxt).width;\u001b[39m\n\u001b[31m        ctx.font='600 '+df+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var dw=dims?ctx.measureText(dimsTxt).width:0;\u001b[39m\n\u001b[31m        ctx.font='700 '+nf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var nw=no?ctx.measureText(noTxt).width+noPadH:0;\u001b[39m\n\u001b[31m        return cw+dw+nw;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      var scale=1.0;\u001b[39m\n\u001b[31m      if(tw(scale)>avail){\u001b[39m\n\u001b[31m        var lo=0.3,hi=1.0;\u001b[39m\n\u001b[31m        for(var i=0;i<10;i++){var mid=(lo+hi)/2;if(tw(mid)<=avail)lo=mid;else hi=mid;}\u001b[39m\n\u001b[31m        scale=lo*0.93;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      cat.style.setProperty('font-size',Math.round(15*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(dims) dims.style.setProperty('font-size',Math.round(10*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(no) no.style.setProperty('font-size',Math.round(12*scale*mm)+'px','important');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function sizePdfThumbs(pageW,pageH){\u001b[39m\n\u001b[31m    var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m    if(!grid||!grid.children.length) return;\u001b[39m\n\u001b[31m    var coverPage=document.getElementById('pg-cover');\u001b[39m\n\u001b[31m    var usedH=56;\u001b[39m\n\u001b[31m    if(coverPage){\u001b[39m\n\u001b[31m      Array.from(coverPage.children).forEach(function(el){\u001b[39m\n\u001b[31m        if(el!==grid) usedH+=el.offsetHeight||0;\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    var gridH=Math.max(80,pageH-usedH);\u001b[39m\n\u001b[31m    var n=grid.children.length,gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m    for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m      var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m      var w=(pageW-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m      var h=w*asp;\u001b[39m\n\u001b[31m      if(rows*h+(rows-1)*gap<=gridH&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m    grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m    grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m    var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m    var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m    var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function preparePdfLayout(){\u001b[39m\n\u001b[31m    var pageW=Math.round((297-24)*mm);\u001b[39m\n\u001b[31m    var pageH=Math.round((210-24)*mm);\u001b[39m\n\u001b[31m    fitBandFonts(pageW);\u001b[39m\n\u001b[31m    sizePdfThumbs(pageW,pageH);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.preparePdfLayout=preparePdfLayout;\u001b[39m\n\u001b[31m  function restorePdfLayout(){\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-cat,.ph-dims,.ph-no').forEach(function(el){\u001b[39m\n\u001b[31m      el.style.removeProperty('font-size');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(window._screenSizeThumbs) window._screenSizeThumbs();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.addEventListener('afterprint',restorePdfLayout);\u001b[39m\n\u001b[31m  function _doBrowserPrint(){\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    printShowTime=Date.now();\u001b[39m\n\u001b[31m    preparePdfLayout();\u001b[39m\n\u001b[31m    if(total===0||loaded>=total){\u001b[39m\n\u001b[31m      var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m      if(ps) ps.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},2000);\u001b[39m\n\u001b[31m      return;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    printPending=true;\u001b[39m\n\u001b[31m    updatePoBar();\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if((!img.complete||img.naturalWidth===0)&&img.getAttribute('loading')==='lazy'){\u001b[39m\n\u001b[31m        img.loading='eager';var s=img.src;img.src='';img.src=s;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.doPDF=async function(){\u001b[39m\n\u001b[31m    if(!SERVER_PDF){_doBrowserPrint();return;}\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      var r=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m      if(r.ok){window.open(SERVER_PDF,'_blank');return;}\u001b[39m\n\u001b[31m    }catch(_){}\u001b[39m\n\u001b[31m    // PDF not ready yet — show overlay and poll\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    if(pf) pf.style.width='0%';\u001b[39m\n\u001b[31m    if(ps) ps.textContent='Waiting for server PDF…';\u001b[39m\n\u001b[31m    var tries=0;\u001b[39m\n\u001b[31m    (async function poll(){\u001b[39m\n\u001b[31m      tries++;\u001b[39m\n\u001b[31m      if(pf) pf.style.width=Math.min(88,tries*8)+'%';\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        var r2=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m        if(r2.ok){\u001b[39m\n\u001b[31m          if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m          setTimeout(function(){if(ov)ov.style.display='none';window.open(SERVER_PDF,'_blank');},400);\u001b[39m\n\u001b[31m          return;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      }catch(_){}\u001b[39m\n\u001b[31m      if(tries>=12){if(ov)ov.style.display='none';_doBrowserPrint();return;}\u001b[39m\n\u001b[31m      setTimeout(poll,5000);\u001b[39m\n\u001b[31m    })();\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  if(total===0){if(bar)bar.style.display='none';}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… 0 / '+total;\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if(img.complete&&img.naturalWidth>0) onImg();\u001b[39m\n\u001b[31m      else{img.addEventListener('load',onImg);img.addEventListener('error',onImg);}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m  if(grid&&grid.children.length>0){\u001b[39m\n\u001b[31m    function sizeThumbs(){\u001b[39m\n\u001b[31m      var n=grid.children.length;\u001b[39m\n\u001b[31m      var gw=grid.clientWidth,gh=grid.clientHeight;\u001b[39m\n\u001b[31m      if(!gw||!gh) return;\u001b[39m\n\u001b[31m      var gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m      for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m        var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m        var w=(gw-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m        var h=w*asp;\u001b[39m\n\u001b[31m        if(rows*h+(rows-1)*gap<=gh&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m      grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m      grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m      var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m      var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m      var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    window._screenSizeThumbs=sizeThumbs;\u001b[39m\n\u001b[31m    requestAnimationFrame(function(){requestAnimationFrame(sizeThumbs);});\u001b[39m\n\u001b[31m    window.addEventListener('resize',sizeThumbs);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m</scr`+'ipt>'+`\u001b[39m\n\u001b[31m</body></html>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncToPostgres(entry) {\u001b[39m\n\u001b[31m  const d   = entry.data || {};\u001b[39m\n\u001b[31m  const hub = _recceHubUser();·\u001b[39m\n\u001b[31m  // Step 1 — upload all photos to VPS, get permanent server URLs\u001b[39m\n\u001b[31m  let photoUrls = { front:[], inside:[], brandings:[], addl:[], doc:null };\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const pResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type: 'save-photos', subId: entry.id,\u001b[39m\n\u001b[31m        photos: {\u001b[39m\n\u001b[31m          front:    (d.frontPhotos||[]).map(p=>({b64:p.b64,   cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64,  cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||null})),\u001b[39m\n\u001b[31m          addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64,   desc:p.desc||''})),\u001b[39m\n\u001b[31m          doc:      d.docB64 || null,\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (pResp.ok) { const r=await pResp.json(); if(r.success) {\u001b[39m\n\u001b[31m      photoUrls=r.photoUrls;\u001b[39m\n\u001b[31m      // Merge retained existing URLs for edit re-submits\u001b[39m\n\u001b[31m      if (entry.editedAt) {\u001b[39m\n\u001b[31m        photoUrls.front    =(photoUrls.front   ||[]).map((u,i)=>u||(d.frontPhotos  ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.inside   =(photoUrls.inside  ||[]).map((u,i)=>u||(d.insidePhotos ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.addl     =(photoUrls.addl    ||[]).map((u,i)=>u||(d.addlPhotos   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.brandings=(photoUrls.brandings||[]).map((u,i)=>u||(d.brandings   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        if(!photoUrls.doc) photoUrls.doc=d._docExistingUrl||null;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }}\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-photos] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 1.5 — trigger Google Slides via proxy using permanent photo URLs (fire-and-forget)\u001b[39m\n\u001b[31m  (async()=>{try{\u001b[39m\n\u001b[31m    const _hasPh=(photoUrls.front||[]).some(Boolean)||(photoUrls.inside||[]).some(Boolean)||(photoUrls.brandings||[]).some(Boolean);\u001b[39m\n\u001b[31m    if(!_hasPh)return;\u001b[39m\n\u001b[31m    const _gu=(await cfg('slides-gas-url'))||(await cfg('gas-url'))||DEFAULT_GAS_URL;if(!_gu)return;\u001b[39m\n\u001b[31m    await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({\u001b[39m\n\u001b[31m      type:'make-slides',gasUrl:_gu,subId:entry.id,\u001b[39m\n\u001b[31m      storeInfo:{storeName:d.storeName||'',brand:d.brand||'',address:d.address||'',mobile:d.mobile||'',date:d.date||'',city:d.city||'',gpsCoords:d.gpsCoords||null},\u001b[39m\n\u001b[31m      photoGroups:{\u001b[39m\n\u001b[31m        front:    (photoUrls.front   ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.frontPhotos  ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        inside:   (photoUrls.inside  ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.insidePhotos ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        brandings:(photoUrls.brandings||[]).filter(Boolean).map((url,i)=>({url,meta:{type:(d.brandings||[])[i]?.type,w:(d.brandings||[])[i]?.w,h:(d.brandings||[])[i]?.h,qty:(d.brandings||[])[i]?.qty,sqft:(d.brandings||[])[i]?.sqft}})),\u001b[39m\n\u001b[31m        addl:    (photoUrls.addl    ||[]).filter(Boolean).map((url,i)=>({url,desc:(d.addlPhotos  ||[])[i]?.desc||''})),\u001b[39m\n\u001b[31m      },\u001b[39m\n\u001b[31m    })});\u001b[39m\n\u001b[31m    entry.gasAt=new Date().toISOString();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[recce-slides]',e.message);}}\u001b[39m\n\u001b[31m  )();·\u001b[39m\n\u001b[31m  // Step 2 — generate rich HTML report using server URLs, save to VPS\u001b[39m\n\u001b[31m  let view_url = null;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const html  = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m    const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-view', subId: entry.id, html })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (vResp.ok) { const r=await vResp.json(); if(r.success) view_url=r.url; }\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-view] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 3 — upsert to PostgreSQL with photo URLs + view URL\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch(`${_RC_BASE}/submissions`, {\u001b[39m\n\u001b[31m      method: 'POST', headers: _RC_UPSERT,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        sub_id:         entry.id,\u001b[39m\n\u001b[31m        store_name:     d.storeName    || 'Unknown',\u001b[39m\n\u001b[31m        brand:          d.brand        || null,\u001b[39m\n\u001b[31m        client_name:    d.clientName   || null,\u001b[39m\n\u001b[31m        visit_date:     d.date         || new Date().toISOString().slice(0,10),\u001b[39m\n\u001b[31m        address:        d.address      || null,\u001b[39m\n\u001b[31m        mobile:         d.mobile       || null,\u001b[39m\n\u001b[31m        city:           d.city         || null,\u001b[39m\n\u001b[31m        has_branding:   !!(d.brandings?.length),\u001b[39m\n\u001b[31m        branding_count: d.brandings?.length || 0,\u001b[39m\n\u001b[31m        has_video:      !!d.hasVideo,\u001b[39m\n\u001b[31m        front_photos:   d.frontPhotos?.length  || 0,\u001b[39m\n\u001b[31m        inside_photos:  d.insidePhotos?.length || 0,\u001b[39m\n\u001b[31m        addl_photos:    d.addlPhotos?.length   || 0,\u001b[39m\n\u001b[31m        gps_lat:        d.gpsCoords?.lat       || null,\u001b[39m\n\u001b[31m        gps_lng:        d.gpsCoords?.lng       || null,\u001b[39m\n\u001b[31m        submitted_by:   hub.empId              || null,\u001b[39m\n\u001b[31m        submitted_at:   entry.timestamp,\u001b[39m\n\u001b[31m        campaign_id:    entry.campaignId       || null,\u001b[39m\n\u001b[31m        photo_urls:     photoUrls,\u001b[39m\n\u001b[31m        view_url,\u001b[39m\n\u001b[31m        meta: {\u001b[39m\n\u001b[31m          brandings: (d.brandings||[]).map(b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft})),\u001b[39m\n\u001b[31m          videoNote: d.videoNote || null,\u001b[39m\n\u001b[31m          videoCmt:  d.videoCmt  || null,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        status: 'submitted',\u001b[39m\n\u001b[31m        edit_assigned_to: null,\u001b[39m\n\u001b[31m        edit_comment: null,\u001b[39m\n\u001b[31m        edited_at: entry.editedAt || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    return { ok: true, viewUrl: view_url };\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    console.warn('[recce-db] sync error:', e.message);\u001b[39m\n\u001b[31m    return { ok: false, viewUrl: null };\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mconst DEFAULT_ADMIN_HASH='42d372e6110bee134990ac6881c3d5eb568482008add9a859f37f10d759430e8';·\u001b[39m\n\u001b[31masync function saveGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('gas-url',url||DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  toast('Endpoint saved','success');\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function testEndpoint(){\u001b[39m\n\u001b[31m  const url=(await cfg('gas-url'))||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  try{await fetch(url,{method:'POST',mode:'no-cors',body:JSON.stringify({test:true})});toast('Endpoint reachable ✓','success');}\u001b[39m\n\u001b[31m  catch{toast('Cannot reach endpoint','error')}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  cfg('gas-url').then(url=>{\u001b[39m\n\u001b[31m    const u=url||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    // Show last 30 chars only for privacy\u001b[39m\n\u001b[31m    el.textContent='Endpoint: …'+u.slice(-30);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── SLIDES GAS URL ────────────────────────────────────────────\u001b[39m\n\u001b[31masync function saveSlidesGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('slides-gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('slides-gas-url', url);\u001b[39m\n\u001b[31m  toast('Slides GAS URL saved','success');\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function updateSlidesGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('slides-gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  const u=await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  el.textContent=u?'Configured: …'+u.slice(-30):'Not configured';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── MAKE SLIDES ───────────────────────────────────────────────\u001b[39m\n\u001b[31masync function makeSlides(id){\u001b[39m\n\u001b[31m  const gasUrl = await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  if(!gasUrl){\u001b[39m\n\u001b[31m    toast('Configure Slides GAS URL in Settings first','error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const entry = await dbGet('subs', id);\u001b[39m\n\u001b[31m  if(!entry){ toast('Entry not found','error'); return; }\u001b[39m\n\u001b[31m  const d = entry.data;·\u001b[39m\n\u001b[31m  toast('Uploading photos & generating slides…','info');·\u001b[39m\n\u001b[31m  // Build photo groups payload\u001b[39m\n\u001b[31m  const photoGroups = {\u001b[39m\n\u001b[31m    front:    (d.frontPhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64, cmt:p.desc||''})),\u001b[39m\n\u001b[31m    brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||'', meta:{type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft}})),\u001b[39m\n\u001b[31m  };·\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type:       'recce',\u001b[39m\n\u001b[31m        subId:      id,\u001b[39m\n\u001b[31m        gasUrl:     gasUrl,\u001b[39m\n\u001b[31m        storeInfo:  {\u001b[39m\n\u001b[31m          storeName: d.storeName, brand: d.brand,\u001b[39m\n\u001b[31m          date: d.date, address: d.address,\u001b[39m\n\u001b[31m          mobile: d.mobile, gpsCoords: d.gpsCoords,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        photoGroups,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const result = await resp.json();\u001b[39m\n\u001b[31m    if(result.success && result.slideUrl){\u001b[39m\n\u001b[31m      // Store slide URL on the entry\u001b[39m\n\u001b[31m      entry.slideUrl = result.slideUrl;\u001b[39m\n\u001b[31m      await dbPut('subs', entry);\u001b[39m\n\u001b[31m      toast('✅ Slides ready!','success');\u001b[39m\n\u001b[31m      window.open(result.slideUrl, '_blank');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast('Slides error: '+(result.error||'Unknown'),'error');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e){\u001b[39m\n\u001b[31m    toast('Network error: '+e.message,'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN LOGIN ──────────────────────────────────────────────\u001b[39m\n\u001b[31mfunction showAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-error').style.display='none';\u001b[39m\n\u001b[31m  // Restore saved config URL\u001b[39m\n\u001b[31m  cfg('admin-cfg-url').then(u=>{if(u&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=u;});\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('admin-pwd').focus(),100);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveAdminCfgUrl(){\u001b[39m\n\u001b[31m  // Admin cfg URL can be saved without login (needed to set up auth itself)\u001b[39m\n\u001b[31m  // But we warn if saving while unlocked only\u001b[39m\n\u001b[31m  const url=document.getElementById('admin-cfg-url').value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  await cfg('admin-cfg-url',url);\u001b[39m\n\u001b[31m  toast('Config URL saved — will use on next login attempt','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function verifyAdmin(){\u001b[39m\n\u001b[31m  // Hub admins (harish/pramod) are auto-unlocked — no password needed\u001b[39m\n\u001b[31m  if (_adminUnlocked) { adminLoginSuccess(); return; }\u001b[39m\n\u001b[31m  const pwd=document.getElementById('admin-pwd').value;\u001b[39m\n\u001b[31m  if(!pwd){document.getElementById('admin-error').style.display='block';document.getElementById('admin-error').textContent='Enter password';return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('admin-login-btn');btn.disabled=true;btn.textContent='Verifying…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // Try server verification first\u001b[39m\n\u001b[31m    const cfgUrl=(await cfg('admin-cfg-url'))||'';\u001b[39m\n\u001b[31m    if(cfgUrl){\u001b[39m\n\u001b[31m      const r=await fetch(cfgUrl,{cache:'no-store'});\u001b[39m\n\u001b[31m      const j=await r.json();\u001b[39m\n\u001b[31m      // Server JSON format: {\\\"password\\\":\\\"plaintext\\\"} or {\\\"hash\\\":\\\"sha256hash\\\"}\u001b[39m\n\u001b[31m      let match=false;\u001b[39m\n\u001b[31m      if(j.password){match=(j.password===pwd);}\u001b[39m\n\u001b[31m      else if(j.hash){\u001b[39m\n\u001b[31m        // SHA-256 comparison\u001b[39m\n\u001b[31m        const enc=new TextEncoder();\u001b[39m\n\u001b[31m        const data=enc.encode(pwd);\u001b[39m\n\u001b[31m        const hashBuf=await crypto.subtle.digest('SHA-256',data);\u001b[39m\n\u001b[31m        const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m        match=(hashHex===j.hash);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      if(match){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m      else{showAdminError('Incorrect password');return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Fallback: local password stored in settings\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if(localHash){\u001b[39m\n\u001b[31m      const enc=new TextEncoder();\u001b[39m\n\u001b[31m      const hashBuf=await crypto.subtle.digest('SHA-256',enc.encode(pwd));\u001b[39m\n\u001b[31m      const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m      if(hashHex===localHash){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Final fallback: check against hardcoded default hash\u001b[39m\n\u001b[31m    const enc2=new TextEncoder();\u001b[39m\n\u001b[31m    const hb2=await crypto.subtle.digest('SHA-256',enc2.encode(pwd));\u001b[39m\n\u001b[31m    const hh2=Array.from(new Uint8Array(hb2)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    if(hh2===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }catch(err){\u001b[39m\n\u001b[31m    // Network error — try all local fallbacks\u001b[39m\n\u001b[31m    const enc3=new TextEncoder();\u001b[39m\n\u001b[31m    const hb3=await crypto.subtle.digest('SHA-256',enc3.encode(pwd));\u001b[39m\n\u001b[31m    const hh3=Array.from(new Uint8Array(hb3)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if((localHash&&hh3===localHash)||hh3===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }finally{btn.disabled=false;btn.textContent='Login';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showAdminError(msg){\u001b[39m\n\u001b[31m  const el=document.getElementById('admin-error');\u001b[39m\n\u001b[31m  el.textContent=msg;el.style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminLoginSuccess(){\u001b[39m\n\u001b[31m  _adminUnlocked=true;\u001b[39m\n\u001b[31m  closeAdminLogin();\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  cfg('gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  cfg('slides-gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('slides-gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||'';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  toast('Admin mode unlocked','success');\u001b[39m\n\u001b[31m  setTimeout(lockAdmin,10*60*1000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction lockAdmin(){\u001b[39m\n\u001b[31m  _adminUnlocked=false;\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  toast('Admin session ended','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updAvailTag(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-avail-tag');\u001b[39m\n\u001b[31m  const ct=document.getElementById('store-avail-count');\u001b[39m\n\u001b[31m  const txt=stores.length?`${stores.length} stores`:'No store list';\u001b[39m\n\u001b[31m  if(el)el.textContent=txt;\u001b[39m\n\u001b[31m  if(ct)ct.textContent=stores.length?t(`${stores.length} stores available — tap to browse`,`${stores.length} स्टोर उपलब्ध — दबाएं`):t('No store list loaded yet','कोई स्टोर सूची नहीं');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PICKER\u001b[39m\n\u001b[31mfunction openPicker(){\u001b[39m\n\u001b[31m  if(!stores.length){toast('Load a store list in Settings first','error');return;}\u001b[39m\n\u001b[31m  document.getElementById('povl').classList.add('open');\u001b[39m\n\u001b[31m  document.getElementById('psearch').value='';\u001b[39m\n\u001b[31m  filterPicker('');\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('psearch').focus(),150);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closePicker(){document.getElementById('povl').classList.remove('open');}\u001b[39m\n\u001b[31masync function filterPicker(q){\u001b[39m\n\u001b[31m  const list=document.getElementById('plist');\u001b[39m\n\u001b[31m  const words=q.toLowerCase().trim().split(/\\\\s+/).filter(Boolean);\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const lastVisit={};\u001b[39m\n\u001b[31m  subs.forEach(s=>{const nm=s.data?.storeName;if(nm&&(!lastVisit[nm]||s.timestamp>lastVisit[nm]))lastVisit[nm]=s.timestamp;});·\u001b[39m\n\u001b[31m  // Multi-word: ALL words must match somewhere in any field (search across both English and Hindi)\u001b[39m\n\u001b[31m  let fl=stores.filter(s=>{\u001b[39m\n\u001b[31m    if(!words.length)return true;\u001b[39m\n\u001b[31m    const hay=[s.name,s.nameHi,s.address,s.addressHi,s.mobile,s.city,s.cityHi,s.distName,s.distNameHi,s.brand,s.sales,s.proj,s.glowSign,s.inshop]\u001b[39m\n\u001b[31m               .map(x=>(x||'').toLowerCase()).join(' ');\u001b[39m\n\u001b[31m    return words.every(w=>hay.includes(w));\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(fl.length>100)fl=fl.slice(0,100);·\u001b[39m\n\u001b[31m  if(!fl.length){\u001b[39m\n\u001b[31m    const esc=q.replace(/'/g,\\\"\\\\\\\\'\\\");\u001b[39m\n\u001b[31m    list.innerHTML=`<div style=\\\"text-align:center;padding:32px 16px;color:var(--g400);font-size:14px\\\">No stores match \\\"${q}\\\"<br><span style=\\\"font-size:12px\\\">Try fewer or different words</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('${esc}')\\\">+ Add \\\"${q}\\\" as new store</div>`;\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Group by brand (including empty brand)\u001b[39m\n\u001b[31m  const g={};\u001b[39m\n\u001b[31m  fl.forEach(s=>{\u001b[39m\n\u001b[31m    const b=s.brand||'(No Brand — will ask)';\u001b[39m\n\u001b[31m    if(!g[b])g[b]=[];\u001b[39m\n\u001b[31m    g[b].push(s);\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html='';\u001b[39m\n\u001b[31m  Object.keys(g).sort().forEach(br=>{\u001b[39m\n\u001b[31m    html+=`<div class=\\\"psec\\\">${br}</div>`;\u001b[39m\n\u001b[31m    g[br].forEach(s=>{\u001b[39m\n\u001b[31m      const lv=lastVisit[s.name];\u001b[39m\n\u001b[31m      const lvStr=lv?`🕐 Last: ${new Date(lv).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'2-digit'})}`:'';\u001b[39m\n\u001b[31m      const chips=[];\u001b[39m\n\u001b[31m      if(s.glowSign&&s.glowSign.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dcfce7;color:#14532d;padding:2px 6px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m      if(s.inshop&&s.inshop.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dbeafe;color:#1e40af;padding:2px 6px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m      if(s.proj)chips.push(`<span style=\\\"font-size:10px;background:var(--g100);color:var(--g600);padding:2px 6px;border-radius:10px\\\">Target: ${s.proj}</span>`);\u001b[39m\n\u001b[31m      const enc=JSON.stringify(s).replace(/\\\"/g,'&quot;');\u001b[39m\n\u001b[31m      const mapsUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m      const waUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const telUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const dispName=LANG==='hi'&&s.nameHi?s.nameHi:s.name;\u001b[39m\n\u001b[31m      const dispAddr=LANG==='hi'&&s.addressHi?s.addressHi:s.address;\u001b[39m\n\u001b[31m      const dispDist=LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m      html+=`<div class=\\\"pitem\\\" onclick=\\\"pickStore(${enc})\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"pi-name\\\">${dispName}</div>\u001b[39m\n\u001b[31m          ${dispAddr?`<div class=\\\"pi-addr\\\">📍 ${dispAddr}</div>`:''}\u001b[39m\n\u001b[31m          ${s.mobile?`<div class=\\\"pi-addr\\\">📞 ${s.mobile}</div>`:''}\u001b[39m\n\u001b[31m          ${dispDist?`<div class=\\\"pi-addr\\\" style=\\\"color:var(--am)\\\">👤 ${dispDist}</div>`:''}\u001b[39m\n\u001b[31m          ${lvStr?`<div class=\\\"pi-last\\\">${lvStr}</div>`:''}\u001b[39m\n\u001b[31m          ${chips.length?`<div style=\\\"display:flex;gap:4px;flex-wrap:wrap;margin-top:4px\\\">${chips.join('')}</div>`:''}\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;gap:6px;margin-top:7px\\\" onclick=\\\"event.stopPropagation()\\\">\u001b[39m\n\u001b[31m            ${mapsUrl?`<a href=\\\"${mapsUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#e0f2fe;color:#0369a1;border-radius:20px;text-decoration:none;font-weight:600\\\">🗺 Maps</a>`:''}\u001b[39m\n\u001b[31m            ${waUrl?`<a href=\\\"${waUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#dcfce7;color:#15803d;border-radius:20px;text-decoration:none;font-weight:600\\\">💬 WhatsApp</a>`:''}\u001b[39m\n\u001b[31m            ${telUrl?`<a href=\\\"${telUrl}\\\" style=\\\"font-size:11px;padding:4px 10px;background:#f0fdf4;color:#166534;border-radius:20px;text-decoration:none;font-weight:600\\\">📞 Call</a>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        ${s.brand?`<div class=\\\"pi-brand\\\">${s.brand}</div>`:'<div class=\\\"pi-brand\\\" style=\\\"background:var(--rd)\\\">?</div>'}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html+=`<div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('')\\\">+ Not in list? Add new store</div>`;\u001b[39m\n\u001b[31m  list.innerHTML=html;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function pickStore(s){\u001b[39m\n\u001b[31m  selectedStore=s;manualMode=false;closePicker();\u001b[39m\n\u001b[31m  const _dn =LANG==='hi'&&s.nameHi    ?s.nameHi    :s.name;\u001b[39m\n\u001b[31m  const _da =LANG==='hi'&&s.addressHi ?s.addressHi :s.address;\u001b[39m\n\u001b[31m  const _dd =LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m  const _dc =LANG==='hi'&&s.cityHi    ?s.cityHi    :s.city;\u001b[39m\n\u001b[31m  document.getElementById('sc-name').textContent=_dn;\u001b[39m\n\u001b[31m  const brandEl=document.getElementById('sc-brand');\u001b[39m\n\u001b[31m  brandEl.textContent=s.brand||'No Brand';brandEl.style.background=s.brand?'var(--nv)':'var(--rd)';\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const prev=subs.filter(x=>x.data?.storeName===s.name).sort((a,b)=>new Date(b.timestamp)-new Date(a.timestamp))[0];\u001b[39m\n\u001b[31m  const lc=document.getElementById('sc-last');\u001b[39m\n\u001b[31m  if(prev){const d=new Date(prev.timestamp);lc.textContent='Last: '+d.toLocaleDateString('en-IN',{day:'numeric',month:'short'});lc.style.display='inline-flex';}\u001b[39m\n\u001b[31m  else lc.style.display='none';\u001b[39m\n\u001b[31m  // All Excel fields — display in active language\u001b[39m\n\u001b[31m  const mUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m  const wUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const tUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const details=[];\u001b[39m\n\u001b[31m  if(_da)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📍 ${_da}${mUrl?` <a href=\\\"${mUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#0369a1;margin-left:6px\\\">🗺 Navigate</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(s.mobile)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📞 ${s.mobile}${tUrl?` <a href=\\\"${tUrl}\\\" style=\\\"font-size:11px;color:#166534;margin-left:6px\\\">Call</a>`:''}${wUrl?` <a href=\\\"${wUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#15803d;margin-left:6px\\\">WhatsApp</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(_dd)details.push(`<div style=\\\"font-size:12px;color:var(--am)\\\">👤 ${_dd}</div>`);\u001b[39m\n\u001b[31m  if(_dc)details.push(`<div style=\\\"font-size:12px;color:var(--g500)\\\">🏙 ${_dc}</div>`);\u001b[39m\n\u001b[31m  const opp=[];\u001b[39m\n\u001b[31m  if(s.glowSign&&s.glowSign.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dcfce7;color:#14532d;padding:2px 7px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m  if(s.inshop&&s.inshop.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dbeafe;color:#1e40af;padding:2px 7px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m  if(s.proj)opp.push(`<span style=\\\"font-size:11px;background:var(--g100);color:var(--g600);padding:2px 7px;border-radius:10px\\\">Target 2026: ${s.proj}</span>`);\u001b[39m\n\u001b[31m  if(opp.length)details.push(`<div style=\\\"display:flex;gap:5px;flex-wrap:wrap;margin-top:3px\\\">${opp.join('')}</div>`);\u001b[39m\n\u001b[31m  document.getElementById('sc-details').innerHTML=details.join('');\u001b[39m\n\u001b[31m  // Missing fields\u001b[39m\n\u001b[31m  const missing=[];\u001b[39m\n\u001b[31m  if(!s.address)missing.push({key:'address',label:'Store Address',type:'textarea',placeholder:'Full address'});\u001b[39m\n\u001b[31m  if(!s.mobile)missing.push({key:'mobile',label:'Mobile No.',type:'tel',placeholder:'10-digit number',maxlen:'10'});\u001b[39m\n\u001b[31m  const mw=document.getElementById('sc-missing'),mf=document.getElementById('sc-missing-fields');\u001b[39m\n\u001b[31m  if(missing.length){\u001b[39m\n\u001b[31m    mf.innerHTML=missing.map(m=>`<div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\"><label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">${m.label} <span class=\\\"req\\\">*</span></label>${m.type==='textarea'?`<textarea id=\\\"sc-miss-${m.key}\\\" rows=\\\"2\\\" placeholder=\\\"${m.placeholder}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></textarea>`:`<input type=\\\"${m.type}\\\" id=\\\"sc-miss-${m.key}\\\" placeholder=\\\"${m.placeholder}\\\" ${m.maxlen?`maxlength=\\\"${m.maxlen}\\\"`:''}  inputmode=\\\"${m.type==='tel'?'numeric':'text'}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\">`}</div>`).join('');\u001b[39m\n\u001b[31m    mw.style.display='block';\u001b[39m\n\u001b[31m  } else {mw.style.display='none';}\u001b[39m\n\u001b[31m  // Brand selector\u001b[39m\n\u001b[31m  const bSel=document.getElementById('brand-selector'),bChips=document.getElementById('brand-chips');\u001b[39m\n\u001b[31m  if(!s.brand){\u001b[39m\n\u001b[31m    renderBrandChips();\u001b[39m\n\u001b[31m    bSel.style.display='block';\u001b[39m\n\u001b[31m  } else {bSel.style.display='none';}\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  F.storeName=s.name;F.brand=s.brand||'';F.address=s.address||'';F.mobile=s.mobile||'';\u001b[39m\n\u001b[31m  if(s.brand&&!_selectedClient&&!_clientOtherMode) autoSetClient(s.brand);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateMissingField(key,val){if(!selectedStore)return;selectedStore[key]=val.trim();F[key]=val.trim();saveDraft();}\u001b[39m\n\u001b[31mfunction selectStoreBrand(b){\u001b[39m\n\u001b[31m  F.brand=b;F.brandLogoUrl=_brandLogos[b]||'';\u001b[39m\n\u001b[31m  if(selectedStore)selectedStore.brand=b;\u001b[39m\n\u001b[31m  const el=document.getElementById('sc-brand');if(el){el.textContent=b;el.style.background='var(--nv)';}\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-chips .chip').forEach(c=>{c.classList.toggle('sel',c.querySelector('span')?.textContent===b||c.textContent.trim()===b);});\u001b[39m\n\u001b[31m  if(!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction onManualBrandChange(){\u001b[39m\n\u001b[31m  const b=document.getElementById('f-brand')?.value||'';\u001b[39m\n\u001b[31m  F.brandLogoUrl=b?(_brandLogos[b]||''):'';\u001b[39m\n\u001b[31m  if(b&&!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction openManual(prefill){\u001b[39m\n\u001b[31m  manualMode=true;\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').classList.add('on');\u001b[39m\n\u001b[31m  document.getElementById('mt-label').innerHTML='← Back to store list';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='block';\u001b[39m\n\u001b[31m  // Pre-fill from selectedStore if available (e.g. when toggling after picker selection)\u001b[39m\n\u001b[31m  const s=selectedStore;\u001b[39m\n\u001b[31m  if(s){\u001b[39m\n\u001b[31m    if(document.getElementById('f-brand'))document.getElementById('f-brand').value=s.brand||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-store'))document.getElementById('f-store').value=s.name||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-addr'))document.getElementById('f-addr').value=s.address||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-mobile'))document.getElementById('f-mobile').value=s.mobile||'';\u001b[39m\n\u001b[31m  } else if(prefill){\u001b[39m\n\u001b[31m    document.getElementById('f-store').value=prefill;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  selectedStore=null;\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction toggleManual(){\u001b[39m\n\u001b[31m  if(manualMode){\u001b[39m\n\u001b[31m    manualMode=false;\u001b[39m\n\u001b[31m    document.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31m    document.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31m    document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    openManual('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// GPS\u001b[39m\n\u001b[31mfunction captureGPS(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gps-status');el.textContent='Getting location…';el.style.color='var(--g500)';\u001b[39m\n\u001b[31m  if(!navigator.geolocation){el.textContent='GPS not available';return;}\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(pos=>{\u001b[39m\n\u001b[31m    gpsCoords={lat:pos.coords.latitude.toFixed(6),lng:pos.coords.longitude.toFixed(6),acc:Math.round(pos.coords.accuracy)};\u001b[39m\n\u001b[31m    el.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${gpsCoords.acc}m)`;el.style.color='var(--gn)';saveDraft();\u001b[39m\n\u001b[31m  },()=>{el.textContent='GPS failed — enter address manually';el.style.color='var(--rd)';},{enableHighAccuracy:true,timeout:10000});\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// DRAFT\u001b[39m\n\u001b[31mlet draftT;\u001b[39m\n\u001b[31mfunction saveDraft(){\u001b[39m\n\u001b[31m  clearTimeout(draftT);\u001b[39m\n\u001b[31m  draftT=setTimeout(async()=>{\u001b[39m\n\u001b[31m    const draft={k:'current',ts:Date.now(),F:{...F,date:document.getElementById('f-date')?.value||'',brand:manualMode?(document.getElementById('f-brand')?.value||''):(selectedStore?.brand||F.brand||''),storeName:selectedStore?selectedStore.name:(document.getElementById('f-store')?.value||''),address:manualMode?(document.getElementById('f-addr')?.value||''):(selectedStore?.address||F.address||''),mobile:manualMode?(document.getElementById('f-mobile')?.value||''):(selectedStore?.mobile||F.mobile||''),clientName:getClientName()},selectedStore,manualMode,gpsCoords,_selectedClient,_clientOtherMode,fCnt:frontPhotos.length,iCnt:insidePhotos.length,bCnt:brandings.length};\u001b[39m\n\u001b[31m    await dbPut('draft',draft);\u001b[39m\n\u001b[31m    // Also save photos as b64 blobs to draft so they survive exit\u001b[39m\n\u001b[31m    await saveDraftPhotos();\u001b[39m\n\u001b[31m  },500);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveDraftPhotos(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const photoData={\u001b[39m\n\u001b[31m      front:await Promise.all(frontPhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      inside:await Promise.all(insidePhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      addl:await Promise.all(addlPhotos.map(async p=>({b64:await b64(p.blob),desc:p.desc||''}))),\u001b[39m\n\u001b[31m      brand:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,b64:b.blob?await b64(b.blob):null})))\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    await dbPut('draft',{k:'photos',...photoData});\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function checkDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');const wrap=document.getElementById('resume-wrap');\u001b[39m\n\u001b[31m  if(!d||!d.F?.storeName){wrap.innerHTML='';return;}\u001b[39m\n\u001b[31m  const ago=Math.round((Date.now()-d.ts)/60000);\u001b[39m\n\u001b[31m  const agoStr=ago<1?'just now':ago<60?`${ago}m ago`:`${Math.round(ago/60)}h ago`;\u001b[39m\n\u001b[31m  wrap.innerHTML=`<button class=\\\"resume-btn\\\" onclick=\\\"resumeDraft()\\\">\u001b[39m\n\u001b[31m    <div><div style=\\\"font-size:12px;color:rgba(255,255,255,.5);margin-bottom:3px\\\">Resume draft · ${agoStr}</div><div>${d.F.storeName} · ${d.F.brand||'No brand'}</div></div>\u001b[39m\n\u001b[31m    <div style=\\\"text-align:right\\\"><div style=\\\"font-size:13px;color:var(--or)\\\">${d.fCnt||0} photos · ${d.bCnt||0} brandings →</div></div>\u001b[39m\n\u001b[31m  </button>`;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function resumeDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');if(!d)return;\u001b[39m\n\u001b[31m  F=d.F||{};gpsCoords=d.gpsCoords||null;\u001b[39m\n\u001b[31m  if(d.selectedStore){await pickStore(d.selectedStore);}\u001b[39m\n\u001b[31m  else if(d.manualMode){openManual('');if(F.brand)document.getElementById('f-brand').value=F.brand;if(F.storeName)document.getElementById('f-store').value=F.storeName;if(F.address)document.getElementById('f-addr').value=F.address;if(F.mobile)document.getElementById('f-mobile').value=F.mobile;}\u001b[39m\n\u001b[31m  if(F.date)document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  // Restore client chip state\u001b[39m\n\u001b[31m  if(d._clientOtherMode){_clientOtherMode=true;_selectedClient='';const inp=document.getElementById('f-client-other');if(inp&&F.clientName)inp.value=F.clientName;}\u001b[39m\n\u001b[31m  else if(d._selectedClient){_selectedClient=d._selectedClient;_clientOtherMode=false;}\u001b[39m\n\u001b[31m  else if(F.clientName){autoSetClient(F.clientName);}\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  // Restore photos from draft\u001b[39m\n\u001b[31m  const pd=await dbGet('draft','photos');\u001b[39m\n\u001b[31m  if(pd){\u001b[39m\n\u001b[31m    async function b64ToBlob(b64str){if(!b64str)return null;try{const r=await fetch(b64str);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m    for(const p of(pd.front||[])){const bl=await b64ToBlob(p.b64);if(bl)frontPhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.inside||[])){const bl=await b64ToBlob(p.b64);if(bl)insidePhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.addl||[])){const bl=await b64ToBlob(p.b64);if(bl)addlPhotos.push({blob:bl,prev:URL.createObjectURL(bl),desc:p.desc||''});}\u001b[39m\n\u001b[31m    for(const b of(pd.brand||[])){const bl=await b64ToBlob(b.b64);brandings.push({type:b.type,w:b.w,h:b.h,qty:b.qty,blob:bl,prev:bl?URL.createObjectURL(bl):null});}\u001b[39m\n\u001b[31m    toast('Draft restored with '+frontPhotos.length+' photos ✓','success');\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    toast('Draft restored — photos could not be recovered','info');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PHOTOS\u001b[39m\n\u001b[31mfunction updPhotoBadge(type){const arr=type==='front'?frontPhotos:insidePhotos;const el=document.getElementById(type+'-badge');if(el){el.textContent=arr.length;el.className='cnt-badge '+(arr.length?'':'gray');}}\u001b[39m\n\u001b[31mfunction renderPhotos(type){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  const cont=document.getElementById(type+'-cont');const addBtn=document.getElementById('add-'+type);\u001b[39m\n\u001b[31m  updPhotoBadge(type);\u001b[39m\n\u001b[31m  if(arr.length===0){cont.innerHTML=`<div class=\\\"pslot\\\" onclick=\\\"addPhoto('${type}')\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to capture or upload</span><span class=\\\"hi-txt\\\">फोटो खींचें या अपलोड करें</span></div></div>`;addBtn.style.display='none';return;}\u001b[39m\n\u001b[31m  cont.innerHTML=arr.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const badge=isRetained?`<span class=\\\"pbadge\\\" style=\\\"background:#475569\\\">Existing</span>`:`<span class=\\\"pbadge\\\">${fmtSz(p.blob.size)}</span>`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replacePhoto('${type}',${i})\\\" style=\\\"right:36px;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"margin-bottom:12px\\\"><div class=\\\"pslot filled\\\" style=\\\"margin-bottom:8px\\\"><img src=\\\"${p.prev}\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmPhoto('${type}',${i})\\\">×</button>${badge}</div><input type=\\\"text\\\" placeholder=\\\"Comments (optional)\\\" value=\\\"${p.cmt||''}\\\" onchange=\\\"${type==='front'?'frontPhotos':'insidePhotos'}[${i}].cmt=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  addBtn.style.display=arr.length<(type==='inside'?5:3)?'inline-flex':'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// Photo source: 'camera' stamps geo, 'gallery' does not\u001b[39m\n\u001b[31mlet _photoSourceCb=null,_photoSourceQuality=null;·\u001b[39m\n\u001b[31mfunction capPhoto(cb,forceSource,quality){\u001b[39m\n\u001b[31m  // quality override: null=use setting, 'hd', 'compressed'\u001b[39m\n\u001b[31m  _photoSourceCb=cb;_photoSourceQuality=quality||null;\u001b[39m\n\u001b[31m  if(forceSource==='camera'){_doCapture(cb,'camera',quality);return;}\u001b[39m\n\u001b[31m  if(forceSource==='gallery'){_doCapture(cb,'gallery',quality);return;}\u001b[39m\n\u001b[31m  // Show picker\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _doCapture(cb,src,quality){\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  const i=document.createElement('input');\u001b[39m\n\u001b[31m  i.type='file';i.accept='image/*';\u001b[39m\n\u001b[31m  if(src==='camera')i.setAttribute('capture','environment');\u001b[39m\n\u001b[31m  i.style.display='none';\u001b[39m\n\u001b[31m  i.onchange=async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f)return;\u001b[39m\n\u001b[31m    const q=quality||_photoSourceQuality||null;\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      const blob=await compress(f,q==='hd'?1920:q==='compressed'?1280:null,q==='hd'?0.90:q==='compressed'?0.78:null);\u001b[39m\n\u001b[31m      // Only stamp if from camera (live photo)\u001b[39m\n\u001b[31m      const stamped=(src==='camera')?await stampPhoto(blob):blob;\u001b[39m\n\u001b[31m      // Save to device (auto-download trigger)\u001b[39m\n\u001b[31m      savePhotoToDevice(stamped);\u001b[39m\n\u001b[31m      cb({target:{files:[f]},_blob:stamped,_src:src});\u001b[39m\n\u001b[31m    }catch(err){toast('Photo processing failed — try again','error');console.error('_doCapture error:',err);}\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  document.body.appendChild(i);i.click();setTimeout(()=>i.remove(),8000);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction photoSrcCamera(){_doCapture(_photoSourceCb,'camera',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcGallery(){_doCapture(_photoSourceCb,'gallery',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcCancel(){document.getElementById('photo-src-dialog').classList.remove('open');_photoSourceCb=null;}·\u001b[39m\n\u001b[31m// Save photo to device gallery/downloads\u001b[39m\n\u001b[31mfunction savePhotoToDevice(blob){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    const a=document.createElement('a');\u001b[39m\n\u001b[31m    a.href=url;\u001b[39m\n\u001b[31m    a.download='Recce_'+Date.now()+'.jpg';\u001b[39m\n\u001b[31m    a.style.display='none';\u001b[39m\n\u001b[31m    document.body.appendChild(a);a.click();\u001b[39m\n\u001b[31m    setTimeout(()=>{URL.revokeObjectURL(url);a.remove();},1000);\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addPhoto(type){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}${e._src==='camera'&&geoStampEnabled?' · Stamped':''}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31masync function handleCapture(e,type){\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmPhoto(type,i){(type==='front'?frontPhotos:insidePhotos).splice(i,1);renderPhotos(type);saveDraft();}\u001b[39m\n\u001b[31mfunction replacePhoto(type,idx){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m    arr[idx]={...arr[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAddl(){\u001b[39m\n\u001b[31m  const cont=document.getElementById('add-cont');const btn=document.getElementById('add-addl');\u001b[39m\n\u001b[31m  const badge=document.getElementById('addl-badge');if(badge){badge.textContent=`${addlPhotos.length} / 8`;badge.className='cnt-badge '+(addlPhotos.length?'':'gray');}\u001b[39m\n\u001b[31m  cont.innerHTML=addlPhotos.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const sizeInfo=isRetained?'<span style=\\\"color:#475569\\\">Existing</span>':`${fmtSz(p.blob.size)}`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replaceAddl(${i})\\\" style=\\\"top:3px;left:3px;right:auto;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;gap:10px;align-items:start;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--g100)\\\"><div style=\\\"position:relative;flex-shrink:0\\\"><img src=\\\"${p.prev}\\\" style=\\\"width:80px;height:80px;object-fit:cover;border-radius:var(--rs)\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmAddl(${i})\\\" style=\\\"top:3px;right:3px\\\">×</button></div><div style=\\\"flex:1\\\"><input type=\\\"text\\\" placeholder=\\\"Description (optional)\\\" value=\\\"${p.desc||''}\\\" onchange=\\\"addlPhotos[${i}].desc=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"><div style=\\\"font-size:11px;color:var(--g400);margin-top:4px\\\">${sizeInfo}</div></div></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  btn.style.display=addlPhotos.length>=8?'none':'inline-flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction addAdditional(){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  addlPhotos.push({blob:bs,prev:URL.createObjectURL(bs),desc:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderAddl();saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31mfunction rmAddl(i){addlPhotos.splice(i,1);renderAddl();saveDraft();}\u001b[39m\n\u001b[31mfunction replaceAddl(idx){\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m    addlPhotos[idx]={...addlPhotos[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderAddl();saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// BRANDING\u001b[39m\n\u001b[31mfunction calcSqft(w,h){const wf=parseFloat(w),hf=parseFloat(h);if(!wf||!hf)return '';return `${(wf*hf).toFixed(0)} sq.in = ${(wf*hf/144).toFixed(2)} sq.ft`;}\u001b[39m\n\u001b[31mfunction renderBrandings(){\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  const cont=document.getElementById('br-items');\u001b[39m\n\u001b[31m  const hb=document.getElementById('br-hdr-badge');if(hb)hb.textContent=`${brandings.length} ${t(brandings.length!==1?'items':'item',brandings.length!==1?'आइटम':'आइटम')}`;\u001b[39m\n\u001b[31m  cont.innerHTML=brandings.map((b,i)=>`<div class=\\\"bitem\\\"><div class=\\\"bitem-hdr\\\"><div class=\\\"bitem-title\\\">${t('Branding','ब्रांडिंग')} ${i+1}${b.type?' — '+b.type:''}</div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:6px\\\">${i>0?`<button class=\\\"btn-d\\\" onclick=\\\"dupBr(${i})\\\" style=\\\"color:var(--or);border-color:var(--orl)\\\">${t('Dup ↑','डुप ↑')}</button>`:''}<button class=\\\"btn-d\\\" onclick=\\\"rmBr(${i})\\\">${t('Remove','हटाएं')}</button></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\"><label>${t('Type','प्रकार')} <span class=\\\"req\\\">*</span></label><div class=\\\"chip-grid\\\">${BTYPE.map(tp=>`<div class=\\\"chip${b.type===tp?' sel':''}\\\" onclick=\\\"setBType(${i},'${tp.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\"> ${tp}</div>`).join('')}</div></div>\u001b[39m\n\u001b[31m    <div class=\\\"dim-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Width (in)','चौड़ाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.w||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].w=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Height (in)','ऊंचाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.h||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].h=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"max-width:74px\\\"><label>${t('Qty','मात्रा')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.qty||''}\\\" placeholder=\\\"1\\\" inputmode=\\\"numeric\\\" onchange=\\\"brandings[${i}].qty=this.value;saveDraft()\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <span class=\\\"sqft\\\" id=\\\"sf${i}\\\">${calcSqft(b.w,b.h)||t('Enter W × H','W × H दर्ज करें')}</span>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-top:12px\\\"><label>${t('Photo','फोटो')} <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      ${b.prev?`<div class=\\\"pslot filled\\\" onclick=\\\"capBr(${i})\\\"><img src=\\\"${b.prev}\\\"><button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();rmBrPh(${i})\\\">×</button><span class=\\\"pbadge\\\">${b.blob?fmtSz(b.blob.size):'Existing'}</span></div>`:`<div><div class=\\\"pslot\\\" onclick=\\\"capBr(${i})\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\">${t('Tap to capture','दबाकर कैप्चर करें')}</div></div><div style=\\\"display:flex;gap:6px;margin-top:6px\\\"><button class=\\\"atool${(b.quality||imgQuality)==='compressed'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'compressed');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">${t('Compressed','कम्प्रेस्ड')}</button><button class=\\\"atool${(b.quality||imgQuality)==='hd'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'hd');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">HD</button></div></div>`}\u001b[39m\n\u001b[31m    </div></div>`).join('');\u001b[39m\n\u001b[31m  // Only show \\\"Add Another\\\" when last item is fully complete\u001b[39m\n\u001b[31m  const addDiv=document.getElementById('br-add');\u001b[39m\n\u001b[31m  if(addDiv&&brandings.length>0){\u001b[39m\n\u001b[31m    const last=brandings[brandings.length-1];\u001b[39m\n\u001b[31m    const lastComplete=last.type&&last.w&&last.h&&last.qty&&last.prev;\u001b[39m\n\u001b[31m    addDiv.style.display=(lastComplete&&brandings.length<15)?'block':'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updSqft(i){const el=document.getElementById('sf'+i);if(el)el.textContent=calcSqft(brandings[i].w,brandings[i].h)||t('Enter W × H','W × H दर्ज करें');saveDraft();}\u001b[39m\n\u001b[31mfunction setBType(i,tp){brandings[i].type=tp;renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction addBranding(){if(brandings.length>=15){toast(t('Max 15 items','अधिकतम 15 आइटम'),'error');return;}brandings.push({type:'',w:'',h:'',qty:'1',blob:null,prev:null});renderBrandings();}\u001b[39m\n\u001b[31mfunction dupBr(i){if(brandings.length>=10){toast(t('Max 10 items','अधिकतम 10 आइटम'),'error');return;}const s=brandings[i-1];brandings.splice(i,0,{type:s.type,w:s.w,h:s.h,qty:s.qty,blob:null,prev:null});renderBrandings();toast(t('Duplicated — add photo','डुप्लीकेट — फोटो जोड़ें'),'info');}\u001b[39m\n\u001b[31mfunction rmBr(i){brandings.splice(i,1);renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction capBr(i){\u001b[39m\n\u001b[31m  const q=brandings[i]?.quality||imgQuality;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f,q==='hd'?1920:1280,q==='hd'?0.90:0.78));\u001b[39m\n\u001b[31m    brandings[i].blob=bs;brandings[i].prev=URL.createObjectURL(bs);\u001b[39m\n\u001b[31m    brandings[i].fromCamera=(e._src==='camera');\u001b[39m\n\u001b[31m    openAnnot(i);\u001b[39m\n\u001b[31m  },null,q);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmBrPh(i){brandings[i].blob=null;brandings[i].prev=null;renderBrandings();}\u001b[39m\n\u001b[31mfunction setBrQuality(i,q){brandings[i].quality=q;renderBrandings();}·\u001b[39m\n\u001b[31m// VIDEO / DOC\u001b[39m\n\u001b[31mfunction setVideo(v){F.hasVideo=v;document.getElementById('vid-yes').classList.toggle('sel',v);document.getElementById('vid-no').classList.toggle('sel',!v);document.getElementById('vid-sec').style.display=v?'block':'none';saveDraft();}\u001b[39m\n\u001b[31masync function handleVideo(e){videoBlob=e.target.files[0];if(!videoBlob)return;document.getElementById('vid-slot').innerHTML=`<div style=\\\"padding:14px;font-size:13px;color:var(--gn)\\\">✓ ${videoBlob.name} (${fmtSz(videoBlob.size)})</div>`;}\u001b[39m\n\u001b[31mfunction setBranding(v){F.hasBranding=v;document.getElementById('br-yes').classList.toggle('sel',v);document.getElementById('br-no').classList.toggle('sel',!v);document.getElementById('br-add').style.display=v?'block':'none';if(v&&brandings.length===0)addBranding();saveDraft();}\u001b[39m\n\u001b[31masync function handleDoc(e){const f=e.target.files[0];if(!f)return;submissionDoc=f.type.startsWith('image/')?await compress(f,1600,.85):f;const slot=document.getElementById('doc-slot');if(f.type.startsWith('image/')){slot.classList.add('filled');slot.innerHTML=`<img src=\\\"${URL.createObjectURL(submissionDoc)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}else{slot.innerHTML=`<div style=\\\"padding:16px;font-size:13px;color:var(--gn)\\\">✓ ${f.name} (${fmtSz(f.size)})</div>`;}buildReview();}·\u001b[39m\n\u001b[31m// CLIENT CHIPS\u001b[39m\n\u001b[31mfunction renderClientChips(){\u001b[39m\n\u001b[31m  const grid = document.getElementById('client-chips'); if (!grid) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  clientList.forEach(c => {\u001b[39m\n\u001b[31m    const sel = !_clientOtherMode && _selectedClient === c;\u001b[39m\n\u001b[31m    html += `<div class=\\\"cl-chip${sel?' sel':''}\\\" onclick=\\\"selectClientChip('${esc(c)}')\\\">${esc(c)}</div>`;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html += `<div class=\\\"cl-chip cl-chip-other${_clientOtherMode?' sel':''}\\\" onclick=\\\"selectClientOther()\\\"><span class=\\\"en-txt\\\">Other…</span><span class=\\\"hi-txt\\\">अन्य…</span></div>`;\u001b[39m\n\u001b[31m  grid.innerHTML = html;\u001b[39m\n\u001b[31m  document.getElementById('client-other-wrap').style.display = _clientOtherMode ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientChip(name){\u001b[39m\n\u001b[31m  _selectedClient = name; _clientOtherMode = false;\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').value = '';\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientOther(){\u001b[39m\n\u001b[31m  _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onClientOtherInput(){\u001b[39m\n\u001b[31m  _selectedClient = document.getElementById('f-client-other').value.trim();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction getClientName(){\u001b[39m\n\u001b[31m  if (_clientOtherMode) return (document.getElementById('f-client-other')?.value||'').trim();\u001b[39m\n\u001b[31m  return _selectedClient;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction autoSetClient(brandName){\u001b[39m\n\u001b[31m  if (!brandName) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  if (clientList.includes(brandName)){\u001b[39m\n\u001b[31m    _selectedClient = brandName; _clientOtherMode = false;\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    // Not in list — pre-fill the Other field\u001b[39m\n\u001b[31m    _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m    const inp = document.getElementById('f-client-other');\u001b[39m\n\u001b[31m    if (inp && !inp.value) inp.value = brandName;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// STEP VALIDATION\u001b[39m\n\u001b[31mfunction getSD(){if(selectedStore&&!manualMode)return{storeName:selectedStore.name,brand:selectedStore.brand||'',address:selectedStore.address||'',mobile:selectedStore.mobile||''};return{storeName:(document.getElementById('f-store')?.value||'').trim(),brand:document.getElementById('f-brand')?.value||'',address:(document.getElementById('f-addr')?.value||'').trim(),mobile:(document.getElementById('f-mobile')?.value||'').trim()};}\u001b[39m\n\u001b[31mfunction step2(){\u001b[39m\n\u001b[31m  const d=document.getElementById('f-date').value;\u001b[39m\n\u001b[31m  if(!d){toast('Select date','error');return;}\u001b[39m\n\u001b[31m  const sd=getSD();\u001b[39m\n\u001b[31m  if(!sd.storeName){toast('Select or enter store name','error');return;}\u001b[39m\n\u001b[31m  if(!sd.brand){toast('Select a brand','error');document.getElementById('brand-selector').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  if(!sd.address){toast('Enter store address','error');return;}\u001b[39m\n\u001b[31m  const clientName=getClientName();\u001b[39m\n\u001b[31m  if(!clientName){toast(t('Select a client','क्लाइंट चुनें'),'error');document.getElementById('client-chips').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  // Check missing fields filled\u001b[39m\n\u001b[31m  const missAddr=document.getElementById('sc-miss-address');\u001b[39m\n\u001b[31m  if(missAddr&&!missAddr.value.trim()){toast('Enter store address in the highlighted field','error');missAddr.focus();return;}\u001b[39m\n\u001b[31m  const missMob=document.getElementById('sc-miss-mobile');\u001b[39m\n\u001b[31m  // mobile not required — just copy if filled\u001b[39m\n\u001b[31m  if(missMob&&missMob.value.trim()&&!F.mobile)F.mobile=missMob.value.trim();\u001b[39m\n\u001b[31m  Object.assign(F,{date:d,...sd,clientName});saveDraft();\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');showView('form-photos');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction step3(){if(!frontPhotos.length){toast('Add at least 1 front view photo','error');return;}showView('form-video');}\u001b[39m\n\u001b[31mfunction step4(){if(F.hasVideo===undefined||F.hasVideo===null){toast('Select Yes or No for video','error');return;}renderBrandings();showView('form-branding');}\u001b[39m\n\u001b[31mfunction step5(){if(F.hasBranding===undefined||F.hasBranding===null){toast('Select Yes or No for branding space','error');return;}if(F.hasBranding){for(let i=0;i<brandings.length;i++){const b=brandings[i];if(!b.type){toast(`Select branding type for item ${i+1}`,'error');return;}if(!b.w||!b.h){toast(`Enter W and H dimensions for item ${i+1}`,'error');return;}if(!b.qty){toast(`Enter qty for item ${i+1}`,'error');return;}if(!b.blob&&!b.prev){toast(`Add photo for item ${i+1}`,'error');return;}}}renderAddl();buildReview();showView('form-additional');}·\u001b[39m\n\u001b[31m// REVIEW\u001b[39m\n\u001b[31mfunction buildReview(){const el=document.getElementById('rev-body');if(!el)return;const sd=getSD();const cn=getClientName();el.innerHTML=`<div><div class=\\\"rev-lbl\\\">Store</div><div class=\\\"rev-val\\\">${sd.storeName||'—'} · ${sd.brand||'—'}</div><div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">${sd.address||'—'}${sd.mobile?' · '+sd.mobile:''}</div>${gpsCoords?`<div style=\\\"font-size:11px;color:var(--gn);margin-top:3px\\\">📍 ${gpsCoords.lat}, ${gpsCoords.lng} ±${gpsCoords.acc}m</div>`:''}</div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Client</div><div class=\\\"rev-val\\\" style=\\\"color:${cn?'var(--nv)':'var(--rd)'}\\\">${cn||'⚠ Not selected — required'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Photos — Front · Inside · Additional</div><div class=\\\"rev-val\\\">${frontPhotos.length} · ${insidePhotos.length} · ${addlPhotos.length}</div><div class=\\\"rev-photos\\\">${[...frontPhotos,...insidePhotos].slice(0,6).map(p=>`<img class=\\\"rev-thumb\\\" src=\\\"${p.prev}\\\">`).join('')}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Video · Branding items</div><div class=\\\"rev-val\\\">${F.hasVideo?'Yes':'No'} · ${brandings.length} item(s)</div></div>${F.hasBranding&&brandings.length?`<div style=\\\"margin-top:8px\\\">${brandings.map((b,i)=>`<div style=\\\"font-size:12px;color:var(--g600);padding:4px 0;border-bottom:1px solid var(--g100)\\\">${i+1}. ${b.type||'No type'} — ${b.w||'?'}×${b.h||'?'}\\\" × ${b.qty||'?'} — ${calcSqft(b.w,b.h)||'?'}</div>`).join('')}</div>`:''}<div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Additional photos <span style=\\\"font-size:11px;color:var(--g400)\\\">(optional)</span></div><div class=\\\"rev-val\\\" style=\\\"color:${addlPhotos.length?'var(--gn)':'var(--g500)'}\\\">${addlPhotos.length?`✓ ${addlPhotos.length} photo(s) added`:'None added'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Mandatory document</div><div class=\\\"rev-val\\\" style=\\\"color:${(submissionDoc||_docExistingUrl)?'var(--gn)':'var(--rd)'}\\\">${(submissionDoc||_docExistingUrl)?'✓ Uploaded':'⚠ Missing — required'}</div></div>`;}·\u001b[39m\n\u001b[31m// SUBMIT\u001b[39m\n\u001b[31masync function submitRecce(){\u001b[39m\n\u001b[31m  if(!submissionDoc&&!_docExistingUrl){toast('Upload mandatory doc first','error');return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('sub-btn');btn.disabled=true;btn.textContent='Saving…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const isEdit=!!(F.editingId);\u001b[39m\n\u001b[31m    const id=isEdit?F.editingId:('RC_'+Date.now()+'_'+Math.random().toString(36).slice(2,6).toUpperCase());\u001b[39m\n\u001b[31m    const sd=getSD();\u001b[39m\n\u001b[31m    const _hub=_recceHubUser();\u001b[39m\n\u001b[31m    const entry={id,timestamp:isEdit?(await dbGet('subs',id))?.timestamp||new Date().toISOString():new Date().toISOString(),editedAt:isEdit?new Date().toISOString():undefined,status:'pending',submittedBy:_hub.empId||null,submittedByName:_hub.name||null,data:{...F,...sd,gpsCoords,frontPhotos:await Promise.all(frontPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),insidePhotos:await Promise.all(insidePhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),videoNote:F.hasVideo&&videoBlob?`Video local (${fmtSz(videoBlob.size)}) — share via WhatsApp`:null,videoCmt:document.getElementById('f-vid-cmt')?.value||'',brandings:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:calcSqft(b.w,b.h),photoB64:b.blob?await b64(b.blob):null,existingUrl:b.existingUrl||null}))),addlPhotos:await Promise.all(addlPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,desc:p.desc,existingUrl:p.existingUrl||null}))),docB64:submissionDoc?await b64(submissionDoc):null,_docExistingUrl:_docExistingUrl||null}};\u001b[39m\n\u001b[31m    entry.campaignId       = _selectedCampaignId || null;\u001b[39m\n\u001b[31m    entry.notifySupervisor = _notifySupervisor   || false;\u001b[39m\n\u001b[31m    await dbPut('subs',entry);\u001b[39m\n\u001b[31m    await dbDel('draft','current');\u001b[39m\n\u001b[31m    toast(isEdit?'Recce updated ✓':'Recce saved ✓','success');\u001b[39m\n\u001b[31m    if(navigator.onLine)syncNow();\u001b[39m\n\u001b[31m    showView('home');loadHome();checkDraft();\u001b[39m\n\u001b[31m  }catch(err){toast('Error: '+err.message,'error');}\u001b[39m\n\u001b[31m  finally{btn.disabled=false;btn.textContent='Submit Recce ✓';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// SYNC\u001b[39m\n\u001b[31masync function syncNow() {\u001b[39m\n\u001b[31m  if (!navigator.onLine) { toast('Offline — sync when back online', 'info'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('sync-btn');\u001b[39m\n\u001b[31m  const SYNC_ICON = '<svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg>Sync';\u001b[39m\n\u001b[31m  if (btn) { btn.innerHTML = '<span class=\\\"spin\\\">↻</span> Syncing'; btn.disabled = true; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const all      = await dbAll('subs');\u001b[39m\n\u001b[31m    const pend     = all.filter(s => s.status === 'pending' || s.status === 'failed');\u001b[39m\n\u001b[31m    const backfill = all.filter(s => s.status === 'synced' && !s.gasAt);\u001b[39m\n\u001b[31m    if (!pend.length && !backfill.length) { toast('All synced ✓', 'success'); return; }·\u001b[39m\n\u001b[31m    const gasUrl = (await cfg('gas-url')) || DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    function fireGas(s) {\u001b[39m\n\u001b[31m      if (!gasUrl) return;\u001b[39m\n\u001b[31m      fetch(gasUrl, { method:'POST', mode:'no-cors',\u001b[39m\n\u001b[31m        body: JSON.stringify({ action:'syncSheet', submission: s }) })\u001b[39m\n\u001b[31m        .catch(() => {});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    let ok = 0;\u001b[39m\n\u001b[31m    for (const s of pend) {\u001b[39m\n\u001b[31m      // Fire Sheet sync (no-cors fire-and-forget — writes row to Google Sheet)\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      // Primary: upload photos → auto-trigger slides → generate report → store in PostgreSQL\u001b[39m\n\u001b[31m      const { ok: pgOk, viewUrl } = await syncToPostgres(s);\u001b[39m\n\u001b[31m      if (pgOk) {\u001b[39m\n\u001b[31m        s.status = 'synced'; s.syncedAt = new Date().toISOString();\u001b[39m\n\u001b[31m        if (viewUrl) s.viewUrl = viewUrl;\u001b[39m\n\u001b[31m        await dbPut('subs', s); ok++;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        s.status = 'failed'; await dbPut('subs', s);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Backfill: entries synced to Postgres but never reached Sheet GAS\u001b[39m\n\u001b[31m    for (const s of backfill) {\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      await dbPut('subs', s);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if (backfill.length) toast(`Sent ${backfill.length} older entries to Sheet`, 'info');·\u001b[39m\n\u001b[31m    await cfg('last-sync', new Date().toISOString());\u001b[39m\n\u001b[31m    if (pend.length) toast(`Synced ${ok}/${pend.length}`, ok === pend.length ? 'success' : 'error');\u001b[39m\n\u001b[31m    loadHome();\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.innerHTML = SYNC_ICON; btn.disabled = false; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN HOME ──────────────────────────────────────────────\u001b[39m\n\u001b[31masync function loadHomeAdmin() {\u001b[39m\n\u001b[31m  // Adapt UI for admin view\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const _sh = document.querySelector('.sh'); if (_sh) _sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = 'All Submissions';\u001b[39m\n\u001b[31m  const slbls = document.querySelectorAll('.slbl');\u001b[39m\n\u001b[31m  if (slbls[0]) slbls[0].textContent = 'Showing';\u001b[39m\n\u001b[31m  if (slbls[1]) slbls[1].textContent = 'Agents';·\u001b[39m\n\u001b[31m  // Back-to-menu button for supervisors\u001b[39m\n\u001b[31m  if (_isSupervisor() && !document.getElementById('sup-back-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => { document.getElementById('sup-back-btn').remove(); renderSupLanding(); };\u001b[39m\n\u001b[31m    const content = document.querySelector('#view-home .content');\u001b[39m\n\u001b[31m    content.prepend(bb);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Show filter bar — restore if hidden by renderSupLanding, else inject fresh\u001b[39m\n\u001b[31m  const _existingFb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (_existingFb) { _existingFb.style.display = ''; }\u001b[39m\n\u001b[31m  if (!_existingFb) {\u001b[39m\n\u001b[31m    const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m    const fb = document.createElement('div');\u001b[39m\n\u001b[31m    fb.id = 'admin-filter-bar';\u001b[39m\n\u001b[31m    fb.className = 'af-bar';\u001b[39m\n\u001b[31m    fb.innerHTML =\u001b[39m\n\u001b[31m      `<div class=\\\"af-grid\\\">\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-agent\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Agents</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-brand\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Brands</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-client\\\" onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Clients</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-period\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">All Time</option>\u001b[39m\n\u001b[31m          <option value=\\\"7\\\">Last 7 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"30\\\">Last 30 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"90\\\">Last 3 months</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-group\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"date\\\">Sort: Recent</option>\u001b[39m\n\u001b[31m          <option value=\\\"agent\\\">Group: Agent</option>\u001b[39m\n\u001b[31m          <option value=\\\"brand\\\">Group: Brand</option>\u001b[39m\n\u001b[31m          <option value=\\\"client\\\">Group: Client</option>\u001b[39m\n\u001b[31m          <option value=\\\"city\\\">Group: City</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m        <input class=\\\"af-inp\\\" id=\\\"af-search\\\" type=\\\"text\\\" placeholder=\\\"🔍 Search store or city…\\\" oninput=\\\"renderAdminList()\\\" style=\\\"flex:1;min-width:120px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"del-toggle-btn\\\" id=\\\"del-toggle-btn\\\" onclick=\\\"toggleDeletedView()\\\" style=\\\"flex-shrink:0\\\">📋 View Deleted</button>\u001b[39m\n\u001b[31m        ${_isSupervisor() ? `<button class=\\\"del-toggle-btn\\\" id=\\\"pending-job-btn\\\" onclick=\\\"togglePendingJobView()\\\" style=\\\"flex-shrink:0;background:#fef3c7;color:#92400e;border-color:#f59e0b\\\">⚑ Unlinked <span id=\\\"pending-job-count\\\" style=\\\"font-weight:900\\\"></span></button>` : ''}\u001b[39m\n\u001b[31m        ${_adminUnlocked ? `<button class=\\\"del-toggle-btn\\\" id=\\\"regen-rpt-btn\\\" onclick=\\\"regenAllReports()\\\" style=\\\"flex-shrink:0\\\">&#x21BB; Regen Reports</button>` : ''}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    sh.parentNode.insertBefore(fb, sh);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Fetch\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  list.innerHTML = '<div style=\\\"text-align:center;padding:40px\\\"><div class=\\\"spinner\\\"></div></div>';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?order=submitted_at.desc&limit=500`, { headers: _RC_READ });\u001b[39m\n\u001b[31m    _adminRows = resp.ok ? await resp.json() : [];\u001b[39m\n\u001b[31m    document.getElementById('stat-total').textContent = _adminRows.length;\u001b[39m\n\u001b[31m    if (resp.ok) {\u001b[39m\n\u001b[31m      const now = new Date();\u001b[39m\n\u001b[31m      document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m        'Loaded ' + now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Populate agent dropdown\u001b[39m\n\u001b[31m    const agents = [...new Set(_adminRows.map(r => r.submitted_by).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-agent').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Agents (${agents.length})</option>` +\u001b[39m\n\u001b[31m      agents.map(a => `<option value=\\\"${a}\\\">${a}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate brand dropdown\u001b[39m\n\u001b[31m    const brands = [...new Set(_adminRows.map(r => r.brand).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-brand').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Brands (${brands.length})</option>` +\u001b[39m\n\u001b[31m      brands.map(b => `<option value=\\\"${b}\\\">${b}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate client dropdown\u001b[39m\n\u001b[31m    const clients = [...new Set(_adminRows.map(r => r.client_name).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-client').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Clients (${clients.length})</option>` +\u001b[39m\n\u001b[31m      clients.map(c => `<option value=\\\"${c}\\\">${c}</option>`).join('');·\u001b[39m\n\u001b[31m    // Update pending-job count badge\u001b[39m\n\u001b[31m    const unlinkedCount = _adminRows.filter(r => !r.deleted_at && !r.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinkedCount ? `(${unlinkedCount})` : '';·\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">⚠️</div><div class=\\\"empty-txt\\\">Could not load — check connection</div></div>';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction togglePendingJobView() {\u001b[39m\n\u001b[31m  _pendingJobFilter = !_pendingJobFilter;\u001b[39m\n\u001b[31m  _showDeletedView  = false;\u001b[39m\n\u001b[31m  const btn = document.getElementById('pending-job-btn');\u001b[39m\n\u001b[31m  if (btn) btn.style.background = _pendingJobFilter ? '#f59e0b' : '#fef3c7';\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function openLinkJobModal(subId, storeName) {\u001b[39m\n\u001b[31m  _linkJobSubId = subId;\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  const storeEl = document.getElementById('link-job-store');\u001b[39m\n\u001b[31m  const sel = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  if (!modal) return;\u001b[39m\n\u001b[31m  if (storeEl) storeEl.textContent = storeName || subId;\u001b[39m\n\u001b[31m  if (errEl) errEl.textContent = '';\u001b[39m\n\u001b[31m  // Load campaigns into dropdown\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (!_campaignList.length) {\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m      _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  if (sel) {\u001b[39m\n\u001b[31m    sel.innerHTML = '<option value=\\\"\\\">— Select campaign —</option>' +\u001b[39m\n\u001b[31m      _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  modal.style.display = 'flex';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeLinkJobModal() {\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  if (modal) modal.style.display = 'none';\u001b[39m\n\u001b[31m  _linkJobSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function saveLinkJob() {\u001b[39m\n\u001b[31m  const sel    = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl  = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  const campId = sel?.value || '';\u001b[39m\n\u001b[31m  if (!campId) { if (errEl) errEl.textContent = 'Select a campaign'; return; }\u001b[39m\n\u001b[31m  if (!_linkJobSubId) return;\u001b[39m\n\u001b[31m  const btn = document.querySelector('#modal-link-job button[onclick=\\\"saveLinkJob()\\\"]');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Linking…'; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(_linkJobSubId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ campaign_id: campId }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Patch failed');\u001b[39m\n\u001b[31m    // Update local cache\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === _linkJobSubId);\u001b[39m\n\u001b[31m    if (idx >= 0) _adminRows[idx].campaign_id = campId;\u001b[39m\n\u001b[31m    // Update pending count badge\u001b[39m\n\u001b[31m    const unlinked = _adminRows.filter(x => !x.deleted_at && !x.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinked ? `(${unlinked})` : '';\u001b[39m\n\u001b[31m    closeLinkJobModal();\u001b[39m\n\u001b[31m    toast('Job linked ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    if (errEl) errEl.textContent = 'Failed to link — try again';\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.disabled = false; btn.textContent = '🔗 Link Job'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAdminList() {\u001b[39m\n\u001b[31m  const agent  = document.getElementById('af-agent')?.value  || '';\u001b[39m\n\u001b[31m  const brand  = document.getElementById('af-brand')?.value  || '';\u001b[39m\n\u001b[31m  const period = document.getElementById('af-period')?.value || '';\u001b[39m\n\u001b[31m  const search = (document.getElementById('af-search')?.value || '').toLowerCase().trim();\u001b[39m\n\u001b[31m  const group  = document.getElementById('af-group')?.value  || 'date';·\u001b[39m\n\u001b[31m  // Pending-job filter overrides deleted/normal modes\u001b[39m\n\u001b[31m  let rows;\u001b[39m\n\u001b[31m  if (_pendingJobFilter) {\u001b[39m\n\u001b[31m    rows = _adminRows.filter(r => !r.deleted_at && !r.campaign_id);\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows = _showDeletedView\u001b[39m\n\u001b[31m      ? _adminRows.filter(r => r.deleted_at)\u001b[39m\n\u001b[31m      : _adminRows.filter(r => !r.deleted_at);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const client = document.getElementById('af-client')?.value || '';\u001b[39m\n\u001b[31m  if (agent)  rows = rows.filter(r => r.submitted_by === agent);\u001b[39m\n\u001b[31m  if (brand)  rows = rows.filter(r => r.brand === brand);\u001b[39m\n\u001b[31m  if (client) rows = rows.filter(r => r.client_name === client);\u001b[39m\n\u001b[31m  if (search) rows = rows.filter(r => (r.store_name||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.city||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.client_name||'').toLowerCase().includes(search));\u001b[39m\n\u001b[31m  if (period && !_showDeletedView) {\u001b[39m\n\u001b[31m    const cut = new Date(); cut.setDate(cut.getDate() - parseInt(period));\u001b[39m\n\u001b[31m    rows = rows.filter(r => new Date(r.submitted_at) >= cut);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const uniqueAgents = new Set(rows.map(r => r.submitted_by).filter(Boolean)).size;\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = rows.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = uniqueAgents;\u001b[39m\n\u001b[31m  const deletedCount = _adminRows.filter(r => r.deleted_at).length;\u001b[39m\n\u001b[31m  const delBtn = document.getElementById('del-toggle-btn');\u001b[39m\n\u001b[31m  if (delBtn) {\u001b[39m\n\u001b[31m    if (_showDeletedView) {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 Hide Deleted (${deletedCount})` : '📋 Hide Deleted';\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 View Deleted (${deletedCount})` : '📋 View Deleted';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    delBtn.classList.toggle('active', _showDeletedView);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!rows.length) {\u001b[39m\n\u001b[31m    list.innerHTML = _showDeletedView\u001b[39m\n\u001b[31m      ? '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">✅</div><div class=\\\"empty-txt\\\">No deleted recces</div></div>'\u001b[39m\n\u001b[31m      : '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">🔍</div><div class=\\\"empty-txt\\\">No matching submissions</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (group === 'agent') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.submitted_by||'').localeCompare(b.submitted_by||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.submitted_by || 'Unknown';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">👤 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'brand') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.brand||'').localeCompare(b.brand||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.brand || 'No Brand';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🏷 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'client') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.client_name||'').localeCompare(b.client_name||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.client_name || 'No Client';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🤝 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'city') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.city||'').localeCompare(b.city||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.city || 'No City';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">📍 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows.sort((a,b) => new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    rows.forEach(r => { html += adminCard(r); });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminCard(r) {\u001b[39m\n\u001b[31m  const dt    = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds    = dt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m  const tm    = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const photos = (r.front_photos||0) + (r.inside_photos||0) + (r.addl_photos||0);\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const canDelete  = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const canArchive = _RECCE_CFG_ADMINS.includes(hub?.empId) && !r.client_archived;·\u001b[39m\n\u001b[31m  // Client status badge\u001b[39m\n\u001b[31m  const clientStatusMap = {\u001b[39m\n\u001b[31m    approved:              {t:'✓ Approved',    s:'color:#166534;background:#dcfce7;border:1px solid #86efac'},\u001b[39m\n\u001b[31m    rejected:              {t:'✕ Rejected',    s:'color:#991b1b;background:#fee2e2;border:1px solid #fca5a5'},\u001b[39m\n\u001b[31m    approved_with_changes: {t:'✎ Approved w/ Comments', s:'color:#92400e;background:#fef3c7;border:1px solid #fcd34d'},\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const csCfg = clientStatusMap[r.client_status];\u001b[39m\n\u001b[31m  const clientStatusBadge = csCfg\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;${csCfg.s}\\\">${csCfg.t}</span>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const archiveBadge = r.client_archived\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;color:#475569;background:#f1f5f9;border:1px solid #cbd5e1\\\">⬚ Client hidden</span>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  if (r.deleted_at) {\u001b[39m\n\u001b[31m    const delDt = new Date(r.deleted_at);\u001b[39m\n\u001b[31m    const delDs = delDt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m    const reasonLabel = r.deletion_reason === 'wrong' ? 'Wrong' : r.deletion_reason === 'duplicate' ? 'Duplicate' : 'Test';\u001b[39m\n\u001b[31m    return `<div class=\\\"asc deleted-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m        <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m            <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds}</span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m          <span class=\\\"del-reason-tag\\\">❌ ${reasonLabel}</span>\u001b[39m\n\u001b[31m          <div class=\\\"del-by-txt\\\">by ${r.deleted_by||'?'} · ${delDs}</div>\u001b[39m\n\u001b[31m          ${canDelete ? `<button class=\\\"restore-btn\\\" onclick=\\\"event.stopPropagation();restoreRecce('${r.sub_id}')\\\">↩ Restore</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Submitted by ${r.submitted_by||'?'}</div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const chips = [\u001b[39m\n\u001b[31m    photos > 0   ? `📷 ${photos} photo${photos!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.has_video  ? '🎥 Video' : null,\u001b[39m\n\u001b[31m    r.has_branding ? `🪧 ${r.branding_count} branding${r.branding_count!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.city       ? `📍 ${r.city}` : (r.address ? `📍 ${r.address}` : null),\u001b[39m\n\u001b[31m    r.view_url   ? '👁 View available' : null,\u001b[39m\n\u001b[31m  ].filter(Boolean);·\u001b[39m\n\u001b[31m  const delBtnHtml = canDelete\u001b[39m\n\u001b[31m    ? `<button class=\\\"del-btn\\\" onclick=\\\"event.stopPropagation();openDeleteModal('${r.sub_id}')\\\" title=\\\"Delete recce\\\">🗑</button>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const editReqHtml = r.edit_assigned_to\u001b[39m\n\u001b[31m    ? `<span class=\\\"edit-req-badge\\\">✏ Edit sent to ${r.edit_assigned_to}</span>`\u001b[39m\n\u001b[31m    : (_isSupervisor()\u001b[39m\n\u001b[31m        ? `<button class=\\\"req-edit-btn\\\" onclick=\\\"event.stopPropagation();openEditRequestModal('${r.sub_id}')\\\">✏ Request Edit</button>`\u001b[39m\n\u001b[31m        : '');·\u001b[39m\n\u001b[31m  const editRow = editReqHtml\u001b[39m\n\u001b[31m    ? `<div style=\\\"margin-top:6px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">${editReqHtml}</div>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const showPdfBtn = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m  const pdfClass = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m  const pdfLabel = '📄 PDF';\u001b[39m\n\u001b[31m  const linkJobBtn = (_pendingJobFilter && _isSupervisor() && !r.campaign_id)\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:#f59e0b;color:#000;border-color:#f59e0b;font-weight:700\\\" onclick=\\\"event.stopPropagation();openLinkJobModal('${r.sub_id}','${(r.store_name||'Unknown').replace(/'/g,'\\\\\\\\\\\\'')}')\\\">🔗 Link Job</button>`\u001b[39m\n\u001b[31m    : (r.campaign_id ? `<span style=\\\"font-size:10px;color:var(--g400);align-self:center\\\">🔗 ${r.campaign_id}</span>` : '');\u001b[39m\n\u001b[31m  const archiveBtn = canArchive\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:rgba(99,102,241,.08);border-color:var(--nv);color:var(--nv)\\\" onclick=\\\"event.stopPropagation();archiveRecce('${r.sub_id}')\\\">⛚ Archive</button>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const btnsRow = `<div class=\\\"rpt-btns\\\">\u001b[39m\n\u001b[31m    <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openAdminRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m    ${showPdfBtn ? `<button class=\\\"${pdfClass}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">${pdfLabel}</button>` : ''}\u001b[39m\n\u001b[31m    ${linkJobBtn}\u001b[39m\n\u001b[31m    ${archiveBtn}\u001b[39m\n\u001b[31m  </div>`;·\u001b[39m\n\u001b[31m  return `<div class=\\\"asc\\\">\u001b[39m\n\u001b[31m    <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m      <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m          ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          ${r.client_name&&r.client_name!==r.brand?`<span class=\\\"client-tag\\\">🤝 ${r.client_name}</span>`:''}\u001b[39m\n\u001b[31m          <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds} · ${tm}</span>\u001b[39m\n\u001b[31m          ${clientStatusBadge}\u001b[39m\n\u001b[31m          ${archiveBadge}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <span class=\\\"asc-agent\\\">👤 ${r.submitted_by||'?'}</span>\u001b[39m\n\u001b[31m        ${delBtnHtml}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    ${chips.length?`<div class=\\\"asc-chips\\\">${chips.map(c=>`<span class=\\\"asc-chip\\\">${c}</span>`).join('')}</div>`:''}\u001b[39m\n\u001b[31m    ${editRow}\u001b[39m\n\u001b[31m    ${btnsRow}\u001b[39m\n\u001b[31m  </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _ensurePdfOverlay() {\u001b[39m\n\u001b[31m  if (document.getElementById('pdf-wait-ov')) return;\u001b[39m\n\u001b[31m  const ov = document.createElement('div');\u001b[39m\n\u001b[31m  ov.id = 'pdf-wait-ov';\u001b[39m\n\u001b[31m  ov.innerHTML = '<div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Generating PDF…</div><div class=\\\"po-sub\\\" id=\\\"pw-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"pw-pfill\\\"></div></div>';\u001b[39m\n\u001b[31m  document.body.appendChild(ov);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _showPdfOverlay(msg) {\u001b[39m\n\u001b[31m  _ensurePdfOverlay();\u001b[39m\n\u001b[31m  document.getElementById('pw-sub').textContent = msg || '';\u001b[39m\n\u001b[31m  document.getElementById('pw-pfill').style.width = '0%';\u001b[39m\n\u001b[31m  document.getElementById('pdf-wait-ov').style.display = 'flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _hidePdfOverlay() {\u001b[39m\n\u001b[31m  const ov = document.getElementById('pdf-wait-ov');\u001b[39m\n\u001b[31m  if (ov) ov.style.display = 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function openPdf(subId, pdfUrl, viewUrl) {\u001b[39m\n\u001b[31m  if (pdfUrl) { window.open(pdfUrl, '_blank'); return; }\u001b[39m\n\u001b[31m  if (!viewUrl) {\u001b[39m\n\u001b[31m    toast('Report view not available yet — please try after the report is generated.', 'info');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _showPdfOverlay('Requesting PDF generation…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type': 'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({type: 'regen-pdf', subId, viewUrl})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  let attempts = 0;\u001b[39m\n\u001b[31m  const MAX = 24;\u001b[39m\n\u001b[31m  const poll = async () => {\u001b[39m\n\u001b[31m    attempts++;\u001b[39m\n\u001b[31m    const pct = Math.min(88, Math.round(attempts / MAX * 88));\u001b[39m\n\u001b[31m    document.getElementById('pw-pfill').style.width = pct + '%';\u001b[39m\n\u001b[31m    const left = Math.ceil((MAX - attempts) * 5);\u001b[39m\n\u001b[31m    document.getElementById('pw-sub').textContent = 'Checking… (' + left + 's remaining)';\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const res = await fetch('/db/submissions?sub_id=eq.' + subId + '&select=pdf_url', {\u001b[39m\n\u001b[31m        headers: {'Content-Profile': 'recce', 'Accept-Profile': 'recce'}\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      const rows = await res.json();\u001b[39m\n\u001b[31m      if (rows && rows[0] && rows[0].pdf_url) {\u001b[39m\n\u001b[31m        document.getElementById('pw-pfill').style.width = '100%';\u001b[39m\n\u001b[31m        setTimeout(() => { _hidePdfOverlay(); window.open(rows[0].pdf_url, '_blank'); }, 400);\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(_) {}\u001b[39m\n\u001b[31m    if (attempts >= MAX) { _hidePdfOverlay(); toast('PDF generation timed out. Please try again later.', 'error'); return; }\u001b[39m\n\u001b[31m    setTimeout(poll, 5000);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  setTimeout(poll, 4000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openAdminRecce(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];·\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">\u001b[39m\n\u001b[31m         📍 View on Google Maps (${Number(r.gps_lat).toFixed(4)}, ${Number(r.gps_lng).toFixed(4)})\u001b[39m\n\u001b[31m       </a>` : '';·\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} ft × ${b.h||'?'} ft · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos not yet available — field agent must re-sync from their device to upload view\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Submission Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">👤 ${r.submitted_by||'Unknown'}</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            ${meta.videoCmt?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500);font-size:12px\\\">${meta.videoCmt}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m          ${(()=>{\u001b[39m\n\u001b[31m            const hub2 = _recceHubUser();\u001b[39m\n\u001b[31m            const isHP = _RECCE_CFG_ADMINS.includes(hub2?.empId);\u001b[39m\n\u001b[31m            const csMap = {\u001b[39m\n\u001b[31m              approved:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#166534;background:#dcfce7\\\">✓ Approved</span>',\u001b[39m\n\u001b[31m              rejected:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#991b1b;background:#fee2e2\\\">✕ Rejected</span>',\u001b[39m\n\u001b[31m              approved_with_changes: '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#92400e;background:#fef3c7\\\">✎ Approved w/ Comments</span>',\u001b[39m\n\u001b[31m            };\u001b[39m\n\u001b[31m            const csBadge = csMap[r.client_status] || '';\u001b[39m\n\u001b[31m            const approvedAt = r.client_approved_at\u001b[39m\n\u001b[31m              ? new Date(r.client_approved_at).toLocaleString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit',timeZone:'Asia/Kolkata'})\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const pdfLink = r.client_approval_pdf_url\u001b[39m\n\u001b[31m              ? `<a href=\\\"${r.client_approval_pdf_url}\\\" target=\\\"_blank\\\" style=\\\"font-size:12px;color:var(--or);text-decoration:none\\\">⬇ Approval PDF</a>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const archAct = isHP && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveRecce('${r.sub_id}')\\\" style=\\\"font-size:12px;color:var(--nv);background:none;border:1px solid var(--nv);border-radius:6px;padding:4px 10px;cursor:pointer\\\">⦽ Archive from client</button>`\u001b[39m\n\u001b[31m              : (r.client_archived ? '<span style=\\\"font-size:11px;color:var(--g400)\\\">⦽ Hidden from client</span>' : '');\u001b[39m\n\u001b[31m            const campAct = isHP && r.campaign_id && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveAllForCampaign('${r.campaign_id}')\\\" style=\\\"font-size:11px;color:#991b1b;background:none;border:1px solid #fca5a5;border-radius:6px;padding:3px 8px;cursor:pointer\\\">Archive ALL for ${r.campaign_id}</button>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            if (!csBadge && !pdfLink && !archAct) return '';\u001b[39m\n\u001b[31m            return `<div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m              <div class=\\\"ardl-lbl\\\">Client Approval</div>\u001b[39m\n\u001b[31m              ${csBadge ? `<div style=\\\"margin-bottom:5px\\\">${csBadge}${approvedAt ? ' <span style=\\\"font-size:11px;color:var(--g400)\\\">' + approvedAt + '</span>' : ''}</div>` : ''}\u001b[39m\n\u001b[31m              ${r.client_comment ? `<div style=\\\"font-size:12px;color:var(--g600);background:var(--g50);border-radius:6px;padding:7px 10px;margin-bottom:5px\\\">\\\"${r.client_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m              ${pdfLink ? `<div style=\\\"margin-bottom:4px\\\">${pdfLink}</div>` : ''}\u001b[39m\n\u001b[31m              ${archAct ? `<div style=\\\"margin-bottom:4px\\\">${archAct}</div>` : ''}\u001b[39m\n\u001b[31m              ${campAct ? `<div>${campAct}</div>` : ''}\u001b[39m\n\u001b[31m            </div>`;\u001b[39m\n\u001b[31m          })()}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeAdminDetail() {\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveRecce(subId) {\u001b[39m\n\u001b[31m  if (!confirm('Archive this recce from client view? The client will no longer see it.')) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(subId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) Object.assign(_adminRows[idx], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    toast('Archived from client view ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveAllForCampaign(campaignId) {\u001b[39m\n\u001b[31m  if (!confirm(`Archive ALL recces for campaign \\\"${campaignId}\\\" from client view?\\\\nClients will no longer see any recce from this campaign.`)) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?campaign_id=eq.${encodeURIComponent(campaignId)}&client_archived=eq.false`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    _adminRows.forEach((row, i) => {\u001b[39m\n\u001b[31m      if (row.campaign_id === campaignId) Object.assign(_adminRows[i], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    toast(`All recces for ${campaignId} archived ✓`, 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function regenAllReports() {\u001b[39m\n\u001b[31m  if (!_adminUnlocked) { toast('Admin access required', 'error'); return; }\u001b[39m\n\u001b[31m  const rows = _adminRows.filter(r => !r.deleted_at && r.photo_urls);\u001b[39m\n\u001b[31m  if (!rows.length) { toast('No synced rows with photos found', 'error'); return; }·\u001b[39m\n\u001b[31m  const btn = document.getElementById('regen-rpt-btn');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Regenerating…'; }\u001b[39m\n\u001b[31m  toast(`Regenerating ${rows.length} reports…`, 'info');·\u001b[39m\n\u001b[31m  let done = 0, failed = 0;\u001b[39m\n\u001b[31m  for (const r of rows) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const photoUrls = typeof r.photo_urls === 'string' ? JSON.parse(r.photo_urls) : (r.photo_urls || {});\u001b[39m\n\u001b[31m      let meta = {};\u001b[39m\n\u001b[31m      try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m      const entry = {\u001b[39m\n\u001b[31m        id: r.sub_id,\u001b[39m\n\u001b[31m        timestamp: r.submitted_at,\u001b[39m\n\u001b[31m        submittedBy: r.submitted_by,\u001b[39m\n\u001b[31m        data: {\u001b[39m\n\u001b[31m          storeName:    r.store_name,\u001b[39m\n\u001b[31m          brand:        r.brand,\u001b[39m\n\u001b[31m          clientName:   r.client_name,\u001b[39m\n\u001b[31m          date:         r.visit_date,\u001b[39m\n\u001b[31m          address:      r.address,\u001b[39m\n\u001b[31m          city:         r.city,\u001b[39m\n\u001b[31m          mobile:       r.mobile,\u001b[39m\n\u001b[31m          gpsCoords:    (r.gps_lat && r.gps_lng) ? { lat: r.gps_lat, lng: r.gps_lng } : null,\u001b[39m\n\u001b[31m          hasVideo:     r.has_video,\u001b[39m\n\u001b[31m          videoNote:    meta.videoNote || '',\u001b[39m\n\u001b[31m          videoCmt:     meta.videoCmt  || '',\u001b[39m\n\u001b[31m          frontPhotos:  (photoUrls.front   || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          insidePhotos: (photoUrls.inside  || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          addlPhotos:   (photoUrls.addl    || []).map(() => ({ desc: '' })),\u001b[39m\n\u001b[31m          brandings:    (meta.brandings    || []),\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      };·\u001b[39m\n\u001b[31m      const html = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m      const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m        method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m        body: JSON.stringify({ type: 'save-view', subId: r.sub_id, html })\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!vResp.ok) { failed++; continue; }\u001b[39m\n\u001b[31m      const vr = await vResp.json();\u001b[39m\n\u001b[31m      if (!vr.success) { failed++; continue; }·\u001b[39m\n\u001b[31m      if (vr.url && vr.url !== r.view_url) {\u001b[39m\n\u001b[31m        await fetch(`${_RC_BASE}/submissions?sub_id=eq.${r.sub_id}`, {\u001b[39m\n\u001b[31m          method: 'PATCH', headers: _RC_WRITE,\u001b[39m\n\u001b[31m          body: JSON.stringify({ view_url: vr.url })\u001b[39m\n\u001b[31m        });\u001b[39m\n\u001b[31m        const idx = _adminRows.findIndex(x => x.sub_id === r.sub_id);\u001b[39m\n\u001b[31m        if (idx >= 0) _adminRows[idx].view_url = vr.url;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      done++;\u001b[39m\n\u001b[31m    } catch(e) { failed++; }\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = false; btn.textContent = '↻ Regen Reports'; }\u001b[39m\n\u001b[31m  toast(`Done: ${done} regenerated${failed ? `, ${failed} failed` : ''}`, done > 0 ? 'success' : 'error');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction toggleDeletedView() {\u001b[39m\n\u001b[31m  _showDeletedView = !_showDeletedView;\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openDeleteModal(subId) {\u001b[39m\n\u001b[31m  _pendingDeleteId = subId;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  const sub = document.getElementById('del-modal-sub');\u001b[39m\n\u001b[31m  if (sub) sub.textContent = r ? `Delete: \\\"${r.store_name||'Unknown'}\\\"` : 'Select reason for deletion:';\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectDeleteReason(reason) {\u001b[39m\n\u001b[31m  _pendingDeleteReason = reason;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  document.getElementById('reason-' + reason)?.classList.add('sel');\u001b[39m\n\u001b[31m  document.getElementById('del-confirm-btn').classList.remove('no-reason');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeDeleteModal() {\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingDeleteId = null;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  clearTimeout(_tt);\u001b[39m\n\u001b[31m  document.getElementById('toast').classList.remove('show');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function restoreRecce(subId) {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({ deleted_at: null, deleted_by: null, deletion_reason: null }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Restore failed: ' + r.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_at = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_by = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deletion_reason = null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    toast('Recce restored ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Restore failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmDelete() {\u001b[39m\n\u001b[31m  if (!_pendingDeleteReason) {\u001b[39m\n\u001b[31m    const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m    btn.style.animation = 'none';\u001b[39m\n\u001b[31m    btn.offsetHeight; // reflow\u001b[39m\n\u001b[31m    btn.style.animation = 'shake .35s ease';\u001b[39m\n\u001b[31m    toast('Select a reason first', 'error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if (!_pendingDeleteId) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Deleting…';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      // Hard delete — no audit trail\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'DELETE',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Delete failed: ' + r.status);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Soft delete — stamp deleted_at, deleted_by, deletion_reason\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'PATCH',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m        body: JSON.stringify({\u001b[39m\n\u001b[31m          deleted_at: new Date().toISOString(),\u001b[39m\n\u001b[31m          deleted_by: hub.empId,\u001b[39m\n\u001b[31m          deletion_reason: _pendingDeleteReason,\u001b[39m\n\u001b[31m        }),\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Update failed: ' + r.status);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Remove or update in local cache\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      _adminRows = _adminRows.filter(x => x.sub_id !== _pendingDeleteId);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      const idx = _adminRows.findIndex(x => x.sub_id === _pendingDeleteId);\u001b[39m\n\u001b[31m      if (idx >= 0) {\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_at = new Date().toISOString();\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_by = hub.empId;\u001b[39m\n\u001b[31m        _adminRows[idx].deletion_reason = _pendingDeleteReason;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeDeleteModal();\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast('Recce deleted', 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Delete failed', 'error');\u001b[39m\n\u001b[31m    btn.classList.remove('no-reason');\u001b[39m\n\u001b[31m    btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openMyServerRecce(subId) {\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  // No view yet — show metadata modal (same layout as admin detail)\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta==='string' ? JSON.parse(r.meta) : (r.meta||{}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">📍 View on Google Maps</a>` : '';\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} × ${b.h||'?'} in · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos will appear after next sync from original device\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Visit Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupLanding() {\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = 'none';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = 'none';\u001b[39m\n\u001b[31m  // Clean up admin + create-mode UI\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('sup-back-btn')?.remove();\u001b[39m\n\u001b[31m  document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m  _supCreateMode = false;\u001b[39m\n\u001b[31m  // Resume-wrap may have been hidden by loadHomeAdmin() — restore it so draft banner shows\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = '';\u001b[39m\n\u001b[31m  document.getElementById('sub-list').innerHTML = `\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorViewAll()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0f9ff\\\">📋</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">View All Recces</span><span class=\\\"hi-txt\\\">सभी रेकी देखें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">Browse & review submissions from all agents</span><span class=\\\"hi-txt\\\">सभी एजेंट की सबमिशन देखें</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorCreateView()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0fdf4\\\">✍️</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">Create Recce</span><span class=\\\"hi-txt\\\">नई रेकी बनाएं</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">My submissions + New Recce button</span><span class=\\\"hi-txt\\\">मेरी सबमिशन + नई रेकी</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorViewAll() {\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  await loadHomeAdmin();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorCreateView() {\u001b[39m\n\u001b[31m  _supCreateMode = true;\u001b[39m\n\u001b[31m  // Restore field-agent UI\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh'); if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = t('My Submissions','मेरी सबमिशन');\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar'); if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  // Add Back to Menu button (once)\u001b[39m\n\u001b[31m  if (!document.getElementById('sup-back-create-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-create-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => {\u001b[39m\n\u001b[31m      _supCreateMode = false;\u001b[39m\n\u001b[31m      document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m      renderSupLanding();\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    document.querySelector('#view-home .content').prepend(bb);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  await loadHome();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadHome() {\u001b[39m\n\u001b[31m  if (_isSupervisor() && !_supCreateMode) { renderSupLanding(); return; }\u001b[39m\n\u001b[31m  if (_adminUnlocked && !_supCreateMode) { await loadHomeAdmin(); return; }·\u001b[39m\n\u001b[31m  const all  = await dbAll('subs');\u001b[39m\n\u001b[31m  const sy   = all.filter(s => s.status === 'synced').length;\u001b[39m\n\u001b[31m  const pe   = all.filter(s => s.status !== 'synced').length;·\u001b[39m\n\u001b[31m  // Fetch this agent's submissions from server — works on any device\u001b[39m\n\u001b[31m  let serverOnly = [];\u001b[39m\n\u001b[31m  let editAssigned = [];\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (navigator.onLine && hub?.empId) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?submitted_by=eq.${encodeURIComponent(hub.empId)}&order=submitted_at.desc&limit=200`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp.ok) {\u001b[39m\n\u001b[31m        const rows = await resp.json();\u001b[39m\n\u001b[31m        const localIds = new Set(all.map(s => s.id));\u001b[39m\n\u001b[31m        serverOnly = rows.filter(r => !localIds.has(r.sub_id));\u001b[39m\n\u001b[31m        _myServerRows = serverOnly;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m    // Fetch edit-assigned recces (supervisor assigned this creator to edit)\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp2 = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?edit_assigned_to=eq.${encodeURIComponent(hub.empId)}&deleted_at=is.null&order=submitted_at.desc`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp2.ok) editAssigned = await resp2.json();\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = sy + serverOnly.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = pe;\u001b[39m\n\u001b[31m  document.getElementById('stat-total').textContent   = all.length + serverOnly.length;·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!all.length && !serverOnly.length && !editAssigned.length) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">📋</div><div class=\\\"empty-txt\\\">No submissions yet</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const icos   = { synced:'✅', pending:'⏳', failed:'❌' };\u001b[39m\n\u001b[31m  const sorted = [...all].sort((a,b) => new Date(b.timestamp) - new Date(a.timestamp)).slice(0, 50);·\u001b[39m\n\u001b[31m  const localCards = sorted.map(s => {\u001b[39m\n\u001b[31m    const dt = new Date(s.timestamp);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const viewBtn = s.viewUrl\u001b[39m\n\u001b[31m      ? `<button class=\\\"edit-btn-sm\\\" onclick=\\\"window.open('${s.viewUrl}','_blank')\\\">👁 View</button>`\u001b[39m\n\u001b[31m      : `<button class=\\\"edit-btn-sm\\\" onclick=\\\"viewRecce('${s.id}')\\\">👁 View</button>`;\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico ${s.status}\\\">${icos[s.status]||'📋'}</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${s.data.storeName||'Unknown'} · ${s.data.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${s.data.address||''}</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge ${s.status}\\\">${s.status}</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          ${viewBtn}\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"editRecce('${s.id}')\\\" style=\\\"background:#fff7ed;border-color:var(--or);color:var(--or)\\\">✏ Edit</button>\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"makeSlides('${s.id}')\\\" style=\\\"background:#eff6ff;border-color:#3b82f6;color:#1d4ed8\\\">📊 Slides</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const serverCards = serverOnly.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const showPdf = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m    const pdfCls = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico synced\\\">✅</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\" style=\\\"min-width:0;flex:1\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"rpt-btns\\\" style=\\\"margin-top:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openMyServerRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m          ${showPdf ? `<button class=\\\"${pdfCls}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">📄 PDF</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge synced\\\">synced</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const editAssignedCards = editAssigned.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    return `<div class=\\\"edit-req-card\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:26px;flex-shrink:0\\\">✏</div>\u001b[39m\n\u001b[31m      <div class=\\\"edit-req-card-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-meta\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        ${r.edit_comment ? `<div class=\\\"edit-req-cmt\\\">\\\"${r.edit_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:10px;display:flex;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"startCreatorEdit('${r.sub_id}')\\\" style=\\\"padding:9px 16px;font-size:13px;font-weight:600\\\">✏ Edit this Recce</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (editAssignedCards.length) {\u001b[39m\n\u001b[31m    html += `<div class=\\\"edit-req-section-hdr\\\">✏ Edit Requested (${editAssignedCards.length})</div>`;\u001b[39m\n\u001b[31m    html += editAssignedCards.join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  html += localCards.join('') + serverCards.join('');\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m  const ls = await cfg('last-sync');\u001b[39m\n\u001b[31m  if (ls) {\u001b[39m\n\u001b[31m    const d = new Date(ls);\u001b[39m\n\u001b[31m    document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m      'Synced ' + d.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// RESET\u001b[39m\n\u001b[31mfunction startNewRecce(){F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  if(geoStampEnabled)autoRequestGPS();\u001b[39m\n\u001b[31m['f-date','f-brand','f-store','f-addr','f-mobile','f-client-other'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';});\u001b[39m\n\u001b[31m_selectedClient='';_clientOtherMode=false;\u001b[39m\n\u001b[31m_selectedCampaignId=null;_notifySupervisor=false;_brandingLocked=false;\u001b[39m\n\u001b[31mconst _camSel=document.getElementById('f-campaign-id');if(_camSel)_camSel.value='';\u001b[39m\n\u001b[31mconst _camNotice=document.getElementById('campaign-notify-msg');if(_camNotice)_camNotice.style.display='none';\u001b[39m\n\u001b[31mloadCampaignsForForm();\u001b[39m\n\u001b[31mrenderClientChips();\u001b[39m\n\u001b[31mdocument.getElementById('f-date').value=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31m// Block future dates\u001b[39m\n\u001b[31mdocument.getElementById('f-date').max=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31mdocument.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('pick-trigger-wrap').style.display=stores.length?'block':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').style.display=stores.length?'flex':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31mdocument.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31mdocument.getElementById('manual-fields').style.display=stores.length?'none':'block';\u001b[39m\n\u001b[31mdocument.getElementById('gps-status').textContent='';\u001b[39m\n\u001b[31m['vid-yes','vid-no','br-yes','br-no'].forEach(id=>document.getElementById(id).classList.remove('sel'));\u001b[39m\n\u001b[31mdocument.getElementById('vid-sec').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('vid-slot').innerHTML=`<div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('br-add').style.display='none';document.getElementById('br-items').innerHTML='';\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').classList.remove('filled');\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').innerHTML=`<div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('brand-selector').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('sc-missing').style.display='none';\u001b[39m\n\u001b[31mpopulateBrandDropdown();\u001b[39m\n\u001b[31mrenderPhotos('front');renderPhotos('inside');renderAddl();updAvailTag();showView('form-store');}\u001b[39m\n\u001b[31mfunction exitForm(){\u001b[39m\n\u001b[31m  // Show safe exit dialog instead of confirm\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitSaveAndLeave(){\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m  checkDraft();\u001b[39m\n\u001b[31m  toast('Draft saved — tap Resume to continue','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitDiscard(){\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];\u001b[39m\n\u001b[31m  videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  dbDel('draft','current');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitCancel(){document.getElementById('exit-dialog').classList.remove('open');}\u001b[39m\n\u001b[31mfunction showView(n){document.querySelectorAll('.view').forEach(v=>v.classList.remove('active'));const t=document.getElementById('view-'+n);if(t){t.classList.add('active');window.scrollTo(0,0);}}\u001b[39m\n\u001b[31mlet _tt;\u001b[39m\n\u001b[31mfunction toast(msg,type='info'){const el=document.getElementById('toast');el.textContent=msg;el.className='toast show '+type;clearTimeout(_tt);_tt=setTimeout(()=>el.classList.remove('show'),3000);}\u001b[39m\n\u001b[31mfunction netStatus(){const on=navigator.onLine;const dot=document.getElementById('net-dot');const txt=document.getElementById('net-txt');if(dot)dot.className='sdot '+(on?'on':'off');if(txt)txt.textContent=on?t('Online','ऑनलाइन'):t('Offline — saves locally','ऑफलाइन — स्थानीय रूप से सेव');}\u001b[39m\n\u001b[31masync function loadSettings(){\u001b[39m\n\u001b[31m  // Gas URL: pre-load default if none saved, update preview\u001b[39m\n\u001b[31m  const gu=await cfg('gas-url');\u001b[39m\n\u001b[31m  if(!gu)await cfg('gas-url',DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m  // Admin cfg url\u001b[39m\n\u001b[31m  const acu=await cfg('admin-cfg-url');if(acu&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=acu;\u001b[39m\n\u001b[31m  const su=await cfg('srv-url')||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su)document.getElementById('srv-url').value=su;\u001b[39m\n\u001b[31m  const sc=await cfg('stores');\u001b[39m\n\u001b[31m  if(sc){\u001b[39m\n\u001b[31m    stores=JSON.parse(sc);\u001b[39m\n\u001b[31m    const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m    document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m      `✓ ${stores.length} stores in cache${noBrand?` · ${noBrand} without brand`:''}`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const sf=await cfg('store-files');if(sf){_storeFiles=JSON.parse(sf);renderStoreFileList();}\u001b[39m\n\u001b[31m  const iq=await cfg('img-quality');imgQuality=iq||'compressed';applyQualityUI(imgQuality);\u001b[39m\n\u001b[31m  const gs=await cfg('geo-stamp');geoStampEnabled=(gs===null||gs==='1');applyGeoStampUI();\u001b[39m\n\u001b[31m  const bl=await cfg('brands');if(bl)brands=JSON.parse(bl);\u001b[39m\n\u001b[31m  loadBrandsFromDb();  // async — updates brands + logos from DB in background\u001b[39m\n\u001b[31m  renderBrandManageList();\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m  // Show store upload row + brand add row to supervisors only\u001b[39m\n\u001b[31m  const sur = document.getElementById('store-upload-row');\u001b[39m\n\u001b[31m  if (sur) sur.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const bar = document.getElementById('brand-add-row');\u001b[39m\n\u001b[31m  if (bar) bar.style.display = _isSupervisor() ? 'flex' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction populateBrandDropdown(){\u001b[39m\n\u001b[31m  const sel=document.getElementById('f-brand');if(!sel)return;\u001b[39m\n\u001b[31m  const cur=sel.value;\u001b[39m\n\u001b[31m  sel.innerHTML='<option value=\\\"\\\">Select brand</option>'+brands.map(b=>`<option${cur===b?' selected':''}>${b}</option>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderBrandManageList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('brand-manage-list');if(!el)return;\u001b[39m\n\u001b[31m  const isSup=_isSupervisor();\u001b[39m\n\u001b[31m  el.innerHTML=brands.map((b,i)=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    const logoHtml=logo?`<img src=\\\"${logo}\\\" style=\\\"height:20px;max-width:48px;object-fit:contain;flex-shrink:0;border-radius:3px\\\">`:'';\u001b[39m\n\u001b[31m    const ctrlHtml=isSup?`<div style=\\\"display:flex;gap:2px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"openEditBrandDialog(${i})\\\" style=\\\"background:none;border:none;color:var(--nv);font-size:15px;cursor:pointer;padding:2px 6px\\\" title=\\\"Edit\\\">✏</button>\u001b[39m\n\u001b[31m      ${brands.length>1?`<button onclick=\\\"confirmRemoveBrand(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:2px 4px\\\">×</button>`:'<span style=\\\"font-size:11px;color:var(--g400);padding:0 6px\\\">Last</span>'}\u001b[39m\n\u001b[31m    </div>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;min-width:0\\\">${logoHtml}<span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${b}</span></div>\u001b[39m\n\u001b[31m      ${ctrlHtml}\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function addBrandToList(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const inp=document.getElementById('brand-add-inp');\u001b[39m\n\u001b[31m  const val=(inp.value.trim()||'').toUpperCase();\u001b[39m\n\u001b[31m  if(!val){toast('Enter a brand name','error');return;}\u001b[39m\n\u001b[31m  if(brands.some(b=>b.toLowerCase()===val.toLowerCase())){toast(`${val} already in list`,'error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands`,{method:'POST',headers:{..._RC_WRITE,'Prefer':'return=minimal'},body:JSON.stringify({name:val,sort_order:99})});\u001b[39m\n\u001b[31m    if(resp.status===409){toast(`${val} already exists in DB`,'error');return;}\u001b[39m\n\u001b[31m    if(!resp.ok){const e=await resp.json().catch(()=>({}));throw new Error(e.message||resp.status);}\u001b[39m\n\u001b[31m    inp.value='';\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${val} added ✓`,'success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Add failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmRemoveBrand(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const name=brands[idx];\u001b[39m\n\u001b[31m  if(brands.length<=1){toast('Need at least one brand','error');return;}\u001b[39m\n\u001b[31m  let count=0;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(name)}&select=sub_id`,{headers:_RC_READ});\u001b[39m\n\u001b[31m    if(r.ok){const rows=await r.json();count=rows.length;}\u001b[39m\n\u001b[31m  }catch(_){}\u001b[39m\n\u001b[31m  const msg=count>0?`Delete \\\"${name}\\\" from brand list?\\\\n(${count} submission${count!==1?'s':''} reference this brand — they keep the name as text.)`:`Delete \\\"${name}\\\" from brand list?`;\u001b[39m\n\u001b[31m  if(!confirm(msg))return;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(name)}`,{method:'DELETE',headers:{'Content-Profile':'recce','Accept-Profile':'recce'}});\u001b[39m\n\u001b[31m    if(!resp.ok&&resp.status!==204){throw new Error(resp.status);}\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${name} removed ✓`,'info');\u001b[39m\n\u001b[31m  }catch(e){toast(`Remove failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadBrandsFromDb(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch('/db/brands?select=name,logo_url&order=sort_order',{\u001b[39m\n\u001b[31m      headers:{'Content-Profile':'recce','Accept-Profile':'recce'}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(!r.ok) return;\u001b[39m\n\u001b[31m    const rows=await r.json();\u001b[39m\n\u001b[31m    if(!rows||!rows.length) return;\u001b[39m\n\u001b[31m    const dbNames=rows.map(r=>r.name);\u001b[39m\n\u001b[31m    const logos={};rows.forEach(r=>{if(r.logo_url)logos[r.name]=r.logo_url;});\u001b[39m\n\u001b[31m    // Merge: DB brands canonical, keep locally-added extras\u001b[39m\n\u001b[31m    const extras=brands.filter(b=>!dbNames.some(n=>n.toLowerCase()===b.toLowerCase()));\u001b[39m\n\u001b[31m    brands=[...dbNames,...extras];\u001b[39m\n\u001b[31m    _brandLogos=logos;\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    // Refresh brand chips if brand-selector is visible\u001b[39m\n\u001b[31m    const bSel=document.getElementById('brand-selector');\u001b[39m\n\u001b[31m    if(bSel&&bSel.style.display!=='none') renderBrandChips();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[brands-db]',e.message);}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction renderBrandChips(){\u001b[39m\n\u001b[31m  const bChips=document.getElementById('brand-chips');if(!bChips)return;\u001b[39m\n\u001b[31m  bChips.innerHTML=brands.map(b=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    return `<div class=\\\"chip brand-chip${F.brand===b?' sel':''}\\\" onclick=\\\"selectStoreBrand('${b.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\">` +\u001b[39m\n\u001b[31m      (logo?`<img src=\\\"${logo}\\\" class=\\\"brand-chip-logo\\\" alt=\\\"\\\">`:'') +\u001b[39m\n\u001b[31m      `<span>${b}</span></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _editBrandIdx=null,_editBrandOld=null;\u001b[39m\n\u001b[31mfunction openEditBrandDialog(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor())return;\u001b[39m\n\u001b[31m  _editBrandIdx=idx;_editBrandOld=brands[idx];\u001b[39m\n\u001b[31m  document.getElementById('be-name').value=brands[idx];\u001b[39m\n\u001b[31m  const logo=_brandLogos[brands[idx]]||'';\u001b[39m\n\u001b[31m  document.getElementById('be-logo').value=logo;\u001b[39m\n\u001b[31m  document.getElementById('be-logo-preview').innerHTML=logo?`<img src=\\\"${logo}\\\" style=\\\"height:28px;object-fit:contain\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Current logo</span>`:'';\u001b[39m\n\u001b[31m  document.getElementById('be-cascade-info').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('brand-edit-modal').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeBrandEditModal(){document.getElementById('brand-edit-modal').classList.remove('open');_editBrandIdx=null;_editBrandOld=null;}\u001b[39m\n\u001b[31mfunction previewBrandLogo(){\u001b[39m\n\u001b[31m  const url=(document.getElementById('be-logo')?.value||'').trim();\u001b[39m\n\u001b[31m  const prev=document.getElementById('be-logo-preview');\u001b[39m\n\u001b[31m  if(prev)prev.innerHTML=url?`<img src=\\\"${url}\\\" style=\\\"height:28px;object-fit:contain\\\" onerror=\\\"this.style.display='none'\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Preview</span>`:'';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveBrandEdit(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const oldName=_editBrandOld;\u001b[39m\n\u001b[31m  const newName=(document.getElementById('be-name').value||'').trim().toUpperCase();\u001b[39m\n\u001b[31m  const newLogo=(document.getElementById('be-logo').value||'').trim();\u001b[39m\n\u001b[31m  if(!newName){toast('Brand name required','error');return;}\u001b[39m\n\u001b[31m  const isRename=newName!==oldName;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // 1. Update recce.brands\u001b[39m\n\u001b[31m    const pResp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m      method:'PATCH',headers:{..._RC_WRITE,'Prefer':'return=minimal'},\u001b[39m\n\u001b[31m      body:JSON.stringify({name:newName,logo_url:newLogo||null})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(pResp.status===409){toast(`\\\"${newName}\\\" already exists`,'error');return;}\u001b[39m\n\u001b[31m    if(!pResp.ok&&pResp.status!==204){const e=await pResp.json().catch(()=>({}));throw new Error(e.message||pResp.status);}\u001b[39m\n\u001b[31m    if(isRename){\u001b[39m\n\u001b[31m      const hub=_recceHubUser();\u001b[39m\n\u001b[31m      // 2. Cascade to submissions\u001b[39m\n\u001b[31m      await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m        method:'PATCH',headers:_RC_WRITE,body:JSON.stringify({brand:newName})\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      // 3. Cascade to stores.json + view HTML files + PDFs\u001b[39m\n\u001b[31m      toast('Cascading rename to reports…','info');\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        const cResp=await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},\u001b[39m\n\u001b[31m          body:JSON.stringify({type:'cascade-rename-brand',oldName,newName,empId:hub?.empId||''})});\u001b[39m\n\u001b[31m        const cRes=cResp.ok?await cResp.json():{};\u001b[39m\n\u001b[31m        const msg=`Brand renamed ✓${cRes.viewsUpdated?` · ${cRes.viewsUpdated} reports re-queued`:''}`;\u001b[39m\n\u001b[31m        closeBrandEditModal();\u001b[39m\n\u001b[31m        await loadBrandsFromDb();\u001b[39m\n\u001b[31m        toast(msg,'success');\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }catch(e){console.warn('[cascade-rename]',e.message);}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeBrandEditModal();\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast('Brand updated ✓','success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Save failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function fetchServerBrands(){\u001b[39m\n\u001b[31m  const url=document.getElementById('brands-url')?.value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    toast('Fetching brands…','info');\u001b[39m\n\u001b[31m    const r=await fetch(url);const j=await r.json();\u001b[39m\n\u001b[31m    const list=Array.isArray(j)?j:j.brands||[];\u001b[39m\n\u001b[31m    if(!list.length){toast('No brands found in response','error');return;}\u001b[39m\n\u001b[31m    brands=list.map(b=>b.toString().toUpperCase());\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    toast(`${brands.length} brands loaded from server`,'success');\u001b[39m\n\u001b[31m  }catch{toast('Failed to fetch — check URL','error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setImgQuality(q){\u001b[39m\n\u001b[31m  imgQuality=q;\u001b[39m\n\u001b[31m  cfg('img-quality',q);\u001b[39m\n\u001b[31m  applyQualityUI(q);\u001b[39m\n\u001b[31m  toast(q==='hd'?'HD Quality selected (~400–600 KB per photo)':'Full Compression selected (~150–200 KB per photo)','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction applyQualityUI(q){\u001b[39m\n\u001b[31m  ['compressed','hd'].forEach(opt=>{\u001b[39m\n\u001b[31m    const label=document.getElementById('q-opt-'+opt);\u001b[39m\n\u001b[31m    const radio=document.getElementById('q-radio-'+opt);\u001b[39m\n\u001b[31m    const dot  =document.getElementById('q-dot-'+opt);\u001b[39m\n\u001b[31m    if(!label)return;\u001b[39m\n\u001b[31m    const active=opt===q;\u001b[39m\n\u001b[31m    label.style.borderColor=active?'var(--or)':'var(--g200)';\u001b[39m\n\u001b[31m    label.style.background=active?'#fff7ed':'var(--g50)';\u001b[39m\n\u001b[31m    if(radio)radio.style.borderColor=active?'var(--or)':'var(--g300)';\u001b[39m\n\u001b[31m    if(dot)dot.style.display=active?'block':'none';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const badge=document.getElementById('q-current-badge');\u001b[39m\n\u001b[31m  if(badge){\u001b[39m\n\u001b[31m    const label=q==='hd'?'HD Quality (~400–600 KB)':'Full Compression (~150–200 KB)';\u001b[39m\n\u001b[31m    badge.innerHTML=`Active: <strong>${label}</strong>`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function clearData(){if(!confirm('Delete ALL local data?'))return;const all=await dbAll('subs');for(const s of all)await dbDel('subs',s.id);stores=[];await cfg('stores',null);toast('All cleared','success');loadHome();}\u001b[39m\n\u001b[31mif('serviceWorker' in navigator){const sw=`const C='recce-v37';self.addEventListener('install',e=>{e.waitUntil(caches.open(C).then(c=>c.add('/')));self.skipWaiting();});self.addEventListener('activate',e=>e.waitUntil(clients.claim()));self.addEventListener('fetch',e=>{if(e.request.method!=='GET')return;e.respondWith(caches.match(e.request).then(r=>{if(r)return r;return fetch(e.request).then(res=>{if(res&&res.status===200&&res.type==='basic'){const cl=res.clone();caches.open(C).then(c=>c.put(e.request,cl));}return res;}).catch(()=>caches.match('/'));}))}); `;const blob=new Blob([sw],{type:'application/javascript'});navigator.serviceWorker.register(URL.createObjectURL(blob),{scope:'/'}).catch(()=>{});}·\u001b[39m\n\u001b[31m// ── GEOLOCATION STAMP ────────────────────────────────────────\u001b[39m\n\u001b[31mfunction applyGeoStampUI(){\u001b[39m\n\u001b[31m  const tog=document.getElementById('geo-tog');\u001b[39m\n\u001b[31m  if(tog)tog.classList.toggle('on',geoStampEnabled);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function toggleGeoStamp(){\u001b[39m\n\u001b[31m  geoStampEnabled=!geoStampEnabled;\u001b[39m\n\u001b[31m  await cfg('geo-stamp',geoStampEnabled?'1':'0');\u001b[39m\n\u001b[31m  applyGeoStampUI();\u001b[39m\n\u001b[31m  toast(geoStampEnabled?'Geolocation stamp enabled':'Geolocation stamp disabled','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Auto-request GPS silently when a new recce starts\u001b[39m\n\u001b[31mfunction autoRequestGPS(){\u001b[39m\n\u001b[31m  if(!navigator.geolocation)return;\u001b[39m\n\u001b[31m  const statusEl=document.getElementById('geo-status');\u001b[39m\n\u001b[31m  if(statusEl)statusEl.textContent='Acquiring GPS…';\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(\u001b[39m\n\u001b[31m    pos=>{\u001b[39m\n\u001b[31m      gpsCoords={\u001b[39m\n\u001b[31m        lat:pos.coords.latitude.toFixed(6),\u001b[39m\n\u001b[31m        lng:pos.coords.longitude.toFixed(6),\u001b[39m\n\u001b[31m        acc:Math.round(pos.coords.accuracy)\u001b[39m\n\u001b[31m      };\u001b[39m\n\u001b[31m      const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m      const quality=acc<=15?'Excellent':acc<=50?'Good':acc<=200?'Fair':'Poor (cell tower)';\u001b[39m\n\u001b[31m      const color=acc<=15?'var(--gn)':acc<=50?'#16a34a':acc<=200?'var(--am)':'var(--rd)';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.innerHTML=`GPS: ${gpsCoords.lat}, ${gpsCoords.lng} · ±${acc}m · <span style=\\\"color:${color};font-weight:600\\\">${quality}</span>`;\u001b[39m\n\u001b[31m      // Update form GPS status too\u001b[39m\n\u001b[31m      const fs=document.getElementById('gps-status');\u001b[39m\n\u001b[31m      if(fs){fs.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${acc}m)`;fs.style.color='var(--gn)';}\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    err=>{\u001b[39m\n\u001b[31m      const msgs={1:'Location permission denied in Chrome',2:'GPS signal unavailable',3:'GPS timed out'};\u001b[39m\n\u001b[31m      const msg=msgs[err.code]||'GPS unavailable';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.textContent=msg+' — stamp will use store address';\u001b[39m\n\u001b[31m      if(err.code===1)toast('Tap the lock icon in Chrome address bar → allow Location','info');\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    {enableHighAccuracy:true,timeout:20000,maximumAge:60000}\u001b[39m\n\u001b[31m  );\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Draw stamp on a photo blob — returns new blob with stamp baked in\u001b[39m\n\u001b[31mfunction roundRectPath(ctx,x,y,w,h,r){\u001b[39m\n\u001b[31m  ctx.beginPath();ctx.moveTo(x+r,y);ctx.lineTo(x+w-r,y);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y,x+w,y+r);ctx.lineTo(x+w,y+h-r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);ctx.lineTo(x+r,y+h);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y+h,x,y+h-r);ctx.lineTo(x,y+r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y,x+r,y);ctx.closePath();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction fitText(ctx,text,maxW){\u001b[39m\n\u001b[31m  if(ctx.measureText(text).width<=maxW)return text;\u001b[39m\n\u001b[31m  while(text.length>1&&ctx.measureText(text+'…').width>maxW)text=text.slice(0,-1);\u001b[39m\n\u001b[31m  return text+'…';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction stampPhoto(blob){\u001b[39m\n\u001b[31m  if(!geoStampEnabled)return Promise.resolve(blob);\u001b[39m\n\u001b[31m  return new Promise(res=>{\u001b[39m\n\u001b[31m    const img=new Image(),url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    img.onload=()=>{\u001b[39m\n\u001b[31m      URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m      const W=img.width,H=img.height;\u001b[39m\n\u001b[31m      const c=document.createElement('canvas');c.width=W;c.height=H;\u001b[39m\n\u001b[31m      const ctx=c.getContext('2d');\u001b[39m\n\u001b[31m      ctx.drawImage(img,0,0);·\u001b[39m\n\u001b[31m      // Stamp dimensions — 18% of image height\u001b[39m\n\u001b[31m      const SH=Math.round(H*0.18);\u001b[39m\n\u001b[31m      const pad=Math.round(W*0.03);\u001b[39m\n\u001b[31m      const SY=H-SH;·\u001b[39m\n\u001b[31m      // Semi-transparent background\u001b[39m\n\u001b[31m      ctx.fillStyle='rgba(10,18,35,0.78)';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,SH);·\u001b[39m\n\u001b[31m      // Orange top accent line\u001b[39m\n\u001b[31m      ctx.fillStyle='#f97316';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,Math.max(3,Math.round(H*0.004)));·\u001b[39m\n\u001b[31m      // Font sizes scaled to image\u001b[39m\n\u001b[31m      const f1=Math.round(SH*0.26); // store name\u001b[39m\n\u001b[31m      const f2=Math.round(SH*0.22); // coords / address\u001b[39m\n\u001b[31m      const f3=Math.round(SH*0.20); // timestamp·\u001b[39m\n\u001b[31m      // Row Y centres\u001b[39m\n\u001b[31m      const r1=SY+SH*0.26;\u001b[39m\n\u001b[31m      const r2=SY+SH*0.55;\u001b[39m\n\u001b[31m      const r3=SY+SH*0.82;·\u001b[39m\n\u001b[31m      // Get stamp data\u001b[39m\n\u001b[31m      const storeName=F.storeName||selectedStore?.name||'';\u001b[39m\n\u001b[31m      const brand=F.brand||selectedStore?.brand||'';\u001b[39m\n\u001b[31m      const addr=F.address||selectedStore?.address||'';\u001b[39m\n\u001b[31m      const now=new Date();\u001b[39m\n\u001b[31m      const dateStr=now.toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m      const timeStr=now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit',hour12:true});·\u001b[39m\n\u001b[31m      // Badge (right side — GPS quality)\u001b[39m\n\u001b[31m      let badgeLabel='',badgeColor='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m        if(acc<=15){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=50){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=200){badgeLabel='~'+acc+'m';badgeColor='#d97706';}\u001b[39m\n\u001b[31m        else{badgeLabel='Cell ~'+acc+'m';badgeColor='#dc2626';}\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        badgeLabel='No GPS';badgeColor='#64748b';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      const bFontSz=Math.round(SH*0.18);\u001b[39m\n\u001b[31m      ctx.font=`bold ${bFontSz}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      const bW=Math.round(ctx.measureText(badgeLabel).width+pad);\u001b[39m\n\u001b[31m      const bH=Math.round(SH*0.32);\u001b[39m\n\u001b[31m      const bX=W-bW-pad;const bY=SY+(SH-bH)/2;\u001b[39m\n\u001b[31m      ctx.fillStyle=badgeColor+'cc';\u001b[39m\n\u001b[31m      roundRectPath(ctx,bX,bY,bW,bH,4);ctx.fill();\u001b[39m\n\u001b[31m      ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';\u001b[39m\n\u001b[31m      ctx.fillText(badgeLabel,bX+bW/2,bY+bH/2);\u001b[39m\n\u001b[31m      ctx.textAlign='left';ctx.textBaseline='alphabetic';·\u001b[39m\n\u001b[31m      const textMaxW=bX-pad*2;·\u001b[39m\n\u001b[31m      // Row 1 — store name + brand\u001b[39m\n\u001b[31m      ctx.font=`bold ${f1}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#ffffff';\u001b[39m\n\u001b[31m      const nameText=storeName+(brand?' · '+brand:'');\u001b[39m\n\u001b[31m      ctx.fillText('📍 '+fitText(ctx,nameText,textMaxW-f1*1.4),pad,r1);·\u001b[39m\n\u001b[31m      // Row 2 — GPS coords OR address\u001b[39m\n\u001b[31m      ctx.font=`${f2}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#cbd5e1';\u001b[39m\n\u001b[31m      let row2='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        row2=`Lat ${gpsCoords.lat}°   Long ${gpsCoords.lng}°`;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        row2=addr?fitText(ctx,addr,textMaxW):'GPS coordinates unavailable';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      ctx.fillText(row2,pad,r2);·\u001b[39m\n\u001b[31m      // Row 3 — date and time\u001b[39m\n\u001b[31m      ctx.font=`${f3}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#94a3b8';\u001b[39m\n\u001b[31m      ctx.fillText(`${dateStr}   ${timeStr}`,pad,r3);·\u001b[39m\n\u001b[31m      c.toBlob(b=>res(b||blob),'image/jpeg',imgQuality==='hd'?0.88:0.82);\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    img.onerror=()=>{URL.revokeObjectURL(url);res(blob);};\u001b[39m\n\u001b[31m    img.src=url;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _aTool='rect',_aColor='#f97316',_aWidth=4,_aTarget=-1;\u001b[39m\n\u001b[31mlet _aImg=null,_aHistory=[],_aDrawing=false,_aStart={},_aPts=[];\u001b[39m\n\u001b[31mlet _aSel=-1,_aDragMode=null,_aDragOff={x:0,y:0};\u001b[39m\n\u001b[31m// Larger hit radius on touch devices for easier finger selection\u001b[39m\n\u001b[31mconst HIT_R=()=>('ontouchstart' in window)?32:16;·\u001b[39m\n\u001b[31mfunction setATool(t){\u001b[39m\n\u001b[31m  _aTool=t;\u001b[39m\n\u001b[31m  ['rect','ellipse','line','arrow','free'].forEach(id=>{const el=document.getElementById('at-'+id);if(el)el.classList.toggle('on',id===t&&t!=='move');});\u001b[39m\n\u001b[31m  const mv=document.getElementById('at-move');if(mv)mv.classList.toggle('sel-on',t==='move');\u001b[39m\n\u001b[31m  const info=document.getElementById('annot-sel-info');if(info)info.style.display=t==='move'?'block':'none';\u001b[39m\n\u001b[31m  if(t!=='move'){_aSel=-1;redrawAnnot();}\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(cvs)cvs.style.cursor=t==='move'?'default':'crosshair';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAColor(c){\u001b[39m\n\u001b[31m  _aColor=c;\u001b[39m\n\u001b[31m  const m={'#f97316':'or','#ef4444':'rd','#ffffff':'wh','#facc15':'yw','#22c55e':'gn'};\u001b[39m\n\u001b[31m  Object.entries(m).forEach(([col,id])=>{const el=document.getElementById('ac-'+id);if(el)el.classList.toggle('on',col===c);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAWidth(w){_aWidth=w;[2,4,7].forEach(v=>{const el=document.getElementById('aw-'+v);if(el)el.classList.toggle('on',v===w);});}·\u001b[39m\n\u001b[31mfunction openAnnot(idx){\u001b[39m\n\u001b[31m  _aTarget=idx;_aHistory=[];_aDrawing=false;_aPts=[];_aSel=-1;_aDragMode=null;\u001b[39m\n\u001b[31m  document.getElementById('annot-modal').classList.add('open');\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');\u001b[39m\n\u001b[31m  const img=new Image(),url=URL.createObjectURL(brandings[idx].blob);\u001b[39m\n\u001b[31m  img.onload=()=>{\u001b[39m\n\u001b[31m    const sc=Math.min(1,window.innerWidth/img.width,(window.innerHeight-185)/img.height);\u001b[39m\n\u001b[31m    cvs.width=Math.round(img.width*sc);cvs.height=Math.round(img.height*sc);\u001b[39m\n\u001b[31m    _aImg=img;redrawAnnot();URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  img.src=url;\u001b[39m\n\u001b[31m  cvs.ontouchstart=aDown;cvs.ontouchmove=aMove;cvs.ontouchend=aUp;\u001b[39m\n\u001b[31m  cvs.onmousedown=aDown;cvs.onmousemove=aMove;cvs.onmouseup=aUp;\u001b[39m\n\u001b[31m  setATool('rect');setAColor('#f97316');setAWidth(4);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aPos(e){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const r=cvs.getBoundingClientRect();\u001b[39m\n\u001b[31m  const src=e.touches?e.touches[0]:e;\u001b[39m\n\u001b[31m  return{x:(src.clientX-r.left)*(cvs.width/r.width),y:(src.clientY-r.top)*(cvs.height/r.height)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Always return normalised (positive w,h) bounds\u001b[39m\n\u001b[31mfunction sBounds(s){\u001b[39m\n\u001b[31m  if(s.type==='free'){\u001b[39m\n\u001b[31m    if(!s.pts||!s.pts.length)return null;\u001b[39m\n\u001b[31m    const xs=s.pts.map(p=>p.x),ys=s.pts.map(p=>p.y);\u001b[39m\n\u001b[31m    const x=Math.min(...xs),y=Math.min(...ys);\u001b[39m\n\u001b[31m    return{x,y,w:Math.max(...xs)-x,h:Math.max(...ys)-y};\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  return{x:Math.min(s.x,s.x+s.w),y:Math.min(s.y,s.y+s.h),w:Math.abs(s.w),h:Math.abs(s.h)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction hitHandle(px,py,s){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return null;\u001b[39m\n\u001b[31m  const b=sBounds(s);const hr=HIT_R();\u001b[39m\n\u001b[31m  for(const[n,x,y]of[['tl',b.x,b.y],['tr',b.x+b.w,b.y],['bl',b.x,b.y+b.h],['br',b.x+b.w,b.y+b.h]])\u001b[39m\n\u001b[31m    if(Math.hypot(px-x,py-y)<hr)return n;\u001b[39m\n\u001b[31m  return null;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction hitShape(px,py,s){\u001b[39m\n\u001b[31m  const b=sBounds(s);if(!b)return false;\u001b[39m\n\u001b[31m  const pad=HIT_R();\u001b[39m\n\u001b[31m  return px>=b.x-pad&&px<=b.x+b.w+pad&&py>=b.y-pad&&py<=b.y+b.h+pad;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aDown(e){\u001b[39m\n\u001b[31m  e.preventDefault();const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'){\u001b[39m\n\u001b[31m    // Check handles of selected shape first\u001b[39m\n\u001b[31m    if(_aSel>=0&&_aSel<_aHistory.length){\u001b[39m\n\u001b[31m      const h=hitHandle(p.x,p.y,_aHistory[_aSel]);\u001b[39m\n\u001b[31m      if(h){_aDragMode='r-'+h;_aDragOff={x:p.x,y:p.y};_aDrawing=true;return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Hit test all shapes topmost first\u001b[39m\n\u001b[31m    for(let i=_aHistory.length-1;i>=0;i--){\u001b[39m\n\u001b[31m      if(hitShape(p.x,p.y,_aHistory[i])){\u001b[39m\n\u001b[31m        _aSel=i;_aDragMode='move';\u001b[39m\n\u001b[31m        const s=_aHistory[i];\u001b[39m\n\u001b[31m        const b=sBounds(s);\u001b[39m\n\u001b[31m        // Store offset from shape top-left corner (normalised)\u001b[39m\n\u001b[31m        _aDragOff={x:p.x-b.x,y:p.y-b.y};\u001b[39m\n\u001b[31m        _aDrawing=true;redrawAnnot();return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    _aSel=-1;redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _aDrawing=true;_aStart={x:p.x,y:p.y};if(_aTool==='free')_aPts=[{x:p.x,y:p.y}];\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aMove(e){\u001b[39m\n\u001b[31m  e.preventDefault();if(!_aDrawing)return;const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'&&_aDragMode){\u001b[39m\n\u001b[31m    const s=_aHistory[_aSel];if(!s)return;\u001b[39m\n\u001b[31m    if(_aDragMode==='move'){\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      // New top-left position\u001b[39m\n\u001b[31m      const nx=p.x-_aDragOff.x;\u001b[39m\n\u001b[31m      const ny=p.y-_aDragOff.y;\u001b[39m\n\u001b[31m      const dx=nx-b.x,dy=ny-b.y;\u001b[39m\n\u001b[31m      if(s.type==='free'){\u001b[39m\n\u001b[31m        s.pts=s.pts.map(pt=>({x:pt.x+dx,y:pt.y+dy}));\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        // Move preserving w/h sign (don't normalise — keep original drawing direction)\u001b[39m\n\u001b[31m        s.x+=dx;s.y+=dy;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Resize from corner — always work on normalised bounds then re-apply\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      const n=_aDragMode.slice(2);\u001b[39m\n\u001b[31m      let nx=b.x,ny=b.y,nw=b.w,nh=b.h;\u001b[39m\n\u001b[31m      if(n==='br'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,p.y-b.y);}\u001b[39m\n\u001b[31m      else if(n==='tl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,b.y+b.h-p.y);nx=p.x;ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='tr'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,b.y+b.h-p.y);ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='bl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,p.y-b.y);nx=p.x;}\u001b[39m\n\u001b[31m      s.x=nx;s.y=ny;s.w=nw;s.h=nh; // store as normalised going forward\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if(_aTool==='free'){_aPts.push({x:p.x,y:p.y});redrawAnnot();drawSh({type:'free',pts:[..._aPts],color:_aColor,lw:_aWidth},true);return;}\u001b[39m\n\u001b[31m  redrawAnnot();drawSh({type:_aTool,x:_aStart.x,y:_aStart.y,w:p.x-_aStart.x,h:p.y-_aStart.y,color:_aColor,lw:_aWidth},true);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction aUp(e){\u001b[39m\n\u001b[31m  if(!_aDrawing)return;_aDrawing=false;\u001b[39m\n\u001b[31m  if(_aTool==='move'){_aDragMode=null;return;}\u001b[39m\n\u001b[31m  const p=aPos(e||{touches:[{clientX:0,clientY:0}]});\u001b[39m\n\u001b[31m  if(_aTool==='free'){if(_aPts.length>2){_aHistory.push({type:'free',pts:[..._aPts],x:_aPts[0].x,y:_aPts[0].y,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  else{const w=p.x-_aStart.x,h=p.y-_aStart.y;if(Math.abs(w)>4||Math.abs(h)>4){_aHistory.push({type:_aTool,x:_aStart.x,y:_aStart.y,w,h,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  _aPts=[];redrawAnnot();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction redrawAnnot(){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.clearRect(0,0,cvs.width,cvs.height);if(_aImg)ctx.drawImage(_aImg,0,0,cvs.width,cvs.height);\u001b[39m\n\u001b[31m  _aHistory.forEach((s,i)=>{drawSh(s,false,ctx);if(_aTool==='move'&&i===_aSel)drawHandles(s,ctx);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawHandles(s,ctx){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return;const b=sBounds(s);ctx.save();\u001b[39m\n\u001b[31m  ctx.setLineDash([5,3]);ctx.strokeStyle='#facc15';ctx.lineWidth=1.5;ctx.strokeRect(b.x-2,b.y-2,b.w+4,b.h+4);ctx.setLineDash([]);\u001b[39m\n\u001b[31m  [[b.x,b.y],[b.x+b.w,b.y],[b.x,b.y+b.h],[b.x+b.w,b.y+b.h]].forEach(([x,y])=>{ctx.beginPath();ctx.arc(x,y,7,0,2*Math.PI);ctx.fillStyle='#f97316';ctx.fill();ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();});\u001b[39m\n\u001b[31m  ctx.restore();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawSh(s,preview=false,ctx){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(!ctx)ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.save();ctx.strokeStyle=s.color;ctx.lineWidth=preview?Math.max(s.lw||4,2):s.lw||4;\u001b[39m\n\u001b[31m  ctx.lineCap='round';ctx.lineJoin='round';ctx.setLineDash(preview?[6,3]:[]);\u001b[39m\n\u001b[31m  if(s.type==='rect'){ctx.strokeRect(s.x,s.y,s.w,s.h);ctx.fillStyle=s.color+'28';ctx.fillRect(s.x,s.y,s.w,s.h);}\u001b[39m\n\u001b[31m  else if(s.type==='ellipse'){const cx=s.x+s.w/2,cy=s.y+s.h/2;ctx.beginPath();ctx.ellipse(cx,cy,Math.abs(s.w/2),Math.abs(s.h/2),0,0,2*Math.PI);ctx.stroke();ctx.fillStyle=s.color+'28';ctx.fill();}\u001b[39m\n\u001b[31m  else if(s.type==='line'){ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(s.x+s.w,s.y+s.h);ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='arrow'){const ex=s.x+s.w,ey=s.y+s.h;ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(ex,ey);ctx.stroke();const a=Math.atan2(s.h,s.w),al=20,aa=0.4;ctx.setLineDash([]);ctx.beginPath();ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a-aa),ey-al*Math.sin(a-aa));ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a+aa),ey-al*Math.sin(a+aa));ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='free'){if(s.pts.length<2){ctx.restore();return;}ctx.beginPath();s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));ctx.stroke();}\u001b[39m\n\u001b[31m  ctx.setLineDash([]);ctx.restore();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction undoAnnot(){if(_aHistory.length){_aHistory.pop();_aSel=Math.min(_aSel,_aHistory.length-1);redrawAnnot();}}\u001b[39m\n\u001b[31mfunction clearAnnot(){_aHistory=[];_aSel=-1;redrawAnnot();}·\u001b[39m\n\u001b[31m// Bottom dialog\u001b[39m\n\u001b[31mlet _bdCb=null;\u001b[39m\n\u001b[31mfunction showBDialog(title,sub,onYes){\u001b[39m\n\u001b[31m  document.getElementById('bdialog-title').textContent=title;\u001b[39m\n\u001b[31m  document.getElementById('bdialog-sub').textContent=sub;\u001b[39m\n\u001b[31m  _bdCb=onYes;document.getElementById('bdialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction bdialogYes(){document.getElementById('bdialog').classList.remove('open');if(_bdCb)_bdCb();_bdCb=null;}\u001b[39m\n\u001b[31mfunction bdialogNo(){document.getElementById('bdialog').classList.remove('open');_bdCb=null;}·\u001b[39m\n\u001b[31mfunction _afterBrandingPhoto(){\u001b[39m\n\u001b[31m  const idx=_aTarget;\u001b[39m\n\u001b[31m  showBDialog(t(`Add reference photos for Branding ${idx+1}?`,`ब्रांडिंग ${idx+1} के लिए अतिरिक्त फोटो?`),t('Optional extra photos for future reference.','वैकल्पिक — भविष्य के लिए अतिरिक्त फोटो।'),()=>{showView('form-additional');setTimeout(()=>addAdditional(),200);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction skipAnnot(){document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo added (${fmtSz(brandings[_aTarget].blob.size)})`,'success');_afterBrandingPhoto();}\u001b[39m\n\u001b[31mfunction saveAnnot(){const cvs=document.getElementById('annot-cvs');cvs.toBlob(blob=>{brandings[_aTarget].blob=blob;brandings[_aTarget].prev=URL.createObjectURL(blob);document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo + markup saved (${fmtSz(blob.size)})`,'success');_afterBrandingPhoto();},'image/jpeg',0.88);}·\u001b[39m\n\u001b[31m// ── VIEW RECCE (read-only) ──────────────────────────────────\u001b[39m\n\u001b[31masync function viewRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  // Synced entries have a server-side rich report — open it directly\u001b[39m\n\u001b[31m  if(entry.viewUrl){window.open(entry.viewUrl,'_blank');return;}\u001b[39m\n\u001b[31m  // Offline / not-yet-synced fallback: generate from local base64 data\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  const ts=new Date(entry.timestamp).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'});·\u001b[39m\n\u001b[31m  async function b64ToUrl(b64){if(!b64)return'';try{const r=await fetch(b64);const bl=await r.blob();return URL.createObjectURL(bl);}catch{return'';}}·\u001b[39m\n\u001b[31m  const fvUrls=await Promise.all((d.frontPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const ivUrls=await Promise.all((d.insidePhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const brUrls=await Promise.all((d.brandings||[]).map(b=>b64ToUrl(b.photoB64)));\u001b[39m\n\u001b[31m  const adUrls=await Promise.all((d.addlPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const docUrl=await b64ToUrl(d.docB64);·\u001b[39m\n\u001b[31m  const brRows=(d.brandings||[]).map((b,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:16px;padding:12px;background:#f8fafc;border-radius:8px;border-left:3px solid #f97316\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-weight:600;font-size:14px;color:#0f172a;margin-bottom:6px\\\">${i+1}. ${b.type||'—'}: ${b.w||'?'}\\\"×${b.h||'?'}\\\" · Qty: ${b.qty||'?'} · ${b.sqft||'?'}</div>\u001b[39m\n\u001b[31m      ${brUrls[i]?`<img src=\\\"${brUrls[i]}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:6px\\\">`:'<div style=\\\"color:#94a3b8;font-size:12px\\\">No photo</div>'}\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  const html=`<!DOCTYPE html><html><head><meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m  <title>Recce — ${d.storeName||'Unknown'}</title>\u001b[39m\n\u001b[31m  <style>body{font-family:Arial,sans-serif;margin:0;padding:16px;background:#f1f5f9}\u001b[39m\n\u001b[31m  .card{background:#fff;border-radius:12px;padding:16px;margin-bottom:14px;box-shadow:0 1px 4px rgba(0,0,0,.08)}\u001b[39m\n\u001b[31m  h1{font-size:18px;color:#0f172a;margin:0 0 4px}h2{font-size:14px;color:#f97316;text-transform:uppercase;letter-spacing:.5px;margin:0 0 10px}\u001b[39m\n\u001b[31m  .meta{font-size:12px;color:#64748b;margin-bottom:12px}.photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}\u001b[39m\n\u001b[31m  img{width:100%;border-radius:8px;object-fit:cover}\u001b[39m\n\u001b[31m  .tag{display:inline-block;background:#0f172a;color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-right:4px}\u001b[39m\n\u001b[31m  @media print{body{background:#fff}.card{box-shadow:none}}</style></head><body>\u001b[39m\n\u001b[31m  <div class=\\\"card\\\">\u001b[39m\n\u001b[31m    <h1>${d.storeName||'Unknown Store'}</h1>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\"><span class=\\\"tag\\\">${d.brand||'No Brand'}</span>${d.address||''}</div>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\">📞 ${d.mobile||'—'} &nbsp;|&nbsp; 📅 ${d.date||'—'} &nbsp;|&nbsp; Submitted: ${ts}</div>\u001b[39m\n\u001b[31m    ${d.gpsCoords?`<div class=\\\"meta\\\">📍 ${d.gpsCoords.lat}, ${d.gpsCoords.lng} ±${d.gpsCoords.acc}m</div>`:''}\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${fvUrls.length?`<div class=\\\"card\\\"><h2>Front View Photos</h2><div class=\\\"photos\\\">${fvUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${ivUrls.length?`<div class=\\\"card\\\"><h2>Inside View Photos</h2><div class=\\\"photos\\\">${ivUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${d.hasVideo?`<div class=\\\"card\\\"><h2>Video</h2><div>${d.videoNote||'Video recorded'}</div></div>`:''}\u001b[39m\n\u001b[31m  ${(d.brandings||[]).length?`<div class=\\\"card\\\"><h2>Branding Items (${(d.brandings||[]).length})</h2>${brRows}</div>`:''}\u001b[39m\n\u001b[31m  ${adUrls.length?`<div class=\\\"card\\\"><h2>Additional Photos</h2><div class=\\\"photos\\\">${adUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${docUrl?`<div class=\\\"card\\\"><h2>Submission Document</h2><img src=\\\"${docUrl}\\\" style=\\\"width:100%;max-height:300px;object-fit:contain\\\"></div>`:''}\u001b[39m\n\u001b[31m  <div style=\\\"text-align:center;margin:16px 0\\\">\u001b[39m\n\u001b[31m    <button onclick=\\\"window.print()\\\" style=\\\"background:#f97316;color:#fff;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer\\\">🖨 Print / Save as PDF</button>\u001b[39m\n\u001b[31m    <button onclick=\\\"window.close()\\\" style=\\\"background:#e2e8f0;color:#475569;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer;margin-left:10px\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  </body></html>`;\u001b[39m\n\u001b[31m  const blob=new Blob([html],{type:'text/html'});\u001b[39m\n\u001b[31m  const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m  window.open(url,'_blank');\u001b[39m\n\u001b[31m  setTimeout(()=>URL.revokeObjectURL(url),30000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── EDIT OLD RECCE ───────────────────────────────────────────\u001b[39m\n\u001b[31masync function editRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=d.gpsCoords||null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  F.editingId=id;F.date=d.date||'';F.brand=d.brand||'';F.storeName=d.storeName||'';F.address=d.address||'';F.mobile=d.mobile||'';F.hasVideo=d.hasVideo;F.hasBranding=d.hasBranding;\u001b[39m\n\u001b[31m  async function b64ToBlob(b64){if(!b64)return null;try{const r=await fetch(b64);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m  toast('Loading recce data…','info');\u001b[39m\n\u001b[31m  for(const p of(d.frontPhotos||[])){const b=await b64ToBlob(p.b64);if(b)frontPhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const p of(d.insidePhotos||[])){const b=await b64ToBlob(p.b64);if(b)insidePhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const br of(d.brandings||[])){const b=await b64ToBlob(br.photoB64);brandings.push({type:br.type,w:br.w,h:br.h,qty:br.qty,blob:b,prev:b?URL.createObjectURL(b):null});}\u001b[39m\n\u001b[31m  for(const p of(d.addlPhotos||[])){const b=await b64ToBlob(p.b64);if(b)addlPhotos.push({blob:b,prev:URL.createObjectURL(b),desc:p.desc||''});}\u001b[39m\n\u001b[31m  if(d.docB64){const b=await b64ToBlob(d.docB64);if(b){submissionDoc=b;const sl=document.getElementById('doc-slot');sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${URL.createObjectURL(b)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}}\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  if(F.brand)document.getElementById('f-brand').value=F.brand;\u001b[39m\n\u001b[31m  if(F.storeName)document.getElementById('f-store').value=F.storeName;\u001b[39m\n\u001b[31m  if(F.address)document.getElementById('f-addr').value=F.address;\u001b[39m\n\u001b[31m  if(F.mobile)document.getElementById('f-mobile').value=F.mobile;\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();updAvailTag();\u001b[39m\n\u001b[31m  toast('Recce loaded — make changes and re-submit','success');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── EDIT REQUEST ────────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mlet _editReqSubId = null;·\u001b[39m\n\u001b[31mfunction _hydratePhotosFromRow(r) {\u001b[39m\n\u001b[31m  let pu={};\u001b[39m\n\u001b[31m  try{pu=typeof r.photo_urls==='string'?JSON.parse(r.photo_urls):(r.photo_urls||{});}catch(_){}\u001b[39m\n\u001b[31m  let meta={};\u001b[39m\n\u001b[31m  try{meta=typeof r.meta==='string'?JSON.parse(r.meta):(r.meta||{});}catch(_){}\u001b[39m\n\u001b[31m  frontPhotos =(pu.front   ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  insidePhotos=(pu.inside  ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  addlPhotos  =(pu.addl    ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,desc:''}));\u001b[39m\n\u001b[31m  brandings   =(meta.brandings||[]).map((b,i)=>({type:b.type,w:b.w,h:b.h,qty:b.qty,existingUrl:(pu.brandings||[])[i]||null,blob:null,prev:(pu.brandings||[])[i]||null}));\u001b[39m\n\u001b[31m  _docExistingUrl=pu.doc||null;\u001b[39m\n\u001b[31m  // Show retained doc in slot\u001b[39m\n\u001b[31m  const sl=document.getElementById('doc-slot');\u001b[39m\n\u001b[31m  if(sl&&_docExistingUrl){sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${_docExistingUrl}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openEditRequestModal(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  _editReqSubId = subId;\u001b[39m\n\u001b[31m  document.getElementById('er-store-name').textContent = r.store_name || 'Unknown';\u001b[39m\n\u001b[31m  document.getElementById('er-comment').value = '';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const assignBtn = document.getElementById('er-assign-btn');\u001b[39m\n\u001b[31m  if (r.submitted_by && r.submitted_by !== hub?.empId) {\u001b[39m\n\u001b[31m    assignBtn.textContent = `👤 Assign to ${r.submitted_by}`;\u001b[39m\n\u001b[31m    assignBtn.style.display = '';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    assignBtn.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeEditRequestModal() {\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _editReqSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorEditMyself() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  // Lock branding if client has reviewed (preserve their approval)\u001b[39m\n\u001b[31m  _brandingLocked = !!(r.client_status && r.client_status !== 'pending');\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function assignEditToCreator() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r || !r.submitted_by) { toast('No creator found for this recce', 'error'); return; }\u001b[39m\n\u001b[31m  const comment = (document.getElementById('er-comment').value || '').trim();\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        status: 'edit_requested',\u001b[39m\n\u001b[31m        edit_assigned_to: r.submitted_by,\u001b[39m\n\u001b[31m        edit_comment: comment || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!resp.ok) throw new Error('Update failed: ' + resp.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].status = 'edit_requested';\u001b[39m\n\u001b[31m      _adminRows[idx].edit_assigned_to = r.submitted_by;\u001b[39m\n\u001b[31m      _adminRows[idx].edit_comment = comment || null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Push notification to creator\u001b[39m\n\u001b[31m    const notifBody = comment || `Please review and re-submit: ${r.store_name || 'your recce'}`;\u001b[39m\n\u001b[31m    fetch('/push-server/notify', {\u001b[39m\n\u001b[31m      method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        user_id: r.submitted_by, title: '✏ Edit Requested',\u001b[39m\n\u001b[31m        body: notifBody, tag: `recce-edit-${subId}`, url: '/recce/',\u001b[39m\n\u001b[31m        icon: '/hub/icons/icon-192.png', badge: '/hub/icons/icon-192.png',\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    }).catch(() => {});\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast(`Edit assigned to ${r.submitted_by} ✓`, 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Assign failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function startCreatorEdit(subId) {\u001b[39m\n\u001b[31m  // Try local IndexedDB first (has photos)\u001b[39m\n\u001b[31m  const local = await dbGet('subs', subId);\u001b[39m\n\u001b[31m  if (local) { await editRecce(subId); return; }\u001b[39m\n\u001b[31m  // Fallback: load text fields from server row\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId)\u001b[39m\n\u001b[31m         || (await (async () => {\u001b[39m\n\u001b[31m              try {\u001b[39m\n\u001b[31m                const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, { headers: _RC_READ });\u001b[39m\n\u001b[31m                if (resp.ok) { const arr = await resp.json(); return arr[0]; }\u001b[39m\n\u001b[31m              } catch(_) {} return null;\u001b[39m\n\u001b[31m            })());\u001b[39m\n\u001b[31m  if (!r) { toast('Record not found', 'error'); return; }\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── End edit request ─────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mfunction goToHub() { window.location.href = '/hub/'; }\u001b[39m\n\u001b[31mfunction recceLogout() {\u001b[39m\n\u001b[31m  if (!confirm('Log out?')) return;\u001b[39m\n\u001b[31m  localStorage.removeItem('lm360-session');\u001b[39m\n\u001b[31m  localStorage.removeItem('360exp-session');\u001b[39m\n\u001b[31m  window.location.href = '/hub/';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction injectHubButtons() {\u001b[39m\n\u001b[31m  const u = _recceHubUser();\u001b[39m\n\u001b[31m  const name = u ? (u.name || '') : '';\u001b[39m\n\u001b[31m  if (name) {\u001b[39m\n\u001b[31m    const bar = document.getElementById('recce-hero-ubar');\u001b[39m\n\u001b[31m    const nm  = document.getElementById('recce-hero-name');\u001b[39m\n\u001b[31m    if (bar) { nm.textContent = name; bar.style.display = 'flex'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.querySelectorAll('.hdr').forEach(hdr => {\u001b[39m\n\u001b[31m    const r = document.createElement('div');\u001b[39m\n\u001b[31m    r.className = 'hdr-r';\u001b[39m\n\u001b[31m    if (name) {\u001b[39m\n\u001b[31m      const un = document.createElement('span');\u001b[39m\n\u001b[31m      un.className = 'hdr-user';\u001b[39m\n\u001b[31m      un.textContent = name;\u001b[39m\n\u001b[31m      r.appendChild(un);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    const hub = document.createElement('button');\u001b[39m\n\u001b[31m    hub.className = 'btn-hub';\u001b[39m\n\u001b[31m    hub.innerHTML = '🏡 Hub';\u001b[39m\n\u001b[31m    hub.addEventListener('click', goToHub);\u001b[39m\n\u001b[31m    r.appendChild(hub);\u001b[39m\n\u001b[31m    const lo = document.createElement('button');\u001b[39m\n\u001b[31m    lo.className = 'btn-logout';\u001b[39m\n\u001b[31m    lo.textContent = 'Logout';\u001b[39m\n\u001b[31m    lo.addEventListener('click', recceLogout);\u001b[39m\n\u001b[31m    r.appendChild(lo);\u001b[39m\n\u001b[31m    hdr.appendChild(r);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction checkAppUpdate(){\u001b[39m\n\u001b[31m  const seen=localStorage.getItem('recce-ver-seen');\u001b[39m\n\u001b[31m  localStorage.setItem('recce-ver-seen',CACHE_VER);\u001b[39m\n\u001b[31m  if(seen&&seen!==CACHE_VER){\u001b[39m\n\u001b[31m    const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m    if(b){b.classList.add('show');setTimeout(()=>b.classList.remove('show'),5000);}\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction dismissUpdateBanner(){\u001b[39m\n\u001b[31m  const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m  if(b)b.classList.remove('show');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function init(){\u001b[39m\n\u001b[31m  // Detect host banners (tiiny.host, etc) and raise bnav above them\u001b[39m\n\u001b[31m  (function detectHostBar(){\u001b[39m\n\u001b[31m    const h=window.location.hostname;\u001b[39m\n\u001b[31m    let extra=0;\u001b[39m\n\u001b[31m    if(h.includes('tiiny'))extra=58;\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // Generic detection: check if window is shorter than expected (host injected a bar)\u001b[39m\n\u001b[31m      const gap=screen.height - window.innerHeight;\u001b[39m\n\u001b[31m      if(gap>100&&gap<200)extra=58; // a fixed bar is roughly 56-60px\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if(extra>0){\u001b[39m\n\u001b[31m      document.documentElement.style.setProperty('--host-bar',extra+'px');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  })();\u001b[39m\n\u001b[31m  setLang(LANG);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m  checkAppUpdate();\u001b[39m\n\u001b[31m  await loadRecceCfg();\u001b[39m\n\u001b[31m  _checkAccessMode();\u001b[39m\n\u001b[31m  await initDB();await loadSettings();await loadHome();await checkDraft();netStatus();window.addEventListener('online',()=>{netStatus();syncNow();});window.addEventListener('offline',netStatus);injectHubButtons();document.getElementById('today-date').textContent=new Date().toLocaleDateString('en-IN',{weekday:'long',day:'numeric',month:'long',year:'numeric'});updAvailTag();\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m  // Auto-fetch stores from server on every startup (uses default Netlify URL if none saved)\u001b[39m\n\u001b[31m  const su=(await cfg('srv-url'))||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su&&navigator.onLine){\u001b[39m\n\u001b[31m    fetch(su).then(r=>r.json()).then(async j=>{\u001b[39m\n\u001b[31m      const d=Array.isArray(j)?j:j.stores||[];\u001b[39m\n\u001b[31m      if(d.length){stores=d;await cfg('stores',JSON.stringify(d));await cfg('srv-url',su);updAvailTag();\u001b[39m\n\u001b[31m        document.getElementById('srv-url').value=su;}\u001b[39m\n\u001b[31m    }).catch(()=>{});\u001b[39m\n\u001b[31m  }}init();\u001b[39m\n\u001b[31m</script>\u001b[39m\n\u001b[31m</body>\u001b[39m\n\u001b[31m</html>\u001b[39m\n\u001b[31m\"\u001b[39m\n\n  335 |     const resp = await page.request.get(BASE_URL);\n  336 |     const src = await resp.text();\n> 337 |     expect(src).toContain('recce-v15');\n      |                 ^\n  338 |     expect(src).not.toContain('recce-v14');\n  339 |   });\n  340 | });\n    at /var/www/360lm/tests/recce.spec.js:337:17"
                        }
                      ],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:48:39.638Z",
                      "annotations": [],
                      "attachments": [
                        {
                          "name": "screenshot",
                          "contentType": "image/png",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v10-dbf60-tos-SW-version-is-recce-v15-desktop-chrome/test-failed-1.png"
                        },
                        {
                          "name": "error-context",
                          "contentType": "text/markdown",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v10-dbf60-tos-SW-version-is-recce-v15-desktop-chrome/error-context.md"
                        }
                      ],
                      "errorLocation": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "column": 17,
                        "line": 337
                      }
                    },
                    {
                      "workerIndex": 7,
                      "parallelIndex": 0,
                      "status": "failed",
                      "duration": 581,
                      "error": {
                        "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoContain\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // indexOf\u001b[22m\n\nExpected substring: \u001b[32m\"recce-v15\"\u001b[39m\nReceived string:    \u001b[31m\"<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\">\u001b[39m\n\u001b[31m<head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\">\u001b[39m\n\u001b[31m<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\\\">\u001b[39m\n\u001b[31m<meta name=\\\"theme-color\\\" content=\\\"#0f172a\\\">\u001b[39m\n\u001b[31m<meta name=\\\"apple-mobile-web-app-capable\\\" content=\\\"yes\\\">\u001b[39m\n\u001b[31m<title>Branding Recce</title>\u001b[39m\n\u001b[31m<link rel=\\\"manifest\\\" href=\\\"manifest.json\\\">\u001b[39m\n\u001b[31m<link rel=\\\"preconnect\\\" href=\\\"https://fonts.googleapis.com\\\">\u001b[39m\n\u001b[31m<link href=\\\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap\\\" rel=\\\"stylesheet\\\">\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--nv:#0f172a;--nv2:#1e293b;--or:#f97316;--orl:#fed7aa;--gn:#16a34a;--rd:#dc2626;--am:#d97706;--g50:#f8fafc;--g100:#f1f5f9;--g200:#e2e8f0;--g300:#cbd5e1;--g400:#94a3b8;--g500:#64748b;--g600:#475569;--r:12px;--rs:8px;--sh:0 1px 3px rgba(0,0,0,.1),0 1px 2px rgba(0,0,0,.06);--bnav-h:72px;--host-bar:0px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}\u001b[39m\n\u001b[31mbody{font-family:'DM Sans',sans-serif;background:var(--g50);color:var(--nv);min-height:100vh;overflow-x:hidden}\u001b[39m\n\u001b[31m.hdr{background:var(--nv);color:#fff;padding:0 16px;height:56px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}\u001b[39m\n\u001b[31m.hdr-l{display:flex;align-items:center;gap:10px}\u001b[39m\n\u001b[31m.hdr-title{font-size:16px;font-weight:600}.hdr-sub{font-size:11px;color:var(--g400)}\u001b[39m\n\u001b[31m.back-btn,.icon-btn{background:none;border:none;color:#fff;padding:8px;cursor:pointer;display:flex;align-items:center}\u001b[39m\n\u001b[31m.back-btn{margin-left:-8px}\u001b[39m\n\u001b[31m.pgbar{height:3px;background:var(--g200)}.pgfill{height:100%;background:var(--or);transition:width .3s}\u001b[39m\n\u001b[31m.view{display:none;min-height:calc(100vh - 56px);padding-bottom:calc(var(--bnav-h) + var(--host-bar) + 24px)}.view.active{display:block}\u001b[39m\n\u001b[31m.content{padding:16px}\u001b[39m\n\u001b[31m.card{background:#fff;border-radius:var(--r);padding:16px;box-shadow:var(--sh);margin-bottom:12px}\u001b[39m\n\u001b[31m.card-title{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;letter-spacing:.6px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between}\u001b[39m\n\u001b[31m.cnt-badge{background:var(--or);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;min-width:22px;text-align:center}\u001b[39m\n\u001b[31m.cnt-badge.gray{background:var(--g400)}\u001b[39m\n\u001b[31m.field{margin-bottom:16px}.field:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.field label{display:block;font-size:13px;font-weight:500;color:var(--g600);margin-bottom:6px}\u001b[39m\n\u001b[31m.req{color:var(--or);margin-left:2px}\u001b[39m\n\u001b[31m.field input,.field select,.field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;color:var(--nv);background:#fff;transition:border-color .15s;-webkit-appearance:none;appearance:none}\u001b[39m\n\u001b[31m.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--or)}\u001b[39m\n\u001b[31m.field input:read-only{background:var(--g50);color:var(--g600)}\u001b[39m\n\u001b[31m.field textarea{resize:vertical;min-height:68px}\u001b[39m\n\u001b[31m.field select{background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}\u001b[39m\n\u001b[31m.pslot{border:2px dashed var(--g300);border-radius:var(--r);min-height:110px;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all .15s;position:relative;overflow:hidden;text-align:center;padding:16px}\u001b[39m\n\u001b[31m.pslot:active{border-color:var(--or);background:var(--g50)}\u001b[39m\n\u001b[31m.pslot.filled{border-style:solid;border-color:var(--or);padding:0;min-height:0}\u001b[39m\n\u001b[31m.pslot img{width:100%;height:150px;object-fit:cover;border-radius:calc(var(--r) - 2px);display:block}\u001b[39m\n\u001b[31m.pslot-lbl{font-size:13px;color:var(--g400);margin-top:6px}.pslot-ico{font-size:28px;color:var(--g300)}\u001b[39m\n\u001b[31m.pbadge{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.premove{position:absolute;top:6px;right:6px;background:var(--rd);color:#fff;border:none;border-radius:50%;width:26px;height:26px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;z-index:5}\u001b[39m\n\u001b[31minput[type=file]{display:none}\u001b[39m\n\u001b[31m.rgroup{display:flex;gap:10px}\u001b[39m\n\u001b[31m.rbtn{flex:1;padding:13px;border:1.5px solid var(--g200);border-radius:var(--rs);text-align:center;cursor:pointer;font-size:14px;font-weight:500;color:var(--g500);transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.rbtn.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.chip-grid{display:flex;flex-wrap:wrap;gap:8px}\u001b[39m\n\u001b[31m.chip{padding:7px 12px;border:1.5px solid var(--g200);border-radius:20px;font-size:13px;color:var(--g600);cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.chip.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.brand-chip{display:flex;align-items:center;gap:6px;padding:5px 12px}\u001b[39m\n\u001b[31m.brand-chip-logo{width:28px;height:18px;object-fit:contain;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{display:block;width:100%;padding:15px;background:var(--or);color:#fff;border:none;border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:700;cursor:pointer;text-align:center;transition:background .15s}\u001b[39m\n\u001b[31m.btn-p:active{background:#ea6c05}.btn-p:disabled{background:var(--g300);cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-s{display:block;width:100%;padding:14px;background:#fff;color:var(--nv);border:1.5px solid var(--g200);border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:500;cursor:pointer;text-align:center}\u001b[39m\n\u001b[31m.btn-s:active{background:var(--g100)}\u001b[39m\n\u001b[31m.btn-o{display:inline-flex;align-items:center;gap:6px;padding:10px 16px;background:#fff;color:var(--or);border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer}\u001b[39m\n\u001b[31m.btn-o:active{background:var(--orl)}\u001b[39m\n\u001b[31m.btn-d{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;background:#fff;color:var(--rd);border:1.5px solid #fecaca;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:12px;cursor:pointer}\u001b[39m\n\u001b[31m.bnav{position:fixed;bottom:var(--host-bar);left:0;right:0;background:#fff;border-top:1px solid var(--g200);display:flex;padding:10px 16px;gap:10px;z-index:100}\u001b[39m\n\u001b[31m.hero{background:var(--nv);color:#fff;padding:20px 16px 24px}\u001b[39m\n\u001b[31m.hero-title{font-size:22px;font-weight:700;margin-bottom:2px}.hero-sub{font-size:13px;color:var(--g400)}\u001b[39m\n\u001b[31m.stats{display:flex;gap:10px;margin-top:16px}\u001b[39m\n\u001b[31m.scard{flex:1;background:rgba(255,255,255,.08);border-radius:var(--rs);padding:12px;text-align:center}\u001b[39m\n\u001b[31m.snum{font-size:22px;font-weight:700}.slbl{font-size:11px;color:var(--g400);margin-top:2px}\u001b[39m\n\u001b[31m.scard.g .snum{color:#4ade80}.scard.a .snum{color:#fbbf24}\u001b[39m\n\u001b[31m.new-btn{background:var(--or);color:#fff;border:none;border-radius:var(--r);padding:16px;font-family:'DM Sans',sans-serif;font-size:16px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:10px;cursor:pointer;width:100%;margin-bottom:10px}\u001b[39m\n\u001b[31m.new-btn:active{background:#ea6c05}\u001b[39m\n\u001b[31m.resume-btn{background:var(--nv2);color:#fff;border:none;border-radius:var(--r);padding:13px 16px;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;display:flex;align-items:center;justify-content:space-between;cursor:pointer;width:100%;margin-bottom:18px}\u001b[39m\n\u001b[31m.sub-card{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:10px;display:flex;align-items:center;gap:12px}\u001b[39m\n\u001b[31m.sub-ico{width:40px;height:40px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}\u001b[39m\n\u001b[31m.sub-ico.pending{background:#fef3c7}.sub-ico.synced{background:#dcfce7}.sub-ico.failed{background:#fee2e2}\u001b[39m\n\u001b[31m.sub-meta{flex:1;min-width:0}.sub-name{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.sub-dtl{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.sbadge{font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;flex-shrink:0}\u001b[39m\n\u001b[31m.sbadge.pending{background:#fef3c7;color:#92400e}.sbadge.synced{background:#dcfce7;color:#14532d}.sbadge.failed{background:#fee2e2;color:#991b1b}\u001b[39m\n\u001b[31m.sh{display:flex;align-items:center;justify-content:space-between;margin:20px 0 12px}\u001b[39m\n\u001b[31m.st{font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.toast{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 8px);left:16px;right:16px;background:var(--nv);color:#fff;padding:12px 16px;border-radius:var(--r);font-size:14px;z-index:1000;transform:translateY(120px);opacity:0;transition:all .3s;pointer-events:none}\u001b[39m\n\u001b[31m.toast.show{transform:translateY(0);opacity:1}.toast.success{background:#16a34a}.toast.error{background:var(--rd)}.toast.info{background:var(--nv2)}\u001b[39m\n\u001b[31m.srow{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:#fff;border-top:1px solid var(--g100);font-size:12px;color:var(--g500)}\u001b[39m\n\u001b[31m.sdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px}.sdot.on{background:var(--gn)}.sdot.off{background:var(--g300)}\u001b[39m\n\u001b[31m.set-item{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:8px}\u001b[39m\n\u001b[31m.set-lbl{font-size:14px;font-weight:600;color:var(--nv);margin-bottom:4px}\u001b[39m\n\u001b[31m.set-sub{font-size:12px;color:var(--g500);margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem{background:#fff;border-radius:var(--r);border:1.5px solid var(--g200);padding:14px;margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\u001b[39m\n\u001b[31m.bitem-title{font-size:14px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.dim-row{display:flex;gap:8px}.dim-row .field{flex:1}\u001b[39m\n\u001b[31m.sqft{display:inline-block;background:var(--g100);color:var(--g600);font-size:12px;padding:4px 10px;border-radius:20px;margin-top:6px}\u001b[39m\n\u001b[31m.divider{height:1px;background:var(--g100);margin:12px 0}\u001b[39m\n\u001b[31m.rev-lbl{font-size:12px;color:var(--g500);margin-bottom:2px}\u001b[39m\n\u001b[31m.rev-val{font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.rev-photos{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}\u001b[39m\n\u001b[31m.rev-thumb{width:56px;height:56px;object-fit:cover;border-radius:var(--rs)}\u001b[39m\n\u001b[31m.empty{text-align:center;padding:40px 20px;color:var(--g400)}.empty-ico{font-size:40px;margin-bottom:12px}.empty-txt{font-size:14px}\u001b[39m\n\u001b[31m/* store picker */\u001b[39m\n\u001b[31m.store-card{border:1.5px solid var(--g200);border-radius:var(--rs);padding:13px 14px;background:#fff;position:relative;cursor:pointer}\u001b[39m\n\u001b[31m.store-card:active{background:var(--g50)}\u001b[39m\n\u001b[31m.store-card-name{font-size:15px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.store-card-meta{font-size:13px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.store-card-change{position:absolute;top:11px;right:12px;background:none;border:none;color:var(--or);font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer}\u001b[39m\n\u001b[31m.brand-tag{display:inline-block;background:var(--nv);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-top:4px}\u001b[39m\n\u001b[31m.last-chip{display:inline-flex;align-items:center;gap:4px;background:#fef3c7;color:#92400e;font-size:11px;font-weight:500;padding:3px 9px;border-radius:20px;margin-left:6px}\u001b[39m\n\u001b[31m.pick-trigger{border:2px solid var(--or);border-radius:var(--rs);padding:14px 16px;background:#fff7ed;display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-size:15px;font-weight:600;color:var(--or)}\u001b[39m\n\u001b[31m.pick-trigger:active{background:#ffedd5;border-color:#ea6800}\u001b[39m\n\u001b[31m.manual-toggle{display:flex;align-items:center;gap:8px;padding:10px 14px;border:1.5px dashed var(--g300);border-radius:var(--rs);cursor:pointer;font-size:13px;color:var(--g600);margin-top:8px;user-select:none}\u001b[39m\n\u001b[31m/* client chip grid */\u001b[39m\n\u001b[31m.cl-chip-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}\u001b[39m\n\u001b[31m.cl-chip{padding:8px 14px;border-radius:20px;border:1.5px solid var(--g200);font-size:13px;font-weight:500;color:var(--g600);background:#fff;cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.cl-chip:active,.cl-chip.sel{background:var(--or);border-color:var(--or);color:#fff;font-weight:600}\u001b[39m\n\u001b[31m.cl-chip-other{border-style:dashed}\u001b[39m\n\u001b[31m.client-tag{display:inline-block;background:#e0f2fe;color:#0369a1;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-left:4px}\u001b[39m\n\u001b[31m.manual-toggle.on{border-color:var(--or);background:#fff7ed;color:var(--or)}\u001b[39m\n\u001b[31m/* picker overlay */\u001b[39m\n\u001b[31m.povl{display:none;position:fixed;inset:0;background:var(--g50);z-index:200;flex-direction:column}\u001b[39m\n\u001b[31m.povl.open{display:flex}\u001b[39m\n\u001b[31m.povl-hdr{background:var(--nv);padding:12px 16px;display:flex;align-items:center;gap:12px;flex-shrink:0}\u001b[39m\n\u001b[31m.psearch{flex:1;padding:10px 14px;border:none;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;background:rgba(255,255,255,.12);color:#fff;outline:none}\u001b[39m\n\u001b[31m.psearch::placeholder{color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.pcancel{background:none;border:none;color:rgba(255,255,255,.7);font-family:'DM Sans',sans-serif;font-size:14px;cursor:pointer;padding:4px;white-space:nowrap}\u001b[39m\n\u001b[31m.plist{overflow-y:auto;flex:1}\u001b[39m\n\u001b[31m.pitem{padding:14px 16px;border-bottom:.5px solid var(--g100);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px}\u001b[39m\n\u001b[31m.pitem:active{background:var(--g100)}\u001b[39m\n\u001b[31m.pi-name{font-size:15px;font-weight:600;color:var(--nv)}.pi-addr{font-size:12px;color:var(--g500);margin-top:2px}.pi-last{font-size:11px;color:var(--am);margin-top:2px}\u001b[39m\n\u001b[31m.pi-brand{font-size:11px;font-weight:700;padding:3px 8px;border-radius:20px;background:var(--nv);color:#fff;flex-shrink:0}\u001b[39m\n\u001b[31m.psec{padding:8px 16px 4px;font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;background:var(--g50)}\u001b[39m\n\u001b[31m.padd{padding:16px;text-align:center;font-size:14px;color:var(--or);font-weight:600;cursor:pointer;background:#fff7ed;border-top:1.5px dashed var(--or)}\u001b[39m\n\u001b[31m.gps-row{display:flex;gap:8px;margin-top:8px}\u001b[39m\n\u001b[31m.gps-btn{flex-shrink:0;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;color:var(--g500);display:flex;align-items:center;gap:6px}\u001b[39m\n\u001b[31m.gps-btn:active{background:var(--orl);border-color:var(--or);color:var(--or)}\u001b[39m\n\u001b[31m@keyframes spin{to{transform:rotate(360deg)}}.spin{animation:spin .7s linear infinite;display:inline-block}\u001b[39m\n\u001b[31m/* ANNOTATION TOOL */\u001b[39m\n\u001b[31m.annot-modal{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column}\u001b[39m\n\u001b[31m.annot-modal.open{display:flex}\u001b[39m\n\u001b[31m.annot-bar{background:var(--nv);padding:8px 12px;flex-shrink:0}\u001b[39m\n\u001b[31m.annot-row{display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap}\u001b[39m\n\u001b[31m.annot-row:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.atool{padding:6px 10px;background:rgba(255,255,255,.1);border:1.5px solid rgba(255,255,255,.2);border-radius:var(--rs);color:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:500;cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.atool.on{background:var(--or);border-color:var(--or)}\u001b[39m\n\u001b[31m.atool.sel-on{background:#7c3aed;border-color:#7c3aed}\u001b[39m\n\u001b[31m.acolor{width:24px;height:24px;border-radius:50%;border:2px solid rgba(255,255,255,.3);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.acolor.on{border-color:#fff;border-width:3px;transform:scale(1.15)}\u001b[39m\n\u001b[31m.annot-cvs-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#111;position:relative}\u001b[39m\n\u001b[31m#annot-cvs{max-width:100%;max-height:100%;display:block;touch-action:none;cursor:crosshair}\u001b[39m\n\u001b[31m.annot-foot{background:var(--nv);padding:10px 16px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.req-note{font-size:12px;color:var(--rd);margin-top:6px;font-weight:500}\u001b[39m\n\u001b[31m/* Bottom dialog */\u001b[39m\n\u001b[31m.bdialog-wrap{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:400;align-items:flex-end}\u001b[39m\n\u001b[31m.bdialog-wrap.open{display:flex}\u001b[39m\n\u001b[31m.bdialog{background:#fff;border-radius:var(--r) var(--r) 0 0;padding:20px 16px 32px;width:100%}\u001b[39m\n\u001b[31m.bdialog-title{font-size:16px;font-weight:700;color:var(--nv);margin-bottom:6px}\u001b[39m\n\u001b[31m.bdialog-sub{font-size:13px;color:var(--g500);margin-bottom:16px}\u001b[39m\n\u001b[31m.bdialog-btns{display:flex;gap:10px}\u001b[39m\n\u001b[31m/* Edit badge on sub-card */\u001b[39m\n\u001b[31m.edit-btn-sm{padding:5px 12px;background:var(--g50);border:1px solid var(--g200);border-radius:20px;font-family:'DM Sans',sans-serif;font-size:12px;color:var(--g600);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m/* Toggle switch */\u001b[39m\n\u001b[31m.tog{width:48px;height:26px;background:var(--g300);border-radius:13px;cursor:pointer;transition:background .2s;flex-shrink:0;position:relative;display:inline-block}\u001b[39m\n\u001b[31m.tog.on{background:var(--or)}\u001b[39m\n\u001b[31m.tog-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2);pointer-events:none}\u001b[39m\n\u001b[31m.tog.on .tog-knob{transform:translateX(22px)}\u001b[39m\n\u001b[31m/* ── ADMIN RECCE VIEW ── */\u001b[39m\n\u001b[31m.af-bar{background:var(--g100);padding:10px 16px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--g200);overflow:hidden}\u001b[39m\n\u001b[31m.af-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}\u001b[39m\n\u001b[31m.af-sel{width:100%;padding:8px 10px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv);cursor:pointer;\u001b[39m\n\u001b[31m  white-space:normal;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.af-sel:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.af-inp{width:100%;padding:8px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv)}\u001b[39m\n\u001b[31m.af-inp:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.grp-hdr{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;\u001b[39m\n\u001b[31m  letter-spacing:.5px;padding:14px 0 6px;border-bottom:1px solid var(--g200);margin-bottom:6px}\u001b[39m\n\u001b[31m.grp-hdr:first-child{padding-top:0}\u001b[39m\n\u001b[31m.asc{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:12px 14px;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;gap:6px;margin-bottom:8px;cursor:pointer;\u001b[39m\n\u001b[31m  transition:box-shadow .15s}\u001b[39m\n\u001b[31m.asc:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.asc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}\u001b[39m\n\u001b[31m.asc-name{font-size:14px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.asc-brand{display:inline-block;background:#fff7ed;color:var(--or);font-size:11px;\u001b[39m\n\u001b[31m  font-weight:600;padding:2px 8px;border-radius:20px;border:1px solid #fed7aa;white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chip{background:var(--g100);border-radius:20px;padding:2px 8px;font-size:11px;color:var(--g600);white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chips{display:flex;flex-wrap:wrap;gap:5px}\u001b[39m\n\u001b[31m.asc-agent{background:var(--nv);color:#fff;font-size:11px;font-weight:600;\u001b[39m\n\u001b[31m  padding:2px 8px;border-radius:20px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m/* Admin detail modal */\u001b[39m\n\u001b[31m.ardl-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:600;\u001b[39m\n\u001b[31m  display:flex;align-items:flex-end;justify-content:center}\u001b[39m\n\u001b[31m.ardl-box{background:#fff;border-radius:var(--r) var(--r) 0 0;width:100%;max-height:80vh;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ardl-hdr{display:flex;align-items:flex-start;justify-content:space-between;\u001b[39m\n\u001b[31m  padding:16px 16px 10px;border-bottom:1px solid var(--g200);gap:10px}\u001b[39m\n\u001b[31m.ardl-title{font-size:17px;font-weight:700;color:var(--nv);line-height:1.3}\u001b[39m\n\u001b[31m.ardl-body{flex:1;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:14px}\u001b[39m\n\u001b[31m.ardl-sec{display:flex;flex-direction:column;gap:6px}\u001b[39m\n\u001b[31m.ardl-lbl{font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.ardl-val{font-size:13px;color:var(--nv);line-height:1.5}\u001b[39m\n\u001b[31m.ardl-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\u001b[39m\n\u001b[31m/* Hub home button */\u001b[39m\n\u001b[31m.btn-hub{background:none;border:1px solid rgba(255,255,255,.25);color:rgba(255,255,255,.85);\u001b[39m\n\u001b[31m  font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;cursor:pointer;\u001b[39m\n\u001b[31m  display:flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-hub:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hdr-r{display:flex;align-items:center;gap:6px;margin-left:auto;flex-shrink:0}\u001b[39m\n\u001b[31m.hdr-user{font-size:11px;color:rgba(255,255,255,.7);white-space:nowrap;max-width:80px;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.btn-logout{background:none;border:1px solid rgba(255,255,255,.2);color:rgba(255,255,255,.7);font-size:11px;font-weight:600;padding:4px 8px;border-radius:20px;cursor:pointer;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-logout:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hero-ubar{display:flex;align-items:center;justify-content:space-between;padding-top:6px;margin-top:2px}\u001b[39m\n\u001b[31m.hero-uname{font-size:12px;color:rgba(255,255,255,.65)}\u001b[39m\n\u001b[31m.hi-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .en-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .hi-txt{display:inline}\u001b[39m\n\u001b[31m.lang-btn{background:none;border:1px solid rgba(255,255,255,.3);color:rgba(255,255,255,.8);font-size:12px;font-weight:700;padding:4px 10px;border-radius:20px;cursor:pointer;display:flex;align-items:center;gap:3px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.lang-btn:active{background:rgba(255,255,255,.15)}\u001b[39m\n\u001b[31m/* ── DELETE / AUDIT ── */\u001b[39m\n\u001b[31m.del-btn{background:none;border:none;padding:6px 8px;cursor:pointer;color:var(--g400);font-size:16px;flex-shrink:0;border-radius:var(--rs);transition:color .15s,background .15s}\u001b[39m\n\u001b[31m.del-btn:active{color:var(--rd);background:#fee2e2}\u001b[39m\n\u001b[31m.asc.deleted-row{background:#fff5f5;border:1px solid #fecaca;opacity:.85}\u001b[39m\n\u001b[31m.asc.deleted-row .asc-name{text-decoration:line-through;color:var(--g500)}\u001b[39m\n\u001b[31m.del-reason-tag{display:inline-block;background:#fee2e2;color:var(--rd);font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.del-by-txt{font-size:11px;color:var(--g400);margin-top:3px}\u001b[39m\n\u001b[31m.restore-btn{background:none;border:1.5px solid #bbf7d0;border-radius:20px;color:#16a34a;font-size:11px;font-weight:700;padding:3px 10px;cursor:pointer;white-space:nowrap;margin-top:5px}\u001b[39m\n\u001b[31m.restore-btn:active{background:#dcfce7}\u001b[39m\n\u001b[31m.sup-tile{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:20px 16px;cursor:pointer;display:flex;align-items:center;gap:14px;margin-bottom:12px;transition:box-shadow .15s}\u001b[39m\n\u001b[31m.sup-tile:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.sup-tile-ico{width:48px;height:48px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:26px;flex-shrink:0}\u001b[39m\n\u001b[31m.sup-tile-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.sup-tile-title{font-size:15px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.sup-tile-sub{font-size:12px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.del-toggle-btn{padding:6px 14px;border:1.5px solid var(--g200);border-radius:20px;background:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:600;color:var(--g500);cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.del-toggle-btn.active{background:#fee2e2;border-color:#fecaca;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1.5px solid var(--g200);border-radius:var(--r);margin-bottom:10px;cursor:pointer;transition:all .15s;font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.reason-opt:active{background:var(--g50)}\u001b[39m\n\u001b[31m.reason-opt.sel{border-color:var(--rd);background:#fff5f5;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt.danger{border-color:#fdba74;background:#fff7ed;color:#9a3412}\u001b[39m\n\u001b[31m.reason-opt.danger.sel{border-color:#c2410c;background:#fff1e6;color:#9a3412}\u001b[39m\n\u001b[31m#del-confirm-btn.no-reason{background:var(--g300)!important;cursor:default}\u001b[39m\n\u001b[31m@keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}\u001b[39m\n\u001b[31m.reason-opt-ico{font-size:22px;flex-shrink:0}\u001b[39m\n\u001b[31m/* ── APP UPDATE BANNER ── */\u001b[39m\n\u001b[31m.upd-banner{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);left:12px;right:12px;background:#16a34a;color:#fff;padding:11px 14px;border-radius:var(--r);display:flex;align-items:center;justify-content:space-between;gap:10px;z-index:550;box-shadow:0 4px 16px rgba(0,0,0,.18);transform:translateY(120px);opacity:0;transition:transform .35s ease,opacity .35s ease;pointer-events:none}\u001b[39m\n\u001b[31m.upd-banner.show{transform:translateY(0);opacity:1;pointer-events:auto}\u001b[39m\n\u001b[31m/* ── EDIT REQUEST ── */\u001b[39m\n\u001b[31m.req-edit-btn{padding:4px 10px;background:#fffbeb;border:1px solid #fde68a;border-radius:20px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:600;color:#92400e;cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.req-edit-btn:active{background:#fef3c7}\u001b[39m\n\u001b[31m.edit-req-badge{display:inline-block;background:#fef3c7;color:#92400e;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;white-space:nowrap}\u001b[39m\n\u001b[31m.edit-req-card{background:#fffbeb;border:1.5px solid #fde68a;border-radius:var(--r);padding:14px 16px;margin-bottom:10px;display:flex;align-items:flex-start;gap:12px}\u001b[39m\n\u001b[31m.edit-req-card-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.edit-req-card-name{font-size:14px;font-weight:600;color:var(--nv);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.edit-req-card-meta{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.edit-req-cmt{font-size:12px;color:#78350f;background:#fff;border:1px solid #fde68a;border-radius:var(--rs);padding:8px 10px;margin-top:8px;line-height:1.5}\u001b[39m\n\u001b[31m.edit-req-section-hdr{font-size:11px;font-weight:700;color:#92400e;text-transform:uppercase;letter-spacing:.5px;padding:10px 0 6px;border-bottom:1px solid #fde68a;margin-bottom:8px}\u001b[39m\n\u001b[31m.upd-banner-ok{background:rgba(255,255,255,.2);border:none;color:#fff;border-radius:20px;padding:5px 13px;font-size:12px;font-weight:600;cursor:pointer;font-family:'DM Sans',sans-serif;white-space:nowrap}\u001b[39m\n\u001b[31m.upd-banner-ok:active{background:rgba(255,255,255,.35)}\u001b[39m\n\u001b[31m/* ── FONT SIZE WIDGET ── */\u001b[39m\n\u001b[31m.fs-widget{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);right:12px;display:flex;align-items:center;gap:0;background:#fff;border:1.5px solid var(--g200);border-radius:24px;box-shadow:0 2px 8px rgba(0,0,0,.12);z-index:500;overflow:hidden;user-select:none}\u001b[39m\n\u001b[31m.fs-btn{background:none;border:none;cursor:pointer;padding:7px 11px;color:var(--g500);line-height:1;transition:background .15s}\u001b[39m\n\u001b[31m.fs-btn:active{background:var(--g100)}\u001b[39m\n\u001b[31m.fs-btn:disabled{color:var(--g300);cursor:default}\u001b[39m\n\u001b[31m.fs-label{font-size:11px;font-weight:700;color:var(--g500);padding:0 4px;pointer-events:none}\u001b[39m\n\u001b[31m/* Level 1 — Large (+15%) */\u001b[39m\n\u001b[31mbody.fs-1 .field label,body.fs-1 .card-title,body.fs-1 .set-lbl,body.fs-1 .set-sub,\u001b[39m\n\u001b[31mbody.fs-1 .hdr-title,body.fs-1 .hdr-sub,body.fs-1 .slbl,body.fs-1 .rev-lbl,body.fs-1 .rev-val,\u001b[39m\n\u001b[31mbody.fs-1 .rbtn,body.fs-1 .chip,body.fs-1 .btn-p,body.fs-1 .btn-s,body.fs-1 .btn-o,\u001b[39m\n\u001b[31mbody.fs-1 .bdialog-title,body.fs-1 .bdialog-sub,body.fs-1 .sub-name,body.fs-1 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-1 .pslot-lbl,body.fs-1 .bitem-title,body.fs-1 .pi-name,body.fs-1 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-1 .asc-name,body.fs-1 .new-btn,body.fs-1 .resume-btn,body.fs-1 .ardl-lbl,body.fs-1 .ardl-val{font-size:calc(1em * 1.15) !important}\u001b[39m\n\u001b[31m/* Level 2 — X-Large (+30%) */\u001b[39m\n\u001b[31mbody.fs-2 .field label,body.fs-2 .card-title,body.fs-2 .set-lbl,body.fs-2 .set-sub,\u001b[39m\n\u001b[31mbody.fs-2 .hdr-title,body.fs-2 .hdr-sub,body.fs-2 .slbl,body.fs-2 .rev-lbl,body.fs-2 .rev-val,\u001b[39m\n\u001b[31mbody.fs-2 .rbtn,body.fs-2 .chip,body.fs-2 .btn-p,body.fs-2 .btn-s,body.fs-2 .btn-o,\u001b[39m\n\u001b[31mbody.fs-2 .bdialog-title,body.fs-2 .bdialog-sub,body.fs-2 .sub-name,body.fs-2 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-2 .pslot-lbl,body.fs-2 .bitem-title,body.fs-2 .pi-name,body.fs-2 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-2 .asc-name,body.fs-2 .new-btn,body.fs-2 .resume-btn,body.fs-2 .ardl-lbl,body.fs-2 .ardl-val{font-size:calc(1em * 1.30) !important}\u001b[39m\n\u001b[31m/* Level 3 — XX-Large (+50%) */\u001b[39m\n\u001b[31mbody.fs-3 .field label,body.fs-3 .card-title,body.fs-3 .set-lbl,body.fs-3 .set-sub,\u001b[39m\n\u001b[31mbody.fs-3 .hdr-title,body.fs-3 .hdr-sub,body.fs-3 .slbl,body.fs-3 .rev-lbl,body.fs-3 .rev-val,\u001b[39m\n\u001b[31mbody.fs-3 .rbtn,body.fs-3 .chip,body.fs-3 .btn-p,body.fs-3 .btn-s,body.fs-3 .btn-o,\u001b[39m\n\u001b[31mbody.fs-3 .bdialog-title,body.fs-3 .bdialog-sub,body.fs-3 .sub-name,body.fs-3 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-3 .pslot-lbl,body.fs-3 .bitem-title,body.fs-3 .pi-name,body.fs-3 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-3 .asc-name,body.fs-3 .new-btn,body.fs-3 .resume-btn,body.fs-3 .ardl-lbl,body.fs-3 .ardl-val{font-size:calc(1em * 1.50) !important}\u001b[39m\n\u001b[31m/* Level 4 — Max (+70%) */\u001b[39m\n\u001b[31mbody.fs-4 .field label,body.fs-4 .card-title,body.fs-4 .set-lbl,body.fs-4 .set-sub,\u001b[39m\n\u001b[31mbody.fs-4 .hdr-title,body.fs-4 .hdr-sub,body.fs-4 .slbl,body.fs-4 .rev-lbl,body.fs-4 .rev-val,\u001b[39m\n\u001b[31mbody.fs-4 .rbtn,body.fs-4 .chip,body.fs-4 .btn-p,body.fs-4 .btn-s,body.fs-4 .btn-o,\u001b[39m\n\u001b[31mbody.fs-4 .bdialog-title,body.fs-4 .bdialog-sub,body.fs-4 .sub-name,body.fs-4 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-4 .pslot-lbl,body.fs-4 .bitem-title,body.fs-4 .pi-name,body.fs-4 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-4 .asc-name,body.fs-4 .new-btn,body.fs-4 .resume-btn,body.fs-4 .ardl-lbl,body.fs-4 .ardl-val{font-size:calc(1em * 1.70) !important}\u001b[39m\n\u001b[31m/* ── RECCE TILE ACTION BUTTONS ── */\u001b[39m\n\u001b[31m.rpt-btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid rgba(0,0,0,.06)}\u001b[39m\n\u001b[31m.rpt-btn{display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 14px;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;border:none;font-family:inherit;transition:background .15s,opacity .15s;flex:1;min-width:110px;letter-spacing:.1px;white-space:nowrap}\u001b[39m\n\u001b[31m.rpt-btn-report{background:#fff7ed;color:var(--or);border:1.5px solid var(--or)}\u001b[39m\n\u001b[31m.rpt-btn-report:active{background:#fed7aa}\u001b[39m\n\u001b[31m.rpt-btn-pdf{background:var(--g100);color:var(--g400);border:1.5px solid var(--g200)}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready{background:var(--or);color:#fff;border-color:transparent}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready:active{background:#ea6c00}\u001b[39m\n\u001b[31m/* PDF wait overlay */\u001b[39m\n\u001b[31m#pdf-wait-ov{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m</style>\u001b[39m\n\u001b[31m</head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<!-- PICKER OVERLAY -->\u001b[39m\n\u001b[31m<div class=\\\"povl\\\" id=\\\"povl\\\">\u001b[39m\n\u001b[31m  <div class=\\\"povl-hdr\\\">\u001b[39m\n\u001b[31m    <input class=\\\"psearch\\\" id=\\\"psearch\\\" type=\\\"text\\\" placeholder=\\\"Search store / दुकान खोजें…\\\" oninput=\\\"filterPicker(this.value)\\\" autocomplete=\\\"off\\\">\u001b[39m\n\u001b[31m    <button class=\\\"pcancel\\\" onclick=\\\"closePicker()\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"plist\\\" id=\\\"plist\\\"></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"app\\\">·\u001b[39m\n\u001b[31m<!-- HOME -->\u001b[39m\n\u001b[31m<div class=\\\"view active\\\" id=\\\"view-home\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hero\\\">\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;justify-content:space-between;align-items:center\\\">\u001b[39m\n\u001b[31m      <div><div class=\\\"hero-title\\\"><span class=\\\"en-txt\\\">Branding Recce</span><span class=\\\"hi-txt\\\">ब्रांडिंग रेकी</span></div><div class=\\\"hero-sub\\\" id=\\\"today-date\\\">—</div></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:6px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"lang-btn\\\" onclick=\\\"setLang(LANG==='en'?'hi':'en')\\\" id=\\\"lang-btn\\\" title=\\\"Switch language / भाषा बदलें\\\">EN | हि</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-hub\\\" onclick=\\\"goToHub()\\\">🏡 Hub</button>\u001b[39m\n\u001b[31m      <button class=\\\"icon-btn\\\" onclick=\\\"showView('settings')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12 15a3 3 0 100-6 3 3 0 000 6z\\\"/><path d=\\\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\\\"/></svg></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"hero-ubar\\\" id=\\\"recce-hero-ubar\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <span class=\\\"hero-uname\\\" id=\\\"recce-hero-name\\\"></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-logout\\\" onclick=\\\"recceLogout()\\\">Logout</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"stats\\\">\u001b[39m\n\u001b[31m      <div class=\\\"scard g\\\"><div class=\\\"snum\\\" id=\\\"stat-synced\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Synced</span><span class=\\\"hi-txt\\\">सिंक्ड</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard a\\\"><div class=\\\"snum\\\" id=\\\"stat-pending\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Pending</span><span class=\\\"hi-txt\\\">बाकी</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard\\\"><div class=\\\"snum\\\" id=\\\"stat-total\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Total</span><span class=\\\"hi-txt\\\">कुल</span></div></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <button class=\\\"new-btn\\\" onclick=\\\"startNewRecce()\\\"><svg width=\\\"20\\\" height=\\\"20\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">New Recce</span><span class=\\\"hi-txt\\\">नई रेकी</span></button>\u001b[39m\n\u001b[31m    <div id=\\\"resume-wrap\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"sh\\\"><span class=\\\"st\\\"><span class=\\\"en-txt\\\">Recent Submissions</span><span class=\\\"hi-txt\\\">हाल की सबमिशन</span></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"syncNow()\\\" id=\\\"sync-btn\\\" style=\\\"padding:7px 12px;font-size:12px\\\"><svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg><span class=\\\"en-txt\\\">Sync</span><span class=\\\"hi-txt\\\">सिंक</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"sub-list\\\"></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"srow\\\"><div><span class=\\\"sdot\\\" id=\\\"net-dot\\\"></span><span id=\\\"net-txt\\\"><span class=\\\"en-txt\\\">Checking…</span><span class=\\\"hi-txt\\\">जाँच…</span></span></div><span id=\\\"last-sync-txt\\\" style=\\\"font-size:11px\\\"><span class=\\\"en-txt\\\">Never synced</span><span class=\\\"hi-txt\\\">कभी सिंक नहीं</span></span></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- SETTINGS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-settings\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('home')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Settings</span><span class=\\\"hi-txt\\\">सेटिंग</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Brand List</span><span class=\\\"hi-txt\\\">ब्रांड सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Manage Brands</span><span class=\\\"hi-txt\\\">ब्रांड प्रबंधन</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">These appear in the brand dropdown and store picker. Add client brands as needed.</div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-manage-list\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-add-row\\\" style=\\\"display:none;gap:8px;align-items:center\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"brand-add-inp\\\" placeholder=\\\"Type brand name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addBrandToList()\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"addBrandToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Store Lists</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Supervisors can upload XLS/CSV store lists here. Updates sync to all devices via server.</span><span class=\\\"hi-txt\\\">सुपरवाइजर यहाँ XLS/CSV स्टोर सूची अपलोड कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m      <!-- Upload/Clear row — supervisor only -->\u001b[39m\n\u001b[31m      <div id=\\\"store-upload-row\\\" style=\\\"display:none;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;margin-top:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"document.getElementById('store-xl').click()\\\"><svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Add File</span><span class=\\\"hi-txt\\\">फ़ाइल जोड़ें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-d\\\" onclick=\\\"clearStoreList()\\\" style=\\\"font-size:12px\\\"><span class=\\\"en-txt\\\">Clear All Stores</span><span class=\\\"hi-txt\\\">सभी स्टोर हटाएं</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" id=\\\"store-push-btn\\\" onclick=\\\"pushStoresToServer()\\\" style=\\\"font-size:12px;display:none\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Push to Server</span><span class=\\\"hi-txt\\\">सर्वर पर पुश करें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"store-xl\\\" accept=\\\".xlsx,.xls,.csv\\\" onchange=\\\"handleStoreUpload(event)\\\">\u001b[39m\n\u001b[31m      <div id=\\\"store-count\\\" style=\\\"font-size:13px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"store-file-list\\\" style=\\\"margin-top:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Brand assignment dialog for files with no brand column -->\u001b[39m\n\u001b[31m    <div id=\\\"brand-assign-dialog\\\" style=\\\"display:none;margin-top:10px;padding:14px;background:#fff7ed;border:1.5px solid var(--or);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\">Which brand is this store list for?</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\" id=\\\"brand-assign-fname\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-assign-chips\\\" class=\\\"chip-grid\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"confirmBrandAssign()\\\" style=\\\"flex:2;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">Assign Brand</span><span class=\\\"hi-txt\\\">ब्रांड असाइन करें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"skipBrandAssign()\\\" style=\\\"flex:1;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">No Brand</span><span class=\\\"hi-txt\\\">कोई ब्रांड नहीं</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Server Store List URL (Admin)</span><span class=\\\"hi-txt\\\">सर्वर स्टोर सूची URL</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Admin pushes stores.json to any public URL. App auto-fetches on open and caches offline.</div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"srv-url\\\" placeholder=\\\"https://yourserver.com/stores.json\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"fetchServerStores()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Fetch Now</button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"saveServerUrl()\\\" style=\\\"padding:9px 14px;font-size:13px;width:auto\\\">Save URL</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Sync Endpoint</span><span class=\\\"hi-txt\\\">सिंक एंडपॉइंट</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Slides Generator</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Managed by admin. Deploy gas_slides.gs from /opt/slides-proxy/ to Google Apps Script and paste the URL here.</div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"slides-gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Not configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"slides-gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"saveSlidesGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Sheet Sync</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Legacy sync endpoint. Writes recce data to Google Sheet.</div>·\u001b[39m\n\u001b[31m      <!-- Locked state (default) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Endpoint configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Unlocked state (after admin login) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;align-items:center;gap:8px;margin-bottom:10px;padding:7px 12px;background:#dcfce7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          <span style=\\\"font-size:12px;color:#14532d;font-weight:600\\\">🔓 Admin mode active</span>\u001b[39m\n\u001b[31m          <button onclick=\\\"lockAdmin()\\\" style=\\\"margin-left:auto;background:none;border:none;color:#14532d;font-size:12px;cursor:pointer;font-weight:600\\\">Lock ×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"testEndpoint()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Test</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>·\u001b[39m\n\u001b[31m    <!-- Admin Login Modal -->\u001b[39m\n\u001b[31m    <div id=\\\"admin-login-modal\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m      <div style=\\\"background:#fff;border-radius:var(--r);padding:24px 20px;margin:20px;max-width:380px;width:100%;box-shadow:0 8px 32px rgba(0,0,0,.2)\\\">\u001b[39m\n\u001b[31m        <div style=\\\"font-size:17px;font-weight:700;color:var(--nv);margin-bottom:4px\\\">Admin Login</div>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:18px\\\">Enter admin password to unlock settings</div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m          <label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">Password</label>\u001b[39m\n\u001b[31m          <input type=\\\"password\\\" id=\\\"admin-pwd\\\" placeholder=\\\"Enter admin password\\\" style=\\\"width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px\\\" onkeydown=\\\"if(event.key==='Enter')verifyAdmin()\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div id=\\\"admin-error\\\" style=\\\"display:none;font-size:12px;color:var(--rd);margin-bottom:12px;padding:8px 12px;background:#fee2e2;border-radius:var(--rs)\\\">Incorrect password</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"verifyAdmin()\\\" style=\\\"flex:2;padding:13px\\\" id=\\\"admin-login-btn\\\">Login</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-s\\\" onclick=\\\"closeAdminLogin()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:14px;padding-top:14px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.4px;margin-bottom:8px\\\">Admin Password Config URL</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:8px\\\">URL to your admin.json file on server (contains hashed password)</div>\u001b[39m\n\u001b[31m          <input type=\\\"url\\\" id=\\\"admin-cfg-url\\\" placeholder=\\\"https://yourserver.com/admin.json\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px;margin-bottom:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveAdminCfgUrl()\\\" style=\\\"font-size:12px;padding:7px 12px;width:100%;justify-content:center\\\">Save Config URL</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Geolocation Stamp</span><span class=\\\"hi-txt\\\">जियोलोकेशन स्टैम्प</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;justify-content:space-between;gap:16px\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1\\\">\u001b[39m\n\u001b[31m          <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Stamp on Photos</span><span class=\\\"hi-txt\\\">फोटो पर स्टैम्प</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"set-sub\\\" style=\\\"margin-bottom:0\\\">Bakes GPS coordinates, store name and timestamp into every photo — visible in the image itself. Same as GPS Map Camera app. Default: On.</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"tog on\\\" id=\\\"geo-tog\\\" onclick=\\\"toggleGeoStamp()\\\"><div class=\\\"tog-knob\\\"></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"geo-status\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\">GPS not yet captured</div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Image Quality</span><span class=\\\"hi-txt\\\">फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Default Photo Quality</span><span class=\\\"hi-txt\\\">डिफ़ॉल्ट फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Applies to all photos — front view, inside view, branding, and additional. HD uses more storage and takes longer to sync on poor networks.</div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;gap:10px;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-compressed\\\" onclick=\\\"setImgQuality('compressed')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-compressed\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-compressed\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">Full Compression</span><span class=\\\"hi-txt\\\">पूर्ण कम्प्रेशन</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~150–200 KB · Max 1280px · Best for poor network</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-left:auto;font-size:11px;font-weight:700;color:var(--gn);background:#dcfce7;padding:3px 8px;border-radius:20px\\\"><span class=\\\"en-txt\\\">Recommended</span><span class=\\\"hi-txt\\\">अनुशंसित</span></div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-hd\\\" onclick=\\\"setImgQuality('hd')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-hd\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-hd\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">HD Quality</span><span class=\\\"hi-txt\\\">HD क्वालिटी</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~400–600 KB · Max 1920px · Better detail for print</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"q-current-badge\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Supervisor Config panel — shown only to supervisors via renderSupPanel() -->\u001b[39m\n\u001b[31m    <div id=\\\"sup-panel\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">🔐 Recce Access Config</span><span class=\\\"hi-txt\\\">🔐 रेकी एक्सेस कॉन्फ़िग</span></div>\u001b[39m\n\u001b[31m      <!-- Access mode — only H/P can change -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"mode-row\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Access Mode</span><span class=\\\"hi-txt\\\">एक्सेस मोड</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Public: any Hub user can submit Recces. Assigned: only Supervisors and Creators can access.</span><span class=\\\"hi-txt\\\">सार्वजनिक: कोई भी Hub यूजर। नियत: सिर्फ़ Supervisors और Creators।</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\" style=\\\"margin-bottom:8px;margin-top:8px\\\">\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-public\\\" onclick=\\\"setRecceMode('public')\\\"><span class=\\\"en-txt\\\">Public</span><span class=\\\"hi-txt\\\">सार्वजनिक</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-assigned\\\" onclick=\\\"setRecceMode('assigned')\\\"><span class=\\\"en-txt\\\">Assigned</span><span class=\\\"hi-txt\\\">नियत</span></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Supervisor list — view all + delete + create -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Supervisors</span><span class=\\\"hi-txt\\\">सुपरवाइजर</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can view all recces, delete with reason, and submit. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">सभी रेकी देख सकते हैं, कारण से हटा सकते हैं, और सबमिट कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"sup-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addSupervisor()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addSupervisor()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Creator list — creation only -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Creators</span><span class=\\\"hi-txt\\\">क्रिएटर्स</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can submit Recces only — no admin view or deletion rights. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">केवल रेकी सबमिट कर सकते हैं — एडमिन व्यू या डिलीट नहीं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"creator-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addCreator()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addCreator()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Client list — used for client portal scoping -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clients</span><span class=\\\"hi-txt\\\">क्लाइंट</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Names that appear as chips when submitting a recce. Add the brand or agency name (e.g. \\\"Marketing Vibe\\\"). These are used to scope what clients see in the Client Portal.</span><span class=\\\"hi-txt\\\">रेकी सबमिट करते समय दिखने वाले क्लाइंट नाम। ब्रांड या एजेंसी नाम जोड़ें।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-mgmt-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"client-add-inp\\\" placeholder=\\\"Client name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addClientToList()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addClientToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Sync to server — only H/P -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"cfg-sync-btn\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Sync Config to Server</span><span class=\\\"hi-txt\\\">सर्वर पर कॉन्फ़िग सिंक करें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Apply supervisor/creator/client lists and access mode to all devices.</span><span class=\\\"hi-txt\\\">सभी डिवाइस पर कॉन्फ़िग लागू करें।</span></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"syncCfgToServer()\\\" style=\\\"max-width:220px;font-size:14px;padding:12px;margin-top:8px\\\"><span class=\\\"en-txt\\\">Sync to Server</span><span class=\\\"hi-txt\\\">सर्वर पर सिंक करें</span></button>\u001b[39m\n\u001b[31m        <div id=\\\"cfg-sync-status\\\" style=\\\"margin-top:8px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Danger Zone</span><span class=\\\"hi-txt\\\">खतरनाक ज़ोन</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\"><div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clear All Local Data</span><span class=\\\"hi-txt\\\">सभी डेटा हटाएं</span></div><div class=\\\"set-sub\\\">Removes all submissions from this device.</div><button class=\\\"btn-d\\\" onclick=\\\"clearData()\\\" style=\\\"padding:9px 14px;font-size:13px\\\">Clear All</button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: STORE INFO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-store\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"exitForm()\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Details</span><span class=\\\"hi-txt\\\">दुकान विवरण</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 1 of 5</span><span class=\\\"hi-txt\\\">चरण 1 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:20%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Recce Info</span><span class=\\\"hi-txt\\\">रेकी जानकारी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Date of Recce</span><span class=\\\"hi-txt\\\">रेकी की तारीख</span> <span class=\\\"req\\\">*</span></label><input type=\\\"date\\\" id=\\\"f-date\\\" onchange=\\\"saveDraft()\\\" max=\\\"\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" id=\\\"campaign-field\\\">\u001b[39m\n\u001b[31m        <label><span class=\\\"en-txt\\\">Job / Campaign</span><span class=\\\"hi-txt\\\">जॉब / कैंपेन</span></label>\u001b[39m\n\u001b[31m        <select id=\\\"f-campaign-id\\\" onchange=\\\"onCampaignSelect()\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">Loading campaigns…</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <div id=\\\"campaign-notify-msg\\\" style=\\\"display:none;font-size:12px;color:#92400e;margin-top:6px;padding:8px 10px;background:#fef3c7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          ⚑ <span class=\\\"en-txt\\\">Recce will submit without a job ID. A notification will flag this for your supervisor to link it later.</span><span class=\\\"hi-txt\\\">रेकी बिना जॉब ID के सबमिट होगी। सुपरवाइजर बाद में लिंक करेगा।</span>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Store</span><span class=\\\"hi-txt\\\">दुकान</span> <span id=\\\"store-avail-tag\\\" style=\\\"font-size:11px;color:var(--g400);font-weight:400;text-transform:none;letter-spacing:0\\\"></span></div>·\u001b[39m\n\u001b[31m      <!-- When store is selected -->\u001b[39m\n\u001b[31m      <div id=\\\"store-selected\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"store-card\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:start;justify-content:space-between;gap:8px\\\">\u001b[39m\n\u001b[31m            <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m              <div class=\\\"store-card-name\\\" id=\\\"sc-name\\\">—</div>\u001b[39m\n\u001b[31m              <div style=\\\"display:flex;align-items:center;gap:6px;margin-top:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m                <span class=\\\"brand-tag\\\" id=\\\"sc-brand\\\">—</span>\u001b[39m\n\u001b[31m                <span class=\\\"last-chip\\\" id=\\\"sc-last\\\" style=\\\"display:none\\\">—</span>\u001b[39m\n\u001b[31m              </div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            <button class=\\\"store-card-change\\\" onclick=\\\"openPicker()\\\"><span class=\\\"en-txt\\\">Change ›</span><span class=\\\"hi-txt\\\">बदलें ›</span></button>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <!-- All fields from Excel shown here -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-details\\\" style=\\\"margin-top:10px;display:flex;flex-direction:column;gap:4px\\\"></div>\u001b[39m\n\u001b[31m          <!-- Missing required fields — editable inline -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-missing\\\" style=\\\"display:none;margin-top:12px;padding-top:12px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m            <div style=\\\"font-size:11px;font-weight:700;color:var(--rd);text-transform:uppercase;letter-spacing:.4px;margin-bottom:10px\\\">⚠ Please complete missing fields</div>\u001b[39m\n\u001b[31m            <div id=\\\"sc-missing-fields\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <!-- Brand selector — shown when store has no brand -->\u001b[39m\n\u001b[31m        <div id=\\\"brand-selector\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\"><span class=\\\"en-txt\\\">Select Brand</span><span class=\\\"hi-txt\\\">ब्रांड चुनें</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\">This store has no brand in the list — select one:</div>\u001b[39m\n\u001b[31m          <div id=\\\"brand-chips\\\" class=\\\"chip-grid\\\"></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Picker trigger (shown when stores loaded) -->\u001b[39m\n\u001b[31m      <div id=\\\"pick-trigger-wrap\\\">\u001b[39m\n\u001b[31m        <div class=\\\"pick-trigger\\\" onclick=\\\"openPicker()\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:center;gap:10px\\\">\u001b[39m\n\u001b[31m            <span style=\\\"font-size:20px\\\">🏪</span>\u001b[39m\n\u001b[31m            <div>\u001b[39m\n\u001b[31m              <div style=\\\"font-size:15px;font-weight:700;color:var(--or)\\\"><span class=\\\"en-txt\\\">Select Store from List</span><span class=\\\"hi-txt\\\">सूची से दुकान चुनें</span></div>\u001b[39m\n\u001b[31m              <div id=\\\"store-avail-count\\\" style=\\\"font-size:12px;font-weight:400;color:var(--am);margin-top:1px\\\"><span class=\\\"en-txt\\\">Tap to browse stores</span><span class=\\\"hi-txt\\\">दुकान खोजने के लिए दबाएं</span></div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual / new store toggle -->\u001b[39m\n\u001b[31m      <div class=\\\"manual-toggle\\\" id=\\\"manual-toggle\\\" onclick=\\\"toggleManual()\\\">\u001b[39m\n\u001b[31m        <svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\" id=\\\"mt-icon\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg>\u001b[39m\n\u001b[31m        <span id=\\\"mt-label\\\"><span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span></span>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual fields -->\u001b[39m\n\u001b[31m      <div id=\\\"manual-fields\\\" style=\\\"display:none;margin-top:14px\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\" style=\\\"margin-bottom:14px\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <select id=\\\"f-brand\\\" onchange=\\\"onManualBrandChange()\\\">\u001b[39m\n\u001b[31m            <option value=\\\"\\\">Select brand</option>\u001b[39m\n\u001b[31m          </select>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span> <span class=\\\"req\\\">*</span></label><input type=\\\"text\\\" id=\\\"f-store\\\" placeholder=\\\"Enter store name\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\">\u001b[39m\n\u001b[31m          <label><span class=\\\"en-txt\\\">Store Address</span><span class=\\\"hi-txt\\\">दुकान का पता</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <textarea id=\\\"f-addr\\\" rows=\\\"2\\\" placeholder=\\\"Full address\\\" onchange=\\\"saveDraft()\\\"></textarea>\u001b[39m\n\u001b[31m          <div class=\\\"gps-row\\\">\u001b[39m\n\u001b[31m            <button class=\\\"gps-btn\\\" onclick=\\\"captureGPS()\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\"/><path d=\\\"M12 2v3M12 19v3M2 12h3M19 12h3\\\"/></svg><span class=\\\"en-txt\\\">Capture GPS</span><span class=\\\"hi-txt\\\">GPS लें</span></button>\u001b[39m\n\u001b[31m            <span id=\\\"gps-status\\\" style=\\\"font-size:12px;color:var(--g500);align-self:center\\\"></span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Mobile No.</span><span class=\\\"hi-txt\\\">मोबाइल नंबर</span></label><input type=\\\"tel\\\" id=\\\"f-mobile\\\" placeholder=\\\"10-digit number\\\" maxlength=\\\"10\\\" inputmode=\\\"numeric\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Client card -->\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Client</span><span class=\\\"hi-txt\\\">क्लाइंट</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\"><span class=\\\"en-txt\\\">Select who this recce is for. Defaults to brand — change if work came via an agency.</span><span class=\\\"hi-txt\\\">यह रेकी किसके लिए है चुनें। ब्रांड से डिफ़ॉल्ट — एजेंसी के ज़रिए हो तो बदलें।</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"cl-chip-grid\\\" id=\\\"client-chips\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"client-other-wrap\\\" style=\\\"display:none;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"f-client-other\\\" placeholder=\\\"Type client name\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" oninput=\\\"onClientOtherInput()\\\">\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-p\\\" onclick=\\\"step2()\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: PHOTOS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-photos\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-store')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Photos</span><span class=\\\"hi-txt\\\">दुकान की फोटो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 2 of 5</span><span class=\\\"hi-txt\\\">चरण 2 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:40%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Front View</span><span class=\\\"hi-txt\\\">आगे का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(min 1, max 3)</span><span class=\\\"cnt-badge gray\\\" id=\\\"front-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"front-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-front\\\" onclick=\\\"addPhoto('front')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Front Photo</span><span class=\\\"hi-txt\\\">आगे की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Inside View</span><span class=\\\"hi-txt\\\">अंदर का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 5)</span><span class=\\\"cnt-badge gray\\\" id=\\\"inside-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"inside-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-inside\\\" onclick=\\\"addPhoto('inside')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Inside Photo</span><span class=\\\"hi-txt\\\">अंदर की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-store')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step3()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: VIDEO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-video\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-photos')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Recce Video</span><span class=\\\"hi-txt\\\">रेकी वीडियो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 3 of 5</span><span class=\\\"hi-txt\\\">चरण 3 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:60%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Video</span><span class=\\\"hi-txt\\\">वीडियो</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Recce video available?</span><span class=\\\"hi-txt\\\">रेकी वीडियो है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"vid-yes\\\" onclick=\\\"setVideo(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"vid-no\\\" onclick=\\\"setVideo(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"vid-sec\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Upload Video</span><span class=\\\"hi-txt\\\">वीडियो अपलोड करें</span></label>\u001b[39m\n\u001b[31m          <div class=\\\"pslot\\\" id=\\\"vid-slot\\\" onclick=\\\"document.getElementById('vid-inp').click()\\\"><div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div></div>\u001b[39m\n\u001b[31m          <input type=\\\"file\\\" id=\\\"vid-inp\\\" accept=\\\"video/*\\\" onchange=\\\"handleVideo(event)\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Video Comments</span><span class=\\\"hi-txt\\\">वीडियो टिप्पणी</span></label><input type=\\\"text\\\" id=\\\"f-vid-cmt\\\" placeholder=\\\"Optional\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-photos')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step4()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: BRANDING -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-branding\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-video')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Branding</span><span class=\\\"hi-txt\\\">ब्रांडिंग</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 4 of 5</span><span class=\\\"hi-txt\\\">चरण 4 / 5</span></div></div></div>\u001b[39m\n\u001b[31m    <span id=\\\"br-hdr-badge\\\" style=\\\"background:rgba(255,255,255,.2);color:#fff;font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px\\\"><span class=\\\"en-txt\\\">0 items</span><span class=\\\"hi-txt\\\">0 आइटम</span></span>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:80%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Branding Space</span><span class=\\\"hi-txt\\\">ब्रांडिंग स्थान</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Space available?</span><span class=\\\"hi-txt\\\">जगह उपलब्ध है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"br-yes\\\" onclick=\\\"setBranding(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"br-no\\\" onclick=\\\"setBranding(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"branding-lock-banner\\\" style=\\\"display:none;background:#fef3c7;border:1.5px solid #f59e0b;border-radius:10px;padding:12px 14px;margin-bottom:10px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:700;color:#92400e\\\">Client approval exists — branding locked</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:#78350f;margin-top:4px\\\"><span class=\\\"en-txt\\\">The client has reviewed this recce. Create a new recce to revise branding items.</span><span class=\\\"hi-txt\\\">क्लाइंट ने रेकी की समीक्षा की है। बदलाव के लिए नई रेकी बनाएं।</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"branding-override-wrap\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m        <button onclick=\\\"unlockBrandingOverride()\\\" style=\\\"background:#f59e0b;color:#000;border:none;border-radius:8px;padding:8px 14px;font-size:12px;font-weight:700;cursor:pointer\\\">Override Edit (H&amp;P only)</button>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:11px;color:#92400e;margin-top:5px\\\">Use only when client has verbally confirmed and app needs correction.</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"br-items\\\"></div>\u001b[39m\n\u001b[31m    <div id=\\\"br-add\\\" style=\\\"display:none;margin-bottom:80px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"addBranding()\\\" style=\\\"width:100%;justify-content:center\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Another Branding Item</span><span class=\\\"hi-txt\\\">एक और ब्रांडिंग जोड़ें</span></button>\u001b[39m\n\u001b[31m      <div style=\\\"text-align:center;font-size:12px;color:var(--g400);margin-top:8px\\\"><span class=\\\"en-txt\\\">Tap Continue below when done adding items</span><span class=\\\"hi-txt\\\">सभी आइटम जोड़ने के बाद आगे दबाएं</span></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-video')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step5()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: ADDITIONAL + SUBMIT -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-additional\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-branding')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Submit</span><span class=\\\"hi-txt\\\">सबमिट</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 5 of 5</span><span class=\\\"hi-txt\\\">चरण 5 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:100%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Mandatory Document</span><span class=\\\"hi-txt\\\">अनिवार्य दस्तावेज़</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"pslot\\\" id=\\\"doc-slot\\\" onclick=\\\"document.getElementById('doc-inp').click()\\\"><div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div></div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"doc-inp\\\" accept=\\\"image/*,.pdf\\\" onchange=\\\"handleDoc(event)\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Additional Photos</span><span class=\\\"hi-txt\\\">अतिरिक्त फोटो</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 8)</span><span class=\\\"cnt-badge gray\\\" id=\\\"addl-badge\\\">0 / 8</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"add-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-addl\\\" onclick=\\\"addAdditional()\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\"><div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Review</span><span class=\\\"hi-txt\\\">समीक्षा</span></div><div id=\\\"rev-body\\\"></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-branding')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"submitRecce()\\\" id=\\\"sub-btn\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Submit Recce ✓</span><span class=\\\"hi-txt\\\">रेकी सबमिट करें ✓</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- ANNOTATION MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"annot-modal\\\" id=\\\"annot-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"annot-bar\\\">\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Draw:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"at-rect\\\"    onclick=\\\"setATool('rect')\\\">▭ Rect</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-ellipse\\\" onclick=\\\"setATool('ellipse')\\\">◯ Ellipse</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-line\\\"    onclick=\\\"setATool('line')\\\">╱ Line</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-arrow\\\"   onclick=\\\"setATool('arrow')\\\">↗ Arrow</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-free\\\"    onclick=\\\"setATool('free')\\\">✏ Free</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool sel-on\\\" id=\\\"at-move\\\" onclick=\\\"setATool('move')\\\" style=\\\"margin-left:4px\\\">⊹ Move</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Color:</span>\u001b[39m\n\u001b[31m      <div class=\\\"acolor on\\\" id=\\\"ac-or\\\" style=\\\"background:#f97316\\\" onclick=\\\"setAColor('#f97316')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-rd\\\" style=\\\"background:#ef4444\\\" onclick=\\\"setAColor('#ef4444')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-wh\\\" style=\\\"background:#ffffff\\\" onclick=\\\"setAColor('#ffffff')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-yw\\\" style=\\\"background:#facc15\\\" onclick=\\\"setAColor('#facc15')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-gn\\\" style=\\\"background:#22c55e\\\" onclick=\\\"setAColor('#22c55e')\\\"></div>\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Width:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-2\\\" onclick=\\\"setAWidth(2)\\\" style=\\\"padding:5px 8px\\\">Thin</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"aw-4\\\" onclick=\\\"setAWidth(4)\\\" style=\\\"padding:5px 8px\\\">Med</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-7\\\" onclick=\\\"setAWidth(7)\\\" style=\\\"padding:5px 8px\\\">Thick</button>\u001b[39m\n\u001b[31m      <div style=\\\"flex:1\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"undoAnnot()\\\">↩</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"clearAnnot()\\\">✕</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"annot-sel-info\\\" style=\\\"display:none;font-size:11px;color:#facc15;padding:4px 0 2px\\\">\u001b[39m\n\u001b[31m      Shape selected — drag to move · drag corners to resize · tap elsewhere to deselect\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-cvs-wrap\\\"><canvas id=\\\"annot-cvs\\\"></canvas></div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-foot\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-s\\\" onclick=\\\"skipAnnot()\\\" style=\\\"flex:1;padding:12px;font-size:14px\\\"><span class=\\\"en-txt\\\">Skip markup</span><span class=\\\"hi-txt\\\">मार्कअप छोड़ें</span></button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" onclick=\\\"saveAnnot()\\\" style=\\\"flex:2;padding:12px\\\"><span class=\\\"en-txt\\\">Done — Save ✓</span><span class=\\\"hi-txt\\\">हो गया — सेव करें ✓</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EXIT DIALOG -->\u001b[39m\n\u001b[31m<!-- MODAL: Link Job to Recce (supervisor only) -->\u001b[39m\n\u001b[31m<div id=\\\"modal-link-job\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m  <div style=\\\"background:#fff;border-radius:14px;padding:20px;width:90%;max-width:380px;display:flex;flex-direction:column;gap:12px;box-shadow:0 8px 32px rgba(0,0,0,.35)\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:15px;font-weight:700;color:#1e293b\\\">&#x1F517; Link Job to Recce</div>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-store\\\" style=\\\"font-size:13px;color:#64748b\\\"></div>\u001b[39m\n\u001b[31m    <select id=\\\"link-job-sel\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m      <option value=\\\"\\\">&#x2014; Select campaign &#x2014;</option>\u001b[39m\n\u001b[31m    </select>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-err\\\" style=\\\"font-size:12px;color:#ef4444;min-height:14px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"closeLinkJobModal()\\\" style=\\\"flex:1;padding:12px;border:1px solid #cbd5e1;border-radius:8px;cursor:pointer;background:#f8fafc;font-size:14px\\\">Cancel</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"saveLinkJob()\\\" style=\\\"flex:2;padding:12px;background:#f59e0b;color:#000;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:700\\\">&#x1F517; Link Job</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"exit-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Exit Recce?</span><span class=\\\"hi-txt\\\">रेकी से बाहर?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Your progress and photos will be saved as a draft. Resume anytime from the home screen.</span><span class=\\\"hi-txt\\\">आपकी प्रगति और फोटो ड्राफ्ट में सेव होंगी। होम स्क्रीन से कभी भी जारी रखें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"exitSaveAndLeave()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">💾 Save Draft & Exit</span><span class=\\\"hi-txt\\\">💾 ड्राफ्ट सेव करें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-d\\\" onclick=\\\"exitDiscard()\\\" style=\\\"flex:1;padding:13px;font-size:13px\\\"><span class=\\\"en-txt\\\">Discard</span><span class=\\\"hi-txt\\\">हटाएं</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"exitCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">← Continue Recce</span><span class=\\\"hi-txt\\\">← रेकी जारी रखें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- PHOTO SOURCE PICKER -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"photo-src-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Camera photos get GPS stamp baked in. Gallery photos are added without stamp.</span><span class=\\\"hi-txt\\\">कैमरा फोटो में GPS स्टैम्प लगती है। गैलरी फोटो में नहीं।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"photoSrcCamera()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">📷 Use Camera</span><span class=\\\"hi-txt\\\">📷 कैमरा</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">GPS stamp applied</span><span class=\\\"hi-txt\\\">GPS स्टैम्प लगेगी</span></span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"photoSrcGallery()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">🖼 Choose from Gallery</span><span class=\\\"hi-txt\\\">🖼 गैलरी से चुनें</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">No stamp</span><span class=\\\"hi-txt\\\">स्टैम्प नहीं</span></span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"photoSrcCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- STORE PREVIEW DIALOG -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"store-preview-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:80vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"store-preview-title\\\"><span class=\\\"en-txt\\\">Preview Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची का प्रीव्यू</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Review before adding to your store list:</span><span class=\\\"hi-txt\\\">जोड़ने से पहले जाँचें:</span></div>\u001b[39m\n\u001b[31m    <div style=\\\"overflow-x:auto;margin-bottom:14px\\\">\u001b[39m\n\u001b[31m      <table style=\\\"width:100%;border-collapse:collapse;font-size:12px\\\">\u001b[39m\n\u001b[31m        <thead><tr style=\\\"background:var(--nv);color:#fff\\\">\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Address</span><span class=\\\"hi-txt\\\">पता</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Mobile</span><span class=\\\"hi-txt\\\">मोबाइल</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span></th>\u001b[39m\n\u001b[31m        </tr></thead>\u001b[39m\n\u001b[31m        <tbody id=\\\"store-preview-body\\\"></tbody>\u001b[39m\n\u001b[31m      </table>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"confirmStorePreview()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">✓ Confirm & Add Stores</span><span class=\\\"hi-txt\\\">✓ स्टोर जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"cancelStorePreview()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BOTTOM DIALOG (branding additional photo prompt) -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"bdialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add reference photos?</span><span class=\\\"hi-txt\\\">संदर्भ फोटो जोड़ें?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Add extra photos for this branding item for future reference.</span><span class=\\\"hi-txt\\\">इस ब्रांडिंग आइटम के लिए अतिरिक्त फोटो जोड़ें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"bdialogYes()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">Yes, add photos</span><span class=\\\"hi-txt\\\">हाँ, जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"bdialogNo()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Skip</span><span class=\\\"hi-txt\\\">छोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- DELETE REASON MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"delete-reason-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"padding-bottom:28px;max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">🗑 Delete Recce</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"del-modal-sub\\\">Select reason for deletion:</div>\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-wrong\\\" onclick=\\\"selectDeleteReason('wrong')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">❌</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Wrong</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Incorrect store / submission error</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-duplicate\\\" onclick=\\\"selectDeleteReason('duplicate')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">📋</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Duplicate</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Same store submitted more than once</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt danger\\\" id=\\\"reason-test\\\" onclick=\\\"selectDeleteReason('test')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">⚠️</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Test Recce</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:#9a3412;margin-top:2px\\\">Permanently deleted — no audit trail</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p no-reason\\\" id=\\\"del-confirm-btn\\\" onclick=\\\"confirmDelete()\\\" style=\\\"flex:2;padding:13px;background:var(--rd)\\\">Delete</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"closeDeleteModal()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EDIT REQUEST MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"edit-req-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Request Edit</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"er-store-name\\\" style=\\\"font-weight:600;color:var(--nv);margin-bottom:4px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:14px\\\">Add a note for the creator (optional)</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m      <textarea id=\\\"er-comment\\\" placeholder=\\\"e.g. Please re-check store address and re-upload front photo\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;color:var(--nv);resize:vertical;min-height:80px;background:#fff\\\"></textarea>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button id=\\\"er-assign-btn\\\" class=\\\"btn-p\\\" onclick=\\\"assignEditToCreator()\\\" style=\\\"padding:14px\\\">👤 Assign to Creator</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"supervisorEditMyself()\\\" style=\\\"padding:14px\\\">✏ Edit Myself</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"closeEditRequestModal()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BRAND EDIT MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"brand-edit-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Edit Brand</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Brand Name <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"text\\\" id=\\\"be-name\\\" placeholder=\\\"e.g. PHILIPS\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:600;text-transform:uppercase\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Logo URL <span style=\\\"font-size:11px;font-weight:400;color:var(--g400)\\\">(optional)</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"url\\\" id=\\\"be-logo\\\" placeholder=\\\"https://…/logo.svg\\\" oninput=\\\"previewBrandLogo()\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px\\\">\u001b[39m\n\u001b[31m      <div id=\\\"be-logo-preview\\\" style=\\\"margin-top:8px;min-height:36px;display:flex;align-items:center;gap:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"be-cascade-info\\\" style=\\\"display:none;font-size:12px;color:var(--g500);padding:8px 12px;background:var(--g50);border-radius:var(--rs);margin-bottom:12px\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"saveBrandEdit()\\\" style=\\\"padding:14px\\\">Save</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"closeBrandEditModal()\\\" style=\\\"width:100%;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FONT SIZE WIDGET -->\u001b[39m\n\u001b[31m<div class=\\\"fs-widget\\\" id=\\\"fs-widget\\\">\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-dec\\\" onclick=\\\"changeFontSize(-1)\\\" title=\\\"Decrease font size\\\" aria-label=\\\"Decrease font size\\\">A<sup style=\\\"font-size:9px\\\">−</sup></button>\u001b[39m\n\u001b[31m  <span class=\\\"fs-label\\\" id=\\\"fs-lbl\\\">A</span>\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-inc\\\" onclick=\\\"changeFontSize(1)\\\" title=\\\"Increase font size\\\" aria-label=\\\"Increase font size\\\"><strong>A</strong><sup style=\\\"font-size:9px\\\">+</sup></button>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"upd-banner\\\" id=\\\"upd-banner\\\">\u001b[39m\n\u001b[31m  <span style=\\\"font-size:13px;font-weight:600;line-height:1.4\\\"><span class=\\\"en-txt\\\">✓ App updated to latest version</span><span class=\\\"hi-txt\\\">✓ ऐप नया संस्करण अपडेट हुआ</span></span>\u001b[39m\n\u001b[31m  <button class=\\\"upd-banner-ok\\\" onclick=\\\"dismissUpdateBanner()\\\"><span class=\\\"en-txt\\\">OK</span><span class=\\\"hi-txt\\\">ठीक है</span></button>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m<div class=\\\"toast\\\" id=\\\"toast\\\"></div>\u001b[39m\n\u001b[31m<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js\\\"></script>\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m// LANGUAGE\u001b[39m\n\u001b[31mlet LANG = localStorage.getItem('recce-lang') || 'en';\u001b[39m\n\u001b[31mfunction setLang(l) {\u001b[39m\n\u001b[31m  LANG = l;\u001b[39m\n\u001b[31m  localStorage.setItem('recce-lang', l);\u001b[39m\n\u001b[31m  document.body.classList.toggle('lang-hi', l === 'hi');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction t(en, hi) { return LANG === 'hi' ? hi : en; }·\u001b[39m\n\u001b[31m// FONT SIZE\u001b[39m\n\u001b[31mlet FS_LEVEL = parseInt(localStorage.getItem('recce-fs') || '0', 10);\u001b[39m\n\u001b[31mconst FS_LABELS = ['A', 'A+', 'A++', 'A+++', 'A++++'];\u001b[39m\n\u001b[31mfunction applyFontSize() {\u001b[39m\n\u001b[31m  document.body.classList.remove('fs-0', 'fs-1', 'fs-2');\u001b[39m\n\u001b[31m  if (FS_LEVEL > 0) document.body.classList.add('fs-' + FS_LEVEL);\u001b[39m\n\u001b[31m  const lbl = document.getElementById('fs-lbl');\u001b[39m\n\u001b[31m  if (lbl) lbl.textContent = FS_LABELS[FS_LEVEL];\u001b[39m\n\u001b[31m  const dec = document.getElementById('fs-dec');\u001b[39m\n\u001b[31m  const inc = document.getElementById('fs-inc');\u001b[39m\n\u001b[31m  if (dec) dec.disabled = FS_LEVEL === 0;\u001b[39m\n\u001b[31m  if (inc) inc.disabled = FS_LEVEL === 4;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction changeFontSize(delta) {\u001b[39m\n\u001b[31m  FS_LEVEL = Math.min(4, Math.max(0, FS_LEVEL + delta));\u001b[39m\n\u001b[31m  localStorage.setItem('recce-fs', FS_LEVEL);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Hub auth gate\u001b[39m\n\u001b[31m(function() {\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (!s || !s.loginAt || Date.now() - new Date(s.loginAt).getTime() > 12 * 3600 * 1000) {\u001b[39m\n\u001b[31m      window.location.replace('/hub/');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) { window.location.replace('/hub/'); }\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31m// STATE\u001b[39m\n\u001b[31mlet F={},frontPhotos=[],insidePhotos=[],addlPhotos=[],brandings=[];\u001b[39m\n\u001b[31mlet videoBlob=null,submissionDoc=null,_docExistingUrl=null,gpsCoords=null;\u001b[39m\n\u001b[31mlet stores=[],selectedStore=null,manualMode=false,DB;\u001b[39m\n\u001b[31mlet imgQuality='compressed'; // 'compressed' | 'hd'\u001b[39m\n\u001b[31mlet geoStampEnabled=true;    // stamp GPS+timestamp on every photo\u001b[39m\n\u001b[31mlet brands=['PHILIPS']; // editable brand list\u001b[39m\n\u001b[31mlet _brandLogos={};   // name → logo_url, loaded from DB\u001b[39m\n\u001b[31mlet _selectedClient=''; // currently selected client chip value\u001b[39m\n\u001b[31mlet _clientOtherMode=false; // true when \\\"Other\\\" chip selected\u001b[39m\n\u001b[31mconst BTYPE=['Glow Sign Board','Inshop Branding','ACP Board','One Way Vision','Fabric Board','Lollypop','Non Lit Flex','Double Side GSB','Clip on Board','Translit','Vinyl Printing','Roll up Standee','Sunboard Standee'];\u001b[39m\n\u001b[31mconst CACHE_VER='recce-v37'; // campaign dropdown + pending job link tab·\u001b[39m\n\u001b[31m// DB\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',3);r.onupgradeneeded=e=>{const d=e.target.result;['subs','cfg','draft'].forEach(s=>{if(!d.objectStoreNames.contains(s))d.createObjectStore(s,{keyPath:'k'||'id'});});if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);});}\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',4);r.onupgradeneeded=e=>{const d=e.target.result;if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);})}\u001b[39m\n\u001b[31mfunction dbGet(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).get(k);r.onsuccess=()=>res(r.result);r.onerror=()=>res(null);}catch{res(null)}})}\u001b[39m\n\u001b[31mfunction dbPut(s,v){return new Promise((res,rej)=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).put(v);r.onsuccess=()=>res();r.onerror=()=>rej();}catch(e){rej(e)}})}\u001b[39m\n\u001b[31mfunction dbAll(s){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).getAll();r.onsuccess=()=>res(r.result);r.onerror=()=>res([]);}catch{res([])}})}\u001b[39m\n\u001b[31mfunction dbDel(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).delete(k);r.onsuccess=()=>res();r.onerror=()=>res();}catch{res()}})}\u001b[39m\n\u001b[31masync function cfg(k,v){if(v===undefined){const r=await dbGet('cfg',k);return r?r.v:null;}await dbPut('cfg',{k,v});}·\u001b[39m\n\u001b[31m// COMPRESS — respects imgQuality setting\u001b[39m\n\u001b[31mfunction compress(file, maxPxOverride, qOverride){\u001b[39m\n\u001b[31m  const maxPx = maxPxOverride || (imgQuality==='hd' ? 1920 : 1280);\u001b[39m\n\u001b[31m  const q     = qOverride     || (imgQuality==='hd' ? 0.90 : 0.78);\u001b[39m\n\u001b[31m  return new Promise(res=>{const img=new Image(),url=URL.createObjectURL(file);img.onload=()=>{const sc=Math.min(1,maxPx/Math.max(img.width,img.height));const c=document.createElement('canvas');c.width=Math.round(img.width*sc);c.height=Math.round(img.height*sc);c.getContext('2d').drawImage(img,0,0,c.width,c.height);URL.revokeObjectURL(url);c.toBlob(b=>res(b),'image/jpeg',q);};img.onerror=()=>{URL.revokeObjectURL(url);res(file)};img.src=url;});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction b64(blob){return new Promise(res=>{const r=new FileReader();r.onload=()=>res(r.result);r.readAsDataURL(blob)})}\u001b[39m\n\u001b[31mfunction fmtSz(b){if(b<1024)return b+'B';if(b<1048576)return(b/1024).toFixed(0)+'KB';return(b/1048576).toFixed(1)+'MB'}·\u001b[39m\n\u001b[31m// STORE LIST\u001b[39m\n\u001b[31mlet _storeFiles=[]; // track uploaded files {name, brand, count}\u001b[39m\n\u001b[31mlet _pendingParse=null; // parsed rows waiting for brand assignment·\u001b[39m\n\u001b[31mfunction parseStoreRow(row, keyFn){\u001b[39m\n\u001b[31m  const v=k=>{\u001b[39m\n\u001b[31m    // Try exact match first, then partial\u001b[39m\n\u001b[31m    const exactKey=Object.keys(row||{}).find(hk=>hk.toLowerCase()===k);\u001b[39m\n\u001b[31m    const partKey=Object.keys(row||{}).find(hk=>hk.toLowerCase().includes(k));\u001b[39m\n\u001b[31m    const useKey=exactKey||partKey;\u001b[39m\n\u001b[31m    if(useKey)return row[useKey]!=null?row[useKey].toString().trim():'';\u001b[39m\n\u001b[31m    // CSV path: keyFn provides value directly\u001b[39m\n\u001b[31m    const col=keyFn(k);return col!=null?col.toString().trim():'';\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const name    = v('sub dealer name')||v('sub dealer')||v('dealer name')||v('store name')||v('store')||v('name');\u001b[39m\n\u001b[31m  const address = v('address')||v('addr')||v('location')||v('area');\u001b[39m\n\u001b[31m  // Contact Detail often stored as a number — toString handles it\u001b[39m\n\u001b[31m  const rawMob  = v('contact detail')||v('contact no.')||v('contact no')||v('mobile no')||v('mobile')||v('phone')||v('mob')||v('contact');\u001b[39m\n\u001b[31m  const mobile  = rawMob.replace(/\\\\D/g,'').slice(-10);\u001b[39m\n\u001b[31m  // Brand: EXACT match only — \\\"Brand\\\" or \\\"Brand Name\\\" columns\u001b[39m\n\u001b[31m  // Partial match is intentionally avoided here because \\\"Inshop Branding\\\" contains \\\"brand\\\"\u001b[39m\n\u001b[31m  const brandKey=Object.keys(row||{}).find(hk=>{\u001b[39m\n\u001b[31m    const lk=hk.toLowerCase().trim();\u001b[39m\n\u001b[31m    return lk==='brand'||lk==='brand name'||lk==='brand_name'||lk==='brandname';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const brand=brandKey?(row[brandKey]||'').toString().trim().toUpperCase():'';\u001b[39m\n\u001b[31m  const distName= v('dist name')||v('distributor name')||v('distributor')||v('dist')||v('territory')||v('tsm')||v('asm');\u001b[39m\n\u001b[31m  const city    = v('city')||v('district')||v('town');\u001b[39m\n\u001b[31m  const sales   = v('2025 full year')||v('2025')||v('full year sales')||v('fy25')||v('sales');\u001b[39m\n\u001b[31m  const proj    = v('2026 projection')||v('2026')||v('projection')||v('fy26')||v('target');\u001b[39m\n\u001b[31m  const glowSign= v('glow sign')||v('glow');\u001b[39m\n\u001b[31m  const inshop  = v('inshop branding')||v('inshop')||v('in-shop')||v('in shop');\u001b[39m\n\u001b[31m  return {name, brand, address, mobile, distName, city, sales, proj, glowSign, inshop};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction dedupeStores(list){\u001b[39m\n\u001b[31m  const seen=new Map();\u001b[39m\n\u001b[31m  list.forEach(s=>{\u001b[39m\n\u001b[31m    // Include address in key — same store name at different locations = different stores\u001b[39m\n\u001b[31m    const key=(s.name.toLowerCase().trim())+'__'+(s.brand||'').toLowerCase()\u001b[39m\n\u001b[31m              +'__'+(s.address||'').toLowerCase().trim().slice(0,30);\u001b[39m\n\u001b[31m    if(!seen.has(key))seen.set(key,s);\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // True duplicate — merge missing fields from second record\u001b[39m\n\u001b[31m      const ex=seen.get(key);\u001b[39m\n\u001b[31m      Object.keys(s).forEach(k=>{ if(!ex[k]&&s[k])ex[k]=s[k]; });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  return Array.from(seen.values());\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderStoreFileList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-file-list');if(!el)return;\u001b[39m\n\u001b[31m  if(!_storeFiles.length){el.innerHTML='';return;}\u001b[39m\n\u001b[31m  el.innerHTML=_storeFiles.map((f,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:5px;font-size:12px\\\">\u001b[39m\n\u001b[31m      <div>\u001b[39m\n\u001b[31m        <span style=\\\"font-weight:600;color:var(--nv)\\\">${f.name}</span>\u001b[39m\n\u001b[31m        <span style=\\\"color:var(--g500);margin-left:6px\\\">${f.count} stores</span>\u001b[39m\n\u001b[31m        ${f.brand?`<span style=\\\"background:var(--nv);color:#fff;font-size:10px;font-weight:700;padding:1px 7px;border-radius:20px;margin-left:5px\\\">${f.brand}</span>`:'<span style=\\\"background:var(--g300);color:var(--g600);font-size:10px;padding:1px 7px;border-radius:20px;margin-left:5px\\\">Mixed brands</span>'}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <button onclick=\\\"removeStoreFile(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:17px;cursor:pointer;padding:0 4px;line-height:1\\\">×</button>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function removeStoreFile(i){\u001b[39m\n\u001b[31m  _storeFiles.splice(i,1);\u001b[39m\n\u001b[31m  // Rebuild stores from remaining files — re-parse from cache not possible, so just reload from DB and remove this file's contribution\u001b[39m\n\u001b[31m  // Simplest approach: clear and ask user to re-upload remaining files\u001b[39m\n\u001b[31m  if(!_storeFiles.length){stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    // Can't re-parse without original files; just note it and keep current store list\u001b[39m\n\u001b[31m    toast('Removed from list. Re-upload the remaining files to refresh store list.','info');\u001b[39m\n\u001b[31m    _storeFiles.splice(0); // clear tracking since we can't reconstruct\u001b[39m\n\u001b[31m    stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderStoreFileList();\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=stores.length?`✓ ${stores.length} stores`:'No stores loaded';\u001b[39m\n\u001b[31m  updAvailTag();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function clearStoreList(){\u001b[39m\n\u001b[31m  if(!confirm('Remove all loaded stores?'))return;\u001b[39m\n\u001b[31m  stores=[];_storeFiles=[];\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent='';\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast('Store list cleared','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function handleStoreUpload(e){\u001b[39m\n\u001b[31m  const file=e.target.files[0];if(!file)return;\u001b[39m\n\u001b[31m  e.target.value=''; // allow same file re-upload\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    let data=[];\u001b[39m\n\u001b[31m    if(file.name.toLowerCase().endsWith('.csv')){\u001b[39m\n\u001b[31m      const txt=await file.text();\u001b[39m\n\u001b[31m      const rows=txt.split('\\\\n').map(r=>r.split(',').map(c=>c.trim().replace(/^\\\"|\\\"$/g,'')));\u001b[39m\n\u001b[31m      if(!rows.length||!rows[0].length){toast('Empty CSV','error');return;}\u001b[39m\n\u001b[31m      const h=rows[0];\u001b[39m\n\u001b[31m      data=rows.slice(1).filter(r=>r.length>1&&r.some(c=>c)).map(r=>{\u001b[39m\n\u001b[31m        const rowObj={};h.forEach((hk,i)=>{rowObj[hk]=r[i]||'';});\u001b[39m\n\u001b[31m        return parseStoreRow(rowObj, ()=>'');\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }else{\u001b[39m\n\u001b[31m      const ab=await file.arrayBuffer();const wb=XLSX.read(ab,{type:'array'});\u001b[39m\n\u001b[31m      const js=XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]],{defval:''});\u001b[39m\n\u001b[31m      data=js.map(row=>parseStoreRow(row,()=>''));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    data=data.filter(d=>d.name.trim());\u001b[39m\n\u001b[31m    if(!data.length){toast('No valid rows found in file','error');return;}\u001b[39m\n\u001b[31m    // Check if any store has a brand\u001b[39m\n\u001b[31m    const hasBrand=data.some(d=>d.brand);\u001b[39m\n\u001b[31m    // Always show preview first before merging\u001b[39m\n\u001b[31m    _pendingParse={file:file.name,data,hasBrand};\u001b[39m\n\u001b[31m    showStorePreview(file.name, data, hasBrand);\u001b[39m\n\u001b[31m  }catch(err){toast('Failed: '+err.message,'error')}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mlet _pendingBrand='';\u001b[39m\n\u001b[31mfunction setPendingBrand(b){\u001b[39m\n\u001b[31m  _pendingBrand=b;\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-assign-chips .chip').forEach(c=>{\u001b[39m\n\u001b[31m    c.classList.toggle('sel',c.textContent===b);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  if(!_pendingBrand){toast('Select a brand first','error');return;}\u001b[39m\n\u001b[31m  // Assign brand to all rows in this file\u001b[39m\n\u001b[31m  const data=_pendingParse.data.map(s=>({...s,brand:_pendingBrand}));\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, data, _pendingBrand);\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function skipBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, _pendingParse.data, '');\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showStorePreview(filename, data, hasBrand){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-preview-dialog');\u001b[39m\n\u001b[31m  const tbody=document.getElementById('store-preview-body');\u001b[39m\n\u001b[31m  document.getElementById('store-preview-title').textContent=`${filename} · ${data.length} ${t('stores found','स्टोर मिले')}`;\u001b[39m\n\u001b[31m  // Show first 8 rows\u001b[39m\n\u001b[31m  const sample=data.slice(0,8);\u001b[39m\n\u001b[31m  tbody.innerHTML=sample.map(s=>`<tr>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;font-weight:500\\\">${s.name||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.address||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.mobile||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px\\\"><span style=\\\"background:${s.brand?'var(--nv)':'var(--rd)'};color:#fff;padding:1px 7px;border-radius:10px;font-size:10px\\\">${s.brand||'?'}</span></td>\u001b[39m\n\u001b[31m  </tr>`).join('');\u001b[39m\n\u001b[31m  if(data.length>8)tbody.innerHTML+=`<tr><td colspan=\\\"4\\\" style=\\\"text-align:center;padding:8px;font-size:12px;color:var(--g400)\\\">…and ${data.length-8} more stores</td></tr>`;\u001b[39m\n\u001b[31m  el.classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function confirmStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  const {file,data,hasBrand}=_pendingParse;\u001b[39m\n\u001b[31m  if(!hasBrand){\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-fname').textContent=`File: ${file} · ${data.length} stores found · No brand column detected`;\u001b[39m\n\u001b[31m    const chips=document.getElementById('brand-assign-chips');\u001b[39m\n\u001b[31m    chips.innerHTML=brands.map(b=>`<div class=\\\"chip\\\" onclick=\\\"setPendingBrand('${b}')\\\" id=\\\"bac-${b}\\\">${b}</div>`).join('');\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').style.display='block';\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    await mergeStores(file, data, '');\u001b[39m\n\u001b[31m    _pendingParse=null;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction cancelStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingParse=null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function mergeStores(filename, newData, assignedBrand){\u001b[39m\n\u001b[31m  const before=stores.length;\u001b[39m\n\u001b[31m  stores=[...stores,...newData];\u001b[39m\n\u001b[31m  stores=dedupeStores(stores);\u001b[39m\n\u001b[31m  const added=stores.length-before;\u001b[39m\n\u001b[31m  const dupes=newData.length-added;\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify(stores));\u001b[39m\n\u001b[31m  // Track file\u001b[39m\n\u001b[31m  _storeFiles.push({name:filename,count:newData.length,brand:assignedBrand||''});\u001b[39m\n\u001b[31m  await cfg('store-files',JSON.stringify(_storeFiles));\u001b[39m\n\u001b[31m  const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m    `✓ ${stores.length} total stores${dupes>0?` · ${dupes} duplicate${dupes>1?'s':''} removed`:''}${noBrand?` · ${noBrand} without brand`:' · All have brand'}`;\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast(`${added} stores added${dupes>0?`, ${dupes} duplicates skipped`:''}${assignedBrand?' as '+assignedBrand:''}`, 'success');\u001b[39m\n\u001b[31m  // Show server-push button for supervisors\u001b[39m\n\u001b[31m  const pb = document.getElementById('store-push-btn');\u001b[39m\n\u001b[31m  if (pb) pb.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function fetchServerStores(){const url=document.getElementById('srv-url').value.trim();if(!url){toast('Enter a URL first','error');return;}try{toast('Fetching…','info');const r=await fetch(url);const j=await r.json();const fetched=Array.isArray(j)?j:j.stores||[];await mergeStores('Server ('+url.split('/').pop()+')',fetched,'');await cfg('srv-url',url);}catch{toast('Fetch failed — check URL','error')}}\u001b[39m\n\u001b[31masync function saveServerUrl(){await cfg('srv-url',document.getElementById('srv-url').value.trim());toast('URL saved','success')}\u001b[39m\n\u001b[31mconst DEFAULT_GAS_URL='https://script.google.com/macros/s/AKfycbwyufC7gQyu1BErCxiDlbQUn0AWiIWv7nEmjk4UcAx3dvlV6bGk7q5fQOiv82CTbokbkA/exec';·\u001b[39m\n\u001b[31mconst DEFAULT_STORES_URL='/recce/stores.json';\u001b[39m\n\u001b[31mconst _RECCE_CFG_URL='/recce/recce-cfg.json';·\u001b[39m\n\u001b[31m// Admin auto-unlock for harish/pramod via hub session\u001b[39m\n\u001b[31mconst _RECCE_ADMIN_IDS = ['harish', 'pramod', 'rakesh'];\u001b[39m\n\u001b[31mconst _RECCE_CFG_ADMINS = ['harish', 'pramod'];\u001b[39m\n\u001b[31mlet _adminRows = [];\u001b[39m\n\u001b[31mlet _myServerRows = [];\u001b[39m\n\u001b[31mlet _adminUnlocked = false;\u001b[39m\n\u001b[31mlet _recceCfg = { version: 1, supervisors: ['harish','pramod','rakesh'], mode: 'public', creators: [], allowed_users: [] };\u001b[39m\n\u001b[31mfunction _isSupervisor() {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  return !!(hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId));\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _showDeletedView = false;\u001b[39m\n\u001b[31mlet _supCreateMode = false;\u001b[39m\n\u001b[31mlet _pendingDeleteId = null;\u001b[39m\n\u001b[31mlet _pendingDeleteReason = null;\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (s?.empId && _RECCE_ADMIN_IDS.includes(s.empId)) _adminUnlocked = true;\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31masync function loadRecceCfg(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(_RECCE_CFG_URL + '?t=' + Date.now());\u001b[39m\n\u001b[31m    if (r.ok) {\u001b[39m\n\u001b[31m      const j = await r.json();\u001b[39m\n\u001b[31m      if (j && j.version) {\u001b[39m\n\u001b[31m        _recceCfg = j;\u001b[39m\n\u001b[31m        if (Array.isArray(j.supervisors) && j.supervisors.length) {\u001b[39m\n\u001b[31m          _recceCfg.supervisors = j.supervisors;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.creators)) _recceCfg.creators = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.allowed_users)) _recceCfg.allowed_users = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.clients)) _recceCfg.clients = [];\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  // Re-check admin status against server supervisor list\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId)) {\u001b[39m\n\u001b[31m    _adminUnlocked = true;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _checkAccessMode(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (_recceCfg.mode !== 'assigned') return;\u001b[39m\n\u001b[31m  const allowed = [\u001b[39m\n\u001b[31m    ...(_recceCfg.supervisors || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.creators || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.allowed_users || []),\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  if (hub?.empId && allowed.includes(hub.empId)) return;\u001b[39m\n\u001b[31m  // Block access — show locked overlay\u001b[39m\n\u001b[31m  document.body.innerHTML = `<div style=\\\"min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0f172a;color:#fff;padding:32px;text-align:center\\\"><div style=\\\"font-size:48px;margin-bottom:16px\\\">🔒</div><div style=\\\"font-size:20px;font-weight:700;margin-bottom:8px\\\">${t('Access Restricted','एक्सेस प्रतिबंधित')}</div><div style=\\\"font-size:14px;color:#94a3b8\\\">${t('You are not authorised to use Branding Recce. Please contact your supervisor.','आप ब्रांडिंग रेक्की उपयोग के लिए अधिकृत नहीं हैं।')}</div></div>`;\u001b[39m\n\u001b[31m  throw new Error('access-restricted');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _recceHubUser() {\u001b[39m\n\u001b[31m  try { return JSON.parse(localStorage.getItem('lm360-session') || '{}'); }\u001b[39m\n\u001b[31m  catch(_) { return {}; }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── Supervisor config management ────────────────────────────────────\u001b[39m\n\u001b[31mfunction renderSupPanel(){\u001b[39m\n\u001b[31m  if (!_adminUnlocked) return;\u001b[39m\n\u001b[31m  const panel = document.getElementById('sup-panel');\u001b[39m\n\u001b[31m  if (panel) panel.style.display = 'block';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const modePublic = document.getElementById('mode-public');\u001b[39m\n\u001b[31m  const modeAssigned = document.getElementById('mode-assigned');\u001b[39m\n\u001b[31m  if (modePublic && modeAssigned) {\u001b[39m\n\u001b[31m    modePublic.classList.toggle('sel', _recceCfg.mode !== 'assigned');\u001b[39m\n\u001b[31m    modeAssigned.classList.toggle('sel', _recceCfg.mode === 'assigned');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  const addRow = document.getElementById('sup-add-row');\u001b[39m\n\u001b[31m  if (addRow) addRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const creatorAddRow = document.getElementById('creator-add-row');\u001b[39m\n\u001b[31m  if (creatorAddRow) creatorAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const clientAddRow = document.getElementById('client-add-row');\u001b[39m\n\u001b[31m  if (clientAddRow) clientAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const modeRow = document.getElementById('mode-row');\u001b[39m\n\u001b[31m  if (modeRow) {\u001b[39m\n\u001b[31m    modeRow.style.display = 'block';\u001b[39m\n\u001b[31m    // Non-cfg-admins see mode as read-only (toggles exist but setRecceMode guards them)\u001b[39m\n\u001b[31m    modeRow.style.opacity = isCfgAdmin ? '1' : '0.65';\u001b[39m\n\u001b[31m    modeRow.style.pointerEvents = isCfgAdmin ? '' : 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const syncBtn = document.getElementById('cfg-sync-btn');\u001b[39m\n\u001b[31m  if (syncBtn) syncBtn.style.display = isCfgAdmin ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('sup-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const sups = _recceCfg.supervisors || [];\u001b[39m\n\u001b[31m  el.innerHTML = sups.map((s,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${s}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin && sups.length > 1 ? `<button onclick=\\\"removeSupervisor(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderCreatorsList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('creator-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const creators = _recceCfg.creators || [];\u001b[39m\n\u001b[31m  el.innerHTML = creators.length ? creators.map((u,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${u}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeCreator(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No creators yet — any Hub user can submit in Public mode.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setRecceMode(mode){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.mode = mode;\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addSupervisor(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('sup-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.supervisors = [...(_recceCfg.supervisors || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeSupervisor(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.supervisors = (_recceCfg.supervisors || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addCreator(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('creator-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.creators || []).includes(val)) { toast(t('Already a creator','पहले से क्रिएटर है'), 'info'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor (includes creation rights)','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.creators = [...(_recceCfg.creators || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeCreator(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.creators = (_recceCfg.creators || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderClientMgmtList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('client-mgmt-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const list = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  el.innerHTML = list.length ? list.map((c,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${esc(c)}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeClientFromList(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No clients yet — add client or agency names to show them as chips in the form.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addClientToList(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('client-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter client name','क्लाइंट नाम दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.clients || []).includes(val)) { toast(t('Already in list','पहले से मौजूद है'), 'info'); return; }\u001b[39m\n\u001b[31m  if (!_recceCfg.clients) _recceCfg.clients = [];\u001b[39m\n\u001b[31m  _recceCfg.clients.push(val);\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeClientFromList(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.clients = (_recceCfg.clients || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncCfgToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast(t('Not authorised','अधिकृत नहीं'), 'error'); return; }\u001b[39m\n\u001b[31m  const st = document.getElementById('cfg-sync-status');\u001b[39m\n\u001b[31m  if (st) st.textContent = t('Syncing…','सिंक हो रहा है…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-cfg', empId: hub.empId, cfg: {\u001b[39m\n\u001b[31m        version: _recceCfg.version || 1,\u001b[39m\n\u001b[31m        supervisors: _recceCfg.supervisors || [],\u001b[39m\n\u001b[31m        mode: _recceCfg.mode || 'public',\u001b[39m\n\u001b[31m        creators: _recceCfg.creators || [],\u001b[39m\n\u001b[31m        allowed_users: _recceCfg.allowed_users || [],\u001b[39m\n\u001b[31m        clients: _recceCfg.clients || [],\u001b[39m\n\u001b[31m      }})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) {\u001b[39m\n\u001b[31m      toast(t('Config synced to server ✓','कॉन्फ़िग सर्वर पर सेव हुआ ✓'), 'success');\u001b[39m\n\u001b[31m      if (st) st.textContent = t('Last synced: just now','अभी सिंक हुआ');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast(j.error || t('Sync failed','सिंक विफल'), 'error');\u001b[39m\n\u001b[31m      if (st) st.textContent = j.error || '';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Network error','नेटवर्क त्रुटि'), 'error');\u001b[39m\n\u001b[31m    if (st) st.textContent = e.message;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function pushStoresToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!hub?.empId || !_adminUnlocked) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-stores', empId: hub.empId, stores })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) toast(`${t('Pushed to server','सर्वर पर पुश हुआ')} · ${j.count} ${t('stores','स्टोर')}`, 'success');\u001b[39m\n\u001b[31m    else toast(j.error || t('Server push failed','सर्वर पुश विफल'), 'error');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Could not reach server','सर्वर से संपर्क नहीं हो सका'), 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── End supervisor config management ────────────────────────────────·\u001b[39m\n\u001b[31m// PostgREST sync constants\u001b[39m\n\u001b[31mconst _RC_BASE      = '/db';\u001b[39m\n\u001b[31mconst _RC_READ      = { 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_WRITE     = { 'Content-Type': 'application/json', 'Content-Profile': 'recce', 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_UPSERT    = { ..._RC_WRITE, 'Prefer': 'resolution=merge-duplicates,return=minimal' };\u001b[39m\n\u001b[31mconst _INSTALL_RD   = { 'Content-Type': 'application/json', 'Accept-Profile': 'installation' };\u001b[39m\n\u001b[31mconst _INSTALL_WR   = { 'Content-Type': 'application/json', 'Content-Profile': 'installation', 'Accept-Profile': 'installation', 'Prefer': 'return=minimal' };·\u001b[39m\n\u001b[31m// ── Campaign selection state ──\u001b[39m\n\u001b[31mlet _selectedCampaignId = null;\u001b[39m\n\u001b[31mlet _notifySupervisor   = false;\u001b[39m\n\u001b[31mlet _campaignList       = [];\u001b[39m\n\u001b[31mlet _pendingJobFilter   = false;\u001b[39m\n\u001b[31mlet _linkJobSubId       = null;\u001b[39m\n\u001b[31mlet _brandingLocked     = false;·\u001b[39m\n\u001b[31mfunction _updateBrandingLock() {\u001b[39m\n\u001b[31m  const hub  = _recceHubUser();\u001b[39m\n\u001b[31m  const isHP = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const banner   = document.getElementById('branding-lock-banner');\u001b[39m\n\u001b[31m  const ovWrap   = document.getElementById('branding-override-wrap');\u001b[39m\n\u001b[31m  const brItems  = document.getElementById('br-items');\u001b[39m\n\u001b[31m  const brAdd    = document.getElementById('br-add');\u001b[39m\n\u001b[31m  const brYes    = document.getElementById('br-yes');\u001b[39m\n\u001b[31m  const brNo     = document.getElementById('br-no');\u001b[39m\n\u001b[31m  if (!banner) return;\u001b[39m\n\u001b[31m  if (_brandingLocked) {\u001b[39m\n\u001b[31m    banner.style.display   = '';\u001b[39m\n\u001b[31m    if (ovWrap)  ovWrap.style.display  = isHP ? '' : 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.pointerEvents = 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.opacity = '0.55';\u001b[39m\n\u001b[31m    if (brAdd)   brAdd.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='none'; brYes.style.opacity='0.5'; }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='none';  brNo.style.opacity='0.5';  }\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    banner.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brItems) { brItems.style.pointerEvents=''; brItems.style.opacity=''; }\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='';  brYes.style.opacity='';   }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='';   brNo.style.opacity='';    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction unlockBrandingOverride() {\u001b[39m\n\u001b[31m  if (!confirm(\u001b[39m\n\u001b[31m    'Client has already reviewed this recce.\\\\n' +\u001b[39m\n\u001b[31m    'Editing brandings will NOT remove their approval.\\\\n' +\u001b[39m\n\u001b[31m    'Continue ONLY if the client has verbally confirmed. Proceed?'\u001b[39m\n\u001b[31m  )) return;\u001b[39m\n\u001b[31m  _brandingLocked = false;\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  renderBrandings();\u001b[39m\n\u001b[31m  toast(t('Branding unlocked for this session', 'ब्रांडिंग इस सत्र के लिए अनलॉक'), 'info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadCampaignsForForm() {\u001b[39m\n\u001b[31m  const sel = document.getElementById('f-campaign-id');\u001b[39m\n\u001b[31m  if (!sel) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m    _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m  } catch(_) { _campaignList = []; }\u001b[39m\n\u001b[31m  sel.innerHTML =\u001b[39m\n\u001b[31m    '<option value=\\\"\\\">— Select job / campaign (optional) —</option>' +\u001b[39m\n\u001b[31m    _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('') +\u001b[39m\n\u001b[31m    '<option value=\\\"__NOTIFY__\\\">⚑ No campaign yet — notify supervisor</option>';\u001b[39m\n\u001b[31m  if (_selectedCampaignId) sel.value = _selectedCampaignId;\u001b[39m\n\u001b[31m  else if (_notifySupervisor) sel.value = '__NOTIFY__';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onCampaignSelect() {\u001b[39m\n\u001b[31m  const val = document.getElementById('f-campaign-id')?.value || '';\u001b[39m\n\u001b[31m  const noticeEl = document.getElementById('campaign-notify-msg');\u001b[39m\n\u001b[31m  if (val === '__NOTIFY__') {\u001b[39m\n\u001b[31m    _selectedCampaignId = null;\u001b[39m\n\u001b[31m    _notifySupervisor   = true;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'block';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    _selectedCampaignId = val || null;\u001b[39m\n\u001b[31m    _notifySupervisor   = false;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction generateRecceReportHtml(entry, photoUrls) {\u001b[39m\n\u001b[31m  const d    = entry.data || {};\u001b[39m\n\u001b[31m  const urls = photoUrls || {};\u001b[39m\n\u001b[31m  const agent = entry.submittedByName || entry.submittedBy || 'Field Agent';\u001b[39m\n\u001b[31m  const _safeId      = (entry.id||'').replace(/\\\\//g,'_').replace(/\\\\.\\\\./g,'');\u001b[39m\n\u001b[31m  const serverPdfUrl = _safeId ? `https://srv1111289.hstgr.cloud/screenshots/recce/views/${_safeId}.pdf` : '';\u001b[39m\n\u001b[31m  const brandLogoUrl = d.brandLogoUrl || _brandLogos[d.brand] || '';\u001b[39m\n\u001b[31m  const tsStr = new Date(entry.timestamp).toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric',hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\u001b[39m\n\u001b[31m  const gpsUrl = d.gpsCoords ? `https://maps.google.com/?q=${d.gpsCoords.lat},${d.gpsCoords.lng}` : null;·\u001b[39m\n\u001b[31m  const frontCount  = (urls.front||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const insideCount = (urls.inside||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const addlCount   = (urls.addl||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const brCount     = (d.brandings||[]).length;·\u001b[39m\n\u001b[31m  // pages: { id, url, bandHtml, cmt, dotLabel, dotColor }\u001b[39m\n\u001b[31m  const pages = [];·\u001b[39m\n\u001b[31m  (urls.front||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Front View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${frontCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.frontPhotos||[])[i]?.cmt||'', dotLabel:`FV${i+1}`, dotColor:'#3b82f6', catLabel:'Front View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.inside||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Inside View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${insideCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.insidePhotos||[])[i]?.cmt||'', dotLabel:`IV${i+1}`, dotColor:'#14b8a6', catLabel:'Inside View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (d.brandings||[]).forEach((b,i)=>{\u001b[39m\n\u001b[31m    const url=(urls.brandings||[])[i]; if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">${esc(b.type||'Branding')}</div><div class=\\\"ph-dims\\\">Width : ${esc(b.w||'?')}&Prime;&nbsp;&times;&nbsp;Height : ${esc(b.h||'?')}&Prime;&nbsp;&mdash;&nbsp;${esc(b.qty||1)} Nos</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${brCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:'', dotLabel:`B${i+1}`, dotColor:'#f97316', catLabel:b.type||'Branding',\u001b[39m\n\u001b[31m      tileDims:`${b.w||'?'}″×${b.h||'?'}″ — ${String(b.qty||1).padStart(2,'0')} Nos` });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.addl||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Additional</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${addlCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.addlPhotos||[])[i]?.desc||'', dotLabel:`A${i+1}`, dotColor:'#94a3b8', catLabel:'Additional', tileDims:'' });\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const sideItems = [\u001b[39m\n\u001b[31m    `<div class=\\\"si-item active\\\" data-tgt=\\\"pg-cover\\\" title=\\\"Cover\\\"><div class=\\\"si-dot\\\" style=\\\"background:#475569\\\">CV</div></div>`\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  pages.forEach(p => {\u001b[39m\n\u001b[31m    sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"${p.id}\\\" title=\\\"${p.dotLabel}\\\"><div class=\\\"si-dot\\\" style=\\\"background:${p.dotColor}\\\">${p.dotLabel}</div></div>`);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(d.hasVideo) sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-vid\\\" title=\\\"Video\\\"><div class=\\\"si-dot\\\" style=\\\"background:#a855f7\\\">VD</div></div>`);\u001b[39m\n\u001b[31m  if(urls.doc)   sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-doc\\\" title=\\\"Document\\\"><div class=\\\"si-dot\\\" style=\\\"background:#64748b\\\">DC</div></div>`);·\u001b[39m\n\u001b[31m  const thumbItems = [\u001b[39m\n\u001b[31m    ...pages,\u001b[39m\n\u001b[31m    ...(d.hasVideo?[{id:'pg-vid',url:null,catLabel:'Video',tileDims:'',dotLabel:'VD',dotColor:'#a855f7'}]:[]),\u001b[39m\n\u001b[31m    ...(urls.doc?[{id:'pg-doc',url:urls.doc,catLabel:'Document',tileDims:'',dotLabel:'DC',dotColor:'#64748b'}]:[])\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  const thumbsHtml = thumbItems.map(p=>`<div class=\\\"cov-thumb\\\" onclick=\\\"document.getElementById('${p.id}').scrollIntoView({behavior:'smooth'})\\\">${p.url?`<img src=\\\"${p.url}\\\" alt=\\\"\\\">`:(`<div class=\\\"cov-thumb-vid\\\">${p.catLabel==='Video'?'&#x25B6;&#xFE0F;':'&#x1F4C4;'}</div>`)}<div class=\\\"cov-thumb-ov\\\" style=\\\"border-top:3px solid ${p.dotColor}\\\"><div class=\\\"cov-thumb-cat\\\">${esc(p.catLabel)}</div>${p.tileDims?`<div class=\\\"cov-thumb-dims\\\">${esc(p.tileDims)}</div>`:''}<div class=\\\"cov-thumb-no\\\">${p.dotLabel}</div></div></div>`).join('');·\u001b[39m\n\u001b[31m  const pagesHtml = pages.map(p => `\u001b[39m\n\u001b[31m<div class=\\\"photo-page\\\" id=\\\"${p.id}\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\">${p.bandHtml}</div>\u001b[39m\n\u001b[31m  <div class=\\\"ph-img\\\"><a href=\\\"${p.url}\\\" target=\\\"_blank\\\"><img src=\\\"${p.url}\\\" loading=\\\"lazy\\\" alt=\\\"\\\"></a>${p.cmt?`<div class=\\\"ph-cmt\\\">${esc(p.cmt)}</div>`:''}</div>\u001b[39m\n\u001b[31m</div>`).join('');·\u001b[39m\n\u001b[31m  return `<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\"><head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m<title>Recce — ${esc(d.storeName||'Unknown')} · ${esc(d.brand||'')}</title>\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--dk:#0f172a;--nv2:#1a2f52;--or:#f97316;--g200:#e2e8f0;--g400:#94a3b8;--g600:#475569;--si:54px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0}\u001b[39m\n\u001b[31mhtml,body{height:100%;overflow:hidden}\u001b[39m\n\u001b[31mbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#111;color:var(--dk);display:flex}\u001b[39m\n\u001b[31ma{color:var(--or);text-decoration:none}\u001b[39m\n\u001b[31mimg{display:block}·\u001b[39m\n\u001b[31m/* ── Side index ── */\u001b[39m\n\u001b[31m.side-idx{width:var(--si);flex-shrink:0;background:var(--dk);overflow-y:auto;display:flex;flex-direction:column;align-items:center;padding:4px 0;scrollbar-width:none;z-index:50}\u001b[39m\n\u001b[31m.side-idx::-webkit-scrollbar{display:none}\u001b[39m\n\u001b[31m.si-item{width:100%;min-height:56px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s}\u001b[39m\n\u001b[31m.si-item:hover{background:rgba(255,255,255,.07)}\u001b[39m\n\u001b[31m.si-dot{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff;opacity:.4;transition:opacity .18s,transform .18s;line-height:1;text-align:center}\u001b[39m\n\u001b[31m.si-item.active .si-dot{opacity:1;transform:scale(1.15)}·\u001b[39m\n\u001b[31m/* ── Main scroll area ── */\u001b[39m\n\u001b[31m.main{flex:1;overflow-y:scroll;scroll-snap-type:y mandatory;scroll-behavior:smooth;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar{width:3px}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15)}·\u001b[39m\n\u001b[31m/* ── Cover ── */\u001b[39m\n\u001b[31m.cover{height:100vh;scroll-snap-align:start;flex-shrink:0;background:linear-gradient(135deg,#0f172a 0%,var(--nv2) 100%);color:#fff;display:flex;flex-direction:column;padding:24px 20px 20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.cover-badge{display:inline-flex;align-items:center;gap:5px;background:var(--or);color:#fff;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:1px;padding:3px 12px;border-radius:20px;margin-bottom:12px;align-self:flex-start}\u001b[39m\n\u001b[31m.cover h1{font-size:20px;font-weight:700;line-height:1.3;margin-bottom:4px}\u001b[39m\n\u001b[31m.cover-addr{color:rgba(255,255,255,.55);font-size:12px;margin-bottom:16px}\u001b[39m\n\u001b[31m.cg{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}\u001b[39m\n\u001b[31m.cm{background:rgba(255,255,255,.08);border-radius:8px;padding:8px 12px}\u001b[39m\n\u001b[31m.cm-l{font-size:9px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}\u001b[39m\n\u001b[31m.cm-v{font-size:13px;font-weight:600;color:#fff}\u001b[39m\n\u001b[31m.cm-v a{color:#fb923c}\u001b[39m\n\u001b[31m.cover-pbar{padding-top:8px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{background:var(--or);color:#fff;border:none;padding:10px 22px;border-radius:22px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}\u001b[39m\n\u001b[31m.btn-p:disabled{opacity:.4;cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-c{background:rgba(255,255,255,.1);color:rgba(255,255,255,.75);border:1px solid rgba(255,255,255,.2);padding:10px 18px;border-radius:22px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit}·\u001b[39m\n\u001b[31m/* ── Cover thumbnail grid ── */\u001b[39m\n\u001b[31m.cov-grid-hdr{font-size:10px;font-weight:700;color:rgba(255,255,255,.35);text-transform:uppercase;letter-spacing:1.2px;padding:10px 0 5px;flex-shrink:0}\u001b[39m\n\u001b[31m.cov-grid{flex:1;min-height:0;display:grid;gap:5px;overflow:hidden;align-content:start}\u001b[39m\n\u001b[31m.cov-thumb{position:relative;overflow:hidden;border-radius:7px;cursor:pointer;background:#1e293b;transition:transform .18s,box-shadow .18s}\u001b[39m\n\u001b[31m.cov-thumb:hover{transform:scale(1.05);box-shadow:0 4px 18px rgba(0,0,0,.55)}\u001b[39m\n\u001b[31m.cov-thumb img{width:100%;height:100%;object-fit:cover;display:block}\u001b[39m\n\u001b[31m.cov-thumb-vid{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:#0f172a}\u001b[39m\n\u001b[31m.cov-thumb-ov{position:absolute;inset:0;background:rgba(0,0,0,.28);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:5px;border-radius:7px}\u001b[39m\n\u001b[31m.cov-thumb-cat{color:rgba(255,255,255,.5);font-weight:900;text-align:center;text-transform:uppercase;letter-spacing:.8px;text-shadow:0 1px 6px rgba(0,0,0,.95);line-height:1.2;word-break:break-word}\u001b[39m\n\u001b[31m.cov-thumb-dims{color:rgba(255,255,255,.5);font-weight:700;text-align:center;text-shadow:0 1px 5px rgba(0,0,0,.95);letter-spacing:.3px;line-height:1.3}\u001b[39m\n\u001b[31m.cov-thumb-no{color:rgba(255,255,255,.5);font-weight:800;text-shadow:0 1px 4px rgba(0,0,0,.95);letter-spacing:.5px}\u001b[39m\n\u001b[31m#cover-btn{position:fixed;bottom:20px;right:16px;display:none;align-items:center;gap:6px;background:rgba(255,255,255,.15);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.25);color:#fff;padding:10px 22px;border-radius:50px;font-size:13px;font-weight:700;cursor:pointer;z-index:200;letter-spacing:.3px;box-shadow:0 2px 12px rgba(0,0,0,.3);font-family:inherit;transition:background .15s,transform .15s}\u001b[39m\n\u001b[31m#cover-btn:hover{background:rgba(255,255,255,.22);transform:scale(1.04)}·\u001b[39m\n\u001b[31m/* ── Print wait overlay ── */\u001b[39m\n\u001b[31m#print-overlay{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m@media print{#print-overlay{display:none!important}}·\u001b[39m\n\u001b[31m/* ── Loading progress bar ── */\u001b[39m\n\u001b[31m.load-bar{position:fixed;bottom:0;left:0;right:0;background:rgba(15,23,42,.95);padding:9px 16px;z-index:9999;display:flex;align-items:center;gap:12px;backdrop-filter:blur(6px)}\u001b[39m\n\u001b[31m.load-track{flex:1;height:5px;background:rgba(255,255,255,.12);border-radius:3px;overflow:hidden}\u001b[39m\n\u001b[31m.load-fill{height:100%;background:var(--or);width:0%;transition:width .35s ease;border-radius:3px}\u001b[39m\n\u001b[31m.load-txt{font-size:11px;color:rgba(255,255,255,.6);white-space:nowrap;min-width:160px}·\u001b[39m\n\u001b[31m/* ── Photo page ── */\u001b[39m\n\u001b[31m.photo-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ph-band{background:var(--dk);padding:16px 26px;flex-shrink:0;display:flex;align-items:center;gap:20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.ph-cat{font-size:35px;font-weight:800;color:#fff;letter-spacing:-.5px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.ph-dims{flex:1;font-size:18px;font-weight:600;color:var(--or);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}\u001b[39m\n\u001b[31m.ph-no{margin-left:auto;flex-shrink:0;font-size:21px;font-weight:700;color:rgba(255,255,255,.85);background:rgba(255,255,255,.1);padding:5px 20px;border-radius:24px;white-space:nowrap}\u001b[39m\n\u001b[31m.ph-of{font-size:18px;font-weight:400;color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.ph-img{flex:1;overflow:hidden;position:relative;background:#111}\u001b[39m\n\u001b[31m.ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m.ph-img img{width:100%;height:100%;object-fit:contain;display:block}\u001b[39m\n\u001b[31m.ph-cmt{position:absolute;bottom:0;left:0;right:0;padding:6px 14px;background:rgba(0,0,0,.62);font-size:11px;color:rgba(255,255,255,.75);font-style:italic;pointer-events:none}·\u001b[39m\n\u001b[31m/* ── Video / Doc pages ── */\u001b[39m\n\u001b[31m.vid-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;background:#fff}\u001b[39m\n\u001b[31m.vid-body{flex:1;padding:20px 24px;font-size:14px;color:var(--g600);border-left:4px solid var(--or)}\u001b[39m\n\u001b[31m.vid-body em{display:block;font-size:12px;color:var(--g400);margin-top:6px}\u001b[39m\n\u001b[31m.doc-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m.doc-wrap{flex:1;display:flex;align-items:center;justify-content:center;background:#111;overflow:hidden}\u001b[39m\n\u001b[31m.doc-img{max-width:100%;max-height:100%;object-fit:contain}·\u001b[39m\n\u001b[31m/* ── Cover header band ── */\u001b[39m\n\u001b[31m.cov-hdr{display:flex;gap:0;margin-bottom:12px;flex-shrink:0;border-radius:10px;overflow:hidden;border:1px solid rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.cov-hdr-l{flex:1;padding:14px 18px;display:flex;flex-direction:column;gap:5px;border-right:1px solid rgba(255,255,255,.1);min-width:0}\u001b[39m\n\u001b[31m.cov-hdr-r{width:170px;flex-shrink:0;padding:14px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:rgba(255,255,255,.04)}\u001b[39m\n\u001b[31m.cov-store{font-size:18px;font-weight:800;color:#fff;line-height:1.25;margin-bottom:2px}\u001b[39m\n\u001b[31m.cov-meta{font-size:12px;color:rgba(255,255,255,.55);display:flex;align-items:center;gap:5px;line-height:1.5}\u001b[39m\n\u001b[31m.cov-brand{background:var(--or);color:#fff;font-size:13px;font-weight:800;padding:5px 16px;border-radius:20px;text-align:center;letter-spacing:.3px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\u001b[39m\n\u001b[31m.cov-date-l{font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.8px;margin-bottom:2px;text-align:center}\u001b[39m\n\u001b[31m.cov-date-v{font-size:13px;font-weight:700;color:#fff;text-align:center}\u001b[39m\n\u001b[31m.cov-logo-box{background:#fff;border-radius:8px;padding:8px 14px;display:flex;align-items:center;justify-content:center;width:100%;max-width:138px}\u001b[39m\n\u001b[31m.cov-logo-box img{max-width:110px;max-height:44px;object-fit:contain;display:block}·\u001b[39m\n\u001b[31m/* ── Print ── */\u001b[39m\n\u001b[31m@page{size:A4 landscape;margin:12mm}\u001b[39m\n\u001b[31m@media print{\u001b[39m\n\u001b[31m  html,body{height:auto;overflow:visible;display:block}\u001b[39m\n\u001b[31m  .side-idx{display:none}\u001b[39m\n\u001b[31m  .main{overflow:visible;display:block;height:auto;scroll-snap-type:none}\u001b[39m\n\u001b[31m  .cover,.vid-page,.doc-page{height:auto;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m  .photo-page{height:186mm;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m  .cover{padding:20px 24px}\u001b[39m\n\u001b[31m  .cover-pbar{display:none}\u001b[39m\n\u001b[31m  .cov-hdr{margin-bottom:8px;border-radius:7px}\u001b[39m\n\u001b[31m  .cov-hdr-l{padding:10px 14px}\u001b[39m\n\u001b[31m  .cov-hdr-r{padding:10px 12px;width:150px}\u001b[39m\n\u001b[31m  .cov-store{font-size:15px}\u001b[39m\n\u001b[31m  .cov-meta{font-size:10px}\u001b[39m\n\u001b[31m  .cov-brand{font-size:11px;padding:3px 12px}\u001b[39m\n\u001b[31m  .cov-date-v{font-size:11px}\u001b[39m\n\u001b[31m  .ph-band{padding:5mm 13mm;gap:10mm}\u001b[39m\n\u001b[31m  .ph-cat{font-size:15mm}\u001b[39m\n\u001b[31m  .ph-dims{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-no{font-size:12mm;padding:2mm 8mm}\u001b[39m\n\u001b[31m  .ph-of{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-img{flex:1;display:flex;align-items:center;justify-content:center;background:#fff;overflow:hidden}\u001b[39m\n\u001b[31m  .ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m  .ph-img img{width:100%;height:100%;object-fit:contain}\u001b[39m\n\u001b[31m  .ph-cmt{position:static;background:transparent;color:#475569;padding:2mm 8mm;font-size:6mm}\u001b[39m\n\u001b[31m  .main>*:last-child{page-break-after:avoid;break-after:avoid}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m</style></head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<div class=\\\"side-idx\\\" id=\\\"side-idx\\\">${sideItems.join('')}</div>·\u001b[39m\n\u001b[31m<div class=\\\"main\\\" id=\\\"main\\\">·\u001b[39m\n\u001b[31m<div class=\\\"cover\\\" id=\\\"pg-cover\\\">\u001b[39m\n\u001b[31m  <div class=\\\"cov-hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-l\\\">\u001b[39m\n\u001b[31m      <div class=\\\"cov-store\\\">${esc(d.storeName||'Unknown Store')}</div>\u001b[39m\n\u001b[31m      ${(d.address||d.city)?`<div class=\\\"cov-meta\\\">&#x1F4CD; ${esc(d.address||'')}${d.city&&!(d.address||'').includes(d.city)?', '+esc(d.city):''}</div>`:''}\u001b[39m\n\u001b[31m      ${d.mobile?`<div class=\\\"cov-meta\\\">&#x1F4DE; ${esc(d.mobile)}</div>`:''}\u001b[39m\n\u001b[31m      ${d.email?`<div class=\\\"cov-meta\\\">&#x2709; ${esc(d.email)}</div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-r\\\">\u001b[39m\n\u001b[31m      ${brandLogoUrl\u001b[39m\n\u001b[31m        ? `<div class=\\\"cov-logo-box\\\"><img src=\\\"${brandLogoUrl}\\\" alt=\\\"${esc(d.brand||'')}\\\"></div>`\u001b[39m\n\u001b[31m        : (d.brand?`<div class=\\\"cov-brand\\\">${esc(d.brand)}</div>`:'')}\u001b[39m\n\u001b[31m      ${d.date?`<div><div class=\\\"cov-date-l\\\">Recce Date</div><div class=\\\"cov-date-v\\\">${esc(d.date)}</div></div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${thumbItems.length ? `<div class=\\\"cov-grid-hdr\\\">&#x1F4F7; ${thumbItems.length} page${thumbItems.length!==1?'s':''} &mdash; tap any to jump</div><div class=\\\"cov-grid\\\" id=\\\"cov-grid\\\">${thumbsHtml}</div>` : ''}\u001b[39m\n\u001b[31m  <div class=\\\"cover-pbar\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" id=\\\"btn-print\\\" onclick=\\\"doPDF()\\\">&#x1F4C4;&nbsp;PDF</button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-c\\\" onclick=\\\"window.close()\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m${pagesHtml}·\u001b[39m\n\u001b[31m${d.hasVideo?`\u001b[39m\n\u001b[31m<div class=\\\"vid-page\\\" id=\\\"pg-vid\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Video</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"vid-body\\\">${esc(d.videoNote||'Video recorded during visit')}${d.videoCmt?`<em>${esc(d.videoCmt)}</em>`:''}</div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m${urls.doc?`\u001b[39m\n\u001b[31m<div class=\\\"doc-page\\\" id=\\\"pg-doc\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Document</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"doc-wrap\\\"><a href=\\\"${urls.doc}\\\" target=\\\"_blank\\\"><img class=\\\"doc-img\\\" src=\\\"${urls.doc}\\\" loading=\\\"lazy\\\" alt=\\\"Document\\\"></a></div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"print-overlay\\\"><div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Preparing print&hellip;</div><div class=\\\"po-sub\\\" id=\\\"po-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"po-pfill\\\"></div></div></div>\u001b[39m\n\u001b[31m${pages.length ? `<div class=\\\"load-bar\\\" id=\\\"load-bar\\\"><div class=\\\"load-track\\\"><div class=\\\"load-fill\\\" id=\\\"load-fill\\\"></div></div><div class=\\\"load-txt\\\" id=\\\"load-txt\\\">Loading photos&#x2026;</div></div>` : ''}\u001b[39m\n\u001b[31m${thumbItems.length ? `<button id=\\\"cover-btn\\\" onclick=\\\"document.getElementById('pg-cover').scrollIntoView({behavior:'smooth'})\\\">&#x1F3E0;&nbsp;Cover Page</button>` : ''}·\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var main=document.getElementById('main');\u001b[39m\n\u001b[31m  var items=document.querySelectorAll('.si-item');\u001b[39m\n\u001b[31m  var covBtn=document.getElementById('cover-btn');\u001b[39m\n\u001b[31m  function setActive(id){\u001b[39m\n\u001b[31m    items.forEach(function(el){el.classList.toggle('active',el.dataset.tgt===id);});\u001b[39m\n\u001b[31m    var a=document.querySelector('.si-item[data-tgt=\\\"'+id+'\\\"]');\u001b[39m\n\u001b[31m    if(a) a.scrollIntoView({block:'nearest'});\u001b[39m\n\u001b[31m    if(covBtn) covBtn.style.display=id==='pg-cover'?'none':'flex';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  items.forEach(function(el){\u001b[39m\n\u001b[31m    el.addEventListener('click',function(){\u001b[39m\n\u001b[31m      var t=document.getElementById(el.dataset.tgt);\u001b[39m\n\u001b[31m      if(t) t.scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if('IntersectionObserver' in window){\u001b[39m\n\u001b[31m    var obs=new IntersectionObserver(function(entries){\u001b[39m\n\u001b[31m      entries.forEach(function(e){if(e.isIntersecting&&e.intersectionRatio>=0.45) setActive(e.target.id);});\u001b[39m\n\u001b[31m    },{root:main,threshold:0.45});\u001b[39m\n\u001b[31m    document.querySelectorAll('[id^=\\\"pg-\\\"]').forEach(function(p){obs.observe(p);});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  setActive('pg-cover');\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var imgs=Array.from(document.querySelectorAll('img'));\u001b[39m\n\u001b[31m  var total=imgs.length,loaded=0;\u001b[39m\n\u001b[31m  var bar=document.getElementById('load-bar');\u001b[39m\n\u001b[31m  var fill=document.getElementById('load-fill');\u001b[39m\n\u001b[31m  var txt=document.getElementById('load-txt');\u001b[39m\n\u001b[31m  var printPending=false,printShowTime=0;\u001b[39m\n\u001b[31m  var mm=96/25.4;\u001b[39m\n\u001b[31m  var SERVER_PDF='${serverPdfUrl}';\u001b[39m\n\u001b[31m  function updatePoBar(){\u001b[39m\n\u001b[31m    var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m    var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(poFill) poFill.style.width=(total?Math.round(loaded/total*100):100)+'%';\u001b[39m\n\u001b[31m    if(poSub) poSub.textContent=loaded+' / '+total+' photos ready';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function done(){\u001b[39m\n\u001b[31m    if(fill) fill.style.width='100%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='✓ All '+total+' photos ready';\u001b[39m\n\u001b[31m    setTimeout(function(){\u001b[39m\n\u001b[31m      if(bar){bar.style.transition='opacity .6s';bar.style.opacity='0';}\u001b[39m\n\u001b[31m      setTimeout(function(){if(bar)bar.style.display='none';},650);\u001b[39m\n\u001b[31m    },2000);\u001b[39m\n\u001b[31m    if(printPending){\u001b[39m\n\u001b[31m      printPending=false;\u001b[39m\n\u001b[31m      var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m      var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m      var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(poFill) poFill.style.width='100%';\u001b[39m\n\u001b[31m      if(poSub) poSub.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},Math.max(400,2000-(Date.now()-printShowTime)));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function onImg(){\u001b[39m\n\u001b[31m    loaded++;\u001b[39m\n\u001b[31m    if(fill) fill.style.width=Math.round(loaded/total*100)+'%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… '+loaded+' / '+total;\u001b[39m\n\u001b[31m    if(printPending) updatePoBar();\u001b[39m\n\u001b[31m    if(loaded>=total) done();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  /* ── PDF layout helpers ── */\u001b[39m\n\u001b[31m  function fitBandFonts(pageW){\u001b[39m\n\u001b[31m    var padH=2*13*mm,gapH=2*10*mm,noPadH=2*8*mm;\u001b[39m\n\u001b[31m    var avail=pageW-padH-gapH;\u001b[39m\n\u001b[31m    var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-band').forEach(function(band){\u001b[39m\n\u001b[31m      var cat=band.querySelector('.ph-cat');\u001b[39m\n\u001b[31m      var dims=band.querySelector('.ph-dims');\u001b[39m\n\u001b[31m      var no=band.querySelector('.ph-no');\u001b[39m\n\u001b[31m      if(!cat) return;\u001b[39m\n\u001b[31m      var catTxt=cat.textContent.trim();\u001b[39m\n\u001b[31m      var dimsTxt=dims?dims.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      var noTxt=no?no.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      function tw(sc){\u001b[39m\n\u001b[31m        var cf=15*sc*mm,df=10*sc*mm,nf=12*sc*mm;\u001b[39m\n\u001b[31m        ctx.font='800 '+cf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var cw=ctx.measureText(catTxt).width;\u001b[39m\n\u001b[31m        ctx.font='600 '+df+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var dw=dims?ctx.measureText(dimsTxt).width:0;\u001b[39m\n\u001b[31m        ctx.font='700 '+nf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var nw=no?ctx.measureText(noTxt).width+noPadH:0;\u001b[39m\n\u001b[31m        return cw+dw+nw;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      var scale=1.0;\u001b[39m\n\u001b[31m      if(tw(scale)>avail){\u001b[39m\n\u001b[31m        var lo=0.3,hi=1.0;\u001b[39m\n\u001b[31m        for(var i=0;i<10;i++){var mid=(lo+hi)/2;if(tw(mid)<=avail)lo=mid;else hi=mid;}\u001b[39m\n\u001b[31m        scale=lo*0.93;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      cat.style.setProperty('font-size',Math.round(15*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(dims) dims.style.setProperty('font-size',Math.round(10*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(no) no.style.setProperty('font-size',Math.round(12*scale*mm)+'px','important');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function sizePdfThumbs(pageW,pageH){\u001b[39m\n\u001b[31m    var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m    if(!grid||!grid.children.length) return;\u001b[39m\n\u001b[31m    var coverPage=document.getElementById('pg-cover');\u001b[39m\n\u001b[31m    var usedH=56;\u001b[39m\n\u001b[31m    if(coverPage){\u001b[39m\n\u001b[31m      Array.from(coverPage.children).forEach(function(el){\u001b[39m\n\u001b[31m        if(el!==grid) usedH+=el.offsetHeight||0;\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    var gridH=Math.max(80,pageH-usedH);\u001b[39m\n\u001b[31m    var n=grid.children.length,gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m    for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m      var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m      var w=(pageW-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m      var h=w*asp;\u001b[39m\n\u001b[31m      if(rows*h+(rows-1)*gap<=gridH&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m    grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m    grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m    var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m    var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m    var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function preparePdfLayout(){\u001b[39m\n\u001b[31m    var pageW=Math.round((297-24)*mm);\u001b[39m\n\u001b[31m    var pageH=Math.round((210-24)*mm);\u001b[39m\n\u001b[31m    fitBandFonts(pageW);\u001b[39m\n\u001b[31m    sizePdfThumbs(pageW,pageH);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.preparePdfLayout=preparePdfLayout;\u001b[39m\n\u001b[31m  function restorePdfLayout(){\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-cat,.ph-dims,.ph-no').forEach(function(el){\u001b[39m\n\u001b[31m      el.style.removeProperty('font-size');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(window._screenSizeThumbs) window._screenSizeThumbs();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.addEventListener('afterprint',restorePdfLayout);\u001b[39m\n\u001b[31m  function _doBrowserPrint(){\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    printShowTime=Date.now();\u001b[39m\n\u001b[31m    preparePdfLayout();\u001b[39m\n\u001b[31m    if(total===0||loaded>=total){\u001b[39m\n\u001b[31m      var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m      if(ps) ps.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},2000);\u001b[39m\n\u001b[31m      return;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    printPending=true;\u001b[39m\n\u001b[31m    updatePoBar();\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if((!img.complete||img.naturalWidth===0)&&img.getAttribute('loading')==='lazy'){\u001b[39m\n\u001b[31m        img.loading='eager';var s=img.src;img.src='';img.src=s;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.doPDF=async function(){\u001b[39m\n\u001b[31m    if(!SERVER_PDF){_doBrowserPrint();return;}\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      var r=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m      if(r.ok){window.open(SERVER_PDF,'_blank');return;}\u001b[39m\n\u001b[31m    }catch(_){}\u001b[39m\n\u001b[31m    // PDF not ready yet — show overlay and poll\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    if(pf) pf.style.width='0%';\u001b[39m\n\u001b[31m    if(ps) ps.textContent='Waiting for server PDF…';\u001b[39m\n\u001b[31m    var tries=0;\u001b[39m\n\u001b[31m    (async function poll(){\u001b[39m\n\u001b[31m      tries++;\u001b[39m\n\u001b[31m      if(pf) pf.style.width=Math.min(88,tries*8)+'%';\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        var r2=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m        if(r2.ok){\u001b[39m\n\u001b[31m          if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m          setTimeout(function(){if(ov)ov.style.display='none';window.open(SERVER_PDF,'_blank');},400);\u001b[39m\n\u001b[31m          return;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      }catch(_){}\u001b[39m\n\u001b[31m      if(tries>=12){if(ov)ov.style.display='none';_doBrowserPrint();return;}\u001b[39m\n\u001b[31m      setTimeout(poll,5000);\u001b[39m\n\u001b[31m    })();\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  if(total===0){if(bar)bar.style.display='none';}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… 0 / '+total;\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if(img.complete&&img.naturalWidth>0) onImg();\u001b[39m\n\u001b[31m      else{img.addEventListener('load',onImg);img.addEventListener('error',onImg);}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m  if(grid&&grid.children.length>0){\u001b[39m\n\u001b[31m    function sizeThumbs(){\u001b[39m\n\u001b[31m      var n=grid.children.length;\u001b[39m\n\u001b[31m      var gw=grid.clientWidth,gh=grid.clientHeight;\u001b[39m\n\u001b[31m      if(!gw||!gh) return;\u001b[39m\n\u001b[31m      var gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m      for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m        var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m        var w=(gw-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m        var h=w*asp;\u001b[39m\n\u001b[31m        if(rows*h+(rows-1)*gap<=gh&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m      grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m      grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m      var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m      var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m      var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    window._screenSizeThumbs=sizeThumbs;\u001b[39m\n\u001b[31m    requestAnimationFrame(function(){requestAnimationFrame(sizeThumbs);});\u001b[39m\n\u001b[31m    window.addEventListener('resize',sizeThumbs);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m</scr`+'ipt>'+`\u001b[39m\n\u001b[31m</body></html>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncToPostgres(entry) {\u001b[39m\n\u001b[31m  const d   = entry.data || {};\u001b[39m\n\u001b[31m  const hub = _recceHubUser();·\u001b[39m\n\u001b[31m  // Step 1 — upload all photos to VPS, get permanent server URLs\u001b[39m\n\u001b[31m  let photoUrls = { front:[], inside:[], brandings:[], addl:[], doc:null };\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const pResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type: 'save-photos', subId: entry.id,\u001b[39m\n\u001b[31m        photos: {\u001b[39m\n\u001b[31m          front:    (d.frontPhotos||[]).map(p=>({b64:p.b64,   cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64,  cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||null})),\u001b[39m\n\u001b[31m          addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64,   desc:p.desc||''})),\u001b[39m\n\u001b[31m          doc:      d.docB64 || null,\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (pResp.ok) { const r=await pResp.json(); if(r.success) {\u001b[39m\n\u001b[31m      photoUrls=r.photoUrls;\u001b[39m\n\u001b[31m      // Merge retained existing URLs for edit re-submits\u001b[39m\n\u001b[31m      if (entry.editedAt) {\u001b[39m\n\u001b[31m        photoUrls.front    =(photoUrls.front   ||[]).map((u,i)=>u||(d.frontPhotos  ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.inside   =(photoUrls.inside  ||[]).map((u,i)=>u||(d.insidePhotos ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.addl     =(photoUrls.addl    ||[]).map((u,i)=>u||(d.addlPhotos   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.brandings=(photoUrls.brandings||[]).map((u,i)=>u||(d.brandings   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        if(!photoUrls.doc) photoUrls.doc=d._docExistingUrl||null;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }}\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-photos] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 1.5 — trigger Google Slides via proxy using permanent photo URLs (fire-and-forget)\u001b[39m\n\u001b[31m  (async()=>{try{\u001b[39m\n\u001b[31m    const _hasPh=(photoUrls.front||[]).some(Boolean)||(photoUrls.inside||[]).some(Boolean)||(photoUrls.brandings||[]).some(Boolean);\u001b[39m\n\u001b[31m    if(!_hasPh)return;\u001b[39m\n\u001b[31m    const _gu=(await cfg('slides-gas-url'))||(await cfg('gas-url'))||DEFAULT_GAS_URL;if(!_gu)return;\u001b[39m\n\u001b[31m    await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({\u001b[39m\n\u001b[31m      type:'make-slides',gasUrl:_gu,subId:entry.id,\u001b[39m\n\u001b[31m      storeInfo:{storeName:d.storeName||'',brand:d.brand||'',address:d.address||'',mobile:d.mobile||'',date:d.date||'',city:d.city||'',gpsCoords:d.gpsCoords||null},\u001b[39m\n\u001b[31m      photoGroups:{\u001b[39m\n\u001b[31m        front:    (photoUrls.front   ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.frontPhotos  ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        inside:   (photoUrls.inside  ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.insidePhotos ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        brandings:(photoUrls.brandings||[]).filter(Boolean).map((url,i)=>({url,meta:{type:(d.brandings||[])[i]?.type,w:(d.brandings||[])[i]?.w,h:(d.brandings||[])[i]?.h,qty:(d.brandings||[])[i]?.qty,sqft:(d.brandings||[])[i]?.sqft}})),\u001b[39m\n\u001b[31m        addl:    (photoUrls.addl    ||[]).filter(Boolean).map((url,i)=>({url,desc:(d.addlPhotos  ||[])[i]?.desc||''})),\u001b[39m\n\u001b[31m      },\u001b[39m\n\u001b[31m    })});\u001b[39m\n\u001b[31m    entry.gasAt=new Date().toISOString();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[recce-slides]',e.message);}}\u001b[39m\n\u001b[31m  )();·\u001b[39m\n\u001b[31m  // Step 2 — generate rich HTML report using server URLs, save to VPS\u001b[39m\n\u001b[31m  let view_url = null;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const html  = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m    const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-view', subId: entry.id, html })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (vResp.ok) { const r=await vResp.json(); if(r.success) view_url=r.url; }\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-view] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 3 — upsert to PostgreSQL with photo URLs + view URL\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch(`${_RC_BASE}/submissions`, {\u001b[39m\n\u001b[31m      method: 'POST', headers: _RC_UPSERT,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        sub_id:         entry.id,\u001b[39m\n\u001b[31m        store_name:     d.storeName    || 'Unknown',\u001b[39m\n\u001b[31m        brand:          d.brand        || null,\u001b[39m\n\u001b[31m        client_name:    d.clientName   || null,\u001b[39m\n\u001b[31m        visit_date:     d.date         || new Date().toISOString().slice(0,10),\u001b[39m\n\u001b[31m        address:        d.address      || null,\u001b[39m\n\u001b[31m        mobile:         d.mobile       || null,\u001b[39m\n\u001b[31m        city:           d.city         || null,\u001b[39m\n\u001b[31m        has_branding:   !!(d.brandings?.length),\u001b[39m\n\u001b[31m        branding_count: d.brandings?.length || 0,\u001b[39m\n\u001b[31m        has_video:      !!d.hasVideo,\u001b[39m\n\u001b[31m        front_photos:   d.frontPhotos?.length  || 0,\u001b[39m\n\u001b[31m        inside_photos:  d.insidePhotos?.length || 0,\u001b[39m\n\u001b[31m        addl_photos:    d.addlPhotos?.length   || 0,\u001b[39m\n\u001b[31m        gps_lat:        d.gpsCoords?.lat       || null,\u001b[39m\n\u001b[31m        gps_lng:        d.gpsCoords?.lng       || null,\u001b[39m\n\u001b[31m        submitted_by:   hub.empId              || null,\u001b[39m\n\u001b[31m        submitted_at:   entry.timestamp,\u001b[39m\n\u001b[31m        campaign_id:    entry.campaignId       || null,\u001b[39m\n\u001b[31m        photo_urls:     photoUrls,\u001b[39m\n\u001b[31m        view_url,\u001b[39m\n\u001b[31m        meta: {\u001b[39m\n\u001b[31m          brandings: (d.brandings||[]).map(b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft})),\u001b[39m\n\u001b[31m          videoNote: d.videoNote || null,\u001b[39m\n\u001b[31m          videoCmt:  d.videoCmt  || null,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        status: 'submitted',\u001b[39m\n\u001b[31m        edit_assigned_to: null,\u001b[39m\n\u001b[31m        edit_comment: null,\u001b[39m\n\u001b[31m        edited_at: entry.editedAt || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    return { ok: true, viewUrl: view_url };\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    console.warn('[recce-db] sync error:', e.message);\u001b[39m\n\u001b[31m    return { ok: false, viewUrl: null };\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mconst DEFAULT_ADMIN_HASH='42d372e6110bee134990ac6881c3d5eb568482008add9a859f37f10d759430e8';·\u001b[39m\n\u001b[31masync function saveGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('gas-url',url||DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  toast('Endpoint saved','success');\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function testEndpoint(){\u001b[39m\n\u001b[31m  const url=(await cfg('gas-url'))||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  try{await fetch(url,{method:'POST',mode:'no-cors',body:JSON.stringify({test:true})});toast('Endpoint reachable ✓','success');}\u001b[39m\n\u001b[31m  catch{toast('Cannot reach endpoint','error')}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  cfg('gas-url').then(url=>{\u001b[39m\n\u001b[31m    const u=url||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    // Show last 30 chars only for privacy\u001b[39m\n\u001b[31m    el.textContent='Endpoint: …'+u.slice(-30);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── SLIDES GAS URL ────────────────────────────────────────────\u001b[39m\n\u001b[31masync function saveSlidesGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('slides-gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('slides-gas-url', url);\u001b[39m\n\u001b[31m  toast('Slides GAS URL saved','success');\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function updateSlidesGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('slides-gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  const u=await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  el.textContent=u?'Configured: …'+u.slice(-30):'Not configured';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── MAKE SLIDES ───────────────────────────────────────────────\u001b[39m\n\u001b[31masync function makeSlides(id){\u001b[39m\n\u001b[31m  const gasUrl = await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  if(!gasUrl){\u001b[39m\n\u001b[31m    toast('Configure Slides GAS URL in Settings first','error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const entry = await dbGet('subs', id);\u001b[39m\n\u001b[31m  if(!entry){ toast('Entry not found','error'); return; }\u001b[39m\n\u001b[31m  const d = entry.data;·\u001b[39m\n\u001b[31m  toast('Uploading photos & generating slides…','info');·\u001b[39m\n\u001b[31m  // Build photo groups payload\u001b[39m\n\u001b[31m  const photoGroups = {\u001b[39m\n\u001b[31m    front:    (d.frontPhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64, cmt:p.desc||''})),\u001b[39m\n\u001b[31m    brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||'', meta:{type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft}})),\u001b[39m\n\u001b[31m  };·\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type:       'recce',\u001b[39m\n\u001b[31m        subId:      id,\u001b[39m\n\u001b[31m        gasUrl:     gasUrl,\u001b[39m\n\u001b[31m        storeInfo:  {\u001b[39m\n\u001b[31m          storeName: d.storeName, brand: d.brand,\u001b[39m\n\u001b[31m          date: d.date, address: d.address,\u001b[39m\n\u001b[31m          mobile: d.mobile, gpsCoords: d.gpsCoords,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        photoGroups,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const result = await resp.json();\u001b[39m\n\u001b[31m    if(result.success && result.slideUrl){\u001b[39m\n\u001b[31m      // Store slide URL on the entry\u001b[39m\n\u001b[31m      entry.slideUrl = result.slideUrl;\u001b[39m\n\u001b[31m      await dbPut('subs', entry);\u001b[39m\n\u001b[31m      toast('✅ Slides ready!','success');\u001b[39m\n\u001b[31m      window.open(result.slideUrl, '_blank');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast('Slides error: '+(result.error||'Unknown'),'error');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e){\u001b[39m\n\u001b[31m    toast('Network error: '+e.message,'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN LOGIN ──────────────────────────────────────────────\u001b[39m\n\u001b[31mfunction showAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-error').style.display='none';\u001b[39m\n\u001b[31m  // Restore saved config URL\u001b[39m\n\u001b[31m  cfg('admin-cfg-url').then(u=>{if(u&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=u;});\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('admin-pwd').focus(),100);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveAdminCfgUrl(){\u001b[39m\n\u001b[31m  // Admin cfg URL can be saved without login (needed to set up auth itself)\u001b[39m\n\u001b[31m  // But we warn if saving while unlocked only\u001b[39m\n\u001b[31m  const url=document.getElementById('admin-cfg-url').value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  await cfg('admin-cfg-url',url);\u001b[39m\n\u001b[31m  toast('Config URL saved — will use on next login attempt','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function verifyAdmin(){\u001b[39m\n\u001b[31m  // Hub admins (harish/pramod) are auto-unlocked — no password needed\u001b[39m\n\u001b[31m  if (_adminUnlocked) { adminLoginSuccess(); return; }\u001b[39m\n\u001b[31m  const pwd=document.getElementById('admin-pwd').value;\u001b[39m\n\u001b[31m  if(!pwd){document.getElementById('admin-error').style.display='block';document.getElementById('admin-error').textContent='Enter password';return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('admin-login-btn');btn.disabled=true;btn.textContent='Verifying…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // Try server verification first\u001b[39m\n\u001b[31m    const cfgUrl=(await cfg('admin-cfg-url'))||'';\u001b[39m\n\u001b[31m    if(cfgUrl){\u001b[39m\n\u001b[31m      const r=await fetch(cfgUrl,{cache:'no-store'});\u001b[39m\n\u001b[31m      const j=await r.json();\u001b[39m\n\u001b[31m      // Server JSON format: {\\\"password\\\":\\\"plaintext\\\"} or {\\\"hash\\\":\\\"sha256hash\\\"}\u001b[39m\n\u001b[31m      let match=false;\u001b[39m\n\u001b[31m      if(j.password){match=(j.password===pwd);}\u001b[39m\n\u001b[31m      else if(j.hash){\u001b[39m\n\u001b[31m        // SHA-256 comparison\u001b[39m\n\u001b[31m        const enc=new TextEncoder();\u001b[39m\n\u001b[31m        const data=enc.encode(pwd);\u001b[39m\n\u001b[31m        const hashBuf=await crypto.subtle.digest('SHA-256',data);\u001b[39m\n\u001b[31m        const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m        match=(hashHex===j.hash);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      if(match){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m      else{showAdminError('Incorrect password');return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Fallback: local password stored in settings\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if(localHash){\u001b[39m\n\u001b[31m      const enc=new TextEncoder();\u001b[39m\n\u001b[31m      const hashBuf=await crypto.subtle.digest('SHA-256',enc.encode(pwd));\u001b[39m\n\u001b[31m      const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m      if(hashHex===localHash){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Final fallback: check against hardcoded default hash\u001b[39m\n\u001b[31m    const enc2=new TextEncoder();\u001b[39m\n\u001b[31m    const hb2=await crypto.subtle.digest('SHA-256',enc2.encode(pwd));\u001b[39m\n\u001b[31m    const hh2=Array.from(new Uint8Array(hb2)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    if(hh2===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }catch(err){\u001b[39m\n\u001b[31m    // Network error — try all local fallbacks\u001b[39m\n\u001b[31m    const enc3=new TextEncoder();\u001b[39m\n\u001b[31m    const hb3=await crypto.subtle.digest('SHA-256',enc3.encode(pwd));\u001b[39m\n\u001b[31m    const hh3=Array.from(new Uint8Array(hb3)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if((localHash&&hh3===localHash)||hh3===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }finally{btn.disabled=false;btn.textContent='Login';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showAdminError(msg){\u001b[39m\n\u001b[31m  const el=document.getElementById('admin-error');\u001b[39m\n\u001b[31m  el.textContent=msg;el.style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminLoginSuccess(){\u001b[39m\n\u001b[31m  _adminUnlocked=true;\u001b[39m\n\u001b[31m  closeAdminLogin();\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  cfg('gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  cfg('slides-gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('slides-gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||'';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  toast('Admin mode unlocked','success');\u001b[39m\n\u001b[31m  setTimeout(lockAdmin,10*60*1000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction lockAdmin(){\u001b[39m\n\u001b[31m  _adminUnlocked=false;\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  toast('Admin session ended','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updAvailTag(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-avail-tag');\u001b[39m\n\u001b[31m  const ct=document.getElementById('store-avail-count');\u001b[39m\n\u001b[31m  const txt=stores.length?`${stores.length} stores`:'No store list';\u001b[39m\n\u001b[31m  if(el)el.textContent=txt;\u001b[39m\n\u001b[31m  if(ct)ct.textContent=stores.length?t(`${stores.length} stores available — tap to browse`,`${stores.length} स्टोर उपलब्ध — दबाएं`):t('No store list loaded yet','कोई स्टोर सूची नहीं');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PICKER\u001b[39m\n\u001b[31mfunction openPicker(){\u001b[39m\n\u001b[31m  if(!stores.length){toast('Load a store list in Settings first','error');return;}\u001b[39m\n\u001b[31m  document.getElementById('povl').classList.add('open');\u001b[39m\n\u001b[31m  document.getElementById('psearch').value='';\u001b[39m\n\u001b[31m  filterPicker('');\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('psearch').focus(),150);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closePicker(){document.getElementById('povl').classList.remove('open');}\u001b[39m\n\u001b[31masync function filterPicker(q){\u001b[39m\n\u001b[31m  const list=document.getElementById('plist');\u001b[39m\n\u001b[31m  const words=q.toLowerCase().trim().split(/\\\\s+/).filter(Boolean);\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const lastVisit={};\u001b[39m\n\u001b[31m  subs.forEach(s=>{const nm=s.data?.storeName;if(nm&&(!lastVisit[nm]||s.timestamp>lastVisit[nm]))lastVisit[nm]=s.timestamp;});·\u001b[39m\n\u001b[31m  // Multi-word: ALL words must match somewhere in any field (search across both English and Hindi)\u001b[39m\n\u001b[31m  let fl=stores.filter(s=>{\u001b[39m\n\u001b[31m    if(!words.length)return true;\u001b[39m\n\u001b[31m    const hay=[s.name,s.nameHi,s.address,s.addressHi,s.mobile,s.city,s.cityHi,s.distName,s.distNameHi,s.brand,s.sales,s.proj,s.glowSign,s.inshop]\u001b[39m\n\u001b[31m               .map(x=>(x||'').toLowerCase()).join(' ');\u001b[39m\n\u001b[31m    return words.every(w=>hay.includes(w));\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(fl.length>100)fl=fl.slice(0,100);·\u001b[39m\n\u001b[31m  if(!fl.length){\u001b[39m\n\u001b[31m    const esc=q.replace(/'/g,\\\"\\\\\\\\'\\\");\u001b[39m\n\u001b[31m    list.innerHTML=`<div style=\\\"text-align:center;padding:32px 16px;color:var(--g400);font-size:14px\\\">No stores match \\\"${q}\\\"<br><span style=\\\"font-size:12px\\\">Try fewer or different words</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('${esc}')\\\">+ Add \\\"${q}\\\" as new store</div>`;\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Group by brand (including empty brand)\u001b[39m\n\u001b[31m  const g={};\u001b[39m\n\u001b[31m  fl.forEach(s=>{\u001b[39m\n\u001b[31m    const b=s.brand||'(No Brand — will ask)';\u001b[39m\n\u001b[31m    if(!g[b])g[b]=[];\u001b[39m\n\u001b[31m    g[b].push(s);\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html='';\u001b[39m\n\u001b[31m  Object.keys(g).sort().forEach(br=>{\u001b[39m\n\u001b[31m    html+=`<div class=\\\"psec\\\">${br}</div>`;\u001b[39m\n\u001b[31m    g[br].forEach(s=>{\u001b[39m\n\u001b[31m      const lv=lastVisit[s.name];\u001b[39m\n\u001b[31m      const lvStr=lv?`🕐 Last: ${new Date(lv).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'2-digit'})}`:'';\u001b[39m\n\u001b[31m      const chips=[];\u001b[39m\n\u001b[31m      if(s.glowSign&&s.glowSign.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dcfce7;color:#14532d;padding:2px 6px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m      if(s.inshop&&s.inshop.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dbeafe;color:#1e40af;padding:2px 6px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m      if(s.proj)chips.push(`<span style=\\\"font-size:10px;background:var(--g100);color:var(--g600);padding:2px 6px;border-radius:10px\\\">Target: ${s.proj}</span>`);\u001b[39m\n\u001b[31m      const enc=JSON.stringify(s).replace(/\\\"/g,'&quot;');\u001b[39m\n\u001b[31m      const mapsUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m      const waUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const telUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const dispName=LANG==='hi'&&s.nameHi?s.nameHi:s.name;\u001b[39m\n\u001b[31m      const dispAddr=LANG==='hi'&&s.addressHi?s.addressHi:s.address;\u001b[39m\n\u001b[31m      const dispDist=LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m      html+=`<div class=\\\"pitem\\\" onclick=\\\"pickStore(${enc})\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"pi-name\\\">${dispName}</div>\u001b[39m\n\u001b[31m          ${dispAddr?`<div class=\\\"pi-addr\\\">📍 ${dispAddr}</div>`:''}\u001b[39m\n\u001b[31m          ${s.mobile?`<div class=\\\"pi-addr\\\">📞 ${s.mobile}</div>`:''}\u001b[39m\n\u001b[31m          ${dispDist?`<div class=\\\"pi-addr\\\" style=\\\"color:var(--am)\\\">👤 ${dispDist}</div>`:''}\u001b[39m\n\u001b[31m          ${lvStr?`<div class=\\\"pi-last\\\">${lvStr}</div>`:''}\u001b[39m\n\u001b[31m          ${chips.length?`<div style=\\\"display:flex;gap:4px;flex-wrap:wrap;margin-top:4px\\\">${chips.join('')}</div>`:''}\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;gap:6px;margin-top:7px\\\" onclick=\\\"event.stopPropagation()\\\">\u001b[39m\n\u001b[31m            ${mapsUrl?`<a href=\\\"${mapsUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#e0f2fe;color:#0369a1;border-radius:20px;text-decoration:none;font-weight:600\\\">🗺 Maps</a>`:''}\u001b[39m\n\u001b[31m            ${waUrl?`<a href=\\\"${waUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#dcfce7;color:#15803d;border-radius:20px;text-decoration:none;font-weight:600\\\">💬 WhatsApp</a>`:''}\u001b[39m\n\u001b[31m            ${telUrl?`<a href=\\\"${telUrl}\\\" style=\\\"font-size:11px;padding:4px 10px;background:#f0fdf4;color:#166534;border-radius:20px;text-decoration:none;font-weight:600\\\">📞 Call</a>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        ${s.brand?`<div class=\\\"pi-brand\\\">${s.brand}</div>`:'<div class=\\\"pi-brand\\\" style=\\\"background:var(--rd)\\\">?</div>'}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html+=`<div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('')\\\">+ Not in list? Add new store</div>`;\u001b[39m\n\u001b[31m  list.innerHTML=html;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function pickStore(s){\u001b[39m\n\u001b[31m  selectedStore=s;manualMode=false;closePicker();\u001b[39m\n\u001b[31m  const _dn =LANG==='hi'&&s.nameHi    ?s.nameHi    :s.name;\u001b[39m\n\u001b[31m  const _da =LANG==='hi'&&s.addressHi ?s.addressHi :s.address;\u001b[39m\n\u001b[31m  const _dd =LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m  const _dc =LANG==='hi'&&s.cityHi    ?s.cityHi    :s.city;\u001b[39m\n\u001b[31m  document.getElementById('sc-name').textContent=_dn;\u001b[39m\n\u001b[31m  const brandEl=document.getElementById('sc-brand');\u001b[39m\n\u001b[31m  brandEl.textContent=s.brand||'No Brand';brandEl.style.background=s.brand?'var(--nv)':'var(--rd)';\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const prev=subs.filter(x=>x.data?.storeName===s.name).sort((a,b)=>new Date(b.timestamp)-new Date(a.timestamp))[0];\u001b[39m\n\u001b[31m  const lc=document.getElementById('sc-last');\u001b[39m\n\u001b[31m  if(prev){const d=new Date(prev.timestamp);lc.textContent='Last: '+d.toLocaleDateString('en-IN',{day:'numeric',month:'short'});lc.style.display='inline-flex';}\u001b[39m\n\u001b[31m  else lc.style.display='none';\u001b[39m\n\u001b[31m  // All Excel fields — display in active language\u001b[39m\n\u001b[31m  const mUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m  const wUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const tUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const details=[];\u001b[39m\n\u001b[31m  if(_da)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📍 ${_da}${mUrl?` <a href=\\\"${mUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#0369a1;margin-left:6px\\\">🗺 Navigate</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(s.mobile)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📞 ${s.mobile}${tUrl?` <a href=\\\"${tUrl}\\\" style=\\\"font-size:11px;color:#166534;margin-left:6px\\\">Call</a>`:''}${wUrl?` <a href=\\\"${wUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#15803d;margin-left:6px\\\">WhatsApp</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(_dd)details.push(`<div style=\\\"font-size:12px;color:var(--am)\\\">👤 ${_dd}</div>`);\u001b[39m\n\u001b[31m  if(_dc)details.push(`<div style=\\\"font-size:12px;color:var(--g500)\\\">🏙 ${_dc}</div>`);\u001b[39m\n\u001b[31m  const opp=[];\u001b[39m\n\u001b[31m  if(s.glowSign&&s.glowSign.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dcfce7;color:#14532d;padding:2px 7px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m  if(s.inshop&&s.inshop.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dbeafe;color:#1e40af;padding:2px 7px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m  if(s.proj)opp.push(`<span style=\\\"font-size:11px;background:var(--g100);color:var(--g600);padding:2px 7px;border-radius:10px\\\">Target 2026: ${s.proj}</span>`);\u001b[39m\n\u001b[31m  if(opp.length)details.push(`<div style=\\\"display:flex;gap:5px;flex-wrap:wrap;margin-top:3px\\\">${opp.join('')}</div>`);\u001b[39m\n\u001b[31m  document.getElementById('sc-details').innerHTML=details.join('');\u001b[39m\n\u001b[31m  // Missing fields\u001b[39m\n\u001b[31m  const missing=[];\u001b[39m\n\u001b[31m  if(!s.address)missing.push({key:'address',label:'Store Address',type:'textarea',placeholder:'Full address'});\u001b[39m\n\u001b[31m  if(!s.mobile)missing.push({key:'mobile',label:'Mobile No.',type:'tel',placeholder:'10-digit number',maxlen:'10'});\u001b[39m\n\u001b[31m  const mw=document.getElementById('sc-missing'),mf=document.getElementById('sc-missing-fields');\u001b[39m\n\u001b[31m  if(missing.length){\u001b[39m\n\u001b[31m    mf.innerHTML=missing.map(m=>`<div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\"><label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">${m.label} <span class=\\\"req\\\">*</span></label>${m.type==='textarea'?`<textarea id=\\\"sc-miss-${m.key}\\\" rows=\\\"2\\\" placeholder=\\\"${m.placeholder}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></textarea>`:`<input type=\\\"${m.type}\\\" id=\\\"sc-miss-${m.key}\\\" placeholder=\\\"${m.placeholder}\\\" ${m.maxlen?`maxlength=\\\"${m.maxlen}\\\"`:''}  inputmode=\\\"${m.type==='tel'?'numeric':'text'}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\">`}</div>`).join('');\u001b[39m\n\u001b[31m    mw.style.display='block';\u001b[39m\n\u001b[31m  } else {mw.style.display='none';}\u001b[39m\n\u001b[31m  // Brand selector\u001b[39m\n\u001b[31m  const bSel=document.getElementById('brand-selector'),bChips=document.getElementById('brand-chips');\u001b[39m\n\u001b[31m  if(!s.brand){\u001b[39m\n\u001b[31m    renderBrandChips();\u001b[39m\n\u001b[31m    bSel.style.display='block';\u001b[39m\n\u001b[31m  } else {bSel.style.display='none';}\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  F.storeName=s.name;F.brand=s.brand||'';F.address=s.address||'';F.mobile=s.mobile||'';\u001b[39m\n\u001b[31m  if(s.brand&&!_selectedClient&&!_clientOtherMode) autoSetClient(s.brand);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateMissingField(key,val){if(!selectedStore)return;selectedStore[key]=val.trim();F[key]=val.trim();saveDraft();}\u001b[39m\n\u001b[31mfunction selectStoreBrand(b){\u001b[39m\n\u001b[31m  F.brand=b;F.brandLogoUrl=_brandLogos[b]||'';\u001b[39m\n\u001b[31m  if(selectedStore)selectedStore.brand=b;\u001b[39m\n\u001b[31m  const el=document.getElementById('sc-brand');if(el){el.textContent=b;el.style.background='var(--nv)';}\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-chips .chip').forEach(c=>{c.classList.toggle('sel',c.querySelector('span')?.textContent===b||c.textContent.trim()===b);});\u001b[39m\n\u001b[31m  if(!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction onManualBrandChange(){\u001b[39m\n\u001b[31m  const b=document.getElementById('f-brand')?.value||'';\u001b[39m\n\u001b[31m  F.brandLogoUrl=b?(_brandLogos[b]||''):'';\u001b[39m\n\u001b[31m  if(b&&!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction openManual(prefill){\u001b[39m\n\u001b[31m  manualMode=true;\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').classList.add('on');\u001b[39m\n\u001b[31m  document.getElementById('mt-label').innerHTML='← Back to store list';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='block';\u001b[39m\n\u001b[31m  // Pre-fill from selectedStore if available (e.g. when toggling after picker selection)\u001b[39m\n\u001b[31m  const s=selectedStore;\u001b[39m\n\u001b[31m  if(s){\u001b[39m\n\u001b[31m    if(document.getElementById('f-brand'))document.getElementById('f-brand').value=s.brand||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-store'))document.getElementById('f-store').value=s.name||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-addr'))document.getElementById('f-addr').value=s.address||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-mobile'))document.getElementById('f-mobile').value=s.mobile||'';\u001b[39m\n\u001b[31m  } else if(prefill){\u001b[39m\n\u001b[31m    document.getElementById('f-store').value=prefill;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  selectedStore=null;\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction toggleManual(){\u001b[39m\n\u001b[31m  if(manualMode){\u001b[39m\n\u001b[31m    manualMode=false;\u001b[39m\n\u001b[31m    document.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31m    document.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31m    document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    openManual('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// GPS\u001b[39m\n\u001b[31mfunction captureGPS(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gps-status');el.textContent='Getting location…';el.style.color='var(--g500)';\u001b[39m\n\u001b[31m  if(!navigator.geolocation){el.textContent='GPS not available';return;}\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(pos=>{\u001b[39m\n\u001b[31m    gpsCoords={lat:pos.coords.latitude.toFixed(6),lng:pos.coords.longitude.toFixed(6),acc:Math.round(pos.coords.accuracy)};\u001b[39m\n\u001b[31m    el.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${gpsCoords.acc}m)`;el.style.color='var(--gn)';saveDraft();\u001b[39m\n\u001b[31m  },()=>{el.textContent='GPS failed — enter address manually';el.style.color='var(--rd)';},{enableHighAccuracy:true,timeout:10000});\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// DRAFT\u001b[39m\n\u001b[31mlet draftT;\u001b[39m\n\u001b[31mfunction saveDraft(){\u001b[39m\n\u001b[31m  clearTimeout(draftT);\u001b[39m\n\u001b[31m  draftT=setTimeout(async()=>{\u001b[39m\n\u001b[31m    const draft={k:'current',ts:Date.now(),F:{...F,date:document.getElementById('f-date')?.value||'',brand:manualMode?(document.getElementById('f-brand')?.value||''):(selectedStore?.brand||F.brand||''),storeName:selectedStore?selectedStore.name:(document.getElementById('f-store')?.value||''),address:manualMode?(document.getElementById('f-addr')?.value||''):(selectedStore?.address||F.address||''),mobile:manualMode?(document.getElementById('f-mobile')?.value||''):(selectedStore?.mobile||F.mobile||''),clientName:getClientName()},selectedStore,manualMode,gpsCoords,_selectedClient,_clientOtherMode,fCnt:frontPhotos.length,iCnt:insidePhotos.length,bCnt:brandings.length};\u001b[39m\n\u001b[31m    await dbPut('draft',draft);\u001b[39m\n\u001b[31m    // Also save photos as b64 blobs to draft so they survive exit\u001b[39m\n\u001b[31m    await saveDraftPhotos();\u001b[39m\n\u001b[31m  },500);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveDraftPhotos(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const photoData={\u001b[39m\n\u001b[31m      front:await Promise.all(frontPhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      inside:await Promise.all(insidePhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      addl:await Promise.all(addlPhotos.map(async p=>({b64:await b64(p.blob),desc:p.desc||''}))),\u001b[39m\n\u001b[31m      brand:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,b64:b.blob?await b64(b.blob):null})))\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    await dbPut('draft',{k:'photos',...photoData});\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function checkDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');const wrap=document.getElementById('resume-wrap');\u001b[39m\n\u001b[31m  if(!d||!d.F?.storeName){wrap.innerHTML='';return;}\u001b[39m\n\u001b[31m  const ago=Math.round((Date.now()-d.ts)/60000);\u001b[39m\n\u001b[31m  const agoStr=ago<1?'just now':ago<60?`${ago}m ago`:`${Math.round(ago/60)}h ago`;\u001b[39m\n\u001b[31m  wrap.innerHTML=`<button class=\\\"resume-btn\\\" onclick=\\\"resumeDraft()\\\">\u001b[39m\n\u001b[31m    <div><div style=\\\"font-size:12px;color:rgba(255,255,255,.5);margin-bottom:3px\\\">Resume draft · ${agoStr}</div><div>${d.F.storeName} · ${d.F.brand||'No brand'}</div></div>\u001b[39m\n\u001b[31m    <div style=\\\"text-align:right\\\"><div style=\\\"font-size:13px;color:var(--or)\\\">${d.fCnt||0} photos · ${d.bCnt||0} brandings →</div></div>\u001b[39m\n\u001b[31m  </button>`;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function resumeDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');if(!d)return;\u001b[39m\n\u001b[31m  F=d.F||{};gpsCoords=d.gpsCoords||null;\u001b[39m\n\u001b[31m  if(d.selectedStore){await pickStore(d.selectedStore);}\u001b[39m\n\u001b[31m  else if(d.manualMode){openManual('');if(F.brand)document.getElementById('f-brand').value=F.brand;if(F.storeName)document.getElementById('f-store').value=F.storeName;if(F.address)document.getElementById('f-addr').value=F.address;if(F.mobile)document.getElementById('f-mobile').value=F.mobile;}\u001b[39m\n\u001b[31m  if(F.date)document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  // Restore client chip state\u001b[39m\n\u001b[31m  if(d._clientOtherMode){_clientOtherMode=true;_selectedClient='';const inp=document.getElementById('f-client-other');if(inp&&F.clientName)inp.value=F.clientName;}\u001b[39m\n\u001b[31m  else if(d._selectedClient){_selectedClient=d._selectedClient;_clientOtherMode=false;}\u001b[39m\n\u001b[31m  else if(F.clientName){autoSetClient(F.clientName);}\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  // Restore photos from draft\u001b[39m\n\u001b[31m  const pd=await dbGet('draft','photos');\u001b[39m\n\u001b[31m  if(pd){\u001b[39m\n\u001b[31m    async function b64ToBlob(b64str){if(!b64str)return null;try{const r=await fetch(b64str);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m    for(const p of(pd.front||[])){const bl=await b64ToBlob(p.b64);if(bl)frontPhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.inside||[])){const bl=await b64ToBlob(p.b64);if(bl)insidePhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.addl||[])){const bl=await b64ToBlob(p.b64);if(bl)addlPhotos.push({blob:bl,prev:URL.createObjectURL(bl),desc:p.desc||''});}\u001b[39m\n\u001b[31m    for(const b of(pd.brand||[])){const bl=await b64ToBlob(b.b64);brandings.push({type:b.type,w:b.w,h:b.h,qty:b.qty,blob:bl,prev:bl?URL.createObjectURL(bl):null});}\u001b[39m\n\u001b[31m    toast('Draft restored with '+frontPhotos.length+' photos ✓','success');\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    toast('Draft restored — photos could not be recovered','info');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PHOTOS\u001b[39m\n\u001b[31mfunction updPhotoBadge(type){const arr=type==='front'?frontPhotos:insidePhotos;const el=document.getElementById(type+'-badge');if(el){el.textContent=arr.length;el.className='cnt-badge '+(arr.length?'':'gray');}}\u001b[39m\n\u001b[31mfunction renderPhotos(type){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  const cont=document.getElementById(type+'-cont');const addBtn=document.getElementById('add-'+type);\u001b[39m\n\u001b[31m  updPhotoBadge(type);\u001b[39m\n\u001b[31m  if(arr.length===0){cont.innerHTML=`<div class=\\\"pslot\\\" onclick=\\\"addPhoto('${type}')\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to capture or upload</span><span class=\\\"hi-txt\\\">फोटो खींचें या अपलोड करें</span></div></div>`;addBtn.style.display='none';return;}\u001b[39m\n\u001b[31m  cont.innerHTML=arr.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const badge=isRetained?`<span class=\\\"pbadge\\\" style=\\\"background:#475569\\\">Existing</span>`:`<span class=\\\"pbadge\\\">${fmtSz(p.blob.size)}</span>`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replacePhoto('${type}',${i})\\\" style=\\\"right:36px;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"margin-bottom:12px\\\"><div class=\\\"pslot filled\\\" style=\\\"margin-bottom:8px\\\"><img src=\\\"${p.prev}\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmPhoto('${type}',${i})\\\">×</button>${badge}</div><input type=\\\"text\\\" placeholder=\\\"Comments (optional)\\\" value=\\\"${p.cmt||''}\\\" onchange=\\\"${type==='front'?'frontPhotos':'insidePhotos'}[${i}].cmt=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  addBtn.style.display=arr.length<(type==='inside'?5:3)?'inline-flex':'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// Photo source: 'camera' stamps geo, 'gallery' does not\u001b[39m\n\u001b[31mlet _photoSourceCb=null,_photoSourceQuality=null;·\u001b[39m\n\u001b[31mfunction capPhoto(cb,forceSource,quality){\u001b[39m\n\u001b[31m  // quality override: null=use setting, 'hd', 'compressed'\u001b[39m\n\u001b[31m  _photoSourceCb=cb;_photoSourceQuality=quality||null;\u001b[39m\n\u001b[31m  if(forceSource==='camera'){_doCapture(cb,'camera',quality);return;}\u001b[39m\n\u001b[31m  if(forceSource==='gallery'){_doCapture(cb,'gallery',quality);return;}\u001b[39m\n\u001b[31m  // Show picker\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _doCapture(cb,src,quality){\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  const i=document.createElement('input');\u001b[39m\n\u001b[31m  i.type='file';i.accept='image/*';\u001b[39m\n\u001b[31m  if(src==='camera')i.setAttribute('capture','environment');\u001b[39m\n\u001b[31m  i.style.display='none';\u001b[39m\n\u001b[31m  i.onchange=async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f)return;\u001b[39m\n\u001b[31m    const q=quality||_photoSourceQuality||null;\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      const blob=await compress(f,q==='hd'?1920:q==='compressed'?1280:null,q==='hd'?0.90:q==='compressed'?0.78:null);\u001b[39m\n\u001b[31m      // Only stamp if from camera (live photo)\u001b[39m\n\u001b[31m      const stamped=(src==='camera')?await stampPhoto(blob):blob;\u001b[39m\n\u001b[31m      // Save to device (auto-download trigger)\u001b[39m\n\u001b[31m      savePhotoToDevice(stamped);\u001b[39m\n\u001b[31m      cb({target:{files:[f]},_blob:stamped,_src:src});\u001b[39m\n\u001b[31m    }catch(err){toast('Photo processing failed — try again','error');console.error('_doCapture error:',err);}\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  document.body.appendChild(i);i.click();setTimeout(()=>i.remove(),8000);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction photoSrcCamera(){_doCapture(_photoSourceCb,'camera',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcGallery(){_doCapture(_photoSourceCb,'gallery',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcCancel(){document.getElementById('photo-src-dialog').classList.remove('open');_photoSourceCb=null;}·\u001b[39m\n\u001b[31m// Save photo to device gallery/downloads\u001b[39m\n\u001b[31mfunction savePhotoToDevice(blob){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    const a=document.createElement('a');\u001b[39m\n\u001b[31m    a.href=url;\u001b[39m\n\u001b[31m    a.download='Recce_'+Date.now()+'.jpg';\u001b[39m\n\u001b[31m    a.style.display='none';\u001b[39m\n\u001b[31m    document.body.appendChild(a);a.click();\u001b[39m\n\u001b[31m    setTimeout(()=>{URL.revokeObjectURL(url);a.remove();},1000);\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addPhoto(type){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}${e._src==='camera'&&geoStampEnabled?' · Stamped':''}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31masync function handleCapture(e,type){\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmPhoto(type,i){(type==='front'?frontPhotos:insidePhotos).splice(i,1);renderPhotos(type);saveDraft();}\u001b[39m\n\u001b[31mfunction replacePhoto(type,idx){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m    arr[idx]={...arr[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAddl(){\u001b[39m\n\u001b[31m  const cont=document.getElementById('add-cont');const btn=document.getElementById('add-addl');\u001b[39m\n\u001b[31m  const badge=document.getElementById('addl-badge');if(badge){badge.textContent=`${addlPhotos.length} / 8`;badge.className='cnt-badge '+(addlPhotos.length?'':'gray');}\u001b[39m\n\u001b[31m  cont.innerHTML=addlPhotos.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const sizeInfo=isRetained?'<span style=\\\"color:#475569\\\">Existing</span>':`${fmtSz(p.blob.size)}`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replaceAddl(${i})\\\" style=\\\"top:3px;left:3px;right:auto;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;gap:10px;align-items:start;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--g100)\\\"><div style=\\\"position:relative;flex-shrink:0\\\"><img src=\\\"${p.prev}\\\" style=\\\"width:80px;height:80px;object-fit:cover;border-radius:var(--rs)\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmAddl(${i})\\\" style=\\\"top:3px;right:3px\\\">×</button></div><div style=\\\"flex:1\\\"><input type=\\\"text\\\" placeholder=\\\"Description (optional)\\\" value=\\\"${p.desc||''}\\\" onchange=\\\"addlPhotos[${i}].desc=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"><div style=\\\"font-size:11px;color:var(--g400);margin-top:4px\\\">${sizeInfo}</div></div></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  btn.style.display=addlPhotos.length>=8?'none':'inline-flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction addAdditional(){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  addlPhotos.push({blob:bs,prev:URL.createObjectURL(bs),desc:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderAddl();saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31mfunction rmAddl(i){addlPhotos.splice(i,1);renderAddl();saveDraft();}\u001b[39m\n\u001b[31mfunction replaceAddl(idx){\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m    addlPhotos[idx]={...addlPhotos[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderAddl();saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// BRANDING\u001b[39m\n\u001b[31mfunction calcSqft(w,h){const wf=parseFloat(w),hf=parseFloat(h);if(!wf||!hf)return '';return `${(wf*hf).toFixed(0)} sq.in = ${(wf*hf/144).toFixed(2)} sq.ft`;}\u001b[39m\n\u001b[31mfunction renderBrandings(){\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  const cont=document.getElementById('br-items');\u001b[39m\n\u001b[31m  const hb=document.getElementById('br-hdr-badge');if(hb)hb.textContent=`${brandings.length} ${t(brandings.length!==1?'items':'item',brandings.length!==1?'आइटम':'आइटम')}`;\u001b[39m\n\u001b[31m  cont.innerHTML=brandings.map((b,i)=>`<div class=\\\"bitem\\\"><div class=\\\"bitem-hdr\\\"><div class=\\\"bitem-title\\\">${t('Branding','ब्रांडिंग')} ${i+1}${b.type?' — '+b.type:''}</div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:6px\\\">${i>0?`<button class=\\\"btn-d\\\" onclick=\\\"dupBr(${i})\\\" style=\\\"color:var(--or);border-color:var(--orl)\\\">${t('Dup ↑','डुप ↑')}</button>`:''}<button class=\\\"btn-d\\\" onclick=\\\"rmBr(${i})\\\">${t('Remove','हटाएं')}</button></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\"><label>${t('Type','प्रकार')} <span class=\\\"req\\\">*</span></label><div class=\\\"chip-grid\\\">${BTYPE.map(tp=>`<div class=\\\"chip${b.type===tp?' sel':''}\\\" onclick=\\\"setBType(${i},'${tp.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\"> ${tp}</div>`).join('')}</div></div>\u001b[39m\n\u001b[31m    <div class=\\\"dim-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Width (in)','चौड़ाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.w||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].w=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Height (in)','ऊंचाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.h||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].h=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"max-width:74px\\\"><label>${t('Qty','मात्रा')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.qty||''}\\\" placeholder=\\\"1\\\" inputmode=\\\"numeric\\\" onchange=\\\"brandings[${i}].qty=this.value;saveDraft()\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <span class=\\\"sqft\\\" id=\\\"sf${i}\\\">${calcSqft(b.w,b.h)||t('Enter W × H','W × H दर्ज करें')}</span>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-top:12px\\\"><label>${t('Photo','फोटो')} <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      ${b.prev?`<div class=\\\"pslot filled\\\" onclick=\\\"capBr(${i})\\\"><img src=\\\"${b.prev}\\\"><button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();rmBrPh(${i})\\\">×</button><span class=\\\"pbadge\\\">${b.blob?fmtSz(b.blob.size):'Existing'}</span></div>`:`<div><div class=\\\"pslot\\\" onclick=\\\"capBr(${i})\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\">${t('Tap to capture','दबाकर कैप्चर करें')}</div></div><div style=\\\"display:flex;gap:6px;margin-top:6px\\\"><button class=\\\"atool${(b.quality||imgQuality)==='compressed'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'compressed');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">${t('Compressed','कम्प्रेस्ड')}</button><button class=\\\"atool${(b.quality||imgQuality)==='hd'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'hd');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">HD</button></div></div>`}\u001b[39m\n\u001b[31m    </div></div>`).join('');\u001b[39m\n\u001b[31m  // Only show \\\"Add Another\\\" when last item is fully complete\u001b[39m\n\u001b[31m  const addDiv=document.getElementById('br-add');\u001b[39m\n\u001b[31m  if(addDiv&&brandings.length>0){\u001b[39m\n\u001b[31m    const last=brandings[brandings.length-1];\u001b[39m\n\u001b[31m    const lastComplete=last.type&&last.w&&last.h&&last.qty&&last.prev;\u001b[39m\n\u001b[31m    addDiv.style.display=(lastComplete&&brandings.length<15)?'block':'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updSqft(i){const el=document.getElementById('sf'+i);if(el)el.textContent=calcSqft(brandings[i].w,brandings[i].h)||t('Enter W × H','W × H दर्ज करें');saveDraft();}\u001b[39m\n\u001b[31mfunction setBType(i,tp){brandings[i].type=tp;renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction addBranding(){if(brandings.length>=15){toast(t('Max 15 items','अधिकतम 15 आइटम'),'error');return;}brandings.push({type:'',w:'',h:'',qty:'1',blob:null,prev:null});renderBrandings();}\u001b[39m\n\u001b[31mfunction dupBr(i){if(brandings.length>=10){toast(t('Max 10 items','अधिकतम 10 आइटम'),'error');return;}const s=brandings[i-1];brandings.splice(i,0,{type:s.type,w:s.w,h:s.h,qty:s.qty,blob:null,prev:null});renderBrandings();toast(t('Duplicated — add photo','डुप्लीकेट — फोटो जोड़ें'),'info');}\u001b[39m\n\u001b[31mfunction rmBr(i){brandings.splice(i,1);renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction capBr(i){\u001b[39m\n\u001b[31m  const q=brandings[i]?.quality||imgQuality;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f,q==='hd'?1920:1280,q==='hd'?0.90:0.78));\u001b[39m\n\u001b[31m    brandings[i].blob=bs;brandings[i].prev=URL.createObjectURL(bs);\u001b[39m\n\u001b[31m    brandings[i].fromCamera=(e._src==='camera');\u001b[39m\n\u001b[31m    openAnnot(i);\u001b[39m\n\u001b[31m  },null,q);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmBrPh(i){brandings[i].blob=null;brandings[i].prev=null;renderBrandings();}\u001b[39m\n\u001b[31mfunction setBrQuality(i,q){brandings[i].quality=q;renderBrandings();}·\u001b[39m\n\u001b[31m// VIDEO / DOC\u001b[39m\n\u001b[31mfunction setVideo(v){F.hasVideo=v;document.getElementById('vid-yes').classList.toggle('sel',v);document.getElementById('vid-no').classList.toggle('sel',!v);document.getElementById('vid-sec').style.display=v?'block':'none';saveDraft();}\u001b[39m\n\u001b[31masync function handleVideo(e){videoBlob=e.target.files[0];if(!videoBlob)return;document.getElementById('vid-slot').innerHTML=`<div style=\\\"padding:14px;font-size:13px;color:var(--gn)\\\">✓ ${videoBlob.name} (${fmtSz(videoBlob.size)})</div>`;}\u001b[39m\n\u001b[31mfunction setBranding(v){F.hasBranding=v;document.getElementById('br-yes').classList.toggle('sel',v);document.getElementById('br-no').classList.toggle('sel',!v);document.getElementById('br-add').style.display=v?'block':'none';if(v&&brandings.length===0)addBranding();saveDraft();}\u001b[39m\n\u001b[31masync function handleDoc(e){const f=e.target.files[0];if(!f)return;submissionDoc=f.type.startsWith('image/')?await compress(f,1600,.85):f;const slot=document.getElementById('doc-slot');if(f.type.startsWith('image/')){slot.classList.add('filled');slot.innerHTML=`<img src=\\\"${URL.createObjectURL(submissionDoc)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}else{slot.innerHTML=`<div style=\\\"padding:16px;font-size:13px;color:var(--gn)\\\">✓ ${f.name} (${fmtSz(f.size)})</div>`;}buildReview();}·\u001b[39m\n\u001b[31m// CLIENT CHIPS\u001b[39m\n\u001b[31mfunction renderClientChips(){\u001b[39m\n\u001b[31m  const grid = document.getElementById('client-chips'); if (!grid) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  clientList.forEach(c => {\u001b[39m\n\u001b[31m    const sel = !_clientOtherMode && _selectedClient === c;\u001b[39m\n\u001b[31m    html += `<div class=\\\"cl-chip${sel?' sel':''}\\\" onclick=\\\"selectClientChip('${esc(c)}')\\\">${esc(c)}</div>`;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html += `<div class=\\\"cl-chip cl-chip-other${_clientOtherMode?' sel':''}\\\" onclick=\\\"selectClientOther()\\\"><span class=\\\"en-txt\\\">Other…</span><span class=\\\"hi-txt\\\">अन्य…</span></div>`;\u001b[39m\n\u001b[31m  grid.innerHTML = html;\u001b[39m\n\u001b[31m  document.getElementById('client-other-wrap').style.display = _clientOtherMode ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientChip(name){\u001b[39m\n\u001b[31m  _selectedClient = name; _clientOtherMode = false;\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').value = '';\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientOther(){\u001b[39m\n\u001b[31m  _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onClientOtherInput(){\u001b[39m\n\u001b[31m  _selectedClient = document.getElementById('f-client-other').value.trim();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction getClientName(){\u001b[39m\n\u001b[31m  if (_clientOtherMode) return (document.getElementById('f-client-other')?.value||'').trim();\u001b[39m\n\u001b[31m  return _selectedClient;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction autoSetClient(brandName){\u001b[39m\n\u001b[31m  if (!brandName) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  if (clientList.includes(brandName)){\u001b[39m\n\u001b[31m    _selectedClient = brandName; _clientOtherMode = false;\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    // Not in list — pre-fill the Other field\u001b[39m\n\u001b[31m    _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m    const inp = document.getElementById('f-client-other');\u001b[39m\n\u001b[31m    if (inp && !inp.value) inp.value = brandName;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// STEP VALIDATION\u001b[39m\n\u001b[31mfunction getSD(){if(selectedStore&&!manualMode)return{storeName:selectedStore.name,brand:selectedStore.brand||'',address:selectedStore.address||'',mobile:selectedStore.mobile||''};return{storeName:(document.getElementById('f-store')?.value||'').trim(),brand:document.getElementById('f-brand')?.value||'',address:(document.getElementById('f-addr')?.value||'').trim(),mobile:(document.getElementById('f-mobile')?.value||'').trim()};}\u001b[39m\n\u001b[31mfunction step2(){\u001b[39m\n\u001b[31m  const d=document.getElementById('f-date').value;\u001b[39m\n\u001b[31m  if(!d){toast('Select date','error');return;}\u001b[39m\n\u001b[31m  const sd=getSD();\u001b[39m\n\u001b[31m  if(!sd.storeName){toast('Select or enter store name','error');return;}\u001b[39m\n\u001b[31m  if(!sd.brand){toast('Select a brand','error');document.getElementById('brand-selector').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  if(!sd.address){toast('Enter store address','error');return;}\u001b[39m\n\u001b[31m  const clientName=getClientName();\u001b[39m\n\u001b[31m  if(!clientName){toast(t('Select a client','क्लाइंट चुनें'),'error');document.getElementById('client-chips').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  // Check missing fields filled\u001b[39m\n\u001b[31m  const missAddr=document.getElementById('sc-miss-address');\u001b[39m\n\u001b[31m  if(missAddr&&!missAddr.value.trim()){toast('Enter store address in the highlighted field','error');missAddr.focus();return;}\u001b[39m\n\u001b[31m  const missMob=document.getElementById('sc-miss-mobile');\u001b[39m\n\u001b[31m  // mobile not required — just copy if filled\u001b[39m\n\u001b[31m  if(missMob&&missMob.value.trim()&&!F.mobile)F.mobile=missMob.value.trim();\u001b[39m\n\u001b[31m  Object.assign(F,{date:d,...sd,clientName});saveDraft();\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');showView('form-photos');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction step3(){if(!frontPhotos.length){toast('Add at least 1 front view photo','error');return;}showView('form-video');}\u001b[39m\n\u001b[31mfunction step4(){if(F.hasVideo===undefined||F.hasVideo===null){toast('Select Yes or No for video','error');return;}renderBrandings();showView('form-branding');}\u001b[39m\n\u001b[31mfunction step5(){if(F.hasBranding===undefined||F.hasBranding===null){toast('Select Yes or No for branding space','error');return;}if(F.hasBranding){for(let i=0;i<brandings.length;i++){const b=brandings[i];if(!b.type){toast(`Select branding type for item ${i+1}`,'error');return;}if(!b.w||!b.h){toast(`Enter W and H dimensions for item ${i+1}`,'error');return;}if(!b.qty){toast(`Enter qty for item ${i+1}`,'error');return;}if(!b.blob&&!b.prev){toast(`Add photo for item ${i+1}`,'error');return;}}}renderAddl();buildReview();showView('form-additional');}·\u001b[39m\n\u001b[31m// REVIEW\u001b[39m\n\u001b[31mfunction buildReview(){const el=document.getElementById('rev-body');if(!el)return;const sd=getSD();const cn=getClientName();el.innerHTML=`<div><div class=\\\"rev-lbl\\\">Store</div><div class=\\\"rev-val\\\">${sd.storeName||'—'} · ${sd.brand||'—'}</div><div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">${sd.address||'—'}${sd.mobile?' · '+sd.mobile:''}</div>${gpsCoords?`<div style=\\\"font-size:11px;color:var(--gn);margin-top:3px\\\">📍 ${gpsCoords.lat}, ${gpsCoords.lng} ±${gpsCoords.acc}m</div>`:''}</div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Client</div><div class=\\\"rev-val\\\" style=\\\"color:${cn?'var(--nv)':'var(--rd)'}\\\">${cn||'⚠ Not selected — required'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Photos — Front · Inside · Additional</div><div class=\\\"rev-val\\\">${frontPhotos.length} · ${insidePhotos.length} · ${addlPhotos.length}</div><div class=\\\"rev-photos\\\">${[...frontPhotos,...insidePhotos].slice(0,6).map(p=>`<img class=\\\"rev-thumb\\\" src=\\\"${p.prev}\\\">`).join('')}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Video · Branding items</div><div class=\\\"rev-val\\\">${F.hasVideo?'Yes':'No'} · ${brandings.length} item(s)</div></div>${F.hasBranding&&brandings.length?`<div style=\\\"margin-top:8px\\\">${brandings.map((b,i)=>`<div style=\\\"font-size:12px;color:var(--g600);padding:4px 0;border-bottom:1px solid var(--g100)\\\">${i+1}. ${b.type||'No type'} — ${b.w||'?'}×${b.h||'?'}\\\" × ${b.qty||'?'} — ${calcSqft(b.w,b.h)||'?'}</div>`).join('')}</div>`:''}<div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Additional photos <span style=\\\"font-size:11px;color:var(--g400)\\\">(optional)</span></div><div class=\\\"rev-val\\\" style=\\\"color:${addlPhotos.length?'var(--gn)':'var(--g500)'}\\\">${addlPhotos.length?`✓ ${addlPhotos.length} photo(s) added`:'None added'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Mandatory document</div><div class=\\\"rev-val\\\" style=\\\"color:${(submissionDoc||_docExistingUrl)?'var(--gn)':'var(--rd)'}\\\">${(submissionDoc||_docExistingUrl)?'✓ Uploaded':'⚠ Missing — required'}</div></div>`;}·\u001b[39m\n\u001b[31m// SUBMIT\u001b[39m\n\u001b[31masync function submitRecce(){\u001b[39m\n\u001b[31m  if(!submissionDoc&&!_docExistingUrl){toast('Upload mandatory doc first','error');return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('sub-btn');btn.disabled=true;btn.textContent='Saving…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const isEdit=!!(F.editingId);\u001b[39m\n\u001b[31m    const id=isEdit?F.editingId:('RC_'+Date.now()+'_'+Math.random().toString(36).slice(2,6).toUpperCase());\u001b[39m\n\u001b[31m    const sd=getSD();\u001b[39m\n\u001b[31m    const _hub=_recceHubUser();\u001b[39m\n\u001b[31m    const entry={id,timestamp:isEdit?(await dbGet('subs',id))?.timestamp||new Date().toISOString():new Date().toISOString(),editedAt:isEdit?new Date().toISOString():undefined,status:'pending',submittedBy:_hub.empId||null,submittedByName:_hub.name||null,data:{...F,...sd,gpsCoords,frontPhotos:await Promise.all(frontPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),insidePhotos:await Promise.all(insidePhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),videoNote:F.hasVideo&&videoBlob?`Video local (${fmtSz(videoBlob.size)}) — share via WhatsApp`:null,videoCmt:document.getElementById('f-vid-cmt')?.value||'',brandings:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:calcSqft(b.w,b.h),photoB64:b.blob?await b64(b.blob):null,existingUrl:b.existingUrl||null}))),addlPhotos:await Promise.all(addlPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,desc:p.desc,existingUrl:p.existingUrl||null}))),docB64:submissionDoc?await b64(submissionDoc):null,_docExistingUrl:_docExistingUrl||null}};\u001b[39m\n\u001b[31m    entry.campaignId       = _selectedCampaignId || null;\u001b[39m\n\u001b[31m    entry.notifySupervisor = _notifySupervisor   || false;\u001b[39m\n\u001b[31m    await dbPut('subs',entry);\u001b[39m\n\u001b[31m    await dbDel('draft','current');\u001b[39m\n\u001b[31m    toast(isEdit?'Recce updated ✓':'Recce saved ✓','success');\u001b[39m\n\u001b[31m    if(navigator.onLine)syncNow();\u001b[39m\n\u001b[31m    showView('home');loadHome();checkDraft();\u001b[39m\n\u001b[31m  }catch(err){toast('Error: '+err.message,'error');}\u001b[39m\n\u001b[31m  finally{btn.disabled=false;btn.textContent='Submit Recce ✓';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// SYNC\u001b[39m\n\u001b[31masync function syncNow() {\u001b[39m\n\u001b[31m  if (!navigator.onLine) { toast('Offline — sync when back online', 'info'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('sync-btn');\u001b[39m\n\u001b[31m  const SYNC_ICON = '<svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg>Sync';\u001b[39m\n\u001b[31m  if (btn) { btn.innerHTML = '<span class=\\\"spin\\\">↻</span> Syncing'; btn.disabled = true; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const all      = await dbAll('subs');\u001b[39m\n\u001b[31m    const pend     = all.filter(s => s.status === 'pending' || s.status === 'failed');\u001b[39m\n\u001b[31m    const backfill = all.filter(s => s.status === 'synced' && !s.gasAt);\u001b[39m\n\u001b[31m    if (!pend.length && !backfill.length) { toast('All synced ✓', 'success'); return; }·\u001b[39m\n\u001b[31m    const gasUrl = (await cfg('gas-url')) || DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    function fireGas(s) {\u001b[39m\n\u001b[31m      if (!gasUrl) return;\u001b[39m\n\u001b[31m      fetch(gasUrl, { method:'POST', mode:'no-cors',\u001b[39m\n\u001b[31m        body: JSON.stringify({ action:'syncSheet', submission: s }) })\u001b[39m\n\u001b[31m        .catch(() => {});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    let ok = 0;\u001b[39m\n\u001b[31m    for (const s of pend) {\u001b[39m\n\u001b[31m      // Fire Sheet sync (no-cors fire-and-forget — writes row to Google Sheet)\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      // Primary: upload photos → auto-trigger slides → generate report → store in PostgreSQL\u001b[39m\n\u001b[31m      const { ok: pgOk, viewUrl } = await syncToPostgres(s);\u001b[39m\n\u001b[31m      if (pgOk) {\u001b[39m\n\u001b[31m        s.status = 'synced'; s.syncedAt = new Date().toISOString();\u001b[39m\n\u001b[31m        if (viewUrl) s.viewUrl = viewUrl;\u001b[39m\n\u001b[31m        await dbPut('subs', s); ok++;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        s.status = 'failed'; await dbPut('subs', s);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Backfill: entries synced to Postgres but never reached Sheet GAS\u001b[39m\n\u001b[31m    for (const s of backfill) {\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      await dbPut('subs', s);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if (backfill.length) toast(`Sent ${backfill.length} older entries to Sheet`, 'info');·\u001b[39m\n\u001b[31m    await cfg('last-sync', new Date().toISOString());\u001b[39m\n\u001b[31m    if (pend.length) toast(`Synced ${ok}/${pend.length}`, ok === pend.length ? 'success' : 'error');\u001b[39m\n\u001b[31m    loadHome();\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.innerHTML = SYNC_ICON; btn.disabled = false; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN HOME ──────────────────────────────────────────────\u001b[39m\n\u001b[31masync function loadHomeAdmin() {\u001b[39m\n\u001b[31m  // Adapt UI for admin view\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const _sh = document.querySelector('.sh'); if (_sh) _sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = 'All Submissions';\u001b[39m\n\u001b[31m  const slbls = document.querySelectorAll('.slbl');\u001b[39m\n\u001b[31m  if (slbls[0]) slbls[0].textContent = 'Showing';\u001b[39m\n\u001b[31m  if (slbls[1]) slbls[1].textContent = 'Agents';·\u001b[39m\n\u001b[31m  // Back-to-menu button for supervisors\u001b[39m\n\u001b[31m  if (_isSupervisor() && !document.getElementById('sup-back-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => { document.getElementById('sup-back-btn').remove(); renderSupLanding(); };\u001b[39m\n\u001b[31m    const content = document.querySelector('#view-home .content');\u001b[39m\n\u001b[31m    content.prepend(bb);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Show filter bar — restore if hidden by renderSupLanding, else inject fresh\u001b[39m\n\u001b[31m  const _existingFb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (_existingFb) { _existingFb.style.display = ''; }\u001b[39m\n\u001b[31m  if (!_existingFb) {\u001b[39m\n\u001b[31m    const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m    const fb = document.createElement('div');\u001b[39m\n\u001b[31m    fb.id = 'admin-filter-bar';\u001b[39m\n\u001b[31m    fb.className = 'af-bar';\u001b[39m\n\u001b[31m    fb.innerHTML =\u001b[39m\n\u001b[31m      `<div class=\\\"af-grid\\\">\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-agent\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Agents</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-brand\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Brands</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-client\\\" onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Clients</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-period\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">All Time</option>\u001b[39m\n\u001b[31m          <option value=\\\"7\\\">Last 7 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"30\\\">Last 30 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"90\\\">Last 3 months</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-group\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"date\\\">Sort: Recent</option>\u001b[39m\n\u001b[31m          <option value=\\\"agent\\\">Group: Agent</option>\u001b[39m\n\u001b[31m          <option value=\\\"brand\\\">Group: Brand</option>\u001b[39m\n\u001b[31m          <option value=\\\"client\\\">Group: Client</option>\u001b[39m\n\u001b[31m          <option value=\\\"city\\\">Group: City</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m        <input class=\\\"af-inp\\\" id=\\\"af-search\\\" type=\\\"text\\\" placeholder=\\\"🔍 Search store or city…\\\" oninput=\\\"renderAdminList()\\\" style=\\\"flex:1;min-width:120px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"del-toggle-btn\\\" id=\\\"del-toggle-btn\\\" onclick=\\\"toggleDeletedView()\\\" style=\\\"flex-shrink:0\\\">📋 View Deleted</button>\u001b[39m\n\u001b[31m        ${_isSupervisor() ? `<button class=\\\"del-toggle-btn\\\" id=\\\"pending-job-btn\\\" onclick=\\\"togglePendingJobView()\\\" style=\\\"flex-shrink:0;background:#fef3c7;color:#92400e;border-color:#f59e0b\\\">⚑ Unlinked <span id=\\\"pending-job-count\\\" style=\\\"font-weight:900\\\"></span></button>` : ''}\u001b[39m\n\u001b[31m        ${_adminUnlocked ? `<button class=\\\"del-toggle-btn\\\" id=\\\"regen-rpt-btn\\\" onclick=\\\"regenAllReports()\\\" style=\\\"flex-shrink:0\\\">&#x21BB; Regen Reports</button>` : ''}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    sh.parentNode.insertBefore(fb, sh);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Fetch\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  list.innerHTML = '<div style=\\\"text-align:center;padding:40px\\\"><div class=\\\"spinner\\\"></div></div>';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?order=submitted_at.desc&limit=500`, { headers: _RC_READ });\u001b[39m\n\u001b[31m    _adminRows = resp.ok ? await resp.json() : [];\u001b[39m\n\u001b[31m    document.getElementById('stat-total').textContent = _adminRows.length;\u001b[39m\n\u001b[31m    if (resp.ok) {\u001b[39m\n\u001b[31m      const now = new Date();\u001b[39m\n\u001b[31m      document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m        'Loaded ' + now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Populate agent dropdown\u001b[39m\n\u001b[31m    const agents = [...new Set(_adminRows.map(r => r.submitted_by).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-agent').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Agents (${agents.length})</option>` +\u001b[39m\n\u001b[31m      agents.map(a => `<option value=\\\"${a}\\\">${a}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate brand dropdown\u001b[39m\n\u001b[31m    const brands = [...new Set(_adminRows.map(r => r.brand).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-brand').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Brands (${brands.length})</option>` +\u001b[39m\n\u001b[31m      brands.map(b => `<option value=\\\"${b}\\\">${b}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate client dropdown\u001b[39m\n\u001b[31m    const clients = [...new Set(_adminRows.map(r => r.client_name).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-client').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Clients (${clients.length})</option>` +\u001b[39m\n\u001b[31m      clients.map(c => `<option value=\\\"${c}\\\">${c}</option>`).join('');·\u001b[39m\n\u001b[31m    // Update pending-job count badge\u001b[39m\n\u001b[31m    const unlinkedCount = _adminRows.filter(r => !r.deleted_at && !r.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinkedCount ? `(${unlinkedCount})` : '';·\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">⚠️</div><div class=\\\"empty-txt\\\">Could not load — check connection</div></div>';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction togglePendingJobView() {\u001b[39m\n\u001b[31m  _pendingJobFilter = !_pendingJobFilter;\u001b[39m\n\u001b[31m  _showDeletedView  = false;\u001b[39m\n\u001b[31m  const btn = document.getElementById('pending-job-btn');\u001b[39m\n\u001b[31m  if (btn) btn.style.background = _pendingJobFilter ? '#f59e0b' : '#fef3c7';\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function openLinkJobModal(subId, storeName) {\u001b[39m\n\u001b[31m  _linkJobSubId = subId;\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  const storeEl = document.getElementById('link-job-store');\u001b[39m\n\u001b[31m  const sel = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  if (!modal) return;\u001b[39m\n\u001b[31m  if (storeEl) storeEl.textContent = storeName || subId;\u001b[39m\n\u001b[31m  if (errEl) errEl.textContent = '';\u001b[39m\n\u001b[31m  // Load campaigns into dropdown\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (!_campaignList.length) {\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m      _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  if (sel) {\u001b[39m\n\u001b[31m    sel.innerHTML = '<option value=\\\"\\\">— Select campaign —</option>' +\u001b[39m\n\u001b[31m      _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  modal.style.display = 'flex';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeLinkJobModal() {\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  if (modal) modal.style.display = 'none';\u001b[39m\n\u001b[31m  _linkJobSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function saveLinkJob() {\u001b[39m\n\u001b[31m  const sel    = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl  = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  const campId = sel?.value || '';\u001b[39m\n\u001b[31m  if (!campId) { if (errEl) errEl.textContent = 'Select a campaign'; return; }\u001b[39m\n\u001b[31m  if (!_linkJobSubId) return;\u001b[39m\n\u001b[31m  const btn = document.querySelector('#modal-link-job button[onclick=\\\"saveLinkJob()\\\"]');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Linking…'; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(_linkJobSubId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ campaign_id: campId }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Patch failed');\u001b[39m\n\u001b[31m    // Update local cache\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === _linkJobSubId);\u001b[39m\n\u001b[31m    if (idx >= 0) _adminRows[idx].campaign_id = campId;\u001b[39m\n\u001b[31m    // Update pending count badge\u001b[39m\n\u001b[31m    const unlinked = _adminRows.filter(x => !x.deleted_at && !x.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinked ? `(${unlinked})` : '';\u001b[39m\n\u001b[31m    closeLinkJobModal();\u001b[39m\n\u001b[31m    toast('Job linked ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    if (errEl) errEl.textContent = 'Failed to link — try again';\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.disabled = false; btn.textContent = '🔗 Link Job'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAdminList() {\u001b[39m\n\u001b[31m  const agent  = document.getElementById('af-agent')?.value  || '';\u001b[39m\n\u001b[31m  const brand  = document.getElementById('af-brand')?.value  || '';\u001b[39m\n\u001b[31m  const period = document.getElementById('af-period')?.value || '';\u001b[39m\n\u001b[31m  const search = (document.getElementById('af-search')?.value || '').toLowerCase().trim();\u001b[39m\n\u001b[31m  const group  = document.getElementById('af-group')?.value  || 'date';·\u001b[39m\n\u001b[31m  // Pending-job filter overrides deleted/normal modes\u001b[39m\n\u001b[31m  let rows;\u001b[39m\n\u001b[31m  if (_pendingJobFilter) {\u001b[39m\n\u001b[31m    rows = _adminRows.filter(r => !r.deleted_at && !r.campaign_id);\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows = _showDeletedView\u001b[39m\n\u001b[31m      ? _adminRows.filter(r => r.deleted_at)\u001b[39m\n\u001b[31m      : _adminRows.filter(r => !r.deleted_at);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const client = document.getElementById('af-client')?.value || '';\u001b[39m\n\u001b[31m  if (agent)  rows = rows.filter(r => r.submitted_by === agent);\u001b[39m\n\u001b[31m  if (brand)  rows = rows.filter(r => r.brand === brand);\u001b[39m\n\u001b[31m  if (client) rows = rows.filter(r => r.client_name === client);\u001b[39m\n\u001b[31m  if (search) rows = rows.filter(r => (r.store_name||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.city||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.client_name||'').toLowerCase().includes(search));\u001b[39m\n\u001b[31m  if (period && !_showDeletedView) {\u001b[39m\n\u001b[31m    const cut = new Date(); cut.setDate(cut.getDate() - parseInt(period));\u001b[39m\n\u001b[31m    rows = rows.filter(r => new Date(r.submitted_at) >= cut);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const uniqueAgents = new Set(rows.map(r => r.submitted_by).filter(Boolean)).size;\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = rows.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = uniqueAgents;\u001b[39m\n\u001b[31m  const deletedCount = _adminRows.filter(r => r.deleted_at).length;\u001b[39m\n\u001b[31m  const delBtn = document.getElementById('del-toggle-btn');\u001b[39m\n\u001b[31m  if (delBtn) {\u001b[39m\n\u001b[31m    if (_showDeletedView) {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 Hide Deleted (${deletedCount})` : '📋 Hide Deleted';\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 View Deleted (${deletedCount})` : '📋 View Deleted';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    delBtn.classList.toggle('active', _showDeletedView);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!rows.length) {\u001b[39m\n\u001b[31m    list.innerHTML = _showDeletedView\u001b[39m\n\u001b[31m      ? '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">✅</div><div class=\\\"empty-txt\\\">No deleted recces</div></div>'\u001b[39m\n\u001b[31m      : '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">🔍</div><div class=\\\"empty-txt\\\">No matching submissions</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (group === 'agent') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.submitted_by||'').localeCompare(b.submitted_by||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.submitted_by || 'Unknown';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">👤 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'brand') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.brand||'').localeCompare(b.brand||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.brand || 'No Brand';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🏷 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'client') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.client_name||'').localeCompare(b.client_name||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.client_name || 'No Client';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🤝 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'city') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.city||'').localeCompare(b.city||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.city || 'No City';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">📍 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows.sort((a,b) => new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    rows.forEach(r => { html += adminCard(r); });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminCard(r) {\u001b[39m\n\u001b[31m  const dt    = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds    = dt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m  const tm    = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const photos = (r.front_photos||0) + (r.inside_photos||0) + (r.addl_photos||0);\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const canDelete  = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const canArchive = _RECCE_CFG_ADMINS.includes(hub?.empId) && !r.client_archived;·\u001b[39m\n\u001b[31m  // Client status badge\u001b[39m\n\u001b[31m  const clientStatusMap = {\u001b[39m\n\u001b[31m    approved:              {t:'✓ Approved',    s:'color:#166534;background:#dcfce7;border:1px solid #86efac'},\u001b[39m\n\u001b[31m    rejected:              {t:'✕ Rejected',    s:'color:#991b1b;background:#fee2e2;border:1px solid #fca5a5'},\u001b[39m\n\u001b[31m    approved_with_changes: {t:'✎ Approved w/ Comments', s:'color:#92400e;background:#fef3c7;border:1px solid #fcd34d'},\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const csCfg = clientStatusMap[r.client_status];\u001b[39m\n\u001b[31m  const clientStatusBadge = csCfg\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;${csCfg.s}\\\">${csCfg.t}</span>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const archiveBadge = r.client_archived\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;color:#475569;background:#f1f5f9;border:1px solid #cbd5e1\\\">⬚ Client hidden</span>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  if (r.deleted_at) {\u001b[39m\n\u001b[31m    const delDt = new Date(r.deleted_at);\u001b[39m\n\u001b[31m    const delDs = delDt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m    const reasonLabel = r.deletion_reason === 'wrong' ? 'Wrong' : r.deletion_reason === 'duplicate' ? 'Duplicate' : 'Test';\u001b[39m\n\u001b[31m    return `<div class=\\\"asc deleted-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m        <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m            <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds}</span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m          <span class=\\\"del-reason-tag\\\">❌ ${reasonLabel}</span>\u001b[39m\n\u001b[31m          <div class=\\\"del-by-txt\\\">by ${r.deleted_by||'?'} · ${delDs}</div>\u001b[39m\n\u001b[31m          ${canDelete ? `<button class=\\\"restore-btn\\\" onclick=\\\"event.stopPropagation();restoreRecce('${r.sub_id}')\\\">↩ Restore</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Submitted by ${r.submitted_by||'?'}</div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const chips = [\u001b[39m\n\u001b[31m    photos > 0   ? `📷 ${photos} photo${photos!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.has_video  ? '🎥 Video' : null,\u001b[39m\n\u001b[31m    r.has_branding ? `🪧 ${r.branding_count} branding${r.branding_count!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.city       ? `📍 ${r.city}` : (r.address ? `📍 ${r.address}` : null),\u001b[39m\n\u001b[31m    r.view_url   ? '👁 View available' : null,\u001b[39m\n\u001b[31m  ].filter(Boolean);·\u001b[39m\n\u001b[31m  const delBtnHtml = canDelete\u001b[39m\n\u001b[31m    ? `<button class=\\\"del-btn\\\" onclick=\\\"event.stopPropagation();openDeleteModal('${r.sub_id}')\\\" title=\\\"Delete recce\\\">🗑</button>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const editReqHtml = r.edit_assigned_to\u001b[39m\n\u001b[31m    ? `<span class=\\\"edit-req-badge\\\">✏ Edit sent to ${r.edit_assigned_to}</span>`\u001b[39m\n\u001b[31m    : (_isSupervisor()\u001b[39m\n\u001b[31m        ? `<button class=\\\"req-edit-btn\\\" onclick=\\\"event.stopPropagation();openEditRequestModal('${r.sub_id}')\\\">✏ Request Edit</button>`\u001b[39m\n\u001b[31m        : '');·\u001b[39m\n\u001b[31m  const editRow = editReqHtml\u001b[39m\n\u001b[31m    ? `<div style=\\\"margin-top:6px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">${editReqHtml}</div>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const showPdfBtn = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m  const pdfClass = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m  const pdfLabel = '📄 PDF';\u001b[39m\n\u001b[31m  const linkJobBtn = (_pendingJobFilter && _isSupervisor() && !r.campaign_id)\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:#f59e0b;color:#000;border-color:#f59e0b;font-weight:700\\\" onclick=\\\"event.stopPropagation();openLinkJobModal('${r.sub_id}','${(r.store_name||'Unknown').replace(/'/g,'\\\\\\\\\\\\'')}')\\\">🔗 Link Job</button>`\u001b[39m\n\u001b[31m    : (r.campaign_id ? `<span style=\\\"font-size:10px;color:var(--g400);align-self:center\\\">🔗 ${r.campaign_id}</span>` : '');\u001b[39m\n\u001b[31m  const archiveBtn = canArchive\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:rgba(99,102,241,.08);border-color:var(--nv);color:var(--nv)\\\" onclick=\\\"event.stopPropagation();archiveRecce('${r.sub_id}')\\\">⛚ Archive</button>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const btnsRow = `<div class=\\\"rpt-btns\\\">\u001b[39m\n\u001b[31m    <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openAdminRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m    ${showPdfBtn ? `<button class=\\\"${pdfClass}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">${pdfLabel}</button>` : ''}\u001b[39m\n\u001b[31m    ${linkJobBtn}\u001b[39m\n\u001b[31m    ${archiveBtn}\u001b[39m\n\u001b[31m  </div>`;·\u001b[39m\n\u001b[31m  return `<div class=\\\"asc\\\">\u001b[39m\n\u001b[31m    <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m      <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m          ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          ${r.client_name&&r.client_name!==r.brand?`<span class=\\\"client-tag\\\">🤝 ${r.client_name}</span>`:''}\u001b[39m\n\u001b[31m          <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds} · ${tm}</span>\u001b[39m\n\u001b[31m          ${clientStatusBadge}\u001b[39m\n\u001b[31m          ${archiveBadge}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <span class=\\\"asc-agent\\\">👤 ${r.submitted_by||'?'}</span>\u001b[39m\n\u001b[31m        ${delBtnHtml}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    ${chips.length?`<div class=\\\"asc-chips\\\">${chips.map(c=>`<span class=\\\"asc-chip\\\">${c}</span>`).join('')}</div>`:''}\u001b[39m\n\u001b[31m    ${editRow}\u001b[39m\n\u001b[31m    ${btnsRow}\u001b[39m\n\u001b[31m  </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _ensurePdfOverlay() {\u001b[39m\n\u001b[31m  if (document.getElementById('pdf-wait-ov')) return;\u001b[39m\n\u001b[31m  const ov = document.createElement('div');\u001b[39m\n\u001b[31m  ov.id = 'pdf-wait-ov';\u001b[39m\n\u001b[31m  ov.innerHTML = '<div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Generating PDF…</div><div class=\\\"po-sub\\\" id=\\\"pw-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"pw-pfill\\\"></div></div>';\u001b[39m\n\u001b[31m  document.body.appendChild(ov);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _showPdfOverlay(msg) {\u001b[39m\n\u001b[31m  _ensurePdfOverlay();\u001b[39m\n\u001b[31m  document.getElementById('pw-sub').textContent = msg || '';\u001b[39m\n\u001b[31m  document.getElementById('pw-pfill').style.width = '0%';\u001b[39m\n\u001b[31m  document.getElementById('pdf-wait-ov').style.display = 'flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _hidePdfOverlay() {\u001b[39m\n\u001b[31m  const ov = document.getElementById('pdf-wait-ov');\u001b[39m\n\u001b[31m  if (ov) ov.style.display = 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function openPdf(subId, pdfUrl, viewUrl) {\u001b[39m\n\u001b[31m  if (pdfUrl) { window.open(pdfUrl, '_blank'); return; }\u001b[39m\n\u001b[31m  if (!viewUrl) {\u001b[39m\n\u001b[31m    toast('Report view not available yet — please try after the report is generated.', 'info');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _showPdfOverlay('Requesting PDF generation…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type': 'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({type: 'regen-pdf', subId, viewUrl})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  let attempts = 0;\u001b[39m\n\u001b[31m  const MAX = 24;\u001b[39m\n\u001b[31m  const poll = async () => {\u001b[39m\n\u001b[31m    attempts++;\u001b[39m\n\u001b[31m    const pct = Math.min(88, Math.round(attempts / MAX * 88));\u001b[39m\n\u001b[31m    document.getElementById('pw-pfill').style.width = pct + '%';\u001b[39m\n\u001b[31m    const left = Math.ceil((MAX - attempts) * 5);\u001b[39m\n\u001b[31m    document.getElementById('pw-sub').textContent = 'Checking… (' + left + 's remaining)';\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const res = await fetch('/db/submissions?sub_id=eq.' + subId + '&select=pdf_url', {\u001b[39m\n\u001b[31m        headers: {'Content-Profile': 'recce', 'Accept-Profile': 'recce'}\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      const rows = await res.json();\u001b[39m\n\u001b[31m      if (rows && rows[0] && rows[0].pdf_url) {\u001b[39m\n\u001b[31m        document.getElementById('pw-pfill').style.width = '100%';\u001b[39m\n\u001b[31m        setTimeout(() => { _hidePdfOverlay(); window.open(rows[0].pdf_url, '_blank'); }, 400);\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(_) {}\u001b[39m\n\u001b[31m    if (attempts >= MAX) { _hidePdfOverlay(); toast('PDF generation timed out. Please try again later.', 'error'); return; }\u001b[39m\n\u001b[31m    setTimeout(poll, 5000);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  setTimeout(poll, 4000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openAdminRecce(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];·\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">\u001b[39m\n\u001b[31m         📍 View on Google Maps (${Number(r.gps_lat).toFixed(4)}, ${Number(r.gps_lng).toFixed(4)})\u001b[39m\n\u001b[31m       </a>` : '';·\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} ft × ${b.h||'?'} ft · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos not yet available — field agent must re-sync from their device to upload view\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Submission Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">👤 ${r.submitted_by||'Unknown'}</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            ${meta.videoCmt?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500);font-size:12px\\\">${meta.videoCmt}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m          ${(()=>{\u001b[39m\n\u001b[31m            const hub2 = _recceHubUser();\u001b[39m\n\u001b[31m            const isHP = _RECCE_CFG_ADMINS.includes(hub2?.empId);\u001b[39m\n\u001b[31m            const csMap = {\u001b[39m\n\u001b[31m              approved:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#166534;background:#dcfce7\\\">✓ Approved</span>',\u001b[39m\n\u001b[31m              rejected:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#991b1b;background:#fee2e2\\\">✕ Rejected</span>',\u001b[39m\n\u001b[31m              approved_with_changes: '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#92400e;background:#fef3c7\\\">✎ Approved w/ Comments</span>',\u001b[39m\n\u001b[31m            };\u001b[39m\n\u001b[31m            const csBadge = csMap[r.client_status] || '';\u001b[39m\n\u001b[31m            const approvedAt = r.client_approved_at\u001b[39m\n\u001b[31m              ? new Date(r.client_approved_at).toLocaleString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit',timeZone:'Asia/Kolkata'})\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const pdfLink = r.client_approval_pdf_url\u001b[39m\n\u001b[31m              ? `<a href=\\\"${r.client_approval_pdf_url}\\\" target=\\\"_blank\\\" style=\\\"font-size:12px;color:var(--or);text-decoration:none\\\">⬇ Approval PDF</a>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const archAct = isHP && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveRecce('${r.sub_id}')\\\" style=\\\"font-size:12px;color:var(--nv);background:none;border:1px solid var(--nv);border-radius:6px;padding:4px 10px;cursor:pointer\\\">⦽ Archive from client</button>`\u001b[39m\n\u001b[31m              : (r.client_archived ? '<span style=\\\"font-size:11px;color:var(--g400)\\\">⦽ Hidden from client</span>' : '');\u001b[39m\n\u001b[31m            const campAct = isHP && r.campaign_id && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveAllForCampaign('${r.campaign_id}')\\\" style=\\\"font-size:11px;color:#991b1b;background:none;border:1px solid #fca5a5;border-radius:6px;padding:3px 8px;cursor:pointer\\\">Archive ALL for ${r.campaign_id}</button>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            if (!csBadge && !pdfLink && !archAct) return '';\u001b[39m\n\u001b[31m            return `<div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m              <div class=\\\"ardl-lbl\\\">Client Approval</div>\u001b[39m\n\u001b[31m              ${csBadge ? `<div style=\\\"margin-bottom:5px\\\">${csBadge}${approvedAt ? ' <span style=\\\"font-size:11px;color:var(--g400)\\\">' + approvedAt + '</span>' : ''}</div>` : ''}\u001b[39m\n\u001b[31m              ${r.client_comment ? `<div style=\\\"font-size:12px;color:var(--g600);background:var(--g50);border-radius:6px;padding:7px 10px;margin-bottom:5px\\\">\\\"${r.client_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m              ${pdfLink ? `<div style=\\\"margin-bottom:4px\\\">${pdfLink}</div>` : ''}\u001b[39m\n\u001b[31m              ${archAct ? `<div style=\\\"margin-bottom:4px\\\">${archAct}</div>` : ''}\u001b[39m\n\u001b[31m              ${campAct ? `<div>${campAct}</div>` : ''}\u001b[39m\n\u001b[31m            </div>`;\u001b[39m\n\u001b[31m          })()}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeAdminDetail() {\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveRecce(subId) {\u001b[39m\n\u001b[31m  if (!confirm('Archive this recce from client view? The client will no longer see it.')) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(subId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) Object.assign(_adminRows[idx], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    toast('Archived from client view ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveAllForCampaign(campaignId) {\u001b[39m\n\u001b[31m  if (!confirm(`Archive ALL recces for campaign \\\"${campaignId}\\\" from client view?\\\\nClients will no longer see any recce from this campaign.`)) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?campaign_id=eq.${encodeURIComponent(campaignId)}&client_archived=eq.false`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    _adminRows.forEach((row, i) => {\u001b[39m\n\u001b[31m      if (row.campaign_id === campaignId) Object.assign(_adminRows[i], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    toast(`All recces for ${campaignId} archived ✓`, 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function regenAllReports() {\u001b[39m\n\u001b[31m  if (!_adminUnlocked) { toast('Admin access required', 'error'); return; }\u001b[39m\n\u001b[31m  const rows = _adminRows.filter(r => !r.deleted_at && r.photo_urls);\u001b[39m\n\u001b[31m  if (!rows.length) { toast('No synced rows with photos found', 'error'); return; }·\u001b[39m\n\u001b[31m  const btn = document.getElementById('regen-rpt-btn');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Regenerating…'; }\u001b[39m\n\u001b[31m  toast(`Regenerating ${rows.length} reports…`, 'info');·\u001b[39m\n\u001b[31m  let done = 0, failed = 0;\u001b[39m\n\u001b[31m  for (const r of rows) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const photoUrls = typeof r.photo_urls === 'string' ? JSON.parse(r.photo_urls) : (r.photo_urls || {});\u001b[39m\n\u001b[31m      let meta = {};\u001b[39m\n\u001b[31m      try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m      const entry = {\u001b[39m\n\u001b[31m        id: r.sub_id,\u001b[39m\n\u001b[31m        timestamp: r.submitted_at,\u001b[39m\n\u001b[31m        submittedBy: r.submitted_by,\u001b[39m\n\u001b[31m        data: {\u001b[39m\n\u001b[31m          storeName:    r.store_name,\u001b[39m\n\u001b[31m          brand:        r.brand,\u001b[39m\n\u001b[31m          clientName:   r.client_name,\u001b[39m\n\u001b[31m          date:         r.visit_date,\u001b[39m\n\u001b[31m          address:      r.address,\u001b[39m\n\u001b[31m          city:         r.city,\u001b[39m\n\u001b[31m          mobile:       r.mobile,\u001b[39m\n\u001b[31m          gpsCoords:    (r.gps_lat && r.gps_lng) ? { lat: r.gps_lat, lng: r.gps_lng } : null,\u001b[39m\n\u001b[31m          hasVideo:     r.has_video,\u001b[39m\n\u001b[31m          videoNote:    meta.videoNote || '',\u001b[39m\n\u001b[31m          videoCmt:     meta.videoCmt  || '',\u001b[39m\n\u001b[31m          frontPhotos:  (photoUrls.front   || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          insidePhotos: (photoUrls.inside  || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          addlPhotos:   (photoUrls.addl    || []).map(() => ({ desc: '' })),\u001b[39m\n\u001b[31m          brandings:    (meta.brandings    || []),\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      };·\u001b[39m\n\u001b[31m      const html = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m      const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m        method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m        body: JSON.stringify({ type: 'save-view', subId: r.sub_id, html })\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!vResp.ok) { failed++; continue; }\u001b[39m\n\u001b[31m      const vr = await vResp.json();\u001b[39m\n\u001b[31m      if (!vr.success) { failed++; continue; }·\u001b[39m\n\u001b[31m      if (vr.url && vr.url !== r.view_url) {\u001b[39m\n\u001b[31m        await fetch(`${_RC_BASE}/submissions?sub_id=eq.${r.sub_id}`, {\u001b[39m\n\u001b[31m          method: 'PATCH', headers: _RC_WRITE,\u001b[39m\n\u001b[31m          body: JSON.stringify({ view_url: vr.url })\u001b[39m\n\u001b[31m        });\u001b[39m\n\u001b[31m        const idx = _adminRows.findIndex(x => x.sub_id === r.sub_id);\u001b[39m\n\u001b[31m        if (idx >= 0) _adminRows[idx].view_url = vr.url;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      done++;\u001b[39m\n\u001b[31m    } catch(e) { failed++; }\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = false; btn.textContent = '↻ Regen Reports'; }\u001b[39m\n\u001b[31m  toast(`Done: ${done} regenerated${failed ? `, ${failed} failed` : ''}`, done > 0 ? 'success' : 'error');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction toggleDeletedView() {\u001b[39m\n\u001b[31m  _showDeletedView = !_showDeletedView;\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openDeleteModal(subId) {\u001b[39m\n\u001b[31m  _pendingDeleteId = subId;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  const sub = document.getElementById('del-modal-sub');\u001b[39m\n\u001b[31m  if (sub) sub.textContent = r ? `Delete: \\\"${r.store_name||'Unknown'}\\\"` : 'Select reason for deletion:';\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectDeleteReason(reason) {\u001b[39m\n\u001b[31m  _pendingDeleteReason = reason;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  document.getElementById('reason-' + reason)?.classList.add('sel');\u001b[39m\n\u001b[31m  document.getElementById('del-confirm-btn').classList.remove('no-reason');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeDeleteModal() {\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingDeleteId = null;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  clearTimeout(_tt);\u001b[39m\n\u001b[31m  document.getElementById('toast').classList.remove('show');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function restoreRecce(subId) {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({ deleted_at: null, deleted_by: null, deletion_reason: null }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Restore failed: ' + r.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_at = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_by = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deletion_reason = null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    toast('Recce restored ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Restore failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmDelete() {\u001b[39m\n\u001b[31m  if (!_pendingDeleteReason) {\u001b[39m\n\u001b[31m    const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m    btn.style.animation = 'none';\u001b[39m\n\u001b[31m    btn.offsetHeight; // reflow\u001b[39m\n\u001b[31m    btn.style.animation = 'shake .35s ease';\u001b[39m\n\u001b[31m    toast('Select a reason first', 'error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if (!_pendingDeleteId) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Deleting…';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      // Hard delete — no audit trail\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'DELETE',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Delete failed: ' + r.status);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Soft delete — stamp deleted_at, deleted_by, deletion_reason\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'PATCH',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m        body: JSON.stringify({\u001b[39m\n\u001b[31m          deleted_at: new Date().toISOString(),\u001b[39m\n\u001b[31m          deleted_by: hub.empId,\u001b[39m\n\u001b[31m          deletion_reason: _pendingDeleteReason,\u001b[39m\n\u001b[31m        }),\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Update failed: ' + r.status);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Remove or update in local cache\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      _adminRows = _adminRows.filter(x => x.sub_id !== _pendingDeleteId);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      const idx = _adminRows.findIndex(x => x.sub_id === _pendingDeleteId);\u001b[39m\n\u001b[31m      if (idx >= 0) {\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_at = new Date().toISOString();\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_by = hub.empId;\u001b[39m\n\u001b[31m        _adminRows[idx].deletion_reason = _pendingDeleteReason;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeDeleteModal();\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast('Recce deleted', 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Delete failed', 'error');\u001b[39m\n\u001b[31m    btn.classList.remove('no-reason');\u001b[39m\n\u001b[31m    btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openMyServerRecce(subId) {\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  // No view yet — show metadata modal (same layout as admin detail)\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta==='string' ? JSON.parse(r.meta) : (r.meta||{}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">📍 View on Google Maps</a>` : '';\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} × ${b.h||'?'} in · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos will appear after next sync from original device\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Visit Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupLanding() {\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = 'none';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = 'none';\u001b[39m\n\u001b[31m  // Clean up admin + create-mode UI\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('sup-back-btn')?.remove();\u001b[39m\n\u001b[31m  document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m  _supCreateMode = false;\u001b[39m\n\u001b[31m  // Resume-wrap may have been hidden by loadHomeAdmin() — restore it so draft banner shows\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = '';\u001b[39m\n\u001b[31m  document.getElementById('sub-list').innerHTML = `\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorViewAll()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0f9ff\\\">📋</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">View All Recces</span><span class=\\\"hi-txt\\\">सभी रेकी देखें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">Browse & review submissions from all agents</span><span class=\\\"hi-txt\\\">सभी एजेंट की सबमिशन देखें</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorCreateView()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0fdf4\\\">✍️</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">Create Recce</span><span class=\\\"hi-txt\\\">नई रेकी बनाएं</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">My submissions + New Recce button</span><span class=\\\"hi-txt\\\">मेरी सबमिशन + नई रेकी</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorViewAll() {\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  await loadHomeAdmin();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorCreateView() {\u001b[39m\n\u001b[31m  _supCreateMode = true;\u001b[39m\n\u001b[31m  // Restore field-agent UI\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh'); if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = t('My Submissions','मेरी सबमिशन');\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar'); if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  // Add Back to Menu button (once)\u001b[39m\n\u001b[31m  if (!document.getElementById('sup-back-create-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-create-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => {\u001b[39m\n\u001b[31m      _supCreateMode = false;\u001b[39m\n\u001b[31m      document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m      renderSupLanding();\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    document.querySelector('#view-home .content').prepend(bb);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  await loadHome();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadHome() {\u001b[39m\n\u001b[31m  if (_isSupervisor() && !_supCreateMode) { renderSupLanding(); return; }\u001b[39m\n\u001b[31m  if (_adminUnlocked && !_supCreateMode) { await loadHomeAdmin(); return; }·\u001b[39m\n\u001b[31m  const all  = await dbAll('subs');\u001b[39m\n\u001b[31m  const sy   = all.filter(s => s.status === 'synced').length;\u001b[39m\n\u001b[31m  const pe   = all.filter(s => s.status !== 'synced').length;·\u001b[39m\n\u001b[31m  // Fetch this agent's submissions from server — works on any device\u001b[39m\n\u001b[31m  let serverOnly = [];\u001b[39m\n\u001b[31m  let editAssigned = [];\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (navigator.onLine && hub?.empId) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?submitted_by=eq.${encodeURIComponent(hub.empId)}&order=submitted_at.desc&limit=200`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp.ok) {\u001b[39m\n\u001b[31m        const rows = await resp.json();\u001b[39m\n\u001b[31m        const localIds = new Set(all.map(s => s.id));\u001b[39m\n\u001b[31m        serverOnly = rows.filter(r => !localIds.has(r.sub_id));\u001b[39m\n\u001b[31m        _myServerRows = serverOnly;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m    // Fetch edit-assigned recces (supervisor assigned this creator to edit)\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp2 = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?edit_assigned_to=eq.${encodeURIComponent(hub.empId)}&deleted_at=is.null&order=submitted_at.desc`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp2.ok) editAssigned = await resp2.json();\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = sy + serverOnly.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = pe;\u001b[39m\n\u001b[31m  document.getElementById('stat-total').textContent   = all.length + serverOnly.length;·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!all.length && !serverOnly.length && !editAssigned.length) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">📋</div><div class=\\\"empty-txt\\\">No submissions yet</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const icos   = { synced:'✅', pending:'⏳', failed:'❌' };\u001b[39m\n\u001b[31m  const sorted = [...all].sort((a,b) => new Date(b.timestamp) - new Date(a.timestamp)).slice(0, 50);·\u001b[39m\n\u001b[31m  const localCards = sorted.map(s => {\u001b[39m\n\u001b[31m    const dt = new Date(s.timestamp);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const viewBtn = s.viewUrl\u001b[39m\n\u001b[31m      ? `<button class=\\\"edit-btn-sm\\\" onclick=\\\"window.open('${s.viewUrl}','_blank')\\\">👁 View</button>`\u001b[39m\n\u001b[31m      : `<button class=\\\"edit-btn-sm\\\" onclick=\\\"viewRecce('${s.id}')\\\">👁 View</button>`;\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico ${s.status}\\\">${icos[s.status]||'📋'}</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${s.data.storeName||'Unknown'} · ${s.data.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${s.data.address||''}</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge ${s.status}\\\">${s.status}</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          ${viewBtn}\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"editRecce('${s.id}')\\\" style=\\\"background:#fff7ed;border-color:var(--or);color:var(--or)\\\">✏ Edit</button>\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"makeSlides('${s.id}')\\\" style=\\\"background:#eff6ff;border-color:#3b82f6;color:#1d4ed8\\\">📊 Slides</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const serverCards = serverOnly.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const showPdf = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m    const pdfCls = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico synced\\\">✅</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\" style=\\\"min-width:0;flex:1\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"rpt-btns\\\" style=\\\"margin-top:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openMyServerRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m          ${showPdf ? `<button class=\\\"${pdfCls}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">📄 PDF</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge synced\\\">synced</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const editAssignedCards = editAssigned.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    return `<div class=\\\"edit-req-card\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:26px;flex-shrink:0\\\">✏</div>\u001b[39m\n\u001b[31m      <div class=\\\"edit-req-card-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-meta\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        ${r.edit_comment ? `<div class=\\\"edit-req-cmt\\\">\\\"${r.edit_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:10px;display:flex;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"startCreatorEdit('${r.sub_id}')\\\" style=\\\"padding:9px 16px;font-size:13px;font-weight:600\\\">✏ Edit this Recce</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (editAssignedCards.length) {\u001b[39m\n\u001b[31m    html += `<div class=\\\"edit-req-section-hdr\\\">✏ Edit Requested (${editAssignedCards.length})</div>`;\u001b[39m\n\u001b[31m    html += editAssignedCards.join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  html += localCards.join('') + serverCards.join('');\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m  const ls = await cfg('last-sync');\u001b[39m\n\u001b[31m  if (ls) {\u001b[39m\n\u001b[31m    const d = new Date(ls);\u001b[39m\n\u001b[31m    document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m      'Synced ' + d.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// RESET\u001b[39m\n\u001b[31mfunction startNewRecce(){F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  if(geoStampEnabled)autoRequestGPS();\u001b[39m\n\u001b[31m['f-date','f-brand','f-store','f-addr','f-mobile','f-client-other'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';});\u001b[39m\n\u001b[31m_selectedClient='';_clientOtherMode=false;\u001b[39m\n\u001b[31m_selectedCampaignId=null;_notifySupervisor=false;_brandingLocked=false;\u001b[39m\n\u001b[31mconst _camSel=document.getElementById('f-campaign-id');if(_camSel)_camSel.value='';\u001b[39m\n\u001b[31mconst _camNotice=document.getElementById('campaign-notify-msg');if(_camNotice)_camNotice.style.display='none';\u001b[39m\n\u001b[31mloadCampaignsForForm();\u001b[39m\n\u001b[31mrenderClientChips();\u001b[39m\n\u001b[31mdocument.getElementById('f-date').value=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31m// Block future dates\u001b[39m\n\u001b[31mdocument.getElementById('f-date').max=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31mdocument.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('pick-trigger-wrap').style.display=stores.length?'block':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').style.display=stores.length?'flex':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31mdocument.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31mdocument.getElementById('manual-fields').style.display=stores.length?'none':'block';\u001b[39m\n\u001b[31mdocument.getElementById('gps-status').textContent='';\u001b[39m\n\u001b[31m['vid-yes','vid-no','br-yes','br-no'].forEach(id=>document.getElementById(id).classList.remove('sel'));\u001b[39m\n\u001b[31mdocument.getElementById('vid-sec').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('vid-slot').innerHTML=`<div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('br-add').style.display='none';document.getElementById('br-items').innerHTML='';\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').classList.remove('filled');\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').innerHTML=`<div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('brand-selector').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('sc-missing').style.display='none';\u001b[39m\n\u001b[31mpopulateBrandDropdown();\u001b[39m\n\u001b[31mrenderPhotos('front');renderPhotos('inside');renderAddl();updAvailTag();showView('form-store');}\u001b[39m\n\u001b[31mfunction exitForm(){\u001b[39m\n\u001b[31m  // Show safe exit dialog instead of confirm\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitSaveAndLeave(){\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m  checkDraft();\u001b[39m\n\u001b[31m  toast('Draft saved — tap Resume to continue','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitDiscard(){\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];\u001b[39m\n\u001b[31m  videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  dbDel('draft','current');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitCancel(){document.getElementById('exit-dialog').classList.remove('open');}\u001b[39m\n\u001b[31mfunction showView(n){document.querySelectorAll('.view').forEach(v=>v.classList.remove('active'));const t=document.getElementById('view-'+n);if(t){t.classList.add('active');window.scrollTo(0,0);}}\u001b[39m\n\u001b[31mlet _tt;\u001b[39m\n\u001b[31mfunction toast(msg,type='info'){const el=document.getElementById('toast');el.textContent=msg;el.className='toast show '+type;clearTimeout(_tt);_tt=setTimeout(()=>el.classList.remove('show'),3000);}\u001b[39m\n\u001b[31mfunction netStatus(){const on=navigator.onLine;const dot=document.getElementById('net-dot');const txt=document.getElementById('net-txt');if(dot)dot.className='sdot '+(on?'on':'off');if(txt)txt.textContent=on?t('Online','ऑनलाइन'):t('Offline — saves locally','ऑफलाइन — स्थानीय रूप से सेव');}\u001b[39m\n\u001b[31masync function loadSettings(){\u001b[39m\n\u001b[31m  // Gas URL: pre-load default if none saved, update preview\u001b[39m\n\u001b[31m  const gu=await cfg('gas-url');\u001b[39m\n\u001b[31m  if(!gu)await cfg('gas-url',DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m  // Admin cfg url\u001b[39m\n\u001b[31m  const acu=await cfg('admin-cfg-url');if(acu&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=acu;\u001b[39m\n\u001b[31m  const su=await cfg('srv-url')||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su)document.getElementById('srv-url').value=su;\u001b[39m\n\u001b[31m  const sc=await cfg('stores');\u001b[39m\n\u001b[31m  if(sc){\u001b[39m\n\u001b[31m    stores=JSON.parse(sc);\u001b[39m\n\u001b[31m    const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m    document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m      `✓ ${stores.length} stores in cache${noBrand?` · ${noBrand} without brand`:''}`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const sf=await cfg('store-files');if(sf){_storeFiles=JSON.parse(sf);renderStoreFileList();}\u001b[39m\n\u001b[31m  const iq=await cfg('img-quality');imgQuality=iq||'compressed';applyQualityUI(imgQuality);\u001b[39m\n\u001b[31m  const gs=await cfg('geo-stamp');geoStampEnabled=(gs===null||gs==='1');applyGeoStampUI();\u001b[39m\n\u001b[31m  const bl=await cfg('brands');if(bl)brands=JSON.parse(bl);\u001b[39m\n\u001b[31m  loadBrandsFromDb();  // async — updates brands + logos from DB in background\u001b[39m\n\u001b[31m  renderBrandManageList();\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m  // Show store upload row + brand add row to supervisors only\u001b[39m\n\u001b[31m  const sur = document.getElementById('store-upload-row');\u001b[39m\n\u001b[31m  if (sur) sur.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const bar = document.getElementById('brand-add-row');\u001b[39m\n\u001b[31m  if (bar) bar.style.display = _isSupervisor() ? 'flex' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction populateBrandDropdown(){\u001b[39m\n\u001b[31m  const sel=document.getElementById('f-brand');if(!sel)return;\u001b[39m\n\u001b[31m  const cur=sel.value;\u001b[39m\n\u001b[31m  sel.innerHTML='<option value=\\\"\\\">Select brand</option>'+brands.map(b=>`<option${cur===b?' selected':''}>${b}</option>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderBrandManageList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('brand-manage-list');if(!el)return;\u001b[39m\n\u001b[31m  const isSup=_isSupervisor();\u001b[39m\n\u001b[31m  el.innerHTML=brands.map((b,i)=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    const logoHtml=logo?`<img src=\\\"${logo}\\\" style=\\\"height:20px;max-width:48px;object-fit:contain;flex-shrink:0;border-radius:3px\\\">`:'';\u001b[39m\n\u001b[31m    const ctrlHtml=isSup?`<div style=\\\"display:flex;gap:2px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"openEditBrandDialog(${i})\\\" style=\\\"background:none;border:none;color:var(--nv);font-size:15px;cursor:pointer;padding:2px 6px\\\" title=\\\"Edit\\\">✏</button>\u001b[39m\n\u001b[31m      ${brands.length>1?`<button onclick=\\\"confirmRemoveBrand(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:2px 4px\\\">×</button>`:'<span style=\\\"font-size:11px;color:var(--g400);padding:0 6px\\\">Last</span>'}\u001b[39m\n\u001b[31m    </div>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;min-width:0\\\">${logoHtml}<span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${b}</span></div>\u001b[39m\n\u001b[31m      ${ctrlHtml}\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function addBrandToList(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const inp=document.getElementById('brand-add-inp');\u001b[39m\n\u001b[31m  const val=(inp.value.trim()||'').toUpperCase();\u001b[39m\n\u001b[31m  if(!val){toast('Enter a brand name','error');return;}\u001b[39m\n\u001b[31m  if(brands.some(b=>b.toLowerCase()===val.toLowerCase())){toast(`${val} already in list`,'error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands`,{method:'POST',headers:{..._RC_WRITE,'Prefer':'return=minimal'},body:JSON.stringify({name:val,sort_order:99})});\u001b[39m\n\u001b[31m    if(resp.status===409){toast(`${val} already exists in DB`,'error');return;}\u001b[39m\n\u001b[31m    if(!resp.ok){const e=await resp.json().catch(()=>({}));throw new Error(e.message||resp.status);}\u001b[39m\n\u001b[31m    inp.value='';\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${val} added ✓`,'success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Add failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmRemoveBrand(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const name=brands[idx];\u001b[39m\n\u001b[31m  if(brands.length<=1){toast('Need at least one brand','error');return;}\u001b[39m\n\u001b[31m  let count=0;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(name)}&select=sub_id`,{headers:_RC_READ});\u001b[39m\n\u001b[31m    if(r.ok){const rows=await r.json();count=rows.length;}\u001b[39m\n\u001b[31m  }catch(_){}\u001b[39m\n\u001b[31m  const msg=count>0?`Delete \\\"${name}\\\" from brand list?\\\\n(${count} submission${count!==1?'s':''} reference this brand — they keep the name as text.)`:`Delete \\\"${name}\\\" from brand list?`;\u001b[39m\n\u001b[31m  if(!confirm(msg))return;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(name)}`,{method:'DELETE',headers:{'Content-Profile':'recce','Accept-Profile':'recce'}});\u001b[39m\n\u001b[31m    if(!resp.ok&&resp.status!==204){throw new Error(resp.status);}\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${name} removed ✓`,'info');\u001b[39m\n\u001b[31m  }catch(e){toast(`Remove failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadBrandsFromDb(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch('/db/brands?select=name,logo_url&order=sort_order',{\u001b[39m\n\u001b[31m      headers:{'Content-Profile':'recce','Accept-Profile':'recce'}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(!r.ok) return;\u001b[39m\n\u001b[31m    const rows=await r.json();\u001b[39m\n\u001b[31m    if(!rows||!rows.length) return;\u001b[39m\n\u001b[31m    const dbNames=rows.map(r=>r.name);\u001b[39m\n\u001b[31m    const logos={};rows.forEach(r=>{if(r.logo_url)logos[r.name]=r.logo_url;});\u001b[39m\n\u001b[31m    // Merge: DB brands canonical, keep locally-added extras\u001b[39m\n\u001b[31m    const extras=brands.filter(b=>!dbNames.some(n=>n.toLowerCase()===b.toLowerCase()));\u001b[39m\n\u001b[31m    brands=[...dbNames,...extras];\u001b[39m\n\u001b[31m    _brandLogos=logos;\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    // Refresh brand chips if brand-selector is visible\u001b[39m\n\u001b[31m    const bSel=document.getElementById('brand-selector');\u001b[39m\n\u001b[31m    if(bSel&&bSel.style.display!=='none') renderBrandChips();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[brands-db]',e.message);}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction renderBrandChips(){\u001b[39m\n\u001b[31m  const bChips=document.getElementById('brand-chips');if(!bChips)return;\u001b[39m\n\u001b[31m  bChips.innerHTML=brands.map(b=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    return `<div class=\\\"chip brand-chip${F.brand===b?' sel':''}\\\" onclick=\\\"selectStoreBrand('${b.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\">` +\u001b[39m\n\u001b[31m      (logo?`<img src=\\\"${logo}\\\" class=\\\"brand-chip-logo\\\" alt=\\\"\\\">`:'') +\u001b[39m\n\u001b[31m      `<span>${b}</span></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _editBrandIdx=null,_editBrandOld=null;\u001b[39m\n\u001b[31mfunction openEditBrandDialog(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor())return;\u001b[39m\n\u001b[31m  _editBrandIdx=idx;_editBrandOld=brands[idx];\u001b[39m\n\u001b[31m  document.getElementById('be-name').value=brands[idx];\u001b[39m\n\u001b[31m  const logo=_brandLogos[brands[idx]]||'';\u001b[39m\n\u001b[31m  document.getElementById('be-logo').value=logo;\u001b[39m\n\u001b[31m  document.getElementById('be-logo-preview').innerHTML=logo?`<img src=\\\"${logo}\\\" style=\\\"height:28px;object-fit:contain\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Current logo</span>`:'';\u001b[39m\n\u001b[31m  document.getElementById('be-cascade-info').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('brand-edit-modal').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeBrandEditModal(){document.getElementById('brand-edit-modal').classList.remove('open');_editBrandIdx=null;_editBrandOld=null;}\u001b[39m\n\u001b[31mfunction previewBrandLogo(){\u001b[39m\n\u001b[31m  const url=(document.getElementById('be-logo')?.value||'').trim();\u001b[39m\n\u001b[31m  const prev=document.getElementById('be-logo-preview');\u001b[39m\n\u001b[31m  if(prev)prev.innerHTML=url?`<img src=\\\"${url}\\\" style=\\\"height:28px;object-fit:contain\\\" onerror=\\\"this.style.display='none'\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Preview</span>`:'';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveBrandEdit(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const oldName=_editBrandOld;\u001b[39m\n\u001b[31m  const newName=(document.getElementById('be-name').value||'').trim().toUpperCase();\u001b[39m\n\u001b[31m  const newLogo=(document.getElementById('be-logo').value||'').trim();\u001b[39m\n\u001b[31m  if(!newName){toast('Brand name required','error');return;}\u001b[39m\n\u001b[31m  const isRename=newName!==oldName;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // 1. Update recce.brands\u001b[39m\n\u001b[31m    const pResp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m      method:'PATCH',headers:{..._RC_WRITE,'Prefer':'return=minimal'},\u001b[39m\n\u001b[31m      body:JSON.stringify({name:newName,logo_url:newLogo||null})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(pResp.status===409){toast(`\\\"${newName}\\\" already exists`,'error');return;}\u001b[39m\n\u001b[31m    if(!pResp.ok&&pResp.status!==204){const e=await pResp.json().catch(()=>({}));throw new Error(e.message||pResp.status);}\u001b[39m\n\u001b[31m    if(isRename){\u001b[39m\n\u001b[31m      const hub=_recceHubUser();\u001b[39m\n\u001b[31m      // 2. Cascade to submissions\u001b[39m\n\u001b[31m      await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m        method:'PATCH',headers:_RC_WRITE,body:JSON.stringify({brand:newName})\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      // 3. Cascade to stores.json + view HTML files + PDFs\u001b[39m\n\u001b[31m      toast('Cascading rename to reports…','info');\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        const cResp=await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},\u001b[39m\n\u001b[31m          body:JSON.stringify({type:'cascade-rename-brand',oldName,newName,empId:hub?.empId||''})});\u001b[39m\n\u001b[31m        const cRes=cResp.ok?await cResp.json():{};\u001b[39m\n\u001b[31m        const msg=`Brand renamed ✓${cRes.viewsUpdated?` · ${cRes.viewsUpdated} reports re-queued`:''}`;\u001b[39m\n\u001b[31m        closeBrandEditModal();\u001b[39m\n\u001b[31m        await loadBrandsFromDb();\u001b[39m\n\u001b[31m        toast(msg,'success');\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }catch(e){console.warn('[cascade-rename]',e.message);}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeBrandEditModal();\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast('Brand updated ✓','success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Save failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function fetchServerBrands(){\u001b[39m\n\u001b[31m  const url=document.getElementById('brands-url')?.value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    toast('Fetching brands…','info');\u001b[39m\n\u001b[31m    const r=await fetch(url);const j=await r.json();\u001b[39m\n\u001b[31m    const list=Array.isArray(j)?j:j.brands||[];\u001b[39m\n\u001b[31m    if(!list.length){toast('No brands found in response','error');return;}\u001b[39m\n\u001b[31m    brands=list.map(b=>b.toString().toUpperCase());\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    toast(`${brands.length} brands loaded from server`,'success');\u001b[39m\n\u001b[31m  }catch{toast('Failed to fetch — check URL','error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setImgQuality(q){\u001b[39m\n\u001b[31m  imgQuality=q;\u001b[39m\n\u001b[31m  cfg('img-quality',q);\u001b[39m\n\u001b[31m  applyQualityUI(q);\u001b[39m\n\u001b[31m  toast(q==='hd'?'HD Quality selected (~400–600 KB per photo)':'Full Compression selected (~150–200 KB per photo)','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction applyQualityUI(q){\u001b[39m\n\u001b[31m  ['compressed','hd'].forEach(opt=>{\u001b[39m\n\u001b[31m    const label=document.getElementById('q-opt-'+opt);\u001b[39m\n\u001b[31m    const radio=document.getElementById('q-radio-'+opt);\u001b[39m\n\u001b[31m    const dot  =document.getElementById('q-dot-'+opt);\u001b[39m\n\u001b[31m    if(!label)return;\u001b[39m\n\u001b[31m    const active=opt===q;\u001b[39m\n\u001b[31m    label.style.borderColor=active?'var(--or)':'var(--g200)';\u001b[39m\n\u001b[31m    label.style.background=active?'#fff7ed':'var(--g50)';\u001b[39m\n\u001b[31m    if(radio)radio.style.borderColor=active?'var(--or)':'var(--g300)';\u001b[39m\n\u001b[31m    if(dot)dot.style.display=active?'block':'none';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const badge=document.getElementById('q-current-badge');\u001b[39m\n\u001b[31m  if(badge){\u001b[39m\n\u001b[31m    const label=q==='hd'?'HD Quality (~400–600 KB)':'Full Compression (~150–200 KB)';\u001b[39m\n\u001b[31m    badge.innerHTML=`Active: <strong>${label}</strong>`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function clearData(){if(!confirm('Delete ALL local data?'))return;const all=await dbAll('subs');for(const s of all)await dbDel('subs',s.id);stores=[];await cfg('stores',null);toast('All cleared','success');loadHome();}\u001b[39m\n\u001b[31mif('serviceWorker' in navigator){const sw=`const C='recce-v37';self.addEventListener('install',e=>{e.waitUntil(caches.open(C).then(c=>c.add('/')));self.skipWaiting();});self.addEventListener('activate',e=>e.waitUntil(clients.claim()));self.addEventListener('fetch',e=>{if(e.request.method!=='GET')return;e.respondWith(caches.match(e.request).then(r=>{if(r)return r;return fetch(e.request).then(res=>{if(res&&res.status===200&&res.type==='basic'){const cl=res.clone();caches.open(C).then(c=>c.put(e.request,cl));}return res;}).catch(()=>caches.match('/'));}))}); `;const blob=new Blob([sw],{type:'application/javascript'});navigator.serviceWorker.register(URL.createObjectURL(blob),{scope:'/'}).catch(()=>{});}·\u001b[39m\n\u001b[31m// ── GEOLOCATION STAMP ────────────────────────────────────────\u001b[39m\n\u001b[31mfunction applyGeoStampUI(){\u001b[39m\n\u001b[31m  const tog=document.getElementById('geo-tog');\u001b[39m\n\u001b[31m  if(tog)tog.classList.toggle('on',geoStampEnabled);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function toggleGeoStamp(){\u001b[39m\n\u001b[31m  geoStampEnabled=!geoStampEnabled;\u001b[39m\n\u001b[31m  await cfg('geo-stamp',geoStampEnabled?'1':'0');\u001b[39m\n\u001b[31m  applyGeoStampUI();\u001b[39m\n\u001b[31m  toast(geoStampEnabled?'Geolocation stamp enabled':'Geolocation stamp disabled','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Auto-request GPS silently when a new recce starts\u001b[39m\n\u001b[31mfunction autoRequestGPS(){\u001b[39m\n\u001b[31m  if(!navigator.geolocation)return;\u001b[39m\n\u001b[31m  const statusEl=document.getElementById('geo-status');\u001b[39m\n\u001b[31m  if(statusEl)statusEl.textContent='Acquiring GPS…';\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(\u001b[39m\n\u001b[31m    pos=>{\u001b[39m\n\u001b[31m      gpsCoords={\u001b[39m\n\u001b[31m        lat:pos.coords.latitude.toFixed(6),\u001b[39m\n\u001b[31m        lng:pos.coords.longitude.toFixed(6),\u001b[39m\n\u001b[31m        acc:Math.round(pos.coords.accuracy)\u001b[39m\n\u001b[31m      };\u001b[39m\n\u001b[31m      const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m      const quality=acc<=15?'Excellent':acc<=50?'Good':acc<=200?'Fair':'Poor (cell tower)';\u001b[39m\n\u001b[31m      const color=acc<=15?'var(--gn)':acc<=50?'#16a34a':acc<=200?'var(--am)':'var(--rd)';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.innerHTML=`GPS: ${gpsCoords.lat}, ${gpsCoords.lng} · ±${acc}m · <span style=\\\"color:${color};font-weight:600\\\">${quality}</span>`;\u001b[39m\n\u001b[31m      // Update form GPS status too\u001b[39m\n\u001b[31m      const fs=document.getElementById('gps-status');\u001b[39m\n\u001b[31m      if(fs){fs.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${acc}m)`;fs.style.color='var(--gn)';}\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    err=>{\u001b[39m\n\u001b[31m      const msgs={1:'Location permission denied in Chrome',2:'GPS signal unavailable',3:'GPS timed out'};\u001b[39m\n\u001b[31m      const msg=msgs[err.code]||'GPS unavailable';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.textContent=msg+' — stamp will use store address';\u001b[39m\n\u001b[31m      if(err.code===1)toast('Tap the lock icon in Chrome address bar → allow Location','info');\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    {enableHighAccuracy:true,timeout:20000,maximumAge:60000}\u001b[39m\n\u001b[31m  );\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Draw stamp on a photo blob — returns new blob with stamp baked in\u001b[39m\n\u001b[31mfunction roundRectPath(ctx,x,y,w,h,r){\u001b[39m\n\u001b[31m  ctx.beginPath();ctx.moveTo(x+r,y);ctx.lineTo(x+w-r,y);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y,x+w,y+r);ctx.lineTo(x+w,y+h-r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);ctx.lineTo(x+r,y+h);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y+h,x,y+h-r);ctx.lineTo(x,y+r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y,x+r,y);ctx.closePath();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction fitText(ctx,text,maxW){\u001b[39m\n\u001b[31m  if(ctx.measureText(text).width<=maxW)return text;\u001b[39m\n\u001b[31m  while(text.length>1&&ctx.measureText(text+'…').width>maxW)text=text.slice(0,-1);\u001b[39m\n\u001b[31m  return text+'…';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction stampPhoto(blob){\u001b[39m\n\u001b[31m  if(!geoStampEnabled)return Promise.resolve(blob);\u001b[39m\n\u001b[31m  return new Promise(res=>{\u001b[39m\n\u001b[31m    const img=new Image(),url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    img.onload=()=>{\u001b[39m\n\u001b[31m      URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m      const W=img.width,H=img.height;\u001b[39m\n\u001b[31m      const c=document.createElement('canvas');c.width=W;c.height=H;\u001b[39m\n\u001b[31m      const ctx=c.getContext('2d');\u001b[39m\n\u001b[31m      ctx.drawImage(img,0,0);·\u001b[39m\n\u001b[31m      // Stamp dimensions — 18% of image height\u001b[39m\n\u001b[31m      const SH=Math.round(H*0.18);\u001b[39m\n\u001b[31m      const pad=Math.round(W*0.03);\u001b[39m\n\u001b[31m      const SY=H-SH;·\u001b[39m\n\u001b[31m      // Semi-transparent background\u001b[39m\n\u001b[31m      ctx.fillStyle='rgba(10,18,35,0.78)';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,SH);·\u001b[39m\n\u001b[31m      // Orange top accent line\u001b[39m\n\u001b[31m      ctx.fillStyle='#f97316';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,Math.max(3,Math.round(H*0.004)));·\u001b[39m\n\u001b[31m      // Font sizes scaled to image\u001b[39m\n\u001b[31m      const f1=Math.round(SH*0.26); // store name\u001b[39m\n\u001b[31m      const f2=Math.round(SH*0.22); // coords / address\u001b[39m\n\u001b[31m      const f3=Math.round(SH*0.20); // timestamp·\u001b[39m\n\u001b[31m      // Row Y centres\u001b[39m\n\u001b[31m      const r1=SY+SH*0.26;\u001b[39m\n\u001b[31m      const r2=SY+SH*0.55;\u001b[39m\n\u001b[31m      const r3=SY+SH*0.82;·\u001b[39m\n\u001b[31m      // Get stamp data\u001b[39m\n\u001b[31m      const storeName=F.storeName||selectedStore?.name||'';\u001b[39m\n\u001b[31m      const brand=F.brand||selectedStore?.brand||'';\u001b[39m\n\u001b[31m      const addr=F.address||selectedStore?.address||'';\u001b[39m\n\u001b[31m      const now=new Date();\u001b[39m\n\u001b[31m      const dateStr=now.toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m      const timeStr=now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit',hour12:true});·\u001b[39m\n\u001b[31m      // Badge (right side — GPS quality)\u001b[39m\n\u001b[31m      let badgeLabel='',badgeColor='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m        if(acc<=15){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=50){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=200){badgeLabel='~'+acc+'m';badgeColor='#d97706';}\u001b[39m\n\u001b[31m        else{badgeLabel='Cell ~'+acc+'m';badgeColor='#dc2626';}\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        badgeLabel='No GPS';badgeColor='#64748b';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      const bFontSz=Math.round(SH*0.18);\u001b[39m\n\u001b[31m      ctx.font=`bold ${bFontSz}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      const bW=Math.round(ctx.measureText(badgeLabel).width+pad);\u001b[39m\n\u001b[31m      const bH=Math.round(SH*0.32);\u001b[39m\n\u001b[31m      const bX=W-bW-pad;const bY=SY+(SH-bH)/2;\u001b[39m\n\u001b[31m      ctx.fillStyle=badgeColor+'cc';\u001b[39m\n\u001b[31m      roundRectPath(ctx,bX,bY,bW,bH,4);ctx.fill();\u001b[39m\n\u001b[31m      ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';\u001b[39m\n\u001b[31m      ctx.fillText(badgeLabel,bX+bW/2,bY+bH/2);\u001b[39m\n\u001b[31m      ctx.textAlign='left';ctx.textBaseline='alphabetic';·\u001b[39m\n\u001b[31m      const textMaxW=bX-pad*2;·\u001b[39m\n\u001b[31m      // Row 1 — store name + brand\u001b[39m\n\u001b[31m      ctx.font=`bold ${f1}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#ffffff';\u001b[39m\n\u001b[31m      const nameText=storeName+(brand?' · '+brand:'');\u001b[39m\n\u001b[31m      ctx.fillText('📍 '+fitText(ctx,nameText,textMaxW-f1*1.4),pad,r1);·\u001b[39m\n\u001b[31m      // Row 2 — GPS coords OR address\u001b[39m\n\u001b[31m      ctx.font=`${f2}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#cbd5e1';\u001b[39m\n\u001b[31m      let row2='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        row2=`Lat ${gpsCoords.lat}°   Long ${gpsCoords.lng}°`;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        row2=addr?fitText(ctx,addr,textMaxW):'GPS coordinates unavailable';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      ctx.fillText(row2,pad,r2);·\u001b[39m\n\u001b[31m      // Row 3 — date and time\u001b[39m\n\u001b[31m      ctx.font=`${f3}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#94a3b8';\u001b[39m\n\u001b[31m      ctx.fillText(`${dateStr}   ${timeStr}`,pad,r3);·\u001b[39m\n\u001b[31m      c.toBlob(b=>res(b||blob),'image/jpeg',imgQuality==='hd'?0.88:0.82);\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    img.onerror=()=>{URL.revokeObjectURL(url);res(blob);};\u001b[39m\n\u001b[31m    img.src=url;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _aTool='rect',_aColor='#f97316',_aWidth=4,_aTarget=-1;\u001b[39m\n\u001b[31mlet _aImg=null,_aHistory=[],_aDrawing=false,_aStart={},_aPts=[];\u001b[39m\n\u001b[31mlet _aSel=-1,_aDragMode=null,_aDragOff={x:0,y:0};\u001b[39m\n\u001b[31m// Larger hit radius on touch devices for easier finger selection\u001b[39m\n\u001b[31mconst HIT_R=()=>('ontouchstart' in window)?32:16;·\u001b[39m\n\u001b[31mfunction setATool(t){\u001b[39m\n\u001b[31m  _aTool=t;\u001b[39m\n\u001b[31m  ['rect','ellipse','line','arrow','free'].forEach(id=>{const el=document.getElementById('at-'+id);if(el)el.classList.toggle('on',id===t&&t!=='move');});\u001b[39m\n\u001b[31m  const mv=document.getElementById('at-move');if(mv)mv.classList.toggle('sel-on',t==='move');\u001b[39m\n\u001b[31m  const info=document.getElementById('annot-sel-info');if(info)info.style.display=t==='move'?'block':'none';\u001b[39m\n\u001b[31m  if(t!=='move'){_aSel=-1;redrawAnnot();}\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(cvs)cvs.style.cursor=t==='move'?'default':'crosshair';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAColor(c){\u001b[39m\n\u001b[31m  _aColor=c;\u001b[39m\n\u001b[31m  const m={'#f97316':'or','#ef4444':'rd','#ffffff':'wh','#facc15':'yw','#22c55e':'gn'};\u001b[39m\n\u001b[31m  Object.entries(m).forEach(([col,id])=>{const el=document.getElementById('ac-'+id);if(el)el.classList.toggle('on',col===c);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAWidth(w){_aWidth=w;[2,4,7].forEach(v=>{const el=document.getElementById('aw-'+v);if(el)el.classList.toggle('on',v===w);});}·\u001b[39m\n\u001b[31mfunction openAnnot(idx){\u001b[39m\n\u001b[31m  _aTarget=idx;_aHistory=[];_aDrawing=false;_aPts=[];_aSel=-1;_aDragMode=null;\u001b[39m\n\u001b[31m  document.getElementById('annot-modal').classList.add('open');\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');\u001b[39m\n\u001b[31m  const img=new Image(),url=URL.createObjectURL(brandings[idx].blob);\u001b[39m\n\u001b[31m  img.onload=()=>{\u001b[39m\n\u001b[31m    const sc=Math.min(1,window.innerWidth/img.width,(window.innerHeight-185)/img.height);\u001b[39m\n\u001b[31m    cvs.width=Math.round(img.width*sc);cvs.height=Math.round(img.height*sc);\u001b[39m\n\u001b[31m    _aImg=img;redrawAnnot();URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  img.src=url;\u001b[39m\n\u001b[31m  cvs.ontouchstart=aDown;cvs.ontouchmove=aMove;cvs.ontouchend=aUp;\u001b[39m\n\u001b[31m  cvs.onmousedown=aDown;cvs.onmousemove=aMove;cvs.onmouseup=aUp;\u001b[39m\n\u001b[31m  setATool('rect');setAColor('#f97316');setAWidth(4);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aPos(e){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const r=cvs.getBoundingClientRect();\u001b[39m\n\u001b[31m  const src=e.touches?e.touches[0]:e;\u001b[39m\n\u001b[31m  return{x:(src.clientX-r.left)*(cvs.width/r.width),y:(src.clientY-r.top)*(cvs.height/r.height)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Always return normalised (positive w,h) bounds\u001b[39m\n\u001b[31mfunction sBounds(s){\u001b[39m\n\u001b[31m  if(s.type==='free'){\u001b[39m\n\u001b[31m    if(!s.pts||!s.pts.length)return null;\u001b[39m\n\u001b[31m    const xs=s.pts.map(p=>p.x),ys=s.pts.map(p=>p.y);\u001b[39m\n\u001b[31m    const x=Math.min(...xs),y=Math.min(...ys);\u001b[39m\n\u001b[31m    return{x,y,w:Math.max(...xs)-x,h:Math.max(...ys)-y};\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  return{x:Math.min(s.x,s.x+s.w),y:Math.min(s.y,s.y+s.h),w:Math.abs(s.w),h:Math.abs(s.h)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction hitHandle(px,py,s){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return null;\u001b[39m\n\u001b[31m  const b=sBounds(s);const hr=HIT_R();\u001b[39m\n\u001b[31m  for(const[n,x,y]of[['tl',b.x,b.y],['tr',b.x+b.w,b.y],['bl',b.x,b.y+b.h],['br',b.x+b.w,b.y+b.h]])\u001b[39m\n\u001b[31m    if(Math.hypot(px-x,py-y)<hr)return n;\u001b[39m\n\u001b[31m  return null;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction hitShape(px,py,s){\u001b[39m\n\u001b[31m  const b=sBounds(s);if(!b)return false;\u001b[39m\n\u001b[31m  const pad=HIT_R();\u001b[39m\n\u001b[31m  return px>=b.x-pad&&px<=b.x+b.w+pad&&py>=b.y-pad&&py<=b.y+b.h+pad;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aDown(e){\u001b[39m\n\u001b[31m  e.preventDefault();const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'){\u001b[39m\n\u001b[31m    // Check handles of selected shape first\u001b[39m\n\u001b[31m    if(_aSel>=0&&_aSel<_aHistory.length){\u001b[39m\n\u001b[31m      const h=hitHandle(p.x,p.y,_aHistory[_aSel]);\u001b[39m\n\u001b[31m      if(h){_aDragMode='r-'+h;_aDragOff={x:p.x,y:p.y};_aDrawing=true;return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Hit test all shapes topmost first\u001b[39m\n\u001b[31m    for(let i=_aHistory.length-1;i>=0;i--){\u001b[39m\n\u001b[31m      if(hitShape(p.x,p.y,_aHistory[i])){\u001b[39m\n\u001b[31m        _aSel=i;_aDragMode='move';\u001b[39m\n\u001b[31m        const s=_aHistory[i];\u001b[39m\n\u001b[31m        const b=sBounds(s);\u001b[39m\n\u001b[31m        // Store offset from shape top-left corner (normalised)\u001b[39m\n\u001b[31m        _aDragOff={x:p.x-b.x,y:p.y-b.y};\u001b[39m\n\u001b[31m        _aDrawing=true;redrawAnnot();return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    _aSel=-1;redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _aDrawing=true;_aStart={x:p.x,y:p.y};if(_aTool==='free')_aPts=[{x:p.x,y:p.y}];\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aMove(e){\u001b[39m\n\u001b[31m  e.preventDefault();if(!_aDrawing)return;const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'&&_aDragMode){\u001b[39m\n\u001b[31m    const s=_aHistory[_aSel];if(!s)return;\u001b[39m\n\u001b[31m    if(_aDragMode==='move'){\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      // New top-left position\u001b[39m\n\u001b[31m      const nx=p.x-_aDragOff.x;\u001b[39m\n\u001b[31m      const ny=p.y-_aDragOff.y;\u001b[39m\n\u001b[31m      const dx=nx-b.x,dy=ny-b.y;\u001b[39m\n\u001b[31m      if(s.type==='free'){\u001b[39m\n\u001b[31m        s.pts=s.pts.map(pt=>({x:pt.x+dx,y:pt.y+dy}));\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        // Move preserving w/h sign (don't normalise — keep original drawing direction)\u001b[39m\n\u001b[31m        s.x+=dx;s.y+=dy;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Resize from corner — always work on normalised bounds then re-apply\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      const n=_aDragMode.slice(2);\u001b[39m\n\u001b[31m      let nx=b.x,ny=b.y,nw=b.w,nh=b.h;\u001b[39m\n\u001b[31m      if(n==='br'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,p.y-b.y);}\u001b[39m\n\u001b[31m      else if(n==='tl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,b.y+b.h-p.y);nx=p.x;ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='tr'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,b.y+b.h-p.y);ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='bl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,p.y-b.y);nx=p.x;}\u001b[39m\n\u001b[31m      s.x=nx;s.y=ny;s.w=nw;s.h=nh; // store as normalised going forward\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if(_aTool==='free'){_aPts.push({x:p.x,y:p.y});redrawAnnot();drawSh({type:'free',pts:[..._aPts],color:_aColor,lw:_aWidth},true);return;}\u001b[39m\n\u001b[31m  redrawAnnot();drawSh({type:_aTool,x:_aStart.x,y:_aStart.y,w:p.x-_aStart.x,h:p.y-_aStart.y,color:_aColor,lw:_aWidth},true);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction aUp(e){\u001b[39m\n\u001b[31m  if(!_aDrawing)return;_aDrawing=false;\u001b[39m\n\u001b[31m  if(_aTool==='move'){_aDragMode=null;return;}\u001b[39m\n\u001b[31m  const p=aPos(e||{touches:[{clientX:0,clientY:0}]});\u001b[39m\n\u001b[31m  if(_aTool==='free'){if(_aPts.length>2){_aHistory.push({type:'free',pts:[..._aPts],x:_aPts[0].x,y:_aPts[0].y,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  else{const w=p.x-_aStart.x,h=p.y-_aStart.y;if(Math.abs(w)>4||Math.abs(h)>4){_aHistory.push({type:_aTool,x:_aStart.x,y:_aStart.y,w,h,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  _aPts=[];redrawAnnot();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction redrawAnnot(){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.clearRect(0,0,cvs.width,cvs.height);if(_aImg)ctx.drawImage(_aImg,0,0,cvs.width,cvs.height);\u001b[39m\n\u001b[31m  _aHistory.forEach((s,i)=>{drawSh(s,false,ctx);if(_aTool==='move'&&i===_aSel)drawHandles(s,ctx);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawHandles(s,ctx){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return;const b=sBounds(s);ctx.save();\u001b[39m\n\u001b[31m  ctx.setLineDash([5,3]);ctx.strokeStyle='#facc15';ctx.lineWidth=1.5;ctx.strokeRect(b.x-2,b.y-2,b.w+4,b.h+4);ctx.setLineDash([]);\u001b[39m\n\u001b[31m  [[b.x,b.y],[b.x+b.w,b.y],[b.x,b.y+b.h],[b.x+b.w,b.y+b.h]].forEach(([x,y])=>{ctx.beginPath();ctx.arc(x,y,7,0,2*Math.PI);ctx.fillStyle='#f97316';ctx.fill();ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();});\u001b[39m\n\u001b[31m  ctx.restore();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawSh(s,preview=false,ctx){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(!ctx)ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.save();ctx.strokeStyle=s.color;ctx.lineWidth=preview?Math.max(s.lw||4,2):s.lw||4;\u001b[39m\n\u001b[31m  ctx.lineCap='round';ctx.lineJoin='round';ctx.setLineDash(preview?[6,3]:[]);\u001b[39m\n\u001b[31m  if(s.type==='rect'){ctx.strokeRect(s.x,s.y,s.w,s.h);ctx.fillStyle=s.color+'28';ctx.fillRect(s.x,s.y,s.w,s.h);}\u001b[39m\n\u001b[31m  else if(s.type==='ellipse'){const cx=s.x+s.w/2,cy=s.y+s.h/2;ctx.beginPath();ctx.ellipse(cx,cy,Math.abs(s.w/2),Math.abs(s.h/2),0,0,2*Math.PI);ctx.stroke();ctx.fillStyle=s.color+'28';ctx.fill();}\u001b[39m\n\u001b[31m  else if(s.type==='line'){ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(s.x+s.w,s.y+s.h);ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='arrow'){const ex=s.x+s.w,ey=s.y+s.h;ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(ex,ey);ctx.stroke();const a=Math.atan2(s.h,s.w),al=20,aa=0.4;ctx.setLineDash([]);ctx.beginPath();ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a-aa),ey-al*Math.sin(a-aa));ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a+aa),ey-al*Math.sin(a+aa));ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='free'){if(s.pts.length<2){ctx.restore();return;}ctx.beginPath();s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));ctx.stroke();}\u001b[39m\n\u001b[31m  ctx.setLineDash([]);ctx.restore();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction undoAnnot(){if(_aHistory.length){_aHistory.pop();_aSel=Math.min(_aSel,_aHistory.length-1);redrawAnnot();}}\u001b[39m\n\u001b[31mfunction clearAnnot(){_aHistory=[];_aSel=-1;redrawAnnot();}·\u001b[39m\n\u001b[31m// Bottom dialog\u001b[39m\n\u001b[31mlet _bdCb=null;\u001b[39m\n\u001b[31mfunction showBDialog(title,sub,onYes){\u001b[39m\n\u001b[31m  document.getElementById('bdialog-title').textContent=title;\u001b[39m\n\u001b[31m  document.getElementById('bdialog-sub').textContent=sub;\u001b[39m\n\u001b[31m  _bdCb=onYes;document.getElementById('bdialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction bdialogYes(){document.getElementById('bdialog').classList.remove('open');if(_bdCb)_bdCb();_bdCb=null;}\u001b[39m\n\u001b[31mfunction bdialogNo(){document.getElementById('bdialog').classList.remove('open');_bdCb=null;}·\u001b[39m\n\u001b[31mfunction _afterBrandingPhoto(){\u001b[39m\n\u001b[31m  const idx=_aTarget;\u001b[39m\n\u001b[31m  showBDialog(t(`Add reference photos for Branding ${idx+1}?`,`ब्रांडिंग ${idx+1} के लिए अतिरिक्त फोटो?`),t('Optional extra photos for future reference.','वैकल्पिक — भविष्य के लिए अतिरिक्त फोटो।'),()=>{showView('form-additional');setTimeout(()=>addAdditional(),200);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction skipAnnot(){document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo added (${fmtSz(brandings[_aTarget].blob.size)})`,'success');_afterBrandingPhoto();}\u001b[39m\n\u001b[31mfunction saveAnnot(){const cvs=document.getElementById('annot-cvs');cvs.toBlob(blob=>{brandings[_aTarget].blob=blob;brandings[_aTarget].prev=URL.createObjectURL(blob);document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo + markup saved (${fmtSz(blob.size)})`,'success');_afterBrandingPhoto();},'image/jpeg',0.88);}·\u001b[39m\n\u001b[31m// ── VIEW RECCE (read-only) ──────────────────────────────────\u001b[39m\n\u001b[31masync function viewRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  // Synced entries have a server-side rich report — open it directly\u001b[39m\n\u001b[31m  if(entry.viewUrl){window.open(entry.viewUrl,'_blank');return;}\u001b[39m\n\u001b[31m  // Offline / not-yet-synced fallback: generate from local base64 data\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  const ts=new Date(entry.timestamp).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'});·\u001b[39m\n\u001b[31m  async function b64ToUrl(b64){if(!b64)return'';try{const r=await fetch(b64);const bl=await r.blob();return URL.createObjectURL(bl);}catch{return'';}}·\u001b[39m\n\u001b[31m  const fvUrls=await Promise.all((d.frontPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const ivUrls=await Promise.all((d.insidePhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const brUrls=await Promise.all((d.brandings||[]).map(b=>b64ToUrl(b.photoB64)));\u001b[39m\n\u001b[31m  const adUrls=await Promise.all((d.addlPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const docUrl=await b64ToUrl(d.docB64);·\u001b[39m\n\u001b[31m  const brRows=(d.brandings||[]).map((b,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:16px;padding:12px;background:#f8fafc;border-radius:8px;border-left:3px solid #f97316\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-weight:600;font-size:14px;color:#0f172a;margin-bottom:6px\\\">${i+1}. ${b.type||'—'}: ${b.w||'?'}\\\"×${b.h||'?'}\\\" · Qty: ${b.qty||'?'} · ${b.sqft||'?'}</div>\u001b[39m\n\u001b[31m      ${brUrls[i]?`<img src=\\\"${brUrls[i]}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:6px\\\">`:'<div style=\\\"color:#94a3b8;font-size:12px\\\">No photo</div>'}\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  const html=`<!DOCTYPE html><html><head><meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m  <title>Recce — ${d.storeName||'Unknown'}</title>\u001b[39m\n\u001b[31m  <style>body{font-family:Arial,sans-serif;margin:0;padding:16px;background:#f1f5f9}\u001b[39m\n\u001b[31m  .card{background:#fff;border-radius:12px;padding:16px;margin-bottom:14px;box-shadow:0 1px 4px rgba(0,0,0,.08)}\u001b[39m\n\u001b[31m  h1{font-size:18px;color:#0f172a;margin:0 0 4px}h2{font-size:14px;color:#f97316;text-transform:uppercase;letter-spacing:.5px;margin:0 0 10px}\u001b[39m\n\u001b[31m  .meta{font-size:12px;color:#64748b;margin-bottom:12px}.photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}\u001b[39m\n\u001b[31m  img{width:100%;border-radius:8px;object-fit:cover}\u001b[39m\n\u001b[31m  .tag{display:inline-block;background:#0f172a;color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-right:4px}\u001b[39m\n\u001b[31m  @media print{body{background:#fff}.card{box-shadow:none}}</style></head><body>\u001b[39m\n\u001b[31m  <div class=\\\"card\\\">\u001b[39m\n\u001b[31m    <h1>${d.storeName||'Unknown Store'}</h1>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\"><span class=\\\"tag\\\">${d.brand||'No Brand'}</span>${d.address||''}</div>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\">📞 ${d.mobile||'—'} &nbsp;|&nbsp; 📅 ${d.date||'—'} &nbsp;|&nbsp; Submitted: ${ts}</div>\u001b[39m\n\u001b[31m    ${d.gpsCoords?`<div class=\\\"meta\\\">📍 ${d.gpsCoords.lat}, ${d.gpsCoords.lng} ±${d.gpsCoords.acc}m</div>`:''}\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${fvUrls.length?`<div class=\\\"card\\\"><h2>Front View Photos</h2><div class=\\\"photos\\\">${fvUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${ivUrls.length?`<div class=\\\"card\\\"><h2>Inside View Photos</h2><div class=\\\"photos\\\">${ivUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${d.hasVideo?`<div class=\\\"card\\\"><h2>Video</h2><div>${d.videoNote||'Video recorded'}</div></div>`:''}\u001b[39m\n\u001b[31m  ${(d.brandings||[]).length?`<div class=\\\"card\\\"><h2>Branding Items (${(d.brandings||[]).length})</h2>${brRows}</div>`:''}\u001b[39m\n\u001b[31m  ${adUrls.length?`<div class=\\\"card\\\"><h2>Additional Photos</h2><div class=\\\"photos\\\">${adUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${docUrl?`<div class=\\\"card\\\"><h2>Submission Document</h2><img src=\\\"${docUrl}\\\" style=\\\"width:100%;max-height:300px;object-fit:contain\\\"></div>`:''}\u001b[39m\n\u001b[31m  <div style=\\\"text-align:center;margin:16px 0\\\">\u001b[39m\n\u001b[31m    <button onclick=\\\"window.print()\\\" style=\\\"background:#f97316;color:#fff;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer\\\">🖨 Print / Save as PDF</button>\u001b[39m\n\u001b[31m    <button onclick=\\\"window.close()\\\" style=\\\"background:#e2e8f0;color:#475569;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer;margin-left:10px\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  </body></html>`;\u001b[39m\n\u001b[31m  const blob=new Blob([html],{type:'text/html'});\u001b[39m\n\u001b[31m  const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m  window.open(url,'_blank');\u001b[39m\n\u001b[31m  setTimeout(()=>URL.revokeObjectURL(url),30000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── EDIT OLD RECCE ───────────────────────────────────────────\u001b[39m\n\u001b[31masync function editRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=d.gpsCoords||null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  F.editingId=id;F.date=d.date||'';F.brand=d.brand||'';F.storeName=d.storeName||'';F.address=d.address||'';F.mobile=d.mobile||'';F.hasVideo=d.hasVideo;F.hasBranding=d.hasBranding;\u001b[39m\n\u001b[31m  async function b64ToBlob(b64){if(!b64)return null;try{const r=await fetch(b64);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m  toast('Loading recce data…','info');\u001b[39m\n\u001b[31m  for(const p of(d.frontPhotos||[])){const b=await b64ToBlob(p.b64);if(b)frontPhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const p of(d.insidePhotos||[])){const b=await b64ToBlob(p.b64);if(b)insidePhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const br of(d.brandings||[])){const b=await b64ToBlob(br.photoB64);brandings.push({type:br.type,w:br.w,h:br.h,qty:br.qty,blob:b,prev:b?URL.createObjectURL(b):null});}\u001b[39m\n\u001b[31m  for(const p of(d.addlPhotos||[])){const b=await b64ToBlob(p.b64);if(b)addlPhotos.push({blob:b,prev:URL.createObjectURL(b),desc:p.desc||''});}\u001b[39m\n\u001b[31m  if(d.docB64){const b=await b64ToBlob(d.docB64);if(b){submissionDoc=b;const sl=document.getElementById('doc-slot');sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${URL.createObjectURL(b)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}}\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  if(F.brand)document.getElementById('f-brand').value=F.brand;\u001b[39m\n\u001b[31m  if(F.storeName)document.getElementById('f-store').value=F.storeName;\u001b[39m\n\u001b[31m  if(F.address)document.getElementById('f-addr').value=F.address;\u001b[39m\n\u001b[31m  if(F.mobile)document.getElementById('f-mobile').value=F.mobile;\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();updAvailTag();\u001b[39m\n\u001b[31m  toast('Recce loaded — make changes and re-submit','success');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── EDIT REQUEST ────────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mlet _editReqSubId = null;·\u001b[39m\n\u001b[31mfunction _hydratePhotosFromRow(r) {\u001b[39m\n\u001b[31m  let pu={};\u001b[39m\n\u001b[31m  try{pu=typeof r.photo_urls==='string'?JSON.parse(r.photo_urls):(r.photo_urls||{});}catch(_){}\u001b[39m\n\u001b[31m  let meta={};\u001b[39m\n\u001b[31m  try{meta=typeof r.meta==='string'?JSON.parse(r.meta):(r.meta||{});}catch(_){}\u001b[39m\n\u001b[31m  frontPhotos =(pu.front   ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  insidePhotos=(pu.inside  ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  addlPhotos  =(pu.addl    ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,desc:''}));\u001b[39m\n\u001b[31m  brandings   =(meta.brandings||[]).map((b,i)=>({type:b.type,w:b.w,h:b.h,qty:b.qty,existingUrl:(pu.brandings||[])[i]||null,blob:null,prev:(pu.brandings||[])[i]||null}));\u001b[39m\n\u001b[31m  _docExistingUrl=pu.doc||null;\u001b[39m\n\u001b[31m  // Show retained doc in slot\u001b[39m\n\u001b[31m  const sl=document.getElementById('doc-slot');\u001b[39m\n\u001b[31m  if(sl&&_docExistingUrl){sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${_docExistingUrl}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openEditRequestModal(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  _editReqSubId = subId;\u001b[39m\n\u001b[31m  document.getElementById('er-store-name').textContent = r.store_name || 'Unknown';\u001b[39m\n\u001b[31m  document.getElementById('er-comment').value = '';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const assignBtn = document.getElementById('er-assign-btn');\u001b[39m\n\u001b[31m  if (r.submitted_by && r.submitted_by !== hub?.empId) {\u001b[39m\n\u001b[31m    assignBtn.textContent = `👤 Assign to ${r.submitted_by}`;\u001b[39m\n\u001b[31m    assignBtn.style.display = '';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    assignBtn.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeEditRequestModal() {\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _editReqSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorEditMyself() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  // Lock branding if client has reviewed (preserve their approval)\u001b[39m\n\u001b[31m  _brandingLocked = !!(r.client_status && r.client_status !== 'pending');\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function assignEditToCreator() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r || !r.submitted_by) { toast('No creator found for this recce', 'error'); return; }\u001b[39m\n\u001b[31m  const comment = (document.getElementById('er-comment').value || '').trim();\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        status: 'edit_requested',\u001b[39m\n\u001b[31m        edit_assigned_to: r.submitted_by,\u001b[39m\n\u001b[31m        edit_comment: comment || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!resp.ok) throw new Error('Update failed: ' + resp.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].status = 'edit_requested';\u001b[39m\n\u001b[31m      _adminRows[idx].edit_assigned_to = r.submitted_by;\u001b[39m\n\u001b[31m      _adminRows[idx].edit_comment = comment || null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Push notification to creator\u001b[39m\n\u001b[31m    const notifBody = comment || `Please review and re-submit: ${r.store_name || 'your recce'}`;\u001b[39m\n\u001b[31m    fetch('/push-server/notify', {\u001b[39m\n\u001b[31m      method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        user_id: r.submitted_by, title: '✏ Edit Requested',\u001b[39m\n\u001b[31m        body: notifBody, tag: `recce-edit-${subId}`, url: '/recce/',\u001b[39m\n\u001b[31m        icon: '/hub/icons/icon-192.png', badge: '/hub/icons/icon-192.png',\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    }).catch(() => {});\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast(`Edit assigned to ${r.submitted_by} ✓`, 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Assign failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function startCreatorEdit(subId) {\u001b[39m\n\u001b[31m  // Try local IndexedDB first (has photos)\u001b[39m\n\u001b[31m  const local = await dbGet('subs', subId);\u001b[39m\n\u001b[31m  if (local) { await editRecce(subId); return; }\u001b[39m\n\u001b[31m  // Fallback: load text fields from server row\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId)\u001b[39m\n\u001b[31m         || (await (async () => {\u001b[39m\n\u001b[31m              try {\u001b[39m\n\u001b[31m                const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, { headers: _RC_READ });\u001b[39m\n\u001b[31m                if (resp.ok) { const arr = await resp.json(); return arr[0]; }\u001b[39m\n\u001b[31m              } catch(_) {} return null;\u001b[39m\n\u001b[31m            })());\u001b[39m\n\u001b[31m  if (!r) { toast('Record not found', 'error'); return; }\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── End edit request ─────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mfunction goToHub() { window.location.href = '/hub/'; }\u001b[39m\n\u001b[31mfunction recceLogout() {\u001b[39m\n\u001b[31m  if (!confirm('Log out?')) return;\u001b[39m\n\u001b[31m  localStorage.removeItem('lm360-session');\u001b[39m\n\u001b[31m  localStorage.removeItem('360exp-session');\u001b[39m\n\u001b[31m  window.location.href = '/hub/';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction injectHubButtons() {\u001b[39m\n\u001b[31m  const u = _recceHubUser();\u001b[39m\n\u001b[31m  const name = u ? (u.name || '') : '';\u001b[39m\n\u001b[31m  if (name) {\u001b[39m\n\u001b[31m    const bar = document.getElementById('recce-hero-ubar');\u001b[39m\n\u001b[31m    const nm  = document.getElementById('recce-hero-name');\u001b[39m\n\u001b[31m    if (bar) { nm.textContent = name; bar.style.display = 'flex'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.querySelectorAll('.hdr').forEach(hdr => {\u001b[39m\n\u001b[31m    const r = document.createElement('div');\u001b[39m\n\u001b[31m    r.className = 'hdr-r';\u001b[39m\n\u001b[31m    if (name) {\u001b[39m\n\u001b[31m      const un = document.createElement('span');\u001b[39m\n\u001b[31m      un.className = 'hdr-user';\u001b[39m\n\u001b[31m      un.textContent = name;\u001b[39m\n\u001b[31m      r.appendChild(un);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    const hub = document.createElement('button');\u001b[39m\n\u001b[31m    hub.className = 'btn-hub';\u001b[39m\n\u001b[31m    hub.innerHTML = '🏡 Hub';\u001b[39m\n\u001b[31m    hub.addEventListener('click', goToHub);\u001b[39m\n\u001b[31m    r.appendChild(hub);\u001b[39m\n\u001b[31m    const lo = document.createElement('button');\u001b[39m\n\u001b[31m    lo.className = 'btn-logout';\u001b[39m\n\u001b[31m    lo.textContent = 'Logout';\u001b[39m\n\u001b[31m    lo.addEventListener('click', recceLogout);\u001b[39m\n\u001b[31m    r.appendChild(lo);\u001b[39m\n\u001b[31m    hdr.appendChild(r);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction checkAppUpdate(){\u001b[39m\n\u001b[31m  const seen=localStorage.getItem('recce-ver-seen');\u001b[39m\n\u001b[31m  localStorage.setItem('recce-ver-seen',CACHE_VER);\u001b[39m\n\u001b[31m  if(seen&&seen!==CACHE_VER){\u001b[39m\n\u001b[31m    const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m    if(b){b.classList.add('show');setTimeout(()=>b.classList.remove('show'),5000);}\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction dismissUpdateBanner(){\u001b[39m\n\u001b[31m  const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m  if(b)b.classList.remove('show');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function init(){\u001b[39m\n\u001b[31m  // Detect host banners (tiiny.host, etc) and raise bnav above them\u001b[39m\n\u001b[31m  (function detectHostBar(){\u001b[39m\n\u001b[31m    const h=window.location.hostname;\u001b[39m\n\u001b[31m    let extra=0;\u001b[39m\n\u001b[31m    if(h.includes('tiiny'))extra=58;\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // Generic detection: check if window is shorter than expected (host injected a bar)\u001b[39m\n\u001b[31m      const gap=screen.height - window.innerHeight;\u001b[39m\n\u001b[31m      if(gap>100&&gap<200)extra=58; // a fixed bar is roughly 56-60px\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if(extra>0){\u001b[39m\n\u001b[31m      document.documentElement.style.setProperty('--host-bar',extra+'px');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  })();\u001b[39m\n\u001b[31m  setLang(LANG);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m  checkAppUpdate();\u001b[39m\n\u001b[31m  await loadRecceCfg();\u001b[39m\n\u001b[31m  _checkAccessMode();\u001b[39m\n\u001b[31m  await initDB();await loadSettings();await loadHome();await checkDraft();netStatus();window.addEventListener('online',()=>{netStatus();syncNow();});window.addEventListener('offline',netStatus);injectHubButtons();document.getElementById('today-date').textContent=new Date().toLocaleDateString('en-IN',{weekday:'long',day:'numeric',month:'long',year:'numeric'});updAvailTag();\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m  // Auto-fetch stores from server on every startup (uses default Netlify URL if none saved)\u001b[39m\n\u001b[31m  const su=(await cfg('srv-url'))||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su&&navigator.onLine){\u001b[39m\n\u001b[31m    fetch(su).then(r=>r.json()).then(async j=>{\u001b[39m\n\u001b[31m      const d=Array.isArray(j)?j:j.stores||[];\u001b[39m\n\u001b[31m      if(d.length){stores=d;await cfg('stores',JSON.stringify(d));await cfg('srv-url',su);updAvailTag();\u001b[39m\n\u001b[31m        document.getElementById('srv-url').value=su;}\u001b[39m\n\u001b[31m    }).catch(()=>{});\u001b[39m\n\u001b[31m  }}init();\u001b[39m\n\u001b[31m</script>\u001b[39m\n\u001b[31m</body>\u001b[39m\n\u001b[31m</html>\u001b[39m\n\u001b[31m\"\u001b[39m",
                        "stack": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoContain\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // indexOf\u001b[22m\n\nExpected substring: \u001b[32m\"recce-v15\"\u001b[39m\nReceived string:    \u001b[31m\"<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\">\u001b[39m\n\u001b[31m<head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\">\u001b[39m\n\u001b[31m<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\\\">\u001b[39m\n\u001b[31m<meta name=\\\"theme-color\\\" content=\\\"#0f172a\\\">\u001b[39m\n\u001b[31m<meta name=\\\"apple-mobile-web-app-capable\\\" content=\\\"yes\\\">\u001b[39m\n\u001b[31m<title>Branding Recce</title>\u001b[39m\n\u001b[31m<link rel=\\\"manifest\\\" href=\\\"manifest.json\\\">\u001b[39m\n\u001b[31m<link rel=\\\"preconnect\\\" href=\\\"https://fonts.googleapis.com\\\">\u001b[39m\n\u001b[31m<link href=\\\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap\\\" rel=\\\"stylesheet\\\">\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--nv:#0f172a;--nv2:#1e293b;--or:#f97316;--orl:#fed7aa;--gn:#16a34a;--rd:#dc2626;--am:#d97706;--g50:#f8fafc;--g100:#f1f5f9;--g200:#e2e8f0;--g300:#cbd5e1;--g400:#94a3b8;--g500:#64748b;--g600:#475569;--r:12px;--rs:8px;--sh:0 1px 3px rgba(0,0,0,.1),0 1px 2px rgba(0,0,0,.06);--bnav-h:72px;--host-bar:0px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}\u001b[39m\n\u001b[31mbody{font-family:'DM Sans',sans-serif;background:var(--g50);color:var(--nv);min-height:100vh;overflow-x:hidden}\u001b[39m\n\u001b[31m.hdr{background:var(--nv);color:#fff;padding:0 16px;height:56px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}\u001b[39m\n\u001b[31m.hdr-l{display:flex;align-items:center;gap:10px}\u001b[39m\n\u001b[31m.hdr-title{font-size:16px;font-weight:600}.hdr-sub{font-size:11px;color:var(--g400)}\u001b[39m\n\u001b[31m.back-btn,.icon-btn{background:none;border:none;color:#fff;padding:8px;cursor:pointer;display:flex;align-items:center}\u001b[39m\n\u001b[31m.back-btn{margin-left:-8px}\u001b[39m\n\u001b[31m.pgbar{height:3px;background:var(--g200)}.pgfill{height:100%;background:var(--or);transition:width .3s}\u001b[39m\n\u001b[31m.view{display:none;min-height:calc(100vh - 56px);padding-bottom:calc(var(--bnav-h) + var(--host-bar) + 24px)}.view.active{display:block}\u001b[39m\n\u001b[31m.content{padding:16px}\u001b[39m\n\u001b[31m.card{background:#fff;border-radius:var(--r);padding:16px;box-shadow:var(--sh);margin-bottom:12px}\u001b[39m\n\u001b[31m.card-title{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;letter-spacing:.6px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between}\u001b[39m\n\u001b[31m.cnt-badge{background:var(--or);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;min-width:22px;text-align:center}\u001b[39m\n\u001b[31m.cnt-badge.gray{background:var(--g400)}\u001b[39m\n\u001b[31m.field{margin-bottom:16px}.field:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.field label{display:block;font-size:13px;font-weight:500;color:var(--g600);margin-bottom:6px}\u001b[39m\n\u001b[31m.req{color:var(--or);margin-left:2px}\u001b[39m\n\u001b[31m.field input,.field select,.field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;color:var(--nv);background:#fff;transition:border-color .15s;-webkit-appearance:none;appearance:none}\u001b[39m\n\u001b[31m.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--or)}\u001b[39m\n\u001b[31m.field input:read-only{background:var(--g50);color:var(--g600)}\u001b[39m\n\u001b[31m.field textarea{resize:vertical;min-height:68px}\u001b[39m\n\u001b[31m.field select{background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}\u001b[39m\n\u001b[31m.pslot{border:2px dashed var(--g300);border-radius:var(--r);min-height:110px;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all .15s;position:relative;overflow:hidden;text-align:center;padding:16px}\u001b[39m\n\u001b[31m.pslot:active{border-color:var(--or);background:var(--g50)}\u001b[39m\n\u001b[31m.pslot.filled{border-style:solid;border-color:var(--or);padding:0;min-height:0}\u001b[39m\n\u001b[31m.pslot img{width:100%;height:150px;object-fit:cover;border-radius:calc(var(--r) - 2px);display:block}\u001b[39m\n\u001b[31m.pslot-lbl{font-size:13px;color:var(--g400);margin-top:6px}.pslot-ico{font-size:28px;color:var(--g300)}\u001b[39m\n\u001b[31m.pbadge{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.premove{position:absolute;top:6px;right:6px;background:var(--rd);color:#fff;border:none;border-radius:50%;width:26px;height:26px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;z-index:5}\u001b[39m\n\u001b[31minput[type=file]{display:none}\u001b[39m\n\u001b[31m.rgroup{display:flex;gap:10px}\u001b[39m\n\u001b[31m.rbtn{flex:1;padding:13px;border:1.5px solid var(--g200);border-radius:var(--rs);text-align:center;cursor:pointer;font-size:14px;font-weight:500;color:var(--g500);transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.rbtn.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.chip-grid{display:flex;flex-wrap:wrap;gap:8px}\u001b[39m\n\u001b[31m.chip{padding:7px 12px;border:1.5px solid var(--g200);border-radius:20px;font-size:13px;color:var(--g600);cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.chip.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.brand-chip{display:flex;align-items:center;gap:6px;padding:5px 12px}\u001b[39m\n\u001b[31m.brand-chip-logo{width:28px;height:18px;object-fit:contain;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{display:block;width:100%;padding:15px;background:var(--or);color:#fff;border:none;border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:700;cursor:pointer;text-align:center;transition:background .15s}\u001b[39m\n\u001b[31m.btn-p:active{background:#ea6c05}.btn-p:disabled{background:var(--g300);cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-s{display:block;width:100%;padding:14px;background:#fff;color:var(--nv);border:1.5px solid var(--g200);border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:500;cursor:pointer;text-align:center}\u001b[39m\n\u001b[31m.btn-s:active{background:var(--g100)}\u001b[39m\n\u001b[31m.btn-o{display:inline-flex;align-items:center;gap:6px;padding:10px 16px;background:#fff;color:var(--or);border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer}\u001b[39m\n\u001b[31m.btn-o:active{background:var(--orl)}\u001b[39m\n\u001b[31m.btn-d{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;background:#fff;color:var(--rd);border:1.5px solid #fecaca;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:12px;cursor:pointer}\u001b[39m\n\u001b[31m.bnav{position:fixed;bottom:var(--host-bar);left:0;right:0;background:#fff;border-top:1px solid var(--g200);display:flex;padding:10px 16px;gap:10px;z-index:100}\u001b[39m\n\u001b[31m.hero{background:var(--nv);color:#fff;padding:20px 16px 24px}\u001b[39m\n\u001b[31m.hero-title{font-size:22px;font-weight:700;margin-bottom:2px}.hero-sub{font-size:13px;color:var(--g400)}\u001b[39m\n\u001b[31m.stats{display:flex;gap:10px;margin-top:16px}\u001b[39m\n\u001b[31m.scard{flex:1;background:rgba(255,255,255,.08);border-radius:var(--rs);padding:12px;text-align:center}\u001b[39m\n\u001b[31m.snum{font-size:22px;font-weight:700}.slbl{font-size:11px;color:var(--g400);margin-top:2px}\u001b[39m\n\u001b[31m.scard.g .snum{color:#4ade80}.scard.a .snum{color:#fbbf24}\u001b[39m\n\u001b[31m.new-btn{background:var(--or);color:#fff;border:none;border-radius:var(--r);padding:16px;font-family:'DM Sans',sans-serif;font-size:16px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:10px;cursor:pointer;width:100%;margin-bottom:10px}\u001b[39m\n\u001b[31m.new-btn:active{background:#ea6c05}\u001b[39m\n\u001b[31m.resume-btn{background:var(--nv2);color:#fff;border:none;border-radius:var(--r);padding:13px 16px;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;display:flex;align-items:center;justify-content:space-between;cursor:pointer;width:100%;margin-bottom:18px}\u001b[39m\n\u001b[31m.sub-card{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:10px;display:flex;align-items:center;gap:12px}\u001b[39m\n\u001b[31m.sub-ico{width:40px;height:40px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}\u001b[39m\n\u001b[31m.sub-ico.pending{background:#fef3c7}.sub-ico.synced{background:#dcfce7}.sub-ico.failed{background:#fee2e2}\u001b[39m\n\u001b[31m.sub-meta{flex:1;min-width:0}.sub-name{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.sub-dtl{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.sbadge{font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;flex-shrink:0}\u001b[39m\n\u001b[31m.sbadge.pending{background:#fef3c7;color:#92400e}.sbadge.synced{background:#dcfce7;color:#14532d}.sbadge.failed{background:#fee2e2;color:#991b1b}\u001b[39m\n\u001b[31m.sh{display:flex;align-items:center;justify-content:space-between;margin:20px 0 12px}\u001b[39m\n\u001b[31m.st{font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.toast{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 8px);left:16px;right:16px;background:var(--nv);color:#fff;padding:12px 16px;border-radius:var(--r);font-size:14px;z-index:1000;transform:translateY(120px);opacity:0;transition:all .3s;pointer-events:none}\u001b[39m\n\u001b[31m.toast.show{transform:translateY(0);opacity:1}.toast.success{background:#16a34a}.toast.error{background:var(--rd)}.toast.info{background:var(--nv2)}\u001b[39m\n\u001b[31m.srow{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:#fff;border-top:1px solid var(--g100);font-size:12px;color:var(--g500)}\u001b[39m\n\u001b[31m.sdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px}.sdot.on{background:var(--gn)}.sdot.off{background:var(--g300)}\u001b[39m\n\u001b[31m.set-item{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:8px}\u001b[39m\n\u001b[31m.set-lbl{font-size:14px;font-weight:600;color:var(--nv);margin-bottom:4px}\u001b[39m\n\u001b[31m.set-sub{font-size:12px;color:var(--g500);margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem{background:#fff;border-radius:var(--r);border:1.5px solid var(--g200);padding:14px;margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\u001b[39m\n\u001b[31m.bitem-title{font-size:14px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.dim-row{display:flex;gap:8px}.dim-row .field{flex:1}\u001b[39m\n\u001b[31m.sqft{display:inline-block;background:var(--g100);color:var(--g600);font-size:12px;padding:4px 10px;border-radius:20px;margin-top:6px}\u001b[39m\n\u001b[31m.divider{height:1px;background:var(--g100);margin:12px 0}\u001b[39m\n\u001b[31m.rev-lbl{font-size:12px;color:var(--g500);margin-bottom:2px}\u001b[39m\n\u001b[31m.rev-val{font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.rev-photos{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}\u001b[39m\n\u001b[31m.rev-thumb{width:56px;height:56px;object-fit:cover;border-radius:var(--rs)}\u001b[39m\n\u001b[31m.empty{text-align:center;padding:40px 20px;color:var(--g400)}.empty-ico{font-size:40px;margin-bottom:12px}.empty-txt{font-size:14px}\u001b[39m\n\u001b[31m/* store picker */\u001b[39m\n\u001b[31m.store-card{border:1.5px solid var(--g200);border-radius:var(--rs);padding:13px 14px;background:#fff;position:relative;cursor:pointer}\u001b[39m\n\u001b[31m.store-card:active{background:var(--g50)}\u001b[39m\n\u001b[31m.store-card-name{font-size:15px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.store-card-meta{font-size:13px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.store-card-change{position:absolute;top:11px;right:12px;background:none;border:none;color:var(--or);font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer}\u001b[39m\n\u001b[31m.brand-tag{display:inline-block;background:var(--nv);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-top:4px}\u001b[39m\n\u001b[31m.last-chip{display:inline-flex;align-items:center;gap:4px;background:#fef3c7;color:#92400e;font-size:11px;font-weight:500;padding:3px 9px;border-radius:20px;margin-left:6px}\u001b[39m\n\u001b[31m.pick-trigger{border:2px solid var(--or);border-radius:var(--rs);padding:14px 16px;background:#fff7ed;display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-size:15px;font-weight:600;color:var(--or)}\u001b[39m\n\u001b[31m.pick-trigger:active{background:#ffedd5;border-color:#ea6800}\u001b[39m\n\u001b[31m.manual-toggle{display:flex;align-items:center;gap:8px;padding:10px 14px;border:1.5px dashed var(--g300);border-radius:var(--rs);cursor:pointer;font-size:13px;color:var(--g600);margin-top:8px;user-select:none}\u001b[39m\n\u001b[31m/* client chip grid */\u001b[39m\n\u001b[31m.cl-chip-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}\u001b[39m\n\u001b[31m.cl-chip{padding:8px 14px;border-radius:20px;border:1.5px solid var(--g200);font-size:13px;font-weight:500;color:var(--g600);background:#fff;cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.cl-chip:active,.cl-chip.sel{background:var(--or);border-color:var(--or);color:#fff;font-weight:600}\u001b[39m\n\u001b[31m.cl-chip-other{border-style:dashed}\u001b[39m\n\u001b[31m.client-tag{display:inline-block;background:#e0f2fe;color:#0369a1;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-left:4px}\u001b[39m\n\u001b[31m.manual-toggle.on{border-color:var(--or);background:#fff7ed;color:var(--or)}\u001b[39m\n\u001b[31m/* picker overlay */\u001b[39m\n\u001b[31m.povl{display:none;position:fixed;inset:0;background:var(--g50);z-index:200;flex-direction:column}\u001b[39m\n\u001b[31m.povl.open{display:flex}\u001b[39m\n\u001b[31m.povl-hdr{background:var(--nv);padding:12px 16px;display:flex;align-items:center;gap:12px;flex-shrink:0}\u001b[39m\n\u001b[31m.psearch{flex:1;padding:10px 14px;border:none;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;background:rgba(255,255,255,.12);color:#fff;outline:none}\u001b[39m\n\u001b[31m.psearch::placeholder{color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.pcancel{background:none;border:none;color:rgba(255,255,255,.7);font-family:'DM Sans',sans-serif;font-size:14px;cursor:pointer;padding:4px;white-space:nowrap}\u001b[39m\n\u001b[31m.plist{overflow-y:auto;flex:1}\u001b[39m\n\u001b[31m.pitem{padding:14px 16px;border-bottom:.5px solid var(--g100);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px}\u001b[39m\n\u001b[31m.pitem:active{background:var(--g100)}\u001b[39m\n\u001b[31m.pi-name{font-size:15px;font-weight:600;color:var(--nv)}.pi-addr{font-size:12px;color:var(--g500);margin-top:2px}.pi-last{font-size:11px;color:var(--am);margin-top:2px}\u001b[39m\n\u001b[31m.pi-brand{font-size:11px;font-weight:700;padding:3px 8px;border-radius:20px;background:var(--nv);color:#fff;flex-shrink:0}\u001b[39m\n\u001b[31m.psec{padding:8px 16px 4px;font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;background:var(--g50)}\u001b[39m\n\u001b[31m.padd{padding:16px;text-align:center;font-size:14px;color:var(--or);font-weight:600;cursor:pointer;background:#fff7ed;border-top:1.5px dashed var(--or)}\u001b[39m\n\u001b[31m.gps-row{display:flex;gap:8px;margin-top:8px}\u001b[39m\n\u001b[31m.gps-btn{flex-shrink:0;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;color:var(--g500);display:flex;align-items:center;gap:6px}\u001b[39m\n\u001b[31m.gps-btn:active{background:var(--orl);border-color:var(--or);color:var(--or)}\u001b[39m\n\u001b[31m@keyframes spin{to{transform:rotate(360deg)}}.spin{animation:spin .7s linear infinite;display:inline-block}\u001b[39m\n\u001b[31m/* ANNOTATION TOOL */\u001b[39m\n\u001b[31m.annot-modal{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column}\u001b[39m\n\u001b[31m.annot-modal.open{display:flex}\u001b[39m\n\u001b[31m.annot-bar{background:var(--nv);padding:8px 12px;flex-shrink:0}\u001b[39m\n\u001b[31m.annot-row{display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap}\u001b[39m\n\u001b[31m.annot-row:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.atool{padding:6px 10px;background:rgba(255,255,255,.1);border:1.5px solid rgba(255,255,255,.2);border-radius:var(--rs);color:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:500;cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.atool.on{background:var(--or);border-color:var(--or)}\u001b[39m\n\u001b[31m.atool.sel-on{background:#7c3aed;border-color:#7c3aed}\u001b[39m\n\u001b[31m.acolor{width:24px;height:24px;border-radius:50%;border:2px solid rgba(255,255,255,.3);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.acolor.on{border-color:#fff;border-width:3px;transform:scale(1.15)}\u001b[39m\n\u001b[31m.annot-cvs-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#111;position:relative}\u001b[39m\n\u001b[31m#annot-cvs{max-width:100%;max-height:100%;display:block;touch-action:none;cursor:crosshair}\u001b[39m\n\u001b[31m.annot-foot{background:var(--nv);padding:10px 16px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.req-note{font-size:12px;color:var(--rd);margin-top:6px;font-weight:500}\u001b[39m\n\u001b[31m/* Bottom dialog */\u001b[39m\n\u001b[31m.bdialog-wrap{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:400;align-items:flex-end}\u001b[39m\n\u001b[31m.bdialog-wrap.open{display:flex}\u001b[39m\n\u001b[31m.bdialog{background:#fff;border-radius:var(--r) var(--r) 0 0;padding:20px 16px 32px;width:100%}\u001b[39m\n\u001b[31m.bdialog-title{font-size:16px;font-weight:700;color:var(--nv);margin-bottom:6px}\u001b[39m\n\u001b[31m.bdialog-sub{font-size:13px;color:var(--g500);margin-bottom:16px}\u001b[39m\n\u001b[31m.bdialog-btns{display:flex;gap:10px}\u001b[39m\n\u001b[31m/* Edit badge on sub-card */\u001b[39m\n\u001b[31m.edit-btn-sm{padding:5px 12px;background:var(--g50);border:1px solid var(--g200);border-radius:20px;font-family:'DM Sans',sans-serif;font-size:12px;color:var(--g600);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m/* Toggle switch */\u001b[39m\n\u001b[31m.tog{width:48px;height:26px;background:var(--g300);border-radius:13px;cursor:pointer;transition:background .2s;flex-shrink:0;position:relative;display:inline-block}\u001b[39m\n\u001b[31m.tog.on{background:var(--or)}\u001b[39m\n\u001b[31m.tog-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2);pointer-events:none}\u001b[39m\n\u001b[31m.tog.on .tog-knob{transform:translateX(22px)}\u001b[39m\n\u001b[31m/* ── ADMIN RECCE VIEW ── */\u001b[39m\n\u001b[31m.af-bar{background:var(--g100);padding:10px 16px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--g200);overflow:hidden}\u001b[39m\n\u001b[31m.af-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}\u001b[39m\n\u001b[31m.af-sel{width:100%;padding:8px 10px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv);cursor:pointer;\u001b[39m\n\u001b[31m  white-space:normal;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.af-sel:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.af-inp{width:100%;padding:8px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv)}\u001b[39m\n\u001b[31m.af-inp:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.grp-hdr{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;\u001b[39m\n\u001b[31m  letter-spacing:.5px;padding:14px 0 6px;border-bottom:1px solid var(--g200);margin-bottom:6px}\u001b[39m\n\u001b[31m.grp-hdr:first-child{padding-top:0}\u001b[39m\n\u001b[31m.asc{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:12px 14px;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;gap:6px;margin-bottom:8px;cursor:pointer;\u001b[39m\n\u001b[31m  transition:box-shadow .15s}\u001b[39m\n\u001b[31m.asc:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.asc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}\u001b[39m\n\u001b[31m.asc-name{font-size:14px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.asc-brand{display:inline-block;background:#fff7ed;color:var(--or);font-size:11px;\u001b[39m\n\u001b[31m  font-weight:600;padding:2px 8px;border-radius:20px;border:1px solid #fed7aa;white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chip{background:var(--g100);border-radius:20px;padding:2px 8px;font-size:11px;color:var(--g600);white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chips{display:flex;flex-wrap:wrap;gap:5px}\u001b[39m\n\u001b[31m.asc-agent{background:var(--nv);color:#fff;font-size:11px;font-weight:600;\u001b[39m\n\u001b[31m  padding:2px 8px;border-radius:20px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m/* Admin detail modal */\u001b[39m\n\u001b[31m.ardl-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:600;\u001b[39m\n\u001b[31m  display:flex;align-items:flex-end;justify-content:center}\u001b[39m\n\u001b[31m.ardl-box{background:#fff;border-radius:var(--r) var(--r) 0 0;width:100%;max-height:80vh;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ardl-hdr{display:flex;align-items:flex-start;justify-content:space-between;\u001b[39m\n\u001b[31m  padding:16px 16px 10px;border-bottom:1px solid var(--g200);gap:10px}\u001b[39m\n\u001b[31m.ardl-title{font-size:17px;font-weight:700;color:var(--nv);line-height:1.3}\u001b[39m\n\u001b[31m.ardl-body{flex:1;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:14px}\u001b[39m\n\u001b[31m.ardl-sec{display:flex;flex-direction:column;gap:6px}\u001b[39m\n\u001b[31m.ardl-lbl{font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.ardl-val{font-size:13px;color:var(--nv);line-height:1.5}\u001b[39m\n\u001b[31m.ardl-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\u001b[39m\n\u001b[31m/* Hub home button */\u001b[39m\n\u001b[31m.btn-hub{background:none;border:1px solid rgba(255,255,255,.25);color:rgba(255,255,255,.85);\u001b[39m\n\u001b[31m  font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;cursor:pointer;\u001b[39m\n\u001b[31m  display:flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-hub:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hdr-r{display:flex;align-items:center;gap:6px;margin-left:auto;flex-shrink:0}\u001b[39m\n\u001b[31m.hdr-user{font-size:11px;color:rgba(255,255,255,.7);white-space:nowrap;max-width:80px;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.btn-logout{background:none;border:1px solid rgba(255,255,255,.2);color:rgba(255,255,255,.7);font-size:11px;font-weight:600;padding:4px 8px;border-radius:20px;cursor:pointer;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-logout:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hero-ubar{display:flex;align-items:center;justify-content:space-between;padding-top:6px;margin-top:2px}\u001b[39m\n\u001b[31m.hero-uname{font-size:12px;color:rgba(255,255,255,.65)}\u001b[39m\n\u001b[31m.hi-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .en-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .hi-txt{display:inline}\u001b[39m\n\u001b[31m.lang-btn{background:none;border:1px solid rgba(255,255,255,.3);color:rgba(255,255,255,.8);font-size:12px;font-weight:700;padding:4px 10px;border-radius:20px;cursor:pointer;display:flex;align-items:center;gap:3px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.lang-btn:active{background:rgba(255,255,255,.15)}\u001b[39m\n\u001b[31m/* ── DELETE / AUDIT ── */\u001b[39m\n\u001b[31m.del-btn{background:none;border:none;padding:6px 8px;cursor:pointer;color:var(--g400);font-size:16px;flex-shrink:0;border-radius:var(--rs);transition:color .15s,background .15s}\u001b[39m\n\u001b[31m.del-btn:active{color:var(--rd);background:#fee2e2}\u001b[39m\n\u001b[31m.asc.deleted-row{background:#fff5f5;border:1px solid #fecaca;opacity:.85}\u001b[39m\n\u001b[31m.asc.deleted-row .asc-name{text-decoration:line-through;color:var(--g500)}\u001b[39m\n\u001b[31m.del-reason-tag{display:inline-block;background:#fee2e2;color:var(--rd);font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.del-by-txt{font-size:11px;color:var(--g400);margin-top:3px}\u001b[39m\n\u001b[31m.restore-btn{background:none;border:1.5px solid #bbf7d0;border-radius:20px;color:#16a34a;font-size:11px;font-weight:700;padding:3px 10px;cursor:pointer;white-space:nowrap;margin-top:5px}\u001b[39m\n\u001b[31m.restore-btn:active{background:#dcfce7}\u001b[39m\n\u001b[31m.sup-tile{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:20px 16px;cursor:pointer;display:flex;align-items:center;gap:14px;margin-bottom:12px;transition:box-shadow .15s}\u001b[39m\n\u001b[31m.sup-tile:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.sup-tile-ico{width:48px;height:48px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:26px;flex-shrink:0}\u001b[39m\n\u001b[31m.sup-tile-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.sup-tile-title{font-size:15px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.sup-tile-sub{font-size:12px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.del-toggle-btn{padding:6px 14px;border:1.5px solid var(--g200);border-radius:20px;background:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:600;color:var(--g500);cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.del-toggle-btn.active{background:#fee2e2;border-color:#fecaca;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1.5px solid var(--g200);border-radius:var(--r);margin-bottom:10px;cursor:pointer;transition:all .15s;font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.reason-opt:active{background:var(--g50)}\u001b[39m\n\u001b[31m.reason-opt.sel{border-color:var(--rd);background:#fff5f5;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt.danger{border-color:#fdba74;background:#fff7ed;color:#9a3412}\u001b[39m\n\u001b[31m.reason-opt.danger.sel{border-color:#c2410c;background:#fff1e6;color:#9a3412}\u001b[39m\n\u001b[31m#del-confirm-btn.no-reason{background:var(--g300)!important;cursor:default}\u001b[39m\n\u001b[31m@keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}\u001b[39m\n\u001b[31m.reason-opt-ico{font-size:22px;flex-shrink:0}\u001b[39m\n\u001b[31m/* ── APP UPDATE BANNER ── */\u001b[39m\n\u001b[31m.upd-banner{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);left:12px;right:12px;background:#16a34a;color:#fff;padding:11px 14px;border-radius:var(--r);display:flex;align-items:center;justify-content:space-between;gap:10px;z-index:550;box-shadow:0 4px 16px rgba(0,0,0,.18);transform:translateY(120px);opacity:0;transition:transform .35s ease,opacity .35s ease;pointer-events:none}\u001b[39m\n\u001b[31m.upd-banner.show{transform:translateY(0);opacity:1;pointer-events:auto}\u001b[39m\n\u001b[31m/* ── EDIT REQUEST ── */\u001b[39m\n\u001b[31m.req-edit-btn{padding:4px 10px;background:#fffbeb;border:1px solid #fde68a;border-radius:20px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:600;color:#92400e;cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.req-edit-btn:active{background:#fef3c7}\u001b[39m\n\u001b[31m.edit-req-badge{display:inline-block;background:#fef3c7;color:#92400e;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;white-space:nowrap}\u001b[39m\n\u001b[31m.edit-req-card{background:#fffbeb;border:1.5px solid #fde68a;border-radius:var(--r);padding:14px 16px;margin-bottom:10px;display:flex;align-items:flex-start;gap:12px}\u001b[39m\n\u001b[31m.edit-req-card-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.edit-req-card-name{font-size:14px;font-weight:600;color:var(--nv);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.edit-req-card-meta{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.edit-req-cmt{font-size:12px;color:#78350f;background:#fff;border:1px solid #fde68a;border-radius:var(--rs);padding:8px 10px;margin-top:8px;line-height:1.5}\u001b[39m\n\u001b[31m.edit-req-section-hdr{font-size:11px;font-weight:700;color:#92400e;text-transform:uppercase;letter-spacing:.5px;padding:10px 0 6px;border-bottom:1px solid #fde68a;margin-bottom:8px}\u001b[39m\n\u001b[31m.upd-banner-ok{background:rgba(255,255,255,.2);border:none;color:#fff;border-radius:20px;padding:5px 13px;font-size:12px;font-weight:600;cursor:pointer;font-family:'DM Sans',sans-serif;white-space:nowrap}\u001b[39m\n\u001b[31m.upd-banner-ok:active{background:rgba(255,255,255,.35)}\u001b[39m\n\u001b[31m/* ── FONT SIZE WIDGET ── */\u001b[39m\n\u001b[31m.fs-widget{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);right:12px;display:flex;align-items:center;gap:0;background:#fff;border:1.5px solid var(--g200);border-radius:24px;box-shadow:0 2px 8px rgba(0,0,0,.12);z-index:500;overflow:hidden;user-select:none}\u001b[39m\n\u001b[31m.fs-btn{background:none;border:none;cursor:pointer;padding:7px 11px;color:var(--g500);line-height:1;transition:background .15s}\u001b[39m\n\u001b[31m.fs-btn:active{background:var(--g100)}\u001b[39m\n\u001b[31m.fs-btn:disabled{color:var(--g300);cursor:default}\u001b[39m\n\u001b[31m.fs-label{font-size:11px;font-weight:700;color:var(--g500);padding:0 4px;pointer-events:none}\u001b[39m\n\u001b[31m/* Level 1 — Large (+15%) */\u001b[39m\n\u001b[31mbody.fs-1 .field label,body.fs-1 .card-title,body.fs-1 .set-lbl,body.fs-1 .set-sub,\u001b[39m\n\u001b[31mbody.fs-1 .hdr-title,body.fs-1 .hdr-sub,body.fs-1 .slbl,body.fs-1 .rev-lbl,body.fs-1 .rev-val,\u001b[39m\n\u001b[31mbody.fs-1 .rbtn,body.fs-1 .chip,body.fs-1 .btn-p,body.fs-1 .btn-s,body.fs-1 .btn-o,\u001b[39m\n\u001b[31mbody.fs-1 .bdialog-title,body.fs-1 .bdialog-sub,body.fs-1 .sub-name,body.fs-1 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-1 .pslot-lbl,body.fs-1 .bitem-title,body.fs-1 .pi-name,body.fs-1 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-1 .asc-name,body.fs-1 .new-btn,body.fs-1 .resume-btn,body.fs-1 .ardl-lbl,body.fs-1 .ardl-val{font-size:calc(1em * 1.15) !important}\u001b[39m\n\u001b[31m/* Level 2 — X-Large (+30%) */\u001b[39m\n\u001b[31mbody.fs-2 .field label,body.fs-2 .card-title,body.fs-2 .set-lbl,body.fs-2 .set-sub,\u001b[39m\n\u001b[31mbody.fs-2 .hdr-title,body.fs-2 .hdr-sub,body.fs-2 .slbl,body.fs-2 .rev-lbl,body.fs-2 .rev-val,\u001b[39m\n\u001b[31mbody.fs-2 .rbtn,body.fs-2 .chip,body.fs-2 .btn-p,body.fs-2 .btn-s,body.fs-2 .btn-o,\u001b[39m\n\u001b[31mbody.fs-2 .bdialog-title,body.fs-2 .bdialog-sub,body.fs-2 .sub-name,body.fs-2 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-2 .pslot-lbl,body.fs-2 .bitem-title,body.fs-2 .pi-name,body.fs-2 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-2 .asc-name,body.fs-2 .new-btn,body.fs-2 .resume-btn,body.fs-2 .ardl-lbl,body.fs-2 .ardl-val{font-size:calc(1em * 1.30) !important}\u001b[39m\n\u001b[31m/* Level 3 — XX-Large (+50%) */\u001b[39m\n\u001b[31mbody.fs-3 .field label,body.fs-3 .card-title,body.fs-3 .set-lbl,body.fs-3 .set-sub,\u001b[39m\n\u001b[31mbody.fs-3 .hdr-title,body.fs-3 .hdr-sub,body.fs-3 .slbl,body.fs-3 .rev-lbl,body.fs-3 .rev-val,\u001b[39m\n\u001b[31mbody.fs-3 .rbtn,body.fs-3 .chip,body.fs-3 .btn-p,body.fs-3 .btn-s,body.fs-3 .btn-o,\u001b[39m\n\u001b[31mbody.fs-3 .bdialog-title,body.fs-3 .bdialog-sub,body.fs-3 .sub-name,body.fs-3 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-3 .pslot-lbl,body.fs-3 .bitem-title,body.fs-3 .pi-name,body.fs-3 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-3 .asc-name,body.fs-3 .new-btn,body.fs-3 .resume-btn,body.fs-3 .ardl-lbl,body.fs-3 .ardl-val{font-size:calc(1em * 1.50) !important}\u001b[39m\n\u001b[31m/* Level 4 — Max (+70%) */\u001b[39m\n\u001b[31mbody.fs-4 .field label,body.fs-4 .card-title,body.fs-4 .set-lbl,body.fs-4 .set-sub,\u001b[39m\n\u001b[31mbody.fs-4 .hdr-title,body.fs-4 .hdr-sub,body.fs-4 .slbl,body.fs-4 .rev-lbl,body.fs-4 .rev-val,\u001b[39m\n\u001b[31mbody.fs-4 .rbtn,body.fs-4 .chip,body.fs-4 .btn-p,body.fs-4 .btn-s,body.fs-4 .btn-o,\u001b[39m\n\u001b[31mbody.fs-4 .bdialog-title,body.fs-4 .bdialog-sub,body.fs-4 .sub-name,body.fs-4 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-4 .pslot-lbl,body.fs-4 .bitem-title,body.fs-4 .pi-name,body.fs-4 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-4 .asc-name,body.fs-4 .new-btn,body.fs-4 .resume-btn,body.fs-4 .ardl-lbl,body.fs-4 .ardl-val{font-size:calc(1em * 1.70) !important}\u001b[39m\n\u001b[31m/* ── RECCE TILE ACTION BUTTONS ── */\u001b[39m\n\u001b[31m.rpt-btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid rgba(0,0,0,.06)}\u001b[39m\n\u001b[31m.rpt-btn{display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 14px;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;border:none;font-family:inherit;transition:background .15s,opacity .15s;flex:1;min-width:110px;letter-spacing:.1px;white-space:nowrap}\u001b[39m\n\u001b[31m.rpt-btn-report{background:#fff7ed;color:var(--or);border:1.5px solid var(--or)}\u001b[39m\n\u001b[31m.rpt-btn-report:active{background:#fed7aa}\u001b[39m\n\u001b[31m.rpt-btn-pdf{background:var(--g100);color:var(--g400);border:1.5px solid var(--g200)}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready{background:var(--or);color:#fff;border-color:transparent}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready:active{background:#ea6c00}\u001b[39m\n\u001b[31m/* PDF wait overlay */\u001b[39m\n\u001b[31m#pdf-wait-ov{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m</style>\u001b[39m\n\u001b[31m</head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<!-- PICKER OVERLAY -->\u001b[39m\n\u001b[31m<div class=\\\"povl\\\" id=\\\"povl\\\">\u001b[39m\n\u001b[31m  <div class=\\\"povl-hdr\\\">\u001b[39m\n\u001b[31m    <input class=\\\"psearch\\\" id=\\\"psearch\\\" type=\\\"text\\\" placeholder=\\\"Search store / दुकान खोजें…\\\" oninput=\\\"filterPicker(this.value)\\\" autocomplete=\\\"off\\\">\u001b[39m\n\u001b[31m    <button class=\\\"pcancel\\\" onclick=\\\"closePicker()\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"plist\\\" id=\\\"plist\\\"></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"app\\\">·\u001b[39m\n\u001b[31m<!-- HOME -->\u001b[39m\n\u001b[31m<div class=\\\"view active\\\" id=\\\"view-home\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hero\\\">\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;justify-content:space-between;align-items:center\\\">\u001b[39m\n\u001b[31m      <div><div class=\\\"hero-title\\\"><span class=\\\"en-txt\\\">Branding Recce</span><span class=\\\"hi-txt\\\">ब्रांडिंग रेकी</span></div><div class=\\\"hero-sub\\\" id=\\\"today-date\\\">—</div></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:6px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"lang-btn\\\" onclick=\\\"setLang(LANG==='en'?'hi':'en')\\\" id=\\\"lang-btn\\\" title=\\\"Switch language / भाषा बदलें\\\">EN | हि</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-hub\\\" onclick=\\\"goToHub()\\\">🏡 Hub</button>\u001b[39m\n\u001b[31m      <button class=\\\"icon-btn\\\" onclick=\\\"showView('settings')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12 15a3 3 0 100-6 3 3 0 000 6z\\\"/><path d=\\\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\\\"/></svg></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"hero-ubar\\\" id=\\\"recce-hero-ubar\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <span class=\\\"hero-uname\\\" id=\\\"recce-hero-name\\\"></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-logout\\\" onclick=\\\"recceLogout()\\\">Logout</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"stats\\\">\u001b[39m\n\u001b[31m      <div class=\\\"scard g\\\"><div class=\\\"snum\\\" id=\\\"stat-synced\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Synced</span><span class=\\\"hi-txt\\\">सिंक्ड</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard a\\\"><div class=\\\"snum\\\" id=\\\"stat-pending\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Pending</span><span class=\\\"hi-txt\\\">बाकी</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard\\\"><div class=\\\"snum\\\" id=\\\"stat-total\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Total</span><span class=\\\"hi-txt\\\">कुल</span></div></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <button class=\\\"new-btn\\\" onclick=\\\"startNewRecce()\\\"><svg width=\\\"20\\\" height=\\\"20\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">New Recce</span><span class=\\\"hi-txt\\\">नई रेकी</span></button>\u001b[39m\n\u001b[31m    <div id=\\\"resume-wrap\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"sh\\\"><span class=\\\"st\\\"><span class=\\\"en-txt\\\">Recent Submissions</span><span class=\\\"hi-txt\\\">हाल की सबमिशन</span></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"syncNow()\\\" id=\\\"sync-btn\\\" style=\\\"padding:7px 12px;font-size:12px\\\"><svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg><span class=\\\"en-txt\\\">Sync</span><span class=\\\"hi-txt\\\">सिंक</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"sub-list\\\"></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"srow\\\"><div><span class=\\\"sdot\\\" id=\\\"net-dot\\\"></span><span id=\\\"net-txt\\\"><span class=\\\"en-txt\\\">Checking…</span><span class=\\\"hi-txt\\\">जाँच…</span></span></div><span id=\\\"last-sync-txt\\\" style=\\\"font-size:11px\\\"><span class=\\\"en-txt\\\">Never synced</span><span class=\\\"hi-txt\\\">कभी सिंक नहीं</span></span></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- SETTINGS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-settings\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('home')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Settings</span><span class=\\\"hi-txt\\\">सेटिंग</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Brand List</span><span class=\\\"hi-txt\\\">ब्रांड सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Manage Brands</span><span class=\\\"hi-txt\\\">ब्रांड प्रबंधन</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">These appear in the brand dropdown and store picker. Add client brands as needed.</div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-manage-list\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-add-row\\\" style=\\\"display:none;gap:8px;align-items:center\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"brand-add-inp\\\" placeholder=\\\"Type brand name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addBrandToList()\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"addBrandToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Store Lists</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Supervisors can upload XLS/CSV store lists here. Updates sync to all devices via server.</span><span class=\\\"hi-txt\\\">सुपरवाइजर यहाँ XLS/CSV स्टोर सूची अपलोड कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m      <!-- Upload/Clear row — supervisor only -->\u001b[39m\n\u001b[31m      <div id=\\\"store-upload-row\\\" style=\\\"display:none;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;margin-top:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"document.getElementById('store-xl').click()\\\"><svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Add File</span><span class=\\\"hi-txt\\\">फ़ाइल जोड़ें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-d\\\" onclick=\\\"clearStoreList()\\\" style=\\\"font-size:12px\\\"><span class=\\\"en-txt\\\">Clear All Stores</span><span class=\\\"hi-txt\\\">सभी स्टोर हटाएं</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" id=\\\"store-push-btn\\\" onclick=\\\"pushStoresToServer()\\\" style=\\\"font-size:12px;display:none\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Push to Server</span><span class=\\\"hi-txt\\\">सर्वर पर पुश करें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"store-xl\\\" accept=\\\".xlsx,.xls,.csv\\\" onchange=\\\"handleStoreUpload(event)\\\">\u001b[39m\n\u001b[31m      <div id=\\\"store-count\\\" style=\\\"font-size:13px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"store-file-list\\\" style=\\\"margin-top:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Brand assignment dialog for files with no brand column -->\u001b[39m\n\u001b[31m    <div id=\\\"brand-assign-dialog\\\" style=\\\"display:none;margin-top:10px;padding:14px;background:#fff7ed;border:1.5px solid var(--or);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\">Which brand is this store list for?</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\" id=\\\"brand-assign-fname\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-assign-chips\\\" class=\\\"chip-grid\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"confirmBrandAssign()\\\" style=\\\"flex:2;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">Assign Brand</span><span class=\\\"hi-txt\\\">ब्रांड असाइन करें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"skipBrandAssign()\\\" style=\\\"flex:1;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">No Brand</span><span class=\\\"hi-txt\\\">कोई ब्रांड नहीं</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Server Store List URL (Admin)</span><span class=\\\"hi-txt\\\">सर्वर स्टोर सूची URL</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Admin pushes stores.json to any public URL. App auto-fetches on open and caches offline.</div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"srv-url\\\" placeholder=\\\"https://yourserver.com/stores.json\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"fetchServerStores()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Fetch Now</button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"saveServerUrl()\\\" style=\\\"padding:9px 14px;font-size:13px;width:auto\\\">Save URL</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Sync Endpoint</span><span class=\\\"hi-txt\\\">सिंक एंडपॉइंट</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Slides Generator</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Managed by admin. Deploy gas_slides.gs from /opt/slides-proxy/ to Google Apps Script and paste the URL here.</div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"slides-gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Not configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"slides-gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"saveSlidesGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Sheet Sync</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Legacy sync endpoint. Writes recce data to Google Sheet.</div>·\u001b[39m\n\u001b[31m      <!-- Locked state (default) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Endpoint configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Unlocked state (after admin login) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;align-items:center;gap:8px;margin-bottom:10px;padding:7px 12px;background:#dcfce7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          <span style=\\\"font-size:12px;color:#14532d;font-weight:600\\\">🔓 Admin mode active</span>\u001b[39m\n\u001b[31m          <button onclick=\\\"lockAdmin()\\\" style=\\\"margin-left:auto;background:none;border:none;color:#14532d;font-size:12px;cursor:pointer;font-weight:600\\\">Lock ×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"testEndpoint()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Test</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>·\u001b[39m\n\u001b[31m    <!-- Admin Login Modal -->\u001b[39m\n\u001b[31m    <div id=\\\"admin-login-modal\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m      <div style=\\\"background:#fff;border-radius:var(--r);padding:24px 20px;margin:20px;max-width:380px;width:100%;box-shadow:0 8px 32px rgba(0,0,0,.2)\\\">\u001b[39m\n\u001b[31m        <div style=\\\"font-size:17px;font-weight:700;color:var(--nv);margin-bottom:4px\\\">Admin Login</div>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:18px\\\">Enter admin password to unlock settings</div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m          <label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">Password</label>\u001b[39m\n\u001b[31m          <input type=\\\"password\\\" id=\\\"admin-pwd\\\" placeholder=\\\"Enter admin password\\\" style=\\\"width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px\\\" onkeydown=\\\"if(event.key==='Enter')verifyAdmin()\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div id=\\\"admin-error\\\" style=\\\"display:none;font-size:12px;color:var(--rd);margin-bottom:12px;padding:8px 12px;background:#fee2e2;border-radius:var(--rs)\\\">Incorrect password</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"verifyAdmin()\\\" style=\\\"flex:2;padding:13px\\\" id=\\\"admin-login-btn\\\">Login</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-s\\\" onclick=\\\"closeAdminLogin()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:14px;padding-top:14px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.4px;margin-bottom:8px\\\">Admin Password Config URL</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:8px\\\">URL to your admin.json file on server (contains hashed password)</div>\u001b[39m\n\u001b[31m          <input type=\\\"url\\\" id=\\\"admin-cfg-url\\\" placeholder=\\\"https://yourserver.com/admin.json\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px;margin-bottom:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveAdminCfgUrl()\\\" style=\\\"font-size:12px;padding:7px 12px;width:100%;justify-content:center\\\">Save Config URL</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Geolocation Stamp</span><span class=\\\"hi-txt\\\">जियोलोकेशन स्टैम्प</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;justify-content:space-between;gap:16px\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1\\\">\u001b[39m\n\u001b[31m          <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Stamp on Photos</span><span class=\\\"hi-txt\\\">फोटो पर स्टैम्प</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"set-sub\\\" style=\\\"margin-bottom:0\\\">Bakes GPS coordinates, store name and timestamp into every photo — visible in the image itself. Same as GPS Map Camera app. Default: On.</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"tog on\\\" id=\\\"geo-tog\\\" onclick=\\\"toggleGeoStamp()\\\"><div class=\\\"tog-knob\\\"></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"geo-status\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\">GPS not yet captured</div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Image Quality</span><span class=\\\"hi-txt\\\">फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Default Photo Quality</span><span class=\\\"hi-txt\\\">डिफ़ॉल्ट फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Applies to all photos — front view, inside view, branding, and additional. HD uses more storage and takes longer to sync on poor networks.</div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;gap:10px;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-compressed\\\" onclick=\\\"setImgQuality('compressed')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-compressed\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-compressed\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">Full Compression</span><span class=\\\"hi-txt\\\">पूर्ण कम्प्रेशन</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~150–200 KB · Max 1280px · Best for poor network</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-left:auto;font-size:11px;font-weight:700;color:var(--gn);background:#dcfce7;padding:3px 8px;border-radius:20px\\\"><span class=\\\"en-txt\\\">Recommended</span><span class=\\\"hi-txt\\\">अनुशंसित</span></div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-hd\\\" onclick=\\\"setImgQuality('hd')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-hd\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-hd\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">HD Quality</span><span class=\\\"hi-txt\\\">HD क्वालिटी</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~400–600 KB · Max 1920px · Better detail for print</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"q-current-badge\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Supervisor Config panel — shown only to supervisors via renderSupPanel() -->\u001b[39m\n\u001b[31m    <div id=\\\"sup-panel\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">🔐 Recce Access Config</span><span class=\\\"hi-txt\\\">🔐 रेकी एक्सेस कॉन्फ़िग</span></div>\u001b[39m\n\u001b[31m      <!-- Access mode — only H/P can change -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"mode-row\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Access Mode</span><span class=\\\"hi-txt\\\">एक्सेस मोड</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Public: any Hub user can submit Recces. Assigned: only Supervisors and Creators can access.</span><span class=\\\"hi-txt\\\">सार्वजनिक: कोई भी Hub यूजर। नियत: सिर्फ़ Supervisors और Creators।</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\" style=\\\"margin-bottom:8px;margin-top:8px\\\">\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-public\\\" onclick=\\\"setRecceMode('public')\\\"><span class=\\\"en-txt\\\">Public</span><span class=\\\"hi-txt\\\">सार्वजनिक</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-assigned\\\" onclick=\\\"setRecceMode('assigned')\\\"><span class=\\\"en-txt\\\">Assigned</span><span class=\\\"hi-txt\\\">नियत</span></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Supervisor list — view all + delete + create -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Supervisors</span><span class=\\\"hi-txt\\\">सुपरवाइजर</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can view all recces, delete with reason, and submit. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">सभी रेकी देख सकते हैं, कारण से हटा सकते हैं, और सबमिट कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"sup-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addSupervisor()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addSupervisor()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Creator list — creation only -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Creators</span><span class=\\\"hi-txt\\\">क्रिएटर्स</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can submit Recces only — no admin view or deletion rights. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">केवल रेकी सबमिट कर सकते हैं — एडमिन व्यू या डिलीट नहीं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"creator-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addCreator()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addCreator()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Client list — used for client portal scoping -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clients</span><span class=\\\"hi-txt\\\">क्लाइंट</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Names that appear as chips when submitting a recce. Add the brand or agency name (e.g. \\\"Marketing Vibe\\\"). These are used to scope what clients see in the Client Portal.</span><span class=\\\"hi-txt\\\">रेकी सबमिट करते समय दिखने वाले क्लाइंट नाम। ब्रांड या एजेंसी नाम जोड़ें।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-mgmt-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"client-add-inp\\\" placeholder=\\\"Client name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addClientToList()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addClientToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Sync to server — only H/P -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"cfg-sync-btn\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Sync Config to Server</span><span class=\\\"hi-txt\\\">सर्वर पर कॉन्फ़िग सिंक करें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Apply supervisor/creator/client lists and access mode to all devices.</span><span class=\\\"hi-txt\\\">सभी डिवाइस पर कॉन्फ़िग लागू करें।</span></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"syncCfgToServer()\\\" style=\\\"max-width:220px;font-size:14px;padding:12px;margin-top:8px\\\"><span class=\\\"en-txt\\\">Sync to Server</span><span class=\\\"hi-txt\\\">सर्वर पर सिंक करें</span></button>\u001b[39m\n\u001b[31m        <div id=\\\"cfg-sync-status\\\" style=\\\"margin-top:8px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Danger Zone</span><span class=\\\"hi-txt\\\">खतरनाक ज़ोन</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\"><div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clear All Local Data</span><span class=\\\"hi-txt\\\">सभी डेटा हटाएं</span></div><div class=\\\"set-sub\\\">Removes all submissions from this device.</div><button class=\\\"btn-d\\\" onclick=\\\"clearData()\\\" style=\\\"padding:9px 14px;font-size:13px\\\">Clear All</button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: STORE INFO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-store\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"exitForm()\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Details</span><span class=\\\"hi-txt\\\">दुकान विवरण</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 1 of 5</span><span class=\\\"hi-txt\\\">चरण 1 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:20%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Recce Info</span><span class=\\\"hi-txt\\\">रेकी जानकारी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Date of Recce</span><span class=\\\"hi-txt\\\">रेकी की तारीख</span> <span class=\\\"req\\\">*</span></label><input type=\\\"date\\\" id=\\\"f-date\\\" onchange=\\\"saveDraft()\\\" max=\\\"\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" id=\\\"campaign-field\\\">\u001b[39m\n\u001b[31m        <label><span class=\\\"en-txt\\\">Job / Campaign</span><span class=\\\"hi-txt\\\">जॉब / कैंपेन</span></label>\u001b[39m\n\u001b[31m        <select id=\\\"f-campaign-id\\\" onchange=\\\"onCampaignSelect()\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">Loading campaigns…</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <div id=\\\"campaign-notify-msg\\\" style=\\\"display:none;font-size:12px;color:#92400e;margin-top:6px;padding:8px 10px;background:#fef3c7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          ⚑ <span class=\\\"en-txt\\\">Recce will submit without a job ID. A notification will flag this for your supervisor to link it later.</span><span class=\\\"hi-txt\\\">रेकी बिना जॉब ID के सबमिट होगी। सुपरवाइजर बाद में लिंक करेगा।</span>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Store</span><span class=\\\"hi-txt\\\">दुकान</span> <span id=\\\"store-avail-tag\\\" style=\\\"font-size:11px;color:var(--g400);font-weight:400;text-transform:none;letter-spacing:0\\\"></span></div>·\u001b[39m\n\u001b[31m      <!-- When store is selected -->\u001b[39m\n\u001b[31m      <div id=\\\"store-selected\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"store-card\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:start;justify-content:space-between;gap:8px\\\">\u001b[39m\n\u001b[31m            <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m              <div class=\\\"store-card-name\\\" id=\\\"sc-name\\\">—</div>\u001b[39m\n\u001b[31m              <div style=\\\"display:flex;align-items:center;gap:6px;margin-top:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m                <span class=\\\"brand-tag\\\" id=\\\"sc-brand\\\">—</span>\u001b[39m\n\u001b[31m                <span class=\\\"last-chip\\\" id=\\\"sc-last\\\" style=\\\"display:none\\\">—</span>\u001b[39m\n\u001b[31m              </div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            <button class=\\\"store-card-change\\\" onclick=\\\"openPicker()\\\"><span class=\\\"en-txt\\\">Change ›</span><span class=\\\"hi-txt\\\">बदलें ›</span></button>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <!-- All fields from Excel shown here -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-details\\\" style=\\\"margin-top:10px;display:flex;flex-direction:column;gap:4px\\\"></div>\u001b[39m\n\u001b[31m          <!-- Missing required fields — editable inline -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-missing\\\" style=\\\"display:none;margin-top:12px;padding-top:12px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m            <div style=\\\"font-size:11px;font-weight:700;color:var(--rd);text-transform:uppercase;letter-spacing:.4px;margin-bottom:10px\\\">⚠ Please complete missing fields</div>\u001b[39m\n\u001b[31m            <div id=\\\"sc-missing-fields\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <!-- Brand selector — shown when store has no brand -->\u001b[39m\n\u001b[31m        <div id=\\\"brand-selector\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\"><span class=\\\"en-txt\\\">Select Brand</span><span class=\\\"hi-txt\\\">ब्रांड चुनें</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\">This store has no brand in the list — select one:</div>\u001b[39m\n\u001b[31m          <div id=\\\"brand-chips\\\" class=\\\"chip-grid\\\"></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Picker trigger (shown when stores loaded) -->\u001b[39m\n\u001b[31m      <div id=\\\"pick-trigger-wrap\\\">\u001b[39m\n\u001b[31m        <div class=\\\"pick-trigger\\\" onclick=\\\"openPicker()\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:center;gap:10px\\\">\u001b[39m\n\u001b[31m            <span style=\\\"font-size:20px\\\">🏪</span>\u001b[39m\n\u001b[31m            <div>\u001b[39m\n\u001b[31m              <div style=\\\"font-size:15px;font-weight:700;color:var(--or)\\\"><span class=\\\"en-txt\\\">Select Store from List</span><span class=\\\"hi-txt\\\">सूची से दुकान चुनें</span></div>\u001b[39m\n\u001b[31m              <div id=\\\"store-avail-count\\\" style=\\\"font-size:12px;font-weight:400;color:var(--am);margin-top:1px\\\"><span class=\\\"en-txt\\\">Tap to browse stores</span><span class=\\\"hi-txt\\\">दुकान खोजने के लिए दबाएं</span></div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual / new store toggle -->\u001b[39m\n\u001b[31m      <div class=\\\"manual-toggle\\\" id=\\\"manual-toggle\\\" onclick=\\\"toggleManual()\\\">\u001b[39m\n\u001b[31m        <svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\" id=\\\"mt-icon\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg>\u001b[39m\n\u001b[31m        <span id=\\\"mt-label\\\"><span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span></span>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual fields -->\u001b[39m\n\u001b[31m      <div id=\\\"manual-fields\\\" style=\\\"display:none;margin-top:14px\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\" style=\\\"margin-bottom:14px\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <select id=\\\"f-brand\\\" onchange=\\\"onManualBrandChange()\\\">\u001b[39m\n\u001b[31m            <option value=\\\"\\\">Select brand</option>\u001b[39m\n\u001b[31m          </select>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span> <span class=\\\"req\\\">*</span></label><input type=\\\"text\\\" id=\\\"f-store\\\" placeholder=\\\"Enter store name\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\">\u001b[39m\n\u001b[31m          <label><span class=\\\"en-txt\\\">Store Address</span><span class=\\\"hi-txt\\\">दुकान का पता</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <textarea id=\\\"f-addr\\\" rows=\\\"2\\\" placeholder=\\\"Full address\\\" onchange=\\\"saveDraft()\\\"></textarea>\u001b[39m\n\u001b[31m          <div class=\\\"gps-row\\\">\u001b[39m\n\u001b[31m            <button class=\\\"gps-btn\\\" onclick=\\\"captureGPS()\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\"/><path d=\\\"M12 2v3M12 19v3M2 12h3M19 12h3\\\"/></svg><span class=\\\"en-txt\\\">Capture GPS</span><span class=\\\"hi-txt\\\">GPS लें</span></button>\u001b[39m\n\u001b[31m            <span id=\\\"gps-status\\\" style=\\\"font-size:12px;color:var(--g500);align-self:center\\\"></span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Mobile No.</span><span class=\\\"hi-txt\\\">मोबाइल नंबर</span></label><input type=\\\"tel\\\" id=\\\"f-mobile\\\" placeholder=\\\"10-digit number\\\" maxlength=\\\"10\\\" inputmode=\\\"numeric\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Client card -->\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Client</span><span class=\\\"hi-txt\\\">क्लाइंट</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\"><span class=\\\"en-txt\\\">Select who this recce is for. Defaults to brand — change if work came via an agency.</span><span class=\\\"hi-txt\\\">यह रेकी किसके लिए है चुनें। ब्रांड से डिफ़ॉल्ट — एजेंसी के ज़रिए हो तो बदलें।</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"cl-chip-grid\\\" id=\\\"client-chips\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"client-other-wrap\\\" style=\\\"display:none;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"f-client-other\\\" placeholder=\\\"Type client name\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" oninput=\\\"onClientOtherInput()\\\">\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-p\\\" onclick=\\\"step2()\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: PHOTOS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-photos\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-store')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Photos</span><span class=\\\"hi-txt\\\">दुकान की फोटो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 2 of 5</span><span class=\\\"hi-txt\\\">चरण 2 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:40%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Front View</span><span class=\\\"hi-txt\\\">आगे का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(min 1, max 3)</span><span class=\\\"cnt-badge gray\\\" id=\\\"front-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"front-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-front\\\" onclick=\\\"addPhoto('front')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Front Photo</span><span class=\\\"hi-txt\\\">आगे की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Inside View</span><span class=\\\"hi-txt\\\">अंदर का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 5)</span><span class=\\\"cnt-badge gray\\\" id=\\\"inside-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"inside-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-inside\\\" onclick=\\\"addPhoto('inside')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Inside Photo</span><span class=\\\"hi-txt\\\">अंदर की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-store')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step3()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: VIDEO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-video\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-photos')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Recce Video</span><span class=\\\"hi-txt\\\">रेकी वीडियो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 3 of 5</span><span class=\\\"hi-txt\\\">चरण 3 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:60%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Video</span><span class=\\\"hi-txt\\\">वीडियो</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Recce video available?</span><span class=\\\"hi-txt\\\">रेकी वीडियो है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"vid-yes\\\" onclick=\\\"setVideo(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"vid-no\\\" onclick=\\\"setVideo(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"vid-sec\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Upload Video</span><span class=\\\"hi-txt\\\">वीडियो अपलोड करें</span></label>\u001b[39m\n\u001b[31m          <div class=\\\"pslot\\\" id=\\\"vid-slot\\\" onclick=\\\"document.getElementById('vid-inp').click()\\\"><div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div></div>\u001b[39m\n\u001b[31m          <input type=\\\"file\\\" id=\\\"vid-inp\\\" accept=\\\"video/*\\\" onchange=\\\"handleVideo(event)\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Video Comments</span><span class=\\\"hi-txt\\\">वीडियो टिप्पणी</span></label><input type=\\\"text\\\" id=\\\"f-vid-cmt\\\" placeholder=\\\"Optional\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-photos')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step4()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: BRANDING -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-branding\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-video')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Branding</span><span class=\\\"hi-txt\\\">ब्रांडिंग</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 4 of 5</span><span class=\\\"hi-txt\\\">चरण 4 / 5</span></div></div></div>\u001b[39m\n\u001b[31m    <span id=\\\"br-hdr-badge\\\" style=\\\"background:rgba(255,255,255,.2);color:#fff;font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px\\\"><span class=\\\"en-txt\\\">0 items</span><span class=\\\"hi-txt\\\">0 आइटम</span></span>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:80%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Branding Space</span><span class=\\\"hi-txt\\\">ब्रांडिंग स्थान</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Space available?</span><span class=\\\"hi-txt\\\">जगह उपलब्ध है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"br-yes\\\" onclick=\\\"setBranding(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"br-no\\\" onclick=\\\"setBranding(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"branding-lock-banner\\\" style=\\\"display:none;background:#fef3c7;border:1.5px solid #f59e0b;border-radius:10px;padding:12px 14px;margin-bottom:10px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:700;color:#92400e\\\">Client approval exists — branding locked</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:#78350f;margin-top:4px\\\"><span class=\\\"en-txt\\\">The client has reviewed this recce. Create a new recce to revise branding items.</span><span class=\\\"hi-txt\\\">क्लाइंट ने रेकी की समीक्षा की है। बदलाव के लिए नई रेकी बनाएं।</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"branding-override-wrap\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m        <button onclick=\\\"unlockBrandingOverride()\\\" style=\\\"background:#f59e0b;color:#000;border:none;border-radius:8px;padding:8px 14px;font-size:12px;font-weight:700;cursor:pointer\\\">Override Edit (H&amp;P only)</button>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:11px;color:#92400e;margin-top:5px\\\">Use only when client has verbally confirmed and app needs correction.</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"br-items\\\"></div>\u001b[39m\n\u001b[31m    <div id=\\\"br-add\\\" style=\\\"display:none;margin-bottom:80px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"addBranding()\\\" style=\\\"width:100%;justify-content:center\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Another Branding Item</span><span class=\\\"hi-txt\\\">एक और ब्रांडिंग जोड़ें</span></button>\u001b[39m\n\u001b[31m      <div style=\\\"text-align:center;font-size:12px;color:var(--g400);margin-top:8px\\\"><span class=\\\"en-txt\\\">Tap Continue below when done adding items</span><span class=\\\"hi-txt\\\">सभी आइटम जोड़ने के बाद आगे दबाएं</span></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-video')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step5()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: ADDITIONAL + SUBMIT -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-additional\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-branding')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Submit</span><span class=\\\"hi-txt\\\">सबमिट</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 5 of 5</span><span class=\\\"hi-txt\\\">चरण 5 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:100%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Mandatory Document</span><span class=\\\"hi-txt\\\">अनिवार्य दस्तावेज़</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"pslot\\\" id=\\\"doc-slot\\\" onclick=\\\"document.getElementById('doc-inp').click()\\\"><div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div></div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"doc-inp\\\" accept=\\\"image/*,.pdf\\\" onchange=\\\"handleDoc(event)\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Additional Photos</span><span class=\\\"hi-txt\\\">अतिरिक्त फोटो</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 8)</span><span class=\\\"cnt-badge gray\\\" id=\\\"addl-badge\\\">0 / 8</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"add-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-addl\\\" onclick=\\\"addAdditional()\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\"><div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Review</span><span class=\\\"hi-txt\\\">समीक्षा</span></div><div id=\\\"rev-body\\\"></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-branding')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"submitRecce()\\\" id=\\\"sub-btn\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Submit Recce ✓</span><span class=\\\"hi-txt\\\">रेकी सबमिट करें ✓</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- ANNOTATION MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"annot-modal\\\" id=\\\"annot-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"annot-bar\\\">\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Draw:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"at-rect\\\"    onclick=\\\"setATool('rect')\\\">▭ Rect</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-ellipse\\\" onclick=\\\"setATool('ellipse')\\\">◯ Ellipse</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-line\\\"    onclick=\\\"setATool('line')\\\">╱ Line</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-arrow\\\"   onclick=\\\"setATool('arrow')\\\">↗ Arrow</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-free\\\"    onclick=\\\"setATool('free')\\\">✏ Free</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool sel-on\\\" id=\\\"at-move\\\" onclick=\\\"setATool('move')\\\" style=\\\"margin-left:4px\\\">⊹ Move</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Color:</span>\u001b[39m\n\u001b[31m      <div class=\\\"acolor on\\\" id=\\\"ac-or\\\" style=\\\"background:#f97316\\\" onclick=\\\"setAColor('#f97316')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-rd\\\" style=\\\"background:#ef4444\\\" onclick=\\\"setAColor('#ef4444')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-wh\\\" style=\\\"background:#ffffff\\\" onclick=\\\"setAColor('#ffffff')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-yw\\\" style=\\\"background:#facc15\\\" onclick=\\\"setAColor('#facc15')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-gn\\\" style=\\\"background:#22c55e\\\" onclick=\\\"setAColor('#22c55e')\\\"></div>\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Width:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-2\\\" onclick=\\\"setAWidth(2)\\\" style=\\\"padding:5px 8px\\\">Thin</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"aw-4\\\" onclick=\\\"setAWidth(4)\\\" style=\\\"padding:5px 8px\\\">Med</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-7\\\" onclick=\\\"setAWidth(7)\\\" style=\\\"padding:5px 8px\\\">Thick</button>\u001b[39m\n\u001b[31m      <div style=\\\"flex:1\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"undoAnnot()\\\">↩</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"clearAnnot()\\\">✕</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"annot-sel-info\\\" style=\\\"display:none;font-size:11px;color:#facc15;padding:4px 0 2px\\\">\u001b[39m\n\u001b[31m      Shape selected — drag to move · drag corners to resize · tap elsewhere to deselect\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-cvs-wrap\\\"><canvas id=\\\"annot-cvs\\\"></canvas></div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-foot\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-s\\\" onclick=\\\"skipAnnot()\\\" style=\\\"flex:1;padding:12px;font-size:14px\\\"><span class=\\\"en-txt\\\">Skip markup</span><span class=\\\"hi-txt\\\">मार्कअप छोड़ें</span></button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" onclick=\\\"saveAnnot()\\\" style=\\\"flex:2;padding:12px\\\"><span class=\\\"en-txt\\\">Done — Save ✓</span><span class=\\\"hi-txt\\\">हो गया — सेव करें ✓</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EXIT DIALOG -->\u001b[39m\n\u001b[31m<!-- MODAL: Link Job to Recce (supervisor only) -->\u001b[39m\n\u001b[31m<div id=\\\"modal-link-job\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m  <div style=\\\"background:#fff;border-radius:14px;padding:20px;width:90%;max-width:380px;display:flex;flex-direction:column;gap:12px;box-shadow:0 8px 32px rgba(0,0,0,.35)\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:15px;font-weight:700;color:#1e293b\\\">&#x1F517; Link Job to Recce</div>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-store\\\" style=\\\"font-size:13px;color:#64748b\\\"></div>\u001b[39m\n\u001b[31m    <select id=\\\"link-job-sel\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m      <option value=\\\"\\\">&#x2014; Select campaign &#x2014;</option>\u001b[39m\n\u001b[31m    </select>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-err\\\" style=\\\"font-size:12px;color:#ef4444;min-height:14px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"closeLinkJobModal()\\\" style=\\\"flex:1;padding:12px;border:1px solid #cbd5e1;border-radius:8px;cursor:pointer;background:#f8fafc;font-size:14px\\\">Cancel</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"saveLinkJob()\\\" style=\\\"flex:2;padding:12px;background:#f59e0b;color:#000;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:700\\\">&#x1F517; Link Job</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"exit-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Exit Recce?</span><span class=\\\"hi-txt\\\">रेकी से बाहर?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Your progress and photos will be saved as a draft. Resume anytime from the home screen.</span><span class=\\\"hi-txt\\\">आपकी प्रगति और फोटो ड्राफ्ट में सेव होंगी। होम स्क्रीन से कभी भी जारी रखें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"exitSaveAndLeave()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">💾 Save Draft & Exit</span><span class=\\\"hi-txt\\\">💾 ड्राफ्ट सेव करें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-d\\\" onclick=\\\"exitDiscard()\\\" style=\\\"flex:1;padding:13px;font-size:13px\\\"><span class=\\\"en-txt\\\">Discard</span><span class=\\\"hi-txt\\\">हटाएं</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"exitCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">← Continue Recce</span><span class=\\\"hi-txt\\\">← रेकी जारी रखें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- PHOTO SOURCE PICKER -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"photo-src-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Camera photos get GPS stamp baked in. Gallery photos are added without stamp.</span><span class=\\\"hi-txt\\\">कैमरा फोटो में GPS स्टैम्प लगती है। गैलरी फोटो में नहीं।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"photoSrcCamera()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">📷 Use Camera</span><span class=\\\"hi-txt\\\">📷 कैमरा</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">GPS stamp applied</span><span class=\\\"hi-txt\\\">GPS स्टैम्प लगेगी</span></span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"photoSrcGallery()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">🖼 Choose from Gallery</span><span class=\\\"hi-txt\\\">🖼 गैलरी से चुनें</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">No stamp</span><span class=\\\"hi-txt\\\">स्टैम्प नहीं</span></span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"photoSrcCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- STORE PREVIEW DIALOG -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"store-preview-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:80vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"store-preview-title\\\"><span class=\\\"en-txt\\\">Preview Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची का प्रीव्यू</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Review before adding to your store list:</span><span class=\\\"hi-txt\\\">जोड़ने से पहले जाँचें:</span></div>\u001b[39m\n\u001b[31m    <div style=\\\"overflow-x:auto;margin-bottom:14px\\\">\u001b[39m\n\u001b[31m      <table style=\\\"width:100%;border-collapse:collapse;font-size:12px\\\">\u001b[39m\n\u001b[31m        <thead><tr style=\\\"background:var(--nv);color:#fff\\\">\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Address</span><span class=\\\"hi-txt\\\">पता</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Mobile</span><span class=\\\"hi-txt\\\">मोबाइल</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span></th>\u001b[39m\n\u001b[31m        </tr></thead>\u001b[39m\n\u001b[31m        <tbody id=\\\"store-preview-body\\\"></tbody>\u001b[39m\n\u001b[31m      </table>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"confirmStorePreview()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">✓ Confirm & Add Stores</span><span class=\\\"hi-txt\\\">✓ स्टोर जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"cancelStorePreview()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BOTTOM DIALOG (branding additional photo prompt) -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"bdialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add reference photos?</span><span class=\\\"hi-txt\\\">संदर्भ फोटो जोड़ें?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Add extra photos for this branding item for future reference.</span><span class=\\\"hi-txt\\\">इस ब्रांडिंग आइटम के लिए अतिरिक्त फोटो जोड़ें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"bdialogYes()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">Yes, add photos</span><span class=\\\"hi-txt\\\">हाँ, जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"bdialogNo()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Skip</span><span class=\\\"hi-txt\\\">छोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- DELETE REASON MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"delete-reason-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"padding-bottom:28px;max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">🗑 Delete Recce</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"del-modal-sub\\\">Select reason for deletion:</div>\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-wrong\\\" onclick=\\\"selectDeleteReason('wrong')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">❌</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Wrong</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Incorrect store / submission error</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-duplicate\\\" onclick=\\\"selectDeleteReason('duplicate')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">📋</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Duplicate</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Same store submitted more than once</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt danger\\\" id=\\\"reason-test\\\" onclick=\\\"selectDeleteReason('test')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">⚠️</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Test Recce</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:#9a3412;margin-top:2px\\\">Permanently deleted — no audit trail</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p no-reason\\\" id=\\\"del-confirm-btn\\\" onclick=\\\"confirmDelete()\\\" style=\\\"flex:2;padding:13px;background:var(--rd)\\\">Delete</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"closeDeleteModal()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EDIT REQUEST MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"edit-req-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Request Edit</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"er-store-name\\\" style=\\\"font-weight:600;color:var(--nv);margin-bottom:4px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:14px\\\">Add a note for the creator (optional)</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m      <textarea id=\\\"er-comment\\\" placeholder=\\\"e.g. Please re-check store address and re-upload front photo\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;color:var(--nv);resize:vertical;min-height:80px;background:#fff\\\"></textarea>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button id=\\\"er-assign-btn\\\" class=\\\"btn-p\\\" onclick=\\\"assignEditToCreator()\\\" style=\\\"padding:14px\\\">👤 Assign to Creator</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"supervisorEditMyself()\\\" style=\\\"padding:14px\\\">✏ Edit Myself</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"closeEditRequestModal()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BRAND EDIT MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"brand-edit-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Edit Brand</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Brand Name <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"text\\\" id=\\\"be-name\\\" placeholder=\\\"e.g. PHILIPS\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:600;text-transform:uppercase\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Logo URL <span style=\\\"font-size:11px;font-weight:400;color:var(--g400)\\\">(optional)</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"url\\\" id=\\\"be-logo\\\" placeholder=\\\"https://…/logo.svg\\\" oninput=\\\"previewBrandLogo()\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px\\\">\u001b[39m\n\u001b[31m      <div id=\\\"be-logo-preview\\\" style=\\\"margin-top:8px;min-height:36px;display:flex;align-items:center;gap:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"be-cascade-info\\\" style=\\\"display:none;font-size:12px;color:var(--g500);padding:8px 12px;background:var(--g50);border-radius:var(--rs);margin-bottom:12px\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"saveBrandEdit()\\\" style=\\\"padding:14px\\\">Save</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"closeBrandEditModal()\\\" style=\\\"width:100%;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FONT SIZE WIDGET -->\u001b[39m\n\u001b[31m<div class=\\\"fs-widget\\\" id=\\\"fs-widget\\\">\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-dec\\\" onclick=\\\"changeFontSize(-1)\\\" title=\\\"Decrease font size\\\" aria-label=\\\"Decrease font size\\\">A<sup style=\\\"font-size:9px\\\">−</sup></button>\u001b[39m\n\u001b[31m  <span class=\\\"fs-label\\\" id=\\\"fs-lbl\\\">A</span>\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-inc\\\" onclick=\\\"changeFontSize(1)\\\" title=\\\"Increase font size\\\" aria-label=\\\"Increase font size\\\"><strong>A</strong><sup style=\\\"font-size:9px\\\">+</sup></button>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"upd-banner\\\" id=\\\"upd-banner\\\">\u001b[39m\n\u001b[31m  <span style=\\\"font-size:13px;font-weight:600;line-height:1.4\\\"><span class=\\\"en-txt\\\">✓ App updated to latest version</span><span class=\\\"hi-txt\\\">✓ ऐप नया संस्करण अपडेट हुआ</span></span>\u001b[39m\n\u001b[31m  <button class=\\\"upd-banner-ok\\\" onclick=\\\"dismissUpdateBanner()\\\"><span class=\\\"en-txt\\\">OK</span><span class=\\\"hi-txt\\\">ठीक है</span></button>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m<div class=\\\"toast\\\" id=\\\"toast\\\"></div>\u001b[39m\n\u001b[31m<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js\\\"></script>\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m// LANGUAGE\u001b[39m\n\u001b[31mlet LANG = localStorage.getItem('recce-lang') || 'en';\u001b[39m\n\u001b[31mfunction setLang(l) {\u001b[39m\n\u001b[31m  LANG = l;\u001b[39m\n\u001b[31m  localStorage.setItem('recce-lang', l);\u001b[39m\n\u001b[31m  document.body.classList.toggle('lang-hi', l === 'hi');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction t(en, hi) { return LANG === 'hi' ? hi : en; }·\u001b[39m\n\u001b[31m// FONT SIZE\u001b[39m\n\u001b[31mlet FS_LEVEL = parseInt(localStorage.getItem('recce-fs') || '0', 10);\u001b[39m\n\u001b[31mconst FS_LABELS = ['A', 'A+', 'A++', 'A+++', 'A++++'];\u001b[39m\n\u001b[31mfunction applyFontSize() {\u001b[39m\n\u001b[31m  document.body.classList.remove('fs-0', 'fs-1', 'fs-2');\u001b[39m\n\u001b[31m  if (FS_LEVEL > 0) document.body.classList.add('fs-' + FS_LEVEL);\u001b[39m\n\u001b[31m  const lbl = document.getElementById('fs-lbl');\u001b[39m\n\u001b[31m  if (lbl) lbl.textContent = FS_LABELS[FS_LEVEL];\u001b[39m\n\u001b[31m  const dec = document.getElementById('fs-dec');\u001b[39m\n\u001b[31m  const inc = document.getElementById('fs-inc');\u001b[39m\n\u001b[31m  if (dec) dec.disabled = FS_LEVEL === 0;\u001b[39m\n\u001b[31m  if (inc) inc.disabled = FS_LEVEL === 4;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction changeFontSize(delta) {\u001b[39m\n\u001b[31m  FS_LEVEL = Math.min(4, Math.max(0, FS_LEVEL + delta));\u001b[39m\n\u001b[31m  localStorage.setItem('recce-fs', FS_LEVEL);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Hub auth gate\u001b[39m\n\u001b[31m(function() {\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (!s || !s.loginAt || Date.now() - new Date(s.loginAt).getTime() > 12 * 3600 * 1000) {\u001b[39m\n\u001b[31m      window.location.replace('/hub/');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) { window.location.replace('/hub/'); }\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31m// STATE\u001b[39m\n\u001b[31mlet F={},frontPhotos=[],insidePhotos=[],addlPhotos=[],brandings=[];\u001b[39m\n\u001b[31mlet videoBlob=null,submissionDoc=null,_docExistingUrl=null,gpsCoords=null;\u001b[39m\n\u001b[31mlet stores=[],selectedStore=null,manualMode=false,DB;\u001b[39m\n\u001b[31mlet imgQuality='compressed'; // 'compressed' | 'hd'\u001b[39m\n\u001b[31mlet geoStampEnabled=true;    // stamp GPS+timestamp on every photo\u001b[39m\n\u001b[31mlet brands=['PHILIPS']; // editable brand list\u001b[39m\n\u001b[31mlet _brandLogos={};   // name → logo_url, loaded from DB\u001b[39m\n\u001b[31mlet _selectedClient=''; // currently selected client chip value\u001b[39m\n\u001b[31mlet _clientOtherMode=false; // true when \\\"Other\\\" chip selected\u001b[39m\n\u001b[31mconst BTYPE=['Glow Sign Board','Inshop Branding','ACP Board','One Way Vision','Fabric Board','Lollypop','Non Lit Flex','Double Side GSB','Clip on Board','Translit','Vinyl Printing','Roll up Standee','Sunboard Standee'];\u001b[39m\n\u001b[31mconst CACHE_VER='recce-v37'; // campaign dropdown + pending job link tab·\u001b[39m\n\u001b[31m// DB\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',3);r.onupgradeneeded=e=>{const d=e.target.result;['subs','cfg','draft'].forEach(s=>{if(!d.objectStoreNames.contains(s))d.createObjectStore(s,{keyPath:'k'||'id'});});if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);});}\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',4);r.onupgradeneeded=e=>{const d=e.target.result;if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);})}\u001b[39m\n\u001b[31mfunction dbGet(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).get(k);r.onsuccess=()=>res(r.result);r.onerror=()=>res(null);}catch{res(null)}})}\u001b[39m\n\u001b[31mfunction dbPut(s,v){return new Promise((res,rej)=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).put(v);r.onsuccess=()=>res();r.onerror=()=>rej();}catch(e){rej(e)}})}\u001b[39m\n\u001b[31mfunction dbAll(s){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).getAll();r.onsuccess=()=>res(r.result);r.onerror=()=>res([]);}catch{res([])}})}\u001b[39m\n\u001b[31mfunction dbDel(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).delete(k);r.onsuccess=()=>res();r.onerror=()=>res();}catch{res()}})}\u001b[39m\n\u001b[31masync function cfg(k,v){if(v===undefined){const r=await dbGet('cfg',k);return r?r.v:null;}await dbPut('cfg',{k,v});}·\u001b[39m\n\u001b[31m// COMPRESS — respects imgQuality setting\u001b[39m\n\u001b[31mfunction compress(file, maxPxOverride, qOverride){\u001b[39m\n\u001b[31m  const maxPx = maxPxOverride || (imgQuality==='hd' ? 1920 : 1280);\u001b[39m\n\u001b[31m  const q     = qOverride     || (imgQuality==='hd' ? 0.90 : 0.78);\u001b[39m\n\u001b[31m  return new Promise(res=>{const img=new Image(),url=URL.createObjectURL(file);img.onload=()=>{const sc=Math.min(1,maxPx/Math.max(img.width,img.height));const c=document.createElement('canvas');c.width=Math.round(img.width*sc);c.height=Math.round(img.height*sc);c.getContext('2d').drawImage(img,0,0,c.width,c.height);URL.revokeObjectURL(url);c.toBlob(b=>res(b),'image/jpeg',q);};img.onerror=()=>{URL.revokeObjectURL(url);res(file)};img.src=url;});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction b64(blob){return new Promise(res=>{const r=new FileReader();r.onload=()=>res(r.result);r.readAsDataURL(blob)})}\u001b[39m\n\u001b[31mfunction fmtSz(b){if(b<1024)return b+'B';if(b<1048576)return(b/1024).toFixed(0)+'KB';return(b/1048576).toFixed(1)+'MB'}·\u001b[39m\n\u001b[31m// STORE LIST\u001b[39m\n\u001b[31mlet _storeFiles=[]; // track uploaded files {name, brand, count}\u001b[39m\n\u001b[31mlet _pendingParse=null; // parsed rows waiting for brand assignment·\u001b[39m\n\u001b[31mfunction parseStoreRow(row, keyFn){\u001b[39m\n\u001b[31m  const v=k=>{\u001b[39m\n\u001b[31m    // Try exact match first, then partial\u001b[39m\n\u001b[31m    const exactKey=Object.keys(row||{}).find(hk=>hk.toLowerCase()===k);\u001b[39m\n\u001b[31m    const partKey=Object.keys(row||{}).find(hk=>hk.toLowerCase().includes(k));\u001b[39m\n\u001b[31m    const useKey=exactKey||partKey;\u001b[39m\n\u001b[31m    if(useKey)return row[useKey]!=null?row[useKey].toString().trim():'';\u001b[39m\n\u001b[31m    // CSV path: keyFn provides value directly\u001b[39m\n\u001b[31m    const col=keyFn(k);return col!=null?col.toString().trim():'';\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const name    = v('sub dealer name')||v('sub dealer')||v('dealer name')||v('store name')||v('store')||v('name');\u001b[39m\n\u001b[31m  const address = v('address')||v('addr')||v('location')||v('area');\u001b[39m\n\u001b[31m  // Contact Detail often stored as a number — toString handles it\u001b[39m\n\u001b[31m  const rawMob  = v('contact detail')||v('contact no.')||v('contact no')||v('mobile no')||v('mobile')||v('phone')||v('mob')||v('contact');\u001b[39m\n\u001b[31m  const mobile  = rawMob.replace(/\\\\D/g,'').slice(-10);\u001b[39m\n\u001b[31m  // Brand: EXACT match only — \\\"Brand\\\" or \\\"Brand Name\\\" columns\u001b[39m\n\u001b[31m  // Partial match is intentionally avoided here because \\\"Inshop Branding\\\" contains \\\"brand\\\"\u001b[39m\n\u001b[31m  const brandKey=Object.keys(row||{}).find(hk=>{\u001b[39m\n\u001b[31m    const lk=hk.toLowerCase().trim();\u001b[39m\n\u001b[31m    return lk==='brand'||lk==='brand name'||lk==='brand_name'||lk==='brandname';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const brand=brandKey?(row[brandKey]||'').toString().trim().toUpperCase():'';\u001b[39m\n\u001b[31m  const distName= v('dist name')||v('distributor name')||v('distributor')||v('dist')||v('territory')||v('tsm')||v('asm');\u001b[39m\n\u001b[31m  const city    = v('city')||v('district')||v('town');\u001b[39m\n\u001b[31m  const sales   = v('2025 full year')||v('2025')||v('full year sales')||v('fy25')||v('sales');\u001b[39m\n\u001b[31m  const proj    = v('2026 projection')||v('2026')||v('projection')||v('fy26')||v('target');\u001b[39m\n\u001b[31m  const glowSign= v('glow sign')||v('glow');\u001b[39m\n\u001b[31m  const inshop  = v('inshop branding')||v('inshop')||v('in-shop')||v('in shop');\u001b[39m\n\u001b[31m  return {name, brand, address, mobile, distName, city, sales, proj, glowSign, inshop};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction dedupeStores(list){\u001b[39m\n\u001b[31m  const seen=new Map();\u001b[39m\n\u001b[31m  list.forEach(s=>{\u001b[39m\n\u001b[31m    // Include address in key — same store name at different locations = different stores\u001b[39m\n\u001b[31m    const key=(s.name.toLowerCase().trim())+'__'+(s.brand||'').toLowerCase()\u001b[39m\n\u001b[31m              +'__'+(s.address||'').toLowerCase().trim().slice(0,30);\u001b[39m\n\u001b[31m    if(!seen.has(key))seen.set(key,s);\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // True duplicate — merge missing fields from second record\u001b[39m\n\u001b[31m      const ex=seen.get(key);\u001b[39m\n\u001b[31m      Object.keys(s).forEach(k=>{ if(!ex[k]&&s[k])ex[k]=s[k]; });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  return Array.from(seen.values());\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderStoreFileList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-file-list');if(!el)return;\u001b[39m\n\u001b[31m  if(!_storeFiles.length){el.innerHTML='';return;}\u001b[39m\n\u001b[31m  el.innerHTML=_storeFiles.map((f,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:5px;font-size:12px\\\">\u001b[39m\n\u001b[31m      <div>\u001b[39m\n\u001b[31m        <span style=\\\"font-weight:600;color:var(--nv)\\\">${f.name}</span>\u001b[39m\n\u001b[31m        <span style=\\\"color:var(--g500);margin-left:6px\\\">${f.count} stores</span>\u001b[39m\n\u001b[31m        ${f.brand?`<span style=\\\"background:var(--nv);color:#fff;font-size:10px;font-weight:700;padding:1px 7px;border-radius:20px;margin-left:5px\\\">${f.brand}</span>`:'<span style=\\\"background:var(--g300);color:var(--g600);font-size:10px;padding:1px 7px;border-radius:20px;margin-left:5px\\\">Mixed brands</span>'}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <button onclick=\\\"removeStoreFile(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:17px;cursor:pointer;padding:0 4px;line-height:1\\\">×</button>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function removeStoreFile(i){\u001b[39m\n\u001b[31m  _storeFiles.splice(i,1);\u001b[39m\n\u001b[31m  // Rebuild stores from remaining files — re-parse from cache not possible, so just reload from DB and remove this file's contribution\u001b[39m\n\u001b[31m  // Simplest approach: clear and ask user to re-upload remaining files\u001b[39m\n\u001b[31m  if(!_storeFiles.length){stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    // Can't re-parse without original files; just note it and keep current store list\u001b[39m\n\u001b[31m    toast('Removed from list. Re-upload the remaining files to refresh store list.','info');\u001b[39m\n\u001b[31m    _storeFiles.splice(0); // clear tracking since we can't reconstruct\u001b[39m\n\u001b[31m    stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderStoreFileList();\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=stores.length?`✓ ${stores.length} stores`:'No stores loaded';\u001b[39m\n\u001b[31m  updAvailTag();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function clearStoreList(){\u001b[39m\n\u001b[31m  if(!confirm('Remove all loaded stores?'))return;\u001b[39m\n\u001b[31m  stores=[];_storeFiles=[];\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent='';\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast('Store list cleared','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function handleStoreUpload(e){\u001b[39m\n\u001b[31m  const file=e.target.files[0];if(!file)return;\u001b[39m\n\u001b[31m  e.target.value=''; // allow same file re-upload\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    let data=[];\u001b[39m\n\u001b[31m    if(file.name.toLowerCase().endsWith('.csv')){\u001b[39m\n\u001b[31m      const txt=await file.text();\u001b[39m\n\u001b[31m      const rows=txt.split('\\\\n').map(r=>r.split(',').map(c=>c.trim().replace(/^\\\"|\\\"$/g,'')));\u001b[39m\n\u001b[31m      if(!rows.length||!rows[0].length){toast('Empty CSV','error');return;}\u001b[39m\n\u001b[31m      const h=rows[0];\u001b[39m\n\u001b[31m      data=rows.slice(1).filter(r=>r.length>1&&r.some(c=>c)).map(r=>{\u001b[39m\n\u001b[31m        const rowObj={};h.forEach((hk,i)=>{rowObj[hk]=r[i]||'';});\u001b[39m\n\u001b[31m        return parseStoreRow(rowObj, ()=>'');\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }else{\u001b[39m\n\u001b[31m      const ab=await file.arrayBuffer();const wb=XLSX.read(ab,{type:'array'});\u001b[39m\n\u001b[31m      const js=XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]],{defval:''});\u001b[39m\n\u001b[31m      data=js.map(row=>parseStoreRow(row,()=>''));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    data=data.filter(d=>d.name.trim());\u001b[39m\n\u001b[31m    if(!data.length){toast('No valid rows found in file','error');return;}\u001b[39m\n\u001b[31m    // Check if any store has a brand\u001b[39m\n\u001b[31m    const hasBrand=data.some(d=>d.brand);\u001b[39m\n\u001b[31m    // Always show preview first before merging\u001b[39m\n\u001b[31m    _pendingParse={file:file.name,data,hasBrand};\u001b[39m\n\u001b[31m    showStorePreview(file.name, data, hasBrand);\u001b[39m\n\u001b[31m  }catch(err){toast('Failed: '+err.message,'error')}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mlet _pendingBrand='';\u001b[39m\n\u001b[31mfunction setPendingBrand(b){\u001b[39m\n\u001b[31m  _pendingBrand=b;\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-assign-chips .chip').forEach(c=>{\u001b[39m\n\u001b[31m    c.classList.toggle('sel',c.textContent===b);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  if(!_pendingBrand){toast('Select a brand first','error');return;}\u001b[39m\n\u001b[31m  // Assign brand to all rows in this file\u001b[39m\n\u001b[31m  const data=_pendingParse.data.map(s=>({...s,brand:_pendingBrand}));\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, data, _pendingBrand);\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function skipBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, _pendingParse.data, '');\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showStorePreview(filename, data, hasBrand){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-preview-dialog');\u001b[39m\n\u001b[31m  const tbody=document.getElementById('store-preview-body');\u001b[39m\n\u001b[31m  document.getElementById('store-preview-title').textContent=`${filename} · ${data.length} ${t('stores found','स्टोर मिले')}`;\u001b[39m\n\u001b[31m  // Show first 8 rows\u001b[39m\n\u001b[31m  const sample=data.slice(0,8);\u001b[39m\n\u001b[31m  tbody.innerHTML=sample.map(s=>`<tr>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;font-weight:500\\\">${s.name||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.address||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.mobile||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px\\\"><span style=\\\"background:${s.brand?'var(--nv)':'var(--rd)'};color:#fff;padding:1px 7px;border-radius:10px;font-size:10px\\\">${s.brand||'?'}</span></td>\u001b[39m\n\u001b[31m  </tr>`).join('');\u001b[39m\n\u001b[31m  if(data.length>8)tbody.innerHTML+=`<tr><td colspan=\\\"4\\\" style=\\\"text-align:center;padding:8px;font-size:12px;color:var(--g400)\\\">…and ${data.length-8} more stores</td></tr>`;\u001b[39m\n\u001b[31m  el.classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function confirmStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  const {file,data,hasBrand}=_pendingParse;\u001b[39m\n\u001b[31m  if(!hasBrand){\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-fname').textContent=`File: ${file} · ${data.length} stores found · No brand column detected`;\u001b[39m\n\u001b[31m    const chips=document.getElementById('brand-assign-chips');\u001b[39m\n\u001b[31m    chips.innerHTML=brands.map(b=>`<div class=\\\"chip\\\" onclick=\\\"setPendingBrand('${b}')\\\" id=\\\"bac-${b}\\\">${b}</div>`).join('');\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').style.display='block';\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    await mergeStores(file, data, '');\u001b[39m\n\u001b[31m    _pendingParse=null;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction cancelStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingParse=null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function mergeStores(filename, newData, assignedBrand){\u001b[39m\n\u001b[31m  const before=stores.length;\u001b[39m\n\u001b[31m  stores=[...stores,...newData];\u001b[39m\n\u001b[31m  stores=dedupeStores(stores);\u001b[39m\n\u001b[31m  const added=stores.length-before;\u001b[39m\n\u001b[31m  const dupes=newData.length-added;\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify(stores));\u001b[39m\n\u001b[31m  // Track file\u001b[39m\n\u001b[31m  _storeFiles.push({name:filename,count:newData.length,brand:assignedBrand||''});\u001b[39m\n\u001b[31m  await cfg('store-files',JSON.stringify(_storeFiles));\u001b[39m\n\u001b[31m  const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m    `✓ ${stores.length} total stores${dupes>0?` · ${dupes} duplicate${dupes>1?'s':''} removed`:''}${noBrand?` · ${noBrand} without brand`:' · All have brand'}`;\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast(`${added} stores added${dupes>0?`, ${dupes} duplicates skipped`:''}${assignedBrand?' as '+assignedBrand:''}`, 'success');\u001b[39m\n\u001b[31m  // Show server-push button for supervisors\u001b[39m\n\u001b[31m  const pb = document.getElementById('store-push-btn');\u001b[39m\n\u001b[31m  if (pb) pb.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function fetchServerStores(){const url=document.getElementById('srv-url').value.trim();if(!url){toast('Enter a URL first','error');return;}try{toast('Fetching…','info');const r=await fetch(url);const j=await r.json();const fetched=Array.isArray(j)?j:j.stores||[];await mergeStores('Server ('+url.split('/').pop()+')',fetched,'');await cfg('srv-url',url);}catch{toast('Fetch failed — check URL','error')}}\u001b[39m\n\u001b[31masync function saveServerUrl(){await cfg('srv-url',document.getElementById('srv-url').value.trim());toast('URL saved','success')}\u001b[39m\n\u001b[31mconst DEFAULT_GAS_URL='https://script.google.com/macros/s/AKfycbwyufC7gQyu1BErCxiDlbQUn0AWiIWv7nEmjk4UcAx3dvlV6bGk7q5fQOiv82CTbokbkA/exec';·\u001b[39m\n\u001b[31mconst DEFAULT_STORES_URL='/recce/stores.json';\u001b[39m\n\u001b[31mconst _RECCE_CFG_URL='/recce/recce-cfg.json';·\u001b[39m\n\u001b[31m// Admin auto-unlock for harish/pramod via hub session\u001b[39m\n\u001b[31mconst _RECCE_ADMIN_IDS = ['harish', 'pramod', 'rakesh'];\u001b[39m\n\u001b[31mconst _RECCE_CFG_ADMINS = ['harish', 'pramod'];\u001b[39m\n\u001b[31mlet _adminRows = [];\u001b[39m\n\u001b[31mlet _myServerRows = [];\u001b[39m\n\u001b[31mlet _adminUnlocked = false;\u001b[39m\n\u001b[31mlet _recceCfg = { version: 1, supervisors: ['harish','pramod','rakesh'], mode: 'public', creators: [], allowed_users: [] };\u001b[39m\n\u001b[31mfunction _isSupervisor() {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  return !!(hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId));\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _showDeletedView = false;\u001b[39m\n\u001b[31mlet _supCreateMode = false;\u001b[39m\n\u001b[31mlet _pendingDeleteId = null;\u001b[39m\n\u001b[31mlet _pendingDeleteReason = null;\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (s?.empId && _RECCE_ADMIN_IDS.includes(s.empId)) _adminUnlocked = true;\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31masync function loadRecceCfg(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(_RECCE_CFG_URL + '?t=' + Date.now());\u001b[39m\n\u001b[31m    if (r.ok) {\u001b[39m\n\u001b[31m      const j = await r.json();\u001b[39m\n\u001b[31m      if (j && j.version) {\u001b[39m\n\u001b[31m        _recceCfg = j;\u001b[39m\n\u001b[31m        if (Array.isArray(j.supervisors) && j.supervisors.length) {\u001b[39m\n\u001b[31m          _recceCfg.supervisors = j.supervisors;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.creators)) _recceCfg.creators = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.allowed_users)) _recceCfg.allowed_users = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.clients)) _recceCfg.clients = [];\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  // Re-check admin status against server supervisor list\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId)) {\u001b[39m\n\u001b[31m    _adminUnlocked = true;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _checkAccessMode(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (_recceCfg.mode !== 'assigned') return;\u001b[39m\n\u001b[31m  const allowed = [\u001b[39m\n\u001b[31m    ...(_recceCfg.supervisors || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.creators || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.allowed_users || []),\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  if (hub?.empId && allowed.includes(hub.empId)) return;\u001b[39m\n\u001b[31m  // Block access — show locked overlay\u001b[39m\n\u001b[31m  document.body.innerHTML = `<div style=\\\"min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0f172a;color:#fff;padding:32px;text-align:center\\\"><div style=\\\"font-size:48px;margin-bottom:16px\\\">🔒</div><div style=\\\"font-size:20px;font-weight:700;margin-bottom:8px\\\">${t('Access Restricted','एक्सेस प्रतिबंधित')}</div><div style=\\\"font-size:14px;color:#94a3b8\\\">${t('You are not authorised to use Branding Recce. Please contact your supervisor.','आप ब्रांडिंग रेक्की उपयोग के लिए अधिकृत नहीं हैं।')}</div></div>`;\u001b[39m\n\u001b[31m  throw new Error('access-restricted');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _recceHubUser() {\u001b[39m\n\u001b[31m  try { return JSON.parse(localStorage.getItem('lm360-session') || '{}'); }\u001b[39m\n\u001b[31m  catch(_) { return {}; }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── Supervisor config management ────────────────────────────────────\u001b[39m\n\u001b[31mfunction renderSupPanel(){\u001b[39m\n\u001b[31m  if (!_adminUnlocked) return;\u001b[39m\n\u001b[31m  const panel = document.getElementById('sup-panel');\u001b[39m\n\u001b[31m  if (panel) panel.style.display = 'block';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const modePublic = document.getElementById('mode-public');\u001b[39m\n\u001b[31m  const modeAssigned = document.getElementById('mode-assigned');\u001b[39m\n\u001b[31m  if (modePublic && modeAssigned) {\u001b[39m\n\u001b[31m    modePublic.classList.toggle('sel', _recceCfg.mode !== 'assigned');\u001b[39m\n\u001b[31m    modeAssigned.classList.toggle('sel', _recceCfg.mode === 'assigned');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  const addRow = document.getElementById('sup-add-row');\u001b[39m\n\u001b[31m  if (addRow) addRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const creatorAddRow = document.getElementById('creator-add-row');\u001b[39m\n\u001b[31m  if (creatorAddRow) creatorAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const clientAddRow = document.getElementById('client-add-row');\u001b[39m\n\u001b[31m  if (clientAddRow) clientAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const modeRow = document.getElementById('mode-row');\u001b[39m\n\u001b[31m  if (modeRow) {\u001b[39m\n\u001b[31m    modeRow.style.display = 'block';\u001b[39m\n\u001b[31m    // Non-cfg-admins see mode as read-only (toggles exist but setRecceMode guards them)\u001b[39m\n\u001b[31m    modeRow.style.opacity = isCfgAdmin ? '1' : '0.65';\u001b[39m\n\u001b[31m    modeRow.style.pointerEvents = isCfgAdmin ? '' : 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const syncBtn = document.getElementById('cfg-sync-btn');\u001b[39m\n\u001b[31m  if (syncBtn) syncBtn.style.display = isCfgAdmin ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('sup-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const sups = _recceCfg.supervisors || [];\u001b[39m\n\u001b[31m  el.innerHTML = sups.map((s,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${s}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin && sups.length > 1 ? `<button onclick=\\\"removeSupervisor(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderCreatorsList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('creator-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const creators = _recceCfg.creators || [];\u001b[39m\n\u001b[31m  el.innerHTML = creators.length ? creators.map((u,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${u}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeCreator(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No creators yet — any Hub user can submit in Public mode.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setRecceMode(mode){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.mode = mode;\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addSupervisor(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('sup-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.supervisors = [...(_recceCfg.supervisors || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeSupervisor(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.supervisors = (_recceCfg.supervisors || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addCreator(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('creator-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.creators || []).includes(val)) { toast(t('Already a creator','पहले से क्रिएटर है'), 'info'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor (includes creation rights)','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.creators = [...(_recceCfg.creators || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeCreator(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.creators = (_recceCfg.creators || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderClientMgmtList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('client-mgmt-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const list = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  el.innerHTML = list.length ? list.map((c,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${esc(c)}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeClientFromList(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No clients yet — add client or agency names to show them as chips in the form.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addClientToList(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('client-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter client name','क्लाइंट नाम दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.clients || []).includes(val)) { toast(t('Already in list','पहले से मौजूद है'), 'info'); return; }\u001b[39m\n\u001b[31m  if (!_recceCfg.clients) _recceCfg.clients = [];\u001b[39m\n\u001b[31m  _recceCfg.clients.push(val);\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeClientFromList(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.clients = (_recceCfg.clients || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncCfgToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast(t('Not authorised','अधिकृत नहीं'), 'error'); return; }\u001b[39m\n\u001b[31m  const st = document.getElementById('cfg-sync-status');\u001b[39m\n\u001b[31m  if (st) st.textContent = t('Syncing…','सिंक हो रहा है…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-cfg', empId: hub.empId, cfg: {\u001b[39m\n\u001b[31m        version: _recceCfg.version || 1,\u001b[39m\n\u001b[31m        supervisors: _recceCfg.supervisors || [],\u001b[39m\n\u001b[31m        mode: _recceCfg.mode || 'public',\u001b[39m\n\u001b[31m        creators: _recceCfg.creators || [],\u001b[39m\n\u001b[31m        allowed_users: _recceCfg.allowed_users || [],\u001b[39m\n\u001b[31m        clients: _recceCfg.clients || [],\u001b[39m\n\u001b[31m      }})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) {\u001b[39m\n\u001b[31m      toast(t('Config synced to server ✓','कॉन्फ़िग सर्वर पर सेव हुआ ✓'), 'success');\u001b[39m\n\u001b[31m      if (st) st.textContent = t('Last synced: just now','अभी सिंक हुआ');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast(j.error || t('Sync failed','सिंक विफल'), 'error');\u001b[39m\n\u001b[31m      if (st) st.textContent = j.error || '';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Network error','नेटवर्क त्रुटि'), 'error');\u001b[39m\n\u001b[31m    if (st) st.textContent = e.message;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function pushStoresToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!hub?.empId || !_adminUnlocked) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-stores', empId: hub.empId, stores })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) toast(`${t('Pushed to server','सर्वर पर पुश हुआ')} · ${j.count} ${t('stores','स्टोर')}`, 'success');\u001b[39m\n\u001b[31m    else toast(j.error || t('Server push failed','सर्वर पुश विफल'), 'error');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Could not reach server','सर्वर से संपर्क नहीं हो सका'), 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── End supervisor config management ────────────────────────────────·\u001b[39m\n\u001b[31m// PostgREST sync constants\u001b[39m\n\u001b[31mconst _RC_BASE      = '/db';\u001b[39m\n\u001b[31mconst _RC_READ      = { 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_WRITE     = { 'Content-Type': 'application/json', 'Content-Profile': 'recce', 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_UPSERT    = { ..._RC_WRITE, 'Prefer': 'resolution=merge-duplicates,return=minimal' };\u001b[39m\n\u001b[31mconst _INSTALL_RD   = { 'Content-Type': 'application/json', 'Accept-Profile': 'installation' };\u001b[39m\n\u001b[31mconst _INSTALL_WR   = { 'Content-Type': 'application/json', 'Content-Profile': 'installation', 'Accept-Profile': 'installation', 'Prefer': 'return=minimal' };·\u001b[39m\n\u001b[31m// ── Campaign selection state ──\u001b[39m\n\u001b[31mlet _selectedCampaignId = null;\u001b[39m\n\u001b[31mlet _notifySupervisor   = false;\u001b[39m\n\u001b[31mlet _campaignList       = [];\u001b[39m\n\u001b[31mlet _pendingJobFilter   = false;\u001b[39m\n\u001b[31mlet _linkJobSubId       = null;\u001b[39m\n\u001b[31mlet _brandingLocked     = false;·\u001b[39m\n\u001b[31mfunction _updateBrandingLock() {\u001b[39m\n\u001b[31m  const hub  = _recceHubUser();\u001b[39m\n\u001b[31m  const isHP = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const banner   = document.getElementById('branding-lock-banner');\u001b[39m\n\u001b[31m  const ovWrap   = document.getElementById('branding-override-wrap');\u001b[39m\n\u001b[31m  const brItems  = document.getElementById('br-items');\u001b[39m\n\u001b[31m  const brAdd    = document.getElementById('br-add');\u001b[39m\n\u001b[31m  const brYes    = document.getElementById('br-yes');\u001b[39m\n\u001b[31m  const brNo     = document.getElementById('br-no');\u001b[39m\n\u001b[31m  if (!banner) return;\u001b[39m\n\u001b[31m  if (_brandingLocked) {\u001b[39m\n\u001b[31m    banner.style.display   = '';\u001b[39m\n\u001b[31m    if (ovWrap)  ovWrap.style.display  = isHP ? '' : 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.pointerEvents = 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.opacity = '0.55';\u001b[39m\n\u001b[31m    if (brAdd)   brAdd.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='none'; brYes.style.opacity='0.5'; }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='none';  brNo.style.opacity='0.5';  }\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    banner.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brItems) { brItems.style.pointerEvents=''; brItems.style.opacity=''; }\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='';  brYes.style.opacity='';   }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='';   brNo.style.opacity='';    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction unlockBrandingOverride() {\u001b[39m\n\u001b[31m  if (!confirm(\u001b[39m\n\u001b[31m    'Client has already reviewed this recce.\\\\n' +\u001b[39m\n\u001b[31m    'Editing brandings will NOT remove their approval.\\\\n' +\u001b[39m\n\u001b[31m    'Continue ONLY if the client has verbally confirmed. Proceed?'\u001b[39m\n\u001b[31m  )) return;\u001b[39m\n\u001b[31m  _brandingLocked = false;\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  renderBrandings();\u001b[39m\n\u001b[31m  toast(t('Branding unlocked for this session', 'ब्रांडिंग इस सत्र के लिए अनलॉक'), 'info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadCampaignsForForm() {\u001b[39m\n\u001b[31m  const sel = document.getElementById('f-campaign-id');\u001b[39m\n\u001b[31m  if (!sel) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m    _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m  } catch(_) { _campaignList = []; }\u001b[39m\n\u001b[31m  sel.innerHTML =\u001b[39m\n\u001b[31m    '<option value=\\\"\\\">— Select job / campaign (optional) —</option>' +\u001b[39m\n\u001b[31m    _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('') +\u001b[39m\n\u001b[31m    '<option value=\\\"__NOTIFY__\\\">⚑ No campaign yet — notify supervisor</option>';\u001b[39m\n\u001b[31m  if (_selectedCampaignId) sel.value = _selectedCampaignId;\u001b[39m\n\u001b[31m  else if (_notifySupervisor) sel.value = '__NOTIFY__';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onCampaignSelect() {\u001b[39m\n\u001b[31m  const val = document.getElementById('f-campaign-id')?.value || '';\u001b[39m\n\u001b[31m  const noticeEl = document.getElementById('campaign-notify-msg');\u001b[39m\n\u001b[31m  if (val === '__NOTIFY__') {\u001b[39m\n\u001b[31m    _selectedCampaignId = null;\u001b[39m\n\u001b[31m    _notifySupervisor   = true;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'block';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    _selectedCampaignId = val || null;\u001b[39m\n\u001b[31m    _notifySupervisor   = false;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction generateRecceReportHtml(entry, photoUrls) {\u001b[39m\n\u001b[31m  const d    = entry.data || {};\u001b[39m\n\u001b[31m  const urls = photoUrls || {};\u001b[39m\n\u001b[31m  const agent = entry.submittedByName || entry.submittedBy || 'Field Agent';\u001b[39m\n\u001b[31m  const _safeId      = (entry.id||'').replace(/\\\\//g,'_').replace(/\\\\.\\\\./g,'');\u001b[39m\n\u001b[31m  const serverPdfUrl = _safeId ? `https://srv1111289.hstgr.cloud/screenshots/recce/views/${_safeId}.pdf` : '';\u001b[39m\n\u001b[31m  const brandLogoUrl = d.brandLogoUrl || _brandLogos[d.brand] || '';\u001b[39m\n\u001b[31m  const tsStr = new Date(entry.timestamp).toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric',hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\u001b[39m\n\u001b[31m  const gpsUrl = d.gpsCoords ? `https://maps.google.com/?q=${d.gpsCoords.lat},${d.gpsCoords.lng}` : null;·\u001b[39m\n\u001b[31m  const frontCount  = (urls.front||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const insideCount = (urls.inside||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const addlCount   = (urls.addl||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const brCount     = (d.brandings||[]).length;·\u001b[39m\n\u001b[31m  // pages: { id, url, bandHtml, cmt, dotLabel, dotColor }\u001b[39m\n\u001b[31m  const pages = [];·\u001b[39m\n\u001b[31m  (urls.front||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Front View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${frontCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.frontPhotos||[])[i]?.cmt||'', dotLabel:`FV${i+1}`, dotColor:'#3b82f6', catLabel:'Front View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.inside||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Inside View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${insideCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.insidePhotos||[])[i]?.cmt||'', dotLabel:`IV${i+1}`, dotColor:'#14b8a6', catLabel:'Inside View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (d.brandings||[]).forEach((b,i)=>{\u001b[39m\n\u001b[31m    const url=(urls.brandings||[])[i]; if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">${esc(b.type||'Branding')}</div><div class=\\\"ph-dims\\\">Width : ${esc(b.w||'?')}&Prime;&nbsp;&times;&nbsp;Height : ${esc(b.h||'?')}&Prime;&nbsp;&mdash;&nbsp;${esc(b.qty||1)} Nos</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${brCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:'', dotLabel:`B${i+1}`, dotColor:'#f97316', catLabel:b.type||'Branding',\u001b[39m\n\u001b[31m      tileDims:`${b.w||'?'}″×${b.h||'?'}″ — ${String(b.qty||1).padStart(2,'0')} Nos` });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.addl||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Additional</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${addlCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.addlPhotos||[])[i]?.desc||'', dotLabel:`A${i+1}`, dotColor:'#94a3b8', catLabel:'Additional', tileDims:'' });\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const sideItems = [\u001b[39m\n\u001b[31m    `<div class=\\\"si-item active\\\" data-tgt=\\\"pg-cover\\\" title=\\\"Cover\\\"><div class=\\\"si-dot\\\" style=\\\"background:#475569\\\">CV</div></div>`\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  pages.forEach(p => {\u001b[39m\n\u001b[31m    sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"${p.id}\\\" title=\\\"${p.dotLabel}\\\"><div class=\\\"si-dot\\\" style=\\\"background:${p.dotColor}\\\">${p.dotLabel}</div></div>`);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(d.hasVideo) sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-vid\\\" title=\\\"Video\\\"><div class=\\\"si-dot\\\" style=\\\"background:#a855f7\\\">VD</div></div>`);\u001b[39m\n\u001b[31m  if(urls.doc)   sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-doc\\\" title=\\\"Document\\\"><div class=\\\"si-dot\\\" style=\\\"background:#64748b\\\">DC</div></div>`);·\u001b[39m\n\u001b[31m  const thumbItems = [\u001b[39m\n\u001b[31m    ...pages,\u001b[39m\n\u001b[31m    ...(d.hasVideo?[{id:'pg-vid',url:null,catLabel:'Video',tileDims:'',dotLabel:'VD',dotColor:'#a855f7'}]:[]),\u001b[39m\n\u001b[31m    ...(urls.doc?[{id:'pg-doc',url:urls.doc,catLabel:'Document',tileDims:'',dotLabel:'DC',dotColor:'#64748b'}]:[])\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  const thumbsHtml = thumbItems.map(p=>`<div class=\\\"cov-thumb\\\" onclick=\\\"document.getElementById('${p.id}').scrollIntoView({behavior:'smooth'})\\\">${p.url?`<img src=\\\"${p.url}\\\" alt=\\\"\\\">`:(`<div class=\\\"cov-thumb-vid\\\">${p.catLabel==='Video'?'&#x25B6;&#xFE0F;':'&#x1F4C4;'}</div>`)}<div class=\\\"cov-thumb-ov\\\" style=\\\"border-top:3px solid ${p.dotColor}\\\"><div class=\\\"cov-thumb-cat\\\">${esc(p.catLabel)}</div>${p.tileDims?`<div class=\\\"cov-thumb-dims\\\">${esc(p.tileDims)}</div>`:''}<div class=\\\"cov-thumb-no\\\">${p.dotLabel}</div></div></div>`).join('');·\u001b[39m\n\u001b[31m  const pagesHtml = pages.map(p => `\u001b[39m\n\u001b[31m<div class=\\\"photo-page\\\" id=\\\"${p.id}\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\">${p.bandHtml}</div>\u001b[39m\n\u001b[31m  <div class=\\\"ph-img\\\"><a href=\\\"${p.url}\\\" target=\\\"_blank\\\"><img src=\\\"${p.url}\\\" loading=\\\"lazy\\\" alt=\\\"\\\"></a>${p.cmt?`<div class=\\\"ph-cmt\\\">${esc(p.cmt)}</div>`:''}</div>\u001b[39m\n\u001b[31m</div>`).join('');·\u001b[39m\n\u001b[31m  return `<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\"><head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m<title>Recce — ${esc(d.storeName||'Unknown')} · ${esc(d.brand||'')}</title>\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--dk:#0f172a;--nv2:#1a2f52;--or:#f97316;--g200:#e2e8f0;--g400:#94a3b8;--g600:#475569;--si:54px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0}\u001b[39m\n\u001b[31mhtml,body{height:100%;overflow:hidden}\u001b[39m\n\u001b[31mbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#111;color:var(--dk);display:flex}\u001b[39m\n\u001b[31ma{color:var(--or);text-decoration:none}\u001b[39m\n\u001b[31mimg{display:block}·\u001b[39m\n\u001b[31m/* ── Side index ── */\u001b[39m\n\u001b[31m.side-idx{width:var(--si);flex-shrink:0;background:var(--dk);overflow-y:auto;display:flex;flex-direction:column;align-items:center;padding:4px 0;scrollbar-width:none;z-index:50}\u001b[39m\n\u001b[31m.side-idx::-webkit-scrollbar{display:none}\u001b[39m\n\u001b[31m.si-item{width:100%;min-height:56px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s}\u001b[39m\n\u001b[31m.si-item:hover{background:rgba(255,255,255,.07)}\u001b[39m\n\u001b[31m.si-dot{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff;opacity:.4;transition:opacity .18s,transform .18s;line-height:1;text-align:center}\u001b[39m\n\u001b[31m.si-item.active .si-dot{opacity:1;transform:scale(1.15)}·\u001b[39m\n\u001b[31m/* ── Main scroll area ── */\u001b[39m\n\u001b[31m.main{flex:1;overflow-y:scroll;scroll-snap-type:y mandatory;scroll-behavior:smooth;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar{width:3px}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15)}·\u001b[39m\n\u001b[31m/* ── Cover ── */\u001b[39m\n\u001b[31m.cover{height:100vh;scroll-snap-align:start;flex-shrink:0;background:linear-gradient(135deg,#0f172a 0%,var(--nv2) 100%);color:#fff;display:flex;flex-direction:column;padding:24px 20px 20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.cover-badge{display:inline-flex;align-items:center;gap:5px;background:var(--or);color:#fff;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:1px;padding:3px 12px;border-radius:20px;margin-bottom:12px;align-self:flex-start}\u001b[39m\n\u001b[31m.cover h1{font-size:20px;font-weight:700;line-height:1.3;margin-bottom:4px}\u001b[39m\n\u001b[31m.cover-addr{color:rgba(255,255,255,.55);font-size:12px;margin-bottom:16px}\u001b[39m\n\u001b[31m.cg{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}\u001b[39m\n\u001b[31m.cm{background:rgba(255,255,255,.08);border-radius:8px;padding:8px 12px}\u001b[39m\n\u001b[31m.cm-l{font-size:9px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}\u001b[39m\n\u001b[31m.cm-v{font-size:13px;font-weight:600;color:#fff}\u001b[39m\n\u001b[31m.cm-v a{color:#fb923c}\u001b[39m\n\u001b[31m.cover-pbar{padding-top:8px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{background:var(--or);color:#fff;border:none;padding:10px 22px;border-radius:22px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}\u001b[39m\n\u001b[31m.btn-p:disabled{opacity:.4;cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-c{background:rgba(255,255,255,.1);color:rgba(255,255,255,.75);border:1px solid rgba(255,255,255,.2);padding:10px 18px;border-radius:22px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit}·\u001b[39m\n\u001b[31m/* ── Cover thumbnail grid ── */\u001b[39m\n\u001b[31m.cov-grid-hdr{font-size:10px;font-weight:700;color:rgba(255,255,255,.35);text-transform:uppercase;letter-spacing:1.2px;padding:10px 0 5px;flex-shrink:0}\u001b[39m\n\u001b[31m.cov-grid{flex:1;min-height:0;display:grid;gap:5px;overflow:hidden;align-content:start}\u001b[39m\n\u001b[31m.cov-thumb{position:relative;overflow:hidden;border-radius:7px;cursor:pointer;background:#1e293b;transition:transform .18s,box-shadow .18s}\u001b[39m\n\u001b[31m.cov-thumb:hover{transform:scale(1.05);box-shadow:0 4px 18px rgba(0,0,0,.55)}\u001b[39m\n\u001b[31m.cov-thumb img{width:100%;height:100%;object-fit:cover;display:block}\u001b[39m\n\u001b[31m.cov-thumb-vid{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:#0f172a}\u001b[39m\n\u001b[31m.cov-thumb-ov{position:absolute;inset:0;background:rgba(0,0,0,.28);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:5px;border-radius:7px}\u001b[39m\n\u001b[31m.cov-thumb-cat{color:rgba(255,255,255,.5);font-weight:900;text-align:center;text-transform:uppercase;letter-spacing:.8px;text-shadow:0 1px 6px rgba(0,0,0,.95);line-height:1.2;word-break:break-word}\u001b[39m\n\u001b[31m.cov-thumb-dims{color:rgba(255,255,255,.5);font-weight:700;text-align:center;text-shadow:0 1px 5px rgba(0,0,0,.95);letter-spacing:.3px;line-height:1.3}\u001b[39m\n\u001b[31m.cov-thumb-no{color:rgba(255,255,255,.5);font-weight:800;text-shadow:0 1px 4px rgba(0,0,0,.95);letter-spacing:.5px}\u001b[39m\n\u001b[31m#cover-btn{position:fixed;bottom:20px;right:16px;display:none;align-items:center;gap:6px;background:rgba(255,255,255,.15);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.25);color:#fff;padding:10px 22px;border-radius:50px;font-size:13px;font-weight:700;cursor:pointer;z-index:200;letter-spacing:.3px;box-shadow:0 2px 12px rgba(0,0,0,.3);font-family:inherit;transition:background .15s,transform .15s}\u001b[39m\n\u001b[31m#cover-btn:hover{background:rgba(255,255,255,.22);transform:scale(1.04)}·\u001b[39m\n\u001b[31m/* ── Print wait overlay ── */\u001b[39m\n\u001b[31m#print-overlay{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m@media print{#print-overlay{display:none!important}}·\u001b[39m\n\u001b[31m/* ── Loading progress bar ── */\u001b[39m\n\u001b[31m.load-bar{position:fixed;bottom:0;left:0;right:0;background:rgba(15,23,42,.95);padding:9px 16px;z-index:9999;display:flex;align-items:center;gap:12px;backdrop-filter:blur(6px)}\u001b[39m\n\u001b[31m.load-track{flex:1;height:5px;background:rgba(255,255,255,.12);border-radius:3px;overflow:hidden}\u001b[39m\n\u001b[31m.load-fill{height:100%;background:var(--or);width:0%;transition:width .35s ease;border-radius:3px}\u001b[39m\n\u001b[31m.load-txt{font-size:11px;color:rgba(255,255,255,.6);white-space:nowrap;min-width:160px}·\u001b[39m\n\u001b[31m/* ── Photo page ── */\u001b[39m\n\u001b[31m.photo-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ph-band{background:var(--dk);padding:16px 26px;flex-shrink:0;display:flex;align-items:center;gap:20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.ph-cat{font-size:35px;font-weight:800;color:#fff;letter-spacing:-.5px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.ph-dims{flex:1;font-size:18px;font-weight:600;color:var(--or);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}\u001b[39m\n\u001b[31m.ph-no{margin-left:auto;flex-shrink:0;font-size:21px;font-weight:700;color:rgba(255,255,255,.85);background:rgba(255,255,255,.1);padding:5px 20px;border-radius:24px;white-space:nowrap}\u001b[39m\n\u001b[31m.ph-of{font-size:18px;font-weight:400;color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.ph-img{flex:1;overflow:hidden;position:relative;background:#111}\u001b[39m\n\u001b[31m.ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m.ph-img img{width:100%;height:100%;object-fit:contain;display:block}\u001b[39m\n\u001b[31m.ph-cmt{position:absolute;bottom:0;left:0;right:0;padding:6px 14px;background:rgba(0,0,0,.62);font-size:11px;color:rgba(255,255,255,.75);font-style:italic;pointer-events:none}·\u001b[39m\n\u001b[31m/* ── Video / Doc pages ── */\u001b[39m\n\u001b[31m.vid-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;background:#fff}\u001b[39m\n\u001b[31m.vid-body{flex:1;padding:20px 24px;font-size:14px;color:var(--g600);border-left:4px solid var(--or)}\u001b[39m\n\u001b[31m.vid-body em{display:block;font-size:12px;color:var(--g400);margin-top:6px}\u001b[39m\n\u001b[31m.doc-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m.doc-wrap{flex:1;display:flex;align-items:center;justify-content:center;background:#111;overflow:hidden}\u001b[39m\n\u001b[31m.doc-img{max-width:100%;max-height:100%;object-fit:contain}·\u001b[39m\n\u001b[31m/* ── Cover header band ── */\u001b[39m\n\u001b[31m.cov-hdr{display:flex;gap:0;margin-bottom:12px;flex-shrink:0;border-radius:10px;overflow:hidden;border:1px solid rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.cov-hdr-l{flex:1;padding:14px 18px;display:flex;flex-direction:column;gap:5px;border-right:1px solid rgba(255,255,255,.1);min-width:0}\u001b[39m\n\u001b[31m.cov-hdr-r{width:170px;flex-shrink:0;padding:14px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:rgba(255,255,255,.04)}\u001b[39m\n\u001b[31m.cov-store{font-size:18px;font-weight:800;color:#fff;line-height:1.25;margin-bottom:2px}\u001b[39m\n\u001b[31m.cov-meta{font-size:12px;color:rgba(255,255,255,.55);display:flex;align-items:center;gap:5px;line-height:1.5}\u001b[39m\n\u001b[31m.cov-brand{background:var(--or);color:#fff;font-size:13px;font-weight:800;padding:5px 16px;border-radius:20px;text-align:center;letter-spacing:.3px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\u001b[39m\n\u001b[31m.cov-date-l{font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.8px;margin-bottom:2px;text-align:center}\u001b[39m\n\u001b[31m.cov-date-v{font-size:13px;font-weight:700;color:#fff;text-align:center}\u001b[39m\n\u001b[31m.cov-logo-box{background:#fff;border-radius:8px;padding:8px 14px;display:flex;align-items:center;justify-content:center;width:100%;max-width:138px}\u001b[39m\n\u001b[31m.cov-logo-box img{max-width:110px;max-height:44px;object-fit:contain;display:block}·\u001b[39m\n\u001b[31m/* ── Print ── */\u001b[39m\n\u001b[31m@page{size:A4 landscape;margin:12mm}\u001b[39m\n\u001b[31m@media print{\u001b[39m\n\u001b[31m  html,body{height:auto;overflow:visible;display:block}\u001b[39m\n\u001b[31m  .side-idx{display:none}\u001b[39m\n\u001b[31m  .main{overflow:visible;display:block;height:auto;scroll-snap-type:none}\u001b[39m\n\u001b[31m  .cover,.vid-page,.doc-page{height:auto;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m  .photo-page{height:186mm;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m  .cover{padding:20px 24px}\u001b[39m\n\u001b[31m  .cover-pbar{display:none}\u001b[39m\n\u001b[31m  .cov-hdr{margin-bottom:8px;border-radius:7px}\u001b[39m\n\u001b[31m  .cov-hdr-l{padding:10px 14px}\u001b[39m\n\u001b[31m  .cov-hdr-r{padding:10px 12px;width:150px}\u001b[39m\n\u001b[31m  .cov-store{font-size:15px}\u001b[39m\n\u001b[31m  .cov-meta{font-size:10px}\u001b[39m\n\u001b[31m  .cov-brand{font-size:11px;padding:3px 12px}\u001b[39m\n\u001b[31m  .cov-date-v{font-size:11px}\u001b[39m\n\u001b[31m  .ph-band{padding:5mm 13mm;gap:10mm}\u001b[39m\n\u001b[31m  .ph-cat{font-size:15mm}\u001b[39m\n\u001b[31m  .ph-dims{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-no{font-size:12mm;padding:2mm 8mm}\u001b[39m\n\u001b[31m  .ph-of{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-img{flex:1;display:flex;align-items:center;justify-content:center;background:#fff;overflow:hidden}\u001b[39m\n\u001b[31m  .ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m  .ph-img img{width:100%;height:100%;object-fit:contain}\u001b[39m\n\u001b[31m  .ph-cmt{position:static;background:transparent;color:#475569;padding:2mm 8mm;font-size:6mm}\u001b[39m\n\u001b[31m  .main>*:last-child{page-break-after:avoid;break-after:avoid}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m</style></head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<div class=\\\"side-idx\\\" id=\\\"side-idx\\\">${sideItems.join('')}</div>·\u001b[39m\n\u001b[31m<div class=\\\"main\\\" id=\\\"main\\\">·\u001b[39m\n\u001b[31m<div class=\\\"cover\\\" id=\\\"pg-cover\\\">\u001b[39m\n\u001b[31m  <div class=\\\"cov-hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-l\\\">\u001b[39m\n\u001b[31m      <div class=\\\"cov-store\\\">${esc(d.storeName||'Unknown Store')}</div>\u001b[39m\n\u001b[31m      ${(d.address||d.city)?`<div class=\\\"cov-meta\\\">&#x1F4CD; ${esc(d.address||'')}${d.city&&!(d.address||'').includes(d.city)?', '+esc(d.city):''}</div>`:''}\u001b[39m\n\u001b[31m      ${d.mobile?`<div class=\\\"cov-meta\\\">&#x1F4DE; ${esc(d.mobile)}</div>`:''}\u001b[39m\n\u001b[31m      ${d.email?`<div class=\\\"cov-meta\\\">&#x2709; ${esc(d.email)}</div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-r\\\">\u001b[39m\n\u001b[31m      ${brandLogoUrl\u001b[39m\n\u001b[31m        ? `<div class=\\\"cov-logo-box\\\"><img src=\\\"${brandLogoUrl}\\\" alt=\\\"${esc(d.brand||'')}\\\"></div>`\u001b[39m\n\u001b[31m        : (d.brand?`<div class=\\\"cov-brand\\\">${esc(d.brand)}</div>`:'')}\u001b[39m\n\u001b[31m      ${d.date?`<div><div class=\\\"cov-date-l\\\">Recce Date</div><div class=\\\"cov-date-v\\\">${esc(d.date)}</div></div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${thumbItems.length ? `<div class=\\\"cov-grid-hdr\\\">&#x1F4F7; ${thumbItems.length} page${thumbItems.length!==1?'s':''} &mdash; tap any to jump</div><div class=\\\"cov-grid\\\" id=\\\"cov-grid\\\">${thumbsHtml}</div>` : ''}\u001b[39m\n\u001b[31m  <div class=\\\"cover-pbar\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" id=\\\"btn-print\\\" onclick=\\\"doPDF()\\\">&#x1F4C4;&nbsp;PDF</button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-c\\\" onclick=\\\"window.close()\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m${pagesHtml}·\u001b[39m\n\u001b[31m${d.hasVideo?`\u001b[39m\n\u001b[31m<div class=\\\"vid-page\\\" id=\\\"pg-vid\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Video</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"vid-body\\\">${esc(d.videoNote||'Video recorded during visit')}${d.videoCmt?`<em>${esc(d.videoCmt)}</em>`:''}</div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m${urls.doc?`\u001b[39m\n\u001b[31m<div class=\\\"doc-page\\\" id=\\\"pg-doc\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Document</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"doc-wrap\\\"><a href=\\\"${urls.doc}\\\" target=\\\"_blank\\\"><img class=\\\"doc-img\\\" src=\\\"${urls.doc}\\\" loading=\\\"lazy\\\" alt=\\\"Document\\\"></a></div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"print-overlay\\\"><div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Preparing print&hellip;</div><div class=\\\"po-sub\\\" id=\\\"po-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"po-pfill\\\"></div></div></div>\u001b[39m\n\u001b[31m${pages.length ? `<div class=\\\"load-bar\\\" id=\\\"load-bar\\\"><div class=\\\"load-track\\\"><div class=\\\"load-fill\\\" id=\\\"load-fill\\\"></div></div><div class=\\\"load-txt\\\" id=\\\"load-txt\\\">Loading photos&#x2026;</div></div>` : ''}\u001b[39m\n\u001b[31m${thumbItems.length ? `<button id=\\\"cover-btn\\\" onclick=\\\"document.getElementById('pg-cover').scrollIntoView({behavior:'smooth'})\\\">&#x1F3E0;&nbsp;Cover Page</button>` : ''}·\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var main=document.getElementById('main');\u001b[39m\n\u001b[31m  var items=document.querySelectorAll('.si-item');\u001b[39m\n\u001b[31m  var covBtn=document.getElementById('cover-btn');\u001b[39m\n\u001b[31m  function setActive(id){\u001b[39m\n\u001b[31m    items.forEach(function(el){el.classList.toggle('active',el.dataset.tgt===id);});\u001b[39m\n\u001b[31m    var a=document.querySelector('.si-item[data-tgt=\\\"'+id+'\\\"]');\u001b[39m\n\u001b[31m    if(a) a.scrollIntoView({block:'nearest'});\u001b[39m\n\u001b[31m    if(covBtn) covBtn.style.display=id==='pg-cover'?'none':'flex';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  items.forEach(function(el){\u001b[39m\n\u001b[31m    el.addEventListener('click',function(){\u001b[39m\n\u001b[31m      var t=document.getElementById(el.dataset.tgt);\u001b[39m\n\u001b[31m      if(t) t.scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if('IntersectionObserver' in window){\u001b[39m\n\u001b[31m    var obs=new IntersectionObserver(function(entries){\u001b[39m\n\u001b[31m      entries.forEach(function(e){if(e.isIntersecting&&e.intersectionRatio>=0.45) setActive(e.target.id);});\u001b[39m\n\u001b[31m    },{root:main,threshold:0.45});\u001b[39m\n\u001b[31m    document.querySelectorAll('[id^=\\\"pg-\\\"]').forEach(function(p){obs.observe(p);});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  setActive('pg-cover');\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var imgs=Array.from(document.querySelectorAll('img'));\u001b[39m\n\u001b[31m  var total=imgs.length,loaded=0;\u001b[39m\n\u001b[31m  var bar=document.getElementById('load-bar');\u001b[39m\n\u001b[31m  var fill=document.getElementById('load-fill');\u001b[39m\n\u001b[31m  var txt=document.getElementById('load-txt');\u001b[39m\n\u001b[31m  var printPending=false,printShowTime=0;\u001b[39m\n\u001b[31m  var mm=96/25.4;\u001b[39m\n\u001b[31m  var SERVER_PDF='${serverPdfUrl}';\u001b[39m\n\u001b[31m  function updatePoBar(){\u001b[39m\n\u001b[31m    var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m    var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(poFill) poFill.style.width=(total?Math.round(loaded/total*100):100)+'%';\u001b[39m\n\u001b[31m    if(poSub) poSub.textContent=loaded+' / '+total+' photos ready';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function done(){\u001b[39m\n\u001b[31m    if(fill) fill.style.width='100%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='✓ All '+total+' photos ready';\u001b[39m\n\u001b[31m    setTimeout(function(){\u001b[39m\n\u001b[31m      if(bar){bar.style.transition='opacity .6s';bar.style.opacity='0';}\u001b[39m\n\u001b[31m      setTimeout(function(){if(bar)bar.style.display='none';},650);\u001b[39m\n\u001b[31m    },2000);\u001b[39m\n\u001b[31m    if(printPending){\u001b[39m\n\u001b[31m      printPending=false;\u001b[39m\n\u001b[31m      var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m      var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m      var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(poFill) poFill.style.width='100%';\u001b[39m\n\u001b[31m      if(poSub) poSub.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},Math.max(400,2000-(Date.now()-printShowTime)));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function onImg(){\u001b[39m\n\u001b[31m    loaded++;\u001b[39m\n\u001b[31m    if(fill) fill.style.width=Math.round(loaded/total*100)+'%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… '+loaded+' / '+total;\u001b[39m\n\u001b[31m    if(printPending) updatePoBar();\u001b[39m\n\u001b[31m    if(loaded>=total) done();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  /* ── PDF layout helpers ── */\u001b[39m\n\u001b[31m  function fitBandFonts(pageW){\u001b[39m\n\u001b[31m    var padH=2*13*mm,gapH=2*10*mm,noPadH=2*8*mm;\u001b[39m\n\u001b[31m    var avail=pageW-padH-gapH;\u001b[39m\n\u001b[31m    var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-band').forEach(function(band){\u001b[39m\n\u001b[31m      var cat=band.querySelector('.ph-cat');\u001b[39m\n\u001b[31m      var dims=band.querySelector('.ph-dims');\u001b[39m\n\u001b[31m      var no=band.querySelector('.ph-no');\u001b[39m\n\u001b[31m      if(!cat) return;\u001b[39m\n\u001b[31m      var catTxt=cat.textContent.trim();\u001b[39m\n\u001b[31m      var dimsTxt=dims?dims.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      var noTxt=no?no.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      function tw(sc){\u001b[39m\n\u001b[31m        var cf=15*sc*mm,df=10*sc*mm,nf=12*sc*mm;\u001b[39m\n\u001b[31m        ctx.font='800 '+cf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var cw=ctx.measureText(catTxt).width;\u001b[39m\n\u001b[31m        ctx.font='600 '+df+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var dw=dims?ctx.measureText(dimsTxt).width:0;\u001b[39m\n\u001b[31m        ctx.font='700 '+nf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var nw=no?ctx.measureText(noTxt).width+noPadH:0;\u001b[39m\n\u001b[31m        return cw+dw+nw;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      var scale=1.0;\u001b[39m\n\u001b[31m      if(tw(scale)>avail){\u001b[39m\n\u001b[31m        var lo=0.3,hi=1.0;\u001b[39m\n\u001b[31m        for(var i=0;i<10;i++){var mid=(lo+hi)/2;if(tw(mid)<=avail)lo=mid;else hi=mid;}\u001b[39m\n\u001b[31m        scale=lo*0.93;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      cat.style.setProperty('font-size',Math.round(15*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(dims) dims.style.setProperty('font-size',Math.round(10*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(no) no.style.setProperty('font-size',Math.round(12*scale*mm)+'px','important');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function sizePdfThumbs(pageW,pageH){\u001b[39m\n\u001b[31m    var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m    if(!grid||!grid.children.length) return;\u001b[39m\n\u001b[31m    var coverPage=document.getElementById('pg-cover');\u001b[39m\n\u001b[31m    var usedH=56;\u001b[39m\n\u001b[31m    if(coverPage){\u001b[39m\n\u001b[31m      Array.from(coverPage.children).forEach(function(el){\u001b[39m\n\u001b[31m        if(el!==grid) usedH+=el.offsetHeight||0;\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    var gridH=Math.max(80,pageH-usedH);\u001b[39m\n\u001b[31m    var n=grid.children.length,gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m    for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m      var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m      var w=(pageW-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m      var h=w*asp;\u001b[39m\n\u001b[31m      if(rows*h+(rows-1)*gap<=gridH&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m    grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m    grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m    var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m    var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m    var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function preparePdfLayout(){\u001b[39m\n\u001b[31m    var pageW=Math.round((297-24)*mm);\u001b[39m\n\u001b[31m    var pageH=Math.round((210-24)*mm);\u001b[39m\n\u001b[31m    fitBandFonts(pageW);\u001b[39m\n\u001b[31m    sizePdfThumbs(pageW,pageH);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.preparePdfLayout=preparePdfLayout;\u001b[39m\n\u001b[31m  function restorePdfLayout(){\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-cat,.ph-dims,.ph-no').forEach(function(el){\u001b[39m\n\u001b[31m      el.style.removeProperty('font-size');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(window._screenSizeThumbs) window._screenSizeThumbs();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.addEventListener('afterprint',restorePdfLayout);\u001b[39m\n\u001b[31m  function _doBrowserPrint(){\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    printShowTime=Date.now();\u001b[39m\n\u001b[31m    preparePdfLayout();\u001b[39m\n\u001b[31m    if(total===0||loaded>=total){\u001b[39m\n\u001b[31m      var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m      if(ps) ps.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},2000);\u001b[39m\n\u001b[31m      return;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    printPending=true;\u001b[39m\n\u001b[31m    updatePoBar();\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if((!img.complete||img.naturalWidth===0)&&img.getAttribute('loading')==='lazy'){\u001b[39m\n\u001b[31m        img.loading='eager';var s=img.src;img.src='';img.src=s;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.doPDF=async function(){\u001b[39m\n\u001b[31m    if(!SERVER_PDF){_doBrowserPrint();return;}\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      var r=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m      if(r.ok){window.open(SERVER_PDF,'_blank');return;}\u001b[39m\n\u001b[31m    }catch(_){}\u001b[39m\n\u001b[31m    // PDF not ready yet — show overlay and poll\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    if(pf) pf.style.width='0%';\u001b[39m\n\u001b[31m    if(ps) ps.textContent='Waiting for server PDF…';\u001b[39m\n\u001b[31m    var tries=0;\u001b[39m\n\u001b[31m    (async function poll(){\u001b[39m\n\u001b[31m      tries++;\u001b[39m\n\u001b[31m      if(pf) pf.style.width=Math.min(88,tries*8)+'%';\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        var r2=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m        if(r2.ok){\u001b[39m\n\u001b[31m          if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m          setTimeout(function(){if(ov)ov.style.display='none';window.open(SERVER_PDF,'_blank');},400);\u001b[39m\n\u001b[31m          return;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      }catch(_){}\u001b[39m\n\u001b[31m      if(tries>=12){if(ov)ov.style.display='none';_doBrowserPrint();return;}\u001b[39m\n\u001b[31m      setTimeout(poll,5000);\u001b[39m\n\u001b[31m    })();\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  if(total===0){if(bar)bar.style.display='none';}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… 0 / '+total;\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if(img.complete&&img.naturalWidth>0) onImg();\u001b[39m\n\u001b[31m      else{img.addEventListener('load',onImg);img.addEventListener('error',onImg);}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m  if(grid&&grid.children.length>0){\u001b[39m\n\u001b[31m    function sizeThumbs(){\u001b[39m\n\u001b[31m      var n=grid.children.length;\u001b[39m\n\u001b[31m      var gw=grid.clientWidth,gh=grid.clientHeight;\u001b[39m\n\u001b[31m      if(!gw||!gh) return;\u001b[39m\n\u001b[31m      var gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m      for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m        var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m        var w=(gw-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m        var h=w*asp;\u001b[39m\n\u001b[31m        if(rows*h+(rows-1)*gap<=gh&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m      grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m      grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m      var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m      var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m      var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    window._screenSizeThumbs=sizeThumbs;\u001b[39m\n\u001b[31m    requestAnimationFrame(function(){requestAnimationFrame(sizeThumbs);});\u001b[39m\n\u001b[31m    window.addEventListener('resize',sizeThumbs);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m</scr`+'ipt>'+`\u001b[39m\n\u001b[31m</body></html>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncToPostgres(entry) {\u001b[39m\n\u001b[31m  const d   = entry.data || {};\u001b[39m\n\u001b[31m  const hub = _recceHubUser();·\u001b[39m\n\u001b[31m  // Step 1 — upload all photos to VPS, get permanent server URLs\u001b[39m\n\u001b[31m  let photoUrls = { front:[], inside:[], brandings:[], addl:[], doc:null };\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const pResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type: 'save-photos', subId: entry.id,\u001b[39m\n\u001b[31m        photos: {\u001b[39m\n\u001b[31m          front:    (d.frontPhotos||[]).map(p=>({b64:p.b64,   cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64,  cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||null})),\u001b[39m\n\u001b[31m          addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64,   desc:p.desc||''})),\u001b[39m\n\u001b[31m          doc:      d.docB64 || null,\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (pResp.ok) { const r=await pResp.json(); if(r.success) {\u001b[39m\n\u001b[31m      photoUrls=r.photoUrls;\u001b[39m\n\u001b[31m      // Merge retained existing URLs for edit re-submits\u001b[39m\n\u001b[31m      if (entry.editedAt) {\u001b[39m\n\u001b[31m        photoUrls.front    =(photoUrls.front   ||[]).map((u,i)=>u||(d.frontPhotos  ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.inside   =(photoUrls.inside  ||[]).map((u,i)=>u||(d.insidePhotos ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.addl     =(photoUrls.addl    ||[]).map((u,i)=>u||(d.addlPhotos   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.brandings=(photoUrls.brandings||[]).map((u,i)=>u||(d.brandings   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        if(!photoUrls.doc) photoUrls.doc=d._docExistingUrl||null;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }}\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-photos] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 1.5 — trigger Google Slides via proxy using permanent photo URLs (fire-and-forget)\u001b[39m\n\u001b[31m  (async()=>{try{\u001b[39m\n\u001b[31m    const _hasPh=(photoUrls.front||[]).some(Boolean)||(photoUrls.inside||[]).some(Boolean)||(photoUrls.brandings||[]).some(Boolean);\u001b[39m\n\u001b[31m    if(!_hasPh)return;\u001b[39m\n\u001b[31m    const _gu=(await cfg('slides-gas-url'))||(await cfg('gas-url'))||DEFAULT_GAS_URL;if(!_gu)return;\u001b[39m\n\u001b[31m    await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({\u001b[39m\n\u001b[31m      type:'make-slides',gasUrl:_gu,subId:entry.id,\u001b[39m\n\u001b[31m      storeInfo:{storeName:d.storeName||'',brand:d.brand||'',address:d.address||'',mobile:d.mobile||'',date:d.date||'',city:d.city||'',gpsCoords:d.gpsCoords||null},\u001b[39m\n\u001b[31m      photoGroups:{\u001b[39m\n\u001b[31m        front:    (photoUrls.front   ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.frontPhotos  ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        inside:   (photoUrls.inside  ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.insidePhotos ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        brandings:(photoUrls.brandings||[]).filter(Boolean).map((url,i)=>({url,meta:{type:(d.brandings||[])[i]?.type,w:(d.brandings||[])[i]?.w,h:(d.brandings||[])[i]?.h,qty:(d.brandings||[])[i]?.qty,sqft:(d.brandings||[])[i]?.sqft}})),\u001b[39m\n\u001b[31m        addl:    (photoUrls.addl    ||[]).filter(Boolean).map((url,i)=>({url,desc:(d.addlPhotos  ||[])[i]?.desc||''})),\u001b[39m\n\u001b[31m      },\u001b[39m\n\u001b[31m    })});\u001b[39m\n\u001b[31m    entry.gasAt=new Date().toISOString();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[recce-slides]',e.message);}}\u001b[39m\n\u001b[31m  )();·\u001b[39m\n\u001b[31m  // Step 2 — generate rich HTML report using server URLs, save to VPS\u001b[39m\n\u001b[31m  let view_url = null;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const html  = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m    const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-view', subId: entry.id, html })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (vResp.ok) { const r=await vResp.json(); if(r.success) view_url=r.url; }\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-view] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 3 — upsert to PostgreSQL with photo URLs + view URL\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch(`${_RC_BASE}/submissions`, {\u001b[39m\n\u001b[31m      method: 'POST', headers: _RC_UPSERT,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        sub_id:         entry.id,\u001b[39m\n\u001b[31m        store_name:     d.storeName    || 'Unknown',\u001b[39m\n\u001b[31m        brand:          d.brand        || null,\u001b[39m\n\u001b[31m        client_name:    d.clientName   || null,\u001b[39m\n\u001b[31m        visit_date:     d.date         || new Date().toISOString().slice(0,10),\u001b[39m\n\u001b[31m        address:        d.address      || null,\u001b[39m\n\u001b[31m        mobile:         d.mobile       || null,\u001b[39m\n\u001b[31m        city:           d.city         || null,\u001b[39m\n\u001b[31m        has_branding:   !!(d.brandings?.length),\u001b[39m\n\u001b[31m        branding_count: d.brandings?.length || 0,\u001b[39m\n\u001b[31m        has_video:      !!d.hasVideo,\u001b[39m\n\u001b[31m        front_photos:   d.frontPhotos?.length  || 0,\u001b[39m\n\u001b[31m        inside_photos:  d.insidePhotos?.length || 0,\u001b[39m\n\u001b[31m        addl_photos:    d.addlPhotos?.length   || 0,\u001b[39m\n\u001b[31m        gps_lat:        d.gpsCoords?.lat       || null,\u001b[39m\n\u001b[31m        gps_lng:        d.gpsCoords?.lng       || null,\u001b[39m\n\u001b[31m        submitted_by:   hub.empId              || null,\u001b[39m\n\u001b[31m        submitted_at:   entry.timestamp,\u001b[39m\n\u001b[31m        campaign_id:    entry.campaignId       || null,\u001b[39m\n\u001b[31m        photo_urls:     photoUrls,\u001b[39m\n\u001b[31m        view_url,\u001b[39m\n\u001b[31m        meta: {\u001b[39m\n\u001b[31m          brandings: (d.brandings||[]).map(b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft})),\u001b[39m\n\u001b[31m          videoNote: d.videoNote || null,\u001b[39m\n\u001b[31m          videoCmt:  d.videoCmt  || null,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        status: 'submitted',\u001b[39m\n\u001b[31m        edit_assigned_to: null,\u001b[39m\n\u001b[31m        edit_comment: null,\u001b[39m\n\u001b[31m        edited_at: entry.editedAt || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    return { ok: true, viewUrl: view_url };\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    console.warn('[recce-db] sync error:', e.message);\u001b[39m\n\u001b[31m    return { ok: false, viewUrl: null };\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mconst DEFAULT_ADMIN_HASH='42d372e6110bee134990ac6881c3d5eb568482008add9a859f37f10d759430e8';·\u001b[39m\n\u001b[31masync function saveGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('gas-url',url||DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  toast('Endpoint saved','success');\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function testEndpoint(){\u001b[39m\n\u001b[31m  const url=(await cfg('gas-url'))||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  try{await fetch(url,{method:'POST',mode:'no-cors',body:JSON.stringify({test:true})});toast('Endpoint reachable ✓','success');}\u001b[39m\n\u001b[31m  catch{toast('Cannot reach endpoint','error')}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  cfg('gas-url').then(url=>{\u001b[39m\n\u001b[31m    const u=url||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    // Show last 30 chars only for privacy\u001b[39m\n\u001b[31m    el.textContent='Endpoint: …'+u.slice(-30);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── SLIDES GAS URL ────────────────────────────────────────────\u001b[39m\n\u001b[31masync function saveSlidesGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('slides-gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('slides-gas-url', url);\u001b[39m\n\u001b[31m  toast('Slides GAS URL saved','success');\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function updateSlidesGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('slides-gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  const u=await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  el.textContent=u?'Configured: …'+u.slice(-30):'Not configured';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── MAKE SLIDES ───────────────────────────────────────────────\u001b[39m\n\u001b[31masync function makeSlides(id){\u001b[39m\n\u001b[31m  const gasUrl = await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  if(!gasUrl){\u001b[39m\n\u001b[31m    toast('Configure Slides GAS URL in Settings first','error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const entry = await dbGet('subs', id);\u001b[39m\n\u001b[31m  if(!entry){ toast('Entry not found','error'); return; }\u001b[39m\n\u001b[31m  const d = entry.data;·\u001b[39m\n\u001b[31m  toast('Uploading photos & generating slides…','info');·\u001b[39m\n\u001b[31m  // Build photo groups payload\u001b[39m\n\u001b[31m  const photoGroups = {\u001b[39m\n\u001b[31m    front:    (d.frontPhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64, cmt:p.desc||''})),\u001b[39m\n\u001b[31m    brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||'', meta:{type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft}})),\u001b[39m\n\u001b[31m  };·\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type:       'recce',\u001b[39m\n\u001b[31m        subId:      id,\u001b[39m\n\u001b[31m        gasUrl:     gasUrl,\u001b[39m\n\u001b[31m        storeInfo:  {\u001b[39m\n\u001b[31m          storeName: d.storeName, brand: d.brand,\u001b[39m\n\u001b[31m          date: d.date, address: d.address,\u001b[39m\n\u001b[31m          mobile: d.mobile, gpsCoords: d.gpsCoords,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        photoGroups,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const result = await resp.json();\u001b[39m\n\u001b[31m    if(result.success && result.slideUrl){\u001b[39m\n\u001b[31m      // Store slide URL on the entry\u001b[39m\n\u001b[31m      entry.slideUrl = result.slideUrl;\u001b[39m\n\u001b[31m      await dbPut('subs', entry);\u001b[39m\n\u001b[31m      toast('✅ Slides ready!','success');\u001b[39m\n\u001b[31m      window.open(result.slideUrl, '_blank');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast('Slides error: '+(result.error||'Unknown'),'error');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e){\u001b[39m\n\u001b[31m    toast('Network error: '+e.message,'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN LOGIN ──────────────────────────────────────────────\u001b[39m\n\u001b[31mfunction showAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-error').style.display='none';\u001b[39m\n\u001b[31m  // Restore saved config URL\u001b[39m\n\u001b[31m  cfg('admin-cfg-url').then(u=>{if(u&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=u;});\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('admin-pwd').focus(),100);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveAdminCfgUrl(){\u001b[39m\n\u001b[31m  // Admin cfg URL can be saved without login (needed to set up auth itself)\u001b[39m\n\u001b[31m  // But we warn if saving while unlocked only\u001b[39m\n\u001b[31m  const url=document.getElementById('admin-cfg-url').value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  await cfg('admin-cfg-url',url);\u001b[39m\n\u001b[31m  toast('Config URL saved — will use on next login attempt','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function verifyAdmin(){\u001b[39m\n\u001b[31m  // Hub admins (harish/pramod) are auto-unlocked — no password needed\u001b[39m\n\u001b[31m  if (_adminUnlocked) { adminLoginSuccess(); return; }\u001b[39m\n\u001b[31m  const pwd=document.getElementById('admin-pwd').value;\u001b[39m\n\u001b[31m  if(!pwd){document.getElementById('admin-error').style.display='block';document.getElementById('admin-error').textContent='Enter password';return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('admin-login-btn');btn.disabled=true;btn.textContent='Verifying…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // Try server verification first\u001b[39m\n\u001b[31m    const cfgUrl=(await cfg('admin-cfg-url'))||'';\u001b[39m\n\u001b[31m    if(cfgUrl){\u001b[39m\n\u001b[31m      const r=await fetch(cfgUrl,{cache:'no-store'});\u001b[39m\n\u001b[31m      const j=await r.json();\u001b[39m\n\u001b[31m      // Server JSON format: {\\\"password\\\":\\\"plaintext\\\"} or {\\\"hash\\\":\\\"sha256hash\\\"}\u001b[39m\n\u001b[31m      let match=false;\u001b[39m\n\u001b[31m      if(j.password){match=(j.password===pwd);}\u001b[39m\n\u001b[31m      else if(j.hash){\u001b[39m\n\u001b[31m        // SHA-256 comparison\u001b[39m\n\u001b[31m        const enc=new TextEncoder();\u001b[39m\n\u001b[31m        const data=enc.encode(pwd);\u001b[39m\n\u001b[31m        const hashBuf=await crypto.subtle.digest('SHA-256',data);\u001b[39m\n\u001b[31m        const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m        match=(hashHex===j.hash);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      if(match){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m      else{showAdminError('Incorrect password');return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Fallback: local password stored in settings\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if(localHash){\u001b[39m\n\u001b[31m      const enc=new TextEncoder();\u001b[39m\n\u001b[31m      const hashBuf=await crypto.subtle.digest('SHA-256',enc.encode(pwd));\u001b[39m\n\u001b[31m      const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m      if(hashHex===localHash){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Final fallback: check against hardcoded default hash\u001b[39m\n\u001b[31m    const enc2=new TextEncoder();\u001b[39m\n\u001b[31m    const hb2=await crypto.subtle.digest('SHA-256',enc2.encode(pwd));\u001b[39m\n\u001b[31m    const hh2=Array.from(new Uint8Array(hb2)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    if(hh2===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }catch(err){\u001b[39m\n\u001b[31m    // Network error — try all local fallbacks\u001b[39m\n\u001b[31m    const enc3=new TextEncoder();\u001b[39m\n\u001b[31m    const hb3=await crypto.subtle.digest('SHA-256',enc3.encode(pwd));\u001b[39m\n\u001b[31m    const hh3=Array.from(new Uint8Array(hb3)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if((localHash&&hh3===localHash)||hh3===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }finally{btn.disabled=false;btn.textContent='Login';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showAdminError(msg){\u001b[39m\n\u001b[31m  const el=document.getElementById('admin-error');\u001b[39m\n\u001b[31m  el.textContent=msg;el.style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminLoginSuccess(){\u001b[39m\n\u001b[31m  _adminUnlocked=true;\u001b[39m\n\u001b[31m  closeAdminLogin();\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  cfg('gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  cfg('slides-gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('slides-gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||'';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  toast('Admin mode unlocked','success');\u001b[39m\n\u001b[31m  setTimeout(lockAdmin,10*60*1000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction lockAdmin(){\u001b[39m\n\u001b[31m  _adminUnlocked=false;\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  toast('Admin session ended','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updAvailTag(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-avail-tag');\u001b[39m\n\u001b[31m  const ct=document.getElementById('store-avail-count');\u001b[39m\n\u001b[31m  const txt=stores.length?`${stores.length} stores`:'No store list';\u001b[39m\n\u001b[31m  if(el)el.textContent=txt;\u001b[39m\n\u001b[31m  if(ct)ct.textContent=stores.length?t(`${stores.length} stores available — tap to browse`,`${stores.length} स्टोर उपलब्ध — दबाएं`):t('No store list loaded yet','कोई स्टोर सूची नहीं');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PICKER\u001b[39m\n\u001b[31mfunction openPicker(){\u001b[39m\n\u001b[31m  if(!stores.length){toast('Load a store list in Settings first','error');return;}\u001b[39m\n\u001b[31m  document.getElementById('povl').classList.add('open');\u001b[39m\n\u001b[31m  document.getElementById('psearch').value='';\u001b[39m\n\u001b[31m  filterPicker('');\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('psearch').focus(),150);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closePicker(){document.getElementById('povl').classList.remove('open');}\u001b[39m\n\u001b[31masync function filterPicker(q){\u001b[39m\n\u001b[31m  const list=document.getElementById('plist');\u001b[39m\n\u001b[31m  const words=q.toLowerCase().trim().split(/\\\\s+/).filter(Boolean);\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const lastVisit={};\u001b[39m\n\u001b[31m  subs.forEach(s=>{const nm=s.data?.storeName;if(nm&&(!lastVisit[nm]||s.timestamp>lastVisit[nm]))lastVisit[nm]=s.timestamp;});·\u001b[39m\n\u001b[31m  // Multi-word: ALL words must match somewhere in any field (search across both English and Hindi)\u001b[39m\n\u001b[31m  let fl=stores.filter(s=>{\u001b[39m\n\u001b[31m    if(!words.length)return true;\u001b[39m\n\u001b[31m    const hay=[s.name,s.nameHi,s.address,s.addressHi,s.mobile,s.city,s.cityHi,s.distName,s.distNameHi,s.brand,s.sales,s.proj,s.glowSign,s.inshop]\u001b[39m\n\u001b[31m               .map(x=>(x||'').toLowerCase()).join(' ');\u001b[39m\n\u001b[31m    return words.every(w=>hay.includes(w));\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(fl.length>100)fl=fl.slice(0,100);·\u001b[39m\n\u001b[31m  if(!fl.length){\u001b[39m\n\u001b[31m    const esc=q.replace(/'/g,\\\"\\\\\\\\'\\\");\u001b[39m\n\u001b[31m    list.innerHTML=`<div style=\\\"text-align:center;padding:32px 16px;color:var(--g400);font-size:14px\\\">No stores match \\\"${q}\\\"<br><span style=\\\"font-size:12px\\\">Try fewer or different words</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('${esc}')\\\">+ Add \\\"${q}\\\" as new store</div>`;\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Group by brand (including empty brand)\u001b[39m\n\u001b[31m  const g={};\u001b[39m\n\u001b[31m  fl.forEach(s=>{\u001b[39m\n\u001b[31m    const b=s.brand||'(No Brand — will ask)';\u001b[39m\n\u001b[31m    if(!g[b])g[b]=[];\u001b[39m\n\u001b[31m    g[b].push(s);\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html='';\u001b[39m\n\u001b[31m  Object.keys(g).sort().forEach(br=>{\u001b[39m\n\u001b[31m    html+=`<div class=\\\"psec\\\">${br}</div>`;\u001b[39m\n\u001b[31m    g[br].forEach(s=>{\u001b[39m\n\u001b[31m      const lv=lastVisit[s.name];\u001b[39m\n\u001b[31m      const lvStr=lv?`🕐 Last: ${new Date(lv).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'2-digit'})}`:'';\u001b[39m\n\u001b[31m      const chips=[];\u001b[39m\n\u001b[31m      if(s.glowSign&&s.glowSign.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dcfce7;color:#14532d;padding:2px 6px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m      if(s.inshop&&s.inshop.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dbeafe;color:#1e40af;padding:2px 6px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m      if(s.proj)chips.push(`<span style=\\\"font-size:10px;background:var(--g100);color:var(--g600);padding:2px 6px;border-radius:10px\\\">Target: ${s.proj}</span>`);\u001b[39m\n\u001b[31m      const enc=JSON.stringify(s).replace(/\\\"/g,'&quot;');\u001b[39m\n\u001b[31m      const mapsUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m      const waUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const telUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const dispName=LANG==='hi'&&s.nameHi?s.nameHi:s.name;\u001b[39m\n\u001b[31m      const dispAddr=LANG==='hi'&&s.addressHi?s.addressHi:s.address;\u001b[39m\n\u001b[31m      const dispDist=LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m      html+=`<div class=\\\"pitem\\\" onclick=\\\"pickStore(${enc})\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"pi-name\\\">${dispName}</div>\u001b[39m\n\u001b[31m          ${dispAddr?`<div class=\\\"pi-addr\\\">📍 ${dispAddr}</div>`:''}\u001b[39m\n\u001b[31m          ${s.mobile?`<div class=\\\"pi-addr\\\">📞 ${s.mobile}</div>`:''}\u001b[39m\n\u001b[31m          ${dispDist?`<div class=\\\"pi-addr\\\" style=\\\"color:var(--am)\\\">👤 ${dispDist}</div>`:''}\u001b[39m\n\u001b[31m          ${lvStr?`<div class=\\\"pi-last\\\">${lvStr}</div>`:''}\u001b[39m\n\u001b[31m          ${chips.length?`<div style=\\\"display:flex;gap:4px;flex-wrap:wrap;margin-top:4px\\\">${chips.join('')}</div>`:''}\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;gap:6px;margin-top:7px\\\" onclick=\\\"event.stopPropagation()\\\">\u001b[39m\n\u001b[31m            ${mapsUrl?`<a href=\\\"${mapsUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#e0f2fe;color:#0369a1;border-radius:20px;text-decoration:none;font-weight:600\\\">🗺 Maps</a>`:''}\u001b[39m\n\u001b[31m            ${waUrl?`<a href=\\\"${waUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#dcfce7;color:#15803d;border-radius:20px;text-decoration:none;font-weight:600\\\">💬 WhatsApp</a>`:''}\u001b[39m\n\u001b[31m            ${telUrl?`<a href=\\\"${telUrl}\\\" style=\\\"font-size:11px;padding:4px 10px;background:#f0fdf4;color:#166534;border-radius:20px;text-decoration:none;font-weight:600\\\">📞 Call</a>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        ${s.brand?`<div class=\\\"pi-brand\\\">${s.brand}</div>`:'<div class=\\\"pi-brand\\\" style=\\\"background:var(--rd)\\\">?</div>'}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html+=`<div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('')\\\">+ Not in list? Add new store</div>`;\u001b[39m\n\u001b[31m  list.innerHTML=html;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function pickStore(s){\u001b[39m\n\u001b[31m  selectedStore=s;manualMode=false;closePicker();\u001b[39m\n\u001b[31m  const _dn =LANG==='hi'&&s.nameHi    ?s.nameHi    :s.name;\u001b[39m\n\u001b[31m  const _da =LANG==='hi'&&s.addressHi ?s.addressHi :s.address;\u001b[39m\n\u001b[31m  const _dd =LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m  const _dc =LANG==='hi'&&s.cityHi    ?s.cityHi    :s.city;\u001b[39m\n\u001b[31m  document.getElementById('sc-name').textContent=_dn;\u001b[39m\n\u001b[31m  const brandEl=document.getElementById('sc-brand');\u001b[39m\n\u001b[31m  brandEl.textContent=s.brand||'No Brand';brandEl.style.background=s.brand?'var(--nv)':'var(--rd)';\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const prev=subs.filter(x=>x.data?.storeName===s.name).sort((a,b)=>new Date(b.timestamp)-new Date(a.timestamp))[0];\u001b[39m\n\u001b[31m  const lc=document.getElementById('sc-last');\u001b[39m\n\u001b[31m  if(prev){const d=new Date(prev.timestamp);lc.textContent='Last: '+d.toLocaleDateString('en-IN',{day:'numeric',month:'short'});lc.style.display='inline-flex';}\u001b[39m\n\u001b[31m  else lc.style.display='none';\u001b[39m\n\u001b[31m  // All Excel fields — display in active language\u001b[39m\n\u001b[31m  const mUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m  const wUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const tUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const details=[];\u001b[39m\n\u001b[31m  if(_da)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📍 ${_da}${mUrl?` <a href=\\\"${mUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#0369a1;margin-left:6px\\\">🗺 Navigate</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(s.mobile)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📞 ${s.mobile}${tUrl?` <a href=\\\"${tUrl}\\\" style=\\\"font-size:11px;color:#166534;margin-left:6px\\\">Call</a>`:''}${wUrl?` <a href=\\\"${wUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#15803d;margin-left:6px\\\">WhatsApp</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(_dd)details.push(`<div style=\\\"font-size:12px;color:var(--am)\\\">👤 ${_dd}</div>`);\u001b[39m\n\u001b[31m  if(_dc)details.push(`<div style=\\\"font-size:12px;color:var(--g500)\\\">🏙 ${_dc}</div>`);\u001b[39m\n\u001b[31m  const opp=[];\u001b[39m\n\u001b[31m  if(s.glowSign&&s.glowSign.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dcfce7;color:#14532d;padding:2px 7px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m  if(s.inshop&&s.inshop.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dbeafe;color:#1e40af;padding:2px 7px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m  if(s.proj)opp.push(`<span style=\\\"font-size:11px;background:var(--g100);color:var(--g600);padding:2px 7px;border-radius:10px\\\">Target 2026: ${s.proj}</span>`);\u001b[39m\n\u001b[31m  if(opp.length)details.push(`<div style=\\\"display:flex;gap:5px;flex-wrap:wrap;margin-top:3px\\\">${opp.join('')}</div>`);\u001b[39m\n\u001b[31m  document.getElementById('sc-details').innerHTML=details.join('');\u001b[39m\n\u001b[31m  // Missing fields\u001b[39m\n\u001b[31m  const missing=[];\u001b[39m\n\u001b[31m  if(!s.address)missing.push({key:'address',label:'Store Address',type:'textarea',placeholder:'Full address'});\u001b[39m\n\u001b[31m  if(!s.mobile)missing.push({key:'mobile',label:'Mobile No.',type:'tel',placeholder:'10-digit number',maxlen:'10'});\u001b[39m\n\u001b[31m  const mw=document.getElementById('sc-missing'),mf=document.getElementById('sc-missing-fields');\u001b[39m\n\u001b[31m  if(missing.length){\u001b[39m\n\u001b[31m    mf.innerHTML=missing.map(m=>`<div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\"><label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">${m.label} <span class=\\\"req\\\">*</span></label>${m.type==='textarea'?`<textarea id=\\\"sc-miss-${m.key}\\\" rows=\\\"2\\\" placeholder=\\\"${m.placeholder}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></textarea>`:`<input type=\\\"${m.type}\\\" id=\\\"sc-miss-${m.key}\\\" placeholder=\\\"${m.placeholder}\\\" ${m.maxlen?`maxlength=\\\"${m.maxlen}\\\"`:''}  inputmode=\\\"${m.type==='tel'?'numeric':'text'}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\">`}</div>`).join('');\u001b[39m\n\u001b[31m    mw.style.display='block';\u001b[39m\n\u001b[31m  } else {mw.style.display='none';}\u001b[39m\n\u001b[31m  // Brand selector\u001b[39m\n\u001b[31m  const bSel=document.getElementById('brand-selector'),bChips=document.getElementById('brand-chips');\u001b[39m\n\u001b[31m  if(!s.brand){\u001b[39m\n\u001b[31m    renderBrandChips();\u001b[39m\n\u001b[31m    bSel.style.display='block';\u001b[39m\n\u001b[31m  } else {bSel.style.display='none';}\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  F.storeName=s.name;F.brand=s.brand||'';F.address=s.address||'';F.mobile=s.mobile||'';\u001b[39m\n\u001b[31m  if(s.brand&&!_selectedClient&&!_clientOtherMode) autoSetClient(s.brand);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateMissingField(key,val){if(!selectedStore)return;selectedStore[key]=val.trim();F[key]=val.trim();saveDraft();}\u001b[39m\n\u001b[31mfunction selectStoreBrand(b){\u001b[39m\n\u001b[31m  F.brand=b;F.brandLogoUrl=_brandLogos[b]||'';\u001b[39m\n\u001b[31m  if(selectedStore)selectedStore.brand=b;\u001b[39m\n\u001b[31m  const el=document.getElementById('sc-brand');if(el){el.textContent=b;el.style.background='var(--nv)';}\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-chips .chip').forEach(c=>{c.classList.toggle('sel',c.querySelector('span')?.textContent===b||c.textContent.trim()===b);});\u001b[39m\n\u001b[31m  if(!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction onManualBrandChange(){\u001b[39m\n\u001b[31m  const b=document.getElementById('f-brand')?.value||'';\u001b[39m\n\u001b[31m  F.brandLogoUrl=b?(_brandLogos[b]||''):'';\u001b[39m\n\u001b[31m  if(b&&!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction openManual(prefill){\u001b[39m\n\u001b[31m  manualMode=true;\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').classList.add('on');\u001b[39m\n\u001b[31m  document.getElementById('mt-label').innerHTML='← Back to store list';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='block';\u001b[39m\n\u001b[31m  // Pre-fill from selectedStore if available (e.g. when toggling after picker selection)\u001b[39m\n\u001b[31m  const s=selectedStore;\u001b[39m\n\u001b[31m  if(s){\u001b[39m\n\u001b[31m    if(document.getElementById('f-brand'))document.getElementById('f-brand').value=s.brand||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-store'))document.getElementById('f-store').value=s.name||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-addr'))document.getElementById('f-addr').value=s.address||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-mobile'))document.getElementById('f-mobile').value=s.mobile||'';\u001b[39m\n\u001b[31m  } else if(prefill){\u001b[39m\n\u001b[31m    document.getElementById('f-store').value=prefill;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  selectedStore=null;\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction toggleManual(){\u001b[39m\n\u001b[31m  if(manualMode){\u001b[39m\n\u001b[31m    manualMode=false;\u001b[39m\n\u001b[31m    document.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31m    document.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31m    document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    openManual('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// GPS\u001b[39m\n\u001b[31mfunction captureGPS(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gps-status');el.textContent='Getting location…';el.style.color='var(--g500)';\u001b[39m\n\u001b[31m  if(!navigator.geolocation){el.textContent='GPS not available';return;}\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(pos=>{\u001b[39m\n\u001b[31m    gpsCoords={lat:pos.coords.latitude.toFixed(6),lng:pos.coords.longitude.toFixed(6),acc:Math.round(pos.coords.accuracy)};\u001b[39m\n\u001b[31m    el.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${gpsCoords.acc}m)`;el.style.color='var(--gn)';saveDraft();\u001b[39m\n\u001b[31m  },()=>{el.textContent='GPS failed — enter address manually';el.style.color='var(--rd)';},{enableHighAccuracy:true,timeout:10000});\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// DRAFT\u001b[39m\n\u001b[31mlet draftT;\u001b[39m\n\u001b[31mfunction saveDraft(){\u001b[39m\n\u001b[31m  clearTimeout(draftT);\u001b[39m\n\u001b[31m  draftT=setTimeout(async()=>{\u001b[39m\n\u001b[31m    const draft={k:'current',ts:Date.now(),F:{...F,date:document.getElementById('f-date')?.value||'',brand:manualMode?(document.getElementById('f-brand')?.value||''):(selectedStore?.brand||F.brand||''),storeName:selectedStore?selectedStore.name:(document.getElementById('f-store')?.value||''),address:manualMode?(document.getElementById('f-addr')?.value||''):(selectedStore?.address||F.address||''),mobile:manualMode?(document.getElementById('f-mobile')?.value||''):(selectedStore?.mobile||F.mobile||''),clientName:getClientName()},selectedStore,manualMode,gpsCoords,_selectedClient,_clientOtherMode,fCnt:frontPhotos.length,iCnt:insidePhotos.length,bCnt:brandings.length};\u001b[39m\n\u001b[31m    await dbPut('draft',draft);\u001b[39m\n\u001b[31m    // Also save photos as b64 blobs to draft so they survive exit\u001b[39m\n\u001b[31m    await saveDraftPhotos();\u001b[39m\n\u001b[31m  },500);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveDraftPhotos(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const photoData={\u001b[39m\n\u001b[31m      front:await Promise.all(frontPhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      inside:await Promise.all(insidePhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      addl:await Promise.all(addlPhotos.map(async p=>({b64:await b64(p.blob),desc:p.desc||''}))),\u001b[39m\n\u001b[31m      brand:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,b64:b.blob?await b64(b.blob):null})))\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    await dbPut('draft',{k:'photos',...photoData});\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function checkDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');const wrap=document.getElementById('resume-wrap');\u001b[39m\n\u001b[31m  if(!d||!d.F?.storeName){wrap.innerHTML='';return;}\u001b[39m\n\u001b[31m  const ago=Math.round((Date.now()-d.ts)/60000);\u001b[39m\n\u001b[31m  const agoStr=ago<1?'just now':ago<60?`${ago}m ago`:`${Math.round(ago/60)}h ago`;\u001b[39m\n\u001b[31m  wrap.innerHTML=`<button class=\\\"resume-btn\\\" onclick=\\\"resumeDraft()\\\">\u001b[39m\n\u001b[31m    <div><div style=\\\"font-size:12px;color:rgba(255,255,255,.5);margin-bottom:3px\\\">Resume draft · ${agoStr}</div><div>${d.F.storeName} · ${d.F.brand||'No brand'}</div></div>\u001b[39m\n\u001b[31m    <div style=\\\"text-align:right\\\"><div style=\\\"font-size:13px;color:var(--or)\\\">${d.fCnt||0} photos · ${d.bCnt||0} brandings →</div></div>\u001b[39m\n\u001b[31m  </button>`;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function resumeDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');if(!d)return;\u001b[39m\n\u001b[31m  F=d.F||{};gpsCoords=d.gpsCoords||null;\u001b[39m\n\u001b[31m  if(d.selectedStore){await pickStore(d.selectedStore);}\u001b[39m\n\u001b[31m  else if(d.manualMode){openManual('');if(F.brand)document.getElementById('f-brand').value=F.brand;if(F.storeName)document.getElementById('f-store').value=F.storeName;if(F.address)document.getElementById('f-addr').value=F.address;if(F.mobile)document.getElementById('f-mobile').value=F.mobile;}\u001b[39m\n\u001b[31m  if(F.date)document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  // Restore client chip state\u001b[39m\n\u001b[31m  if(d._clientOtherMode){_clientOtherMode=true;_selectedClient='';const inp=document.getElementById('f-client-other');if(inp&&F.clientName)inp.value=F.clientName;}\u001b[39m\n\u001b[31m  else if(d._selectedClient){_selectedClient=d._selectedClient;_clientOtherMode=false;}\u001b[39m\n\u001b[31m  else if(F.clientName){autoSetClient(F.clientName);}\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  // Restore photos from draft\u001b[39m\n\u001b[31m  const pd=await dbGet('draft','photos');\u001b[39m\n\u001b[31m  if(pd){\u001b[39m\n\u001b[31m    async function b64ToBlob(b64str){if(!b64str)return null;try{const r=await fetch(b64str);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m    for(const p of(pd.front||[])){const bl=await b64ToBlob(p.b64);if(bl)frontPhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.inside||[])){const bl=await b64ToBlob(p.b64);if(bl)insidePhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.addl||[])){const bl=await b64ToBlob(p.b64);if(bl)addlPhotos.push({blob:bl,prev:URL.createObjectURL(bl),desc:p.desc||''});}\u001b[39m\n\u001b[31m    for(const b of(pd.brand||[])){const bl=await b64ToBlob(b.b64);brandings.push({type:b.type,w:b.w,h:b.h,qty:b.qty,blob:bl,prev:bl?URL.createObjectURL(bl):null});}\u001b[39m\n\u001b[31m    toast('Draft restored with '+frontPhotos.length+' photos ✓','success');\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    toast('Draft restored — photos could not be recovered','info');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PHOTOS\u001b[39m\n\u001b[31mfunction updPhotoBadge(type){const arr=type==='front'?frontPhotos:insidePhotos;const el=document.getElementById(type+'-badge');if(el){el.textContent=arr.length;el.className='cnt-badge '+(arr.length?'':'gray');}}\u001b[39m\n\u001b[31mfunction renderPhotos(type){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  const cont=document.getElementById(type+'-cont');const addBtn=document.getElementById('add-'+type);\u001b[39m\n\u001b[31m  updPhotoBadge(type);\u001b[39m\n\u001b[31m  if(arr.length===0){cont.innerHTML=`<div class=\\\"pslot\\\" onclick=\\\"addPhoto('${type}')\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to capture or upload</span><span class=\\\"hi-txt\\\">फोटो खींचें या अपलोड करें</span></div></div>`;addBtn.style.display='none';return;}\u001b[39m\n\u001b[31m  cont.innerHTML=arr.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const badge=isRetained?`<span class=\\\"pbadge\\\" style=\\\"background:#475569\\\">Existing</span>`:`<span class=\\\"pbadge\\\">${fmtSz(p.blob.size)}</span>`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replacePhoto('${type}',${i})\\\" style=\\\"right:36px;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"margin-bottom:12px\\\"><div class=\\\"pslot filled\\\" style=\\\"margin-bottom:8px\\\"><img src=\\\"${p.prev}\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmPhoto('${type}',${i})\\\">×</button>${badge}</div><input type=\\\"text\\\" placeholder=\\\"Comments (optional)\\\" value=\\\"${p.cmt||''}\\\" onchange=\\\"${type==='front'?'frontPhotos':'insidePhotos'}[${i}].cmt=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  addBtn.style.display=arr.length<(type==='inside'?5:3)?'inline-flex':'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// Photo source: 'camera' stamps geo, 'gallery' does not\u001b[39m\n\u001b[31mlet _photoSourceCb=null,_photoSourceQuality=null;·\u001b[39m\n\u001b[31mfunction capPhoto(cb,forceSource,quality){\u001b[39m\n\u001b[31m  // quality override: null=use setting, 'hd', 'compressed'\u001b[39m\n\u001b[31m  _photoSourceCb=cb;_photoSourceQuality=quality||null;\u001b[39m\n\u001b[31m  if(forceSource==='camera'){_doCapture(cb,'camera',quality);return;}\u001b[39m\n\u001b[31m  if(forceSource==='gallery'){_doCapture(cb,'gallery',quality);return;}\u001b[39m\n\u001b[31m  // Show picker\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _doCapture(cb,src,quality){\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  const i=document.createElement('input');\u001b[39m\n\u001b[31m  i.type='file';i.accept='image/*';\u001b[39m\n\u001b[31m  if(src==='camera')i.setAttribute('capture','environment');\u001b[39m\n\u001b[31m  i.style.display='none';\u001b[39m\n\u001b[31m  i.onchange=async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f)return;\u001b[39m\n\u001b[31m    const q=quality||_photoSourceQuality||null;\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      const blob=await compress(f,q==='hd'?1920:q==='compressed'?1280:null,q==='hd'?0.90:q==='compressed'?0.78:null);\u001b[39m\n\u001b[31m      // Only stamp if from camera (live photo)\u001b[39m\n\u001b[31m      const stamped=(src==='camera')?await stampPhoto(blob):blob;\u001b[39m\n\u001b[31m      // Save to device (auto-download trigger)\u001b[39m\n\u001b[31m      savePhotoToDevice(stamped);\u001b[39m\n\u001b[31m      cb({target:{files:[f]},_blob:stamped,_src:src});\u001b[39m\n\u001b[31m    }catch(err){toast('Photo processing failed — try again','error');console.error('_doCapture error:',err);}\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  document.body.appendChild(i);i.click();setTimeout(()=>i.remove(),8000);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction photoSrcCamera(){_doCapture(_photoSourceCb,'camera',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcGallery(){_doCapture(_photoSourceCb,'gallery',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcCancel(){document.getElementById('photo-src-dialog').classList.remove('open');_photoSourceCb=null;}·\u001b[39m\n\u001b[31m// Save photo to device gallery/downloads\u001b[39m\n\u001b[31mfunction savePhotoToDevice(blob){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    const a=document.createElement('a');\u001b[39m\n\u001b[31m    a.href=url;\u001b[39m\n\u001b[31m    a.download='Recce_'+Date.now()+'.jpg';\u001b[39m\n\u001b[31m    a.style.display='none';\u001b[39m\n\u001b[31m    document.body.appendChild(a);a.click();\u001b[39m\n\u001b[31m    setTimeout(()=>{URL.revokeObjectURL(url);a.remove();},1000);\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addPhoto(type){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}${e._src==='camera'&&geoStampEnabled?' · Stamped':''}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31masync function handleCapture(e,type){\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmPhoto(type,i){(type==='front'?frontPhotos:insidePhotos).splice(i,1);renderPhotos(type);saveDraft();}\u001b[39m\n\u001b[31mfunction replacePhoto(type,idx){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m    arr[idx]={...arr[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAddl(){\u001b[39m\n\u001b[31m  const cont=document.getElementById('add-cont');const btn=document.getElementById('add-addl');\u001b[39m\n\u001b[31m  const badge=document.getElementById('addl-badge');if(badge){badge.textContent=`${addlPhotos.length} / 8`;badge.className='cnt-badge '+(addlPhotos.length?'':'gray');}\u001b[39m\n\u001b[31m  cont.innerHTML=addlPhotos.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const sizeInfo=isRetained?'<span style=\\\"color:#475569\\\">Existing</span>':`${fmtSz(p.blob.size)}`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replaceAddl(${i})\\\" style=\\\"top:3px;left:3px;right:auto;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;gap:10px;align-items:start;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--g100)\\\"><div style=\\\"position:relative;flex-shrink:0\\\"><img src=\\\"${p.prev}\\\" style=\\\"width:80px;height:80px;object-fit:cover;border-radius:var(--rs)\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmAddl(${i})\\\" style=\\\"top:3px;right:3px\\\">×</button></div><div style=\\\"flex:1\\\"><input type=\\\"text\\\" placeholder=\\\"Description (optional)\\\" value=\\\"${p.desc||''}\\\" onchange=\\\"addlPhotos[${i}].desc=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"><div style=\\\"font-size:11px;color:var(--g400);margin-top:4px\\\">${sizeInfo}</div></div></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  btn.style.display=addlPhotos.length>=8?'none':'inline-flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction addAdditional(){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  addlPhotos.push({blob:bs,prev:URL.createObjectURL(bs),desc:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderAddl();saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31mfunction rmAddl(i){addlPhotos.splice(i,1);renderAddl();saveDraft();}\u001b[39m\n\u001b[31mfunction replaceAddl(idx){\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m    addlPhotos[idx]={...addlPhotos[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderAddl();saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// BRANDING\u001b[39m\n\u001b[31mfunction calcSqft(w,h){const wf=parseFloat(w),hf=parseFloat(h);if(!wf||!hf)return '';return `${(wf*hf).toFixed(0)} sq.in = ${(wf*hf/144).toFixed(2)} sq.ft`;}\u001b[39m\n\u001b[31mfunction renderBrandings(){\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  const cont=document.getElementById('br-items');\u001b[39m\n\u001b[31m  const hb=document.getElementById('br-hdr-badge');if(hb)hb.textContent=`${brandings.length} ${t(brandings.length!==1?'items':'item',brandings.length!==1?'आइटम':'आइटम')}`;\u001b[39m\n\u001b[31m  cont.innerHTML=brandings.map((b,i)=>`<div class=\\\"bitem\\\"><div class=\\\"bitem-hdr\\\"><div class=\\\"bitem-title\\\">${t('Branding','ब्रांडिंग')} ${i+1}${b.type?' — '+b.type:''}</div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:6px\\\">${i>0?`<button class=\\\"btn-d\\\" onclick=\\\"dupBr(${i})\\\" style=\\\"color:var(--or);border-color:var(--orl)\\\">${t('Dup ↑','डुप ↑')}</button>`:''}<button class=\\\"btn-d\\\" onclick=\\\"rmBr(${i})\\\">${t('Remove','हटाएं')}</button></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\"><label>${t('Type','प्रकार')} <span class=\\\"req\\\">*</span></label><div class=\\\"chip-grid\\\">${BTYPE.map(tp=>`<div class=\\\"chip${b.type===tp?' sel':''}\\\" onclick=\\\"setBType(${i},'${tp.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\"> ${tp}</div>`).join('')}</div></div>\u001b[39m\n\u001b[31m    <div class=\\\"dim-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Width (in)','चौड़ाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.w||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].w=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Height (in)','ऊंचाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.h||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].h=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"max-width:74px\\\"><label>${t('Qty','मात्रा')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.qty||''}\\\" placeholder=\\\"1\\\" inputmode=\\\"numeric\\\" onchange=\\\"brandings[${i}].qty=this.value;saveDraft()\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <span class=\\\"sqft\\\" id=\\\"sf${i}\\\">${calcSqft(b.w,b.h)||t('Enter W × H','W × H दर्ज करें')}</span>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-top:12px\\\"><label>${t('Photo','फोटो')} <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      ${b.prev?`<div class=\\\"pslot filled\\\" onclick=\\\"capBr(${i})\\\"><img src=\\\"${b.prev}\\\"><button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();rmBrPh(${i})\\\">×</button><span class=\\\"pbadge\\\">${b.blob?fmtSz(b.blob.size):'Existing'}</span></div>`:`<div><div class=\\\"pslot\\\" onclick=\\\"capBr(${i})\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\">${t('Tap to capture','दबाकर कैप्चर करें')}</div></div><div style=\\\"display:flex;gap:6px;margin-top:6px\\\"><button class=\\\"atool${(b.quality||imgQuality)==='compressed'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'compressed');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">${t('Compressed','कम्प्रेस्ड')}</button><button class=\\\"atool${(b.quality||imgQuality)==='hd'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'hd');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">HD</button></div></div>`}\u001b[39m\n\u001b[31m    </div></div>`).join('');\u001b[39m\n\u001b[31m  // Only show \\\"Add Another\\\" when last item is fully complete\u001b[39m\n\u001b[31m  const addDiv=document.getElementById('br-add');\u001b[39m\n\u001b[31m  if(addDiv&&brandings.length>0){\u001b[39m\n\u001b[31m    const last=brandings[brandings.length-1];\u001b[39m\n\u001b[31m    const lastComplete=last.type&&last.w&&last.h&&last.qty&&last.prev;\u001b[39m\n\u001b[31m    addDiv.style.display=(lastComplete&&brandings.length<15)?'block':'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updSqft(i){const el=document.getElementById('sf'+i);if(el)el.textContent=calcSqft(brandings[i].w,brandings[i].h)||t('Enter W × H','W × H दर्ज करें');saveDraft();}\u001b[39m\n\u001b[31mfunction setBType(i,tp){brandings[i].type=tp;renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction addBranding(){if(brandings.length>=15){toast(t('Max 15 items','अधिकतम 15 आइटम'),'error');return;}brandings.push({type:'',w:'',h:'',qty:'1',blob:null,prev:null});renderBrandings();}\u001b[39m\n\u001b[31mfunction dupBr(i){if(brandings.length>=10){toast(t('Max 10 items','अधिकतम 10 आइटम'),'error');return;}const s=brandings[i-1];brandings.splice(i,0,{type:s.type,w:s.w,h:s.h,qty:s.qty,blob:null,prev:null});renderBrandings();toast(t('Duplicated — add photo','डुप्लीकेट — फोटो जोड़ें'),'info');}\u001b[39m\n\u001b[31mfunction rmBr(i){brandings.splice(i,1);renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction capBr(i){\u001b[39m\n\u001b[31m  const q=brandings[i]?.quality||imgQuality;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f,q==='hd'?1920:1280,q==='hd'?0.90:0.78));\u001b[39m\n\u001b[31m    brandings[i].blob=bs;brandings[i].prev=URL.createObjectURL(bs);\u001b[39m\n\u001b[31m    brandings[i].fromCamera=(e._src==='camera');\u001b[39m\n\u001b[31m    openAnnot(i);\u001b[39m\n\u001b[31m  },null,q);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmBrPh(i){brandings[i].blob=null;brandings[i].prev=null;renderBrandings();}\u001b[39m\n\u001b[31mfunction setBrQuality(i,q){brandings[i].quality=q;renderBrandings();}·\u001b[39m\n\u001b[31m// VIDEO / DOC\u001b[39m\n\u001b[31mfunction setVideo(v){F.hasVideo=v;document.getElementById('vid-yes').classList.toggle('sel',v);document.getElementById('vid-no').classList.toggle('sel',!v);document.getElementById('vid-sec').style.display=v?'block':'none';saveDraft();}\u001b[39m\n\u001b[31masync function handleVideo(e){videoBlob=e.target.files[0];if(!videoBlob)return;document.getElementById('vid-slot').innerHTML=`<div style=\\\"padding:14px;font-size:13px;color:var(--gn)\\\">✓ ${videoBlob.name} (${fmtSz(videoBlob.size)})</div>`;}\u001b[39m\n\u001b[31mfunction setBranding(v){F.hasBranding=v;document.getElementById('br-yes').classList.toggle('sel',v);document.getElementById('br-no').classList.toggle('sel',!v);document.getElementById('br-add').style.display=v?'block':'none';if(v&&brandings.length===0)addBranding();saveDraft();}\u001b[39m\n\u001b[31masync function handleDoc(e){const f=e.target.files[0];if(!f)return;submissionDoc=f.type.startsWith('image/')?await compress(f,1600,.85):f;const slot=document.getElementById('doc-slot');if(f.type.startsWith('image/')){slot.classList.add('filled');slot.innerHTML=`<img src=\\\"${URL.createObjectURL(submissionDoc)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}else{slot.innerHTML=`<div style=\\\"padding:16px;font-size:13px;color:var(--gn)\\\">✓ ${f.name} (${fmtSz(f.size)})</div>`;}buildReview();}·\u001b[39m\n\u001b[31m// CLIENT CHIPS\u001b[39m\n\u001b[31mfunction renderClientChips(){\u001b[39m\n\u001b[31m  const grid = document.getElementById('client-chips'); if (!grid) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  clientList.forEach(c => {\u001b[39m\n\u001b[31m    const sel = !_clientOtherMode && _selectedClient === c;\u001b[39m\n\u001b[31m    html += `<div class=\\\"cl-chip${sel?' sel':''}\\\" onclick=\\\"selectClientChip('${esc(c)}')\\\">${esc(c)}</div>`;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html += `<div class=\\\"cl-chip cl-chip-other${_clientOtherMode?' sel':''}\\\" onclick=\\\"selectClientOther()\\\"><span class=\\\"en-txt\\\">Other…</span><span class=\\\"hi-txt\\\">अन्य…</span></div>`;\u001b[39m\n\u001b[31m  grid.innerHTML = html;\u001b[39m\n\u001b[31m  document.getElementById('client-other-wrap').style.display = _clientOtherMode ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientChip(name){\u001b[39m\n\u001b[31m  _selectedClient = name; _clientOtherMode = false;\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').value = '';\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientOther(){\u001b[39m\n\u001b[31m  _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onClientOtherInput(){\u001b[39m\n\u001b[31m  _selectedClient = document.getElementById('f-client-other').value.trim();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction getClientName(){\u001b[39m\n\u001b[31m  if (_clientOtherMode) return (document.getElementById('f-client-other')?.value||'').trim();\u001b[39m\n\u001b[31m  return _selectedClient;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction autoSetClient(brandName){\u001b[39m\n\u001b[31m  if (!brandName) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  if (clientList.includes(brandName)){\u001b[39m\n\u001b[31m    _selectedClient = brandName; _clientOtherMode = false;\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    // Not in list — pre-fill the Other field\u001b[39m\n\u001b[31m    _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m    const inp = document.getElementById('f-client-other');\u001b[39m\n\u001b[31m    if (inp && !inp.value) inp.value = brandName;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// STEP VALIDATION\u001b[39m\n\u001b[31mfunction getSD(){if(selectedStore&&!manualMode)return{storeName:selectedStore.name,brand:selectedStore.brand||'',address:selectedStore.address||'',mobile:selectedStore.mobile||''};return{storeName:(document.getElementById('f-store')?.value||'').trim(),brand:document.getElementById('f-brand')?.value||'',address:(document.getElementById('f-addr')?.value||'').trim(),mobile:(document.getElementById('f-mobile')?.value||'').trim()};}\u001b[39m\n\u001b[31mfunction step2(){\u001b[39m\n\u001b[31m  const d=document.getElementById('f-date').value;\u001b[39m\n\u001b[31m  if(!d){toast('Select date','error');return;}\u001b[39m\n\u001b[31m  const sd=getSD();\u001b[39m\n\u001b[31m  if(!sd.storeName){toast('Select or enter store name','error');return;}\u001b[39m\n\u001b[31m  if(!sd.brand){toast('Select a brand','error');document.getElementById('brand-selector').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  if(!sd.address){toast('Enter store address','error');return;}\u001b[39m\n\u001b[31m  const clientName=getClientName();\u001b[39m\n\u001b[31m  if(!clientName){toast(t('Select a client','क्लाइंट चुनें'),'error');document.getElementById('client-chips').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  // Check missing fields filled\u001b[39m\n\u001b[31m  const missAddr=document.getElementById('sc-miss-address');\u001b[39m\n\u001b[31m  if(missAddr&&!missAddr.value.trim()){toast('Enter store address in the highlighted field','error');missAddr.focus();return;}\u001b[39m\n\u001b[31m  const missMob=document.getElementById('sc-miss-mobile');\u001b[39m\n\u001b[31m  // mobile not required — just copy if filled\u001b[39m\n\u001b[31m  if(missMob&&missMob.value.trim()&&!F.mobile)F.mobile=missMob.value.trim();\u001b[39m\n\u001b[31m  Object.assign(F,{date:d,...sd,clientName});saveDraft();\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');showView('form-photos');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction step3(){if(!frontPhotos.length){toast('Add at least 1 front view photo','error');return;}showView('form-video');}\u001b[39m\n\u001b[31mfunction step4(){if(F.hasVideo===undefined||F.hasVideo===null){toast('Select Yes or No for video','error');return;}renderBrandings();showView('form-branding');}\u001b[39m\n\u001b[31mfunction step5(){if(F.hasBranding===undefined||F.hasBranding===null){toast('Select Yes or No for branding space','error');return;}if(F.hasBranding){for(let i=0;i<brandings.length;i++){const b=brandings[i];if(!b.type){toast(`Select branding type for item ${i+1}`,'error');return;}if(!b.w||!b.h){toast(`Enter W and H dimensions for item ${i+1}`,'error');return;}if(!b.qty){toast(`Enter qty for item ${i+1}`,'error');return;}if(!b.blob&&!b.prev){toast(`Add photo for item ${i+1}`,'error');return;}}}renderAddl();buildReview();showView('form-additional');}·\u001b[39m\n\u001b[31m// REVIEW\u001b[39m\n\u001b[31mfunction buildReview(){const el=document.getElementById('rev-body');if(!el)return;const sd=getSD();const cn=getClientName();el.innerHTML=`<div><div class=\\\"rev-lbl\\\">Store</div><div class=\\\"rev-val\\\">${sd.storeName||'—'} · ${sd.brand||'—'}</div><div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">${sd.address||'—'}${sd.mobile?' · '+sd.mobile:''}</div>${gpsCoords?`<div style=\\\"font-size:11px;color:var(--gn);margin-top:3px\\\">📍 ${gpsCoords.lat}, ${gpsCoords.lng} ±${gpsCoords.acc}m</div>`:''}</div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Client</div><div class=\\\"rev-val\\\" style=\\\"color:${cn?'var(--nv)':'var(--rd)'}\\\">${cn||'⚠ Not selected — required'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Photos — Front · Inside · Additional</div><div class=\\\"rev-val\\\">${frontPhotos.length} · ${insidePhotos.length} · ${addlPhotos.length}</div><div class=\\\"rev-photos\\\">${[...frontPhotos,...insidePhotos].slice(0,6).map(p=>`<img class=\\\"rev-thumb\\\" src=\\\"${p.prev}\\\">`).join('')}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Video · Branding items</div><div class=\\\"rev-val\\\">${F.hasVideo?'Yes':'No'} · ${brandings.length} item(s)</div></div>${F.hasBranding&&brandings.length?`<div style=\\\"margin-top:8px\\\">${brandings.map((b,i)=>`<div style=\\\"font-size:12px;color:var(--g600);padding:4px 0;border-bottom:1px solid var(--g100)\\\">${i+1}. ${b.type||'No type'} — ${b.w||'?'}×${b.h||'?'}\\\" × ${b.qty||'?'} — ${calcSqft(b.w,b.h)||'?'}</div>`).join('')}</div>`:''}<div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Additional photos <span style=\\\"font-size:11px;color:var(--g400)\\\">(optional)</span></div><div class=\\\"rev-val\\\" style=\\\"color:${addlPhotos.length?'var(--gn)':'var(--g500)'}\\\">${addlPhotos.length?`✓ ${addlPhotos.length} photo(s) added`:'None added'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Mandatory document</div><div class=\\\"rev-val\\\" style=\\\"color:${(submissionDoc||_docExistingUrl)?'var(--gn)':'var(--rd)'}\\\">${(submissionDoc||_docExistingUrl)?'✓ Uploaded':'⚠ Missing — required'}</div></div>`;}·\u001b[39m\n\u001b[31m// SUBMIT\u001b[39m\n\u001b[31masync function submitRecce(){\u001b[39m\n\u001b[31m  if(!submissionDoc&&!_docExistingUrl){toast('Upload mandatory doc first','error');return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('sub-btn');btn.disabled=true;btn.textContent='Saving…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const isEdit=!!(F.editingId);\u001b[39m\n\u001b[31m    const id=isEdit?F.editingId:('RC_'+Date.now()+'_'+Math.random().toString(36).slice(2,6).toUpperCase());\u001b[39m\n\u001b[31m    const sd=getSD();\u001b[39m\n\u001b[31m    const _hub=_recceHubUser();\u001b[39m\n\u001b[31m    const entry={id,timestamp:isEdit?(await dbGet('subs',id))?.timestamp||new Date().toISOString():new Date().toISOString(),editedAt:isEdit?new Date().toISOString():undefined,status:'pending',submittedBy:_hub.empId||null,submittedByName:_hub.name||null,data:{...F,...sd,gpsCoords,frontPhotos:await Promise.all(frontPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),insidePhotos:await Promise.all(insidePhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),videoNote:F.hasVideo&&videoBlob?`Video local (${fmtSz(videoBlob.size)}) — share via WhatsApp`:null,videoCmt:document.getElementById('f-vid-cmt')?.value||'',brandings:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:calcSqft(b.w,b.h),photoB64:b.blob?await b64(b.blob):null,existingUrl:b.existingUrl||null}))),addlPhotos:await Promise.all(addlPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,desc:p.desc,existingUrl:p.existingUrl||null}))),docB64:submissionDoc?await b64(submissionDoc):null,_docExistingUrl:_docExistingUrl||null}};\u001b[39m\n\u001b[31m    entry.campaignId       = _selectedCampaignId || null;\u001b[39m\n\u001b[31m    entry.notifySupervisor = _notifySupervisor   || false;\u001b[39m\n\u001b[31m    await dbPut('subs',entry);\u001b[39m\n\u001b[31m    await dbDel('draft','current');\u001b[39m\n\u001b[31m    toast(isEdit?'Recce updated ✓':'Recce saved ✓','success');\u001b[39m\n\u001b[31m    if(navigator.onLine)syncNow();\u001b[39m\n\u001b[31m    showView('home');loadHome();checkDraft();\u001b[39m\n\u001b[31m  }catch(err){toast('Error: '+err.message,'error');}\u001b[39m\n\u001b[31m  finally{btn.disabled=false;btn.textContent='Submit Recce ✓';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// SYNC\u001b[39m\n\u001b[31masync function syncNow() {\u001b[39m\n\u001b[31m  if (!navigator.onLine) { toast('Offline — sync when back online', 'info'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('sync-btn');\u001b[39m\n\u001b[31m  const SYNC_ICON = '<svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg>Sync';\u001b[39m\n\u001b[31m  if (btn) { btn.innerHTML = '<span class=\\\"spin\\\">↻</span> Syncing'; btn.disabled = true; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const all      = await dbAll('subs');\u001b[39m\n\u001b[31m    const pend     = all.filter(s => s.status === 'pending' || s.status === 'failed');\u001b[39m\n\u001b[31m    const backfill = all.filter(s => s.status === 'synced' && !s.gasAt);\u001b[39m\n\u001b[31m    if (!pend.length && !backfill.length) { toast('All synced ✓', 'success'); return; }·\u001b[39m\n\u001b[31m    const gasUrl = (await cfg('gas-url')) || DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    function fireGas(s) {\u001b[39m\n\u001b[31m      if (!gasUrl) return;\u001b[39m\n\u001b[31m      fetch(gasUrl, { method:'POST', mode:'no-cors',\u001b[39m\n\u001b[31m        body: JSON.stringify({ action:'syncSheet', submission: s }) })\u001b[39m\n\u001b[31m        .catch(() => {});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    let ok = 0;\u001b[39m\n\u001b[31m    for (const s of pend) {\u001b[39m\n\u001b[31m      // Fire Sheet sync (no-cors fire-and-forget — writes row to Google Sheet)\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      // Primary: upload photos → auto-trigger slides → generate report → store in PostgreSQL\u001b[39m\n\u001b[31m      const { ok: pgOk, viewUrl } = await syncToPostgres(s);\u001b[39m\n\u001b[31m      if (pgOk) {\u001b[39m\n\u001b[31m        s.status = 'synced'; s.syncedAt = new Date().toISOString();\u001b[39m\n\u001b[31m        if (viewUrl) s.viewUrl = viewUrl;\u001b[39m\n\u001b[31m        await dbPut('subs', s); ok++;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        s.status = 'failed'; await dbPut('subs', s);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Backfill: entries synced to Postgres but never reached Sheet GAS\u001b[39m\n\u001b[31m    for (const s of backfill) {\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      await dbPut('subs', s);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if (backfill.length) toast(`Sent ${backfill.length} older entries to Sheet`, 'info');·\u001b[39m\n\u001b[31m    await cfg('last-sync', new Date().toISOString());\u001b[39m\n\u001b[31m    if (pend.length) toast(`Synced ${ok}/${pend.length}`, ok === pend.length ? 'success' : 'error');\u001b[39m\n\u001b[31m    loadHome();\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.innerHTML = SYNC_ICON; btn.disabled = false; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN HOME ──────────────────────────────────────────────\u001b[39m\n\u001b[31masync function loadHomeAdmin() {\u001b[39m\n\u001b[31m  // Adapt UI for admin view\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const _sh = document.querySelector('.sh'); if (_sh) _sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = 'All Submissions';\u001b[39m\n\u001b[31m  const slbls = document.querySelectorAll('.slbl');\u001b[39m\n\u001b[31m  if (slbls[0]) slbls[0].textContent = 'Showing';\u001b[39m\n\u001b[31m  if (slbls[1]) slbls[1].textContent = 'Agents';·\u001b[39m\n\u001b[31m  // Back-to-menu button for supervisors\u001b[39m\n\u001b[31m  if (_isSupervisor() && !document.getElementById('sup-back-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => { document.getElementById('sup-back-btn').remove(); renderSupLanding(); };\u001b[39m\n\u001b[31m    const content = document.querySelector('#view-home .content');\u001b[39m\n\u001b[31m    content.prepend(bb);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Show filter bar — restore if hidden by renderSupLanding, else inject fresh\u001b[39m\n\u001b[31m  const _existingFb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (_existingFb) { _existingFb.style.display = ''; }\u001b[39m\n\u001b[31m  if (!_existingFb) {\u001b[39m\n\u001b[31m    const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m    const fb = document.createElement('div');\u001b[39m\n\u001b[31m    fb.id = 'admin-filter-bar';\u001b[39m\n\u001b[31m    fb.className = 'af-bar';\u001b[39m\n\u001b[31m    fb.innerHTML =\u001b[39m\n\u001b[31m      `<div class=\\\"af-grid\\\">\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-agent\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Agents</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-brand\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Brands</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-client\\\" onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Clients</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-period\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">All Time</option>\u001b[39m\n\u001b[31m          <option value=\\\"7\\\">Last 7 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"30\\\">Last 30 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"90\\\">Last 3 months</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-group\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"date\\\">Sort: Recent</option>\u001b[39m\n\u001b[31m          <option value=\\\"agent\\\">Group: Agent</option>\u001b[39m\n\u001b[31m          <option value=\\\"brand\\\">Group: Brand</option>\u001b[39m\n\u001b[31m          <option value=\\\"client\\\">Group: Client</option>\u001b[39m\n\u001b[31m          <option value=\\\"city\\\">Group: City</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m        <input class=\\\"af-inp\\\" id=\\\"af-search\\\" type=\\\"text\\\" placeholder=\\\"🔍 Search store or city…\\\" oninput=\\\"renderAdminList()\\\" style=\\\"flex:1;min-width:120px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"del-toggle-btn\\\" id=\\\"del-toggle-btn\\\" onclick=\\\"toggleDeletedView()\\\" style=\\\"flex-shrink:0\\\">📋 View Deleted</button>\u001b[39m\n\u001b[31m        ${_isSupervisor() ? `<button class=\\\"del-toggle-btn\\\" id=\\\"pending-job-btn\\\" onclick=\\\"togglePendingJobView()\\\" style=\\\"flex-shrink:0;background:#fef3c7;color:#92400e;border-color:#f59e0b\\\">⚑ Unlinked <span id=\\\"pending-job-count\\\" style=\\\"font-weight:900\\\"></span></button>` : ''}\u001b[39m\n\u001b[31m        ${_adminUnlocked ? `<button class=\\\"del-toggle-btn\\\" id=\\\"regen-rpt-btn\\\" onclick=\\\"regenAllReports()\\\" style=\\\"flex-shrink:0\\\">&#x21BB; Regen Reports</button>` : ''}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    sh.parentNode.insertBefore(fb, sh);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Fetch\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  list.innerHTML = '<div style=\\\"text-align:center;padding:40px\\\"><div class=\\\"spinner\\\"></div></div>';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?order=submitted_at.desc&limit=500`, { headers: _RC_READ });\u001b[39m\n\u001b[31m    _adminRows = resp.ok ? await resp.json() : [];\u001b[39m\n\u001b[31m    document.getElementById('stat-total').textContent = _adminRows.length;\u001b[39m\n\u001b[31m    if (resp.ok) {\u001b[39m\n\u001b[31m      const now = new Date();\u001b[39m\n\u001b[31m      document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m        'Loaded ' + now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Populate agent dropdown\u001b[39m\n\u001b[31m    const agents = [...new Set(_adminRows.map(r => r.submitted_by).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-agent').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Agents (${agents.length})</option>` +\u001b[39m\n\u001b[31m      agents.map(a => `<option value=\\\"${a}\\\">${a}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate brand dropdown\u001b[39m\n\u001b[31m    const brands = [...new Set(_adminRows.map(r => r.brand).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-brand').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Brands (${brands.length})</option>` +\u001b[39m\n\u001b[31m      brands.map(b => `<option value=\\\"${b}\\\">${b}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate client dropdown\u001b[39m\n\u001b[31m    const clients = [...new Set(_adminRows.map(r => r.client_name).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-client').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Clients (${clients.length})</option>` +\u001b[39m\n\u001b[31m      clients.map(c => `<option value=\\\"${c}\\\">${c}</option>`).join('');·\u001b[39m\n\u001b[31m    // Update pending-job count badge\u001b[39m\n\u001b[31m    const unlinkedCount = _adminRows.filter(r => !r.deleted_at && !r.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinkedCount ? `(${unlinkedCount})` : '';·\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">⚠️</div><div class=\\\"empty-txt\\\">Could not load — check connection</div></div>';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction togglePendingJobView() {\u001b[39m\n\u001b[31m  _pendingJobFilter = !_pendingJobFilter;\u001b[39m\n\u001b[31m  _showDeletedView  = false;\u001b[39m\n\u001b[31m  const btn = document.getElementById('pending-job-btn');\u001b[39m\n\u001b[31m  if (btn) btn.style.background = _pendingJobFilter ? '#f59e0b' : '#fef3c7';\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function openLinkJobModal(subId, storeName) {\u001b[39m\n\u001b[31m  _linkJobSubId = subId;\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  const storeEl = document.getElementById('link-job-store');\u001b[39m\n\u001b[31m  const sel = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  if (!modal) return;\u001b[39m\n\u001b[31m  if (storeEl) storeEl.textContent = storeName || subId;\u001b[39m\n\u001b[31m  if (errEl) errEl.textContent = '';\u001b[39m\n\u001b[31m  // Load campaigns into dropdown\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (!_campaignList.length) {\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m      _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  if (sel) {\u001b[39m\n\u001b[31m    sel.innerHTML = '<option value=\\\"\\\">— Select campaign —</option>' +\u001b[39m\n\u001b[31m      _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  modal.style.display = 'flex';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeLinkJobModal() {\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  if (modal) modal.style.display = 'none';\u001b[39m\n\u001b[31m  _linkJobSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function saveLinkJob() {\u001b[39m\n\u001b[31m  const sel    = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl  = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  const campId = sel?.value || '';\u001b[39m\n\u001b[31m  if (!campId) { if (errEl) errEl.textContent = 'Select a campaign'; return; }\u001b[39m\n\u001b[31m  if (!_linkJobSubId) return;\u001b[39m\n\u001b[31m  const btn = document.querySelector('#modal-link-job button[onclick=\\\"saveLinkJob()\\\"]');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Linking…'; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(_linkJobSubId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ campaign_id: campId }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Patch failed');\u001b[39m\n\u001b[31m    // Update local cache\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === _linkJobSubId);\u001b[39m\n\u001b[31m    if (idx >= 0) _adminRows[idx].campaign_id = campId;\u001b[39m\n\u001b[31m    // Update pending count badge\u001b[39m\n\u001b[31m    const unlinked = _adminRows.filter(x => !x.deleted_at && !x.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinked ? `(${unlinked})` : '';\u001b[39m\n\u001b[31m    closeLinkJobModal();\u001b[39m\n\u001b[31m    toast('Job linked ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    if (errEl) errEl.textContent = 'Failed to link — try again';\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.disabled = false; btn.textContent = '🔗 Link Job'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAdminList() {\u001b[39m\n\u001b[31m  const agent  = document.getElementById('af-agent')?.value  || '';\u001b[39m\n\u001b[31m  const brand  = document.getElementById('af-brand')?.value  || '';\u001b[39m\n\u001b[31m  const period = document.getElementById('af-period')?.value || '';\u001b[39m\n\u001b[31m  const search = (document.getElementById('af-search')?.value || '').toLowerCase().trim();\u001b[39m\n\u001b[31m  const group  = document.getElementById('af-group')?.value  || 'date';·\u001b[39m\n\u001b[31m  // Pending-job filter overrides deleted/normal modes\u001b[39m\n\u001b[31m  let rows;\u001b[39m\n\u001b[31m  if (_pendingJobFilter) {\u001b[39m\n\u001b[31m    rows = _adminRows.filter(r => !r.deleted_at && !r.campaign_id);\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows = _showDeletedView\u001b[39m\n\u001b[31m      ? _adminRows.filter(r => r.deleted_at)\u001b[39m\n\u001b[31m      : _adminRows.filter(r => !r.deleted_at);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const client = document.getElementById('af-client')?.value || '';\u001b[39m\n\u001b[31m  if (agent)  rows = rows.filter(r => r.submitted_by === agent);\u001b[39m\n\u001b[31m  if (brand)  rows = rows.filter(r => r.brand === brand);\u001b[39m\n\u001b[31m  if (client) rows = rows.filter(r => r.client_name === client);\u001b[39m\n\u001b[31m  if (search) rows = rows.filter(r => (r.store_name||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.city||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.client_name||'').toLowerCase().includes(search));\u001b[39m\n\u001b[31m  if (period && !_showDeletedView) {\u001b[39m\n\u001b[31m    const cut = new Date(); cut.setDate(cut.getDate() - parseInt(period));\u001b[39m\n\u001b[31m    rows = rows.filter(r => new Date(r.submitted_at) >= cut);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const uniqueAgents = new Set(rows.map(r => r.submitted_by).filter(Boolean)).size;\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = rows.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = uniqueAgents;\u001b[39m\n\u001b[31m  const deletedCount = _adminRows.filter(r => r.deleted_at).length;\u001b[39m\n\u001b[31m  const delBtn = document.getElementById('del-toggle-btn');\u001b[39m\n\u001b[31m  if (delBtn) {\u001b[39m\n\u001b[31m    if (_showDeletedView) {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 Hide Deleted (${deletedCount})` : '📋 Hide Deleted';\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 View Deleted (${deletedCount})` : '📋 View Deleted';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    delBtn.classList.toggle('active', _showDeletedView);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!rows.length) {\u001b[39m\n\u001b[31m    list.innerHTML = _showDeletedView\u001b[39m\n\u001b[31m      ? '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">✅</div><div class=\\\"empty-txt\\\">No deleted recces</div></div>'\u001b[39m\n\u001b[31m      : '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">🔍</div><div class=\\\"empty-txt\\\">No matching submissions</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (group === 'agent') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.submitted_by||'').localeCompare(b.submitted_by||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.submitted_by || 'Unknown';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">👤 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'brand') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.brand||'').localeCompare(b.brand||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.brand || 'No Brand';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🏷 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'client') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.client_name||'').localeCompare(b.client_name||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.client_name || 'No Client';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🤝 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'city') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.city||'').localeCompare(b.city||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.city || 'No City';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">📍 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows.sort((a,b) => new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    rows.forEach(r => { html += adminCard(r); });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminCard(r) {\u001b[39m\n\u001b[31m  const dt    = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds    = dt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m  const tm    = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const photos = (r.front_photos||0) + (r.inside_photos||0) + (r.addl_photos||0);\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const canDelete  = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const canArchive = _RECCE_CFG_ADMINS.includes(hub?.empId) && !r.client_archived;·\u001b[39m\n\u001b[31m  // Client status badge\u001b[39m\n\u001b[31m  const clientStatusMap = {\u001b[39m\n\u001b[31m    approved:              {t:'✓ Approved',    s:'color:#166534;background:#dcfce7;border:1px solid #86efac'},\u001b[39m\n\u001b[31m    rejected:              {t:'✕ Rejected',    s:'color:#991b1b;background:#fee2e2;border:1px solid #fca5a5'},\u001b[39m\n\u001b[31m    approved_with_changes: {t:'✎ Approved w/ Comments', s:'color:#92400e;background:#fef3c7;border:1px solid #fcd34d'},\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const csCfg = clientStatusMap[r.client_status];\u001b[39m\n\u001b[31m  const clientStatusBadge = csCfg\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;${csCfg.s}\\\">${csCfg.t}</span>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const archiveBadge = r.client_archived\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;color:#475569;background:#f1f5f9;border:1px solid #cbd5e1\\\">⬚ Client hidden</span>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  if (r.deleted_at) {\u001b[39m\n\u001b[31m    const delDt = new Date(r.deleted_at);\u001b[39m\n\u001b[31m    const delDs = delDt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m    const reasonLabel = r.deletion_reason === 'wrong' ? 'Wrong' : r.deletion_reason === 'duplicate' ? 'Duplicate' : 'Test';\u001b[39m\n\u001b[31m    return `<div class=\\\"asc deleted-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m        <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m            <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds}</span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m          <span class=\\\"del-reason-tag\\\">❌ ${reasonLabel}</span>\u001b[39m\n\u001b[31m          <div class=\\\"del-by-txt\\\">by ${r.deleted_by||'?'} · ${delDs}</div>\u001b[39m\n\u001b[31m          ${canDelete ? `<button class=\\\"restore-btn\\\" onclick=\\\"event.stopPropagation();restoreRecce('${r.sub_id}')\\\">↩ Restore</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Submitted by ${r.submitted_by||'?'}</div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const chips = [\u001b[39m\n\u001b[31m    photos > 0   ? `📷 ${photos} photo${photos!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.has_video  ? '🎥 Video' : null,\u001b[39m\n\u001b[31m    r.has_branding ? `🪧 ${r.branding_count} branding${r.branding_count!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.city       ? `📍 ${r.city}` : (r.address ? `📍 ${r.address}` : null),\u001b[39m\n\u001b[31m    r.view_url   ? '👁 View available' : null,\u001b[39m\n\u001b[31m  ].filter(Boolean);·\u001b[39m\n\u001b[31m  const delBtnHtml = canDelete\u001b[39m\n\u001b[31m    ? `<button class=\\\"del-btn\\\" onclick=\\\"event.stopPropagation();openDeleteModal('${r.sub_id}')\\\" title=\\\"Delete recce\\\">🗑</button>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const editReqHtml = r.edit_assigned_to\u001b[39m\n\u001b[31m    ? `<span class=\\\"edit-req-badge\\\">✏ Edit sent to ${r.edit_assigned_to}</span>`\u001b[39m\n\u001b[31m    : (_isSupervisor()\u001b[39m\n\u001b[31m        ? `<button class=\\\"req-edit-btn\\\" onclick=\\\"event.stopPropagation();openEditRequestModal('${r.sub_id}')\\\">✏ Request Edit</button>`\u001b[39m\n\u001b[31m        : '');·\u001b[39m\n\u001b[31m  const editRow = editReqHtml\u001b[39m\n\u001b[31m    ? `<div style=\\\"margin-top:6px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">${editReqHtml}</div>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const showPdfBtn = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m  const pdfClass = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m  const pdfLabel = '📄 PDF';\u001b[39m\n\u001b[31m  const linkJobBtn = (_pendingJobFilter && _isSupervisor() && !r.campaign_id)\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:#f59e0b;color:#000;border-color:#f59e0b;font-weight:700\\\" onclick=\\\"event.stopPropagation();openLinkJobModal('${r.sub_id}','${(r.store_name||'Unknown').replace(/'/g,'\\\\\\\\\\\\'')}')\\\">🔗 Link Job</button>`\u001b[39m\n\u001b[31m    : (r.campaign_id ? `<span style=\\\"font-size:10px;color:var(--g400);align-self:center\\\">🔗 ${r.campaign_id}</span>` : '');\u001b[39m\n\u001b[31m  const archiveBtn = canArchive\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:rgba(99,102,241,.08);border-color:var(--nv);color:var(--nv)\\\" onclick=\\\"event.stopPropagation();archiveRecce('${r.sub_id}')\\\">⛚ Archive</button>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const btnsRow = `<div class=\\\"rpt-btns\\\">\u001b[39m\n\u001b[31m    <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openAdminRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m    ${showPdfBtn ? `<button class=\\\"${pdfClass}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">${pdfLabel}</button>` : ''}\u001b[39m\n\u001b[31m    ${linkJobBtn}\u001b[39m\n\u001b[31m    ${archiveBtn}\u001b[39m\n\u001b[31m  </div>`;·\u001b[39m\n\u001b[31m  return `<div class=\\\"asc\\\">\u001b[39m\n\u001b[31m    <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m      <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m          ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          ${r.client_name&&r.client_name!==r.brand?`<span class=\\\"client-tag\\\">🤝 ${r.client_name}</span>`:''}\u001b[39m\n\u001b[31m          <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds} · ${tm}</span>\u001b[39m\n\u001b[31m          ${clientStatusBadge}\u001b[39m\n\u001b[31m          ${archiveBadge}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <span class=\\\"asc-agent\\\">👤 ${r.submitted_by||'?'}</span>\u001b[39m\n\u001b[31m        ${delBtnHtml}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    ${chips.length?`<div class=\\\"asc-chips\\\">${chips.map(c=>`<span class=\\\"asc-chip\\\">${c}</span>`).join('')}</div>`:''}\u001b[39m\n\u001b[31m    ${editRow}\u001b[39m\n\u001b[31m    ${btnsRow}\u001b[39m\n\u001b[31m  </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _ensurePdfOverlay() {\u001b[39m\n\u001b[31m  if (document.getElementById('pdf-wait-ov')) return;\u001b[39m\n\u001b[31m  const ov = document.createElement('div');\u001b[39m\n\u001b[31m  ov.id = 'pdf-wait-ov';\u001b[39m\n\u001b[31m  ov.innerHTML = '<div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Generating PDF…</div><div class=\\\"po-sub\\\" id=\\\"pw-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"pw-pfill\\\"></div></div>';\u001b[39m\n\u001b[31m  document.body.appendChild(ov);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _showPdfOverlay(msg) {\u001b[39m\n\u001b[31m  _ensurePdfOverlay();\u001b[39m\n\u001b[31m  document.getElementById('pw-sub').textContent = msg || '';\u001b[39m\n\u001b[31m  document.getElementById('pw-pfill').style.width = '0%';\u001b[39m\n\u001b[31m  document.getElementById('pdf-wait-ov').style.display = 'flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _hidePdfOverlay() {\u001b[39m\n\u001b[31m  const ov = document.getElementById('pdf-wait-ov');\u001b[39m\n\u001b[31m  if (ov) ov.style.display = 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function openPdf(subId, pdfUrl, viewUrl) {\u001b[39m\n\u001b[31m  if (pdfUrl) { window.open(pdfUrl, '_blank'); return; }\u001b[39m\n\u001b[31m  if (!viewUrl) {\u001b[39m\n\u001b[31m    toast('Report view not available yet — please try after the report is generated.', 'info');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _showPdfOverlay('Requesting PDF generation…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type': 'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({type: 'regen-pdf', subId, viewUrl})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  let attempts = 0;\u001b[39m\n\u001b[31m  const MAX = 24;\u001b[39m\n\u001b[31m  const poll = async () => {\u001b[39m\n\u001b[31m    attempts++;\u001b[39m\n\u001b[31m    const pct = Math.min(88, Math.round(attempts / MAX * 88));\u001b[39m\n\u001b[31m    document.getElementById('pw-pfill').style.width = pct + '%';\u001b[39m\n\u001b[31m    const left = Math.ceil((MAX - attempts) * 5);\u001b[39m\n\u001b[31m    document.getElementById('pw-sub').textContent = 'Checking… (' + left + 's remaining)';\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const res = await fetch('/db/submissions?sub_id=eq.' + subId + '&select=pdf_url', {\u001b[39m\n\u001b[31m        headers: {'Content-Profile': 'recce', 'Accept-Profile': 'recce'}\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      const rows = await res.json();\u001b[39m\n\u001b[31m      if (rows && rows[0] && rows[0].pdf_url) {\u001b[39m\n\u001b[31m        document.getElementById('pw-pfill').style.width = '100%';\u001b[39m\n\u001b[31m        setTimeout(() => { _hidePdfOverlay(); window.open(rows[0].pdf_url, '_blank'); }, 400);\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(_) {}\u001b[39m\n\u001b[31m    if (attempts >= MAX) { _hidePdfOverlay(); toast('PDF generation timed out. Please try again later.', 'error'); return; }\u001b[39m\n\u001b[31m    setTimeout(poll, 5000);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  setTimeout(poll, 4000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openAdminRecce(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];·\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">\u001b[39m\n\u001b[31m         📍 View on Google Maps (${Number(r.gps_lat).toFixed(4)}, ${Number(r.gps_lng).toFixed(4)})\u001b[39m\n\u001b[31m       </a>` : '';·\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} ft × ${b.h||'?'} ft · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos not yet available — field agent must re-sync from their device to upload view\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Submission Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">👤 ${r.submitted_by||'Unknown'}</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            ${meta.videoCmt?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500);font-size:12px\\\">${meta.videoCmt}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m          ${(()=>{\u001b[39m\n\u001b[31m            const hub2 = _recceHubUser();\u001b[39m\n\u001b[31m            const isHP = _RECCE_CFG_ADMINS.includes(hub2?.empId);\u001b[39m\n\u001b[31m            const csMap = {\u001b[39m\n\u001b[31m              approved:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#166534;background:#dcfce7\\\">✓ Approved</span>',\u001b[39m\n\u001b[31m              rejected:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#991b1b;background:#fee2e2\\\">✕ Rejected</span>',\u001b[39m\n\u001b[31m              approved_with_changes: '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#92400e;background:#fef3c7\\\">✎ Approved w/ Comments</span>',\u001b[39m\n\u001b[31m            };\u001b[39m\n\u001b[31m            const csBadge = csMap[r.client_status] || '';\u001b[39m\n\u001b[31m            const approvedAt = r.client_approved_at\u001b[39m\n\u001b[31m              ? new Date(r.client_approved_at).toLocaleString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit',timeZone:'Asia/Kolkata'})\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const pdfLink = r.client_approval_pdf_url\u001b[39m\n\u001b[31m              ? `<a href=\\\"${r.client_approval_pdf_url}\\\" target=\\\"_blank\\\" style=\\\"font-size:12px;color:var(--or);text-decoration:none\\\">⬇ Approval PDF</a>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const archAct = isHP && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveRecce('${r.sub_id}')\\\" style=\\\"font-size:12px;color:var(--nv);background:none;border:1px solid var(--nv);border-radius:6px;padding:4px 10px;cursor:pointer\\\">⦽ Archive from client</button>`\u001b[39m\n\u001b[31m              : (r.client_archived ? '<span style=\\\"font-size:11px;color:var(--g400)\\\">⦽ Hidden from client</span>' : '');\u001b[39m\n\u001b[31m            const campAct = isHP && r.campaign_id && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveAllForCampaign('${r.campaign_id}')\\\" style=\\\"font-size:11px;color:#991b1b;background:none;border:1px solid #fca5a5;border-radius:6px;padding:3px 8px;cursor:pointer\\\">Archive ALL for ${r.campaign_id}</button>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            if (!csBadge && !pdfLink && !archAct) return '';\u001b[39m\n\u001b[31m            return `<div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m              <div class=\\\"ardl-lbl\\\">Client Approval</div>\u001b[39m\n\u001b[31m              ${csBadge ? `<div style=\\\"margin-bottom:5px\\\">${csBadge}${approvedAt ? ' <span style=\\\"font-size:11px;color:var(--g400)\\\">' + approvedAt + '</span>' : ''}</div>` : ''}\u001b[39m\n\u001b[31m              ${r.client_comment ? `<div style=\\\"font-size:12px;color:var(--g600);background:var(--g50);border-radius:6px;padding:7px 10px;margin-bottom:5px\\\">\\\"${r.client_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m              ${pdfLink ? `<div style=\\\"margin-bottom:4px\\\">${pdfLink}</div>` : ''}\u001b[39m\n\u001b[31m              ${archAct ? `<div style=\\\"margin-bottom:4px\\\">${archAct}</div>` : ''}\u001b[39m\n\u001b[31m              ${campAct ? `<div>${campAct}</div>` : ''}\u001b[39m\n\u001b[31m            </div>`;\u001b[39m\n\u001b[31m          })()}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeAdminDetail() {\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveRecce(subId) {\u001b[39m\n\u001b[31m  if (!confirm('Archive this recce from client view? The client will no longer see it.')) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(subId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) Object.assign(_adminRows[idx], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    toast('Archived from client view ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveAllForCampaign(campaignId) {\u001b[39m\n\u001b[31m  if (!confirm(`Archive ALL recces for campaign \\\"${campaignId}\\\" from client view?\\\\nClients will no longer see any recce from this campaign.`)) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?campaign_id=eq.${encodeURIComponent(campaignId)}&client_archived=eq.false`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    _adminRows.forEach((row, i) => {\u001b[39m\n\u001b[31m      if (row.campaign_id === campaignId) Object.assign(_adminRows[i], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    toast(`All recces for ${campaignId} archived ✓`, 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function regenAllReports() {\u001b[39m\n\u001b[31m  if (!_adminUnlocked) { toast('Admin access required', 'error'); return; }\u001b[39m\n\u001b[31m  const rows = _adminRows.filter(r => !r.deleted_at && r.photo_urls);\u001b[39m\n\u001b[31m  if (!rows.length) { toast('No synced rows with photos found', 'error'); return; }·\u001b[39m\n\u001b[31m  const btn = document.getElementById('regen-rpt-btn');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Regenerating…'; }\u001b[39m\n\u001b[31m  toast(`Regenerating ${rows.length} reports…`, 'info');·\u001b[39m\n\u001b[31m  let done = 0, failed = 0;\u001b[39m\n\u001b[31m  for (const r of rows) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const photoUrls = typeof r.photo_urls === 'string' ? JSON.parse(r.photo_urls) : (r.photo_urls || {});\u001b[39m\n\u001b[31m      let meta = {};\u001b[39m\n\u001b[31m      try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m      const entry = {\u001b[39m\n\u001b[31m        id: r.sub_id,\u001b[39m\n\u001b[31m        timestamp: r.submitted_at,\u001b[39m\n\u001b[31m        submittedBy: r.submitted_by,\u001b[39m\n\u001b[31m        data: {\u001b[39m\n\u001b[31m          storeName:    r.store_name,\u001b[39m\n\u001b[31m          brand:        r.brand,\u001b[39m\n\u001b[31m          clientName:   r.client_name,\u001b[39m\n\u001b[31m          date:         r.visit_date,\u001b[39m\n\u001b[31m          address:      r.address,\u001b[39m\n\u001b[31m          city:         r.city,\u001b[39m\n\u001b[31m          mobile:       r.mobile,\u001b[39m\n\u001b[31m          gpsCoords:    (r.gps_lat && r.gps_lng) ? { lat: r.gps_lat, lng: r.gps_lng } : null,\u001b[39m\n\u001b[31m          hasVideo:     r.has_video,\u001b[39m\n\u001b[31m          videoNote:    meta.videoNote || '',\u001b[39m\n\u001b[31m          videoCmt:     meta.videoCmt  || '',\u001b[39m\n\u001b[31m          frontPhotos:  (photoUrls.front   || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          insidePhotos: (photoUrls.inside  || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          addlPhotos:   (photoUrls.addl    || []).map(() => ({ desc: '' })),\u001b[39m\n\u001b[31m          brandings:    (meta.brandings    || []),\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      };·\u001b[39m\n\u001b[31m      const html = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m      const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m        method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m        body: JSON.stringify({ type: 'save-view', subId: r.sub_id, html })\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!vResp.ok) { failed++; continue; }\u001b[39m\n\u001b[31m      const vr = await vResp.json();\u001b[39m\n\u001b[31m      if (!vr.success) { failed++; continue; }·\u001b[39m\n\u001b[31m      if (vr.url && vr.url !== r.view_url) {\u001b[39m\n\u001b[31m        await fetch(`${_RC_BASE}/submissions?sub_id=eq.${r.sub_id}`, {\u001b[39m\n\u001b[31m          method: 'PATCH', headers: _RC_WRITE,\u001b[39m\n\u001b[31m          body: JSON.stringify({ view_url: vr.url })\u001b[39m\n\u001b[31m        });\u001b[39m\n\u001b[31m        const idx = _adminRows.findIndex(x => x.sub_id === r.sub_id);\u001b[39m\n\u001b[31m        if (idx >= 0) _adminRows[idx].view_url = vr.url;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      done++;\u001b[39m\n\u001b[31m    } catch(e) { failed++; }\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = false; btn.textContent = '↻ Regen Reports'; }\u001b[39m\n\u001b[31m  toast(`Done: ${done} regenerated${failed ? `, ${failed} failed` : ''}`, done > 0 ? 'success' : 'error');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction toggleDeletedView() {\u001b[39m\n\u001b[31m  _showDeletedView = !_showDeletedView;\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openDeleteModal(subId) {\u001b[39m\n\u001b[31m  _pendingDeleteId = subId;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  const sub = document.getElementById('del-modal-sub');\u001b[39m\n\u001b[31m  if (sub) sub.textContent = r ? `Delete: \\\"${r.store_name||'Unknown'}\\\"` : 'Select reason for deletion:';\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectDeleteReason(reason) {\u001b[39m\n\u001b[31m  _pendingDeleteReason = reason;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  document.getElementById('reason-' + reason)?.classList.add('sel');\u001b[39m\n\u001b[31m  document.getElementById('del-confirm-btn').classList.remove('no-reason');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeDeleteModal() {\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingDeleteId = null;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  clearTimeout(_tt);\u001b[39m\n\u001b[31m  document.getElementById('toast').classList.remove('show');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function restoreRecce(subId) {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({ deleted_at: null, deleted_by: null, deletion_reason: null }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Restore failed: ' + r.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_at = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_by = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deletion_reason = null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    toast('Recce restored ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Restore failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmDelete() {\u001b[39m\n\u001b[31m  if (!_pendingDeleteReason) {\u001b[39m\n\u001b[31m    const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m    btn.style.animation = 'none';\u001b[39m\n\u001b[31m    btn.offsetHeight; // reflow\u001b[39m\n\u001b[31m    btn.style.animation = 'shake .35s ease';\u001b[39m\n\u001b[31m    toast('Select a reason first', 'error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if (!_pendingDeleteId) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Deleting…';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      // Hard delete — no audit trail\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'DELETE',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Delete failed: ' + r.status);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Soft delete — stamp deleted_at, deleted_by, deletion_reason\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'PATCH',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m        body: JSON.stringify({\u001b[39m\n\u001b[31m          deleted_at: new Date().toISOString(),\u001b[39m\n\u001b[31m          deleted_by: hub.empId,\u001b[39m\n\u001b[31m          deletion_reason: _pendingDeleteReason,\u001b[39m\n\u001b[31m        }),\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Update failed: ' + r.status);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Remove or update in local cache\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      _adminRows = _adminRows.filter(x => x.sub_id !== _pendingDeleteId);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      const idx = _adminRows.findIndex(x => x.sub_id === _pendingDeleteId);\u001b[39m\n\u001b[31m      if (idx >= 0) {\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_at = new Date().toISOString();\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_by = hub.empId;\u001b[39m\n\u001b[31m        _adminRows[idx].deletion_reason = _pendingDeleteReason;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeDeleteModal();\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast('Recce deleted', 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Delete failed', 'error');\u001b[39m\n\u001b[31m    btn.classList.remove('no-reason');\u001b[39m\n\u001b[31m    btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openMyServerRecce(subId) {\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  // No view yet — show metadata modal (same layout as admin detail)\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta==='string' ? JSON.parse(r.meta) : (r.meta||{}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">📍 View on Google Maps</a>` : '';\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} × ${b.h||'?'} in · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos will appear after next sync from original device\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Visit Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupLanding() {\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = 'none';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = 'none';\u001b[39m\n\u001b[31m  // Clean up admin + create-mode UI\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('sup-back-btn')?.remove();\u001b[39m\n\u001b[31m  document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m  _supCreateMode = false;\u001b[39m\n\u001b[31m  // Resume-wrap may have been hidden by loadHomeAdmin() — restore it so draft banner shows\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = '';\u001b[39m\n\u001b[31m  document.getElementById('sub-list').innerHTML = `\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorViewAll()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0f9ff\\\">📋</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">View All Recces</span><span class=\\\"hi-txt\\\">सभी रेकी देखें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">Browse & review submissions from all agents</span><span class=\\\"hi-txt\\\">सभी एजेंट की सबमिशन देखें</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorCreateView()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0fdf4\\\">✍️</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">Create Recce</span><span class=\\\"hi-txt\\\">नई रेकी बनाएं</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">My submissions + New Recce button</span><span class=\\\"hi-txt\\\">मेरी सबमिशन + नई रेकी</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorViewAll() {\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  await loadHomeAdmin();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorCreateView() {\u001b[39m\n\u001b[31m  _supCreateMode = true;\u001b[39m\n\u001b[31m  // Restore field-agent UI\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh'); if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = t('My Submissions','मेरी सबमिशन');\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar'); if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  // Add Back to Menu button (once)\u001b[39m\n\u001b[31m  if (!document.getElementById('sup-back-create-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-create-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => {\u001b[39m\n\u001b[31m      _supCreateMode = false;\u001b[39m\n\u001b[31m      document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m      renderSupLanding();\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    document.querySelector('#view-home .content').prepend(bb);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  await loadHome();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadHome() {\u001b[39m\n\u001b[31m  if (_isSupervisor() && !_supCreateMode) { renderSupLanding(); return; }\u001b[39m\n\u001b[31m  if (_adminUnlocked && !_supCreateMode) { await loadHomeAdmin(); return; }·\u001b[39m\n\u001b[31m  const all  = await dbAll('subs');\u001b[39m\n\u001b[31m  const sy   = all.filter(s => s.status === 'synced').length;\u001b[39m\n\u001b[31m  const pe   = all.filter(s => s.status !== 'synced').length;·\u001b[39m\n\u001b[31m  // Fetch this agent's submissions from server — works on any device\u001b[39m\n\u001b[31m  let serverOnly = [];\u001b[39m\n\u001b[31m  let editAssigned = [];\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (navigator.onLine && hub?.empId) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?submitted_by=eq.${encodeURIComponent(hub.empId)}&order=submitted_at.desc&limit=200`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp.ok) {\u001b[39m\n\u001b[31m        const rows = await resp.json();\u001b[39m\n\u001b[31m        const localIds = new Set(all.map(s => s.id));\u001b[39m\n\u001b[31m        serverOnly = rows.filter(r => !localIds.has(r.sub_id));\u001b[39m\n\u001b[31m        _myServerRows = serverOnly;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m    // Fetch edit-assigned recces (supervisor assigned this creator to edit)\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp2 = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?edit_assigned_to=eq.${encodeURIComponent(hub.empId)}&deleted_at=is.null&order=submitted_at.desc`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp2.ok) editAssigned = await resp2.json();\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = sy + serverOnly.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = pe;\u001b[39m\n\u001b[31m  document.getElementById('stat-total').textContent   = all.length + serverOnly.length;·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!all.length && !serverOnly.length && !editAssigned.length) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">📋</div><div class=\\\"empty-txt\\\">No submissions yet</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const icos   = { synced:'✅', pending:'⏳', failed:'❌' };\u001b[39m\n\u001b[31m  const sorted = [...all].sort((a,b) => new Date(b.timestamp) - new Date(a.timestamp)).slice(0, 50);·\u001b[39m\n\u001b[31m  const localCards = sorted.map(s => {\u001b[39m\n\u001b[31m    const dt = new Date(s.timestamp);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const viewBtn = s.viewUrl\u001b[39m\n\u001b[31m      ? `<button class=\\\"edit-btn-sm\\\" onclick=\\\"window.open('${s.viewUrl}','_blank')\\\">👁 View</button>`\u001b[39m\n\u001b[31m      : `<button class=\\\"edit-btn-sm\\\" onclick=\\\"viewRecce('${s.id}')\\\">👁 View</button>`;\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico ${s.status}\\\">${icos[s.status]||'📋'}</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${s.data.storeName||'Unknown'} · ${s.data.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${s.data.address||''}</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge ${s.status}\\\">${s.status}</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          ${viewBtn}\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"editRecce('${s.id}')\\\" style=\\\"background:#fff7ed;border-color:var(--or);color:var(--or)\\\">✏ Edit</button>\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"makeSlides('${s.id}')\\\" style=\\\"background:#eff6ff;border-color:#3b82f6;color:#1d4ed8\\\">📊 Slides</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const serverCards = serverOnly.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const showPdf = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m    const pdfCls = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico synced\\\">✅</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\" style=\\\"min-width:0;flex:1\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"rpt-btns\\\" style=\\\"margin-top:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openMyServerRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m          ${showPdf ? `<button class=\\\"${pdfCls}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">📄 PDF</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge synced\\\">synced</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const editAssignedCards = editAssigned.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    return `<div class=\\\"edit-req-card\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:26px;flex-shrink:0\\\">✏</div>\u001b[39m\n\u001b[31m      <div class=\\\"edit-req-card-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-meta\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        ${r.edit_comment ? `<div class=\\\"edit-req-cmt\\\">\\\"${r.edit_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:10px;display:flex;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"startCreatorEdit('${r.sub_id}')\\\" style=\\\"padding:9px 16px;font-size:13px;font-weight:600\\\">✏ Edit this Recce</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (editAssignedCards.length) {\u001b[39m\n\u001b[31m    html += `<div class=\\\"edit-req-section-hdr\\\">✏ Edit Requested (${editAssignedCards.length})</div>`;\u001b[39m\n\u001b[31m    html += editAssignedCards.join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  html += localCards.join('') + serverCards.join('');\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m  const ls = await cfg('last-sync');\u001b[39m\n\u001b[31m  if (ls) {\u001b[39m\n\u001b[31m    const d = new Date(ls);\u001b[39m\n\u001b[31m    document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m      'Synced ' + d.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// RESET\u001b[39m\n\u001b[31mfunction startNewRecce(){F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  if(geoStampEnabled)autoRequestGPS();\u001b[39m\n\u001b[31m['f-date','f-brand','f-store','f-addr','f-mobile','f-client-other'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';});\u001b[39m\n\u001b[31m_selectedClient='';_clientOtherMode=false;\u001b[39m\n\u001b[31m_selectedCampaignId=null;_notifySupervisor=false;_brandingLocked=false;\u001b[39m\n\u001b[31mconst _camSel=document.getElementById('f-campaign-id');if(_camSel)_camSel.value='';\u001b[39m\n\u001b[31mconst _camNotice=document.getElementById('campaign-notify-msg');if(_camNotice)_camNotice.style.display='none';\u001b[39m\n\u001b[31mloadCampaignsForForm();\u001b[39m\n\u001b[31mrenderClientChips();\u001b[39m\n\u001b[31mdocument.getElementById('f-date').value=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31m// Block future dates\u001b[39m\n\u001b[31mdocument.getElementById('f-date').max=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31mdocument.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('pick-trigger-wrap').style.display=stores.length?'block':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').style.display=stores.length?'flex':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31mdocument.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31mdocument.getElementById('manual-fields').style.display=stores.length?'none':'block';\u001b[39m\n\u001b[31mdocument.getElementById('gps-status').textContent='';\u001b[39m\n\u001b[31m['vid-yes','vid-no','br-yes','br-no'].forEach(id=>document.getElementById(id).classList.remove('sel'));\u001b[39m\n\u001b[31mdocument.getElementById('vid-sec').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('vid-slot').innerHTML=`<div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('br-add').style.display='none';document.getElementById('br-items').innerHTML='';\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').classList.remove('filled');\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').innerHTML=`<div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('brand-selector').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('sc-missing').style.display='none';\u001b[39m\n\u001b[31mpopulateBrandDropdown();\u001b[39m\n\u001b[31mrenderPhotos('front');renderPhotos('inside');renderAddl();updAvailTag();showView('form-store');}\u001b[39m\n\u001b[31mfunction exitForm(){\u001b[39m\n\u001b[31m  // Show safe exit dialog instead of confirm\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitSaveAndLeave(){\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m  checkDraft();\u001b[39m\n\u001b[31m  toast('Draft saved — tap Resume to continue','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitDiscard(){\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];\u001b[39m\n\u001b[31m  videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  dbDel('draft','current');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitCancel(){document.getElementById('exit-dialog').classList.remove('open');}\u001b[39m\n\u001b[31mfunction showView(n){document.querySelectorAll('.view').forEach(v=>v.classList.remove('active'));const t=document.getElementById('view-'+n);if(t){t.classList.add('active');window.scrollTo(0,0);}}\u001b[39m\n\u001b[31mlet _tt;\u001b[39m\n\u001b[31mfunction toast(msg,type='info'){const el=document.getElementById('toast');el.textContent=msg;el.className='toast show '+type;clearTimeout(_tt);_tt=setTimeout(()=>el.classList.remove('show'),3000);}\u001b[39m\n\u001b[31mfunction netStatus(){const on=navigator.onLine;const dot=document.getElementById('net-dot');const txt=document.getElementById('net-txt');if(dot)dot.className='sdot '+(on?'on':'off');if(txt)txt.textContent=on?t('Online','ऑनलाइन'):t('Offline — saves locally','ऑफलाइन — स्थानीय रूप से सेव');}\u001b[39m\n\u001b[31masync function loadSettings(){\u001b[39m\n\u001b[31m  // Gas URL: pre-load default if none saved, update preview\u001b[39m\n\u001b[31m  const gu=await cfg('gas-url');\u001b[39m\n\u001b[31m  if(!gu)await cfg('gas-url',DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m  // Admin cfg url\u001b[39m\n\u001b[31m  const acu=await cfg('admin-cfg-url');if(acu&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=acu;\u001b[39m\n\u001b[31m  const su=await cfg('srv-url')||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su)document.getElementById('srv-url').value=su;\u001b[39m\n\u001b[31m  const sc=await cfg('stores');\u001b[39m\n\u001b[31m  if(sc){\u001b[39m\n\u001b[31m    stores=JSON.parse(sc);\u001b[39m\n\u001b[31m    const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m    document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m      `✓ ${stores.length} stores in cache${noBrand?` · ${noBrand} without brand`:''}`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const sf=await cfg('store-files');if(sf){_storeFiles=JSON.parse(sf);renderStoreFileList();}\u001b[39m\n\u001b[31m  const iq=await cfg('img-quality');imgQuality=iq||'compressed';applyQualityUI(imgQuality);\u001b[39m\n\u001b[31m  const gs=await cfg('geo-stamp');geoStampEnabled=(gs===null||gs==='1');applyGeoStampUI();\u001b[39m\n\u001b[31m  const bl=await cfg('brands');if(bl)brands=JSON.parse(bl);\u001b[39m\n\u001b[31m  loadBrandsFromDb();  // async — updates brands + logos from DB in background\u001b[39m\n\u001b[31m  renderBrandManageList();\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m  // Show store upload row + brand add row to supervisors only\u001b[39m\n\u001b[31m  const sur = document.getElementById('store-upload-row');\u001b[39m\n\u001b[31m  if (sur) sur.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const bar = document.getElementById('brand-add-row');\u001b[39m\n\u001b[31m  if (bar) bar.style.display = _isSupervisor() ? 'flex' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction populateBrandDropdown(){\u001b[39m\n\u001b[31m  const sel=document.getElementById('f-brand');if(!sel)return;\u001b[39m\n\u001b[31m  const cur=sel.value;\u001b[39m\n\u001b[31m  sel.innerHTML='<option value=\\\"\\\">Select brand</option>'+brands.map(b=>`<option${cur===b?' selected':''}>${b}</option>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderBrandManageList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('brand-manage-list');if(!el)return;\u001b[39m\n\u001b[31m  const isSup=_isSupervisor();\u001b[39m\n\u001b[31m  el.innerHTML=brands.map((b,i)=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    const logoHtml=logo?`<img src=\\\"${logo}\\\" style=\\\"height:20px;max-width:48px;object-fit:contain;flex-shrink:0;border-radius:3px\\\">`:'';\u001b[39m\n\u001b[31m    const ctrlHtml=isSup?`<div style=\\\"display:flex;gap:2px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"openEditBrandDialog(${i})\\\" style=\\\"background:none;border:none;color:var(--nv);font-size:15px;cursor:pointer;padding:2px 6px\\\" title=\\\"Edit\\\">✏</button>\u001b[39m\n\u001b[31m      ${brands.length>1?`<button onclick=\\\"confirmRemoveBrand(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:2px 4px\\\">×</button>`:'<span style=\\\"font-size:11px;color:var(--g400);padding:0 6px\\\">Last</span>'}\u001b[39m\n\u001b[31m    </div>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;min-width:0\\\">${logoHtml}<span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${b}</span></div>\u001b[39m\n\u001b[31m      ${ctrlHtml}\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function addBrandToList(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const inp=document.getElementById('brand-add-inp');\u001b[39m\n\u001b[31m  const val=(inp.value.trim()||'').toUpperCase();\u001b[39m\n\u001b[31m  if(!val){toast('Enter a brand name','error');return;}\u001b[39m\n\u001b[31m  if(brands.some(b=>b.toLowerCase()===val.toLowerCase())){toast(`${val} already in list`,'error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands`,{method:'POST',headers:{..._RC_WRITE,'Prefer':'return=minimal'},body:JSON.stringify({name:val,sort_order:99})});\u001b[39m\n\u001b[31m    if(resp.status===409){toast(`${val} already exists in DB`,'error');return;}\u001b[39m\n\u001b[31m    if(!resp.ok){const e=await resp.json().catch(()=>({}));throw new Error(e.message||resp.status);}\u001b[39m\n\u001b[31m    inp.value='';\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${val} added ✓`,'success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Add failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmRemoveBrand(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const name=brands[idx];\u001b[39m\n\u001b[31m  if(brands.length<=1){toast('Need at least one brand','error');return;}\u001b[39m\n\u001b[31m  let count=0;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(name)}&select=sub_id`,{headers:_RC_READ});\u001b[39m\n\u001b[31m    if(r.ok){const rows=await r.json();count=rows.length;}\u001b[39m\n\u001b[31m  }catch(_){}\u001b[39m\n\u001b[31m  const msg=count>0?`Delete \\\"${name}\\\" from brand list?\\\\n(${count} submission${count!==1?'s':''} reference this brand — they keep the name as text.)`:`Delete \\\"${name}\\\" from brand list?`;\u001b[39m\n\u001b[31m  if(!confirm(msg))return;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(name)}`,{method:'DELETE',headers:{'Content-Profile':'recce','Accept-Profile':'recce'}});\u001b[39m\n\u001b[31m    if(!resp.ok&&resp.status!==204){throw new Error(resp.status);}\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${name} removed ✓`,'info');\u001b[39m\n\u001b[31m  }catch(e){toast(`Remove failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadBrandsFromDb(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch('/db/brands?select=name,logo_url&order=sort_order',{\u001b[39m\n\u001b[31m      headers:{'Content-Profile':'recce','Accept-Profile':'recce'}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(!r.ok) return;\u001b[39m\n\u001b[31m    const rows=await r.json();\u001b[39m\n\u001b[31m    if(!rows||!rows.length) return;\u001b[39m\n\u001b[31m    const dbNames=rows.map(r=>r.name);\u001b[39m\n\u001b[31m    const logos={};rows.forEach(r=>{if(r.logo_url)logos[r.name]=r.logo_url;});\u001b[39m\n\u001b[31m    // Merge: DB brands canonical, keep locally-added extras\u001b[39m\n\u001b[31m    const extras=brands.filter(b=>!dbNames.some(n=>n.toLowerCase()===b.toLowerCase()));\u001b[39m\n\u001b[31m    brands=[...dbNames,...extras];\u001b[39m\n\u001b[31m    _brandLogos=logos;\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    // Refresh brand chips if brand-selector is visible\u001b[39m\n\u001b[31m    const bSel=document.getElementById('brand-selector');\u001b[39m\n\u001b[31m    if(bSel&&bSel.style.display!=='none') renderBrandChips();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[brands-db]',e.message);}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction renderBrandChips(){\u001b[39m\n\u001b[31m  const bChips=document.getElementById('brand-chips');if(!bChips)return;\u001b[39m\n\u001b[31m  bChips.innerHTML=brands.map(b=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    return `<div class=\\\"chip brand-chip${F.brand===b?' sel':''}\\\" onclick=\\\"selectStoreBrand('${b.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\">` +\u001b[39m\n\u001b[31m      (logo?`<img src=\\\"${logo}\\\" class=\\\"brand-chip-logo\\\" alt=\\\"\\\">`:'') +\u001b[39m\n\u001b[31m      `<span>${b}</span></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _editBrandIdx=null,_editBrandOld=null;\u001b[39m\n\u001b[31mfunction openEditBrandDialog(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor())return;\u001b[39m\n\u001b[31m  _editBrandIdx=idx;_editBrandOld=brands[idx];\u001b[39m\n\u001b[31m  document.getElementById('be-name').value=brands[idx];\u001b[39m\n\u001b[31m  const logo=_brandLogos[brands[idx]]||'';\u001b[39m\n\u001b[31m  document.getElementById('be-logo').value=logo;\u001b[39m\n\u001b[31m  document.getElementById('be-logo-preview').innerHTML=logo?`<img src=\\\"${logo}\\\" style=\\\"height:28px;object-fit:contain\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Current logo</span>`:'';\u001b[39m\n\u001b[31m  document.getElementById('be-cascade-info').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('brand-edit-modal').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeBrandEditModal(){document.getElementById('brand-edit-modal').classList.remove('open');_editBrandIdx=null;_editBrandOld=null;}\u001b[39m\n\u001b[31mfunction previewBrandLogo(){\u001b[39m\n\u001b[31m  const url=(document.getElementById('be-logo')?.value||'').trim();\u001b[39m\n\u001b[31m  const prev=document.getElementById('be-logo-preview');\u001b[39m\n\u001b[31m  if(prev)prev.innerHTML=url?`<img src=\\\"${url}\\\" style=\\\"height:28px;object-fit:contain\\\" onerror=\\\"this.style.display='none'\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Preview</span>`:'';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveBrandEdit(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const oldName=_editBrandOld;\u001b[39m\n\u001b[31m  const newName=(document.getElementById('be-name').value||'').trim().toUpperCase();\u001b[39m\n\u001b[31m  const newLogo=(document.getElementById('be-logo').value||'').trim();\u001b[39m\n\u001b[31m  if(!newName){toast('Brand name required','error');return;}\u001b[39m\n\u001b[31m  const isRename=newName!==oldName;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // 1. Update recce.brands\u001b[39m\n\u001b[31m    const pResp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m      method:'PATCH',headers:{..._RC_WRITE,'Prefer':'return=minimal'},\u001b[39m\n\u001b[31m      body:JSON.stringify({name:newName,logo_url:newLogo||null})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(pResp.status===409){toast(`\\\"${newName}\\\" already exists`,'error');return;}\u001b[39m\n\u001b[31m    if(!pResp.ok&&pResp.status!==204){const e=await pResp.json().catch(()=>({}));throw new Error(e.message||pResp.status);}\u001b[39m\n\u001b[31m    if(isRename){\u001b[39m\n\u001b[31m      const hub=_recceHubUser();\u001b[39m\n\u001b[31m      // 2. Cascade to submissions\u001b[39m\n\u001b[31m      await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m        method:'PATCH',headers:_RC_WRITE,body:JSON.stringify({brand:newName})\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      // 3. Cascade to stores.json + view HTML files + PDFs\u001b[39m\n\u001b[31m      toast('Cascading rename to reports…','info');\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        const cResp=await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},\u001b[39m\n\u001b[31m          body:JSON.stringify({type:'cascade-rename-brand',oldName,newName,empId:hub?.empId||''})});\u001b[39m\n\u001b[31m        const cRes=cResp.ok?await cResp.json():{};\u001b[39m\n\u001b[31m        const msg=`Brand renamed ✓${cRes.viewsUpdated?` · ${cRes.viewsUpdated} reports re-queued`:''}`;\u001b[39m\n\u001b[31m        closeBrandEditModal();\u001b[39m\n\u001b[31m        await loadBrandsFromDb();\u001b[39m\n\u001b[31m        toast(msg,'success');\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }catch(e){console.warn('[cascade-rename]',e.message);}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeBrandEditModal();\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast('Brand updated ✓','success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Save failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function fetchServerBrands(){\u001b[39m\n\u001b[31m  const url=document.getElementById('brands-url')?.value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    toast('Fetching brands…','info');\u001b[39m\n\u001b[31m    const r=await fetch(url);const j=await r.json();\u001b[39m\n\u001b[31m    const list=Array.isArray(j)?j:j.brands||[];\u001b[39m\n\u001b[31m    if(!list.length){toast('No brands found in response','error');return;}\u001b[39m\n\u001b[31m    brands=list.map(b=>b.toString().toUpperCase());\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    toast(`${brands.length} brands loaded from server`,'success');\u001b[39m\n\u001b[31m  }catch{toast('Failed to fetch — check URL','error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setImgQuality(q){\u001b[39m\n\u001b[31m  imgQuality=q;\u001b[39m\n\u001b[31m  cfg('img-quality',q);\u001b[39m\n\u001b[31m  applyQualityUI(q);\u001b[39m\n\u001b[31m  toast(q==='hd'?'HD Quality selected (~400–600 KB per photo)':'Full Compression selected (~150–200 KB per photo)','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction applyQualityUI(q){\u001b[39m\n\u001b[31m  ['compressed','hd'].forEach(opt=>{\u001b[39m\n\u001b[31m    const label=document.getElementById('q-opt-'+opt);\u001b[39m\n\u001b[31m    const radio=document.getElementById('q-radio-'+opt);\u001b[39m\n\u001b[31m    const dot  =document.getElementById('q-dot-'+opt);\u001b[39m\n\u001b[31m    if(!label)return;\u001b[39m\n\u001b[31m    const active=opt===q;\u001b[39m\n\u001b[31m    label.style.borderColor=active?'var(--or)':'var(--g200)';\u001b[39m\n\u001b[31m    label.style.background=active?'#fff7ed':'var(--g50)';\u001b[39m\n\u001b[31m    if(radio)radio.style.borderColor=active?'var(--or)':'var(--g300)';\u001b[39m\n\u001b[31m    if(dot)dot.style.display=active?'block':'none';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const badge=document.getElementById('q-current-badge');\u001b[39m\n\u001b[31m  if(badge){\u001b[39m\n\u001b[31m    const label=q==='hd'?'HD Quality (~400–600 KB)':'Full Compression (~150–200 KB)';\u001b[39m\n\u001b[31m    badge.innerHTML=`Active: <strong>${label}</strong>`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function clearData(){if(!confirm('Delete ALL local data?'))return;const all=await dbAll('subs');for(const s of all)await dbDel('subs',s.id);stores=[];await cfg('stores',null);toast('All cleared','success');loadHome();}\u001b[39m\n\u001b[31mif('serviceWorker' in navigator){const sw=`const C='recce-v37';self.addEventListener('install',e=>{e.waitUntil(caches.open(C).then(c=>c.add('/')));self.skipWaiting();});self.addEventListener('activate',e=>e.waitUntil(clients.claim()));self.addEventListener('fetch',e=>{if(e.request.method!=='GET')return;e.respondWith(caches.match(e.request).then(r=>{if(r)return r;return fetch(e.request).then(res=>{if(res&&res.status===200&&res.type==='basic'){const cl=res.clone();caches.open(C).then(c=>c.put(e.request,cl));}return res;}).catch(()=>caches.match('/'));}))}); `;const blob=new Blob([sw],{type:'application/javascript'});navigator.serviceWorker.register(URL.createObjectURL(blob),{scope:'/'}).catch(()=>{});}·\u001b[39m\n\u001b[31m// ── GEOLOCATION STAMP ────────────────────────────────────────\u001b[39m\n\u001b[31mfunction applyGeoStampUI(){\u001b[39m\n\u001b[31m  const tog=document.getElementById('geo-tog');\u001b[39m\n\u001b[31m  if(tog)tog.classList.toggle('on',geoStampEnabled);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function toggleGeoStamp(){\u001b[39m\n\u001b[31m  geoStampEnabled=!geoStampEnabled;\u001b[39m\n\u001b[31m  await cfg('geo-stamp',geoStampEnabled?'1':'0');\u001b[39m\n\u001b[31m  applyGeoStampUI();\u001b[39m\n\u001b[31m  toast(geoStampEnabled?'Geolocation stamp enabled':'Geolocation stamp disabled','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Auto-request GPS silently when a new recce starts\u001b[39m\n\u001b[31mfunction autoRequestGPS(){\u001b[39m\n\u001b[31m  if(!navigator.geolocation)return;\u001b[39m\n\u001b[31m  const statusEl=document.getElementById('geo-status');\u001b[39m\n\u001b[31m  if(statusEl)statusEl.textContent='Acquiring GPS…';\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(\u001b[39m\n\u001b[31m    pos=>{\u001b[39m\n\u001b[31m      gpsCoords={\u001b[39m\n\u001b[31m        lat:pos.coords.latitude.toFixed(6),\u001b[39m\n\u001b[31m        lng:pos.coords.longitude.toFixed(6),\u001b[39m\n\u001b[31m        acc:Math.round(pos.coords.accuracy)\u001b[39m\n\u001b[31m      };\u001b[39m\n\u001b[31m      const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m      const quality=acc<=15?'Excellent':acc<=50?'Good':acc<=200?'Fair':'Poor (cell tower)';\u001b[39m\n\u001b[31m      const color=acc<=15?'var(--gn)':acc<=50?'#16a34a':acc<=200?'var(--am)':'var(--rd)';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.innerHTML=`GPS: ${gpsCoords.lat}, ${gpsCoords.lng} · ±${acc}m · <span style=\\\"color:${color};font-weight:600\\\">${quality}</span>`;\u001b[39m\n\u001b[31m      // Update form GPS status too\u001b[39m\n\u001b[31m      const fs=document.getElementById('gps-status');\u001b[39m\n\u001b[31m      if(fs){fs.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${acc}m)`;fs.style.color='var(--gn)';}\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    err=>{\u001b[39m\n\u001b[31m      const msgs={1:'Location permission denied in Chrome',2:'GPS signal unavailable',3:'GPS timed out'};\u001b[39m\n\u001b[31m      const msg=msgs[err.code]||'GPS unavailable';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.textContent=msg+' — stamp will use store address';\u001b[39m\n\u001b[31m      if(err.code===1)toast('Tap the lock icon in Chrome address bar → allow Location','info');\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    {enableHighAccuracy:true,timeout:20000,maximumAge:60000}\u001b[39m\n\u001b[31m  );\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Draw stamp on a photo blob — returns new blob with stamp baked in\u001b[39m\n\u001b[31mfunction roundRectPath(ctx,x,y,w,h,r){\u001b[39m\n\u001b[31m  ctx.beginPath();ctx.moveTo(x+r,y);ctx.lineTo(x+w-r,y);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y,x+w,y+r);ctx.lineTo(x+w,y+h-r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);ctx.lineTo(x+r,y+h);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y+h,x,y+h-r);ctx.lineTo(x,y+r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y,x+r,y);ctx.closePath();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction fitText(ctx,text,maxW){\u001b[39m\n\u001b[31m  if(ctx.measureText(text).width<=maxW)return text;\u001b[39m\n\u001b[31m  while(text.length>1&&ctx.measureText(text+'…').width>maxW)text=text.slice(0,-1);\u001b[39m\n\u001b[31m  return text+'…';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction stampPhoto(blob){\u001b[39m\n\u001b[31m  if(!geoStampEnabled)return Promise.resolve(blob);\u001b[39m\n\u001b[31m  return new Promise(res=>{\u001b[39m\n\u001b[31m    const img=new Image(),url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    img.onload=()=>{\u001b[39m\n\u001b[31m      URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m      const W=img.width,H=img.height;\u001b[39m\n\u001b[31m      const c=document.createElement('canvas');c.width=W;c.height=H;\u001b[39m\n\u001b[31m      const ctx=c.getContext('2d');\u001b[39m\n\u001b[31m      ctx.drawImage(img,0,0);·\u001b[39m\n\u001b[31m      // Stamp dimensions — 18% of image height\u001b[39m\n\u001b[31m      const SH=Math.round(H*0.18);\u001b[39m\n\u001b[31m      const pad=Math.round(W*0.03);\u001b[39m\n\u001b[31m      const SY=H-SH;·\u001b[39m\n\u001b[31m      // Semi-transparent background\u001b[39m\n\u001b[31m      ctx.fillStyle='rgba(10,18,35,0.78)';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,SH);·\u001b[39m\n\u001b[31m      // Orange top accent line\u001b[39m\n\u001b[31m      ctx.fillStyle='#f97316';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,Math.max(3,Math.round(H*0.004)));·\u001b[39m\n\u001b[31m      // Font sizes scaled to image\u001b[39m\n\u001b[31m      const f1=Math.round(SH*0.26); // store name\u001b[39m\n\u001b[31m      const f2=Math.round(SH*0.22); // coords / address\u001b[39m\n\u001b[31m      const f3=Math.round(SH*0.20); // timestamp·\u001b[39m\n\u001b[31m      // Row Y centres\u001b[39m\n\u001b[31m      const r1=SY+SH*0.26;\u001b[39m\n\u001b[31m      const r2=SY+SH*0.55;\u001b[39m\n\u001b[31m      const r3=SY+SH*0.82;·\u001b[39m\n\u001b[31m      // Get stamp data\u001b[39m\n\u001b[31m      const storeName=F.storeName||selectedStore?.name||'';\u001b[39m\n\u001b[31m      const brand=F.brand||selectedStore?.brand||'';\u001b[39m\n\u001b[31m      const addr=F.address||selectedStore?.address||'';\u001b[39m\n\u001b[31m      const now=new Date();\u001b[39m\n\u001b[31m      const dateStr=now.toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m      const timeStr=now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit',hour12:true});·\u001b[39m\n\u001b[31m      // Badge (right side — GPS quality)\u001b[39m\n\u001b[31m      let badgeLabel='',badgeColor='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m        if(acc<=15){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=50){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=200){badgeLabel='~'+acc+'m';badgeColor='#d97706';}\u001b[39m\n\u001b[31m        else{badgeLabel='Cell ~'+acc+'m';badgeColor='#dc2626';}\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        badgeLabel='No GPS';badgeColor='#64748b';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      const bFontSz=Math.round(SH*0.18);\u001b[39m\n\u001b[31m      ctx.font=`bold ${bFontSz}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      const bW=Math.round(ctx.measureText(badgeLabel).width+pad);\u001b[39m\n\u001b[31m      const bH=Math.round(SH*0.32);\u001b[39m\n\u001b[31m      const bX=W-bW-pad;const bY=SY+(SH-bH)/2;\u001b[39m\n\u001b[31m      ctx.fillStyle=badgeColor+'cc';\u001b[39m\n\u001b[31m      roundRectPath(ctx,bX,bY,bW,bH,4);ctx.fill();\u001b[39m\n\u001b[31m      ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';\u001b[39m\n\u001b[31m      ctx.fillText(badgeLabel,bX+bW/2,bY+bH/2);\u001b[39m\n\u001b[31m      ctx.textAlign='left';ctx.textBaseline='alphabetic';·\u001b[39m\n\u001b[31m      const textMaxW=bX-pad*2;·\u001b[39m\n\u001b[31m      // Row 1 — store name + brand\u001b[39m\n\u001b[31m      ctx.font=`bold ${f1}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#ffffff';\u001b[39m\n\u001b[31m      const nameText=storeName+(brand?' · '+brand:'');\u001b[39m\n\u001b[31m      ctx.fillText('📍 '+fitText(ctx,nameText,textMaxW-f1*1.4),pad,r1);·\u001b[39m\n\u001b[31m      // Row 2 — GPS coords OR address\u001b[39m\n\u001b[31m      ctx.font=`${f2}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#cbd5e1';\u001b[39m\n\u001b[31m      let row2='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        row2=`Lat ${gpsCoords.lat}°   Long ${gpsCoords.lng}°`;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        row2=addr?fitText(ctx,addr,textMaxW):'GPS coordinates unavailable';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      ctx.fillText(row2,pad,r2);·\u001b[39m\n\u001b[31m      // Row 3 — date and time\u001b[39m\n\u001b[31m      ctx.font=`${f3}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#94a3b8';\u001b[39m\n\u001b[31m      ctx.fillText(`${dateStr}   ${timeStr}`,pad,r3);·\u001b[39m\n\u001b[31m      c.toBlob(b=>res(b||blob),'image/jpeg',imgQuality==='hd'?0.88:0.82);\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    img.onerror=()=>{URL.revokeObjectURL(url);res(blob);};\u001b[39m\n\u001b[31m    img.src=url;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _aTool='rect',_aColor='#f97316',_aWidth=4,_aTarget=-1;\u001b[39m\n\u001b[31mlet _aImg=null,_aHistory=[],_aDrawing=false,_aStart={},_aPts=[];\u001b[39m\n\u001b[31mlet _aSel=-1,_aDragMode=null,_aDragOff={x:0,y:0};\u001b[39m\n\u001b[31m// Larger hit radius on touch devices for easier finger selection\u001b[39m\n\u001b[31mconst HIT_R=()=>('ontouchstart' in window)?32:16;·\u001b[39m\n\u001b[31mfunction setATool(t){\u001b[39m\n\u001b[31m  _aTool=t;\u001b[39m\n\u001b[31m  ['rect','ellipse','line','arrow','free'].forEach(id=>{const el=document.getElementById('at-'+id);if(el)el.classList.toggle('on',id===t&&t!=='move');});\u001b[39m\n\u001b[31m  const mv=document.getElementById('at-move');if(mv)mv.classList.toggle('sel-on',t==='move');\u001b[39m\n\u001b[31m  const info=document.getElementById('annot-sel-info');if(info)info.style.display=t==='move'?'block':'none';\u001b[39m\n\u001b[31m  if(t!=='move'){_aSel=-1;redrawAnnot();}\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(cvs)cvs.style.cursor=t==='move'?'default':'crosshair';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAColor(c){\u001b[39m\n\u001b[31m  _aColor=c;\u001b[39m\n\u001b[31m  const m={'#f97316':'or','#ef4444':'rd','#ffffff':'wh','#facc15':'yw','#22c55e':'gn'};\u001b[39m\n\u001b[31m  Object.entries(m).forEach(([col,id])=>{const el=document.getElementById('ac-'+id);if(el)el.classList.toggle('on',col===c);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAWidth(w){_aWidth=w;[2,4,7].forEach(v=>{const el=document.getElementById('aw-'+v);if(el)el.classList.toggle('on',v===w);});}·\u001b[39m\n\u001b[31mfunction openAnnot(idx){\u001b[39m\n\u001b[31m  _aTarget=idx;_aHistory=[];_aDrawing=false;_aPts=[];_aSel=-1;_aDragMode=null;\u001b[39m\n\u001b[31m  document.getElementById('annot-modal').classList.add('open');\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');\u001b[39m\n\u001b[31m  const img=new Image(),url=URL.createObjectURL(brandings[idx].blob);\u001b[39m\n\u001b[31m  img.onload=()=>{\u001b[39m\n\u001b[31m    const sc=Math.min(1,window.innerWidth/img.width,(window.innerHeight-185)/img.height);\u001b[39m\n\u001b[31m    cvs.width=Math.round(img.width*sc);cvs.height=Math.round(img.height*sc);\u001b[39m\n\u001b[31m    _aImg=img;redrawAnnot();URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  img.src=url;\u001b[39m\n\u001b[31m  cvs.ontouchstart=aDown;cvs.ontouchmove=aMove;cvs.ontouchend=aUp;\u001b[39m\n\u001b[31m  cvs.onmousedown=aDown;cvs.onmousemove=aMove;cvs.onmouseup=aUp;\u001b[39m\n\u001b[31m  setATool('rect');setAColor('#f97316');setAWidth(4);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aPos(e){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const r=cvs.getBoundingClientRect();\u001b[39m\n\u001b[31m  const src=e.touches?e.touches[0]:e;\u001b[39m\n\u001b[31m  return{x:(src.clientX-r.left)*(cvs.width/r.width),y:(src.clientY-r.top)*(cvs.height/r.height)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Always return normalised (positive w,h) bounds\u001b[39m\n\u001b[31mfunction sBounds(s){\u001b[39m\n\u001b[31m  if(s.type==='free'){\u001b[39m\n\u001b[31m    if(!s.pts||!s.pts.length)return null;\u001b[39m\n\u001b[31m    const xs=s.pts.map(p=>p.x),ys=s.pts.map(p=>p.y);\u001b[39m\n\u001b[31m    const x=Math.min(...xs),y=Math.min(...ys);\u001b[39m\n\u001b[31m    return{x,y,w:Math.max(...xs)-x,h:Math.max(...ys)-y};\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  return{x:Math.min(s.x,s.x+s.w),y:Math.min(s.y,s.y+s.h),w:Math.abs(s.w),h:Math.abs(s.h)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction hitHandle(px,py,s){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return null;\u001b[39m\n\u001b[31m  const b=sBounds(s);const hr=HIT_R();\u001b[39m\n\u001b[31m  for(const[n,x,y]of[['tl',b.x,b.y],['tr',b.x+b.w,b.y],['bl',b.x,b.y+b.h],['br',b.x+b.w,b.y+b.h]])\u001b[39m\n\u001b[31m    if(Math.hypot(px-x,py-y)<hr)return n;\u001b[39m\n\u001b[31m  return null;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction hitShape(px,py,s){\u001b[39m\n\u001b[31m  const b=sBounds(s);if(!b)return false;\u001b[39m\n\u001b[31m  const pad=HIT_R();\u001b[39m\n\u001b[31m  return px>=b.x-pad&&px<=b.x+b.w+pad&&py>=b.y-pad&&py<=b.y+b.h+pad;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aDown(e){\u001b[39m\n\u001b[31m  e.preventDefault();const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'){\u001b[39m\n\u001b[31m    // Check handles of selected shape first\u001b[39m\n\u001b[31m    if(_aSel>=0&&_aSel<_aHistory.length){\u001b[39m\n\u001b[31m      const h=hitHandle(p.x,p.y,_aHistory[_aSel]);\u001b[39m\n\u001b[31m      if(h){_aDragMode='r-'+h;_aDragOff={x:p.x,y:p.y};_aDrawing=true;return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Hit test all shapes topmost first\u001b[39m\n\u001b[31m    for(let i=_aHistory.length-1;i>=0;i--){\u001b[39m\n\u001b[31m      if(hitShape(p.x,p.y,_aHistory[i])){\u001b[39m\n\u001b[31m        _aSel=i;_aDragMode='move';\u001b[39m\n\u001b[31m        const s=_aHistory[i];\u001b[39m\n\u001b[31m        const b=sBounds(s);\u001b[39m\n\u001b[31m        // Store offset from shape top-left corner (normalised)\u001b[39m\n\u001b[31m        _aDragOff={x:p.x-b.x,y:p.y-b.y};\u001b[39m\n\u001b[31m        _aDrawing=true;redrawAnnot();return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    _aSel=-1;redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _aDrawing=true;_aStart={x:p.x,y:p.y};if(_aTool==='free')_aPts=[{x:p.x,y:p.y}];\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aMove(e){\u001b[39m\n\u001b[31m  e.preventDefault();if(!_aDrawing)return;const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'&&_aDragMode){\u001b[39m\n\u001b[31m    const s=_aHistory[_aSel];if(!s)return;\u001b[39m\n\u001b[31m    if(_aDragMode==='move'){\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      // New top-left position\u001b[39m\n\u001b[31m      const nx=p.x-_aDragOff.x;\u001b[39m\n\u001b[31m      const ny=p.y-_aDragOff.y;\u001b[39m\n\u001b[31m      const dx=nx-b.x,dy=ny-b.y;\u001b[39m\n\u001b[31m      if(s.type==='free'){\u001b[39m\n\u001b[31m        s.pts=s.pts.map(pt=>({x:pt.x+dx,y:pt.y+dy}));\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        // Move preserving w/h sign (don't normalise — keep original drawing direction)\u001b[39m\n\u001b[31m        s.x+=dx;s.y+=dy;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Resize from corner — always work on normalised bounds then re-apply\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      const n=_aDragMode.slice(2);\u001b[39m\n\u001b[31m      let nx=b.x,ny=b.y,nw=b.w,nh=b.h;\u001b[39m\n\u001b[31m      if(n==='br'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,p.y-b.y);}\u001b[39m\n\u001b[31m      else if(n==='tl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,b.y+b.h-p.y);nx=p.x;ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='tr'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,b.y+b.h-p.y);ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='bl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,p.y-b.y);nx=p.x;}\u001b[39m\n\u001b[31m      s.x=nx;s.y=ny;s.w=nw;s.h=nh; // store as normalised going forward\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if(_aTool==='free'){_aPts.push({x:p.x,y:p.y});redrawAnnot();drawSh({type:'free',pts:[..._aPts],color:_aColor,lw:_aWidth},true);return;}\u001b[39m\n\u001b[31m  redrawAnnot();drawSh({type:_aTool,x:_aStart.x,y:_aStart.y,w:p.x-_aStart.x,h:p.y-_aStart.y,color:_aColor,lw:_aWidth},true);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction aUp(e){\u001b[39m\n\u001b[31m  if(!_aDrawing)return;_aDrawing=false;\u001b[39m\n\u001b[31m  if(_aTool==='move'){_aDragMode=null;return;}\u001b[39m\n\u001b[31m  const p=aPos(e||{touches:[{clientX:0,clientY:0}]});\u001b[39m\n\u001b[31m  if(_aTool==='free'){if(_aPts.length>2){_aHistory.push({type:'free',pts:[..._aPts],x:_aPts[0].x,y:_aPts[0].y,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  else{const w=p.x-_aStart.x,h=p.y-_aStart.y;if(Math.abs(w)>4||Math.abs(h)>4){_aHistory.push({type:_aTool,x:_aStart.x,y:_aStart.y,w,h,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  _aPts=[];redrawAnnot();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction redrawAnnot(){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.clearRect(0,0,cvs.width,cvs.height);if(_aImg)ctx.drawImage(_aImg,0,0,cvs.width,cvs.height);\u001b[39m\n\u001b[31m  _aHistory.forEach((s,i)=>{drawSh(s,false,ctx);if(_aTool==='move'&&i===_aSel)drawHandles(s,ctx);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawHandles(s,ctx){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return;const b=sBounds(s);ctx.save();\u001b[39m\n\u001b[31m  ctx.setLineDash([5,3]);ctx.strokeStyle='#facc15';ctx.lineWidth=1.5;ctx.strokeRect(b.x-2,b.y-2,b.w+4,b.h+4);ctx.setLineDash([]);\u001b[39m\n\u001b[31m  [[b.x,b.y],[b.x+b.w,b.y],[b.x,b.y+b.h],[b.x+b.w,b.y+b.h]].forEach(([x,y])=>{ctx.beginPath();ctx.arc(x,y,7,0,2*Math.PI);ctx.fillStyle='#f97316';ctx.fill();ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();});\u001b[39m\n\u001b[31m  ctx.restore();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawSh(s,preview=false,ctx){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(!ctx)ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.save();ctx.strokeStyle=s.color;ctx.lineWidth=preview?Math.max(s.lw||4,2):s.lw||4;\u001b[39m\n\u001b[31m  ctx.lineCap='round';ctx.lineJoin='round';ctx.setLineDash(preview?[6,3]:[]);\u001b[39m\n\u001b[31m  if(s.type==='rect'){ctx.strokeRect(s.x,s.y,s.w,s.h);ctx.fillStyle=s.color+'28';ctx.fillRect(s.x,s.y,s.w,s.h);}\u001b[39m\n\u001b[31m  else if(s.type==='ellipse'){const cx=s.x+s.w/2,cy=s.y+s.h/2;ctx.beginPath();ctx.ellipse(cx,cy,Math.abs(s.w/2),Math.abs(s.h/2),0,0,2*Math.PI);ctx.stroke();ctx.fillStyle=s.color+'28';ctx.fill();}\u001b[39m\n\u001b[31m  else if(s.type==='line'){ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(s.x+s.w,s.y+s.h);ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='arrow'){const ex=s.x+s.w,ey=s.y+s.h;ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(ex,ey);ctx.stroke();const a=Math.atan2(s.h,s.w),al=20,aa=0.4;ctx.setLineDash([]);ctx.beginPath();ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a-aa),ey-al*Math.sin(a-aa));ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a+aa),ey-al*Math.sin(a+aa));ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='free'){if(s.pts.length<2){ctx.restore();return;}ctx.beginPath();s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));ctx.stroke();}\u001b[39m\n\u001b[31m  ctx.setLineDash([]);ctx.restore();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction undoAnnot(){if(_aHistory.length){_aHistory.pop();_aSel=Math.min(_aSel,_aHistory.length-1);redrawAnnot();}}\u001b[39m\n\u001b[31mfunction clearAnnot(){_aHistory=[];_aSel=-1;redrawAnnot();}·\u001b[39m\n\u001b[31m// Bottom dialog\u001b[39m\n\u001b[31mlet _bdCb=null;\u001b[39m\n\u001b[31mfunction showBDialog(title,sub,onYes){\u001b[39m\n\u001b[31m  document.getElementById('bdialog-title').textContent=title;\u001b[39m\n\u001b[31m  document.getElementById('bdialog-sub').textContent=sub;\u001b[39m\n\u001b[31m  _bdCb=onYes;document.getElementById('bdialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction bdialogYes(){document.getElementById('bdialog').classList.remove('open');if(_bdCb)_bdCb();_bdCb=null;}\u001b[39m\n\u001b[31mfunction bdialogNo(){document.getElementById('bdialog').classList.remove('open');_bdCb=null;}·\u001b[39m\n\u001b[31mfunction _afterBrandingPhoto(){\u001b[39m\n\u001b[31m  const idx=_aTarget;\u001b[39m\n\u001b[31m  showBDialog(t(`Add reference photos for Branding ${idx+1}?`,`ब्रांडिंग ${idx+1} के लिए अतिरिक्त फोटो?`),t('Optional extra photos for future reference.','वैकल्पिक — भविष्य के लिए अतिरिक्त फोटो।'),()=>{showView('form-additional');setTimeout(()=>addAdditional(),200);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction skipAnnot(){document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo added (${fmtSz(brandings[_aTarget].blob.size)})`,'success');_afterBrandingPhoto();}\u001b[39m\n\u001b[31mfunction saveAnnot(){const cvs=document.getElementById('annot-cvs');cvs.toBlob(blob=>{brandings[_aTarget].blob=blob;brandings[_aTarget].prev=URL.createObjectURL(blob);document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo + markup saved (${fmtSz(blob.size)})`,'success');_afterBrandingPhoto();},'image/jpeg',0.88);}·\u001b[39m\n\u001b[31m// ── VIEW RECCE (read-only) ──────────────────────────────────\u001b[39m\n\u001b[31masync function viewRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  // Synced entries have a server-side rich report — open it directly\u001b[39m\n\u001b[31m  if(entry.viewUrl){window.open(entry.viewUrl,'_blank');return;}\u001b[39m\n\u001b[31m  // Offline / not-yet-synced fallback: generate from local base64 data\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  const ts=new Date(entry.timestamp).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'});·\u001b[39m\n\u001b[31m  async function b64ToUrl(b64){if(!b64)return'';try{const r=await fetch(b64);const bl=await r.blob();return URL.createObjectURL(bl);}catch{return'';}}·\u001b[39m\n\u001b[31m  const fvUrls=await Promise.all((d.frontPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const ivUrls=await Promise.all((d.insidePhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const brUrls=await Promise.all((d.brandings||[]).map(b=>b64ToUrl(b.photoB64)));\u001b[39m\n\u001b[31m  const adUrls=await Promise.all((d.addlPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const docUrl=await b64ToUrl(d.docB64);·\u001b[39m\n\u001b[31m  const brRows=(d.brandings||[]).map((b,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:16px;padding:12px;background:#f8fafc;border-radius:8px;border-left:3px solid #f97316\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-weight:600;font-size:14px;color:#0f172a;margin-bottom:6px\\\">${i+1}. ${b.type||'—'}: ${b.w||'?'}\\\"×${b.h||'?'}\\\" · Qty: ${b.qty||'?'} · ${b.sqft||'?'}</div>\u001b[39m\n\u001b[31m      ${brUrls[i]?`<img src=\\\"${brUrls[i]}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:6px\\\">`:'<div style=\\\"color:#94a3b8;font-size:12px\\\">No photo</div>'}\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  const html=`<!DOCTYPE html><html><head><meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m  <title>Recce — ${d.storeName||'Unknown'}</title>\u001b[39m\n\u001b[31m  <style>body{font-family:Arial,sans-serif;margin:0;padding:16px;background:#f1f5f9}\u001b[39m\n\u001b[31m  .card{background:#fff;border-radius:12px;padding:16px;margin-bottom:14px;box-shadow:0 1px 4px rgba(0,0,0,.08)}\u001b[39m\n\u001b[31m  h1{font-size:18px;color:#0f172a;margin:0 0 4px}h2{font-size:14px;color:#f97316;text-transform:uppercase;letter-spacing:.5px;margin:0 0 10px}\u001b[39m\n\u001b[31m  .meta{font-size:12px;color:#64748b;margin-bottom:12px}.photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}\u001b[39m\n\u001b[31m  img{width:100%;border-radius:8px;object-fit:cover}\u001b[39m\n\u001b[31m  .tag{display:inline-block;background:#0f172a;color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-right:4px}\u001b[39m\n\u001b[31m  @media print{body{background:#fff}.card{box-shadow:none}}</style></head><body>\u001b[39m\n\u001b[31m  <div class=\\\"card\\\">\u001b[39m\n\u001b[31m    <h1>${d.storeName||'Unknown Store'}</h1>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\"><span class=\\\"tag\\\">${d.brand||'No Brand'}</span>${d.address||''}</div>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\">📞 ${d.mobile||'—'} &nbsp;|&nbsp; 📅 ${d.date||'—'} &nbsp;|&nbsp; Submitted: ${ts}</div>\u001b[39m\n\u001b[31m    ${d.gpsCoords?`<div class=\\\"meta\\\">📍 ${d.gpsCoords.lat}, ${d.gpsCoords.lng} ±${d.gpsCoords.acc}m</div>`:''}\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${fvUrls.length?`<div class=\\\"card\\\"><h2>Front View Photos</h2><div class=\\\"photos\\\">${fvUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${ivUrls.length?`<div class=\\\"card\\\"><h2>Inside View Photos</h2><div class=\\\"photos\\\">${ivUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${d.hasVideo?`<div class=\\\"card\\\"><h2>Video</h2><div>${d.videoNote||'Video recorded'}</div></div>`:''}\u001b[39m\n\u001b[31m  ${(d.brandings||[]).length?`<div class=\\\"card\\\"><h2>Branding Items (${(d.brandings||[]).length})</h2>${brRows}</div>`:''}\u001b[39m\n\u001b[31m  ${adUrls.length?`<div class=\\\"card\\\"><h2>Additional Photos</h2><div class=\\\"photos\\\">${adUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${docUrl?`<div class=\\\"card\\\"><h2>Submission Document</h2><img src=\\\"${docUrl}\\\" style=\\\"width:100%;max-height:300px;object-fit:contain\\\"></div>`:''}\u001b[39m\n\u001b[31m  <div style=\\\"text-align:center;margin:16px 0\\\">\u001b[39m\n\u001b[31m    <button onclick=\\\"window.print()\\\" style=\\\"background:#f97316;color:#fff;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer\\\">🖨 Print / Save as PDF</button>\u001b[39m\n\u001b[31m    <button onclick=\\\"window.close()\\\" style=\\\"background:#e2e8f0;color:#475569;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer;margin-left:10px\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  </body></html>`;\u001b[39m\n\u001b[31m  const blob=new Blob([html],{type:'text/html'});\u001b[39m\n\u001b[31m  const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m  window.open(url,'_blank');\u001b[39m\n\u001b[31m  setTimeout(()=>URL.revokeObjectURL(url),30000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── EDIT OLD RECCE ───────────────────────────────────────────\u001b[39m\n\u001b[31masync function editRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=d.gpsCoords||null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  F.editingId=id;F.date=d.date||'';F.brand=d.brand||'';F.storeName=d.storeName||'';F.address=d.address||'';F.mobile=d.mobile||'';F.hasVideo=d.hasVideo;F.hasBranding=d.hasBranding;\u001b[39m\n\u001b[31m  async function b64ToBlob(b64){if(!b64)return null;try{const r=await fetch(b64);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m  toast('Loading recce data…','info');\u001b[39m\n\u001b[31m  for(const p of(d.frontPhotos||[])){const b=await b64ToBlob(p.b64);if(b)frontPhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const p of(d.insidePhotos||[])){const b=await b64ToBlob(p.b64);if(b)insidePhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const br of(d.brandings||[])){const b=await b64ToBlob(br.photoB64);brandings.push({type:br.type,w:br.w,h:br.h,qty:br.qty,blob:b,prev:b?URL.createObjectURL(b):null});}\u001b[39m\n\u001b[31m  for(const p of(d.addlPhotos||[])){const b=await b64ToBlob(p.b64);if(b)addlPhotos.push({blob:b,prev:URL.createObjectURL(b),desc:p.desc||''});}\u001b[39m\n\u001b[31m  if(d.docB64){const b=await b64ToBlob(d.docB64);if(b){submissionDoc=b;const sl=document.getElementById('doc-slot');sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${URL.createObjectURL(b)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}}\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  if(F.brand)document.getElementById('f-brand').value=F.brand;\u001b[39m\n\u001b[31m  if(F.storeName)document.getElementById('f-store').value=F.storeName;\u001b[39m\n\u001b[31m  if(F.address)document.getElementById('f-addr').value=F.address;\u001b[39m\n\u001b[31m  if(F.mobile)document.getElementById('f-mobile').value=F.mobile;\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();updAvailTag();\u001b[39m\n\u001b[31m  toast('Recce loaded — make changes and re-submit','success');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── EDIT REQUEST ────────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mlet _editReqSubId = null;·\u001b[39m\n\u001b[31mfunction _hydratePhotosFromRow(r) {\u001b[39m\n\u001b[31m  let pu={};\u001b[39m\n\u001b[31m  try{pu=typeof r.photo_urls==='string'?JSON.parse(r.photo_urls):(r.photo_urls||{});}catch(_){}\u001b[39m\n\u001b[31m  let meta={};\u001b[39m\n\u001b[31m  try{meta=typeof r.meta==='string'?JSON.parse(r.meta):(r.meta||{});}catch(_){}\u001b[39m\n\u001b[31m  frontPhotos =(pu.front   ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  insidePhotos=(pu.inside  ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  addlPhotos  =(pu.addl    ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,desc:''}));\u001b[39m\n\u001b[31m  brandings   =(meta.brandings||[]).map((b,i)=>({type:b.type,w:b.w,h:b.h,qty:b.qty,existingUrl:(pu.brandings||[])[i]||null,blob:null,prev:(pu.brandings||[])[i]||null}));\u001b[39m\n\u001b[31m  _docExistingUrl=pu.doc||null;\u001b[39m\n\u001b[31m  // Show retained doc in slot\u001b[39m\n\u001b[31m  const sl=document.getElementById('doc-slot');\u001b[39m\n\u001b[31m  if(sl&&_docExistingUrl){sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${_docExistingUrl}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openEditRequestModal(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  _editReqSubId = subId;\u001b[39m\n\u001b[31m  document.getElementById('er-store-name').textContent = r.store_name || 'Unknown';\u001b[39m\n\u001b[31m  document.getElementById('er-comment').value = '';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const assignBtn = document.getElementById('er-assign-btn');\u001b[39m\n\u001b[31m  if (r.submitted_by && r.submitted_by !== hub?.empId) {\u001b[39m\n\u001b[31m    assignBtn.textContent = `👤 Assign to ${r.submitted_by}`;\u001b[39m\n\u001b[31m    assignBtn.style.display = '';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    assignBtn.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeEditRequestModal() {\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _editReqSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorEditMyself() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  // Lock branding if client has reviewed (preserve their approval)\u001b[39m\n\u001b[31m  _brandingLocked = !!(r.client_status && r.client_status !== 'pending');\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function assignEditToCreator() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r || !r.submitted_by) { toast('No creator found for this recce', 'error'); return; }\u001b[39m\n\u001b[31m  const comment = (document.getElementById('er-comment').value || '').trim();\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        status: 'edit_requested',\u001b[39m\n\u001b[31m        edit_assigned_to: r.submitted_by,\u001b[39m\n\u001b[31m        edit_comment: comment || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!resp.ok) throw new Error('Update failed: ' + resp.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].status = 'edit_requested';\u001b[39m\n\u001b[31m      _adminRows[idx].edit_assigned_to = r.submitted_by;\u001b[39m\n\u001b[31m      _adminRows[idx].edit_comment = comment || null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Push notification to creator\u001b[39m\n\u001b[31m    const notifBody = comment || `Please review and re-submit: ${r.store_name || 'your recce'}`;\u001b[39m\n\u001b[31m    fetch('/push-server/notify', {\u001b[39m\n\u001b[31m      method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        user_id: r.submitted_by, title: '✏ Edit Requested',\u001b[39m\n\u001b[31m        body: notifBody, tag: `recce-edit-${subId}`, url: '/recce/',\u001b[39m\n\u001b[31m        icon: '/hub/icons/icon-192.png', badge: '/hub/icons/icon-192.png',\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    }).catch(() => {});\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast(`Edit assigned to ${r.submitted_by} ✓`, 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Assign failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function startCreatorEdit(subId) {\u001b[39m\n\u001b[31m  // Try local IndexedDB first (has photos)\u001b[39m\n\u001b[31m  const local = await dbGet('subs', subId);\u001b[39m\n\u001b[31m  if (local) { await editRecce(subId); return; }\u001b[39m\n\u001b[31m  // Fallback: load text fields from server row\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId)\u001b[39m\n\u001b[31m         || (await (async () => {\u001b[39m\n\u001b[31m              try {\u001b[39m\n\u001b[31m                const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, { headers: _RC_READ });\u001b[39m\n\u001b[31m                if (resp.ok) { const arr = await resp.json(); return arr[0]; }\u001b[39m\n\u001b[31m              } catch(_) {} return null;\u001b[39m\n\u001b[31m            })());\u001b[39m\n\u001b[31m  if (!r) { toast('Record not found', 'error'); return; }\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── End edit request ─────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mfunction goToHub() { window.location.href = '/hub/'; }\u001b[39m\n\u001b[31mfunction recceLogout() {\u001b[39m\n\u001b[31m  if (!confirm('Log out?')) return;\u001b[39m\n\u001b[31m  localStorage.removeItem('lm360-session');\u001b[39m\n\u001b[31m  localStorage.removeItem('360exp-session');\u001b[39m\n\u001b[31m  window.location.href = '/hub/';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction injectHubButtons() {\u001b[39m\n\u001b[31m  const u = _recceHubUser();\u001b[39m\n\u001b[31m  const name = u ? (u.name || '') : '';\u001b[39m\n\u001b[31m  if (name) {\u001b[39m\n\u001b[31m    const bar = document.getElementById('recce-hero-ubar');\u001b[39m\n\u001b[31m    const nm  = document.getElementById('recce-hero-name');\u001b[39m\n\u001b[31m    if (bar) { nm.textContent = name; bar.style.display = 'flex'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.querySelectorAll('.hdr').forEach(hdr => {\u001b[39m\n\u001b[31m    const r = document.createElement('div');\u001b[39m\n\u001b[31m    r.className = 'hdr-r';\u001b[39m\n\u001b[31m    if (name) {\u001b[39m\n\u001b[31m      const un = document.createElement('span');\u001b[39m\n\u001b[31m      un.className = 'hdr-user';\u001b[39m\n\u001b[31m      un.textContent = name;\u001b[39m\n\u001b[31m      r.appendChild(un);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    const hub = document.createElement('button');\u001b[39m\n\u001b[31m    hub.className = 'btn-hub';\u001b[39m\n\u001b[31m    hub.innerHTML = '🏡 Hub';\u001b[39m\n\u001b[31m    hub.addEventListener('click', goToHub);\u001b[39m\n\u001b[31m    r.appendChild(hub);\u001b[39m\n\u001b[31m    const lo = document.createElement('button');\u001b[39m\n\u001b[31m    lo.className = 'btn-logout';\u001b[39m\n\u001b[31m    lo.textContent = 'Logout';\u001b[39m\n\u001b[31m    lo.addEventListener('click', recceLogout);\u001b[39m\n\u001b[31m    r.appendChild(lo);\u001b[39m\n\u001b[31m    hdr.appendChild(r);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction checkAppUpdate(){\u001b[39m\n\u001b[31m  const seen=localStorage.getItem('recce-ver-seen');\u001b[39m\n\u001b[31m  localStorage.setItem('recce-ver-seen',CACHE_VER);\u001b[39m\n\u001b[31m  if(seen&&seen!==CACHE_VER){\u001b[39m\n\u001b[31m    const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m    if(b){b.classList.add('show');setTimeout(()=>b.classList.remove('show'),5000);}\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction dismissUpdateBanner(){\u001b[39m\n\u001b[31m  const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m  if(b)b.classList.remove('show');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function init(){\u001b[39m\n\u001b[31m  // Detect host banners (tiiny.host, etc) and raise bnav above them\u001b[39m\n\u001b[31m  (function detectHostBar(){\u001b[39m\n\u001b[31m    const h=window.location.hostname;\u001b[39m\n\u001b[31m    let extra=0;\u001b[39m\n\u001b[31m    if(h.includes('tiiny'))extra=58;\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // Generic detection: check if window is shorter than expected (host injected a bar)\u001b[39m\n\u001b[31m      const gap=screen.height - window.innerHeight;\u001b[39m\n\u001b[31m      if(gap>100&&gap<200)extra=58; // a fixed bar is roughly 56-60px\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if(extra>0){\u001b[39m\n\u001b[31m      document.documentElement.style.setProperty('--host-bar',extra+'px');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  })();\u001b[39m\n\u001b[31m  setLang(LANG);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m  checkAppUpdate();\u001b[39m\n\u001b[31m  await loadRecceCfg();\u001b[39m\n\u001b[31m  _checkAccessMode();\u001b[39m\n\u001b[31m  await initDB();await loadSettings();await loadHome();await checkDraft();netStatus();window.addEventListener('online',()=>{netStatus();syncNow();});window.addEventListener('offline',netStatus);injectHubButtons();document.getElementById('today-date').textContent=new Date().toLocaleDateString('en-IN',{weekday:'long',day:'numeric',month:'long',year:'numeric'});updAvailTag();\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m  // Auto-fetch stores from server on every startup (uses default Netlify URL if none saved)\u001b[39m\n\u001b[31m  const su=(await cfg('srv-url'))||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su&&navigator.onLine){\u001b[39m\n\u001b[31m    fetch(su).then(r=>r.json()).then(async j=>{\u001b[39m\n\u001b[31m      const d=Array.isArray(j)?j:j.stores||[];\u001b[39m\n\u001b[31m      if(d.length){stores=d;await cfg('stores',JSON.stringify(d));await cfg('srv-url',su);updAvailTag();\u001b[39m\n\u001b[31m        document.getElementById('srv-url').value=su;}\u001b[39m\n\u001b[31m    }).catch(()=>{});\u001b[39m\n\u001b[31m  }}init();\u001b[39m\n\u001b[31m</script>\u001b[39m\n\u001b[31m</body>\u001b[39m\n\u001b[31m</html>\u001b[39m\n\u001b[31m\"\u001b[39m\n    at /var/www/360lm/tests/recce.spec.js:337:17",
                        "location": {
                          "file": "/var/www/360lm/tests/recce.spec.js",
                          "column": 17,
                          "line": 337
                        },
                        "snippet": "  335 |     const resp = await page.request.get(BASE_URL);\n  336 |     const src = await resp.text();\n> 337 |     expect(src).toContain('recce-v15');\n      |                 ^\n  338 |     expect(src).not.toContain('recce-v14');\n  339 |   });\n  340 | });"
                      },
                      "errors": [
                        {
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "column": 17,
                            "line": 337
                          },
                          "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoContain\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // indexOf\u001b[22m\n\nExpected substring: \u001b[32m\"recce-v15\"\u001b[39m\nReceived string:    \u001b[31m\"<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\">\u001b[39m\n\u001b[31m<head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\">\u001b[39m\n\u001b[31m<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\\\">\u001b[39m\n\u001b[31m<meta name=\\\"theme-color\\\" content=\\\"#0f172a\\\">\u001b[39m\n\u001b[31m<meta name=\\\"apple-mobile-web-app-capable\\\" content=\\\"yes\\\">\u001b[39m\n\u001b[31m<title>Branding Recce</title>\u001b[39m\n\u001b[31m<link rel=\\\"manifest\\\" href=\\\"manifest.json\\\">\u001b[39m\n\u001b[31m<link rel=\\\"preconnect\\\" href=\\\"https://fonts.googleapis.com\\\">\u001b[39m\n\u001b[31m<link href=\\\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap\\\" rel=\\\"stylesheet\\\">\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--nv:#0f172a;--nv2:#1e293b;--or:#f97316;--orl:#fed7aa;--gn:#16a34a;--rd:#dc2626;--am:#d97706;--g50:#f8fafc;--g100:#f1f5f9;--g200:#e2e8f0;--g300:#cbd5e1;--g400:#94a3b8;--g500:#64748b;--g600:#475569;--r:12px;--rs:8px;--sh:0 1px 3px rgba(0,0,0,.1),0 1px 2px rgba(0,0,0,.06);--bnav-h:72px;--host-bar:0px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}\u001b[39m\n\u001b[31mbody{font-family:'DM Sans',sans-serif;background:var(--g50);color:var(--nv);min-height:100vh;overflow-x:hidden}\u001b[39m\n\u001b[31m.hdr{background:var(--nv);color:#fff;padding:0 16px;height:56px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}\u001b[39m\n\u001b[31m.hdr-l{display:flex;align-items:center;gap:10px}\u001b[39m\n\u001b[31m.hdr-title{font-size:16px;font-weight:600}.hdr-sub{font-size:11px;color:var(--g400)}\u001b[39m\n\u001b[31m.back-btn,.icon-btn{background:none;border:none;color:#fff;padding:8px;cursor:pointer;display:flex;align-items:center}\u001b[39m\n\u001b[31m.back-btn{margin-left:-8px}\u001b[39m\n\u001b[31m.pgbar{height:3px;background:var(--g200)}.pgfill{height:100%;background:var(--or);transition:width .3s}\u001b[39m\n\u001b[31m.view{display:none;min-height:calc(100vh - 56px);padding-bottom:calc(var(--bnav-h) + var(--host-bar) + 24px)}.view.active{display:block}\u001b[39m\n\u001b[31m.content{padding:16px}\u001b[39m\n\u001b[31m.card{background:#fff;border-radius:var(--r);padding:16px;box-shadow:var(--sh);margin-bottom:12px}\u001b[39m\n\u001b[31m.card-title{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;letter-spacing:.6px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between}\u001b[39m\n\u001b[31m.cnt-badge{background:var(--or);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;min-width:22px;text-align:center}\u001b[39m\n\u001b[31m.cnt-badge.gray{background:var(--g400)}\u001b[39m\n\u001b[31m.field{margin-bottom:16px}.field:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.field label{display:block;font-size:13px;font-weight:500;color:var(--g600);margin-bottom:6px}\u001b[39m\n\u001b[31m.req{color:var(--or);margin-left:2px}\u001b[39m\n\u001b[31m.field input,.field select,.field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;color:var(--nv);background:#fff;transition:border-color .15s;-webkit-appearance:none;appearance:none}\u001b[39m\n\u001b[31m.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--or)}\u001b[39m\n\u001b[31m.field input:read-only{background:var(--g50);color:var(--g600)}\u001b[39m\n\u001b[31m.field textarea{resize:vertical;min-height:68px}\u001b[39m\n\u001b[31m.field select{background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}\u001b[39m\n\u001b[31m.pslot{border:2px dashed var(--g300);border-radius:var(--r);min-height:110px;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:all .15s;position:relative;overflow:hidden;text-align:center;padding:16px}\u001b[39m\n\u001b[31m.pslot:active{border-color:var(--or);background:var(--g50)}\u001b[39m\n\u001b[31m.pslot.filled{border-style:solid;border-color:var(--or);padding:0;min-height:0}\u001b[39m\n\u001b[31m.pslot img{width:100%;height:150px;object-fit:cover;border-radius:calc(var(--r) - 2px);display:block}\u001b[39m\n\u001b[31m.pslot-lbl{font-size:13px;color:var(--g400);margin-top:6px}.pslot-ico{font-size:28px;color:var(--g300)}\u001b[39m\n\u001b[31m.pbadge{position:absolute;bottom:6px;right:6px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.premove{position:absolute;top:6px;right:6px;background:var(--rd);color:#fff;border:none;border-radius:50%;width:26px;height:26px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;z-index:5}\u001b[39m\n\u001b[31minput[type=file]{display:none}\u001b[39m\n\u001b[31m.rgroup{display:flex;gap:10px}\u001b[39m\n\u001b[31m.rbtn{flex:1;padding:13px;border:1.5px solid var(--g200);border-radius:var(--rs);text-align:center;cursor:pointer;font-size:14px;font-weight:500;color:var(--g500);transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.rbtn.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.chip-grid{display:flex;flex-wrap:wrap;gap:8px}\u001b[39m\n\u001b[31m.chip{padding:7px 12px;border:1.5px solid var(--g200);border-radius:20px;font-size:13px;color:var(--g600);cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.chip.sel{border-color:var(--or);background:var(--or);color:#fff}\u001b[39m\n\u001b[31m.brand-chip{display:flex;align-items:center;gap:6px;padding:5px 12px}\u001b[39m\n\u001b[31m.brand-chip-logo{width:28px;height:18px;object-fit:contain;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{display:block;width:100%;padding:15px;background:var(--or);color:#fff;border:none;border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:700;cursor:pointer;text-align:center;transition:background .15s}\u001b[39m\n\u001b[31m.btn-p:active{background:#ea6c05}.btn-p:disabled{background:var(--g300);cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-s{display:block;width:100%;padding:14px;background:#fff;color:var(--nv);border:1.5px solid var(--g200);border-radius:var(--r);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:500;cursor:pointer;text-align:center}\u001b[39m\n\u001b[31m.btn-s:active{background:var(--g100)}\u001b[39m\n\u001b[31m.btn-o{display:inline-flex;align-items:center;gap:6px;padding:10px 16px;background:#fff;color:var(--or);border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer}\u001b[39m\n\u001b[31m.btn-o:active{background:var(--orl)}\u001b[39m\n\u001b[31m.btn-d{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;background:#fff;color:var(--rd);border:1.5px solid #fecaca;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:12px;cursor:pointer}\u001b[39m\n\u001b[31m.bnav{position:fixed;bottom:var(--host-bar);left:0;right:0;background:#fff;border-top:1px solid var(--g200);display:flex;padding:10px 16px;gap:10px;z-index:100}\u001b[39m\n\u001b[31m.hero{background:var(--nv);color:#fff;padding:20px 16px 24px}\u001b[39m\n\u001b[31m.hero-title{font-size:22px;font-weight:700;margin-bottom:2px}.hero-sub{font-size:13px;color:var(--g400)}\u001b[39m\n\u001b[31m.stats{display:flex;gap:10px;margin-top:16px}\u001b[39m\n\u001b[31m.scard{flex:1;background:rgba(255,255,255,.08);border-radius:var(--rs);padding:12px;text-align:center}\u001b[39m\n\u001b[31m.snum{font-size:22px;font-weight:700}.slbl{font-size:11px;color:var(--g400);margin-top:2px}\u001b[39m\n\u001b[31m.scard.g .snum{color:#4ade80}.scard.a .snum{color:#fbbf24}\u001b[39m\n\u001b[31m.new-btn{background:var(--or);color:#fff;border:none;border-radius:var(--r);padding:16px;font-family:'DM Sans',sans-serif;font-size:16px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:10px;cursor:pointer;width:100%;margin-bottom:10px}\u001b[39m\n\u001b[31m.new-btn:active{background:#ea6c05}\u001b[39m\n\u001b[31m.resume-btn{background:var(--nv2);color:#fff;border:none;border-radius:var(--r);padding:13px 16px;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:500;display:flex;align-items:center;justify-content:space-between;cursor:pointer;width:100%;margin-bottom:18px}\u001b[39m\n\u001b[31m.sub-card{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:10px;display:flex;align-items:center;gap:12px}\u001b[39m\n\u001b[31m.sub-ico{width:40px;height:40px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}\u001b[39m\n\u001b[31m.sub-ico.pending{background:#fef3c7}.sub-ico.synced{background:#dcfce7}.sub-ico.failed{background:#fee2e2}\u001b[39m\n\u001b[31m.sub-meta{flex:1;min-width:0}.sub-name{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.sub-dtl{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.sbadge{font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;flex-shrink:0}\u001b[39m\n\u001b[31m.sbadge.pending{background:#fef3c7;color:#92400e}.sbadge.synced{background:#dcfce7;color:#14532d}.sbadge.failed{background:#fee2e2;color:#991b1b}\u001b[39m\n\u001b[31m.sh{display:flex;align-items:center;justify-content:space-between;margin:20px 0 12px}\u001b[39m\n\u001b[31m.st{font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.toast{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 8px);left:16px;right:16px;background:var(--nv);color:#fff;padding:12px 16px;border-radius:var(--r);font-size:14px;z-index:1000;transform:translateY(120px);opacity:0;transition:all .3s;pointer-events:none}\u001b[39m\n\u001b[31m.toast.show{transform:translateY(0);opacity:1}.toast.success{background:#16a34a}.toast.error{background:var(--rd)}.toast.info{background:var(--nv2)}\u001b[39m\n\u001b[31m.srow{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:#fff;border-top:1px solid var(--g100);font-size:12px;color:var(--g500)}\u001b[39m\n\u001b[31m.sdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px}.sdot.on{background:var(--gn)}.sdot.off{background:var(--g300)}\u001b[39m\n\u001b[31m.set-item{background:#fff;border-radius:var(--r);padding:14px 16px;box-shadow:var(--sh);margin-bottom:8px}\u001b[39m\n\u001b[31m.set-lbl{font-size:14px;font-weight:600;color:var(--nv);margin-bottom:4px}\u001b[39m\n\u001b[31m.set-sub{font-size:12px;color:var(--g500);margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem{background:#fff;border-radius:var(--r);border:1.5px solid var(--g200);padding:14px;margin-bottom:10px}\u001b[39m\n\u001b[31m.bitem-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\u001b[39m\n\u001b[31m.bitem-title{font-size:14px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.dim-row{display:flex;gap:8px}.dim-row .field{flex:1}\u001b[39m\n\u001b[31m.sqft{display:inline-block;background:var(--g100);color:var(--g600);font-size:12px;padding:4px 10px;border-radius:20px;margin-top:6px}\u001b[39m\n\u001b[31m.divider{height:1px;background:var(--g100);margin:12px 0}\u001b[39m\n\u001b[31m.rev-lbl{font-size:12px;color:var(--g500);margin-bottom:2px}\u001b[39m\n\u001b[31m.rev-val{font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.rev-photos{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}\u001b[39m\n\u001b[31m.rev-thumb{width:56px;height:56px;object-fit:cover;border-radius:var(--rs)}\u001b[39m\n\u001b[31m.empty{text-align:center;padding:40px 20px;color:var(--g400)}.empty-ico{font-size:40px;margin-bottom:12px}.empty-txt{font-size:14px}\u001b[39m\n\u001b[31m/* store picker */\u001b[39m\n\u001b[31m.store-card{border:1.5px solid var(--g200);border-radius:var(--rs);padding:13px 14px;background:#fff;position:relative;cursor:pointer}\u001b[39m\n\u001b[31m.store-card:active{background:var(--g50)}\u001b[39m\n\u001b[31m.store-card-name{font-size:15px;font-weight:600;color:var(--nv)}\u001b[39m\n\u001b[31m.store-card-meta{font-size:13px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.store-card-change{position:absolute;top:11px;right:12px;background:none;border:none;color:var(--or);font-family:'DM Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer}\u001b[39m\n\u001b[31m.brand-tag{display:inline-block;background:var(--nv);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-top:4px}\u001b[39m\n\u001b[31m.last-chip{display:inline-flex;align-items:center;gap:4px;background:#fef3c7;color:#92400e;font-size:11px;font-weight:500;padding:3px 9px;border-radius:20px;margin-left:6px}\u001b[39m\n\u001b[31m.pick-trigger{border:2px solid var(--or);border-radius:var(--rs);padding:14px 16px;background:#fff7ed;display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-size:15px;font-weight:600;color:var(--or)}\u001b[39m\n\u001b[31m.pick-trigger:active{background:#ffedd5;border-color:#ea6800}\u001b[39m\n\u001b[31m.manual-toggle{display:flex;align-items:center;gap:8px;padding:10px 14px;border:1.5px dashed var(--g300);border-radius:var(--rs);cursor:pointer;font-size:13px;color:var(--g600);margin-top:8px;user-select:none}\u001b[39m\n\u001b[31m/* client chip grid */\u001b[39m\n\u001b[31m.cl-chip-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}\u001b[39m\n\u001b[31m.cl-chip{padding:8px 14px;border-radius:20px;border:1.5px solid var(--g200);font-size:13px;font-weight:500;color:var(--g600);background:#fff;cursor:pointer;transition:all .15s;user-select:none}\u001b[39m\n\u001b[31m.cl-chip:active,.cl-chip.sel{background:var(--or);border-color:var(--or);color:#fff;font-weight:600}\u001b[39m\n\u001b[31m.cl-chip-other{border-style:dashed}\u001b[39m\n\u001b[31m.client-tag{display:inline-block;background:#e0f2fe;color:#0369a1;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-left:4px}\u001b[39m\n\u001b[31m.manual-toggle.on{border-color:var(--or);background:#fff7ed;color:var(--or)}\u001b[39m\n\u001b[31m/* picker overlay */\u001b[39m\n\u001b[31m.povl{display:none;position:fixed;inset:0;background:var(--g50);z-index:200;flex-direction:column}\u001b[39m\n\u001b[31m.povl.open{display:flex}\u001b[39m\n\u001b[31m.povl-hdr{background:var(--nv);padding:12px 16px;display:flex;align-items:center;gap:12px;flex-shrink:0}\u001b[39m\n\u001b[31m.psearch{flex:1;padding:10px 14px;border:none;border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;background:rgba(255,255,255,.12);color:#fff;outline:none}\u001b[39m\n\u001b[31m.psearch::placeholder{color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.pcancel{background:none;border:none;color:rgba(255,255,255,.7);font-family:'DM Sans',sans-serif;font-size:14px;cursor:pointer;padding:4px;white-space:nowrap}\u001b[39m\n\u001b[31m.plist{overflow-y:auto;flex:1}\u001b[39m\n\u001b[31m.pitem{padding:14px 16px;border-bottom:.5px solid var(--g100);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px}\u001b[39m\n\u001b[31m.pitem:active{background:var(--g100)}\u001b[39m\n\u001b[31m.pi-name{font-size:15px;font-weight:600;color:var(--nv)}.pi-addr{font-size:12px;color:var(--g500);margin-top:2px}.pi-last{font-size:11px;color:var(--am);margin-top:2px}\u001b[39m\n\u001b[31m.pi-brand{font-size:11px;font-weight:700;padding:3px 8px;border-radius:20px;background:var(--nv);color:#fff;flex-shrink:0}\u001b[39m\n\u001b[31m.psec{padding:8px 16px 4px;font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;background:var(--g50)}\u001b[39m\n\u001b[31m.padd{padding:16px;text-align:center;font-size:14px;color:var(--or);font-weight:600;cursor:pointer;background:#fff7ed;border-top:1.5px dashed var(--or)}\u001b[39m\n\u001b[31m.gps-row{display:flex;gap:8px;margin-top:8px}\u001b[39m\n\u001b[31m.gps-btn{flex-shrink:0;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs);cursor:pointer;font-family:'DM Sans',sans-serif;font-size:13px;color:var(--g500);display:flex;align-items:center;gap:6px}\u001b[39m\n\u001b[31m.gps-btn:active{background:var(--orl);border-color:var(--or);color:var(--or)}\u001b[39m\n\u001b[31m@keyframes spin{to{transform:rotate(360deg)}}.spin{animation:spin .7s linear infinite;display:inline-block}\u001b[39m\n\u001b[31m/* ANNOTATION TOOL */\u001b[39m\n\u001b[31m.annot-modal{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column}\u001b[39m\n\u001b[31m.annot-modal.open{display:flex}\u001b[39m\n\u001b[31m.annot-bar{background:var(--nv);padding:8px 12px;flex-shrink:0}\u001b[39m\n\u001b[31m.annot-row{display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap}\u001b[39m\n\u001b[31m.annot-row:last-child{margin-bottom:0}\u001b[39m\n\u001b[31m.atool{padding:6px 10px;background:rgba(255,255,255,.1);border:1.5px solid rgba(255,255,255,.2);border-radius:var(--rs);color:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:500;cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.atool.on{background:var(--or);border-color:var(--or)}\u001b[39m\n\u001b[31m.atool.sel-on{background:#7c3aed;border-color:#7c3aed}\u001b[39m\n\u001b[31m.acolor{width:24px;height:24px;border-radius:50%;border:2px solid rgba(255,255,255,.3);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.acolor.on{border-color:#fff;border-width:3px;transform:scale(1.15)}\u001b[39m\n\u001b[31m.annot-cvs-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#111;position:relative}\u001b[39m\n\u001b[31m#annot-cvs{max-width:100%;max-height:100%;display:block;touch-action:none;cursor:crosshair}\u001b[39m\n\u001b[31m.annot-foot{background:var(--nv);padding:10px 16px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.req-note{font-size:12px;color:var(--rd);margin-top:6px;font-weight:500}\u001b[39m\n\u001b[31m/* Bottom dialog */\u001b[39m\n\u001b[31m.bdialog-wrap{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:400;align-items:flex-end}\u001b[39m\n\u001b[31m.bdialog-wrap.open{display:flex}\u001b[39m\n\u001b[31m.bdialog{background:#fff;border-radius:var(--r) var(--r) 0 0;padding:20px 16px 32px;width:100%}\u001b[39m\n\u001b[31m.bdialog-title{font-size:16px;font-weight:700;color:var(--nv);margin-bottom:6px}\u001b[39m\n\u001b[31m.bdialog-sub{font-size:13px;color:var(--g500);margin-bottom:16px}\u001b[39m\n\u001b[31m.bdialog-btns{display:flex;gap:10px}\u001b[39m\n\u001b[31m/* Edit badge on sub-card */\u001b[39m\n\u001b[31m.edit-btn-sm{padding:5px 12px;background:var(--g50);border:1px solid var(--g200);border-radius:20px;font-family:'DM Sans',sans-serif;font-size:12px;color:var(--g600);cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m/* Toggle switch */\u001b[39m\n\u001b[31m.tog{width:48px;height:26px;background:var(--g300);border-radius:13px;cursor:pointer;transition:background .2s;flex-shrink:0;position:relative;display:inline-block}\u001b[39m\n\u001b[31m.tog.on{background:var(--or)}\u001b[39m\n\u001b[31m.tog-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2);pointer-events:none}\u001b[39m\n\u001b[31m.tog.on .tog-knob{transform:translateX(22px)}\u001b[39m\n\u001b[31m/* ── ADMIN RECCE VIEW ── */\u001b[39m\n\u001b[31m.af-bar{background:var(--g100);padding:10px 16px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--g200);overflow:hidden}\u001b[39m\n\u001b[31m.af-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}\u001b[39m\n\u001b[31m.af-sel{width:100%;padding:8px 10px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv);cursor:pointer;\u001b[39m\n\u001b[31m  white-space:normal;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.af-sel:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.af-inp{width:100%;padding:8px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);\u001b[39m\n\u001b[31m  font-family:'DM Sans',sans-serif;font-size:13px;background:#fff;color:var(--nv)}\u001b[39m\n\u001b[31m.af-inp:focus{border-color:var(--or);outline:none}\u001b[39m\n\u001b[31m.grp-hdr{font-size:11px;font-weight:700;color:var(--g500);text-transform:uppercase;\u001b[39m\n\u001b[31m  letter-spacing:.5px;padding:14px 0 6px;border-bottom:1px solid var(--g200);margin-bottom:6px}\u001b[39m\n\u001b[31m.grp-hdr:first-child{padding-top:0}\u001b[39m\n\u001b[31m.asc{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:12px 14px;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;gap:6px;margin-bottom:8px;cursor:pointer;\u001b[39m\n\u001b[31m  transition:box-shadow .15s}\u001b[39m\n\u001b[31m.asc:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.asc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}\u001b[39m\n\u001b[31m.asc-name{font-size:14px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.asc-brand{display:inline-block;background:#fff7ed;color:var(--or);font-size:11px;\u001b[39m\n\u001b[31m  font-weight:600;padding:2px 8px;border-radius:20px;border:1px solid #fed7aa;white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chip{background:var(--g100);border-radius:20px;padding:2px 8px;font-size:11px;color:var(--g600);white-space:nowrap}\u001b[39m\n\u001b[31m.asc-chips{display:flex;flex-wrap:wrap;gap:5px}\u001b[39m\n\u001b[31m.asc-agent{background:var(--nv);color:#fff;font-size:11px;font-weight:600;\u001b[39m\n\u001b[31m  padding:2px 8px;border-radius:20px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m/* Admin detail modal */\u001b[39m\n\u001b[31m.ardl-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:600;\u001b[39m\n\u001b[31m  display:flex;align-items:flex-end;justify-content:center}\u001b[39m\n\u001b[31m.ardl-box{background:#fff;border-radius:var(--r) var(--r) 0 0;width:100%;max-height:80vh;\u001b[39m\n\u001b[31m  display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ardl-hdr{display:flex;align-items:flex-start;justify-content:space-between;\u001b[39m\n\u001b[31m  padding:16px 16px 10px;border-bottom:1px solid var(--g200);gap:10px}\u001b[39m\n\u001b[31m.ardl-title{font-size:17px;font-weight:700;color:var(--nv);line-height:1.3}\u001b[39m\n\u001b[31m.ardl-body{flex:1;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:14px}\u001b[39m\n\u001b[31m.ardl-sec{display:flex;flex-direction:column;gap:6px}\u001b[39m\n\u001b[31m.ardl-lbl{font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px}\u001b[39m\n\u001b[31m.ardl-val{font-size:13px;color:var(--nv);line-height:1.5}\u001b[39m\n\u001b[31m.ardl-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\u001b[39m\n\u001b[31m/* Hub home button */\u001b[39m\n\u001b[31m.btn-hub{background:none;border:1px solid rgba(255,255,255,.25);color:rgba(255,255,255,.85);\u001b[39m\n\u001b[31m  font-size:12px;font-weight:600;padding:4px 10px;border-radius:20px;cursor:pointer;\u001b[39m\n\u001b[31m  display:flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-hub:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hdr-r{display:flex;align-items:center;gap:6px;margin-left:auto;flex-shrink:0}\u001b[39m\n\u001b[31m.hdr-user{font-size:11px;color:rgba(255,255,255,.7);white-space:nowrap;max-width:80px;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.btn-logout{background:none;border:1px solid rgba(255,255,255,.2);color:rgba(255,255,255,.7);font-size:11px;font-weight:600;padding:4px 8px;border-radius:20px;cursor:pointer;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-logout:active{background:rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.hero-ubar{display:flex;align-items:center;justify-content:space-between;padding-top:6px;margin-top:2px}\u001b[39m\n\u001b[31m.hero-uname{font-size:12px;color:rgba(255,255,255,.65)}\u001b[39m\n\u001b[31m.hi-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .en-txt{display:none}\u001b[39m\n\u001b[31mbody.lang-hi .hi-txt{display:inline}\u001b[39m\n\u001b[31m.lang-btn{background:none;border:1px solid rgba(255,255,255,.3);color:rgba(255,255,255,.8);font-size:12px;font-weight:700;padding:4px 10px;border-radius:20px;cursor:pointer;display:flex;align-items:center;gap:3px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.lang-btn:active{background:rgba(255,255,255,.15)}\u001b[39m\n\u001b[31m/* ── DELETE / AUDIT ── */\u001b[39m\n\u001b[31m.del-btn{background:none;border:none;padding:6px 8px;cursor:pointer;color:var(--g400);font-size:16px;flex-shrink:0;border-radius:var(--rs);transition:color .15s,background .15s}\u001b[39m\n\u001b[31m.del-btn:active{color:var(--rd);background:#fee2e2}\u001b[39m\n\u001b[31m.asc.deleted-row{background:#fff5f5;border:1px solid #fecaca;opacity:.85}\u001b[39m\n\u001b[31m.asc.deleted-row .asc-name{text-decoration:line-through;color:var(--g500)}\u001b[39m\n\u001b[31m.del-reason-tag{display:inline-block;background:#fee2e2;color:var(--rd);font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px}\u001b[39m\n\u001b[31m.del-by-txt{font-size:11px;color:var(--g400);margin-top:3px}\u001b[39m\n\u001b[31m.restore-btn{background:none;border:1.5px solid #bbf7d0;border-radius:20px;color:#16a34a;font-size:11px;font-weight:700;padding:3px 10px;cursor:pointer;white-space:nowrap;margin-top:5px}\u001b[39m\n\u001b[31m.restore-btn:active{background:#dcfce7}\u001b[39m\n\u001b[31m.sup-tile{background:#fff;border-radius:var(--r);box-shadow:var(--sh);padding:20px 16px;cursor:pointer;display:flex;align-items:center;gap:14px;margin-bottom:12px;transition:box-shadow .15s}\u001b[39m\n\u001b[31m.sup-tile:active{box-shadow:0 0 0 2px var(--or)}\u001b[39m\n\u001b[31m.sup-tile-ico{width:48px;height:48px;border-radius:var(--rs);display:flex;align-items:center;justify-content:center;font-size:26px;flex-shrink:0}\u001b[39m\n\u001b[31m.sup-tile-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.sup-tile-title{font-size:15px;font-weight:700;color:var(--nv)}\u001b[39m\n\u001b[31m.sup-tile-sub{font-size:12px;color:var(--g500);margin-top:3px}\u001b[39m\n\u001b[31m.del-toggle-btn{padding:6px 14px;border:1.5px solid var(--g200);border-radius:20px;background:#fff;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:600;color:var(--g500);cursor:pointer;white-space:nowrap}\u001b[39m\n\u001b[31m.del-toggle-btn.active{background:#fee2e2;border-color:#fecaca;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1.5px solid var(--g200);border-radius:var(--r);margin-bottom:10px;cursor:pointer;transition:all .15s;font-size:14px;font-weight:500;color:var(--nv)}\u001b[39m\n\u001b[31m.reason-opt:active{background:var(--g50)}\u001b[39m\n\u001b[31m.reason-opt.sel{border-color:var(--rd);background:#fff5f5;color:var(--rd)}\u001b[39m\n\u001b[31m.reason-opt.danger{border-color:#fdba74;background:#fff7ed;color:#9a3412}\u001b[39m\n\u001b[31m.reason-opt.danger.sel{border-color:#c2410c;background:#fff1e6;color:#9a3412}\u001b[39m\n\u001b[31m#del-confirm-btn.no-reason{background:var(--g300)!important;cursor:default}\u001b[39m\n\u001b[31m@keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}\u001b[39m\n\u001b[31m.reason-opt-ico{font-size:22px;flex-shrink:0}\u001b[39m\n\u001b[31m/* ── APP UPDATE BANNER ── */\u001b[39m\n\u001b[31m.upd-banner{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);left:12px;right:12px;background:#16a34a;color:#fff;padding:11px 14px;border-radius:var(--r);display:flex;align-items:center;justify-content:space-between;gap:10px;z-index:550;box-shadow:0 4px 16px rgba(0,0,0,.18);transform:translateY(120px);opacity:0;transition:transform .35s ease,opacity .35s ease;pointer-events:none}\u001b[39m\n\u001b[31m.upd-banner.show{transform:translateY(0);opacity:1;pointer-events:auto}\u001b[39m\n\u001b[31m/* ── EDIT REQUEST ── */\u001b[39m\n\u001b[31m.req-edit-btn{padding:4px 10px;background:#fffbeb;border:1px solid #fde68a;border-radius:20px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:600;color:#92400e;cursor:pointer;flex-shrink:0}\u001b[39m\n\u001b[31m.req-edit-btn:active{background:#fef3c7}\u001b[39m\n\u001b[31m.edit-req-badge{display:inline-block;background:#fef3c7;color:#92400e;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;white-space:nowrap}\u001b[39m\n\u001b[31m.edit-req-card{background:#fffbeb;border:1.5px solid #fde68a;border-radius:var(--r);padding:14px 16px;margin-bottom:10px;display:flex;align-items:flex-start;gap:12px}\u001b[39m\n\u001b[31m.edit-req-card-body{flex:1;min-width:0}\u001b[39m\n\u001b[31m.edit-req-card-name{font-size:14px;font-weight:600;color:var(--nv);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\u001b[39m\n\u001b[31m.edit-req-card-meta{font-size:12px;color:var(--g500);margin-top:2px}\u001b[39m\n\u001b[31m.edit-req-cmt{font-size:12px;color:#78350f;background:#fff;border:1px solid #fde68a;border-radius:var(--rs);padding:8px 10px;margin-top:8px;line-height:1.5}\u001b[39m\n\u001b[31m.edit-req-section-hdr{font-size:11px;font-weight:700;color:#92400e;text-transform:uppercase;letter-spacing:.5px;padding:10px 0 6px;border-bottom:1px solid #fde68a;margin-bottom:8px}\u001b[39m\n\u001b[31m.upd-banner-ok{background:rgba(255,255,255,.2);border:none;color:#fff;border-radius:20px;padding:5px 13px;font-size:12px;font-weight:600;cursor:pointer;font-family:'DM Sans',sans-serif;white-space:nowrap}\u001b[39m\n\u001b[31m.upd-banner-ok:active{background:rgba(255,255,255,.35)}\u001b[39m\n\u001b[31m/* ── FONT SIZE WIDGET ── */\u001b[39m\n\u001b[31m.fs-widget{position:fixed;bottom:calc(var(--bnav-h) + var(--host-bar) + 10px);right:12px;display:flex;align-items:center;gap:0;background:#fff;border:1.5px solid var(--g200);border-radius:24px;box-shadow:0 2px 8px rgba(0,0,0,.12);z-index:500;overflow:hidden;user-select:none}\u001b[39m\n\u001b[31m.fs-btn{background:none;border:none;cursor:pointer;padding:7px 11px;color:var(--g500);line-height:1;transition:background .15s}\u001b[39m\n\u001b[31m.fs-btn:active{background:var(--g100)}\u001b[39m\n\u001b[31m.fs-btn:disabled{color:var(--g300);cursor:default}\u001b[39m\n\u001b[31m.fs-label{font-size:11px;font-weight:700;color:var(--g500);padding:0 4px;pointer-events:none}\u001b[39m\n\u001b[31m/* Level 1 — Large (+15%) */\u001b[39m\n\u001b[31mbody.fs-1 .field label,body.fs-1 .card-title,body.fs-1 .set-lbl,body.fs-1 .set-sub,\u001b[39m\n\u001b[31mbody.fs-1 .hdr-title,body.fs-1 .hdr-sub,body.fs-1 .slbl,body.fs-1 .rev-lbl,body.fs-1 .rev-val,\u001b[39m\n\u001b[31mbody.fs-1 .rbtn,body.fs-1 .chip,body.fs-1 .btn-p,body.fs-1 .btn-s,body.fs-1 .btn-o,\u001b[39m\n\u001b[31mbody.fs-1 .bdialog-title,body.fs-1 .bdialog-sub,body.fs-1 .sub-name,body.fs-1 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-1 .pslot-lbl,body.fs-1 .bitem-title,body.fs-1 .pi-name,body.fs-1 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-1 .asc-name,body.fs-1 .new-btn,body.fs-1 .resume-btn,body.fs-1 .ardl-lbl,body.fs-1 .ardl-val{font-size:calc(1em * 1.15) !important}\u001b[39m\n\u001b[31m/* Level 2 — X-Large (+30%) */\u001b[39m\n\u001b[31mbody.fs-2 .field label,body.fs-2 .card-title,body.fs-2 .set-lbl,body.fs-2 .set-sub,\u001b[39m\n\u001b[31mbody.fs-2 .hdr-title,body.fs-2 .hdr-sub,body.fs-2 .slbl,body.fs-2 .rev-lbl,body.fs-2 .rev-val,\u001b[39m\n\u001b[31mbody.fs-2 .rbtn,body.fs-2 .chip,body.fs-2 .btn-p,body.fs-2 .btn-s,body.fs-2 .btn-o,\u001b[39m\n\u001b[31mbody.fs-2 .bdialog-title,body.fs-2 .bdialog-sub,body.fs-2 .sub-name,body.fs-2 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-2 .pslot-lbl,body.fs-2 .bitem-title,body.fs-2 .pi-name,body.fs-2 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-2 .asc-name,body.fs-2 .new-btn,body.fs-2 .resume-btn,body.fs-2 .ardl-lbl,body.fs-2 .ardl-val{font-size:calc(1em * 1.30) !important}\u001b[39m\n\u001b[31m/* Level 3 — XX-Large (+50%) */\u001b[39m\n\u001b[31mbody.fs-3 .field label,body.fs-3 .card-title,body.fs-3 .set-lbl,body.fs-3 .set-sub,\u001b[39m\n\u001b[31mbody.fs-3 .hdr-title,body.fs-3 .hdr-sub,body.fs-3 .slbl,body.fs-3 .rev-lbl,body.fs-3 .rev-val,\u001b[39m\n\u001b[31mbody.fs-3 .rbtn,body.fs-3 .chip,body.fs-3 .btn-p,body.fs-3 .btn-s,body.fs-3 .btn-o,\u001b[39m\n\u001b[31mbody.fs-3 .bdialog-title,body.fs-3 .bdialog-sub,body.fs-3 .sub-name,body.fs-3 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-3 .pslot-lbl,body.fs-3 .bitem-title,body.fs-3 .pi-name,body.fs-3 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-3 .asc-name,body.fs-3 .new-btn,body.fs-3 .resume-btn,body.fs-3 .ardl-lbl,body.fs-3 .ardl-val{font-size:calc(1em * 1.50) !important}\u001b[39m\n\u001b[31m/* Level 4 — Max (+70%) */\u001b[39m\n\u001b[31mbody.fs-4 .field label,body.fs-4 .card-title,body.fs-4 .set-lbl,body.fs-4 .set-sub,\u001b[39m\n\u001b[31mbody.fs-4 .hdr-title,body.fs-4 .hdr-sub,body.fs-4 .slbl,body.fs-4 .rev-lbl,body.fs-4 .rev-val,\u001b[39m\n\u001b[31mbody.fs-4 .rbtn,body.fs-4 .chip,body.fs-4 .btn-p,body.fs-4 .btn-s,body.fs-4 .btn-o,\u001b[39m\n\u001b[31mbody.fs-4 .bdialog-title,body.fs-4 .bdialog-sub,body.fs-4 .sub-name,body.fs-4 .sub-dtl,\u001b[39m\n\u001b[31mbody.fs-4 .pslot-lbl,body.fs-4 .bitem-title,body.fs-4 .pi-name,body.fs-4 .pi-addr,\u001b[39m\n\u001b[31mbody.fs-4 .asc-name,body.fs-4 .new-btn,body.fs-4 .resume-btn,body.fs-4 .ardl-lbl,body.fs-4 .ardl-val{font-size:calc(1em * 1.70) !important}\u001b[39m\n\u001b[31m/* ── RECCE TILE ACTION BUTTONS ── */\u001b[39m\n\u001b[31m.rpt-btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid rgba(0,0,0,.06)}\u001b[39m\n\u001b[31m.rpt-btn{display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 14px;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;border:none;font-family:inherit;transition:background .15s,opacity .15s;flex:1;min-width:110px;letter-spacing:.1px;white-space:nowrap}\u001b[39m\n\u001b[31m.rpt-btn-report{background:#fff7ed;color:var(--or);border:1.5px solid var(--or)}\u001b[39m\n\u001b[31m.rpt-btn-report:active{background:#fed7aa}\u001b[39m\n\u001b[31m.rpt-btn-pdf{background:var(--g100);color:var(--g400);border:1.5px solid var(--g200)}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready{background:var(--or);color:#fff;border-color:transparent}\u001b[39m\n\u001b[31m.rpt-btn-pdf.ready:active{background:#ea6c00}\u001b[39m\n\u001b[31m/* PDF wait overlay */\u001b[39m\n\u001b[31m#pdf-wait-ov{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m</style>\u001b[39m\n\u001b[31m</head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<!-- PICKER OVERLAY -->\u001b[39m\n\u001b[31m<div class=\\\"povl\\\" id=\\\"povl\\\">\u001b[39m\n\u001b[31m  <div class=\\\"povl-hdr\\\">\u001b[39m\n\u001b[31m    <input class=\\\"psearch\\\" id=\\\"psearch\\\" type=\\\"text\\\" placeholder=\\\"Search store / दुकान खोजें…\\\" oninput=\\\"filterPicker(this.value)\\\" autocomplete=\\\"off\\\">\u001b[39m\n\u001b[31m    <button class=\\\"pcancel\\\" onclick=\\\"closePicker()\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"plist\\\" id=\\\"plist\\\"></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"app\\\">·\u001b[39m\n\u001b[31m<!-- HOME -->\u001b[39m\n\u001b[31m<div class=\\\"view active\\\" id=\\\"view-home\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hero\\\">\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;justify-content:space-between;align-items:center\\\">\u001b[39m\n\u001b[31m      <div><div class=\\\"hero-title\\\"><span class=\\\"en-txt\\\">Branding Recce</span><span class=\\\"hi-txt\\\">ब्रांडिंग रेकी</span></div><div class=\\\"hero-sub\\\" id=\\\"today-date\\\">—</div></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:6px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"lang-btn\\\" onclick=\\\"setLang(LANG==='en'?'hi':'en')\\\" id=\\\"lang-btn\\\" title=\\\"Switch language / भाषा बदलें\\\">EN | हि</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-hub\\\" onclick=\\\"goToHub()\\\">🏡 Hub</button>\u001b[39m\n\u001b[31m      <button class=\\\"icon-btn\\\" onclick=\\\"showView('settings')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12 15a3 3 0 100-6 3 3 0 000 6z\\\"/><path d=\\\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\\\"/></svg></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"hero-ubar\\\" id=\\\"recce-hero-ubar\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <span class=\\\"hero-uname\\\" id=\\\"recce-hero-name\\\"></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-logout\\\" onclick=\\\"recceLogout()\\\">Logout</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"stats\\\">\u001b[39m\n\u001b[31m      <div class=\\\"scard g\\\"><div class=\\\"snum\\\" id=\\\"stat-synced\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Synced</span><span class=\\\"hi-txt\\\">सिंक्ड</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard a\\\"><div class=\\\"snum\\\" id=\\\"stat-pending\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Pending</span><span class=\\\"hi-txt\\\">बाकी</span></div></div>\u001b[39m\n\u001b[31m      <div class=\\\"scard\\\"><div class=\\\"snum\\\" id=\\\"stat-total\\\">0</div><div class=\\\"slbl\\\"><span class=\\\"en-txt\\\">Total</span><span class=\\\"hi-txt\\\">कुल</span></div></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <button class=\\\"new-btn\\\" onclick=\\\"startNewRecce()\\\"><svg width=\\\"20\\\" height=\\\"20\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">New Recce</span><span class=\\\"hi-txt\\\">नई रेकी</span></button>\u001b[39m\n\u001b[31m    <div id=\\\"resume-wrap\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"sh\\\"><span class=\\\"st\\\"><span class=\\\"en-txt\\\">Recent Submissions</span><span class=\\\"hi-txt\\\">हाल की सबमिशन</span></span>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"syncNow()\\\" id=\\\"sync-btn\\\" style=\\\"padding:7px 12px;font-size:12px\\\"><svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg><span class=\\\"en-txt\\\">Sync</span><span class=\\\"hi-txt\\\">सिंक</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"sub-list\\\"></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"srow\\\"><div><span class=\\\"sdot\\\" id=\\\"net-dot\\\"></span><span id=\\\"net-txt\\\"><span class=\\\"en-txt\\\">Checking…</span><span class=\\\"hi-txt\\\">जाँच…</span></span></div><span id=\\\"last-sync-txt\\\" style=\\\"font-size:11px\\\"><span class=\\\"en-txt\\\">Never synced</span><span class=\\\"hi-txt\\\">कभी सिंक नहीं</span></span></div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- SETTINGS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-settings\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('home')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Settings</span><span class=\\\"hi-txt\\\">सेटिंग</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Brand List</span><span class=\\\"hi-txt\\\">ब्रांड सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Manage Brands</span><span class=\\\"hi-txt\\\">ब्रांड प्रबंधन</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">These appear in the brand dropdown and store picker. Add client brands as needed.</div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-manage-list\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-add-row\\\" style=\\\"display:none;gap:8px;align-items:center\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"brand-add-inp\\\" placeholder=\\\"Type brand name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addBrandToList()\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"addBrandToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Store Lists</span><span class=\\\"hi-txt\\\">स्टोर सूची</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Supervisors can upload XLS/CSV store lists here. Updates sync to all devices via server.</span><span class=\\\"hi-txt\\\">सुपरवाइजर यहाँ XLS/CSV स्टोर सूची अपलोड कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m      <!-- Upload/Clear row — supervisor only -->\u001b[39m\n\u001b[31m      <div id=\\\"store-upload-row\\\" style=\\\"display:none;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;margin-top:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"document.getElementById('store-xl').click()\\\"><svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Add File</span><span class=\\\"hi-txt\\\">फ़ाइल जोड़ें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-d\\\" onclick=\\\"clearStoreList()\\\" style=\\\"font-size:12px\\\"><span class=\\\"en-txt\\\">Clear All Stores</span><span class=\\\"hi-txt\\\">सभी स्टोर हटाएं</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" id=\\\"store-push-btn\\\" onclick=\\\"pushStoresToServer()\\\" style=\\\"font-size:12px;display:none\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\\\"/><polyline points=\\\"17 8 12 3 7 8\\\"/><line x1=\\\"12\\\" y1=\\\"3\\\" x2=\\\"12\\\" y2=\\\"15\\\"/></svg><span class=\\\"en-txt\\\">Push to Server</span><span class=\\\"hi-txt\\\">सर्वर पर पुश करें</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"store-xl\\\" accept=\\\".xlsx,.xls,.csv\\\" onchange=\\\"handleStoreUpload(event)\\\">\u001b[39m\n\u001b[31m      <div id=\\\"store-count\\\" style=\\\"font-size:13px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"store-file-list\\\" style=\\\"margin-top:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Brand assignment dialog for files with no brand column -->\u001b[39m\n\u001b[31m    <div id=\\\"brand-assign-dialog\\\" style=\\\"display:none;margin-top:10px;padding:14px;background:#fff7ed;border:1.5px solid var(--or);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\">Which brand is this store list for?</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\" id=\\\"brand-assign-fname\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"brand-assign-chips\\\" class=\\\"chip-grid\\\" style=\\\"margin-bottom:10px\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"confirmBrandAssign()\\\" style=\\\"flex:2;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">Assign Brand</span><span class=\\\"hi-txt\\\">ब्रांड असाइन करें</span></button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"skipBrandAssign()\\\" style=\\\"flex:1;padding:11px;font-size:14px\\\"><span class=\\\"en-txt\\\">No Brand</span><span class=\\\"hi-txt\\\">कोई ब्रांड नहीं</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Server Store List URL (Admin)</span><span class=\\\"hi-txt\\\">सर्वर स्टोर सूची URL</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Admin pushes stores.json to any public URL. App auto-fetches on open and caches offline.</div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"srv-url\\\" placeholder=\\\"https://yourserver.com/stores.json\\\"></div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"fetchServerStores()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Fetch Now</button>\u001b[39m\n\u001b[31m        <button class=\\\"btn-s\\\" onclick=\\\"saveServerUrl()\\\" style=\\\"padding:9px 14px;font-size:13px;width:auto\\\">Save URL</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Sync Endpoint</span><span class=\\\"hi-txt\\\">सिंक एंडपॉइंट</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Slides Generator</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Managed by admin. Deploy gas_slides.gs from /opt/slides-proxy/ to Google Apps Script and paste the URL here.</div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"slides-gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Not configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"slides-gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"slides-gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"saveSlidesGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\">Google Apps Script URL — Sheet Sync</div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Legacy sync endpoint. Writes recce data to Google Sheet.</div>·\u001b[39m\n\u001b[31m      <!-- Locked state (default) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-locked\\\" style=\\\"display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--g50);border:1.5px solid var(--g200);border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;color:var(--g600)\\\">🔒 Admin access required</div>\u001b[39m\n\u001b[31m          <div id=\\\"gas-url-preview\\\" style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Endpoint configured</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-o\\\" onclick=\\\"showAdminLogin()\\\" style=\\\"font-size:13px;padding:8px 14px\\\"><span class=\\\"en-txt\\\">Admin Login</span><span class=\\\"hi-txt\\\">एडमिन लॉगिन</span></button>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Unlocked state (after admin login) -->\u001b[39m\n\u001b[31m      <div id=\\\"gas-unlocked\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;align-items:center;gap:8px;margin-bottom:10px;padding:7px 12px;background:#dcfce7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          <span style=\\\"font-size:12px;color:#14532d;font-weight:600\\\">🔓 Admin mode active</span>\u001b[39m\n\u001b[31m          <button onclick=\\\"lockAdmin()\\\" style=\\\"margin-left:auto;background:none;border:none;color:#14532d;font-size:12px;cursor:pointer;font-weight:600\\\">Lock ×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:8px\\\"><input type=\\\"url\\\" id=\\\"gas-url\\\" placeholder=\\\"https://script.google.com/macros/s/…/exec\\\"></div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveGasUrl()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Save</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"testEndpoint()\\\" style=\\\"font-size:13px;padding:9px 14px\\\">Test</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>·\u001b[39m\n\u001b[31m    <!-- Admin Login Modal -->\u001b[39m\n\u001b[31m    <div id=\\\"admin-login-modal\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m      <div style=\\\"background:#fff;border-radius:var(--r);padding:24px 20px;margin:20px;max-width:380px;width:100%;box-shadow:0 8px 32px rgba(0,0,0,.2)\\\">\u001b[39m\n\u001b[31m        <div style=\\\"font-size:17px;font-weight:700;color:var(--nv);margin-bottom:4px\\\">Admin Login</div>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:18px\\\">Enter admin password to unlock settings</div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m          <label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">Password</label>\u001b[39m\n\u001b[31m          <input type=\\\"password\\\" id=\\\"admin-pwd\\\" placeholder=\\\"Enter admin password\\\" style=\\\"width:100%;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px\\\" onkeydown=\\\"if(event.key==='Enter')verifyAdmin()\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div id=\\\"admin-error\\\" style=\\\"display:none;font-size:12px;color:var(--rd);margin-bottom:12px;padding:8px 12px;background:#fee2e2;border-radius:var(--rs)\\\">Incorrect password</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"verifyAdmin()\\\" style=\\\"flex:2;padding:13px\\\" id=\\\"admin-login-btn\\\">Login</button>\u001b[39m\n\u001b[31m          <button class=\\\"btn-s\\\" onclick=\\\"closeAdminLogin()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:14px;padding-top:14px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:11px;font-weight:600;color:var(--g400);text-transform:uppercase;letter-spacing:.4px;margin-bottom:8px\\\">Admin Password Config URL</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:8px\\\">URL to your admin.json file on server (contains hashed password)</div>\u001b[39m\n\u001b[31m          <input type=\\\"url\\\" id=\\\"admin-cfg-url\\\" placeholder=\\\"https://yourserver.com/admin.json\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px;margin-bottom:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"saveAdminCfgUrl()\\\" style=\\\"font-size:12px;padding:7px 12px;width:100%;justify-content:center\\\">Save Config URL</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Geolocation Stamp</span><span class=\\\"hi-txt\\\">जियोलोकेशन स्टैम्प</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;justify-content:space-between;gap:16px\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1\\\">\u001b[39m\n\u001b[31m          <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Stamp on Photos</span><span class=\\\"hi-txt\\\">फोटो पर स्टैम्प</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"set-sub\\\" style=\\\"margin-bottom:0\\\">Bakes GPS coordinates, store name and timestamp into every photo — visible in the image itself. Same as GPS Map Camera app. Default: On.</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"tog on\\\" id=\\\"geo-tog\\\" onclick=\\\"toggleGeoStamp()\\\"><div class=\\\"tog-knob\\\"></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"geo-status\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\">GPS not yet captured</div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Image Quality</span><span class=\\\"hi-txt\\\">फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m      <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Default Photo Quality</span><span class=\\\"hi-txt\\\">डिफ़ॉल्ट फोटो क्वालिटी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"set-sub\\\">Applies to all photos — front view, inside view, branding, and additional. HD uses more storage and takes longer to sync on poor networks.</div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;gap:10px;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-compressed\\\" onclick=\\\"setImgQuality('compressed')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-compressed\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-compressed\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">Full Compression</span><span class=\\\"hi-txt\\\">पूर्ण कम्प्रेशन</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~150–200 KB · Max 1280px · Best for poor network</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-left:auto;font-size:11px;font-weight:700;color:var(--gn);background:#dcfce7;padding:3px 8px;border-radius:20px\\\"><span class=\\\"en-txt\\\">Recommended</span><span class=\\\"hi-txt\\\">अनुशंसित</span></div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m        <label style=\\\"display:flex;align-items:center;gap:12px;cursor:pointer;padding:12px 14px;border:1.5px solid var(--g200);border-radius:var(--rs);transition:border-color .15s\\\" id=\\\"q-opt-hd\\\" onclick=\\\"setImgQuality('hd')\\\">\u001b[39m\n\u001b[31m          <div style=\\\"width:18px;height:18px;border-radius:50%;border:2px solid var(--g300);flex-shrink:0;display:flex;align-items:center;justify-content:center\\\" id=\\\"q-radio-hd\\\">\u001b[39m\n\u001b[31m            <div style=\\\"width:9px;height:9px;border-radius:50%;background:var(--or);display:none\\\" id=\\\"q-dot-hd\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:14px;font-weight:600;color:var(--nv)\\\"><span class=\\\"en-txt\\\">HD Quality</span><span class=\\\"hi-txt\\\">HD क्वालिटी</span></div>\u001b[39m\n\u001b[31m            <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">~400–600 KB · Max 1920px · Better detail for print</div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </label>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"q-current-badge\\\" style=\\\"margin-top:10px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Supervisor Config panel — shown only to supervisors via renderSupPanel() -->\u001b[39m\n\u001b[31m    <div id=\\\"sup-panel\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">🔐 Recce Access Config</span><span class=\\\"hi-txt\\\">🔐 रेकी एक्सेस कॉन्फ़िग</span></div>\u001b[39m\n\u001b[31m      <!-- Access mode — only H/P can change -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"mode-row\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Access Mode</span><span class=\\\"hi-txt\\\">एक्सेस मोड</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Public: any Hub user can submit Recces. Assigned: only Supervisors and Creators can access.</span><span class=\\\"hi-txt\\\">सार्वजनिक: कोई भी Hub यूजर। नियत: सिर्फ़ Supervisors और Creators।</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\" style=\\\"margin-bottom:8px;margin-top:8px\\\">\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-public\\\" onclick=\\\"setRecceMode('public')\\\"><span class=\\\"en-txt\\\">Public</span><span class=\\\"hi-txt\\\">सार्वजनिक</span></div>\u001b[39m\n\u001b[31m          <div class=\\\"rbtn\\\" id=\\\"mode-assigned\\\" onclick=\\\"setRecceMode('assigned')\\\"><span class=\\\"en-txt\\\">Assigned</span><span class=\\\"hi-txt\\\">नियत</span></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Supervisor list — view all + delete + create -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Supervisors</span><span class=\\\"hi-txt\\\">सुपरवाइजर</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can view all recces, delete with reason, and submit. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">सभी रेकी देख सकते हैं, कारण से हटा सकते हैं, और सबमिट कर सकते हैं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"sup-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"sup-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addSupervisor()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addSupervisor()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Creator list — creation only -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Creators</span><span class=\\\"hi-txt\\\">क्रिएटर्स</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Can submit Recces only — no admin view or deletion rights. Harish/Pramod can add or remove.</span><span class=\\\"hi-txt\\\">केवल रेकी सबमिट कर सकते हैं — एडमिन व्यू या डिलीट नहीं।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"creator-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"creator-add-inp\\\" placeholder=\\\"Employee ID\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addCreator()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addCreator()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Client list — used for client portal scoping -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clients</span><span class=\\\"hi-txt\\\">क्लाइंट</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Names that appear as chips when submitting a recce. Add the brand or agency name (e.g. \\\"Marketing Vibe\\\"). These are used to scope what clients see in the Client Portal.</span><span class=\\\"hi-txt\\\">रेकी सबमिट करते समय दिखने वाले क्लाइंट नाम। ब्रांड या एजेंसी नाम जोड़ें।</span></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-mgmt-list\\\" style=\\\"margin-top:8px;margin-bottom:8px\\\"></div>\u001b[39m\n\u001b[31m        <div id=\\\"client-add-row\\\" style=\\\"display:none;gap:8px\\\">\u001b[39m\n\u001b[31m          <input type=\\\"text\\\" id=\\\"client-add-inp\\\" placeholder=\\\"Client name\\\" style=\\\"flex:1;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" onkeydown=\\\"if(event.key==='Enter')addClientToList()\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-o\\\" onclick=\\\"addClientToList()\\\" style=\\\"font-size:13px;padding:9px 14px;flex-shrink:0\\\"><span class=\\\"en-txt\\\">Add</span><span class=\\\"hi-txt\\\">जोड़ें</span></button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <!-- Sync to server — only H/P -->\u001b[39m\n\u001b[31m      <div class=\\\"set-item\\\" id=\\\"cfg-sync-btn\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Sync Config to Server</span><span class=\\\"hi-txt\\\">सर्वर पर कॉन्फ़िग सिंक करें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"set-sub\\\"><span class=\\\"en-txt\\\">Apply supervisor/creator/client lists and access mode to all devices.</span><span class=\\\"hi-txt\\\">सभी डिवाइस पर कॉन्फ़िग लागू करें।</span></div>\u001b[39m\n\u001b[31m        <button class=\\\"btn-p\\\" onclick=\\\"syncCfgToServer()\\\" style=\\\"max-width:220px;font-size:14px;padding:12px;margin-top:8px\\\"><span class=\\\"en-txt\\\">Sync to Server</span><span class=\\\"hi-txt\\\">सर्वर पर सिंक करें</span></button>\u001b[39m\n\u001b[31m        <div id=\\\"cfg-sync-status\\\" style=\\\"margin-top:8px;font-size:12px;color:var(--g500)\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:11px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:.5px;padding:16px 0 8px\\\"><span class=\\\"en-txt\\\">Danger Zone</span><span class=\\\"hi-txt\\\">खतरनाक ज़ोन</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"set-item\\\"><div class=\\\"set-lbl\\\"><span class=\\\"en-txt\\\">Clear All Local Data</span><span class=\\\"hi-txt\\\">सभी डेटा हटाएं</span></div><div class=\\\"set-sub\\\">Removes all submissions from this device.</div><button class=\\\"btn-d\\\" onclick=\\\"clearData()\\\" style=\\\"padding:9px 14px;font-size:13px\\\">Clear All</button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: STORE INFO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-store\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"exitForm()\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Details</span><span class=\\\"hi-txt\\\">दुकान विवरण</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 1 of 5</span><span class=\\\"hi-txt\\\">चरण 1 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:20%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Recce Info</span><span class=\\\"hi-txt\\\">रेकी जानकारी</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Date of Recce</span><span class=\\\"hi-txt\\\">रेकी की तारीख</span> <span class=\\\"req\\\">*</span></label><input type=\\\"date\\\" id=\\\"f-date\\\" onchange=\\\"saveDraft()\\\" max=\\\"\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" id=\\\"campaign-field\\\">\u001b[39m\n\u001b[31m        <label><span class=\\\"en-txt\\\">Job / Campaign</span><span class=\\\"hi-txt\\\">जॉब / कैंपेन</span></label>\u001b[39m\n\u001b[31m        <select id=\\\"f-campaign-id\\\" onchange=\\\"onCampaignSelect()\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">Loading campaigns…</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <div id=\\\"campaign-notify-msg\\\" style=\\\"display:none;font-size:12px;color:#92400e;margin-top:6px;padding:8px 10px;background:#fef3c7;border-radius:var(--rs)\\\">\u001b[39m\n\u001b[31m          ⚑ <span class=\\\"en-txt\\\">Recce will submit without a job ID. A notification will flag this for your supervisor to link it later.</span><span class=\\\"hi-txt\\\">रेकी बिना जॉब ID के सबमिट होगी। सुपरवाइजर बाद में लिंक करेगा।</span>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Store</span><span class=\\\"hi-txt\\\">दुकान</span> <span id=\\\"store-avail-tag\\\" style=\\\"font-size:11px;color:var(--g400);font-weight:400;text-transform:none;letter-spacing:0\\\"></span></div>·\u001b[39m\n\u001b[31m      <!-- When store is selected -->\u001b[39m\n\u001b[31m      <div id=\\\"store-selected\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"store-card\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:start;justify-content:space-between;gap:8px\\\">\u001b[39m\n\u001b[31m            <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m              <div class=\\\"store-card-name\\\" id=\\\"sc-name\\\">—</div>\u001b[39m\n\u001b[31m              <div style=\\\"display:flex;align-items:center;gap:6px;margin-top:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m                <span class=\\\"brand-tag\\\" id=\\\"sc-brand\\\">—</span>\u001b[39m\n\u001b[31m                <span class=\\\"last-chip\\\" id=\\\"sc-last\\\" style=\\\"display:none\\\">—</span>\u001b[39m\n\u001b[31m              </div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            <button class=\\\"store-card-change\\\" onclick=\\\"openPicker()\\\"><span class=\\\"en-txt\\\">Change ›</span><span class=\\\"hi-txt\\\">बदलें ›</span></button>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <!-- All fields from Excel shown here -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-details\\\" style=\\\"margin-top:10px;display:flex;flex-direction:column;gap:4px\\\"></div>\u001b[39m\n\u001b[31m          <!-- Missing required fields — editable inline -->\u001b[39m\n\u001b[31m          <div id=\\\"sc-missing\\\" style=\\\"display:none;margin-top:12px;padding-top:12px;border-top:1px solid var(--g100)\\\">\u001b[39m\n\u001b[31m            <div style=\\\"font-size:11px;font-weight:700;color:var(--rd);text-transform:uppercase;letter-spacing:.4px;margin-bottom:10px\\\">⚠ Please complete missing fields</div>\u001b[39m\n\u001b[31m            <div id=\\\"sc-missing-fields\\\"></div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <!-- Brand selector — shown when store has no brand -->\u001b[39m\n\u001b[31m        <div id=\\\"brand-selector\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m          <div style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:4px\\\"><span class=\\\"en-txt\\\">Select Brand</span><span class=\\\"hi-txt\\\">ब्रांड चुनें</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\">This store has no brand in the list — select one:</div>\u001b[39m\n\u001b[31m          <div id=\\\"brand-chips\\\" class=\\\"chip-grid\\\"></div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Picker trigger (shown when stores loaded) -->\u001b[39m\n\u001b[31m      <div id=\\\"pick-trigger-wrap\\\">\u001b[39m\n\u001b[31m        <div class=\\\"pick-trigger\\\" onclick=\\\"openPicker()\\\">\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;align-items:center;gap:10px\\\">\u001b[39m\n\u001b[31m            <span style=\\\"font-size:20px\\\">🏪</span>\u001b[39m\n\u001b[31m            <div>\u001b[39m\n\u001b[31m              <div style=\\\"font-size:15px;font-weight:700;color:var(--or)\\\"><span class=\\\"en-txt\\\">Select Store from List</span><span class=\\\"hi-txt\\\">सूची से दुकान चुनें</span></div>\u001b[39m\n\u001b[31m              <div id=\\\"store-avail-count\\\" style=\\\"font-size:12px;font-weight:400;color:var(--am);margin-top:1px\\\"><span class=\\\"en-txt\\\">Tap to browse stores</span><span class=\\\"hi-txt\\\">दुकान खोजने के लिए दबाएं</span></div>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual / new store toggle -->\u001b[39m\n\u001b[31m      <div class=\\\"manual-toggle\\\" id=\\\"manual-toggle\\\" onclick=\\\"toggleManual()\\\">\u001b[39m\n\u001b[31m        <svg width=\\\"15\\\" height=\\\"15\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\" id=\\\"mt-icon\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg>\u001b[39m\n\u001b[31m        <span id=\\\"mt-label\\\"><span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span></span>\u001b[39m\n\u001b[31m      </div>·\u001b[39m\n\u001b[31m      <!-- Manual fields -->\u001b[39m\n\u001b[31m      <div id=\\\"manual-fields\\\" style=\\\"display:none;margin-top:14px\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\" style=\\\"margin-bottom:14px\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <select id=\\\"f-brand\\\" onchange=\\\"onManualBrandChange()\\\">\u001b[39m\n\u001b[31m            <option value=\\\"\\\">Select brand</option>\u001b[39m\n\u001b[31m          </select>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span> <span class=\\\"req\\\">*</span></label><input type=\\\"text\\\" id=\\\"f-store\\\" placeholder=\\\"Enter store name\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\">\u001b[39m\n\u001b[31m          <label><span class=\\\"en-txt\\\">Store Address</span><span class=\\\"hi-txt\\\">दुकान का पता</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m          <textarea id=\\\"f-addr\\\" rows=\\\"2\\\" placeholder=\\\"Full address\\\" onchange=\\\"saveDraft()\\\"></textarea>\u001b[39m\n\u001b[31m          <div class=\\\"gps-row\\\">\u001b[39m\n\u001b[31m            <button class=\\\"gps-btn\\\" onclick=\\\"captureGPS()\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\"/><path d=\\\"M12 2v3M12 19v3M2 12h3M19 12h3\\\"/></svg><span class=\\\"en-txt\\\">Capture GPS</span><span class=\\\"hi-txt\\\">GPS लें</span></button>\u001b[39m\n\u001b[31m            <span id=\\\"gps-status\\\" style=\\\"font-size:12px;color:var(--g500);align-self:center\\\"></span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Store Mobile No.</span><span class=\\\"hi-txt\\\">मोबाइल नंबर</span></label><input type=\\\"tel\\\" id=\\\"f-mobile\\\" placeholder=\\\"10-digit number\\\" maxlength=\\\"10\\\" inputmode=\\\"numeric\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <!-- Client card -->\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Client</span><span class=\\\"hi-txt\\\">क्लाइंट</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:var(--g500);margin-bottom:10px\\\"><span class=\\\"en-txt\\\">Select who this recce is for. Defaults to brand — change if work came via an agency.</span><span class=\\\"hi-txt\\\">यह रेकी किसके लिए है चुनें। ब्रांड से डिफ़ॉल्ट — एजेंसी के ज़रिए हो तो बदलें।</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"cl-chip-grid\\\" id=\\\"client-chips\\\"></div>\u001b[39m\n\u001b[31m      <div id=\\\"client-other-wrap\\\" style=\\\"display:none;margin-top:4px\\\">\u001b[39m\n\u001b[31m        <input type=\\\"text\\\" id=\\\"f-client-other\\\" placeholder=\\\"Type client name\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\" oninput=\\\"onClientOtherInput()\\\">\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-p\\\" onclick=\\\"step2()\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: PHOTOS -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-photos\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-store')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Store Photos</span><span class=\\\"hi-txt\\\">दुकान की फोटो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 2 of 5</span><span class=\\\"hi-txt\\\">चरण 2 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:40%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Front View</span><span class=\\\"hi-txt\\\">आगे का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(min 1, max 3)</span><span class=\\\"cnt-badge gray\\\" id=\\\"front-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"front-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-front\\\" onclick=\\\"addPhoto('front')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Front Photo</span><span class=\\\"hi-txt\\\">आगे की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Inside View</span><span class=\\\"hi-txt\\\">अंदर का दृश्य</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 5)</span><span class=\\\"cnt-badge gray\\\" id=\\\"inside-badge\\\">0</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"inside-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-inside\\\" onclick=\\\"addPhoto('inside')\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Inside Photo</span><span class=\\\"hi-txt\\\">अंदर की फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-store')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step3()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: VIDEO -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-video\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-photos')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Recce Video</span><span class=\\\"hi-txt\\\">रेकी वीडियो</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 3 of 5</span><span class=\\\"hi-txt\\\">चरण 3 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:60%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Video</span><span class=\\\"hi-txt\\\">वीडियो</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Recce video available?</span><span class=\\\"hi-txt\\\">रेकी वीडियो है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"vid-yes\\\" onclick=\\\"setVideo(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"vid-no\\\" onclick=\\\"setVideo(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div id=\\\"vid-sec\\\" style=\\\"display:none\\\">\u001b[39m\n\u001b[31m        <div class=\\\"divider\\\"></div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Upload Video</span><span class=\\\"hi-txt\\\">वीडियो अपलोड करें</span></label>\u001b[39m\n\u001b[31m          <div class=\\\"pslot\\\" id=\\\"vid-slot\\\" onclick=\\\"document.getElementById('vid-inp').click()\\\"><div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div></div>\u001b[39m\n\u001b[31m          <input type=\\\"file\\\" id=\\\"vid-inp\\\" accept=\\\"video/*\\\" onchange=\\\"handleVideo(event)\\\">\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Video Comments</span><span class=\\\"hi-txt\\\">वीडियो टिप्पणी</span></label><input type=\\\"text\\\" id=\\\"f-vid-cmt\\\" placeholder=\\\"Optional\\\" onchange=\\\"saveDraft()\\\"></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-photos')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step4()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: BRANDING -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-branding\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-video')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Branding</span><span class=\\\"hi-txt\\\">ब्रांडिंग</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 4 of 5</span><span class=\\\"hi-txt\\\">चरण 4 / 5</span></div></div></div>\u001b[39m\n\u001b[31m    <span id=\\\"br-hdr-badge\\\" style=\\\"background:rgba(255,255,255,.2);color:#fff;font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px\\\"><span class=\\\"en-txt\\\">0 items</span><span class=\\\"hi-txt\\\">0 आइटम</span></span>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:80%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Branding Space</span><span class=\\\"hi-txt\\\">ब्रांडिंग स्थान</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label><span class=\\\"en-txt\\\">Space available?</span><span class=\\\"hi-txt\\\">जगह उपलब्ध है?</span> <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m        <div class=\\\"rgroup\\\"><div class=\\\"rbtn\\\" id=\\\"br-yes\\\" onclick=\\\"setBranding(true)\\\"><span class=\\\"en-txt\\\">Yes</span><span class=\\\"hi-txt\\\">हाँ</span></div><div class=\\\"rbtn\\\" id=\\\"br-no\\\" onclick=\\\"setBranding(false)\\\"><span class=\\\"en-txt\\\">No</span><span class=\\\"hi-txt\\\">नहीं</span></div></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"branding-lock-banner\\\" style=\\\"display:none;background:#fef3c7;border:1.5px solid #f59e0b;border-radius:10px;padding:12px 14px;margin-bottom:10px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:13px;font-weight:700;color:#92400e\\\">Client approval exists — branding locked</div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:12px;color:#78350f;margin-top:4px\\\"><span class=\\\"en-txt\\\">The client has reviewed this recce. Create a new recce to revise branding items.</span><span class=\\\"hi-txt\\\">क्लाइंट ने रेकी की समीक्षा की है। बदलाव के लिए नई रेकी बनाएं।</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"branding-override-wrap\\\" style=\\\"display:none;margin-top:10px\\\">\u001b[39m\n\u001b[31m        <button onclick=\\\"unlockBrandingOverride()\\\" style=\\\"background:#f59e0b;color:#000;border:none;border-radius:8px;padding:8px 14px;font-size:12px;font-weight:700;cursor:pointer\\\">Override Edit (H&amp;P only)</button>\u001b[39m\n\u001b[31m        <div style=\\\"font-size:11px;color:#92400e;margin-top:5px\\\">Use only when client has verbally confirmed and app needs correction.</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"br-items\\\"></div>\u001b[39m\n\u001b[31m    <div id=\\\"br-add\\\" style=\\\"display:none;margin-bottom:80px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" onclick=\\\"addBranding()\\\" style=\\\"width:100%;justify-content:center\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Another Branding Item</span><span class=\\\"hi-txt\\\">एक और ब्रांडिंग जोड़ें</span></button>\u001b[39m\n\u001b[31m      <div style=\\\"text-align:center;font-size:12px;color:var(--g400);margin-top:8px\\\"><span class=\\\"en-txt\\\">Tap Continue below when done adding items</span><span class=\\\"hi-txt\\\">सभी आइटम जोड़ने के बाद आगे दबाएं</span></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-video')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"step5()\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Continue →</span><span class=\\\"hi-txt\\\">आगे →</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FORM: ADDITIONAL + SUBMIT -->\u001b[39m\n\u001b[31m<div class=\\\"view\\\" id=\\\"view-form-additional\\\">\u001b[39m\n\u001b[31m  <div class=\\\"hdr\\\"><div class=\\\"hdr-l\\\"><button class=\\\"back-btn\\\" onclick=\\\"showView('form-branding')\\\"><svg width=\\\"22\\\" height=\\\"22\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg></button><div><div class=\\\"hdr-title\\\"><span class=\\\"en-txt\\\">Submit</span><span class=\\\"hi-txt\\\">सबमिट</span></div><div class=\\\"hdr-sub\\\"><span class=\\\"en-txt\\\">Step 5 of 5</span><span class=\\\"hi-txt\\\">चरण 5 / 5</span></div></div></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"pgbar\\\"><div class=\\\"pgfill\\\" style=\\\"width:100%\\\"></div></div>\u001b[39m\n\u001b[31m  <div class=\\\"content\\\">\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Mandatory Document</span><span class=\\\"hi-txt\\\">अनिवार्य दस्तावेज़</span> <span class=\\\"req\\\">*</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"pslot\\\" id=\\\"doc-slot\\\" onclick=\\\"document.getElementById('doc-inp').click()\\\"><div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div></div>\u001b[39m\n\u001b[31m      <input type=\\\"file\\\" id=\\\"doc-inp\\\" accept=\\\"image/*,.pdf\\\" onchange=\\\"handleDoc(event)\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Additional Photos</span><span class=\\\"hi-txt\\\">अतिरिक्त फोटो</span> <span style=\\\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;color:var(--g400)\\\">(optional, max 8)</span><span class=\\\"cnt-badge gray\\\" id=\\\"addl-badge\\\">0 / 8</span></div>\u001b[39m\n\u001b[31m      <div id=\\\"add-cont\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"btn-o\\\" id=\\\"add-addl\\\" onclick=\\\"addAdditional()\\\" style=\\\"margin-top:10px;font-size:13px\\\"><svg width=\\\"14\\\" height=\\\"14\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><line x1=\\\"12\\\" y1=\\\"5\\\" x2=\\\"12\\\" y2=\\\"19\\\"/><line x1=\\\"5\\\" y1=\\\"12\\\" x2=\\\"19\\\" y2=\\\"12\\\"/></svg><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"card\\\"><div class=\\\"card-title\\\"><span class=\\\"en-txt\\\">Review</span><span class=\\\"hi-txt\\\">समीक्षा</span></div><div id=\\\"rev-body\\\"></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"bnav\\\"><button class=\\\"btn-s\\\" onclick=\\\"showView('form-branding')\\\" style=\\\"flex:1\\\"><span class=\\\"en-txt\\\">← Back</span><span class=\\\"hi-txt\\\">← वापस</span></button><button class=\\\"btn-p\\\" onclick=\\\"submitRecce()\\\" id=\\\"sub-btn\\\" style=\\\"flex:2\\\"><span class=\\\"en-txt\\\">Submit Recce ✓</span><span class=\\\"hi-txt\\\">रेकी सबमिट करें ✓</span></button></div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- ANNOTATION MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"annot-modal\\\" id=\\\"annot-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"annot-bar\\\">\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Draw:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"at-rect\\\"    onclick=\\\"setATool('rect')\\\">▭ Rect</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-ellipse\\\" onclick=\\\"setATool('ellipse')\\\">◯ Ellipse</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-line\\\"    onclick=\\\"setATool('line')\\\">╱ Line</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-arrow\\\"   onclick=\\\"setATool('arrow')\\\">↗ Arrow</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\"    id=\\\"at-free\\\"    onclick=\\\"setATool('free')\\\">✏ Free</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool sel-on\\\" id=\\\"at-move\\\" onclick=\\\"setATool('move')\\\" style=\\\"margin-left:4px\\\">⊹ Move</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"annot-row\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400)\\\">Color:</span>\u001b[39m\n\u001b[31m      <div class=\\\"acolor on\\\" id=\\\"ac-or\\\" style=\\\"background:#f97316\\\" onclick=\\\"setAColor('#f97316')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-rd\\\" style=\\\"background:#ef4444\\\" onclick=\\\"setAColor('#ef4444')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-wh\\\" style=\\\"background:#ffffff\\\" onclick=\\\"setAColor('#ffffff')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-yw\\\" style=\\\"background:#facc15\\\" onclick=\\\"setAColor('#facc15')\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"acolor\\\"    id=\\\"ac-gn\\\" style=\\\"background:#22c55e\\\" onclick=\\\"setAColor('#22c55e')\\\"></div>\u001b[39m\n\u001b[31m      <span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Width:</span>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-2\\\" onclick=\\\"setAWidth(2)\\\" style=\\\"padding:5px 8px\\\">Thin</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool on\\\" id=\\\"aw-4\\\" onclick=\\\"setAWidth(4)\\\" style=\\\"padding:5px 8px\\\">Med</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" id=\\\"aw-7\\\" onclick=\\\"setAWidth(7)\\\" style=\\\"padding:5px 8px\\\">Thick</button>\u001b[39m\n\u001b[31m      <div style=\\\"flex:1\\\"></div>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"undoAnnot()\\\">↩</button>\u001b[39m\n\u001b[31m      <button class=\\\"atool\\\" onclick=\\\"clearAnnot()\\\">✕</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"annot-sel-info\\\" style=\\\"display:none;font-size:11px;color:#facc15;padding:4px 0 2px\\\">\u001b[39m\n\u001b[31m      Shape selected — drag to move · drag corners to resize · tap elsewhere to deselect\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-cvs-wrap\\\"><canvas id=\\\"annot-cvs\\\"></canvas></div>\u001b[39m\n\u001b[31m  <div class=\\\"annot-foot\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-s\\\" onclick=\\\"skipAnnot()\\\" style=\\\"flex:1;padding:12px;font-size:14px\\\"><span class=\\\"en-txt\\\">Skip markup</span><span class=\\\"hi-txt\\\">मार्कअप छोड़ें</span></button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" onclick=\\\"saveAnnot()\\\" style=\\\"flex:2;padding:12px\\\"><span class=\\\"en-txt\\\">Done — Save ✓</span><span class=\\\"hi-txt\\\">हो गया — सेव करें ✓</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EXIT DIALOG -->\u001b[39m\n\u001b[31m<!-- MODAL: Link Job to Recce (supervisor only) -->\u001b[39m\n\u001b[31m<div id=\\\"modal-link-job\\\" style=\\\"display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:500;align-items:center;justify-content:center\\\">\u001b[39m\n\u001b[31m  <div style=\\\"background:#fff;border-radius:14px;padding:20px;width:90%;max-width:380px;display:flex;flex-direction:column;gap:12px;box-shadow:0 8px 32px rgba(0,0,0,.35)\\\">\u001b[39m\n\u001b[31m    <div style=\\\"font-size:15px;font-weight:700;color:#1e293b\\\">&#x1F517; Link Job to Recce</div>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-store\\\" style=\\\"font-size:13px;color:#64748b\\\"></div>\u001b[39m\n\u001b[31m    <select id=\\\"link-job-sel\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid #cbd5e1;border-radius:8px;font-size:14px;background:#fff;color:#1e293b\\\">\u001b[39m\n\u001b[31m      <option value=\\\"\\\">&#x2014; Select campaign &#x2014;</option>\u001b[39m\n\u001b[31m    </select>\u001b[39m\n\u001b[31m    <div id=\\\"link-job-err\\\" style=\\\"font-size:12px;color:#ef4444;min-height:14px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:10px\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"closeLinkJobModal()\\\" style=\\\"flex:1;padding:12px;border:1px solid #cbd5e1;border-radius:8px;cursor:pointer;background:#f8fafc;font-size:14px\\\">Cancel</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"saveLinkJob()\\\" style=\\\"flex:2;padding:12px;background:#f59e0b;color:#000;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:700\\\">&#x1F517; Link Job</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"exit-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Exit Recce?</span><span class=\\\"hi-txt\\\">रेकी से बाहर?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Your progress and photos will be saved as a draft. Resume anytime from the home screen.</span><span class=\\\"hi-txt\\\">आपकी प्रगति और फोटो ड्राफ्ट में सेव होंगी। होम स्क्रीन से कभी भी जारी रखें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"exitSaveAndLeave()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">💾 Save Draft & Exit</span><span class=\\\"hi-txt\\\">💾 ड्राफ्ट सेव करें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-d\\\" onclick=\\\"exitDiscard()\\\" style=\\\"flex:1;padding:13px;font-size:13px\\\"><span class=\\\"en-txt\\\">Discard</span><span class=\\\"hi-txt\\\">हटाएं</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"exitCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">← Continue Recce</span><span class=\\\"hi-txt\\\">← रेकी जारी रखें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- PHOTO SOURCE PICKER -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"photo-src-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add Photo</span><span class=\\\"hi-txt\\\">फोटो जोड़ें</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Camera photos get GPS stamp baked in. Gallery photos are added without stamp.</span><span class=\\\"hi-txt\\\">कैमरा फोटो में GPS स्टैम्प लगती है। गैलरी फोटो में नहीं।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"photoSrcCamera()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">📷 Use Camera</span><span class=\\\"hi-txt\\\">📷 कैमरा</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">GPS stamp applied</span><span class=\\\"hi-txt\\\">GPS स्टैम्प लगेगी</span></span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"photoSrcGallery()\\\" style=\\\"padding:14px;font-size:15px\\\"><span class=\\\"en-txt\\\">🖼 Choose from Gallery</span><span class=\\\"hi-txt\\\">🖼 गैलरी से चुनें</span>  <span style=\\\"font-size:11px;opacity:.8;margin-left:4px\\\"><span class=\\\"en-txt\\\">No stamp</span><span class=\\\"hi-txt\\\">स्टैम्प नहीं</span></span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"photoSrcCancel()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- STORE PREVIEW DIALOG -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"store-preview-dialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:80vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"store-preview-title\\\"><span class=\\\"en-txt\\\">Preview Store List</span><span class=\\\"hi-txt\\\">स्टोर सूची का प्रीव्यू</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Review before adding to your store list:</span><span class=\\\"hi-txt\\\">जोड़ने से पहले जाँचें:</span></div>\u001b[39m\n\u001b[31m    <div style=\\\"overflow-x:auto;margin-bottom:14px\\\">\u001b[39m\n\u001b[31m      <table style=\\\"width:100%;border-collapse:collapse;font-size:12px\\\">\u001b[39m\n\u001b[31m        <thead><tr style=\\\"background:var(--nv);color:#fff\\\">\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Store Name</span><span class=\\\"hi-txt\\\">दुकान का नाम</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Address</span><span class=\\\"hi-txt\\\">पता</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Mobile</span><span class=\\\"hi-txt\\\">मोबाइल</span></th>\u001b[39m\n\u001b[31m          <th style=\\\"padding:6px 8px;text-align:left\\\"><span class=\\\"en-txt\\\">Brand</span><span class=\\\"hi-txt\\\">ब्रांड</span></th>\u001b[39m\n\u001b[31m        </tr></thead>\u001b[39m\n\u001b[31m        <tbody id=\\\"store-preview-body\\\"></tbody>\u001b[39m\n\u001b[31m      </table>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"confirmStorePreview()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">✓ Confirm & Add Stores</span><span class=\\\"hi-txt\\\">✓ स्टोर जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"cancelStorePreview()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Cancel</span><span class=\\\"hi-txt\\\">रद्द करें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BOTTOM DIALOG (branding additional photo prompt) -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"bdialog\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\" id=\\\"bdialog-title\\\"><span class=\\\"en-txt\\\">Add reference photos?</span><span class=\\\"hi-txt\\\">संदर्भ फोटो जोड़ें?</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"bdialog-sub\\\"><span class=\\\"en-txt\\\">Add extra photos for this branding item for future reference.</span><span class=\\\"hi-txt\\\">इस ब्रांडिंग आइटम के लिए अतिरिक्त फोटो जोड़ें।</span></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"bdialogYes()\\\" style=\\\"flex:2;padding:13px\\\"><span class=\\\"en-txt\\\">Yes, add photos</span><span class=\\\"hi-txt\\\">हाँ, जोड़ें</span></button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"bdialogNo()\\\" style=\\\"flex:1;padding:13px\\\"><span class=\\\"en-txt\\\">Skip</span><span class=\\\"hi-txt\\\">छोड़ें</span></button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- DELETE REASON MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"delete-reason-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"padding-bottom:28px;max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">🗑 Delete Recce</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"del-modal-sub\\\">Select reason for deletion:</div>\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-wrong\\\" onclick=\\\"selectDeleteReason('wrong')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">❌</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Wrong</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Incorrect store / submission error</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt\\\" id=\\\"reason-duplicate\\\" onclick=\\\"selectDeleteReason('duplicate')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">📋</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Duplicate</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">Same store submitted more than once</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div class=\\\"reason-opt danger\\\" id=\\\"reason-test\\\" onclick=\\\"selectDeleteReason('test')\\\">\u001b[39m\n\u001b[31m        <span class=\\\"reason-opt-ico\\\">⚠️</span>\u001b[39m\n\u001b[31m        <div>\u001b[39m\n\u001b[31m          <div style=\\\"font-weight:600\\\">Test Recce</div>\u001b[39m\n\u001b[31m          <div style=\\\"font-size:12px;color:#9a3412;margin-top:2px\\\">Permanently deleted — no audit trail</div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p no-reason\\\" id=\\\"del-confirm-btn\\\" onclick=\\\"confirmDelete()\\\" style=\\\"flex:2;padding:13px;background:var(--rd)\\\">Delete</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"closeDeleteModal()\\\" style=\\\"flex:1;padding:13px\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- EDIT REQUEST MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"edit-req-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Request Edit</div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-sub\\\" id=\\\"er-store-name\\\" style=\\\"font-weight:600;color:var(--nv);margin-bottom:4px\\\"></div>\u001b[39m\n\u001b[31m    <div style=\\\"font-size:13px;color:var(--g500);margin-bottom:14px\\\">Add a note for the creator (optional)</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:16px\\\">\u001b[39m\n\u001b[31m      <textarea id=\\\"er-comment\\\" placeholder=\\\"e.g. Please re-check store address and re-upload front photo\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px;color:var(--nv);resize:vertical;min-height:80px;background:#fff\\\"></textarea>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button id=\\\"er-assign-btn\\\" class=\\\"btn-p\\\" onclick=\\\"assignEditToCreator()\\\" style=\\\"padding:14px\\\">👤 Assign to Creator</button>\u001b[39m\n\u001b[31m      <button class=\\\"btn-s\\\" onclick=\\\"supervisorEditMyself()\\\" style=\\\"padding:14px\\\">✏ Edit Myself</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <button onclick=\\\"closeEditRequestModal()\\\" style=\\\"width:100%;margin-top:10px;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- BRAND EDIT MODAL -->\u001b[39m\n\u001b[31m<div class=\\\"bdialog-wrap\\\" id=\\\"brand-edit-modal\\\">\u001b[39m\n\u001b[31m  <div class=\\\"bdialog\\\" style=\\\"max-height:85vh;overflow-y:auto\\\">\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-title\\\">✏ Edit Brand</div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Brand Name <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"text\\\" id=\\\"be-name\\\" placeholder=\\\"e.g. PHILIPS\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:15px;font-weight:600;text-transform:uppercase\\\">\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\">\u001b[39m\n\u001b[31m      <label style=\\\"font-size:13px;font-weight:600;color:var(--nv);margin-bottom:5px;display:block\\\">Logo URL <span style=\\\"font-size:11px;font-weight:400;color:var(--g400)\\\">(optional)</span></label>\u001b[39m\n\u001b[31m      <input type=\\\"url\\\" id=\\\"be-logo\\\" placeholder=\\\"https://…/logo.svg\\\" oninput=\\\"previewBrandLogo()\\\" style=\\\"width:100%;padding:11px 13px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:13px\\\">\u001b[39m\n\u001b[31m      <div id=\\\"be-logo-preview\\\" style=\\\"margin-top:8px;min-height:36px;display:flex;align-items:center;gap:8px\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div id=\\\"be-cascade-info\\\" style=\\\"display:none;font-size:12px;color:var(--g500);padding:8px 12px;background:var(--g50);border-radius:var(--rs);margin-bottom:12px\\\"></div>\u001b[39m\n\u001b[31m    <div class=\\\"bdialog-btns\\\" style=\\\"flex-direction:column;gap:10px\\\">\u001b[39m\n\u001b[31m      <button class=\\\"btn-p\\\" onclick=\\\"saveBrandEdit()\\\" style=\\\"padding:14px\\\">Save</button>\u001b[39m\n\u001b[31m      <button onclick=\\\"closeBrandEditModal()\\\" style=\\\"width:100%;background:none;border:none;color:var(--g500);font-size:14px;padding:8px;cursor:pointer\\\">Cancel</button>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<!-- FONT SIZE WIDGET -->\u001b[39m\n\u001b[31m<div class=\\\"fs-widget\\\" id=\\\"fs-widget\\\">\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-dec\\\" onclick=\\\"changeFontSize(-1)\\\" title=\\\"Decrease font size\\\" aria-label=\\\"Decrease font size\\\">A<sup style=\\\"font-size:9px\\\">−</sup></button>\u001b[39m\n\u001b[31m  <span class=\\\"fs-label\\\" id=\\\"fs-lbl\\\">A</span>\u001b[39m\n\u001b[31m  <button class=\\\"fs-btn\\\" id=\\\"fs-inc\\\" onclick=\\\"changeFontSize(1)\\\" title=\\\"Increase font size\\\" aria-label=\\\"Increase font size\\\"><strong>A</strong><sup style=\\\"font-size:9px\\\">+</sup></button>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div class=\\\"upd-banner\\\" id=\\\"upd-banner\\\">\u001b[39m\n\u001b[31m  <span style=\\\"font-size:13px;font-weight:600;line-height:1.4\\\"><span class=\\\"en-txt\\\">✓ App updated to latest version</span><span class=\\\"hi-txt\\\">✓ ऐप नया संस्करण अपडेट हुआ</span></span>\u001b[39m\n\u001b[31m  <button class=\\\"upd-banner-ok\\\" onclick=\\\"dismissUpdateBanner()\\\"><span class=\\\"en-txt\\\">OK</span><span class=\\\"hi-txt\\\">ठीक है</span></button>\u001b[39m\n\u001b[31m</div>\u001b[39m\n\u001b[31m<div class=\\\"toast\\\" id=\\\"toast\\\"></div>\u001b[39m\n\u001b[31m<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js\\\"></script>\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m// LANGUAGE\u001b[39m\n\u001b[31mlet LANG = localStorage.getItem('recce-lang') || 'en';\u001b[39m\n\u001b[31mfunction setLang(l) {\u001b[39m\n\u001b[31m  LANG = l;\u001b[39m\n\u001b[31m  localStorage.setItem('recce-lang', l);\u001b[39m\n\u001b[31m  document.body.classList.toggle('lang-hi', l === 'hi');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction t(en, hi) { return LANG === 'hi' ? hi : en; }·\u001b[39m\n\u001b[31m// FONT SIZE\u001b[39m\n\u001b[31mlet FS_LEVEL = parseInt(localStorage.getItem('recce-fs') || '0', 10);\u001b[39m\n\u001b[31mconst FS_LABELS = ['A', 'A+', 'A++', 'A+++', 'A++++'];\u001b[39m\n\u001b[31mfunction applyFontSize() {\u001b[39m\n\u001b[31m  document.body.classList.remove('fs-0', 'fs-1', 'fs-2');\u001b[39m\n\u001b[31m  if (FS_LEVEL > 0) document.body.classList.add('fs-' + FS_LEVEL);\u001b[39m\n\u001b[31m  const lbl = document.getElementById('fs-lbl');\u001b[39m\n\u001b[31m  if (lbl) lbl.textContent = FS_LABELS[FS_LEVEL];\u001b[39m\n\u001b[31m  const dec = document.getElementById('fs-dec');\u001b[39m\n\u001b[31m  const inc = document.getElementById('fs-inc');\u001b[39m\n\u001b[31m  if (dec) dec.disabled = FS_LEVEL === 0;\u001b[39m\n\u001b[31m  if (inc) inc.disabled = FS_LEVEL === 4;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction changeFontSize(delta) {\u001b[39m\n\u001b[31m  FS_LEVEL = Math.min(4, Math.max(0, FS_LEVEL + delta));\u001b[39m\n\u001b[31m  localStorage.setItem('recce-fs', FS_LEVEL);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Hub auth gate\u001b[39m\n\u001b[31m(function() {\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (!s || !s.loginAt || Date.now() - new Date(s.loginAt).getTime() > 12 * 3600 * 1000) {\u001b[39m\n\u001b[31m      window.location.replace('/hub/');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) { window.location.replace('/hub/'); }\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31m// STATE\u001b[39m\n\u001b[31mlet F={},frontPhotos=[],insidePhotos=[],addlPhotos=[],brandings=[];\u001b[39m\n\u001b[31mlet videoBlob=null,submissionDoc=null,_docExistingUrl=null,gpsCoords=null;\u001b[39m\n\u001b[31mlet stores=[],selectedStore=null,manualMode=false,DB;\u001b[39m\n\u001b[31mlet imgQuality='compressed'; // 'compressed' | 'hd'\u001b[39m\n\u001b[31mlet geoStampEnabled=true;    // stamp GPS+timestamp on every photo\u001b[39m\n\u001b[31mlet brands=['PHILIPS']; // editable brand list\u001b[39m\n\u001b[31mlet _brandLogos={};   // name → logo_url, loaded from DB\u001b[39m\n\u001b[31mlet _selectedClient=''; // currently selected client chip value\u001b[39m\n\u001b[31mlet _clientOtherMode=false; // true when \\\"Other\\\" chip selected\u001b[39m\n\u001b[31mconst BTYPE=['Glow Sign Board','Inshop Branding','ACP Board','One Way Vision','Fabric Board','Lollypop','Non Lit Flex','Double Side GSB','Clip on Board','Translit','Vinyl Printing','Roll up Standee','Sunboard Standee'];\u001b[39m\n\u001b[31mconst CACHE_VER='recce-v37'; // campaign dropdown + pending job link tab·\u001b[39m\n\u001b[31m// DB\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',3);r.onupgradeneeded=e=>{const d=e.target.result;['subs','cfg','draft'].forEach(s=>{if(!d.objectStoreNames.contains(s))d.createObjectStore(s,{keyPath:'k'||'id'});});if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);});}\u001b[39m\n\u001b[31mfunction initDB(){return new Promise((res,rej)=>{const r=indexedDB.open('RecceDB',4);r.onupgradeneeded=e=>{const d=e.target.result;if(!d.objectStoreNames.contains('subs'))d.createObjectStore('subs',{keyPath:'id'});if(!d.objectStoreNames.contains('cfg'))d.createObjectStore('cfg',{keyPath:'k'});if(!d.objectStoreNames.contains('draft'))d.createObjectStore('draft',{keyPath:'k'});};r.onsuccess=e=>{DB=e.target.result;res(DB);};r.onerror=()=>rej(r.error);})}\u001b[39m\n\u001b[31mfunction dbGet(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).get(k);r.onsuccess=()=>res(r.result);r.onerror=()=>res(null);}catch{res(null)}})}\u001b[39m\n\u001b[31mfunction dbPut(s,v){return new Promise((res,rej)=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).put(v);r.onsuccess=()=>res();r.onerror=()=>rej();}catch(e){rej(e)}})}\u001b[39m\n\u001b[31mfunction dbAll(s){return new Promise(res=>{try{const r=DB.transaction(s,'readonly').objectStore(s).getAll();r.onsuccess=()=>res(r.result);r.onerror=()=>res([]);}catch{res([])}})}\u001b[39m\n\u001b[31mfunction dbDel(s,k){return new Promise(res=>{try{const r=DB.transaction(s,'readwrite').objectStore(s).delete(k);r.onsuccess=()=>res();r.onerror=()=>res();}catch{res()}})}\u001b[39m\n\u001b[31masync function cfg(k,v){if(v===undefined){const r=await dbGet('cfg',k);return r?r.v:null;}await dbPut('cfg',{k,v});}·\u001b[39m\n\u001b[31m// COMPRESS — respects imgQuality setting\u001b[39m\n\u001b[31mfunction compress(file, maxPxOverride, qOverride){\u001b[39m\n\u001b[31m  const maxPx = maxPxOverride || (imgQuality==='hd' ? 1920 : 1280);\u001b[39m\n\u001b[31m  const q     = qOverride     || (imgQuality==='hd' ? 0.90 : 0.78);\u001b[39m\n\u001b[31m  return new Promise(res=>{const img=new Image(),url=URL.createObjectURL(file);img.onload=()=>{const sc=Math.min(1,maxPx/Math.max(img.width,img.height));const c=document.createElement('canvas');c.width=Math.round(img.width*sc);c.height=Math.round(img.height*sc);c.getContext('2d').drawImage(img,0,0,c.width,c.height);URL.revokeObjectURL(url);c.toBlob(b=>res(b),'image/jpeg',q);};img.onerror=()=>{URL.revokeObjectURL(url);res(file)};img.src=url;});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction b64(blob){return new Promise(res=>{const r=new FileReader();r.onload=()=>res(r.result);r.readAsDataURL(blob)})}\u001b[39m\n\u001b[31mfunction fmtSz(b){if(b<1024)return b+'B';if(b<1048576)return(b/1024).toFixed(0)+'KB';return(b/1048576).toFixed(1)+'MB'}·\u001b[39m\n\u001b[31m// STORE LIST\u001b[39m\n\u001b[31mlet _storeFiles=[]; // track uploaded files {name, brand, count}\u001b[39m\n\u001b[31mlet _pendingParse=null; // parsed rows waiting for brand assignment·\u001b[39m\n\u001b[31mfunction parseStoreRow(row, keyFn){\u001b[39m\n\u001b[31m  const v=k=>{\u001b[39m\n\u001b[31m    // Try exact match first, then partial\u001b[39m\n\u001b[31m    const exactKey=Object.keys(row||{}).find(hk=>hk.toLowerCase()===k);\u001b[39m\n\u001b[31m    const partKey=Object.keys(row||{}).find(hk=>hk.toLowerCase().includes(k));\u001b[39m\n\u001b[31m    const useKey=exactKey||partKey;\u001b[39m\n\u001b[31m    if(useKey)return row[useKey]!=null?row[useKey].toString().trim():'';\u001b[39m\n\u001b[31m    // CSV path: keyFn provides value directly\u001b[39m\n\u001b[31m    const col=keyFn(k);return col!=null?col.toString().trim():'';\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const name    = v('sub dealer name')||v('sub dealer')||v('dealer name')||v('store name')||v('store')||v('name');\u001b[39m\n\u001b[31m  const address = v('address')||v('addr')||v('location')||v('area');\u001b[39m\n\u001b[31m  // Contact Detail often stored as a number — toString handles it\u001b[39m\n\u001b[31m  const rawMob  = v('contact detail')||v('contact no.')||v('contact no')||v('mobile no')||v('mobile')||v('phone')||v('mob')||v('contact');\u001b[39m\n\u001b[31m  const mobile  = rawMob.replace(/\\\\D/g,'').slice(-10);\u001b[39m\n\u001b[31m  // Brand: EXACT match only — \\\"Brand\\\" or \\\"Brand Name\\\" columns\u001b[39m\n\u001b[31m  // Partial match is intentionally avoided here because \\\"Inshop Branding\\\" contains \\\"brand\\\"\u001b[39m\n\u001b[31m  const brandKey=Object.keys(row||{}).find(hk=>{\u001b[39m\n\u001b[31m    const lk=hk.toLowerCase().trim();\u001b[39m\n\u001b[31m    return lk==='brand'||lk==='brand name'||lk==='brand_name'||lk==='brandname';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const brand=brandKey?(row[brandKey]||'').toString().trim().toUpperCase():'';\u001b[39m\n\u001b[31m  const distName= v('dist name')||v('distributor name')||v('distributor')||v('dist')||v('territory')||v('tsm')||v('asm');\u001b[39m\n\u001b[31m  const city    = v('city')||v('district')||v('town');\u001b[39m\n\u001b[31m  const sales   = v('2025 full year')||v('2025')||v('full year sales')||v('fy25')||v('sales');\u001b[39m\n\u001b[31m  const proj    = v('2026 projection')||v('2026')||v('projection')||v('fy26')||v('target');\u001b[39m\n\u001b[31m  const glowSign= v('glow sign')||v('glow');\u001b[39m\n\u001b[31m  const inshop  = v('inshop branding')||v('inshop')||v('in-shop')||v('in shop');\u001b[39m\n\u001b[31m  return {name, brand, address, mobile, distName, city, sales, proj, glowSign, inshop};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction dedupeStores(list){\u001b[39m\n\u001b[31m  const seen=new Map();\u001b[39m\n\u001b[31m  list.forEach(s=>{\u001b[39m\n\u001b[31m    // Include address in key — same store name at different locations = different stores\u001b[39m\n\u001b[31m    const key=(s.name.toLowerCase().trim())+'__'+(s.brand||'').toLowerCase()\u001b[39m\n\u001b[31m              +'__'+(s.address||'').toLowerCase().trim().slice(0,30);\u001b[39m\n\u001b[31m    if(!seen.has(key))seen.set(key,s);\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // True duplicate — merge missing fields from second record\u001b[39m\n\u001b[31m      const ex=seen.get(key);\u001b[39m\n\u001b[31m      Object.keys(s).forEach(k=>{ if(!ex[k]&&s[k])ex[k]=s[k]; });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  return Array.from(seen.values());\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderStoreFileList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-file-list');if(!el)return;\u001b[39m\n\u001b[31m  if(!_storeFiles.length){el.innerHTML='';return;}\u001b[39m\n\u001b[31m  el.innerHTML=_storeFiles.map((f,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:5px;font-size:12px\\\">\u001b[39m\n\u001b[31m      <div>\u001b[39m\n\u001b[31m        <span style=\\\"font-weight:600;color:var(--nv)\\\">${f.name}</span>\u001b[39m\n\u001b[31m        <span style=\\\"color:var(--g500);margin-left:6px\\\">${f.count} stores</span>\u001b[39m\n\u001b[31m        ${f.brand?`<span style=\\\"background:var(--nv);color:#fff;font-size:10px;font-weight:700;padding:1px 7px;border-radius:20px;margin-left:5px\\\">${f.brand}</span>`:'<span style=\\\"background:var(--g300);color:var(--g600);font-size:10px;padding:1px 7px;border-radius:20px;margin-left:5px\\\">Mixed brands</span>'}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <button onclick=\\\"removeStoreFile(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:17px;cursor:pointer;padding:0 4px;line-height:1\\\">×</button>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function removeStoreFile(i){\u001b[39m\n\u001b[31m  _storeFiles.splice(i,1);\u001b[39m\n\u001b[31m  // Rebuild stores from remaining files — re-parse from cache not possible, so just reload from DB and remove this file's contribution\u001b[39m\n\u001b[31m  // Simplest approach: clear and ask user to re-upload remaining files\u001b[39m\n\u001b[31m  if(!_storeFiles.length){stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    // Can't re-parse without original files; just note it and keep current store list\u001b[39m\n\u001b[31m    toast('Removed from list. Re-upload the remaining files to refresh store list.','info');\u001b[39m\n\u001b[31m    _storeFiles.splice(0); // clear tracking since we can't reconstruct\u001b[39m\n\u001b[31m    stores=[];await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderStoreFileList();\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=stores.length?`✓ ${stores.length} stores`:'No stores loaded';\u001b[39m\n\u001b[31m  updAvailTag();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function clearStoreList(){\u001b[39m\n\u001b[31m  if(!confirm('Remove all loaded stores?'))return;\u001b[39m\n\u001b[31m  stores=[];_storeFiles=[];\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify([]));await cfg('store-files',JSON.stringify([]));\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent='';\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast('Store list cleared','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function handleStoreUpload(e){\u001b[39m\n\u001b[31m  const file=e.target.files[0];if(!file)return;\u001b[39m\n\u001b[31m  e.target.value=''; // allow same file re-upload\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    let data=[];\u001b[39m\n\u001b[31m    if(file.name.toLowerCase().endsWith('.csv')){\u001b[39m\n\u001b[31m      const txt=await file.text();\u001b[39m\n\u001b[31m      const rows=txt.split('\\\\n').map(r=>r.split(',').map(c=>c.trim().replace(/^\\\"|\\\"$/g,'')));\u001b[39m\n\u001b[31m      if(!rows.length||!rows[0].length){toast('Empty CSV','error');return;}\u001b[39m\n\u001b[31m      const h=rows[0];\u001b[39m\n\u001b[31m      data=rows.slice(1).filter(r=>r.length>1&&r.some(c=>c)).map(r=>{\u001b[39m\n\u001b[31m        const rowObj={};h.forEach((hk,i)=>{rowObj[hk]=r[i]||'';});\u001b[39m\n\u001b[31m        return parseStoreRow(rowObj, ()=>'');\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }else{\u001b[39m\n\u001b[31m      const ab=await file.arrayBuffer();const wb=XLSX.read(ab,{type:'array'});\u001b[39m\n\u001b[31m      const js=XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]],{defval:''});\u001b[39m\n\u001b[31m      data=js.map(row=>parseStoreRow(row,()=>''));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    data=data.filter(d=>d.name.trim());\u001b[39m\n\u001b[31m    if(!data.length){toast('No valid rows found in file','error');return;}\u001b[39m\n\u001b[31m    // Check if any store has a brand\u001b[39m\n\u001b[31m    const hasBrand=data.some(d=>d.brand);\u001b[39m\n\u001b[31m    // Always show preview first before merging\u001b[39m\n\u001b[31m    _pendingParse={file:file.name,data,hasBrand};\u001b[39m\n\u001b[31m    showStorePreview(file.name, data, hasBrand);\u001b[39m\n\u001b[31m  }catch(err){toast('Failed: '+err.message,'error')}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mlet _pendingBrand='';\u001b[39m\n\u001b[31mfunction setPendingBrand(b){\u001b[39m\n\u001b[31m  _pendingBrand=b;\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-assign-chips .chip').forEach(c=>{\u001b[39m\n\u001b[31m    c.classList.toggle('sel',c.textContent===b);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  if(!_pendingBrand){toast('Select a brand first','error');return;}\u001b[39m\n\u001b[31m  // Assign brand to all rows in this file\u001b[39m\n\u001b[31m  const data=_pendingParse.data.map(s=>({...s,brand:_pendingBrand}));\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, data, _pendingBrand);\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function skipBrandAssign(){\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  await mergeStores(_pendingParse.file, _pendingParse.data, '');\u001b[39m\n\u001b[31m  _pendingParse=null;_pendingBrand='';\u001b[39m\n\u001b[31m  document.getElementById('brand-assign-dialog').style.display='none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showStorePreview(filename, data, hasBrand){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-preview-dialog');\u001b[39m\n\u001b[31m  const tbody=document.getElementById('store-preview-body');\u001b[39m\n\u001b[31m  document.getElementById('store-preview-title').textContent=`${filename} · ${data.length} ${t('stores found','स्टोर मिले')}`;\u001b[39m\n\u001b[31m  // Show first 8 rows\u001b[39m\n\u001b[31m  const sample=data.slice(0,8);\u001b[39m\n\u001b[31m  tbody.innerHTML=sample.map(s=>`<tr>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;font-weight:500\\\">${s.name||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.address||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500)\\\">${s.mobile||'—'}</td>\u001b[39m\n\u001b[31m    <td style=\\\"padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px\\\"><span style=\\\"background:${s.brand?'var(--nv)':'var(--rd)'};color:#fff;padding:1px 7px;border-radius:10px;font-size:10px\\\">${s.brand||'?'}</span></td>\u001b[39m\n\u001b[31m  </tr>`).join('');\u001b[39m\n\u001b[31m  if(data.length>8)tbody.innerHTML+=`<tr><td colspan=\\\"4\\\" style=\\\"text-align:center;padding:8px;font-size:12px;color:var(--g400)\\\">…and ${data.length-8} more stores</td></tr>`;\u001b[39m\n\u001b[31m  el.classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function confirmStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  if(!_pendingParse)return;\u001b[39m\n\u001b[31m  const {file,data,hasBrand}=_pendingParse;\u001b[39m\n\u001b[31m  if(!hasBrand){\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-fname').textContent=`File: ${file} · ${data.length} stores found · No brand column detected`;\u001b[39m\n\u001b[31m    const chips=document.getElementById('brand-assign-chips');\u001b[39m\n\u001b[31m    chips.innerHTML=brands.map(b=>`<div class=\\\"chip\\\" onclick=\\\"setPendingBrand('${b}')\\\" id=\\\"bac-${b}\\\">${b}</div>`).join('');\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').style.display='block';\u001b[39m\n\u001b[31m    document.getElementById('brand-assign-dialog').scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    await mergeStores(file, data, '');\u001b[39m\n\u001b[31m    _pendingParse=null;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction cancelStorePreview(){\u001b[39m\n\u001b[31m  document.getElementById('store-preview-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingParse=null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function mergeStores(filename, newData, assignedBrand){\u001b[39m\n\u001b[31m  const before=stores.length;\u001b[39m\n\u001b[31m  stores=[...stores,...newData];\u001b[39m\n\u001b[31m  stores=dedupeStores(stores);\u001b[39m\n\u001b[31m  const added=stores.length-before;\u001b[39m\n\u001b[31m  const dupes=newData.length-added;\u001b[39m\n\u001b[31m  await cfg('stores',JSON.stringify(stores));\u001b[39m\n\u001b[31m  // Track file\u001b[39m\n\u001b[31m  _storeFiles.push({name:filename,count:newData.length,brand:assignedBrand||''});\u001b[39m\n\u001b[31m  await cfg('store-files',JSON.stringify(_storeFiles));\u001b[39m\n\u001b[31m  const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m  document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m    `✓ ${stores.length} total stores${dupes>0?` · ${dupes} duplicate${dupes>1?'s':''} removed`:''}${noBrand?` · ${noBrand} without brand`:' · All have brand'}`;\u001b[39m\n\u001b[31m  renderStoreFileList();updAvailTag();\u001b[39m\n\u001b[31m  toast(`${added} stores added${dupes>0?`, ${dupes} duplicates skipped`:''}${assignedBrand?' as '+assignedBrand:''}`, 'success');\u001b[39m\n\u001b[31m  // Show server-push button for supervisors\u001b[39m\n\u001b[31m  const pb = document.getElementById('store-push-btn');\u001b[39m\n\u001b[31m  if (pb) pb.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function fetchServerStores(){const url=document.getElementById('srv-url').value.trim();if(!url){toast('Enter a URL first','error');return;}try{toast('Fetching…','info');const r=await fetch(url);const j=await r.json();const fetched=Array.isArray(j)?j:j.stores||[];await mergeStores('Server ('+url.split('/').pop()+')',fetched,'');await cfg('srv-url',url);}catch{toast('Fetch failed — check URL','error')}}\u001b[39m\n\u001b[31masync function saveServerUrl(){await cfg('srv-url',document.getElementById('srv-url').value.trim());toast('URL saved','success')}\u001b[39m\n\u001b[31mconst DEFAULT_GAS_URL='https://script.google.com/macros/s/AKfycbwyufC7gQyu1BErCxiDlbQUn0AWiIWv7nEmjk4UcAx3dvlV6bGk7q5fQOiv82CTbokbkA/exec';·\u001b[39m\n\u001b[31mconst DEFAULT_STORES_URL='/recce/stores.json';\u001b[39m\n\u001b[31mconst _RECCE_CFG_URL='/recce/recce-cfg.json';·\u001b[39m\n\u001b[31m// Admin auto-unlock for harish/pramod via hub session\u001b[39m\n\u001b[31mconst _RECCE_ADMIN_IDS = ['harish', 'pramod', 'rakesh'];\u001b[39m\n\u001b[31mconst _RECCE_CFG_ADMINS = ['harish', 'pramod'];\u001b[39m\n\u001b[31mlet _adminRows = [];\u001b[39m\n\u001b[31mlet _myServerRows = [];\u001b[39m\n\u001b[31mlet _adminUnlocked = false;\u001b[39m\n\u001b[31mlet _recceCfg = { version: 1, supervisors: ['harish','pramod','rakesh'], mode: 'public', creators: [], allowed_users: [] };\u001b[39m\n\u001b[31mfunction _isSupervisor() {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  return !!(hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId));\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _showDeletedView = false;\u001b[39m\n\u001b[31mlet _supCreateMode = false;\u001b[39m\n\u001b[31mlet _pendingDeleteId = null;\u001b[39m\n\u001b[31mlet _pendingDeleteReason = null;\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const s = JSON.parse(localStorage.getItem('lm360-session') || 'null');\u001b[39m\n\u001b[31m    if (s?.empId && _RECCE_ADMIN_IDS.includes(s.empId)) _adminUnlocked = true;\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m})();·\u001b[39m\n\u001b[31masync function loadRecceCfg(){\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(_RECCE_CFG_URL + '?t=' + Date.now());\u001b[39m\n\u001b[31m    if (r.ok) {\u001b[39m\n\u001b[31m      const j = await r.json();\u001b[39m\n\u001b[31m      if (j && j.version) {\u001b[39m\n\u001b[31m        _recceCfg = j;\u001b[39m\n\u001b[31m        if (Array.isArray(j.supervisors) && j.supervisors.length) {\u001b[39m\n\u001b[31m          _recceCfg.supervisors = j.supervisors;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.creators)) _recceCfg.creators = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.allowed_users)) _recceCfg.allowed_users = [];\u001b[39m\n\u001b[31m        if (!Array.isArray(_recceCfg.clients)) _recceCfg.clients = [];\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  // Re-check admin status against server supervisor list\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (hub?.empId && Array.isArray(_recceCfg.supervisors) && _recceCfg.supervisors.includes(hub.empId)) {\u001b[39m\n\u001b[31m    _adminUnlocked = true;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _checkAccessMode(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (_recceCfg.mode !== 'assigned') return;\u001b[39m\n\u001b[31m  const allowed = [\u001b[39m\n\u001b[31m    ...(_recceCfg.supervisors || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.creators || []),\u001b[39m\n\u001b[31m    ...(_recceCfg.allowed_users || []),\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  if (hub?.empId && allowed.includes(hub.empId)) return;\u001b[39m\n\u001b[31m  // Block access — show locked overlay\u001b[39m\n\u001b[31m  document.body.innerHTML = `<div style=\\\"min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0f172a;color:#fff;padding:32px;text-align:center\\\"><div style=\\\"font-size:48px;margin-bottom:16px\\\">🔒</div><div style=\\\"font-size:20px;font-weight:700;margin-bottom:8px\\\">${t('Access Restricted','एक्सेस प्रतिबंधित')}</div><div style=\\\"font-size:14px;color:#94a3b8\\\">${t('You are not authorised to use Branding Recce. Please contact your supervisor.','आप ब्रांडिंग रेक्की उपयोग के लिए अधिकृत नहीं हैं।')}</div></div>`;\u001b[39m\n\u001b[31m  throw new Error('access-restricted');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _recceHubUser() {\u001b[39m\n\u001b[31m  try { return JSON.parse(localStorage.getItem('lm360-session') || '{}'); }\u001b[39m\n\u001b[31m  catch(_) { return {}; }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── Supervisor config management ────────────────────────────────────\u001b[39m\n\u001b[31mfunction renderSupPanel(){\u001b[39m\n\u001b[31m  if (!_adminUnlocked) return;\u001b[39m\n\u001b[31m  const panel = document.getElementById('sup-panel');\u001b[39m\n\u001b[31m  if (panel) panel.style.display = 'block';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const modePublic = document.getElementById('mode-public');\u001b[39m\n\u001b[31m  const modeAssigned = document.getElementById('mode-assigned');\u001b[39m\n\u001b[31m  if (modePublic && modeAssigned) {\u001b[39m\n\u001b[31m    modePublic.classList.toggle('sel', _recceCfg.mode !== 'assigned');\u001b[39m\n\u001b[31m    modeAssigned.classList.toggle('sel', _recceCfg.mode === 'assigned');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  const addRow = document.getElementById('sup-add-row');\u001b[39m\n\u001b[31m  if (addRow) addRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const creatorAddRow = document.getElementById('creator-add-row');\u001b[39m\n\u001b[31m  if (creatorAddRow) creatorAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const clientAddRow = document.getElementById('client-add-row');\u001b[39m\n\u001b[31m  if (clientAddRow) clientAddRow.style.display = isCfgAdmin ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const modeRow = document.getElementById('mode-row');\u001b[39m\n\u001b[31m  if (modeRow) {\u001b[39m\n\u001b[31m    modeRow.style.display = 'block';\u001b[39m\n\u001b[31m    // Non-cfg-admins see mode as read-only (toggles exist but setRecceMode guards them)\u001b[39m\n\u001b[31m    modeRow.style.opacity = isCfgAdmin ? '1' : '0.65';\u001b[39m\n\u001b[31m    modeRow.style.pointerEvents = isCfgAdmin ? '' : 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const syncBtn = document.getElementById('cfg-sync-btn');\u001b[39m\n\u001b[31m  if (syncBtn) syncBtn.style.display = isCfgAdmin ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('sup-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const sups = _recceCfg.supervisors || [];\u001b[39m\n\u001b[31m  el.innerHTML = sups.map((s,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${s}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin && sups.length > 1 ? `<button onclick=\\\"removeSupervisor(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderCreatorsList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('creator-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const creators = _recceCfg.creators || [];\u001b[39m\n\u001b[31m  el.innerHTML = creators.length ? creators.map((u,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${u}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeCreator(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No creators yet — any Hub user can submit in Public mode.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setRecceMode(mode){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.mode = mode;\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addSupervisor(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('sup-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.supervisors = [...(_recceCfg.supervisors || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeSupervisor(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.supervisors = (_recceCfg.supervisors || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderSupList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addCreator(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('creator-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim().toLowerCase();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter employee ID','ID दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.creators || []).includes(val)) { toast(t('Already a creator','पहले से क्रिएटर है'), 'info'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.supervisors || []).includes(val)) { toast(t('Already a supervisor (includes creation rights)','पहले से सुपरवाइजर है'), 'info'); return; }\u001b[39m\n\u001b[31m  _recceCfg.creators = [...(_recceCfg.creators || []), val];\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeCreator(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.creators = (_recceCfg.creators || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderCreatorsList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderClientMgmtList(){\u001b[39m\n\u001b[31m  const el = document.getElementById('client-mgmt-list'); if (!el) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const isCfgAdmin = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const list = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  el.innerHTML = list.length ? list.map((c,i) => `\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${esc(c)}</span>\u001b[39m\n\u001b[31m      ${isCfgAdmin ? `<button onclick=\\\"removeClientFromList(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:0 4px\\\">×</button>` : ''}\u001b[39m\n\u001b[31m    </div>`).join('') : '<div style=\\\"font-size:13px;color:var(--g400);padding:6px 0\\\">No clients yet — add client or agency names to show them as chips in the form.</div>';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addClientToList(){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  const inp = document.getElementById('client-add-inp'); if (!inp) return;\u001b[39m\n\u001b[31m  const val = inp.value.trim();\u001b[39m\n\u001b[31m  if (!val) { toast(t('Enter client name','क्लाइंट नाम दर्ज करें'), 'error'); return; }\u001b[39m\n\u001b[31m  if ((_recceCfg.clients || []).includes(val)) { toast(t('Already in list','पहले से मौजूद है'), 'info'); return; }\u001b[39m\n\u001b[31m  if (!_recceCfg.clients) _recceCfg.clients = [];\u001b[39m\n\u001b[31m  _recceCfg.clients.push(val);\u001b[39m\n\u001b[31m  inp.value = '';\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction removeClientFromList(i){\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(_recceHubUser()?.empId)) return;\u001b[39m\n\u001b[31m  _recceCfg.clients = (_recceCfg.clients || []).filter((_,idx) => idx !== i);\u001b[39m\n\u001b[31m  renderClientMgmtList();\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncCfgToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast(t('Not authorised','अधिकृत नहीं'), 'error'); return; }\u001b[39m\n\u001b[31m  const st = document.getElementById('cfg-sync-status');\u001b[39m\n\u001b[31m  if (st) st.textContent = t('Syncing…','सिंक हो रहा है…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-cfg', empId: hub.empId, cfg: {\u001b[39m\n\u001b[31m        version: _recceCfg.version || 1,\u001b[39m\n\u001b[31m        supervisors: _recceCfg.supervisors || [],\u001b[39m\n\u001b[31m        mode: _recceCfg.mode || 'public',\u001b[39m\n\u001b[31m        creators: _recceCfg.creators || [],\u001b[39m\n\u001b[31m        allowed_users: _recceCfg.allowed_users || [],\u001b[39m\n\u001b[31m        clients: _recceCfg.clients || [],\u001b[39m\n\u001b[31m      }})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) {\u001b[39m\n\u001b[31m      toast(t('Config synced to server ✓','कॉन्फ़िग सर्वर पर सेव हुआ ✓'), 'success');\u001b[39m\n\u001b[31m      if (st) st.textContent = t('Last synced: just now','अभी सिंक हुआ');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast(j.error || t('Sync failed','सिंक विफल'), 'error');\u001b[39m\n\u001b[31m      if (st) st.textContent = j.error || '';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Network error','नेटवर्क त्रुटि'), 'error');\u001b[39m\n\u001b[31m    if (st) st.textContent = e.message;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function pushStoresToServer(){\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!hub?.empId || !_adminUnlocked) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-stores', empId: hub.empId, stores })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const j = await r.json();\u001b[39m\n\u001b[31m    if (j.success) toast(`${t('Pushed to server','सर्वर पर पुश हुआ')} · ${j.count} ${t('stores','स्टोर')}`, 'success');\u001b[39m\n\u001b[31m    else toast(j.error || t('Server push failed','सर्वर पुश विफल'), 'error');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(t('Could not reach server','सर्वर से संपर्क नहीं हो सका'), 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── End supervisor config management ────────────────────────────────·\u001b[39m\n\u001b[31m// PostgREST sync constants\u001b[39m\n\u001b[31mconst _RC_BASE      = '/db';\u001b[39m\n\u001b[31mconst _RC_READ      = { 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_WRITE     = { 'Content-Type': 'application/json', 'Content-Profile': 'recce', 'Accept-Profile': 'recce' };\u001b[39m\n\u001b[31mconst _RC_UPSERT    = { ..._RC_WRITE, 'Prefer': 'resolution=merge-duplicates,return=minimal' };\u001b[39m\n\u001b[31mconst _INSTALL_RD   = { 'Content-Type': 'application/json', 'Accept-Profile': 'installation' };\u001b[39m\n\u001b[31mconst _INSTALL_WR   = { 'Content-Type': 'application/json', 'Content-Profile': 'installation', 'Accept-Profile': 'installation', 'Prefer': 'return=minimal' };·\u001b[39m\n\u001b[31m// ── Campaign selection state ──\u001b[39m\n\u001b[31mlet _selectedCampaignId = null;\u001b[39m\n\u001b[31mlet _notifySupervisor   = false;\u001b[39m\n\u001b[31mlet _campaignList       = [];\u001b[39m\n\u001b[31mlet _pendingJobFilter   = false;\u001b[39m\n\u001b[31mlet _linkJobSubId       = null;\u001b[39m\n\u001b[31mlet _brandingLocked     = false;·\u001b[39m\n\u001b[31mfunction _updateBrandingLock() {\u001b[39m\n\u001b[31m  const hub  = _recceHubUser();\u001b[39m\n\u001b[31m  const isHP = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const banner   = document.getElementById('branding-lock-banner');\u001b[39m\n\u001b[31m  const ovWrap   = document.getElementById('branding-override-wrap');\u001b[39m\n\u001b[31m  const brItems  = document.getElementById('br-items');\u001b[39m\n\u001b[31m  const brAdd    = document.getElementById('br-add');\u001b[39m\n\u001b[31m  const brYes    = document.getElementById('br-yes');\u001b[39m\n\u001b[31m  const brNo     = document.getElementById('br-no');\u001b[39m\n\u001b[31m  if (!banner) return;\u001b[39m\n\u001b[31m  if (_brandingLocked) {\u001b[39m\n\u001b[31m    banner.style.display   = '';\u001b[39m\n\u001b[31m    if (ovWrap)  ovWrap.style.display  = isHP ? '' : 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.pointerEvents = 'none';\u001b[39m\n\u001b[31m    if (brItems) brItems.style.opacity = '0.55';\u001b[39m\n\u001b[31m    if (brAdd)   brAdd.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='none'; brYes.style.opacity='0.5'; }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='none';  brNo.style.opacity='0.5';  }\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    banner.style.display   = 'none';\u001b[39m\n\u001b[31m    if (brItems) { brItems.style.pointerEvents=''; brItems.style.opacity=''; }\u001b[39m\n\u001b[31m    if (brYes)   { brYes.style.pointerEvents='';  brYes.style.opacity='';   }\u001b[39m\n\u001b[31m    if (brNo)    { brNo.style.pointerEvents='';   brNo.style.opacity='';    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction unlockBrandingOverride() {\u001b[39m\n\u001b[31m  if (!confirm(\u001b[39m\n\u001b[31m    'Client has already reviewed this recce.\\\\n' +\u001b[39m\n\u001b[31m    'Editing brandings will NOT remove their approval.\\\\n' +\u001b[39m\n\u001b[31m    'Continue ONLY if the client has verbally confirmed. Proceed?'\u001b[39m\n\u001b[31m  )) return;\u001b[39m\n\u001b[31m  _brandingLocked = false;\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  renderBrandings();\u001b[39m\n\u001b[31m  toast(t('Branding unlocked for this session', 'ब्रांडिंग इस सत्र के लिए अनलॉक'), 'info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadCampaignsForForm() {\u001b[39m\n\u001b[31m  const sel = document.getElementById('f-campaign-id');\u001b[39m\n\u001b[31m  if (!sel) return;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m    _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m  } catch(_) { _campaignList = []; }\u001b[39m\n\u001b[31m  sel.innerHTML =\u001b[39m\n\u001b[31m    '<option value=\\\"\\\">— Select job / campaign (optional) —</option>' +\u001b[39m\n\u001b[31m    _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('') +\u001b[39m\n\u001b[31m    '<option value=\\\"__NOTIFY__\\\">⚑ No campaign yet — notify supervisor</option>';\u001b[39m\n\u001b[31m  if (_selectedCampaignId) sel.value = _selectedCampaignId;\u001b[39m\n\u001b[31m  else if (_notifySupervisor) sel.value = '__NOTIFY__';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onCampaignSelect() {\u001b[39m\n\u001b[31m  const val = document.getElementById('f-campaign-id')?.value || '';\u001b[39m\n\u001b[31m  const noticeEl = document.getElementById('campaign-notify-msg');\u001b[39m\n\u001b[31m  if (val === '__NOTIFY__') {\u001b[39m\n\u001b[31m    _selectedCampaignId = null;\u001b[39m\n\u001b[31m    _notifySupervisor   = true;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'block';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    _selectedCampaignId = val || null;\u001b[39m\n\u001b[31m    _notifySupervisor   = false;\u001b[39m\n\u001b[31m    if (noticeEl) noticeEl.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction generateRecceReportHtml(entry, photoUrls) {\u001b[39m\n\u001b[31m  const d    = entry.data || {};\u001b[39m\n\u001b[31m  const urls = photoUrls || {};\u001b[39m\n\u001b[31m  const agent = entry.submittedByName || entry.submittedBy || 'Field Agent';\u001b[39m\n\u001b[31m  const _safeId      = (entry.id||'').replace(/\\\\//g,'_').replace(/\\\\.\\\\./g,'');\u001b[39m\n\u001b[31m  const serverPdfUrl = _safeId ? `https://srv1111289.hstgr.cloud/screenshots/recce/views/${_safeId}.pdf` : '';\u001b[39m\n\u001b[31m  const brandLogoUrl = d.brandLogoUrl || _brandLogos[d.brand] || '';\u001b[39m\n\u001b[31m  const tsStr = new Date(entry.timestamp).toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric',hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\u001b[39m\n\u001b[31m  const gpsUrl = d.gpsCoords ? `https://maps.google.com/?q=${d.gpsCoords.lat},${d.gpsCoords.lng}` : null;·\u001b[39m\n\u001b[31m  const frontCount  = (urls.front||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const insideCount = (urls.inside||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const addlCount   = (urls.addl||[]).filter(Boolean).length;\u001b[39m\n\u001b[31m  const brCount     = (d.brandings||[]).length;·\u001b[39m\n\u001b[31m  // pages: { id, url, bandHtml, cmt, dotLabel, dotColor }\u001b[39m\n\u001b[31m  const pages = [];·\u001b[39m\n\u001b[31m  (urls.front||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Front View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${frontCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.frontPhotos||[])[i]?.cmt||'', dotLabel:`FV${i+1}`, dotColor:'#3b82f6', catLabel:'Front View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.inside||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Inside View</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${insideCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.insidePhotos||[])[i]?.cmt||'', dotLabel:`IV${i+1}`, dotColor:'#14b8a6', catLabel:'Inside View', tileDims:'' });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (d.brandings||[]).forEach((b,i)=>{\u001b[39m\n\u001b[31m    const url=(urls.brandings||[])[i]; if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">${esc(b.type||'Branding')}</div><div class=\\\"ph-dims\\\">Width : ${esc(b.w||'?')}&Prime;&nbsp;&times;&nbsp;Height : ${esc(b.h||'?')}&Prime;&nbsp;&mdash;&nbsp;${esc(b.qty||1)} Nos</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${brCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:'', dotLabel:`B${i+1}`, dotColor:'#f97316', catLabel:b.type||'Branding',\u001b[39m\n\u001b[31m      tileDims:`${b.w||'?'}″×${b.h||'?'}″ — ${String(b.qty||1).padStart(2,'0')} Nos` });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  (urls.addl||[]).forEach((url,i)=>{\u001b[39m\n\u001b[31m    if(!url) return;\u001b[39m\n\u001b[31m    pages.push({ id:`pg-${pages.length}`, url,\u001b[39m\n\u001b[31m      bandHtml:`<div class=\\\"ph-cat\\\">Additional</div><div class=\\\"ph-no\\\">${i+1}<span class=\\\"ph-of\\\"> / ${addlCount}</span></div>`,\u001b[39m\n\u001b[31m      cmt:(d.addlPhotos||[])[i]?.desc||'', dotLabel:`A${i+1}`, dotColor:'#94a3b8', catLabel:'Additional', tileDims:'' });\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const sideItems = [\u001b[39m\n\u001b[31m    `<div class=\\\"si-item active\\\" data-tgt=\\\"pg-cover\\\" title=\\\"Cover\\\"><div class=\\\"si-dot\\\" style=\\\"background:#475569\\\">CV</div></div>`\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  pages.forEach(p => {\u001b[39m\n\u001b[31m    sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"${p.id}\\\" title=\\\"${p.dotLabel}\\\"><div class=\\\"si-dot\\\" style=\\\"background:${p.dotColor}\\\">${p.dotLabel}</div></div>`);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(d.hasVideo) sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-vid\\\" title=\\\"Video\\\"><div class=\\\"si-dot\\\" style=\\\"background:#a855f7\\\">VD</div></div>`);\u001b[39m\n\u001b[31m  if(urls.doc)   sideItems.push(`<div class=\\\"si-item\\\" data-tgt=\\\"pg-doc\\\" title=\\\"Document\\\"><div class=\\\"si-dot\\\" style=\\\"background:#64748b\\\">DC</div></div>`);·\u001b[39m\n\u001b[31m  const thumbItems = [\u001b[39m\n\u001b[31m    ...pages,\u001b[39m\n\u001b[31m    ...(d.hasVideo?[{id:'pg-vid',url:null,catLabel:'Video',tileDims:'',dotLabel:'VD',dotColor:'#a855f7'}]:[]),\u001b[39m\n\u001b[31m    ...(urls.doc?[{id:'pg-doc',url:urls.doc,catLabel:'Document',tileDims:'',dotLabel:'DC',dotColor:'#64748b'}]:[])\u001b[39m\n\u001b[31m  ];\u001b[39m\n\u001b[31m  const thumbsHtml = thumbItems.map(p=>`<div class=\\\"cov-thumb\\\" onclick=\\\"document.getElementById('${p.id}').scrollIntoView({behavior:'smooth'})\\\">${p.url?`<img src=\\\"${p.url}\\\" alt=\\\"\\\">`:(`<div class=\\\"cov-thumb-vid\\\">${p.catLabel==='Video'?'&#x25B6;&#xFE0F;':'&#x1F4C4;'}</div>`)}<div class=\\\"cov-thumb-ov\\\" style=\\\"border-top:3px solid ${p.dotColor}\\\"><div class=\\\"cov-thumb-cat\\\">${esc(p.catLabel)}</div>${p.tileDims?`<div class=\\\"cov-thumb-dims\\\">${esc(p.tileDims)}</div>`:''}<div class=\\\"cov-thumb-no\\\">${p.dotLabel}</div></div></div>`).join('');·\u001b[39m\n\u001b[31m  const pagesHtml = pages.map(p => `\u001b[39m\n\u001b[31m<div class=\\\"photo-page\\\" id=\\\"${p.id}\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\">${p.bandHtml}</div>\u001b[39m\n\u001b[31m  <div class=\\\"ph-img\\\"><a href=\\\"${p.url}\\\" target=\\\"_blank\\\"><img src=\\\"${p.url}\\\" loading=\\\"lazy\\\" alt=\\\"\\\"></a>${p.cmt?`<div class=\\\"ph-cmt\\\">${esc(p.cmt)}</div>`:''}</div>\u001b[39m\n\u001b[31m</div>`).join('');·\u001b[39m\n\u001b[31m  return `<!DOCTYPE html>\u001b[39m\n\u001b[31m<html lang=\\\"en\\\"><head>\u001b[39m\n\u001b[31m<meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m<title>Recce — ${esc(d.storeName||'Unknown')} · ${esc(d.brand||'')}</title>\u001b[39m\n\u001b[31m<style>\u001b[39m\n\u001b[31m:root{--dk:#0f172a;--nv2:#1a2f52;--or:#f97316;--g200:#e2e8f0;--g400:#94a3b8;--g600:#475569;--si:54px}\u001b[39m\n\u001b[31m*{box-sizing:border-box;margin:0;padding:0}\u001b[39m\n\u001b[31mhtml,body{height:100%;overflow:hidden}\u001b[39m\n\u001b[31mbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#111;color:var(--dk);display:flex}\u001b[39m\n\u001b[31ma{color:var(--or);text-decoration:none}\u001b[39m\n\u001b[31mimg{display:block}·\u001b[39m\n\u001b[31m/* ── Side index ── */\u001b[39m\n\u001b[31m.side-idx{width:var(--si);flex-shrink:0;background:var(--dk);overflow-y:auto;display:flex;flex-direction:column;align-items:center;padding:4px 0;scrollbar-width:none;z-index:50}\u001b[39m\n\u001b[31m.side-idx::-webkit-scrollbar{display:none}\u001b[39m\n\u001b[31m.si-item{width:100%;min-height:56px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s}\u001b[39m\n\u001b[31m.si-item:hover{background:rgba(255,255,255,.07)}\u001b[39m\n\u001b[31m.si-dot{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff;opacity:.4;transition:opacity .18s,transform .18s;line-height:1;text-align:center}\u001b[39m\n\u001b[31m.si-item.active .si-dot{opacity:1;transform:scale(1.15)}·\u001b[39m\n\u001b[31m/* ── Main scroll area ── */\u001b[39m\n\u001b[31m.main{flex:1;overflow-y:scroll;scroll-snap-type:y mandatory;scroll-behavior:smooth;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.15) transparent}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar{width:3px}\u001b[39m\n\u001b[31m.main::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15)}·\u001b[39m\n\u001b[31m/* ── Cover ── */\u001b[39m\n\u001b[31m.cover{height:100vh;scroll-snap-align:start;flex-shrink:0;background:linear-gradient(135deg,#0f172a 0%,var(--nv2) 100%);color:#fff;display:flex;flex-direction:column;padding:24px 20px 20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.cover-badge{display:inline-flex;align-items:center;gap:5px;background:var(--or);color:#fff;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:1px;padding:3px 12px;border-radius:20px;margin-bottom:12px;align-self:flex-start}\u001b[39m\n\u001b[31m.cover h1{font-size:20px;font-weight:700;line-height:1.3;margin-bottom:4px}\u001b[39m\n\u001b[31m.cover-addr{color:rgba(255,255,255,.55);font-size:12px;margin-bottom:16px}\u001b[39m\n\u001b[31m.cg{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}\u001b[39m\n\u001b[31m.cm{background:rgba(255,255,255,.08);border-radius:8px;padding:8px 12px}\u001b[39m\n\u001b[31m.cm-l{font-size:9px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}\u001b[39m\n\u001b[31m.cm-v{font-size:13px;font-weight:600;color:#fff}\u001b[39m\n\u001b[31m.cm-v a{color:#fb923c}\u001b[39m\n\u001b[31m.cover-pbar{padding-top:8px;display:flex;gap:10px;flex-shrink:0}\u001b[39m\n\u001b[31m.btn-p{background:var(--or);color:#fff;border:none;padding:10px 22px;border-radius:22px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit}\u001b[39m\n\u001b[31m.btn-p:disabled{opacity:.4;cursor:not-allowed}\u001b[39m\n\u001b[31m.btn-c{background:rgba(255,255,255,.1);color:rgba(255,255,255,.75);border:1px solid rgba(255,255,255,.2);padding:10px 18px;border-radius:22px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit}·\u001b[39m\n\u001b[31m/* ── Cover thumbnail grid ── */\u001b[39m\n\u001b[31m.cov-grid-hdr{font-size:10px;font-weight:700;color:rgba(255,255,255,.35);text-transform:uppercase;letter-spacing:1.2px;padding:10px 0 5px;flex-shrink:0}\u001b[39m\n\u001b[31m.cov-grid{flex:1;min-height:0;display:grid;gap:5px;overflow:hidden;align-content:start}\u001b[39m\n\u001b[31m.cov-thumb{position:relative;overflow:hidden;border-radius:7px;cursor:pointer;background:#1e293b;transition:transform .18s,box-shadow .18s}\u001b[39m\n\u001b[31m.cov-thumb:hover{transform:scale(1.05);box-shadow:0 4px 18px rgba(0,0,0,.55)}\u001b[39m\n\u001b[31m.cov-thumb img{width:100%;height:100%;object-fit:cover;display:block}\u001b[39m\n\u001b[31m.cov-thumb-vid{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:#0f172a}\u001b[39m\n\u001b[31m.cov-thumb-ov{position:absolute;inset:0;background:rgba(0,0,0,.28);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:5px;border-radius:7px}\u001b[39m\n\u001b[31m.cov-thumb-cat{color:rgba(255,255,255,.5);font-weight:900;text-align:center;text-transform:uppercase;letter-spacing:.8px;text-shadow:0 1px 6px rgba(0,0,0,.95);line-height:1.2;word-break:break-word}\u001b[39m\n\u001b[31m.cov-thumb-dims{color:rgba(255,255,255,.5);font-weight:700;text-align:center;text-shadow:0 1px 5px rgba(0,0,0,.95);letter-spacing:.3px;line-height:1.3}\u001b[39m\n\u001b[31m.cov-thumb-no{color:rgba(255,255,255,.5);font-weight:800;text-shadow:0 1px 4px rgba(0,0,0,.95);letter-spacing:.5px}\u001b[39m\n\u001b[31m#cover-btn{position:fixed;bottom:20px;right:16px;display:none;align-items:center;gap:6px;background:rgba(255,255,255,.15);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.25);color:#fff;padding:10px 22px;border-radius:50px;font-size:13px;font-weight:700;cursor:pointer;z-index:200;letter-spacing:.3px;box-shadow:0 2px 12px rgba(0,0,0,.3);font-family:inherit;transition:background .15s,transform .15s}\u001b[39m\n\u001b[31m#cover-btn:hover{background:rgba(255,255,255,.22);transform:scale(1.04)}·\u001b[39m\n\u001b[31m/* ── Print wait overlay ── */\u001b[39m\n\u001b[31m#print-overlay{position:fixed;inset:0;background:rgba(8,12,25,.92);z-index:9998;display:none;flex-direction:column;align-items:center;justify-content:center;gap:18px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}\u001b[39m\n\u001b[31m.po-printer{position:relative;width:90px;height:82px}\u001b[39m\n\u001b[31m.po-tray{position:absolute;top:0;left:12px;right:12px;height:16px;background:#3b4a6b;border-radius:5px 5px 0 0;border-bottom:2px solid #1e2f4a}\u001b[39m\n\u001b[31m.po-body{position:absolute;top:14px;left:0;right:0;height:38px;background:#1e2f4a;border-radius:6px;box-shadow:0 6px 18px rgba(0,0,0,.6)}\u001b[39m\n\u001b[31m.po-slot{position:absolute;top:30px;left:10px;right:10px;height:5px;background:#0a1020;border-radius:2px}\u001b[39m\n\u001b[31m.po-led{position:absolute;top:20px;right:14px;width:8px;height:8px;background:#22c55e;border-radius:50%;box-shadow:0 0 8px #22c55e;animation:po-blink 1.2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-blink{0%,100%{opacity:1;box-shadow:0 0 8px #22c55e}50%{opacity:.25;box-shadow:0 0 2px #22c55e}}\u001b[39m\n\u001b[31m.po-paper{position:absolute;top:35px;left:20px;right:20px;background:#fff;border-radius:0 0 3px 3px;height:0;animation:po-slide 2s ease-in-out infinite}\u001b[39m\n\u001b[31m@keyframes po-slide{0%{height:0}35%{height:44px}65%{height:44px}100%{height:0}}\u001b[39m\n\u001b[31m.po-line{position:absolute;left:6px;right:6px;height:2px;background:#cbd5e1;border-radius:1px;opacity:.7}\u001b[39m\n\u001b[31m.po-line-1{top:8px}.po-line-2{top:15px;right:14px}.po-line-3{top:22px;right:20px}\u001b[39m\n\u001b[31m.po-txt{color:#fff;font-size:15px;font-weight:700;letter-spacing:.2px;text-align:center}\u001b[39m\n\u001b[31m.po-sub{color:rgba(255,255,255,.5);font-size:12px;font-weight:500;text-align:center;min-height:1.4em}\u001b[39m\n\u001b[31m.po-bar{width:200px;height:4px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden}\u001b[39m\n\u001b[31m.po-pfill{height:100%;background:var(--or);border-radius:2px;transition:width .3s ease;width:0%}\u001b[39m\n\u001b[31m@media print{#print-overlay{display:none!important}}·\u001b[39m\n\u001b[31m/* ── Loading progress bar ── */\u001b[39m\n\u001b[31m.load-bar{position:fixed;bottom:0;left:0;right:0;background:rgba(15,23,42,.95);padding:9px 16px;z-index:9999;display:flex;align-items:center;gap:12px;backdrop-filter:blur(6px)}\u001b[39m\n\u001b[31m.load-track{flex:1;height:5px;background:rgba(255,255,255,.12);border-radius:3px;overflow:hidden}\u001b[39m\n\u001b[31m.load-fill{height:100%;background:var(--or);width:0%;transition:width .35s ease;border-radius:3px}\u001b[39m\n\u001b[31m.load-txt{font-size:11px;color:rgba(255,255,255,.6);white-space:nowrap;min-width:160px}·\u001b[39m\n\u001b[31m/* ── Photo page ── */\u001b[39m\n\u001b[31m.photo-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m.ph-band{background:var(--dk);padding:16px 26px;flex-shrink:0;display:flex;align-items:center;gap:20px;-webkit-print-color-adjust:exact;print-color-adjust:exact}\u001b[39m\n\u001b[31m.ph-cat{font-size:35px;font-weight:800;color:#fff;letter-spacing:-.5px;white-space:nowrap;flex-shrink:0}\u001b[39m\n\u001b[31m.ph-dims{flex:1;font-size:18px;font-weight:600;color:var(--or);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}\u001b[39m\n\u001b[31m.ph-no{margin-left:auto;flex-shrink:0;font-size:21px;font-weight:700;color:rgba(255,255,255,.85);background:rgba(255,255,255,.1);padding:5px 20px;border-radius:24px;white-space:nowrap}\u001b[39m\n\u001b[31m.ph-of{font-size:18px;font-weight:400;color:rgba(255,255,255,.4)}\u001b[39m\n\u001b[31m.ph-img{flex:1;overflow:hidden;position:relative;background:#111}\u001b[39m\n\u001b[31m.ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m.ph-img img{width:100%;height:100%;object-fit:contain;display:block}\u001b[39m\n\u001b[31m.ph-cmt{position:absolute;bottom:0;left:0;right:0;padding:6px 14px;background:rgba(0,0,0,.62);font-size:11px;color:rgba(255,255,255,.75);font-style:italic;pointer-events:none}·\u001b[39m\n\u001b[31m/* ── Video / Doc pages ── */\u001b[39m\n\u001b[31m.vid-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column;background:#fff}\u001b[39m\n\u001b[31m.vid-body{flex:1;padding:20px 24px;font-size:14px;color:var(--g600);border-left:4px solid var(--or)}\u001b[39m\n\u001b[31m.vid-body em{display:block;font-size:12px;color:var(--g400);margin-top:6px}\u001b[39m\n\u001b[31m.doc-page{height:100vh;scroll-snap-align:start;flex-shrink:0;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m.doc-wrap{flex:1;display:flex;align-items:center;justify-content:center;background:#111;overflow:hidden}\u001b[39m\n\u001b[31m.doc-img{max-width:100%;max-height:100%;object-fit:contain}·\u001b[39m\n\u001b[31m/* ── Cover header band ── */\u001b[39m\n\u001b[31m.cov-hdr{display:flex;gap:0;margin-bottom:12px;flex-shrink:0;border-radius:10px;overflow:hidden;border:1px solid rgba(255,255,255,.12)}\u001b[39m\n\u001b[31m.cov-hdr-l{flex:1;padding:14px 18px;display:flex;flex-direction:column;gap:5px;border-right:1px solid rgba(255,255,255,.1);min-width:0}\u001b[39m\n\u001b[31m.cov-hdr-r{width:170px;flex-shrink:0;padding:14px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:rgba(255,255,255,.04)}\u001b[39m\n\u001b[31m.cov-store{font-size:18px;font-weight:800;color:#fff;line-height:1.25;margin-bottom:2px}\u001b[39m\n\u001b[31m.cov-meta{font-size:12px;color:rgba(255,255,255,.55);display:flex;align-items:center;gap:5px;line-height:1.5}\u001b[39m\n\u001b[31m.cov-brand{background:var(--or);color:#fff;font-size:13px;font-weight:800;padding:5px 16px;border-radius:20px;text-align:center;letter-spacing:.3px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\u001b[39m\n\u001b[31m.cov-date-l{font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.8px;margin-bottom:2px;text-align:center}\u001b[39m\n\u001b[31m.cov-date-v{font-size:13px;font-weight:700;color:#fff;text-align:center}\u001b[39m\n\u001b[31m.cov-logo-box{background:#fff;border-radius:8px;padding:8px 14px;display:flex;align-items:center;justify-content:center;width:100%;max-width:138px}\u001b[39m\n\u001b[31m.cov-logo-box img{max-width:110px;max-height:44px;object-fit:contain;display:block}·\u001b[39m\n\u001b[31m/* ── Print ── */\u001b[39m\n\u001b[31m@page{size:A4 landscape;margin:12mm}\u001b[39m\n\u001b[31m@media print{\u001b[39m\n\u001b[31m  html,body{height:auto;overflow:visible;display:block}\u001b[39m\n\u001b[31m  .side-idx{display:none}\u001b[39m\n\u001b[31m  .main{overflow:visible;display:block;height:auto;scroll-snap-type:none}\u001b[39m\n\u001b[31m  .cover,.vid-page,.doc-page{height:auto;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column}\u001b[39m\n\u001b[31m  .photo-page{height:186mm;scroll-snap-align:none;page-break-after:always;break-after:page;display:flex;flex-direction:column;overflow:hidden}\u001b[39m\n\u001b[31m  .cover{padding:20px 24px}\u001b[39m\n\u001b[31m  .cover-pbar{display:none}\u001b[39m\n\u001b[31m  .cov-hdr{margin-bottom:8px;border-radius:7px}\u001b[39m\n\u001b[31m  .cov-hdr-l{padding:10px 14px}\u001b[39m\n\u001b[31m  .cov-hdr-r{padding:10px 12px;width:150px}\u001b[39m\n\u001b[31m  .cov-store{font-size:15px}\u001b[39m\n\u001b[31m  .cov-meta{font-size:10px}\u001b[39m\n\u001b[31m  .cov-brand{font-size:11px;padding:3px 12px}\u001b[39m\n\u001b[31m  .cov-date-v{font-size:11px}\u001b[39m\n\u001b[31m  .ph-band{padding:5mm 13mm;gap:10mm}\u001b[39m\n\u001b[31m  .ph-cat{font-size:15mm}\u001b[39m\n\u001b[31m  .ph-dims{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-no{font-size:12mm;padding:2mm 8mm}\u001b[39m\n\u001b[31m  .ph-of{font-size:10mm}\u001b[39m\n\u001b[31m  .ph-img{flex:1;display:flex;align-items:center;justify-content:center;background:#fff;overflow:hidden}\u001b[39m\n\u001b[31m  .ph-img a{display:block;width:100%;height:100%}\u001b[39m\n\u001b[31m  .ph-img img{width:100%;height:100%;object-fit:contain}\u001b[39m\n\u001b[31m  .ph-cmt{position:static;background:transparent;color:#475569;padding:2mm 8mm;font-size:6mm}\u001b[39m\n\u001b[31m  .main>*:last-child{page-break-after:avoid;break-after:avoid}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m</style></head>\u001b[39m\n\u001b[31m<body>·\u001b[39m\n\u001b[31m<div class=\\\"side-idx\\\" id=\\\"side-idx\\\">${sideItems.join('')}</div>·\u001b[39m\n\u001b[31m<div class=\\\"main\\\" id=\\\"main\\\">·\u001b[39m\n\u001b[31m<div class=\\\"cover\\\" id=\\\"pg-cover\\\">\u001b[39m\n\u001b[31m  <div class=\\\"cov-hdr\\\">\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-l\\\">\u001b[39m\n\u001b[31m      <div class=\\\"cov-store\\\">${esc(d.storeName||'Unknown Store')}</div>\u001b[39m\n\u001b[31m      ${(d.address||d.city)?`<div class=\\\"cov-meta\\\">&#x1F4CD; ${esc(d.address||'')}${d.city&&!(d.address||'').includes(d.city)?', '+esc(d.city):''}</div>`:''}\u001b[39m\n\u001b[31m      ${d.mobile?`<div class=\\\"cov-meta\\\">&#x1F4DE; ${esc(d.mobile)}</div>`:''}\u001b[39m\n\u001b[31m      ${d.email?`<div class=\\\"cov-meta\\\">&#x2709; ${esc(d.email)}</div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"cov-hdr-r\\\">\u001b[39m\n\u001b[31m      ${brandLogoUrl\u001b[39m\n\u001b[31m        ? `<div class=\\\"cov-logo-box\\\"><img src=\\\"${brandLogoUrl}\\\" alt=\\\"${esc(d.brand||'')}\\\"></div>`\u001b[39m\n\u001b[31m        : (d.brand?`<div class=\\\"cov-brand\\\">${esc(d.brand)}</div>`:'')}\u001b[39m\n\u001b[31m      ${d.date?`<div><div class=\\\"cov-date-l\\\">Recce Date</div><div class=\\\"cov-date-v\\\">${esc(d.date)}</div></div>`:''}\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${thumbItems.length ? `<div class=\\\"cov-grid-hdr\\\">&#x1F4F7; ${thumbItems.length} page${thumbItems.length!==1?'s':''} &mdash; tap any to jump</div><div class=\\\"cov-grid\\\" id=\\\"cov-grid\\\">${thumbsHtml}</div>` : ''}\u001b[39m\n\u001b[31m  <div class=\\\"cover-pbar\\\">\u001b[39m\n\u001b[31m    <button class=\\\"btn-p\\\" id=\\\"btn-print\\\" onclick=\\\"doPDF()\\\">&#x1F4C4;&nbsp;PDF</button>\u001b[39m\n\u001b[31m    <button class=\\\"btn-c\\\" onclick=\\\"window.close()\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m${pagesHtml}·\u001b[39m\n\u001b[31m${d.hasVideo?`\u001b[39m\n\u001b[31m<div class=\\\"vid-page\\\" id=\\\"pg-vid\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Video</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"vid-body\\\">${esc(d.videoNote||'Video recorded during visit')}${d.videoCmt?`<em>${esc(d.videoCmt)}</em>`:''}</div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m${urls.doc?`\u001b[39m\n\u001b[31m<div class=\\\"doc-page\\\" id=\\\"pg-doc\\\">\u001b[39m\n\u001b[31m  <div class=\\\"ph-band\\\" style=\\\"flex-shrink:0\\\"><div class=\\\"ph-cat\\\">Document</div></div>\u001b[39m\n\u001b[31m  <div class=\\\"doc-wrap\\\"><a href=\\\"${urls.doc}\\\" target=\\\"_blank\\\"><img class=\\\"doc-img\\\" src=\\\"${urls.doc}\\\" loading=\\\"lazy\\\" alt=\\\"Document\\\"></a></div>\u001b[39m\n\u001b[31m</div>`:''}·\u001b[39m\n\u001b[31m</div>·\u001b[39m\n\u001b[31m<div id=\\\"print-overlay\\\"><div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Preparing print&hellip;</div><div class=\\\"po-sub\\\" id=\\\"po-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"po-pfill\\\"></div></div></div>\u001b[39m\n\u001b[31m${pages.length ? `<div class=\\\"load-bar\\\" id=\\\"load-bar\\\"><div class=\\\"load-track\\\"><div class=\\\"load-fill\\\" id=\\\"load-fill\\\"></div></div><div class=\\\"load-txt\\\" id=\\\"load-txt\\\">Loading photos&#x2026;</div></div>` : ''}\u001b[39m\n\u001b[31m${thumbItems.length ? `<button id=\\\"cover-btn\\\" onclick=\\\"document.getElementById('pg-cover').scrollIntoView({behavior:'smooth'})\\\">&#x1F3E0;&nbsp;Cover Page</button>` : ''}·\u001b[39m\n\u001b[31m<script>\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var main=document.getElementById('main');\u001b[39m\n\u001b[31m  var items=document.querySelectorAll('.si-item');\u001b[39m\n\u001b[31m  var covBtn=document.getElementById('cover-btn');\u001b[39m\n\u001b[31m  function setActive(id){\u001b[39m\n\u001b[31m    items.forEach(function(el){el.classList.toggle('active',el.dataset.tgt===id);});\u001b[39m\n\u001b[31m    var a=document.querySelector('.si-item[data-tgt=\\\"'+id+'\\\"]');\u001b[39m\n\u001b[31m    if(a) a.scrollIntoView({block:'nearest'});\u001b[39m\n\u001b[31m    if(covBtn) covBtn.style.display=id==='pg-cover'?'none':'flex';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  items.forEach(function(el){\u001b[39m\n\u001b[31m    el.addEventListener('click',function(){\u001b[39m\n\u001b[31m      var t=document.getElementById(el.dataset.tgt);\u001b[39m\n\u001b[31m      if(t) t.scrollIntoView({behavior:'smooth'});\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if('IntersectionObserver' in window){\u001b[39m\n\u001b[31m    var obs=new IntersectionObserver(function(entries){\u001b[39m\n\u001b[31m      entries.forEach(function(e){if(e.isIntersecting&&e.intersectionRatio>=0.45) setActive(e.target.id);});\u001b[39m\n\u001b[31m    },{root:main,threshold:0.45});\u001b[39m\n\u001b[31m    document.querySelectorAll('[id^=\\\"pg-\\\"]').forEach(function(p){obs.observe(p);});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  setActive('pg-cover');\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m(function(){\u001b[39m\n\u001b[31m  var imgs=Array.from(document.querySelectorAll('img'));\u001b[39m\n\u001b[31m  var total=imgs.length,loaded=0;\u001b[39m\n\u001b[31m  var bar=document.getElementById('load-bar');\u001b[39m\n\u001b[31m  var fill=document.getElementById('load-fill');\u001b[39m\n\u001b[31m  var txt=document.getElementById('load-txt');\u001b[39m\n\u001b[31m  var printPending=false,printShowTime=0;\u001b[39m\n\u001b[31m  var mm=96/25.4;\u001b[39m\n\u001b[31m  var SERVER_PDF='${serverPdfUrl}';\u001b[39m\n\u001b[31m  function updatePoBar(){\u001b[39m\n\u001b[31m    var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m    var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(poFill) poFill.style.width=(total?Math.round(loaded/total*100):100)+'%';\u001b[39m\n\u001b[31m    if(poSub) poSub.textContent=loaded+' / '+total+' photos ready';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function done(){\u001b[39m\n\u001b[31m    if(fill) fill.style.width='100%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='✓ All '+total+' photos ready';\u001b[39m\n\u001b[31m    setTimeout(function(){\u001b[39m\n\u001b[31m      if(bar){bar.style.transition='opacity .6s';bar.style.opacity='0';}\u001b[39m\n\u001b[31m      setTimeout(function(){if(bar)bar.style.display='none';},650);\u001b[39m\n\u001b[31m    },2000);\u001b[39m\n\u001b[31m    if(printPending){\u001b[39m\n\u001b[31m      printPending=false;\u001b[39m\n\u001b[31m      var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m      var poFill=document.getElementById('po-pfill');\u001b[39m\n\u001b[31m      var poSub=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(poFill) poFill.style.width='100%';\u001b[39m\n\u001b[31m      if(poSub) poSub.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},Math.max(400,2000-(Date.now()-printShowTime)));\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function onImg(){\u001b[39m\n\u001b[31m    loaded++;\u001b[39m\n\u001b[31m    if(fill) fill.style.width=Math.round(loaded/total*100)+'%';\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… '+loaded+' / '+total;\u001b[39m\n\u001b[31m    if(printPending) updatePoBar();\u001b[39m\n\u001b[31m    if(loaded>=total) done();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  /* ── PDF layout helpers ── */\u001b[39m\n\u001b[31m  function fitBandFonts(pageW){\u001b[39m\n\u001b[31m    var padH=2*13*mm,gapH=2*10*mm,noPadH=2*8*mm;\u001b[39m\n\u001b[31m    var avail=pageW-padH-gapH;\u001b[39m\n\u001b[31m    var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-band').forEach(function(band){\u001b[39m\n\u001b[31m      var cat=band.querySelector('.ph-cat');\u001b[39m\n\u001b[31m      var dims=band.querySelector('.ph-dims');\u001b[39m\n\u001b[31m      var no=band.querySelector('.ph-no');\u001b[39m\n\u001b[31m      if(!cat) return;\u001b[39m\n\u001b[31m      var catTxt=cat.textContent.trim();\u001b[39m\n\u001b[31m      var dimsTxt=dims?dims.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      var noTxt=no?no.textContent.replace(/\\\\s+/g,' ').trim():'';\u001b[39m\n\u001b[31m      function tw(sc){\u001b[39m\n\u001b[31m        var cf=15*sc*mm,df=10*sc*mm,nf=12*sc*mm;\u001b[39m\n\u001b[31m        ctx.font='800 '+cf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var cw=ctx.measureText(catTxt).width;\u001b[39m\n\u001b[31m        ctx.font='600 '+df+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var dw=dims?ctx.measureText(dimsTxt).width:0;\u001b[39m\n\u001b[31m        ctx.font='700 '+nf+'px \\\"DM Sans\\\",sans-serif';\u001b[39m\n\u001b[31m        var nw=no?ctx.measureText(noTxt).width+noPadH:0;\u001b[39m\n\u001b[31m        return cw+dw+nw;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      var scale=1.0;\u001b[39m\n\u001b[31m      if(tw(scale)>avail){\u001b[39m\n\u001b[31m        var lo=0.3,hi=1.0;\u001b[39m\n\u001b[31m        for(var i=0;i<10;i++){var mid=(lo+hi)/2;if(tw(mid)<=avail)lo=mid;else hi=mid;}\u001b[39m\n\u001b[31m        scale=lo*0.93;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      cat.style.setProperty('font-size',Math.round(15*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(dims) dims.style.setProperty('font-size',Math.round(10*scale*mm)+'px','important');\u001b[39m\n\u001b[31m      if(no) no.style.setProperty('font-size',Math.round(12*scale*mm)+'px','important');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function sizePdfThumbs(pageW,pageH){\u001b[39m\n\u001b[31m    var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m    if(!grid||!grid.children.length) return;\u001b[39m\n\u001b[31m    var coverPage=document.getElementById('pg-cover');\u001b[39m\n\u001b[31m    var usedH=56;\u001b[39m\n\u001b[31m    if(coverPage){\u001b[39m\n\u001b[31m      Array.from(coverPage.children).forEach(function(el){\u001b[39m\n\u001b[31m        if(el!==grid) usedH+=el.offsetHeight||0;\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    var gridH=Math.max(80,pageH-usedH);\u001b[39m\n\u001b[31m    var n=grid.children.length,gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m    for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m      var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m      var w=(pageW-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m      var h=w*asp;\u001b[39m\n\u001b[31m      if(rows*h+(rows-1)*gap<=gridH&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m    grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m    grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m    var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m    var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m    var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m    document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  function preparePdfLayout(){\u001b[39m\n\u001b[31m    var pageW=Math.round((297-24)*mm);\u001b[39m\n\u001b[31m    var pageH=Math.round((210-24)*mm);\u001b[39m\n\u001b[31m    fitBandFonts(pageW);\u001b[39m\n\u001b[31m    sizePdfThumbs(pageW,pageH);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.preparePdfLayout=preparePdfLayout;\u001b[39m\n\u001b[31m  function restorePdfLayout(){\u001b[39m\n\u001b[31m    document.querySelectorAll('.ph-cat,.ph-dims,.ph-no').forEach(function(el){\u001b[39m\n\u001b[31m      el.style.removeProperty('font-size');\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(window._screenSizeThumbs) window._screenSizeThumbs();\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.addEventListener('afterprint',restorePdfLayout);\u001b[39m\n\u001b[31m  function _doBrowserPrint(){\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    printShowTime=Date.now();\u001b[39m\n\u001b[31m    preparePdfLayout();\u001b[39m\n\u001b[31m    if(total===0||loaded>=total){\u001b[39m\n\u001b[31m      var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m      if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m      if(ps) ps.textContent='All photos ready — opening print…';\u001b[39m\n\u001b[31m      setTimeout(function(){if(ov)ov.style.display='none';window.print();},2000);\u001b[39m\n\u001b[31m      return;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    printPending=true;\u001b[39m\n\u001b[31m    updatePoBar();\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if((!img.complete||img.naturalWidth===0)&&img.getAttribute('loading')==='lazy'){\u001b[39m\n\u001b[31m        img.loading='eager';var s=img.src;img.src='';img.src=s;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  window.doPDF=async function(){\u001b[39m\n\u001b[31m    if(!SERVER_PDF){_doBrowserPrint();return;}\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      var r=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m      if(r.ok){window.open(SERVER_PDF,'_blank');return;}\u001b[39m\n\u001b[31m    }catch(_){}\u001b[39m\n\u001b[31m    // PDF not ready yet — show overlay and poll\u001b[39m\n\u001b[31m    var ov=document.getElementById('print-overlay');\u001b[39m\n\u001b[31m    var pf=document.getElementById('po-pfill'),ps=document.getElementById('po-sub');\u001b[39m\n\u001b[31m    if(ov) ov.style.display='flex';\u001b[39m\n\u001b[31m    if(pf) pf.style.width='0%';\u001b[39m\n\u001b[31m    if(ps) ps.textContent='Waiting for server PDF…';\u001b[39m\n\u001b[31m    var tries=0;\u001b[39m\n\u001b[31m    (async function poll(){\u001b[39m\n\u001b[31m      tries++;\u001b[39m\n\u001b[31m      if(pf) pf.style.width=Math.min(88,tries*8)+'%';\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        var r2=await fetch(SERVER_PDF,{method:'HEAD'});\u001b[39m\n\u001b[31m        if(r2.ok){\u001b[39m\n\u001b[31m          if(pf) pf.style.width='100%';\u001b[39m\n\u001b[31m          setTimeout(function(){if(ov)ov.style.display='none';window.open(SERVER_PDF,'_blank');},400);\u001b[39m\n\u001b[31m          return;\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      }catch(_){}\u001b[39m\n\u001b[31m      if(tries>=12){if(ov)ov.style.display='none';_doBrowserPrint();return;}\u001b[39m\n\u001b[31m      setTimeout(poll,5000);\u001b[39m\n\u001b[31m    })();\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  if(total===0){if(bar)bar.style.display='none';}\u001b[39m\n\u001b[31m  else{\u001b[39m\n\u001b[31m    if(txt) txt.textContent='Loading photos… 0 / '+total;\u001b[39m\n\u001b[31m    imgs.forEach(function(img){\u001b[39m\n\u001b[31m      if(img.complete&&img.naturalWidth>0) onImg();\u001b[39m\n\u001b[31m      else{img.addEventListener('load',onImg);img.addEventListener('error',onImg);}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  var grid=document.getElementById('cov-grid');\u001b[39m\n\u001b[31m  if(grid&&grid.children.length>0){\u001b[39m\n\u001b[31m    function sizeThumbs(){\u001b[39m\n\u001b[31m      var n=grid.children.length;\u001b[39m\n\u001b[31m      var gw=grid.clientWidth,gh=grid.clientHeight;\u001b[39m\n\u001b[31m      if(!gw||!gh) return;\u001b[39m\n\u001b[31m      var gap=5,asp=9/16,bestW=40;\u001b[39m\n\u001b[31m      for(var cols=1;cols<=n;cols++){\u001b[39m\n\u001b[31m        var rows=Math.ceil(n/cols);\u001b[39m\n\u001b[31m        var w=(gw-gap*(cols-1))/cols;\u001b[39m\n\u001b[31m        var h=w*asp;\u001b[39m\n\u001b[31m        if(rows*h+(rows-1)*gap<=gh&&w>bestW) bestW=w;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      bestW=Math.floor(bestW);\u001b[39m\n\u001b[31m      grid.style.gridTemplateColumns='repeat(auto-fill,minmax('+bestW+'px,1fr))';\u001b[39m\n\u001b[31m      grid.style.gridAutoRows=Math.floor(bestW*(9/16))+'px';\u001b[39m\n\u001b[31m      var cf=Math.max(6,Math.min(15,Math.round(bestW*.13)))+'px';\u001b[39m\n\u001b[31m      var df=Math.max(5,Math.min(12,Math.round(bestW*.11)))+'px';\u001b[39m\n\u001b[31m      var nf=Math.max(5,Math.min(11,Math.round(bestW*.09)))+'px';\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-cat').forEach(function(el){el.style.fontSize=cf;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-dims').forEach(function(el){el.style.fontSize=df;});\u001b[39m\n\u001b[31m      document.querySelectorAll('.cov-thumb-no').forEach(function(el){el.style.fontSize=nf;});\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    window._screenSizeThumbs=sizeThumbs;\u001b[39m\n\u001b[31m    requestAnimationFrame(function(){requestAnimationFrame(sizeThumbs);});\u001b[39m\n\u001b[31m    window.addEventListener('resize',sizeThumbs);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m})();\u001b[39m\n\u001b[31m</scr`+'ipt>'+`\u001b[39m\n\u001b[31m</body></html>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function syncToPostgres(entry) {\u001b[39m\n\u001b[31m  const d   = entry.data || {};\u001b[39m\n\u001b[31m  const hub = _recceHubUser();·\u001b[39m\n\u001b[31m  // Step 1 — upload all photos to VPS, get permanent server URLs\u001b[39m\n\u001b[31m  let photoUrls = { front:[], inside:[], brandings:[], addl:[], doc:null };\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const pResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type: 'save-photos', subId: entry.id,\u001b[39m\n\u001b[31m        photos: {\u001b[39m\n\u001b[31m          front:    (d.frontPhotos||[]).map(p=>({b64:p.b64,   cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64,  cmt:p.cmt||''})),\u001b[39m\n\u001b[31m          brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||null})),\u001b[39m\n\u001b[31m          addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64,   desc:p.desc||''})),\u001b[39m\n\u001b[31m          doc:      d.docB64 || null,\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (pResp.ok) { const r=await pResp.json(); if(r.success) {\u001b[39m\n\u001b[31m      photoUrls=r.photoUrls;\u001b[39m\n\u001b[31m      // Merge retained existing URLs for edit re-submits\u001b[39m\n\u001b[31m      if (entry.editedAt) {\u001b[39m\n\u001b[31m        photoUrls.front    =(photoUrls.front   ||[]).map((u,i)=>u||(d.frontPhotos  ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.inside   =(photoUrls.inside  ||[]).map((u,i)=>u||(d.insidePhotos ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.addl     =(photoUrls.addl    ||[]).map((u,i)=>u||(d.addlPhotos   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        photoUrls.brandings=(photoUrls.brandings||[]).map((u,i)=>u||(d.brandings   ||[])[i]?.existingUrl||null);\u001b[39m\n\u001b[31m        if(!photoUrls.doc) photoUrls.doc=d._docExistingUrl||null;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }}\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-photos] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 1.5 — trigger Google Slides via proxy using permanent photo URLs (fire-and-forget)\u001b[39m\n\u001b[31m  (async()=>{try{\u001b[39m\n\u001b[31m    const _hasPh=(photoUrls.front||[]).some(Boolean)||(photoUrls.inside||[]).some(Boolean)||(photoUrls.brandings||[]).some(Boolean);\u001b[39m\n\u001b[31m    if(!_hasPh)return;\u001b[39m\n\u001b[31m    const _gu=(await cfg('slides-gas-url'))||(await cfg('gas-url'))||DEFAULT_GAS_URL;if(!_gu)return;\u001b[39m\n\u001b[31m    await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({\u001b[39m\n\u001b[31m      type:'make-slides',gasUrl:_gu,subId:entry.id,\u001b[39m\n\u001b[31m      storeInfo:{storeName:d.storeName||'',brand:d.brand||'',address:d.address||'',mobile:d.mobile||'',date:d.date||'',city:d.city||'',gpsCoords:d.gpsCoords||null},\u001b[39m\n\u001b[31m      photoGroups:{\u001b[39m\n\u001b[31m        front:    (photoUrls.front   ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.frontPhotos  ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        inside:   (photoUrls.inside  ||[]).filter(Boolean).map((url,i)=>({url,cmt:(d.insidePhotos ||[])[i]?.cmt||''})),\u001b[39m\n\u001b[31m        brandings:(photoUrls.brandings||[]).filter(Boolean).map((url,i)=>({url,meta:{type:(d.brandings||[])[i]?.type,w:(d.brandings||[])[i]?.w,h:(d.brandings||[])[i]?.h,qty:(d.brandings||[])[i]?.qty,sqft:(d.brandings||[])[i]?.sqft}})),\u001b[39m\n\u001b[31m        addl:    (photoUrls.addl    ||[]).filter(Boolean).map((url,i)=>({url,desc:(d.addlPhotos  ||[])[i]?.desc||''})),\u001b[39m\n\u001b[31m      },\u001b[39m\n\u001b[31m    })});\u001b[39m\n\u001b[31m    entry.gasAt=new Date().toISOString();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[recce-slides]',e.message);}}\u001b[39m\n\u001b[31m  )();·\u001b[39m\n\u001b[31m  // Step 2 — generate rich HTML report using server URLs, save to VPS\u001b[39m\n\u001b[31m  let view_url = null;\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const html  = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m    const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m      method: 'POST', headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({ type: 'save-view', subId: entry.id, html })\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (vResp.ok) { const r=await vResp.json(); if(r.success) view_url=r.url; }\u001b[39m\n\u001b[31m  } catch(e) { console.warn('[recce-view] upload failed:', e.message); }·\u001b[39m\n\u001b[31m  // Step 3 — upsert to PostgreSQL with photo URLs + view URL\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch(`${_RC_BASE}/submissions`, {\u001b[39m\n\u001b[31m      method: 'POST', headers: _RC_UPSERT,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        sub_id:         entry.id,\u001b[39m\n\u001b[31m        store_name:     d.storeName    || 'Unknown',\u001b[39m\n\u001b[31m        brand:          d.brand        || null,\u001b[39m\n\u001b[31m        client_name:    d.clientName   || null,\u001b[39m\n\u001b[31m        visit_date:     d.date         || new Date().toISOString().slice(0,10),\u001b[39m\n\u001b[31m        address:        d.address      || null,\u001b[39m\n\u001b[31m        mobile:         d.mobile       || null,\u001b[39m\n\u001b[31m        city:           d.city         || null,\u001b[39m\n\u001b[31m        has_branding:   !!(d.brandings?.length),\u001b[39m\n\u001b[31m        branding_count: d.brandings?.length || 0,\u001b[39m\n\u001b[31m        has_video:      !!d.hasVideo,\u001b[39m\n\u001b[31m        front_photos:   d.frontPhotos?.length  || 0,\u001b[39m\n\u001b[31m        inside_photos:  d.insidePhotos?.length || 0,\u001b[39m\n\u001b[31m        addl_photos:    d.addlPhotos?.length   || 0,\u001b[39m\n\u001b[31m        gps_lat:        d.gpsCoords?.lat       || null,\u001b[39m\n\u001b[31m        gps_lng:        d.gpsCoords?.lng       || null,\u001b[39m\n\u001b[31m        submitted_by:   hub.empId              || null,\u001b[39m\n\u001b[31m        submitted_at:   entry.timestamp,\u001b[39m\n\u001b[31m        campaign_id:    entry.campaignId       || null,\u001b[39m\n\u001b[31m        photo_urls:     photoUrls,\u001b[39m\n\u001b[31m        view_url,\u001b[39m\n\u001b[31m        meta: {\u001b[39m\n\u001b[31m          brandings: (d.brandings||[]).map(b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft})),\u001b[39m\n\u001b[31m          videoNote: d.videoNote || null,\u001b[39m\n\u001b[31m          videoCmt:  d.videoCmt  || null,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        status: 'submitted',\u001b[39m\n\u001b[31m        edit_assigned_to: null,\u001b[39m\n\u001b[31m        edit_comment: null,\u001b[39m\n\u001b[31m        edited_at: entry.editedAt || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    return { ok: true, viewUrl: view_url };\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    console.warn('[recce-db] sync error:', e.message);\u001b[39m\n\u001b[31m    return { ok: false, viewUrl: null };\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mconst DEFAULT_ADMIN_HASH='42d372e6110bee134990ac6881c3d5eb568482008add9a859f37f10d759430e8';·\u001b[39m\n\u001b[31masync function saveGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('gas-url',url||DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  toast('Endpoint saved','success');\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function testEndpoint(){\u001b[39m\n\u001b[31m  const url=(await cfg('gas-url'))||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  try{await fetch(url,{method:'POST',mode:'no-cors',body:JSON.stringify({test:true})});toast('Endpoint reachable ✓','success');}\u001b[39m\n\u001b[31m  catch{toast('Cannot reach endpoint','error')}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  cfg('gas-url').then(url=>{\u001b[39m\n\u001b[31m    const u=url||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    // Show last 30 chars only for privacy\u001b[39m\n\u001b[31m    el.textContent='Endpoint: …'+u.slice(-30);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── SLIDES GAS URL ────────────────────────────────────────────\u001b[39m\n\u001b[31masync function saveSlidesGasUrl(){\u001b[39m\n\u001b[31m  if(!_adminUnlocked){toast('Admin login required','error');return;}\u001b[39m\n\u001b[31m  const url=document.getElementById('slides-gas-url').value.trim();\u001b[39m\n\u001b[31m  await cfg('slides-gas-url', url);\u001b[39m\n\u001b[31m  toast('Slides GAS URL saved','success');\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function updateSlidesGasPreview(){\u001b[39m\n\u001b[31m  const el=document.getElementById('slides-gas-url-preview');\u001b[39m\n\u001b[31m  if(!el)return;\u001b[39m\n\u001b[31m  const u=await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  el.textContent=u?'Configured: …'+u.slice(-30):'Not configured';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── MAKE SLIDES ───────────────────────────────────────────────\u001b[39m\n\u001b[31masync function makeSlides(id){\u001b[39m\n\u001b[31m  const gasUrl = await cfg('slides-gas-url');\u001b[39m\n\u001b[31m  if(!gasUrl){\u001b[39m\n\u001b[31m    toast('Configure Slides GAS URL in Settings first','error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const entry = await dbGet('subs', id);\u001b[39m\n\u001b[31m  if(!entry){ toast('Entry not found','error'); return; }\u001b[39m\n\u001b[31m  const d = entry.data;·\u001b[39m\n\u001b[31m  toast('Uploading photos & generating slides…','info');·\u001b[39m\n\u001b[31m  // Build photo groups payload\u001b[39m\n\u001b[31m  const photoGroups = {\u001b[39m\n\u001b[31m    front:    (d.frontPhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    inside:   (d.insidePhotos||[]).map(p=>({b64:p.b64, cmt:p.cmt||''})),\u001b[39m\n\u001b[31m    addl:     (d.addlPhotos||[]).map(p=>({b64:p.b64, cmt:p.desc||''})),\u001b[39m\n\u001b[31m    brandings:(d.brandings||[]).map(b=>({b64:b.photoB64||'', meta:{type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:b.sqft}})),\u001b[39m\n\u001b[31m  };·\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type':'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        type:       'recce',\u001b[39m\n\u001b[31m        subId:      id,\u001b[39m\n\u001b[31m        gasUrl:     gasUrl,\u001b[39m\n\u001b[31m        storeInfo:  {\u001b[39m\n\u001b[31m          storeName: d.storeName, brand: d.brand,\u001b[39m\n\u001b[31m          date: d.date, address: d.address,\u001b[39m\n\u001b[31m          mobile: d.mobile, gpsCoords: d.gpsCoords,\u001b[39m\n\u001b[31m        },\u001b[39m\n\u001b[31m        photoGroups,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    const result = await resp.json();\u001b[39m\n\u001b[31m    if(result.success && result.slideUrl){\u001b[39m\n\u001b[31m      // Store slide URL on the entry\u001b[39m\n\u001b[31m      entry.slideUrl = result.slideUrl;\u001b[39m\n\u001b[31m      await dbPut('subs', entry);\u001b[39m\n\u001b[31m      toast('✅ Slides ready!','success');\u001b[39m\n\u001b[31m      window.open(result.slideUrl, '_blank');\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      toast('Slides error: '+(result.error||'Unknown'),'error');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(e){\u001b[39m\n\u001b[31m    toast('Network error: '+e.message,'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN LOGIN ──────────────────────────────────────────────\u001b[39m\n\u001b[31mfunction showAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-error').style.display='none';\u001b[39m\n\u001b[31m  // Restore saved config URL\u001b[39m\n\u001b[31m  cfg('admin-cfg-url').then(u=>{if(u&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=u;});\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('admin-pwd').focus(),100);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeAdminLogin(){\u001b[39m\n\u001b[31m  document.getElementById('admin-login-modal').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveAdminCfgUrl(){\u001b[39m\n\u001b[31m  // Admin cfg URL can be saved without login (needed to set up auth itself)\u001b[39m\n\u001b[31m  // But we warn if saving while unlocked only\u001b[39m\n\u001b[31m  const url=document.getElementById('admin-cfg-url').value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  await cfg('admin-cfg-url',url);\u001b[39m\n\u001b[31m  toast('Config URL saved — will use on next login attempt','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function verifyAdmin(){\u001b[39m\n\u001b[31m  // Hub admins (harish/pramod) are auto-unlocked — no password needed\u001b[39m\n\u001b[31m  if (_adminUnlocked) { adminLoginSuccess(); return; }\u001b[39m\n\u001b[31m  const pwd=document.getElementById('admin-pwd').value;\u001b[39m\n\u001b[31m  if(!pwd){document.getElementById('admin-error').style.display='block';document.getElementById('admin-error').textContent='Enter password';return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('admin-login-btn');btn.disabled=true;btn.textContent='Verifying…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // Try server verification first\u001b[39m\n\u001b[31m    const cfgUrl=(await cfg('admin-cfg-url'))||'';\u001b[39m\n\u001b[31m    if(cfgUrl){\u001b[39m\n\u001b[31m      const r=await fetch(cfgUrl,{cache:'no-store'});\u001b[39m\n\u001b[31m      const j=await r.json();\u001b[39m\n\u001b[31m      // Server JSON format: {\\\"password\\\":\\\"plaintext\\\"} or {\\\"hash\\\":\\\"sha256hash\\\"}\u001b[39m\n\u001b[31m      let match=false;\u001b[39m\n\u001b[31m      if(j.password){match=(j.password===pwd);}\u001b[39m\n\u001b[31m      else if(j.hash){\u001b[39m\n\u001b[31m        // SHA-256 comparison\u001b[39m\n\u001b[31m        const enc=new TextEncoder();\u001b[39m\n\u001b[31m        const data=enc.encode(pwd);\u001b[39m\n\u001b[31m        const hashBuf=await crypto.subtle.digest('SHA-256',data);\u001b[39m\n\u001b[31m        const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m        match=(hashHex===j.hash);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      if(match){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m      else{showAdminError('Incorrect password');return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Fallback: local password stored in settings\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if(localHash){\u001b[39m\n\u001b[31m      const enc=new TextEncoder();\u001b[39m\n\u001b[31m      const hashBuf=await crypto.subtle.digest('SHA-256',enc.encode(pwd));\u001b[39m\n\u001b[31m      const hashHex=Array.from(new Uint8Array(hashBuf)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m      if(hashHex===localHash){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Final fallback: check against hardcoded default hash\u001b[39m\n\u001b[31m    const enc2=new TextEncoder();\u001b[39m\n\u001b[31m    const hb2=await crypto.subtle.digest('SHA-256',enc2.encode(pwd));\u001b[39m\n\u001b[31m    const hh2=Array.from(new Uint8Array(hb2)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    if(hh2===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }catch(err){\u001b[39m\n\u001b[31m    // Network error — try all local fallbacks\u001b[39m\n\u001b[31m    const enc3=new TextEncoder();\u001b[39m\n\u001b[31m    const hb3=await crypto.subtle.digest('SHA-256',enc3.encode(pwd));\u001b[39m\n\u001b[31m    const hh3=Array.from(new Uint8Array(hb3)).map(b=>b.toString(16).padStart(2,'0')).join('');\u001b[39m\n\u001b[31m    const localHash=await cfg('admin-hash');\u001b[39m\n\u001b[31m    if((localHash&&hh3===localHash)||hh3===DEFAULT_ADMIN_HASH){adminLoginSuccess();return;}\u001b[39m\n\u001b[31m    showAdminError('Incorrect password');\u001b[39m\n\u001b[31m  }finally{btn.disabled=false;btn.textContent='Login';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction showAdminError(msg){\u001b[39m\n\u001b[31m  const el=document.getElementById('admin-error');\u001b[39m\n\u001b[31m  el.textContent=msg;el.style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').value='';\u001b[39m\n\u001b[31m  document.getElementById('admin-pwd').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminLoginSuccess(){\u001b[39m\n\u001b[31m  _adminUnlocked=true;\u001b[39m\n\u001b[31m  closeAdminLogin();\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='block';\u001b[39m\n\u001b[31m  cfg('gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  cfg('slides-gas-url').then(u=>{\u001b[39m\n\u001b[31m    const el=document.getElementById('slides-gas-url');\u001b[39m\n\u001b[31m    if(el)el.value=u||'';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  toast('Admin mode unlocked','success');\u001b[39m\n\u001b[31m  setTimeout(lockAdmin,10*60*1000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction lockAdmin(){\u001b[39m\n\u001b[31m  _adminUnlocked=false;\u001b[39m\n\u001b[31m  document.getElementById('gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-locked').style.display='flex';\u001b[39m\n\u001b[31m  document.getElementById('slides-gas-unlocked').style.display='none';\u001b[39m\n\u001b[31m  toast('Admin session ended','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updAvailTag(){\u001b[39m\n\u001b[31m  const el=document.getElementById('store-avail-tag');\u001b[39m\n\u001b[31m  const ct=document.getElementById('store-avail-count');\u001b[39m\n\u001b[31m  const txt=stores.length?`${stores.length} stores`:'No store list';\u001b[39m\n\u001b[31m  if(el)el.textContent=txt;\u001b[39m\n\u001b[31m  if(ct)ct.textContent=stores.length?t(`${stores.length} stores available — tap to browse`,`${stores.length} स्टोर उपलब्ध — दबाएं`):t('No store list loaded yet','कोई स्टोर सूची नहीं');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PICKER\u001b[39m\n\u001b[31mfunction openPicker(){\u001b[39m\n\u001b[31m  if(!stores.length){toast('Load a store list in Settings first','error');return;}\u001b[39m\n\u001b[31m  document.getElementById('povl').classList.add('open');\u001b[39m\n\u001b[31m  document.getElementById('psearch').value='';\u001b[39m\n\u001b[31m  filterPicker('');\u001b[39m\n\u001b[31m  setTimeout(()=>document.getElementById('psearch').focus(),150);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closePicker(){document.getElementById('povl').classList.remove('open');}\u001b[39m\n\u001b[31masync function filterPicker(q){\u001b[39m\n\u001b[31m  const list=document.getElementById('plist');\u001b[39m\n\u001b[31m  const words=q.toLowerCase().trim().split(/\\\\s+/).filter(Boolean);\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const lastVisit={};\u001b[39m\n\u001b[31m  subs.forEach(s=>{const nm=s.data?.storeName;if(nm&&(!lastVisit[nm]||s.timestamp>lastVisit[nm]))lastVisit[nm]=s.timestamp;});·\u001b[39m\n\u001b[31m  // Multi-word: ALL words must match somewhere in any field (search across both English and Hindi)\u001b[39m\n\u001b[31m  let fl=stores.filter(s=>{\u001b[39m\n\u001b[31m    if(!words.length)return true;\u001b[39m\n\u001b[31m    const hay=[s.name,s.nameHi,s.address,s.addressHi,s.mobile,s.city,s.cityHi,s.distName,s.distNameHi,s.brand,s.sales,s.proj,s.glowSign,s.inshop]\u001b[39m\n\u001b[31m               .map(x=>(x||'').toLowerCase()).join(' ');\u001b[39m\n\u001b[31m    return words.every(w=>hay.includes(w));\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  if(fl.length>100)fl=fl.slice(0,100);·\u001b[39m\n\u001b[31m  if(!fl.length){\u001b[39m\n\u001b[31m    const esc=q.replace(/'/g,\\\"\\\\\\\\'\\\");\u001b[39m\n\u001b[31m    list.innerHTML=`<div style=\\\"text-align:center;padding:32px 16px;color:var(--g400);font-size:14px\\\">No stores match \\\"${q}\\\"<br><span style=\\\"font-size:12px\\\">Try fewer or different words</span></div>\u001b[39m\n\u001b[31m      <div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('${esc}')\\\">+ Add \\\"${q}\\\" as new store</div>`;\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Group by brand (including empty brand)\u001b[39m\n\u001b[31m  const g={};\u001b[39m\n\u001b[31m  fl.forEach(s=>{\u001b[39m\n\u001b[31m    const b=s.brand||'(No Brand — will ask)';\u001b[39m\n\u001b[31m    if(!g[b])g[b]=[];\u001b[39m\n\u001b[31m    g[b].push(s);\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html='';\u001b[39m\n\u001b[31m  Object.keys(g).sort().forEach(br=>{\u001b[39m\n\u001b[31m    html+=`<div class=\\\"psec\\\">${br}</div>`;\u001b[39m\n\u001b[31m    g[br].forEach(s=>{\u001b[39m\n\u001b[31m      const lv=lastVisit[s.name];\u001b[39m\n\u001b[31m      const lvStr=lv?`🕐 Last: ${new Date(lv).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'2-digit'})}`:'';\u001b[39m\n\u001b[31m      const chips=[];\u001b[39m\n\u001b[31m      if(s.glowSign&&s.glowSign.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dcfce7;color:#14532d;padding:2px 6px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m      if(s.inshop&&s.inshop.toLowerCase()==='yes')chips.push('<span style=\\\"font-size:10px;background:#dbeafe;color:#1e40af;padding:2px 6px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m      if(s.proj)chips.push(`<span style=\\\"font-size:10px;background:var(--g100);color:var(--g600);padding:2px 6px;border-radius:10px\\\">Target: ${s.proj}</span>`);\u001b[39m\n\u001b[31m      const enc=JSON.stringify(s).replace(/\\\"/g,'&quot;');\u001b[39m\n\u001b[31m      const mapsUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m      const waUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const telUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m      const dispName=LANG==='hi'&&s.nameHi?s.nameHi:s.name;\u001b[39m\n\u001b[31m      const dispAddr=LANG==='hi'&&s.addressHi?s.addressHi:s.address;\u001b[39m\n\u001b[31m      const dispDist=LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m      html+=`<div class=\\\"pitem\\\" onclick=\\\"pickStore(${enc})\\\">\u001b[39m\n\u001b[31m        <div style=\\\"flex:1;min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"pi-name\\\">${dispName}</div>\u001b[39m\n\u001b[31m          ${dispAddr?`<div class=\\\"pi-addr\\\">📍 ${dispAddr}</div>`:''}\u001b[39m\n\u001b[31m          ${s.mobile?`<div class=\\\"pi-addr\\\">📞 ${s.mobile}</div>`:''}\u001b[39m\n\u001b[31m          ${dispDist?`<div class=\\\"pi-addr\\\" style=\\\"color:var(--am)\\\">👤 ${dispDist}</div>`:''}\u001b[39m\n\u001b[31m          ${lvStr?`<div class=\\\"pi-last\\\">${lvStr}</div>`:''}\u001b[39m\n\u001b[31m          ${chips.length?`<div style=\\\"display:flex;gap:4px;flex-wrap:wrap;margin-top:4px\\\">${chips.join('')}</div>`:''}\u001b[39m\n\u001b[31m          <div style=\\\"display:flex;gap:6px;margin-top:7px\\\" onclick=\\\"event.stopPropagation()\\\">\u001b[39m\n\u001b[31m            ${mapsUrl?`<a href=\\\"${mapsUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#e0f2fe;color:#0369a1;border-radius:20px;text-decoration:none;font-weight:600\\\">🗺 Maps</a>`:''}\u001b[39m\n\u001b[31m            ${waUrl?`<a href=\\\"${waUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;padding:4px 10px;background:#dcfce7;color:#15803d;border-radius:20px;text-decoration:none;font-weight:600\\\">💬 WhatsApp</a>`:''}\u001b[39m\n\u001b[31m            ${telUrl?`<a href=\\\"${telUrl}\\\" style=\\\"font-size:11px;padding:4px 10px;background:#f0fdf4;color:#166534;border-radius:20px;text-decoration:none;font-weight:600\\\">📞 Call</a>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        ${s.brand?`<div class=\\\"pi-brand\\\">${s.brand}</div>`:'<div class=\\\"pi-brand\\\" style=\\\"background:var(--rd)\\\">?</div>'}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html+=`<div class=\\\"padd\\\" onclick=\\\"closePicker();openManual('')\\\">+ Not in list? Add new store</div>`;\u001b[39m\n\u001b[31m  list.innerHTML=html;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function pickStore(s){\u001b[39m\n\u001b[31m  selectedStore=s;manualMode=false;closePicker();\u001b[39m\n\u001b[31m  const _dn =LANG==='hi'&&s.nameHi    ?s.nameHi    :s.name;\u001b[39m\n\u001b[31m  const _da =LANG==='hi'&&s.addressHi ?s.addressHi :s.address;\u001b[39m\n\u001b[31m  const _dd =LANG==='hi'&&s.distNameHi?s.distNameHi:s.distName;\u001b[39m\n\u001b[31m  const _dc =LANG==='hi'&&s.cityHi    ?s.cityHi    :s.city;\u001b[39m\n\u001b[31m  document.getElementById('sc-name').textContent=_dn;\u001b[39m\n\u001b[31m  const brandEl=document.getElementById('sc-brand');\u001b[39m\n\u001b[31m  brandEl.textContent=s.brand||'No Brand';brandEl.style.background=s.brand?'var(--nv)':'var(--rd)';\u001b[39m\n\u001b[31m  const subs=await dbAll('subs');\u001b[39m\n\u001b[31m  const prev=subs.filter(x=>x.data?.storeName===s.name).sort((a,b)=>new Date(b.timestamp)-new Date(a.timestamp))[0];\u001b[39m\n\u001b[31m  const lc=document.getElementById('sc-last');\u001b[39m\n\u001b[31m  if(prev){const d=new Date(prev.timestamp);lc.textContent='Last: '+d.toLocaleDateString('en-IN',{day:'numeric',month:'short'});lc.style.display='inline-flex';}\u001b[39m\n\u001b[31m  else lc.style.display='none';\u001b[39m\n\u001b[31m  // All Excel fields — display in active language\u001b[39m\n\u001b[31m  const mUrl=s.address?`https://maps.google.com/?q=${encodeURIComponent(s.address)}`:'';\u001b[39m\n\u001b[31m  const wUrl=s.mobile?`https://wa.me/91${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const tUrl=s.mobile?`tel:${s.mobile.replace(/\\\\D/g,'').slice(-10)}`:'';\u001b[39m\n\u001b[31m  const details=[];\u001b[39m\n\u001b[31m  if(_da)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📍 ${_da}${mUrl?` <a href=\\\"${mUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#0369a1;margin-left:6px\\\">🗺 Navigate</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(s.mobile)details.push(`<div style=\\\"font-size:13px;color:var(--g600)\\\">📞 ${s.mobile}${tUrl?` <a href=\\\"${tUrl}\\\" style=\\\"font-size:11px;color:#166534;margin-left:6px\\\">Call</a>`:''}${wUrl?` <a href=\\\"${wUrl}\\\" target=\\\"_blank\\\" style=\\\"font-size:11px;color:#15803d;margin-left:6px\\\">WhatsApp</a>`:''}</div>`);\u001b[39m\n\u001b[31m  if(_dd)details.push(`<div style=\\\"font-size:12px;color:var(--am)\\\">👤 ${_dd}</div>`);\u001b[39m\n\u001b[31m  if(_dc)details.push(`<div style=\\\"font-size:12px;color:var(--g500)\\\">🏙 ${_dc}</div>`);\u001b[39m\n\u001b[31m  const opp=[];\u001b[39m\n\u001b[31m  if(s.glowSign&&s.glowSign.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dcfce7;color:#14532d;padding:2px 7px;border-radius:10px;font-weight:600\\\">Glow ✓</span>');\u001b[39m\n\u001b[31m  if(s.inshop&&s.inshop.toLowerCase()==='yes')opp.push('<span style=\\\"font-size:11px;background:#dbeafe;color:#1e40af;padding:2px 7px;border-radius:10px;font-weight:600\\\">Inshop ✓</span>');\u001b[39m\n\u001b[31m  if(s.proj)opp.push(`<span style=\\\"font-size:11px;background:var(--g100);color:var(--g600);padding:2px 7px;border-radius:10px\\\">Target 2026: ${s.proj}</span>`);\u001b[39m\n\u001b[31m  if(opp.length)details.push(`<div style=\\\"display:flex;gap:5px;flex-wrap:wrap;margin-top:3px\\\">${opp.join('')}</div>`);\u001b[39m\n\u001b[31m  document.getElementById('sc-details').innerHTML=details.join('');\u001b[39m\n\u001b[31m  // Missing fields\u001b[39m\n\u001b[31m  const missing=[];\u001b[39m\n\u001b[31m  if(!s.address)missing.push({key:'address',label:'Store Address',type:'textarea',placeholder:'Full address'});\u001b[39m\n\u001b[31m  if(!s.mobile)missing.push({key:'mobile',label:'Mobile No.',type:'tel',placeholder:'10-digit number',maxlen:'10'});\u001b[39m\n\u001b[31m  const mw=document.getElementById('sc-missing'),mf=document.getElementById('sc-missing-fields');\u001b[39m\n\u001b[31m  if(missing.length){\u001b[39m\n\u001b[31m    mf.innerHTML=missing.map(m=>`<div class=\\\"field\\\" style=\\\"margin-bottom:12px\\\"><label style=\\\"font-size:13px;font-weight:500;color:var(--g600)\\\">${m.label} <span class=\\\"req\\\">*</span></label>${m.type==='textarea'?`<textarea id=\\\"sc-miss-${m.key}\\\" rows=\\\"2\\\" placeholder=\\\"${m.placeholder}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></textarea>`:`<input type=\\\"${m.type}\\\" id=\\\"sc-miss-${m.key}\\\" placeholder=\\\"${m.placeholder}\\\" ${m.maxlen?`maxlength=\\\"${m.maxlen}\\\"`:''}  inputmode=\\\"${m.type==='tel'?'numeric':'text'}\\\" onchange=\\\"updateMissingField('${m.key}',this.value)\\\" style=\\\"width:100%;padding:10px 12px;border:1.5px solid var(--or);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\">`}</div>`).join('');\u001b[39m\n\u001b[31m    mw.style.display='block';\u001b[39m\n\u001b[31m  } else {mw.style.display='none';}\u001b[39m\n\u001b[31m  // Brand selector\u001b[39m\n\u001b[31m  const bSel=document.getElementById('brand-selector'),bChips=document.getElementById('brand-chips');\u001b[39m\n\u001b[31m  if(!s.brand){\u001b[39m\n\u001b[31m    renderBrandChips();\u001b[39m\n\u001b[31m    bSel.style.display='block';\u001b[39m\n\u001b[31m  } else {bSel.style.display='none';}\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  F.storeName=s.name;F.brand=s.brand||'';F.address=s.address||'';F.mobile=s.mobile||'';\u001b[39m\n\u001b[31m  if(s.brand&&!_selectedClient&&!_clientOtherMode) autoSetClient(s.brand);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updateMissingField(key,val){if(!selectedStore)return;selectedStore[key]=val.trim();F[key]=val.trim();saveDraft();}\u001b[39m\n\u001b[31mfunction selectStoreBrand(b){\u001b[39m\n\u001b[31m  F.brand=b;F.brandLogoUrl=_brandLogos[b]||'';\u001b[39m\n\u001b[31m  if(selectedStore)selectedStore.brand=b;\u001b[39m\n\u001b[31m  const el=document.getElementById('sc-brand');if(el){el.textContent=b;el.style.background='var(--nv)';}\u001b[39m\n\u001b[31m  document.querySelectorAll('#brand-chips .chip').forEach(c=>{c.classList.toggle('sel',c.querySelector('span')?.textContent===b||c.textContent.trim()===b);});\u001b[39m\n\u001b[31m  if(!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction onManualBrandChange(){\u001b[39m\n\u001b[31m  const b=document.getElementById('f-brand')?.value||'';\u001b[39m\n\u001b[31m  F.brandLogoUrl=b?(_brandLogos[b]||''):'';\u001b[39m\n\u001b[31m  if(b&&!_selectedClient&&!_clientOtherMode) autoSetClient(b);\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction openManual(prefill){\u001b[39m\n\u001b[31m  manualMode=true;\u001b[39m\n\u001b[31m  document.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('pick-trigger-wrap').style.display='block';\u001b[39m\n\u001b[31m  document.getElementById('manual-toggle').classList.add('on');\u001b[39m\n\u001b[31m  document.getElementById('mt-label').innerHTML='← Back to store list';\u001b[39m\n\u001b[31m  document.getElementById('manual-fields').style.display='block';\u001b[39m\n\u001b[31m  // Pre-fill from selectedStore if available (e.g. when toggling after picker selection)\u001b[39m\n\u001b[31m  const s=selectedStore;\u001b[39m\n\u001b[31m  if(s){\u001b[39m\n\u001b[31m    if(document.getElementById('f-brand'))document.getElementById('f-brand').value=s.brand||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-store'))document.getElementById('f-store').value=s.name||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-addr'))document.getElementById('f-addr').value=s.address||'';\u001b[39m\n\u001b[31m    if(document.getElementById('f-mobile'))document.getElementById('f-mobile').value=s.mobile||'';\u001b[39m\n\u001b[31m  } else if(prefill){\u001b[39m\n\u001b[31m    document.getElementById('f-store').value=prefill;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  selectedStore=null;\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction toggleManual(){\u001b[39m\n\u001b[31m  if(manualMode){\u001b[39m\n\u001b[31m    manualMode=false;\u001b[39m\n\u001b[31m    document.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31m    document.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31m    document.getElementById('manual-fields').style.display='none';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    openManual('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// GPS\u001b[39m\n\u001b[31mfunction captureGPS(){\u001b[39m\n\u001b[31m  const el=document.getElementById('gps-status');el.textContent='Getting location…';el.style.color='var(--g500)';\u001b[39m\n\u001b[31m  if(!navigator.geolocation){el.textContent='GPS not available';return;}\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(pos=>{\u001b[39m\n\u001b[31m    gpsCoords={lat:pos.coords.latitude.toFixed(6),lng:pos.coords.longitude.toFixed(6),acc:Math.round(pos.coords.accuracy)};\u001b[39m\n\u001b[31m    el.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${gpsCoords.acc}m)`;el.style.color='var(--gn)';saveDraft();\u001b[39m\n\u001b[31m  },()=>{el.textContent='GPS failed — enter address manually';el.style.color='var(--rd)';},{enableHighAccuracy:true,timeout:10000});\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// DRAFT\u001b[39m\n\u001b[31mlet draftT;\u001b[39m\n\u001b[31mfunction saveDraft(){\u001b[39m\n\u001b[31m  clearTimeout(draftT);\u001b[39m\n\u001b[31m  draftT=setTimeout(async()=>{\u001b[39m\n\u001b[31m    const draft={k:'current',ts:Date.now(),F:{...F,date:document.getElementById('f-date')?.value||'',brand:manualMode?(document.getElementById('f-brand')?.value||''):(selectedStore?.brand||F.brand||''),storeName:selectedStore?selectedStore.name:(document.getElementById('f-store')?.value||''),address:manualMode?(document.getElementById('f-addr')?.value||''):(selectedStore?.address||F.address||''),mobile:manualMode?(document.getElementById('f-mobile')?.value||''):(selectedStore?.mobile||F.mobile||''),clientName:getClientName()},selectedStore,manualMode,gpsCoords,_selectedClient,_clientOtherMode,fCnt:frontPhotos.length,iCnt:insidePhotos.length,bCnt:brandings.length};\u001b[39m\n\u001b[31m    await dbPut('draft',draft);\u001b[39m\n\u001b[31m    // Also save photos as b64 blobs to draft so they survive exit\u001b[39m\n\u001b[31m    await saveDraftPhotos();\u001b[39m\n\u001b[31m  },500);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveDraftPhotos(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const photoData={\u001b[39m\n\u001b[31m      front:await Promise.all(frontPhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      inside:await Promise.all(insidePhotos.map(async p=>({b64:await b64(p.blob),cmt:p.cmt||''}))),\u001b[39m\n\u001b[31m      addl:await Promise.all(addlPhotos.map(async p=>({b64:await b64(p.blob),desc:p.desc||''}))),\u001b[39m\n\u001b[31m      brand:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,b64:b.blob?await b64(b.blob):null})))\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    await dbPut('draft',{k:'photos',...photoData});\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function checkDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');const wrap=document.getElementById('resume-wrap');\u001b[39m\n\u001b[31m  if(!d||!d.F?.storeName){wrap.innerHTML='';return;}\u001b[39m\n\u001b[31m  const ago=Math.round((Date.now()-d.ts)/60000);\u001b[39m\n\u001b[31m  const agoStr=ago<1?'just now':ago<60?`${ago}m ago`:`${Math.round(ago/60)}h ago`;\u001b[39m\n\u001b[31m  wrap.innerHTML=`<button class=\\\"resume-btn\\\" onclick=\\\"resumeDraft()\\\">\u001b[39m\n\u001b[31m    <div><div style=\\\"font-size:12px;color:rgba(255,255,255,.5);margin-bottom:3px\\\">Resume draft · ${agoStr}</div><div>${d.F.storeName} · ${d.F.brand||'No brand'}</div></div>\u001b[39m\n\u001b[31m    <div style=\\\"text-align:right\\\"><div style=\\\"font-size:13px;color:var(--or)\\\">${d.fCnt||0} photos · ${d.bCnt||0} brandings →</div></div>\u001b[39m\n\u001b[31m  </button>`;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function resumeDraft(){\u001b[39m\n\u001b[31m  const d=await dbGet('draft','current');if(!d)return;\u001b[39m\n\u001b[31m  F=d.F||{};gpsCoords=d.gpsCoords||null;\u001b[39m\n\u001b[31m  if(d.selectedStore){await pickStore(d.selectedStore);}\u001b[39m\n\u001b[31m  else if(d.manualMode){openManual('');if(F.brand)document.getElementById('f-brand').value=F.brand;if(F.storeName)document.getElementById('f-store').value=F.storeName;if(F.address)document.getElementById('f-addr').value=F.address;if(F.mobile)document.getElementById('f-mobile').value=F.mobile;}\u001b[39m\n\u001b[31m  if(F.date)document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  // Restore client chip state\u001b[39m\n\u001b[31m  if(d._clientOtherMode){_clientOtherMode=true;_selectedClient='';const inp=document.getElementById('f-client-other');if(inp&&F.clientName)inp.value=F.clientName;}\u001b[39m\n\u001b[31m  else if(d._selectedClient){_selectedClient=d._selectedClient;_clientOtherMode=false;}\u001b[39m\n\u001b[31m  else if(F.clientName){autoSetClient(F.clientName);}\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  // Restore photos from draft\u001b[39m\n\u001b[31m  const pd=await dbGet('draft','photos');\u001b[39m\n\u001b[31m  if(pd){\u001b[39m\n\u001b[31m    async function b64ToBlob(b64str){if(!b64str)return null;try{const r=await fetch(b64str);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m    for(const p of(pd.front||[])){const bl=await b64ToBlob(p.b64);if(bl)frontPhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.inside||[])){const bl=await b64ToBlob(p.b64);if(bl)insidePhotos.push({blob:bl,prev:URL.createObjectURL(bl),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m    for(const p of(pd.addl||[])){const bl=await b64ToBlob(p.b64);if(bl)addlPhotos.push({blob:bl,prev:URL.createObjectURL(bl),desc:p.desc||''});}\u001b[39m\n\u001b[31m    for(const b of(pd.brand||[])){const bl=await b64ToBlob(b.b64);brandings.push({type:b.type,w:b.w,h:b.h,qty:b.qty,blob:bl,prev:bl?URL.createObjectURL(bl):null});}\u001b[39m\n\u001b[31m    toast('Draft restored with '+frontPhotos.length+' photos ✓','success');\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    toast('Draft restored — photos could not be recovered','info');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// PHOTOS\u001b[39m\n\u001b[31mfunction updPhotoBadge(type){const arr=type==='front'?frontPhotos:insidePhotos;const el=document.getElementById(type+'-badge');if(el){el.textContent=arr.length;el.className='cnt-badge '+(arr.length?'':'gray');}}\u001b[39m\n\u001b[31mfunction renderPhotos(type){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  const cont=document.getElementById(type+'-cont');const addBtn=document.getElementById('add-'+type);\u001b[39m\n\u001b[31m  updPhotoBadge(type);\u001b[39m\n\u001b[31m  if(arr.length===0){cont.innerHTML=`<div class=\\\"pslot\\\" onclick=\\\"addPhoto('${type}')\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to capture or upload</span><span class=\\\"hi-txt\\\">फोटो खींचें या अपलोड करें</span></div></div>`;addBtn.style.display='none';return;}\u001b[39m\n\u001b[31m  cont.innerHTML=arr.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const badge=isRetained?`<span class=\\\"pbadge\\\" style=\\\"background:#475569\\\">Existing</span>`:`<span class=\\\"pbadge\\\">${fmtSz(p.blob.size)}</span>`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replacePhoto('${type}',${i})\\\" style=\\\"right:36px;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"margin-bottom:12px\\\"><div class=\\\"pslot filled\\\" style=\\\"margin-bottom:8px\\\"><img src=\\\"${p.prev}\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmPhoto('${type}',${i})\\\">×</button>${badge}</div><input type=\\\"text\\\" placeholder=\\\"Comments (optional)\\\" value=\\\"${p.cmt||''}\\\" onchange=\\\"${type==='front'?'frontPhotos':'insidePhotos'}[${i}].cmt=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  addBtn.style.display=arr.length<(type==='inside'?5:3)?'inline-flex':'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// Photo source: 'camera' stamps geo, 'gallery' does not\u001b[39m\n\u001b[31mlet _photoSourceCb=null,_photoSourceQuality=null;·\u001b[39m\n\u001b[31mfunction capPhoto(cb,forceSource,quality){\u001b[39m\n\u001b[31m  // quality override: null=use setting, 'hd', 'compressed'\u001b[39m\n\u001b[31m  _photoSourceCb=cb;_photoSourceQuality=quality||null;\u001b[39m\n\u001b[31m  if(forceSource==='camera'){_doCapture(cb,'camera',quality);return;}\u001b[39m\n\u001b[31m  if(forceSource==='gallery'){_doCapture(cb,'gallery',quality);return;}\u001b[39m\n\u001b[31m  // Show picker\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _doCapture(cb,src,quality){\u001b[39m\n\u001b[31m  document.getElementById('photo-src-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  const i=document.createElement('input');\u001b[39m\n\u001b[31m  i.type='file';i.accept='image/*';\u001b[39m\n\u001b[31m  if(src==='camera')i.setAttribute('capture','environment');\u001b[39m\n\u001b[31m  i.style.display='none';\u001b[39m\n\u001b[31m  i.onchange=async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f)return;\u001b[39m\n\u001b[31m    const q=quality||_photoSourceQuality||null;\u001b[39m\n\u001b[31m    try{\u001b[39m\n\u001b[31m      const blob=await compress(f,q==='hd'?1920:q==='compressed'?1280:null,q==='hd'?0.90:q==='compressed'?0.78:null);\u001b[39m\n\u001b[31m      // Only stamp if from camera (live photo)\u001b[39m\n\u001b[31m      const stamped=(src==='camera')?await stampPhoto(blob):blob;\u001b[39m\n\u001b[31m      // Save to device (auto-download trigger)\u001b[39m\n\u001b[31m      savePhotoToDevice(stamped);\u001b[39m\n\u001b[31m      cb({target:{files:[f]},_blob:stamped,_src:src});\u001b[39m\n\u001b[31m    }catch(err){toast('Photo processing failed — try again','error');console.error('_doCapture error:',err);}\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  document.body.appendChild(i);i.click();setTimeout(()=>i.remove(),8000);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction photoSrcCamera(){_doCapture(_photoSourceCb,'camera',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcGallery(){_doCapture(_photoSourceCb,'gallery',_photoSourceQuality);}\u001b[39m\n\u001b[31mfunction photoSrcCancel(){document.getElementById('photo-src-dialog').classList.remove('open');_photoSourceCb=null;}·\u001b[39m\n\u001b[31m// Save photo to device gallery/downloads\u001b[39m\n\u001b[31mfunction savePhotoToDevice(blob){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    const a=document.createElement('a');\u001b[39m\n\u001b[31m    a.href=url;\u001b[39m\n\u001b[31m    a.download='Recce_'+Date.now()+'.jpg';\u001b[39m\n\u001b[31m    a.style.display='none';\u001b[39m\n\u001b[31m    document.body.appendChild(a);a.click();\u001b[39m\n\u001b[31m    setTimeout(()=>{URL.revokeObjectURL(url);a.remove();},1000);\u001b[39m\n\u001b[31m  }catch(e){}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction addPhoto(type){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}${e._src==='camera'&&geoStampEnabled?' · Stamped':''}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31masync function handleCapture(e,type){\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  (type==='front'?frontPhotos:insidePhotos).push({blob:bs,prev:URL.createObjectURL(bs),cmt:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmPhoto(type,i){(type==='front'?frontPhotos:insidePhotos).splice(i,1);renderPhotos(type);saveDraft();}\u001b[39m\n\u001b[31mfunction replacePhoto(type,idx){\u001b[39m\n\u001b[31m  const arr=type==='front'?frontPhotos:insidePhotos;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await stampPhoto(await compress(f)));\u001b[39m\n\u001b[31m    arr[idx]={...arr[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderPhotos(type);saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAddl(){\u001b[39m\n\u001b[31m  const cont=document.getElementById('add-cont');const btn=document.getElementById('add-addl');\u001b[39m\n\u001b[31m  const badge=document.getElementById('addl-badge');if(badge){badge.textContent=`${addlPhotos.length} / 8`;badge.className='cnt-badge '+(addlPhotos.length?'':'gray');}\u001b[39m\n\u001b[31m  cont.innerHTML=addlPhotos.map((p,i)=>{\u001b[39m\n\u001b[31m    const isRetained=!p.blob&&p.existingUrl;\u001b[39m\n\u001b[31m    const sizeInfo=isRetained?'<span style=\\\"color:#475569\\\">Existing</span>':`${fmtSz(p.blob.size)}`;\u001b[39m\n\u001b[31m    const replBtn=isRetained?`<button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();replaceAddl(${i})\\\" style=\\\"top:3px;left:3px;right:auto;background:var(--or)\\\">↺</button>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;gap:10px;align-items:start;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--g100)\\\"><div style=\\\"position:relative;flex-shrink:0\\\"><img src=\\\"${p.prev}\\\" style=\\\"width:80px;height:80px;object-fit:cover;border-radius:var(--rs)\\\">${replBtn}<button class=\\\"premove\\\" onclick=\\\"rmAddl(${i})\\\" style=\\\"top:3px;right:3px\\\">×</button></div><div style=\\\"flex:1\\\"><input type=\\\"text\\\" placeholder=\\\"Description (optional)\\\" value=\\\"${p.desc||''}\\\" onchange=\\\"addlPhotos[${i}].desc=this.value;saveDraft()\\\" style=\\\"width:100%;padding:9px 12px;border:1.5px solid var(--g200);border-radius:var(--rs);font-family:'DM Sans',sans-serif;font-size:14px\\\"><div style=\\\"font-size:11px;color:var(--g400);margin-top:4px\\\">${sizeInfo}</div></div></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m  btn.style.display=addlPhotos.length>=8?'none':'inline-flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction addAdditional(){capPhoto(async e=>{\u001b[39m\n\u001b[31m  const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m  const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m  addlPhotos.push({blob:bs,prev:URL.createObjectURL(bs),desc:'',src:e._src||'gallery'});\u001b[39m\n\u001b[31m  renderAddl();saveDraft();\u001b[39m\n\u001b[31m  toast(`Photo added · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m});}·\u001b[39m\n\u001b[31mfunction rmAddl(i){addlPhotos.splice(i,1);renderAddl();saveDraft();}\u001b[39m\n\u001b[31mfunction replaceAddl(idx){\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f));\u001b[39m\n\u001b[31m    addlPhotos[idx]={...addlPhotos[idx],blob:bs,prev:URL.createObjectURL(bs)};\u001b[39m\n\u001b[31m    renderAddl();saveDraft();\u001b[39m\n\u001b[31m    toast(`Photo replaced · ${fmtSz(bs.size)}`,'success');\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// BRANDING\u001b[39m\n\u001b[31mfunction calcSqft(w,h){const wf=parseFloat(w),hf=parseFloat(h);if(!wf||!hf)return '';return `${(wf*hf).toFixed(0)} sq.in = ${(wf*hf/144).toFixed(2)} sq.ft`;}\u001b[39m\n\u001b[31mfunction renderBrandings(){\u001b[39m\n\u001b[31m  _updateBrandingLock();\u001b[39m\n\u001b[31m  const cont=document.getElementById('br-items');\u001b[39m\n\u001b[31m  const hb=document.getElementById('br-hdr-badge');if(hb)hb.textContent=`${brandings.length} ${t(brandings.length!==1?'items':'item',brandings.length!==1?'आइटम':'आइटम')}`;\u001b[39m\n\u001b[31m  cont.innerHTML=brandings.map((b,i)=>`<div class=\\\"bitem\\\"><div class=\\\"bitem-hdr\\\"><div class=\\\"bitem-title\\\">${t('Branding','ब्रांडिंग')} ${i+1}${b.type?' — '+b.type:''}</div>\u001b[39m\n\u001b[31m    <div style=\\\"display:flex;gap:6px\\\">${i>0?`<button class=\\\"btn-d\\\" onclick=\\\"dupBr(${i})\\\" style=\\\"color:var(--or);border-color:var(--orl)\\\">${t('Dup ↑','डुप ↑')}</button>`:''}<button class=\\\"btn-d\\\" onclick=\\\"rmBr(${i})\\\">${t('Remove','हटाएं')}</button></div></div>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\"><label>${t('Type','प्रकार')} <span class=\\\"req\\\">*</span></label><div class=\\\"chip-grid\\\">${BTYPE.map(tp=>`<div class=\\\"chip${b.type===tp?' sel':''}\\\" onclick=\\\"setBType(${i},'${tp.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\"> ${tp}</div>`).join('')}</div></div>\u001b[39m\n\u001b[31m    <div class=\\\"dim-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Width (in)','चौड़ाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.w||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].w=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\"><label>${t('Height (in)','ऊंचाई (इंच)')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.h||''}\\\" placeholder=\\\"0\\\" inputmode=\\\"decimal\\\" oninput=\\\"brandings[${i}].h=this.value;updSqft(${i})\\\"></div>\u001b[39m\n\u001b[31m      <div class=\\\"field\\\" style=\\\"max-width:74px\\\"><label>${t('Qty','मात्रा')} <span class=\\\"req\\\">*</span></label><input type=\\\"number\\\" value=\\\"${b.qty||''}\\\" placeholder=\\\"1\\\" inputmode=\\\"numeric\\\" onchange=\\\"brandings[${i}].qty=this.value;saveDraft()\\\"></div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <span class=\\\"sqft\\\" id=\\\"sf${i}\\\">${calcSqft(b.w,b.h)||t('Enter W × H','W × H दर्ज करें')}</span>\u001b[39m\n\u001b[31m    <div class=\\\"field\\\" style=\\\"margin-top:12px\\\"><label>${t('Photo','फोटो')} <span class=\\\"req\\\">*</span></label>\u001b[39m\n\u001b[31m      ${b.prev?`<div class=\\\"pslot filled\\\" onclick=\\\"capBr(${i})\\\"><img src=\\\"${b.prev}\\\"><button class=\\\"premove\\\" onclick=\\\"event.stopPropagation();rmBrPh(${i})\\\">×</button><span class=\\\"pbadge\\\">${b.blob?fmtSz(b.blob.size):'Existing'}</span></div>`:`<div><div class=\\\"pslot\\\" onclick=\\\"capBr(${i})\\\"><div class=\\\"pslot-ico\\\">📷</div><div class=\\\"pslot-lbl\\\">${t('Tap to capture','दबाकर कैप्चर करें')}</div></div><div style=\\\"display:flex;gap:6px;margin-top:6px\\\"><button class=\\\"atool${(b.quality||imgQuality)==='compressed'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'compressed');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">${t('Compressed','कम्प्रेस्ड')}</button><button class=\\\"atool${(b.quality||imgQuality)==='hd'?' on':''}\\\" onclick=\\\"setBrQuality(${i},'hd');event.stopPropagation()\\\" style=\\\"font-size:11px;padding:4px 10px\\\">HD</button></div></div>`}\u001b[39m\n\u001b[31m    </div></div>`).join('');\u001b[39m\n\u001b[31m  // Only show \\\"Add Another\\\" when last item is fully complete\u001b[39m\n\u001b[31m  const addDiv=document.getElementById('br-add');\u001b[39m\n\u001b[31m  if(addDiv&&brandings.length>0){\u001b[39m\n\u001b[31m    const last=brandings[brandings.length-1];\u001b[39m\n\u001b[31m    const lastComplete=last.type&&last.w&&last.h&&last.qty&&last.prev;\u001b[39m\n\u001b[31m    addDiv.style.display=(lastComplete&&brandings.length<15)?'block':'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction updSqft(i){const el=document.getElementById('sf'+i);if(el)el.textContent=calcSqft(brandings[i].w,brandings[i].h)||t('Enter W × H','W × H दर्ज करें');saveDraft();}\u001b[39m\n\u001b[31mfunction setBType(i,tp){brandings[i].type=tp;renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction addBranding(){if(brandings.length>=15){toast(t('Max 15 items','अधिकतम 15 आइटम'),'error');return;}brandings.push({type:'',w:'',h:'',qty:'1',blob:null,prev:null});renderBrandings();}\u001b[39m\n\u001b[31mfunction dupBr(i){if(brandings.length>=10){toast(t('Max 10 items','अधिकतम 10 आइटम'),'error');return;}const s=brandings[i-1];brandings.splice(i,0,{type:s.type,w:s.w,h:s.h,qty:s.qty,blob:null,prev:null});renderBrandings();toast(t('Duplicated — add photo','डुप्लीकेट — फोटो जोड़ें'),'info');}\u001b[39m\n\u001b[31mfunction rmBr(i){brandings.splice(i,1);renderBrandings();saveDraft();}\u001b[39m\n\u001b[31mfunction capBr(i){\u001b[39m\n\u001b[31m  const q=brandings[i]?.quality||imgQuality;\u001b[39m\n\u001b[31m  capPhoto(async e=>{\u001b[39m\n\u001b[31m    const f=e.target.files[0];if(!f&&!e._blob)return;\u001b[39m\n\u001b[31m    const bs=e._blob||(await compress(f,q==='hd'?1920:1280,q==='hd'?0.90:0.78));\u001b[39m\n\u001b[31m    brandings[i].blob=bs;brandings[i].prev=URL.createObjectURL(bs);\u001b[39m\n\u001b[31m    brandings[i].fromCamera=(e._src==='camera');\u001b[39m\n\u001b[31m    openAnnot(i);\u001b[39m\n\u001b[31m  },null,q);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction rmBrPh(i){brandings[i].blob=null;brandings[i].prev=null;renderBrandings();}\u001b[39m\n\u001b[31mfunction setBrQuality(i,q){brandings[i].quality=q;renderBrandings();}·\u001b[39m\n\u001b[31m// VIDEO / DOC\u001b[39m\n\u001b[31mfunction setVideo(v){F.hasVideo=v;document.getElementById('vid-yes').classList.toggle('sel',v);document.getElementById('vid-no').classList.toggle('sel',!v);document.getElementById('vid-sec').style.display=v?'block':'none';saveDraft();}\u001b[39m\n\u001b[31masync function handleVideo(e){videoBlob=e.target.files[0];if(!videoBlob)return;document.getElementById('vid-slot').innerHTML=`<div style=\\\"padding:14px;font-size:13px;color:var(--gn)\\\">✓ ${videoBlob.name} (${fmtSz(videoBlob.size)})</div>`;}\u001b[39m\n\u001b[31mfunction setBranding(v){F.hasBranding=v;document.getElementById('br-yes').classList.toggle('sel',v);document.getElementById('br-no').classList.toggle('sel',!v);document.getElementById('br-add').style.display=v?'block':'none';if(v&&brandings.length===0)addBranding();saveDraft();}\u001b[39m\n\u001b[31masync function handleDoc(e){const f=e.target.files[0];if(!f)return;submissionDoc=f.type.startsWith('image/')?await compress(f,1600,.85):f;const slot=document.getElementById('doc-slot');if(f.type.startsWith('image/')){slot.classList.add('filled');slot.innerHTML=`<img src=\\\"${URL.createObjectURL(submissionDoc)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}else{slot.innerHTML=`<div style=\\\"padding:16px;font-size:13px;color:var(--gn)\\\">✓ ${f.name} (${fmtSz(f.size)})</div>`;}buildReview();}·\u001b[39m\n\u001b[31m// CLIENT CHIPS\u001b[39m\n\u001b[31mfunction renderClientChips(){\u001b[39m\n\u001b[31m  const grid = document.getElementById('client-chips'); if (!grid) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  clientList.forEach(c => {\u001b[39m\n\u001b[31m    const sel = !_clientOtherMode && _selectedClient === c;\u001b[39m\n\u001b[31m    html += `<div class=\\\"cl-chip${sel?' sel':''}\\\" onclick=\\\"selectClientChip('${esc(c)}')\\\">${esc(c)}</div>`;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  html += `<div class=\\\"cl-chip cl-chip-other${_clientOtherMode?' sel':''}\\\" onclick=\\\"selectClientOther()\\\"><span class=\\\"en-txt\\\">Other…</span><span class=\\\"hi-txt\\\">अन्य…</span></div>`;\u001b[39m\n\u001b[31m  grid.innerHTML = html;\u001b[39m\n\u001b[31m  document.getElementById('client-other-wrap').style.display = _clientOtherMode ? 'block' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientChip(name){\u001b[39m\n\u001b[31m  _selectedClient = name; _clientOtherMode = false;\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').value = '';\u001b[39m\n\u001b[31m  renderClientChips(); saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectClientOther(){\u001b[39m\n\u001b[31m  _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  document.getElementById('f-client-other').focus();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction onClientOtherInput(){\u001b[39m\n\u001b[31m  _selectedClient = document.getElementById('f-client-other').value.trim();\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction getClientName(){\u001b[39m\n\u001b[31m  if (_clientOtherMode) return (document.getElementById('f-client-other')?.value||'').trim();\u001b[39m\n\u001b[31m  return _selectedClient;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction autoSetClient(brandName){\u001b[39m\n\u001b[31m  if (!brandName) return;\u001b[39m\n\u001b[31m  const clientList = _recceCfg.clients || [];\u001b[39m\n\u001b[31m  if (clientList.includes(brandName)){\u001b[39m\n\u001b[31m    _selectedClient = brandName; _clientOtherMode = false;\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    // Not in list — pre-fill the Other field\u001b[39m\n\u001b[31m    _clientOtherMode = true; _selectedClient = '';\u001b[39m\n\u001b[31m    const inp = document.getElementById('f-client-other');\u001b[39m\n\u001b[31m    if (inp && !inp.value) inp.value = brandName;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// STEP VALIDATION\u001b[39m\n\u001b[31mfunction getSD(){if(selectedStore&&!manualMode)return{storeName:selectedStore.name,brand:selectedStore.brand||'',address:selectedStore.address||'',mobile:selectedStore.mobile||''};return{storeName:(document.getElementById('f-store')?.value||'').trim(),brand:document.getElementById('f-brand')?.value||'',address:(document.getElementById('f-addr')?.value||'').trim(),mobile:(document.getElementById('f-mobile')?.value||'').trim()};}\u001b[39m\n\u001b[31mfunction step2(){\u001b[39m\n\u001b[31m  const d=document.getElementById('f-date').value;\u001b[39m\n\u001b[31m  if(!d){toast('Select date','error');return;}\u001b[39m\n\u001b[31m  const sd=getSD();\u001b[39m\n\u001b[31m  if(!sd.storeName){toast('Select or enter store name','error');return;}\u001b[39m\n\u001b[31m  if(!sd.brand){toast('Select a brand','error');document.getElementById('brand-selector').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  if(!sd.address){toast('Enter store address','error');return;}\u001b[39m\n\u001b[31m  const clientName=getClientName();\u001b[39m\n\u001b[31m  if(!clientName){toast(t('Select a client','क्लाइंट चुनें'),'error');document.getElementById('client-chips').scrollIntoView({behavior:'smooth'});return;}\u001b[39m\n\u001b[31m  // Check missing fields filled\u001b[39m\n\u001b[31m  const missAddr=document.getElementById('sc-miss-address');\u001b[39m\n\u001b[31m  if(missAddr&&!missAddr.value.trim()){toast('Enter store address in the highlighted field','error');missAddr.focus();return;}\u001b[39m\n\u001b[31m  const missMob=document.getElementById('sc-miss-mobile');\u001b[39m\n\u001b[31m  // mobile not required — just copy if filled\u001b[39m\n\u001b[31m  if(missMob&&missMob.value.trim()&&!F.mobile)F.mobile=missMob.value.trim();\u001b[39m\n\u001b[31m  Object.assign(F,{date:d,...sd,clientName});saveDraft();\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');showView('form-photos');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction step3(){if(!frontPhotos.length){toast('Add at least 1 front view photo','error');return;}showView('form-video');}\u001b[39m\n\u001b[31mfunction step4(){if(F.hasVideo===undefined||F.hasVideo===null){toast('Select Yes or No for video','error');return;}renderBrandings();showView('form-branding');}\u001b[39m\n\u001b[31mfunction step5(){if(F.hasBranding===undefined||F.hasBranding===null){toast('Select Yes or No for branding space','error');return;}if(F.hasBranding){for(let i=0;i<brandings.length;i++){const b=brandings[i];if(!b.type){toast(`Select branding type for item ${i+1}`,'error');return;}if(!b.w||!b.h){toast(`Enter W and H dimensions for item ${i+1}`,'error');return;}if(!b.qty){toast(`Enter qty for item ${i+1}`,'error');return;}if(!b.blob&&!b.prev){toast(`Add photo for item ${i+1}`,'error');return;}}}renderAddl();buildReview();showView('form-additional');}·\u001b[39m\n\u001b[31m// REVIEW\u001b[39m\n\u001b[31mfunction buildReview(){const el=document.getElementById('rev-body');if(!el)return;const sd=getSD();const cn=getClientName();el.innerHTML=`<div><div class=\\\"rev-lbl\\\">Store</div><div class=\\\"rev-val\\\">${sd.storeName||'—'} · ${sd.brand||'—'}</div><div style=\\\"font-size:12px;color:var(--g500);margin-top:2px\\\">${sd.address||'—'}${sd.mobile?' · '+sd.mobile:''}</div>${gpsCoords?`<div style=\\\"font-size:11px;color:var(--gn);margin-top:3px\\\">📍 ${gpsCoords.lat}, ${gpsCoords.lng} ±${gpsCoords.acc}m</div>`:''}</div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Client</div><div class=\\\"rev-val\\\" style=\\\"color:${cn?'var(--nv)':'var(--rd)'}\\\">${cn||'⚠ Not selected — required'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Photos — Front · Inside · Additional</div><div class=\\\"rev-val\\\">${frontPhotos.length} · ${insidePhotos.length} · ${addlPhotos.length}</div><div class=\\\"rev-photos\\\">${[...frontPhotos,...insidePhotos].slice(0,6).map(p=>`<img class=\\\"rev-thumb\\\" src=\\\"${p.prev}\\\">`).join('')}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Video · Branding items</div><div class=\\\"rev-val\\\">${F.hasVideo?'Yes':'No'} · ${brandings.length} item(s)</div></div>${F.hasBranding&&brandings.length?`<div style=\\\"margin-top:8px\\\">${brandings.map((b,i)=>`<div style=\\\"font-size:12px;color:var(--g600);padding:4px 0;border-bottom:1px solid var(--g100)\\\">${i+1}. ${b.type||'No type'} — ${b.w||'?'}×${b.h||'?'}\\\" × ${b.qty||'?'} — ${calcSqft(b.w,b.h)||'?'}</div>`).join('')}</div>`:''}<div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Additional photos <span style=\\\"font-size:11px;color:var(--g400)\\\">(optional)</span></div><div class=\\\"rev-val\\\" style=\\\"color:${addlPhotos.length?'var(--gn)':'var(--g500)'}\\\">${addlPhotos.length?`✓ ${addlPhotos.length} photo(s) added`:'None added'}</div></div><div class=\\\"divider\\\"></div><div><div class=\\\"rev-lbl\\\">Mandatory document</div><div class=\\\"rev-val\\\" style=\\\"color:${(submissionDoc||_docExistingUrl)?'var(--gn)':'var(--rd)'}\\\">${(submissionDoc||_docExistingUrl)?'✓ Uploaded':'⚠ Missing — required'}</div></div>`;}·\u001b[39m\n\u001b[31m// SUBMIT\u001b[39m\n\u001b[31masync function submitRecce(){\u001b[39m\n\u001b[31m  if(!submissionDoc&&!_docExistingUrl){toast('Upload mandatory doc first','error');return;}\u001b[39m\n\u001b[31m  const btn=document.getElementById('sub-btn');btn.disabled=true;btn.textContent='Saving…';\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const isEdit=!!(F.editingId);\u001b[39m\n\u001b[31m    const id=isEdit?F.editingId:('RC_'+Date.now()+'_'+Math.random().toString(36).slice(2,6).toUpperCase());\u001b[39m\n\u001b[31m    const sd=getSD();\u001b[39m\n\u001b[31m    const _hub=_recceHubUser();\u001b[39m\n\u001b[31m    const entry={id,timestamp:isEdit?(await dbGet('subs',id))?.timestamp||new Date().toISOString():new Date().toISOString(),editedAt:isEdit?new Date().toISOString():undefined,status:'pending',submittedBy:_hub.empId||null,submittedByName:_hub.name||null,data:{...F,...sd,gpsCoords,frontPhotos:await Promise.all(frontPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),insidePhotos:await Promise.all(insidePhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,cmt:p.cmt,existingUrl:p.existingUrl||null}))),videoNote:F.hasVideo&&videoBlob?`Video local (${fmtSz(videoBlob.size)}) — share via WhatsApp`:null,videoCmt:document.getElementById('f-vid-cmt')?.value||'',brandings:await Promise.all(brandings.map(async b=>({type:b.type,w:b.w,h:b.h,qty:b.qty,sqft:calcSqft(b.w,b.h),photoB64:b.blob?await b64(b.blob):null,existingUrl:b.existingUrl||null}))),addlPhotos:await Promise.all(addlPhotos.map(async p=>({b64:p.blob?await b64(p.blob):null,desc:p.desc,existingUrl:p.existingUrl||null}))),docB64:submissionDoc?await b64(submissionDoc):null,_docExistingUrl:_docExistingUrl||null}};\u001b[39m\n\u001b[31m    entry.campaignId       = _selectedCampaignId || null;\u001b[39m\n\u001b[31m    entry.notifySupervisor = _notifySupervisor   || false;\u001b[39m\n\u001b[31m    await dbPut('subs',entry);\u001b[39m\n\u001b[31m    await dbDel('draft','current');\u001b[39m\n\u001b[31m    toast(isEdit?'Recce updated ✓':'Recce saved ✓','success');\u001b[39m\n\u001b[31m    if(navigator.onLine)syncNow();\u001b[39m\n\u001b[31m    showView('home');loadHome();checkDraft();\u001b[39m\n\u001b[31m  }catch(err){toast('Error: '+err.message,'error');}\u001b[39m\n\u001b[31m  finally{btn.disabled=false;btn.textContent='Submit Recce ✓';}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// SYNC\u001b[39m\n\u001b[31masync function syncNow() {\u001b[39m\n\u001b[31m  if (!navigator.onLine) { toast('Offline — sync when back online', 'info'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('sync-btn');\u001b[39m\n\u001b[31m  const SYNC_ICON = '<svg width=\\\"13\\\" height=\\\"13\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"23 4 23 10 17 10\\\"/><polyline points=\\\"1 20 1 14 7 14\\\"/><path d=\\\"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15\\\"/></svg>Sync';\u001b[39m\n\u001b[31m  if (btn) { btn.innerHTML = '<span class=\\\"spin\\\">↻</span> Syncing'; btn.disabled = true; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const all      = await dbAll('subs');\u001b[39m\n\u001b[31m    const pend     = all.filter(s => s.status === 'pending' || s.status === 'failed');\u001b[39m\n\u001b[31m    const backfill = all.filter(s => s.status === 'synced' && !s.gasAt);\u001b[39m\n\u001b[31m    if (!pend.length && !backfill.length) { toast('All synced ✓', 'success'); return; }·\u001b[39m\n\u001b[31m    const gasUrl = (await cfg('gas-url')) || DEFAULT_GAS_URL;\u001b[39m\n\u001b[31m    function fireGas(s) {\u001b[39m\n\u001b[31m      if (!gasUrl) return;\u001b[39m\n\u001b[31m      fetch(gasUrl, { method:'POST', mode:'no-cors',\u001b[39m\n\u001b[31m        body: JSON.stringify({ action:'syncSheet', submission: s }) })\u001b[39m\n\u001b[31m        .catch(() => {});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    let ok = 0;\u001b[39m\n\u001b[31m    for (const s of pend) {\u001b[39m\n\u001b[31m      // Fire Sheet sync (no-cors fire-and-forget — writes row to Google Sheet)\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      // Primary: upload photos → auto-trigger slides → generate report → store in PostgreSQL\u001b[39m\n\u001b[31m      const { ok: pgOk, viewUrl } = await syncToPostgres(s);\u001b[39m\n\u001b[31m      if (pgOk) {\u001b[39m\n\u001b[31m        s.status = 'synced'; s.syncedAt = new Date().toISOString();\u001b[39m\n\u001b[31m        if (viewUrl) s.viewUrl = viewUrl;\u001b[39m\n\u001b[31m        await dbPut('subs', s); ok++;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        s.status = 'failed'; await dbPut('subs', s);\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Backfill: entries synced to Postgres but never reached Sheet GAS\u001b[39m\n\u001b[31m    for (const s of backfill) {\u001b[39m\n\u001b[31m      fireGas(s);\u001b[39m\n\u001b[31m      s.gasAt = new Date().toISOString();\u001b[39m\n\u001b[31m      await dbPut('subs', s);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if (backfill.length) toast(`Sent ${backfill.length} older entries to Sheet`, 'info');·\u001b[39m\n\u001b[31m    await cfg('last-sync', new Date().toISOString());\u001b[39m\n\u001b[31m    if (pend.length) toast(`Synced ${ok}/${pend.length}`, ok === pend.length ? 'success' : 'error');\u001b[39m\n\u001b[31m    loadHome();\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.innerHTML = SYNC_ICON; btn.disabled = false; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── ADMIN HOME ──────────────────────────────────────────────\u001b[39m\n\u001b[31masync function loadHomeAdmin() {\u001b[39m\n\u001b[31m  // Adapt UI for admin view\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const _sh = document.querySelector('.sh'); if (_sh) _sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = 'All Submissions';\u001b[39m\n\u001b[31m  const slbls = document.querySelectorAll('.slbl');\u001b[39m\n\u001b[31m  if (slbls[0]) slbls[0].textContent = 'Showing';\u001b[39m\n\u001b[31m  if (slbls[1]) slbls[1].textContent = 'Agents';·\u001b[39m\n\u001b[31m  // Back-to-menu button for supervisors\u001b[39m\n\u001b[31m  if (_isSupervisor() && !document.getElementById('sup-back-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => { document.getElementById('sup-back-btn').remove(); renderSupLanding(); };\u001b[39m\n\u001b[31m    const content = document.querySelector('#view-home .content');\u001b[39m\n\u001b[31m    content.prepend(bb);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Show filter bar — restore if hidden by renderSupLanding, else inject fresh\u001b[39m\n\u001b[31m  const _existingFb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (_existingFb) { _existingFb.style.display = ''; }\u001b[39m\n\u001b[31m  if (!_existingFb) {\u001b[39m\n\u001b[31m    const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m    const fb = document.createElement('div');\u001b[39m\n\u001b[31m    fb.id = 'admin-filter-bar';\u001b[39m\n\u001b[31m    fb.className = 'af-bar';\u001b[39m\n\u001b[31m    fb.innerHTML =\u001b[39m\n\u001b[31m      `<div class=\\\"af-grid\\\">\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-agent\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Agents</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-brand\\\"  onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Brands</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-client\\\" onchange=\\\"renderAdminList()\\\"><option value=\\\"\\\">All Clients</option></select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-period\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"\\\">All Time</option>\u001b[39m\n\u001b[31m          <option value=\\\"7\\\">Last 7 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"30\\\">Last 30 days</option>\u001b[39m\n\u001b[31m          <option value=\\\"90\\\">Last 3 months</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m        <select class=\\\"af-sel\\\" id=\\\"af-group\\\" onchange=\\\"renderAdminList()\\\">\u001b[39m\n\u001b[31m          <option value=\\\"date\\\">Sort: Recent</option>\u001b[39m\n\u001b[31m          <option value=\\\"agent\\\">Group: Agent</option>\u001b[39m\n\u001b[31m          <option value=\\\"brand\\\">Group: Brand</option>\u001b[39m\n\u001b[31m          <option value=\\\"client\\\">Group: Client</option>\u001b[39m\n\u001b[31m          <option value=\\\"city\\\">Group: City</option>\u001b[39m\n\u001b[31m        </select>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m        <input class=\\\"af-inp\\\" id=\\\"af-search\\\" type=\\\"text\\\" placeholder=\\\"🔍 Search store or city…\\\" oninput=\\\"renderAdminList()\\\" style=\\\"flex:1;min-width:120px\\\">\u001b[39m\n\u001b[31m        <button class=\\\"del-toggle-btn\\\" id=\\\"del-toggle-btn\\\" onclick=\\\"toggleDeletedView()\\\" style=\\\"flex-shrink:0\\\">📋 View Deleted</button>\u001b[39m\n\u001b[31m        ${_isSupervisor() ? `<button class=\\\"del-toggle-btn\\\" id=\\\"pending-job-btn\\\" onclick=\\\"togglePendingJobView()\\\" style=\\\"flex-shrink:0;background:#fef3c7;color:#92400e;border-color:#f59e0b\\\">⚑ Unlinked <span id=\\\"pending-job-count\\\" style=\\\"font-weight:900\\\"></span></button>` : ''}\u001b[39m\n\u001b[31m        ${_adminUnlocked ? `<button class=\\\"del-toggle-btn\\\" id=\\\"regen-rpt-btn\\\" onclick=\\\"regenAllReports()\\\" style=\\\"flex-shrink:0\\\">&#x21BB; Regen Reports</button>` : ''}\u001b[39m\n\u001b[31m      </div>`;\u001b[39m\n\u001b[31m    sh.parentNode.insertBefore(fb, sh);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  // Fetch\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  list.innerHTML = '<div style=\\\"text-align:center;padding:40px\\\"><div class=\\\"spinner\\\"></div></div>';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?order=submitted_at.desc&limit=500`, { headers: _RC_READ });\u001b[39m\n\u001b[31m    _adminRows = resp.ok ? await resp.json() : [];\u001b[39m\n\u001b[31m    document.getElementById('stat-total').textContent = _adminRows.length;\u001b[39m\n\u001b[31m    if (resp.ok) {\u001b[39m\n\u001b[31m      const now = new Date();\u001b[39m\n\u001b[31m      document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m        'Loaded ' + now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    }·\u001b[39m\n\u001b[31m    // Populate agent dropdown\u001b[39m\n\u001b[31m    const agents = [...new Set(_adminRows.map(r => r.submitted_by).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-agent').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Agents (${agents.length})</option>` +\u001b[39m\n\u001b[31m      agents.map(a => `<option value=\\\"${a}\\\">${a}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate brand dropdown\u001b[39m\n\u001b[31m    const brands = [...new Set(_adminRows.map(r => r.brand).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-brand').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Brands (${brands.length})</option>` +\u001b[39m\n\u001b[31m      brands.map(b => `<option value=\\\"${b}\\\">${b}</option>`).join('');·\u001b[39m\n\u001b[31m    // Populate client dropdown\u001b[39m\n\u001b[31m    const clients = [...new Set(_adminRows.map(r => r.client_name).filter(Boolean))].sort();\u001b[39m\n\u001b[31m    document.getElementById('af-client').innerHTML =\u001b[39m\n\u001b[31m      `<option value=\\\"\\\">All Clients (${clients.length})</option>` +\u001b[39m\n\u001b[31m      clients.map(c => `<option value=\\\"${c}\\\">${c}</option>`).join('');·\u001b[39m\n\u001b[31m    // Update pending-job count badge\u001b[39m\n\u001b[31m    const unlinkedCount = _adminRows.filter(r => !r.deleted_at && !r.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinkedCount ? `(${unlinkedCount})` : '';·\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">⚠️</div><div class=\\\"empty-txt\\\">Could not load — check connection</div></div>';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction togglePendingJobView() {\u001b[39m\n\u001b[31m  _pendingJobFilter = !_pendingJobFilter;\u001b[39m\n\u001b[31m  _showDeletedView  = false;\u001b[39m\n\u001b[31m  const btn = document.getElementById('pending-job-btn');\u001b[39m\n\u001b[31m  if (btn) btn.style.background = _pendingJobFilter ? '#f59e0b' : '#fef3c7';\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function openLinkJobModal(subId, storeName) {\u001b[39m\n\u001b[31m  _linkJobSubId = subId;\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  const storeEl = document.getElementById('link-job-store');\u001b[39m\n\u001b[31m  const sel = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  if (!modal) return;\u001b[39m\n\u001b[31m  if (storeEl) storeEl.textContent = storeName || subId;\u001b[39m\n\u001b[31m  if (errEl) errEl.textContent = '';\u001b[39m\n\u001b[31m  // Load campaigns into dropdown\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (!_campaignList.length) {\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/campaigns?status=eq.active&order=created_at.desc&limit=100`, { headers: _INSTALL_RD });\u001b[39m\n\u001b[31m      _campaignList = r.ok ? await r.json() : [];\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  if (sel) {\u001b[39m\n\u001b[31m    sel.innerHTML = '<option value=\\\"\\\">— Select campaign —</option>' +\u001b[39m\n\u001b[31m      _campaignList.map(c => `<option value=\\\"${c.campaign_id}\\\">${c.campaign_id}</option>`).join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  modal.style.display = 'flex';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeLinkJobModal() {\u001b[39m\n\u001b[31m  const modal = document.getElementById('modal-link-job');\u001b[39m\n\u001b[31m  if (modal) modal.style.display = 'none';\u001b[39m\n\u001b[31m  _linkJobSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function saveLinkJob() {\u001b[39m\n\u001b[31m  const sel    = document.getElementById('link-job-sel');\u001b[39m\n\u001b[31m  const errEl  = document.getElementById('link-job-err');\u001b[39m\n\u001b[31m  const campId = sel?.value || '';\u001b[39m\n\u001b[31m  if (!campId) { if (errEl) errEl.textContent = 'Select a campaign'; return; }\u001b[39m\n\u001b[31m  if (!_linkJobSubId) return;\u001b[39m\n\u001b[31m  const btn = document.querySelector('#modal-link-job button[onclick=\\\"saveLinkJob()\\\"]');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Linking…'; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(_linkJobSubId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ campaign_id: campId }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Patch failed');\u001b[39m\n\u001b[31m    // Update local cache\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === _linkJobSubId);\u001b[39m\n\u001b[31m    if (idx >= 0) _adminRows[idx].campaign_id = campId;\u001b[39m\n\u001b[31m    // Update pending count badge\u001b[39m\n\u001b[31m    const unlinked = _adminRows.filter(x => !x.deleted_at && !x.campaign_id).length;\u001b[39m\n\u001b[31m    const pjCount = document.getElementById('pending-job-count');\u001b[39m\n\u001b[31m    if (pjCount) pjCount.textContent = unlinked ? `(${unlinked})` : '';\u001b[39m\n\u001b[31m    closeLinkJobModal();\u001b[39m\n\u001b[31m    toast('Job linked ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    if (errEl) errEl.textContent = 'Failed to link — try again';\u001b[39m\n\u001b[31m  } finally {\u001b[39m\n\u001b[31m    if (btn) { btn.disabled = false; btn.textContent = '🔗 Link Job'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderAdminList() {\u001b[39m\n\u001b[31m  const agent  = document.getElementById('af-agent')?.value  || '';\u001b[39m\n\u001b[31m  const brand  = document.getElementById('af-brand')?.value  || '';\u001b[39m\n\u001b[31m  const period = document.getElementById('af-period')?.value || '';\u001b[39m\n\u001b[31m  const search = (document.getElementById('af-search')?.value || '').toLowerCase().trim();\u001b[39m\n\u001b[31m  const group  = document.getElementById('af-group')?.value  || 'date';·\u001b[39m\n\u001b[31m  // Pending-job filter overrides deleted/normal modes\u001b[39m\n\u001b[31m  let rows;\u001b[39m\n\u001b[31m  if (_pendingJobFilter) {\u001b[39m\n\u001b[31m    rows = _adminRows.filter(r => !r.deleted_at && !r.campaign_id);\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows = _showDeletedView\u001b[39m\n\u001b[31m      ? _adminRows.filter(r => r.deleted_at)\u001b[39m\n\u001b[31m      : _adminRows.filter(r => !r.deleted_at);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const client = document.getElementById('af-client')?.value || '';\u001b[39m\n\u001b[31m  if (agent)  rows = rows.filter(r => r.submitted_by === agent);\u001b[39m\n\u001b[31m  if (brand)  rows = rows.filter(r => r.brand === brand);\u001b[39m\n\u001b[31m  if (client) rows = rows.filter(r => r.client_name === client);\u001b[39m\n\u001b[31m  if (search) rows = rows.filter(r => (r.store_name||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.city||'').toLowerCase().includes(search) ||\u001b[39m\n\u001b[31m                                      (r.client_name||'').toLowerCase().includes(search));\u001b[39m\n\u001b[31m  if (period && !_showDeletedView) {\u001b[39m\n\u001b[31m    const cut = new Date(); cut.setDate(cut.getDate() - parseInt(period));\u001b[39m\n\u001b[31m    rows = rows.filter(r => new Date(r.submitted_at) >= cut);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const uniqueAgents = new Set(rows.map(r => r.submitted_by).filter(Boolean)).size;\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = rows.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = uniqueAgents;\u001b[39m\n\u001b[31m  const deletedCount = _adminRows.filter(r => r.deleted_at).length;\u001b[39m\n\u001b[31m  const delBtn = document.getElementById('del-toggle-btn');\u001b[39m\n\u001b[31m  if (delBtn) {\u001b[39m\n\u001b[31m    if (_showDeletedView) {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 Hide Deleted (${deletedCount})` : '📋 Hide Deleted';\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      delBtn.textContent = deletedCount > 0 ? `📋 View Deleted (${deletedCount})` : '📋 View Deleted';\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    delBtn.classList.toggle('active', _showDeletedView);\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!rows.length) {\u001b[39m\n\u001b[31m    list.innerHTML = _showDeletedView\u001b[39m\n\u001b[31m      ? '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">✅</div><div class=\\\"empty-txt\\\">No deleted recces</div></div>'\u001b[39m\n\u001b[31m      : '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">🔍</div><div class=\\\"empty-txt\\\">No matching submissions</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (group === 'agent') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.submitted_by||'').localeCompare(b.submitted_by||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.submitted_by || 'Unknown';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">👤 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'brand') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.brand||'').localeCompare(b.brand||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.brand || 'No Brand';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🏷 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'client') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.client_name||'').localeCompare(b.client_name||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.client_name || 'No Client';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">🤝 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else if (group === 'city') {\u001b[39m\n\u001b[31m    rows.sort((a,b) => (a.city||'').localeCompare(b.city||'') ||\u001b[39m\n\u001b[31m                       new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    let last = null;\u001b[39m\n\u001b[31m    rows.forEach(r => {\u001b[39m\n\u001b[31m      const key = r.city || 'No City';\u001b[39m\n\u001b[31m      if (key !== last) { last = key; html += `<div class=\\\"grp-hdr\\\">📍 ${key}</div>`; }\u001b[39m\n\u001b[31m      html += adminCard(r);\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    rows.sort((a,b) => new Date(b.submitted_at) - new Date(a.submitted_at));\u001b[39m\n\u001b[31m    rows.forEach(r => { html += adminCard(r); });\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction adminCard(r) {\u001b[39m\n\u001b[31m  const dt    = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds    = dt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m  const tm    = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  const photos = (r.front_photos||0) + (r.inside_photos||0) + (r.addl_photos||0);\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const canDelete  = _RECCE_CFG_ADMINS.includes(hub?.empId);\u001b[39m\n\u001b[31m  const canArchive = _RECCE_CFG_ADMINS.includes(hub?.empId) && !r.client_archived;·\u001b[39m\n\u001b[31m  // Client status badge\u001b[39m\n\u001b[31m  const clientStatusMap = {\u001b[39m\n\u001b[31m    approved:              {t:'✓ Approved',    s:'color:#166534;background:#dcfce7;border:1px solid #86efac'},\u001b[39m\n\u001b[31m    rejected:              {t:'✕ Rejected',    s:'color:#991b1b;background:#fee2e2;border:1px solid #fca5a5'},\u001b[39m\n\u001b[31m    approved_with_changes: {t:'✎ Approved w/ Comments', s:'color:#92400e;background:#fef3c7;border:1px solid #fcd34d'},\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  const csCfg = clientStatusMap[r.client_status];\u001b[39m\n\u001b[31m  const clientStatusBadge = csCfg\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;${csCfg.s}\\\">${csCfg.t}</span>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const archiveBadge = r.client_archived\u001b[39m\n\u001b[31m    ? `<span style=\\\"font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;color:#475569;background:#f1f5f9;border:1px solid #cbd5e1\\\">⬚ Client hidden</span>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  if (r.deleted_at) {\u001b[39m\n\u001b[31m    const delDt = new Date(r.deleted_at);\u001b[39m\n\u001b[31m    const delDs = delDt.toLocaleDateString('en-IN', {day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m    const reasonLabel = r.deletion_reason === 'wrong' ? 'Wrong' : r.deletion_reason === 'duplicate' ? 'Duplicate' : 'Test';\u001b[39m\n\u001b[31m    return `<div class=\\\"asc deleted-row\\\">\u001b[39m\n\u001b[31m      <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m        <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m          <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m          <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m            <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds}</span>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m          <span class=\\\"del-reason-tag\\\">❌ ${reasonLabel}</span>\u001b[39m\n\u001b[31m          <div class=\\\"del-by-txt\\\">by ${r.deleted_by||'?'} · ${delDs}</div>\u001b[39m\n\u001b[31m          ${canDelete ? `<button class=\\\"restore-btn\\\" onclick=\\\"event.stopPropagation();restoreRecce('${r.sub_id}')\\\">↩ Restore</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"font-size:11px;color:var(--g400);margin-top:2px\\\">Submitted by ${r.submitted_by||'?'}</div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const chips = [\u001b[39m\n\u001b[31m    photos > 0   ? `📷 ${photos} photo${photos!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.has_video  ? '🎥 Video' : null,\u001b[39m\n\u001b[31m    r.has_branding ? `🪧 ${r.branding_count} branding${r.branding_count!==1?'s':''}` : null,\u001b[39m\n\u001b[31m    r.city       ? `📍 ${r.city}` : (r.address ? `📍 ${r.address}` : null),\u001b[39m\n\u001b[31m    r.view_url   ? '👁 View available' : null,\u001b[39m\n\u001b[31m  ].filter(Boolean);·\u001b[39m\n\u001b[31m  const delBtnHtml = canDelete\u001b[39m\n\u001b[31m    ? `<button class=\\\"del-btn\\\" onclick=\\\"event.stopPropagation();openDeleteModal('${r.sub_id}')\\\" title=\\\"Delete recce\\\">🗑</button>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const editReqHtml = r.edit_assigned_to\u001b[39m\n\u001b[31m    ? `<span class=\\\"edit-req-badge\\\">✏ Edit sent to ${r.edit_assigned_to}</span>`\u001b[39m\n\u001b[31m    : (_isSupervisor()\u001b[39m\n\u001b[31m        ? `<button class=\\\"req-edit-btn\\\" onclick=\\\"event.stopPropagation();openEditRequestModal('${r.sub_id}')\\\">✏ Request Edit</button>`\u001b[39m\n\u001b[31m        : '');·\u001b[39m\n\u001b[31m  const editRow = editReqHtml\u001b[39m\n\u001b[31m    ? `<div style=\\\"margin-top:6px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">${editReqHtml}</div>`\u001b[39m\n\u001b[31m    : '';·\u001b[39m\n\u001b[31m  const showPdfBtn = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m  const pdfClass = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m  const pdfLabel = '📄 PDF';\u001b[39m\n\u001b[31m  const linkJobBtn = (_pendingJobFilter && _isSupervisor() && !r.campaign_id)\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:#f59e0b;color:#000;border-color:#f59e0b;font-weight:700\\\" onclick=\\\"event.stopPropagation();openLinkJobModal('${r.sub_id}','${(r.store_name||'Unknown').replace(/'/g,'\\\\\\\\\\\\'')}')\\\">🔗 Link Job</button>`\u001b[39m\n\u001b[31m    : (r.campaign_id ? `<span style=\\\"font-size:10px;color:var(--g400);align-self:center\\\">🔗 ${r.campaign_id}</span>` : '');\u001b[39m\n\u001b[31m  const archiveBtn = canArchive\u001b[39m\n\u001b[31m    ? `<button class=\\\"rpt-btn\\\" style=\\\"background:rgba(99,102,241,.08);border-color:var(--nv);color:var(--nv)\\\" onclick=\\\"event.stopPropagation();archiveRecce('${r.sub_id}')\\\">⛚ Archive</button>`\u001b[39m\n\u001b[31m    : '';\u001b[39m\n\u001b[31m  const btnsRow = `<div class=\\\"rpt-btns\\\">\u001b[39m\n\u001b[31m    <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openAdminRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m    ${showPdfBtn ? `<button class=\\\"${pdfClass}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">${pdfLabel}</button>` : ''}\u001b[39m\n\u001b[31m    ${linkJobBtn}\u001b[39m\n\u001b[31m    ${archiveBtn}\u001b[39m\n\u001b[31m  </div>`;·\u001b[39m\n\u001b[31m  return `<div class=\\\"asc\\\">\u001b[39m\n\u001b[31m    <div class=\\\"asc-top\\\">\u001b[39m\n\u001b[31m      <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"asc-name\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:4px;display:flex;gap:6px;flex-wrap:wrap;align-items:center\\\">\u001b[39m\n\u001b[31m          ${r.brand?`<span class=\\\"asc-brand\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          ${r.client_name&&r.client_name!==r.brand?`<span class=\\\"client-tag\\\">🤝 ${r.client_name}</span>`:''}\u001b[39m\n\u001b[31m          <span style=\\\"font-size:11px;color:var(--g400)\\\">${ds} · ${tm}</span>\u001b[39m\n\u001b[31m          ${clientStatusBadge}\u001b[39m\n\u001b[31m          ${archiveBadge}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:4px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <span class=\\\"asc-agent\\\">👤 ${r.submitted_by||'?'}</span>\u001b[39m\n\u001b[31m        ${delBtnHtml}\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    ${chips.length?`<div class=\\\"asc-chips\\\">${chips.map(c=>`<span class=\\\"asc-chip\\\">${c}</span>`).join('')}</div>`:''}\u001b[39m\n\u001b[31m    ${editRow}\u001b[39m\n\u001b[31m    ${btnsRow}\u001b[39m\n\u001b[31m  </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction _ensurePdfOverlay() {\u001b[39m\n\u001b[31m  if (document.getElementById('pdf-wait-ov')) return;\u001b[39m\n\u001b[31m  const ov = document.createElement('div');\u001b[39m\n\u001b[31m  ov.id = 'pdf-wait-ov';\u001b[39m\n\u001b[31m  ov.innerHTML = '<div class=\\\"po-printer\\\"><div class=\\\"po-tray\\\"></div><div class=\\\"po-body\\\"><div class=\\\"po-slot\\\"></div><div class=\\\"po-led\\\"></div></div><div class=\\\"po-paper\\\"><div class=\\\"po-line po-line-1\\\"></div><div class=\\\"po-line po-line-2\\\"></div><div class=\\\"po-line po-line-3\\\"></div></div></div><div class=\\\"po-txt\\\">Generating PDF…</div><div class=\\\"po-sub\\\" id=\\\"pw-sub\\\"></div><div class=\\\"po-bar\\\"><div class=\\\"po-pfill\\\" id=\\\"pw-pfill\\\"></div></div>';\u001b[39m\n\u001b[31m  document.body.appendChild(ov);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _showPdfOverlay(msg) {\u001b[39m\n\u001b[31m  _ensurePdfOverlay();\u001b[39m\n\u001b[31m  document.getElementById('pw-sub').textContent = msg || '';\u001b[39m\n\u001b[31m  document.getElementById('pw-pfill').style.width = '0%';\u001b[39m\n\u001b[31m  document.getElementById('pdf-wait-ov').style.display = 'flex';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction _hidePdfOverlay() {\u001b[39m\n\u001b[31m  const ov = document.getElementById('pdf-wait-ov');\u001b[39m\n\u001b[31m  if (ov) ov.style.display = 'none';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function openPdf(subId, pdfUrl, viewUrl) {\u001b[39m\n\u001b[31m  if (pdfUrl) { window.open(pdfUrl, '_blank'); return; }\u001b[39m\n\u001b[31m  if (!viewUrl) {\u001b[39m\n\u001b[31m    toast('Report view not available yet — please try after the report is generated.', 'info');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _showPdfOverlay('Requesting PDF generation…');\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    await fetch('/slides-proxy/', {\u001b[39m\n\u001b[31m      method: 'POST',\u001b[39m\n\u001b[31m      headers: {'Content-Type': 'application/json'},\u001b[39m\n\u001b[31m      body: JSON.stringify({type: 'regen-pdf', subId, viewUrl})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m  } catch(_) {}\u001b[39m\n\u001b[31m  let attempts = 0;\u001b[39m\n\u001b[31m  const MAX = 24;\u001b[39m\n\u001b[31m  const poll = async () => {\u001b[39m\n\u001b[31m    attempts++;\u001b[39m\n\u001b[31m    const pct = Math.min(88, Math.round(attempts / MAX * 88));\u001b[39m\n\u001b[31m    document.getElementById('pw-pfill').style.width = pct + '%';\u001b[39m\n\u001b[31m    const left = Math.ceil((MAX - attempts) * 5);\u001b[39m\n\u001b[31m    document.getElementById('pw-sub').textContent = 'Checking… (' + left + 's remaining)';\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const res = await fetch('/db/submissions?sub_id=eq.' + subId + '&select=pdf_url', {\u001b[39m\n\u001b[31m        headers: {'Content-Profile': 'recce', 'Accept-Profile': 'recce'}\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      const rows = await res.json();\u001b[39m\n\u001b[31m      if (rows && rows[0] && rows[0].pdf_url) {\u001b[39m\n\u001b[31m        document.getElementById('pw-pfill').style.width = '100%';\u001b[39m\n\u001b[31m        setTimeout(() => { _hidePdfOverlay(); window.open(rows[0].pdf_url, '_blank'); }, 400);\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(_) {}\u001b[39m\n\u001b[31m    if (attempts >= MAX) { _hidePdfOverlay(); toast('PDF generation timed out. Please try again later.', 'error'); return; }\u001b[39m\n\u001b[31m    setTimeout(poll, 5000);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  setTimeout(poll, 4000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openAdminRecce(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN', {day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN', {hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];·\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">\u001b[39m\n\u001b[31m         📍 View on Google Maps (${Number(r.gps_lat).toFixed(4)}, ${Number(r.gps_lng).toFixed(4)})\u001b[39m\n\u001b[31m       </a>` : '';·\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} ft × ${b.h||'?'} ft · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos not yet available — field agent must re-sync from their device to upload view\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Submission Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">👤 ${r.submitted_by||'Unknown'}</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m            ${meta.videoCmt?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500);font-size:12px\\\">${meta.videoCmt}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m          ${(()=>{\u001b[39m\n\u001b[31m            const hub2 = _recceHubUser();\u001b[39m\n\u001b[31m            const isHP = _RECCE_CFG_ADMINS.includes(hub2?.empId);\u001b[39m\n\u001b[31m            const csMap = {\u001b[39m\n\u001b[31m              approved:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#166534;background:#dcfce7\\\">✓ Approved</span>',\u001b[39m\n\u001b[31m              rejected:              '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#991b1b;background:#fee2e2\\\">✕ Rejected</span>',\u001b[39m\n\u001b[31m              approved_with_changes: '<span style=\\\"font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;color:#92400e;background:#fef3c7\\\">✎ Approved w/ Comments</span>',\u001b[39m\n\u001b[31m            };\u001b[39m\n\u001b[31m            const csBadge = csMap[r.client_status] || '';\u001b[39m\n\u001b[31m            const approvedAt = r.client_approved_at\u001b[39m\n\u001b[31m              ? new Date(r.client_approved_at).toLocaleString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit',timeZone:'Asia/Kolkata'})\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const pdfLink = r.client_approval_pdf_url\u001b[39m\n\u001b[31m              ? `<a href=\\\"${r.client_approval_pdf_url}\\\" target=\\\"_blank\\\" style=\\\"font-size:12px;color:var(--or);text-decoration:none\\\">⬇ Approval PDF</a>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            const archAct = isHP && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveRecce('${r.sub_id}')\\\" style=\\\"font-size:12px;color:var(--nv);background:none;border:1px solid var(--nv);border-radius:6px;padding:4px 10px;cursor:pointer\\\">⦽ Archive from client</button>`\u001b[39m\n\u001b[31m              : (r.client_archived ? '<span style=\\\"font-size:11px;color:var(--g400)\\\">⦽ Hidden from client</span>' : '');\u001b[39m\n\u001b[31m            const campAct = isHP && r.campaign_id && !r.client_archived\u001b[39m\n\u001b[31m              ? `<button onclick=\\\"closeAdminDetail();archiveAllForCampaign('${r.campaign_id}')\\\" style=\\\"font-size:11px;color:#991b1b;background:none;border:1px solid #fca5a5;border-radius:6px;padding:3px 8px;cursor:pointer\\\">Archive ALL for ${r.campaign_id}</button>`\u001b[39m\n\u001b[31m              : '';\u001b[39m\n\u001b[31m            if (!csBadge && !pdfLink && !archAct) return '';\u001b[39m\n\u001b[31m            return `<div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m              <div class=\\\"ardl-lbl\\\">Client Approval</div>\u001b[39m\n\u001b[31m              ${csBadge ? `<div style=\\\"margin-bottom:5px\\\">${csBadge}${approvedAt ? ' <span style=\\\"font-size:11px;color:var(--g400)\\\">' + approvedAt + '</span>' : ''}</div>` : ''}\u001b[39m\n\u001b[31m              ${r.client_comment ? `<div style=\\\"font-size:12px;color:var(--g600);background:var(--g50);border-radius:6px;padding:7px 10px;margin-bottom:5px\\\">\\\"${r.client_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m              ${pdfLink ? `<div style=\\\"margin-bottom:4px\\\">${pdfLink}</div>` : ''}\u001b[39m\n\u001b[31m              ${archAct ? `<div style=\\\"margin-bottom:4px\\\">${archAct}</div>` : ''}\u001b[39m\n\u001b[31m              ${campAct ? `<div>${campAct}</div>` : ''}\u001b[39m\n\u001b[31m            </div>`;\u001b[39m\n\u001b[31m          })()}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeAdminDetail() {\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveRecce(subId) {\u001b[39m\n\u001b[31m  if (!confirm('Archive this recce from client view? The client will no longer see it.')) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${encodeURIComponent(subId)}`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) Object.assign(_adminRows[idx], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    toast('Archived from client view ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function archiveAllForCampaign(campaignId) {\u001b[39m\n\u001b[31m  if (!confirm(`Archive ALL recces for campaign \\\"${campaignId}\\\" from client view?\\\\nClients will no longer see any recce from this campaign.`)) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?campaign_id=eq.${encodeURIComponent(campaignId)}&client_archived=eq.false`, {\u001b[39m\n\u001b[31m      method: 'PATCH', headers: { ..._RC_WRITE, 'Prefer': 'return=minimal' },\u001b[39m\n\u001b[31m      body: JSON.stringify({ client_archived: true, client_archived_at: new Date().toISOString(), client_archived_by: hub?.empId||'' }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('PATCH failed');\u001b[39m\n\u001b[31m    _adminRows.forEach((row, i) => {\u001b[39m\n\u001b[31m      if (row.campaign_id === campaignId) Object.assign(_adminRows[i], { client_archived: true, client_archived_by: hub?.empId||'' });\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    toast(`All recces for ${campaignId} archived ✓`, 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(_) { toast('Archive failed', 'error'); }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function regenAllReports() {\u001b[39m\n\u001b[31m  if (!_adminUnlocked) { toast('Admin access required', 'error'); return; }\u001b[39m\n\u001b[31m  const rows = _adminRows.filter(r => !r.deleted_at && r.photo_urls);\u001b[39m\n\u001b[31m  if (!rows.length) { toast('No synced rows with photos found', 'error'); return; }·\u001b[39m\n\u001b[31m  const btn = document.getElementById('regen-rpt-btn');\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = true; btn.textContent = 'Regenerating…'; }\u001b[39m\n\u001b[31m  toast(`Regenerating ${rows.length} reports…`, 'info');·\u001b[39m\n\u001b[31m  let done = 0, failed = 0;\u001b[39m\n\u001b[31m  for (const r of rows) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const photoUrls = typeof r.photo_urls === 'string' ? JSON.parse(r.photo_urls) : (r.photo_urls || {});\u001b[39m\n\u001b[31m      let meta = {};\u001b[39m\n\u001b[31m      try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m      const entry = {\u001b[39m\n\u001b[31m        id: r.sub_id,\u001b[39m\n\u001b[31m        timestamp: r.submitted_at,\u001b[39m\n\u001b[31m        submittedBy: r.submitted_by,\u001b[39m\n\u001b[31m        data: {\u001b[39m\n\u001b[31m          storeName:    r.store_name,\u001b[39m\n\u001b[31m          brand:        r.brand,\u001b[39m\n\u001b[31m          clientName:   r.client_name,\u001b[39m\n\u001b[31m          date:         r.visit_date,\u001b[39m\n\u001b[31m          address:      r.address,\u001b[39m\n\u001b[31m          city:         r.city,\u001b[39m\n\u001b[31m          mobile:       r.mobile,\u001b[39m\n\u001b[31m          gpsCoords:    (r.gps_lat && r.gps_lng) ? { lat: r.gps_lat, lng: r.gps_lng } : null,\u001b[39m\n\u001b[31m          hasVideo:     r.has_video,\u001b[39m\n\u001b[31m          videoNote:    meta.videoNote || '',\u001b[39m\n\u001b[31m          videoCmt:     meta.videoCmt  || '',\u001b[39m\n\u001b[31m          frontPhotos:  (photoUrls.front   || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          insidePhotos: (photoUrls.inside  || []).map(() => ({ cmt: '' })),\u001b[39m\n\u001b[31m          addlPhotos:   (photoUrls.addl    || []).map(() => ({ desc: '' })),\u001b[39m\n\u001b[31m          brandings:    (meta.brandings    || []),\u001b[39m\n\u001b[31m        }\u001b[39m\n\u001b[31m      };·\u001b[39m\n\u001b[31m      const html = generateRecceReportHtml(entry, photoUrls);\u001b[39m\n\u001b[31m      const vResp = await fetch('/slides-proxy', {\u001b[39m\n\u001b[31m        method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m        body: JSON.stringify({ type: 'save-view', subId: r.sub_id, html })\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!vResp.ok) { failed++; continue; }\u001b[39m\n\u001b[31m      const vr = await vResp.json();\u001b[39m\n\u001b[31m      if (!vr.success) { failed++; continue; }·\u001b[39m\n\u001b[31m      if (vr.url && vr.url !== r.view_url) {\u001b[39m\n\u001b[31m        await fetch(`${_RC_BASE}/submissions?sub_id=eq.${r.sub_id}`, {\u001b[39m\n\u001b[31m          method: 'PATCH', headers: _RC_WRITE,\u001b[39m\n\u001b[31m          body: JSON.stringify({ view_url: vr.url })\u001b[39m\n\u001b[31m        });\u001b[39m\n\u001b[31m        const idx = _adminRows.findIndex(x => x.sub_id === r.sub_id);\u001b[39m\n\u001b[31m        if (idx >= 0) _adminRows[idx].view_url = vr.url;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      done++;\u001b[39m\n\u001b[31m    } catch(e) { failed++; }\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  if (btn) { btn.disabled = false; btn.textContent = '↻ Regen Reports'; }\u001b[39m\n\u001b[31m  toast(`Done: ${done} regenerated${failed ? `, ${failed} failed` : ''}`, done > 0 ? 'success' : 'error');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction toggleDeletedView() {\u001b[39m\n\u001b[31m  _showDeletedView = !_showDeletedView;\u001b[39m\n\u001b[31m  renderAdminList();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openDeleteModal(subId) {\u001b[39m\n\u001b[31m  _pendingDeleteId = subId;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  const sub = document.getElementById('del-modal-sub');\u001b[39m\n\u001b[31m  if (sub) sub.textContent = r ? `Delete: \\\"${r.store_name||'Unknown'}\\\"` : 'Select reason for deletion:';\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction selectDeleteReason(reason) {\u001b[39m\n\u001b[31m  _pendingDeleteReason = reason;\u001b[39m\n\u001b[31m  document.querySelectorAll('.reason-opt').forEach(el => el.classList.remove('sel'));\u001b[39m\n\u001b[31m  document.getElementById('reason-' + reason)?.classList.add('sel');\u001b[39m\n\u001b[31m  document.getElementById('del-confirm-btn').classList.remove('no-reason');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeDeleteModal() {\u001b[39m\n\u001b[31m  document.getElementById('delete-reason-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _pendingDeleteId = null;\u001b[39m\n\u001b[31m  _pendingDeleteReason = null;\u001b[39m\n\u001b[31m  clearTimeout(_tt);\u001b[39m\n\u001b[31m  document.getElementById('toast').classList.remove('show');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function restoreRecce(subId) {\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({ deleted_at: null, deleted_by: null, deletion_reason: null }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!r.ok) throw new Error('Restore failed: ' + r.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_at = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deleted_by = null;\u001b[39m\n\u001b[31m      _adminRows[idx].deletion_reason = null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    toast('Recce restored ✓', 'success');\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Restore failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmDelete() {\u001b[39m\n\u001b[31m  if (!_pendingDeleteReason) {\u001b[39m\n\u001b[31m    const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m    btn.style.animation = 'none';\u001b[39m\n\u001b[31m    btn.offsetHeight; // reflow\u001b[39m\n\u001b[31m    btn.style.animation = 'shake .35s ease';\u001b[39m\n\u001b[31m    toast('Select a reason first', 'error');\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if (!_pendingDeleteId) return;\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (!_RECCE_CFG_ADMINS.includes(hub?.empId)) { toast('Not authorised', 'error'); return; }\u001b[39m\n\u001b[31m  const btn = document.getElementById('del-confirm-btn');\u001b[39m\n\u001b[31m  btn.classList.add('no-reason');\u001b[39m\n\u001b[31m  btn.textContent = 'Deleting…';\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      // Hard delete — no audit trail\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'DELETE',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Delete failed: ' + r.status);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Soft delete — stamp deleted_at, deleted_by, deletion_reason\u001b[39m\n\u001b[31m      const r = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${_pendingDeleteId}`, {\u001b[39m\n\u001b[31m        method: 'PATCH',\u001b[39m\n\u001b[31m        headers: _RC_WRITE,\u001b[39m\n\u001b[31m        body: JSON.stringify({\u001b[39m\n\u001b[31m          deleted_at: new Date().toISOString(),\u001b[39m\n\u001b[31m          deleted_by: hub.empId,\u001b[39m\n\u001b[31m          deletion_reason: _pendingDeleteReason,\u001b[39m\n\u001b[31m        }),\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      if (!r.ok) throw new Error('Update failed: ' + r.status);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Remove or update in local cache\u001b[39m\n\u001b[31m    if (_pendingDeleteReason === 'test') {\u001b[39m\n\u001b[31m      _adminRows = _adminRows.filter(x => x.sub_id !== _pendingDeleteId);\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      const idx = _adminRows.findIndex(x => x.sub_id === _pendingDeleteId);\u001b[39m\n\u001b[31m      if (idx >= 0) {\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_at = new Date().toISOString();\u001b[39m\n\u001b[31m        _adminRows[idx].deleted_by = hub.empId;\u001b[39m\n\u001b[31m        _adminRows[idx].deletion_reason = _pendingDeleteReason;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeDeleteModal();\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast('Recce deleted', 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Delete failed', 'error');\u001b[39m\n\u001b[31m    btn.classList.remove('no-reason');\u001b[39m\n\u001b[31m    btn.textContent = 'Delete';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openMyServerRecce(subId) {\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  if (r.view_url) { window.open(r.view_url, '_blank'); return; }\u001b[39m\n\u001b[31m  // No view yet — show metadata modal (same layout as admin detail)\u001b[39m\n\u001b[31m  const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m  const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'long',year:'numeric'});\u001b[39m\n\u001b[31m  const tm = dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta==='string' ? JSON.parse(r.meta) : (r.meta||{}); } catch(_) {}\u001b[39m\n\u001b[31m  const brandings = meta.brandings || [];\u001b[39m\n\u001b[31m  const gpsHtml = (r.gps_lat && r.gps_lng)\u001b[39m\n\u001b[31m    ? `<a href=\\\"https://maps.google.com/?q=${r.gps_lat},${r.gps_lng}\\\" target=\\\"_blank\\\"\u001b[39m\n\u001b[31m         style=\\\"color:var(--or);font-size:12px;text-decoration:none\\\">📍 View on Google Maps</a>` : '';\u001b[39m\n\u001b[31m  const brandingRows = brandings.map(b =>\u001b[39m\n\u001b[31m    `<div class=\\\"ardl-row\\\">\u001b[39m\n\u001b[31m      <span class=\\\"asc-chip\\\">${b.type||'Unknown'}</span>\u001b[39m\n\u001b[31m      <span class=\\\"ardl-val\\\">${b.w||'?'} × ${b.h||'?'} in · qty ${b.qty||1} · ${b.sqft||'?'} sqft</span>\u001b[39m\n\u001b[31m    </div>`).join('');\u001b[39m\n\u001b[31m  document.getElementById('ardl-overlay')?.remove();\u001b[39m\n\u001b[31m  document.body.insertAdjacentHTML('beforeend', `\u001b[39m\n\u001b[31m    <div class=\\\"ardl-overlay\\\" id=\\\"ardl-overlay\\\" onclick=\\\"if(event.target===this)closeAdminDetail()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"ardl-box\\\">\u001b[39m\n\u001b[31m        <div class=\\\"ardl-hdr\\\">\u001b[39m\n\u001b[31m          <div style=\\\"min-width:0\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-title\\\">${r.store_name||'Unknown'}</div>\u001b[39m\n\u001b[31m            ${r.brand?`<span class=\\\"asc-brand\\\" style=\\\"margin-top:6px;display:inline-block\\\">${r.brand}</span>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <button onclick=\\\"closeAdminDetail()\\\" style=\\\"background:none;border:none;font-size:26px;color:var(--g400);cursor:pointer;line-height:1;flex-shrink:0\\\">×</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m        <div class=\\\"ardl-body\\\">\u001b[39m\n\u001b[31m          <div style=\\\"background:#fff7ed;border-radius:8px;padding:10px 12px;margin-bottom:10px;font-size:12px;color:#92400e\\\">\u001b[39m\n\u001b[31m            📸 Photos will appear after next sync from original device\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Visit Info</div>\u001b[39m\n\u001b[31m            <div class=\\\"ardl-val\\\">📅 ${ds} · ${tm}</div>\u001b[39m\n\u001b[31m            ${r.city?`<div class=\\\"ardl-val\\\">🏙 ${r.city}</div>`:''}\u001b[39m\n\u001b[31m            ${r.address?`<div class=\\\"ardl-val\\\" style=\\\"color:var(--g500)\\\">${r.address}</div>`:''}\u001b[39m\n\u001b[31m            ${r.mobile?`<div class=\\\"ardl-val\\\">📞 ${r.mobile}</div>`:''}\u001b[39m\n\u001b[31m            ${gpsHtml?`<div class=\\\"ardl-val\\\">${gpsHtml}</div>`:''}\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Media</div>\u001b[39m\n\u001b[31m            <div class=\\\"asc-chips\\\">\u001b[39m\n\u001b[31m              ${r.front_photos?`<span class=\\\"asc-chip\\\">📷 ${r.front_photos} front</span>`:''}\u001b[39m\n\u001b[31m              ${r.inside_photos?`<span class=\\\"asc-chip\\\">📷 ${r.inside_photos} inside</span>`:''}\u001b[39m\n\u001b[31m              ${r.addl_photos?`<span class=\\\"asc-chip\\\">📷 ${r.addl_photos} additional</span>`:''}\u001b[39m\n\u001b[31m              <span class=\\\"asc-chip\\\">${r.has_video?'🎥 Video':'No video'}</span>\u001b[39m\n\u001b[31m            </div>\u001b[39m\n\u001b[31m          </div>\u001b[39m\n\u001b[31m          ${brandings.length?`\u001b[39m\n\u001b[31m          <div class=\\\"ardl-sec\\\">\u001b[39m\n\u001b[31m            <div class=\\\"ardl-lbl\\\">Branding Items (${brandings.length})</div>\u001b[39m\n\u001b[31m            ${brandingRows}\u001b[39m\n\u001b[31m          </div>`:''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderSupLanding() {\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = 'none';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = 'none';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = 'none';\u001b[39m\n\u001b[31m  // Clean up admin + create-mode UI\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar');\u001b[39m\n\u001b[31m  if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  document.getElementById('sup-back-btn')?.remove();\u001b[39m\n\u001b[31m  document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m  _supCreateMode = false;\u001b[39m\n\u001b[31m  // Resume-wrap may have been hidden by loadHomeAdmin() — restore it so draft banner shows\u001b[39m\n\u001b[31m  document.getElementById('resume-wrap').style.display = '';\u001b[39m\n\u001b[31m  document.getElementById('sub-list').innerHTML = `\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorViewAll()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0f9ff\\\">📋</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">View All Recces</span><span class=\\\"hi-txt\\\">सभी रेकी देखें</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">Browse & review submissions from all agents</span><span class=\\\"hi-txt\\\">सभी एजेंट की सबमिशन देखें</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>\u001b[39m\n\u001b[31m    <div class=\\\"sup-tile\\\" onclick=\\\"supervisorCreateView()\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-ico\\\" style=\\\"background:#f0fdf4\\\">✍️</div>\u001b[39m\n\u001b[31m      <div class=\\\"sup-tile-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-title\\\"><span class=\\\"en-txt\\\">Create Recce</span><span class=\\\"hi-txt\\\">नई रेकी बनाएं</span></div>\u001b[39m\n\u001b[31m        <div class=\\\"sup-tile-sub\\\"><span class=\\\"en-txt\\\">My submissions + New Recce button</span><span class=\\\"hi-txt\\\">मेरी सबमिशन + नई रेकी</span></div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <svg width=\\\"18\\\" height=\\\"18\\\" fill=\\\"none\\\" stroke=\\\"#94a3b8\\\" stroke-width=\\\"2\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"9 18 15 12 9 6\\\"/></svg>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorViewAll() {\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh');\u001b[39m\n\u001b[31m  if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  await loadHomeAdmin();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorCreateView() {\u001b[39m\n\u001b[31m  _supCreateMode = true;\u001b[39m\n\u001b[31m  // Restore field-agent UI\u001b[39m\n\u001b[31m  document.querySelector('.new-btn').style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.stats').style.display = '';\u001b[39m\n\u001b[31m  const sh = document.querySelector('.sh'); if (sh) sh.style.display = '';\u001b[39m\n\u001b[31m  document.querySelector('.st').textContent = t('My Submissions','मेरी सबमिशन');\u001b[39m\n\u001b[31m  const fb = document.getElementById('admin-filter-bar'); if (fb) fb.style.display = 'none';\u001b[39m\n\u001b[31m  // Add Back to Menu button (once)\u001b[39m\n\u001b[31m  if (!document.getElementById('sup-back-create-btn')) {\u001b[39m\n\u001b[31m    const bb = document.createElement('button');\u001b[39m\n\u001b[31m    bb.id = 'sup-back-create-btn';\u001b[39m\n\u001b[31m    bb.className = 'btn-o';\u001b[39m\n\u001b[31m    bb.style.cssText = 'display:flex;align-items:center;gap:5px;padding:8px 14px;font-size:13px;margin-bottom:10px';\u001b[39m\n\u001b[31m    bb.innerHTML = '<svg width=\\\"16\\\" height=\\\"16\\\" fill=\\\"none\\\" stroke=\\\"currentColor\\\" stroke-width=\\\"2.5\\\" viewBox=\\\"0 0 24 24\\\"><polyline points=\\\"15 18 9 12 15 6\\\"/></svg><span class=\\\"en-txt\\\">Back to Menu</span><span class=\\\"hi-txt\\\">मेनू पर वापस</span>';\u001b[39m\n\u001b[31m    bb.onclick = () => {\u001b[39m\n\u001b[31m      _supCreateMode = false;\u001b[39m\n\u001b[31m      document.getElementById('sup-back-create-btn')?.remove();\u001b[39m\n\u001b[31m      renderSupLanding();\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    document.querySelector('#view-home .content').prepend(bb);\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  await loadHome();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadHome() {\u001b[39m\n\u001b[31m  if (_isSupervisor() && !_supCreateMode) { renderSupLanding(); return; }\u001b[39m\n\u001b[31m  if (_adminUnlocked && !_supCreateMode) { await loadHomeAdmin(); return; }·\u001b[39m\n\u001b[31m  const all  = await dbAll('subs');\u001b[39m\n\u001b[31m  const sy   = all.filter(s => s.status === 'synced').length;\u001b[39m\n\u001b[31m  const pe   = all.filter(s => s.status !== 'synced').length;·\u001b[39m\n\u001b[31m  // Fetch this agent's submissions from server — works on any device\u001b[39m\n\u001b[31m  let serverOnly = [];\u001b[39m\n\u001b[31m  let editAssigned = [];\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  if (navigator.onLine && hub?.empId) {\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?submitted_by=eq.${encodeURIComponent(hub.empId)}&order=submitted_at.desc&limit=200`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp.ok) {\u001b[39m\n\u001b[31m        const rows = await resp.json();\u001b[39m\n\u001b[31m        const localIds = new Set(all.map(s => s.id));\u001b[39m\n\u001b[31m        serverOnly = rows.filter(r => !localIds.has(r.sub_id));\u001b[39m\n\u001b[31m        _myServerRows = serverOnly;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m    // Fetch edit-assigned recces (supervisor assigned this creator to edit)\u001b[39m\n\u001b[31m    try {\u001b[39m\n\u001b[31m      const resp2 = await fetch(\u001b[39m\n\u001b[31m        `${_RC_BASE}/submissions?edit_assigned_to=eq.${encodeURIComponent(hub.empId)}&deleted_at=is.null&order=submitted_at.desc`,\u001b[39m\n\u001b[31m        { headers: _RC_READ }\u001b[39m\n\u001b[31m      );\u001b[39m\n\u001b[31m      if (resp2.ok) editAssigned = await resp2.json();\u001b[39m\n\u001b[31m    } catch(e) {}\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  document.getElementById('stat-synced').textContent = sy + serverOnly.length;\u001b[39m\n\u001b[31m  document.getElementById('stat-pending').textContent = pe;\u001b[39m\n\u001b[31m  document.getElementById('stat-total').textContent   = all.length + serverOnly.length;·\u001b[39m\n\u001b[31m  const list = document.getElementById('sub-list');\u001b[39m\n\u001b[31m  if (!all.length && !serverOnly.length && !editAssigned.length) {\u001b[39m\n\u001b[31m    list.innerHTML = '<div class=\\\"empty\\\"><div class=\\\"empty-ico\\\">📋</div><div class=\\\"empty-txt\\\">No submissions yet</div></div>';\u001b[39m\n\u001b[31m    return;\u001b[39m\n\u001b[31m  }·\u001b[39m\n\u001b[31m  const icos   = { synced:'✅', pending:'⏳', failed:'❌' };\u001b[39m\n\u001b[31m  const sorted = [...all].sort((a,b) => new Date(b.timestamp) - new Date(a.timestamp)).slice(0, 50);·\u001b[39m\n\u001b[31m  const localCards = sorted.map(s => {\u001b[39m\n\u001b[31m    const dt = new Date(s.timestamp);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const viewBtn = s.viewUrl\u001b[39m\n\u001b[31m      ? `<button class=\\\"edit-btn-sm\\\" onclick=\\\"window.open('${s.viewUrl}','_blank')\\\">👁 View</button>`\u001b[39m\n\u001b[31m      : `<button class=\\\"edit-btn-sm\\\" onclick=\\\"viewRecce('${s.id}')\\\">👁 View</button>`;\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico ${s.status}\\\">${icos[s.status]||'📋'}</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${s.data.storeName||'Unknown'} · ${s.data.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${s.data.address||''}</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge ${s.status}\\\">${s.status}</div>\u001b[39m\n\u001b[31m        <div style=\\\"display:flex;gap:5px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          ${viewBtn}\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"editRecce('${s.id}')\\\" style=\\\"background:#fff7ed;border-color:var(--or);color:var(--or)\\\">✏ Edit</button>\u001b[39m\n\u001b[31m          <button class=\\\"edit-btn-sm\\\" onclick=\\\"makeSlides('${s.id}')\\\" style=\\\"background:#eff6ff;border-color:#3b82f6;color:#1d4ed8\\\">📊 Slides</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const serverCards = serverOnly.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    const showPdf = r.view_url || r.pdf_url;\u001b[39m\n\u001b[31m    const pdfCls = 'rpt-btn rpt-btn-pdf' + (r.pdf_url ? ' ready' : '');\u001b[39m\n\u001b[31m    return `<div class=\\\"sub-card\\\">\u001b[39m\n\u001b[31m      <div class=\\\"sub-ico synced\\\">✅</div>\u001b[39m\n\u001b[31m      <div class=\\\"sub-meta\\\" style=\\\"min-width:0;flex:1\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sub-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"sub-dtl\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"rpt-btns\\\" style=\\\"margin-top:8px\\\">\u001b[39m\n\u001b[31m          <button class=\\\"rpt-btn rpt-btn-report\\\" onclick=\\\"openMyServerRecce('${r.sub_id}')\\\">📋 Recce Report</button>\u001b[39m\n\u001b[31m          ${showPdf ? `<button class=\\\"${pdfCls}\\\" onclick=\\\"openPdf('${r.sub_id}','${r.pdf_url||''}','${r.view_url||''}')\\\">📄 PDF</button>` : ''}\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m      <div style=\\\"flex-shrink:0\\\">\u001b[39m\n\u001b[31m        <div class=\\\"sbadge synced\\\">synced</div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  const editAssignedCards = editAssigned.map(r => {\u001b[39m\n\u001b[31m    const dt = new Date(r.submitted_at);\u001b[39m\n\u001b[31m    const ds = dt.toLocaleDateString('en-IN',{day:'numeric',month:'short'}) + ' ' +\u001b[39m\n\u001b[31m               dt.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m    return `<div class=\\\"edit-req-card\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-size:26px;flex-shrink:0\\\">✏</div>\u001b[39m\n\u001b[31m      <div class=\\\"edit-req-card-body\\\">\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-name\\\">${r.store_name||'Unknown'} · ${r.brand||''}</div>\u001b[39m\n\u001b[31m        <div class=\\\"edit-req-card-meta\\\">${ds} · ${r.address||''}</div>\u001b[39m\n\u001b[31m        ${r.edit_comment ? `<div class=\\\"edit-req-cmt\\\">\\\"${r.edit_comment}\\\"</div>` : ''}\u001b[39m\n\u001b[31m        <div style=\\\"margin-top:10px;display:flex;gap:8px;flex-wrap:wrap\\\">\u001b[39m\n\u001b[31m          <button class=\\\"btn-p\\\" onclick=\\\"startCreatorEdit('${r.sub_id}')\\\" style=\\\"padding:9px 16px;font-size:13px;font-weight:600\\\">✏ Edit this Recce</button>\u001b[39m\n\u001b[31m        </div>\u001b[39m\n\u001b[31m      </div>\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  });·\u001b[39m\n\u001b[31m  let html = '';\u001b[39m\n\u001b[31m  if (editAssignedCards.length) {\u001b[39m\n\u001b[31m    html += `<div class=\\\"edit-req-section-hdr\\\">✏ Edit Requested (${editAssignedCards.length})</div>`;\u001b[39m\n\u001b[31m    html += editAssignedCards.join('');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  html += localCards.join('') + serverCards.join('');\u001b[39m\n\u001b[31m  list.innerHTML = html;\u001b[39m\n\u001b[31m  const ls = await cfg('last-sync');\u001b[39m\n\u001b[31m  if (ls) {\u001b[39m\n\u001b[31m    const d = new Date(ls);\u001b[39m\n\u001b[31m    document.getElementById('last-sync-txt').textContent =\u001b[39m\n\u001b[31m      'Synced ' + d.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit'});\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// RESET\u001b[39m\n\u001b[31mfunction startNewRecce(){F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  if(geoStampEnabled)autoRequestGPS();\u001b[39m\n\u001b[31m['f-date','f-brand','f-store','f-addr','f-mobile','f-client-other'].forEach(id=>{const el=document.getElementById(id);if(el)el.value='';});\u001b[39m\n\u001b[31m_selectedClient='';_clientOtherMode=false;\u001b[39m\n\u001b[31m_selectedCampaignId=null;_notifySupervisor=false;_brandingLocked=false;\u001b[39m\n\u001b[31mconst _camSel=document.getElementById('f-campaign-id');if(_camSel)_camSel.value='';\u001b[39m\n\u001b[31mconst _camNotice=document.getElementById('campaign-notify-msg');if(_camNotice)_camNotice.style.display='none';\u001b[39m\n\u001b[31mloadCampaignsForForm();\u001b[39m\n\u001b[31mrenderClientChips();\u001b[39m\n\u001b[31mdocument.getElementById('f-date').value=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31m// Block future dates\u001b[39m\n\u001b[31mdocument.getElementById('f-date').max=new Date().toISOString().split('T')[0];\u001b[39m\n\u001b[31mdocument.getElementById('store-selected').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('pick-trigger-wrap').style.display=stores.length?'block':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').style.display=stores.length?'flex':'none';\u001b[39m\n\u001b[31mdocument.getElementById('manual-toggle').classList.remove('on');\u001b[39m\n\u001b[31mdocument.getElementById('mt-label').innerHTML='<span class=\\\"en-txt\\\">Store not in list? Enter manually</span><span class=\\\"hi-txt\\\">सूची में नहीं? खुद भरें</span>';\u001b[39m\n\u001b[31mdocument.getElementById('manual-fields').style.display=stores.length?'none':'block';\u001b[39m\n\u001b[31mdocument.getElementById('gps-status').textContent='';\u001b[39m\n\u001b[31m['vid-yes','vid-no','br-yes','br-no'].forEach(id=>document.getElementById(id).classList.remove('sel'));\u001b[39m\n\u001b[31mdocument.getElementById('vid-sec').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('vid-slot').innerHTML=`<div class=\\\"pslot-ico\\\">🎥</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Tap to select video</span><span class=\\\"hi-txt\\\">वीडियो चुनने के लिए दबाएं</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('br-add').style.display='none';document.getElementById('br-items').innerHTML='';\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').classList.remove('filled');\u001b[39m\n\u001b[31mdocument.getElementById('doc-slot').innerHTML=`<div class=\\\"pslot-ico\\\">📄</div><div class=\\\"pslot-lbl\\\"><span class=\\\"en-txt\\\">Upload store branding image or PDF</span><span class=\\\"hi-txt\\\">ब्रांडिंग फोटो या PDF अपलोड करें</span></div>`;\u001b[39m\n\u001b[31mdocument.getElementById('brand-selector').style.display='none';\u001b[39m\n\u001b[31mdocument.getElementById('sc-missing').style.display='none';\u001b[39m\n\u001b[31mpopulateBrandDropdown();\u001b[39m\n\u001b[31mrenderPhotos('front');renderPhotos('inside');renderAddl();updAvailTag();showView('form-store');}\u001b[39m\n\u001b[31mfunction exitForm(){\u001b[39m\n\u001b[31m  // Show safe exit dialog instead of confirm\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitSaveAndLeave(){\u001b[39m\n\u001b[31m  saveDraft();\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m  checkDraft();\u001b[39m\n\u001b[31m  toast('Draft saved — tap Resume to continue','info');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitDiscard(){\u001b[39m\n\u001b[31m  document.getElementById('exit-dialog').classList.remove('open');\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];\u001b[39m\n\u001b[31m  videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  dbDel('draft','current');\u001b[39m\n\u001b[31m  showView('home');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction exitCancel(){document.getElementById('exit-dialog').classList.remove('open');}\u001b[39m\n\u001b[31mfunction showView(n){document.querySelectorAll('.view').forEach(v=>v.classList.remove('active'));const t=document.getElementById('view-'+n);if(t){t.classList.add('active');window.scrollTo(0,0);}}\u001b[39m\n\u001b[31mlet _tt;\u001b[39m\n\u001b[31mfunction toast(msg,type='info'){const el=document.getElementById('toast');el.textContent=msg;el.className='toast show '+type;clearTimeout(_tt);_tt=setTimeout(()=>el.classList.remove('show'),3000);}\u001b[39m\n\u001b[31mfunction netStatus(){const on=navigator.onLine;const dot=document.getElementById('net-dot');const txt=document.getElementById('net-txt');if(dot)dot.className='sdot '+(on?'on':'off');if(txt)txt.textContent=on?t('Online','ऑनलाइन'):t('Offline — saves locally','ऑफलाइन — स्थानीय रूप से सेव');}\u001b[39m\n\u001b[31masync function loadSettings(){\u001b[39m\n\u001b[31m  // Gas URL: pre-load default if none saved, update preview\u001b[39m\n\u001b[31m  const gu=await cfg('gas-url');\u001b[39m\n\u001b[31m  if(!gu)await cfg('gas-url',DEFAULT_GAS_URL);\u001b[39m\n\u001b[31m  updateGasPreview();\u001b[39m\n\u001b[31m  updateSlidesGasPreview();\u001b[39m\n\u001b[31m  // Admin cfg url\u001b[39m\n\u001b[31m  const acu=await cfg('admin-cfg-url');if(acu&&document.getElementById('admin-cfg-url'))document.getElementById('admin-cfg-url').value=acu;\u001b[39m\n\u001b[31m  const su=await cfg('srv-url')||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su)document.getElementById('srv-url').value=su;\u001b[39m\n\u001b[31m  const sc=await cfg('stores');\u001b[39m\n\u001b[31m  if(sc){\u001b[39m\n\u001b[31m    stores=JSON.parse(sc);\u001b[39m\n\u001b[31m    const noBrand=stores.filter(s=>!s.brand).length;\u001b[39m\n\u001b[31m    document.getElementById('store-count').textContent=\u001b[39m\n\u001b[31m      `✓ ${stores.length} stores in cache${noBrand?` · ${noBrand} without brand`:''}`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  const sf=await cfg('store-files');if(sf){_storeFiles=JSON.parse(sf);renderStoreFileList();}\u001b[39m\n\u001b[31m  const iq=await cfg('img-quality');imgQuality=iq||'compressed';applyQualityUI(imgQuality);\u001b[39m\n\u001b[31m  const gs=await cfg('geo-stamp');geoStampEnabled=(gs===null||gs==='1');applyGeoStampUI();\u001b[39m\n\u001b[31m  const bl=await cfg('brands');if(bl)brands=JSON.parse(bl);\u001b[39m\n\u001b[31m  loadBrandsFromDb();  // async — updates brands + logos from DB in background\u001b[39m\n\u001b[31m  renderBrandManageList();\u001b[39m\n\u001b[31m  populateBrandDropdown();\u001b[39m\n\u001b[31m  // Show store upload row + brand add row to supervisors only\u001b[39m\n\u001b[31m  const sur = document.getElementById('store-upload-row');\u001b[39m\n\u001b[31m  if (sur) sur.style.display = _adminUnlocked ? 'flex' : 'none';\u001b[39m\n\u001b[31m  const bar = document.getElementById('brand-add-row');\u001b[39m\n\u001b[31m  if (bar) bar.style.display = _isSupervisor() ? 'flex' : 'none';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction populateBrandDropdown(){\u001b[39m\n\u001b[31m  const sel=document.getElementById('f-brand');if(!sel)return;\u001b[39m\n\u001b[31m  const cur=sel.value;\u001b[39m\n\u001b[31m  sel.innerHTML='<option value=\\\"\\\">Select brand</option>'+brands.map(b=>`<option${cur===b?' selected':''}>${b}</option>`).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction renderBrandManageList(){\u001b[39m\n\u001b[31m  const el=document.getElementById('brand-manage-list');if(!el)return;\u001b[39m\n\u001b[31m  const isSup=_isSupervisor();\u001b[39m\n\u001b[31m  el.innerHTML=brands.map((b,i)=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    const logoHtml=logo?`<img src=\\\"${logo}\\\" style=\\\"height:20px;max-width:48px;object-fit:contain;flex-shrink:0;border-radius:3px\\\">`:'';\u001b[39m\n\u001b[31m    const ctrlHtml=isSup?`<div style=\\\"display:flex;gap:2px;flex-shrink:0\\\">\u001b[39m\n\u001b[31m      <button onclick=\\\"openEditBrandDialog(${i})\\\" style=\\\"background:none;border:none;color:var(--nv);font-size:15px;cursor:pointer;padding:2px 6px\\\" title=\\\"Edit\\\">✏</button>\u001b[39m\n\u001b[31m      ${brands.length>1?`<button onclick=\\\"confirmRemoveBrand(${i})\\\" style=\\\"background:none;border:none;color:var(--rd);font-size:18px;cursor:pointer;line-height:1;padding:2px 4px\\\">×</button>`:'<span style=\\\"font-size:11px;color:var(--g400);padding:0 6px\\\">Last</span>'}\u001b[39m\n\u001b[31m    </div>`:'';\u001b[39m\n\u001b[31m    return `<div style=\\\"display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--g50);border-radius:var(--rs);margin-bottom:6px\\\">\u001b[39m\n\u001b[31m      <div style=\\\"display:flex;align-items:center;gap:8px;min-width:0\\\">${logoHtml}<span style=\\\"font-size:14px;font-weight:500;color:var(--nv)\\\">${b}</span></div>\u001b[39m\n\u001b[31m      ${ctrlHtml}\u001b[39m\n\u001b[31m    </div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function addBrandToList(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const inp=document.getElementById('brand-add-inp');\u001b[39m\n\u001b[31m  const val=(inp.value.trim()||'').toUpperCase();\u001b[39m\n\u001b[31m  if(!val){toast('Enter a brand name','error');return;}\u001b[39m\n\u001b[31m  if(brands.some(b=>b.toLowerCase()===val.toLowerCase())){toast(`${val} already in list`,'error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands`,{method:'POST',headers:{..._RC_WRITE,'Prefer':'return=minimal'},body:JSON.stringify({name:val,sort_order:99})});\u001b[39m\n\u001b[31m    if(resp.status===409){toast(`${val} already exists in DB`,'error');return;}\u001b[39m\n\u001b[31m    if(!resp.ok){const e=await resp.json().catch(()=>({}));throw new Error(e.message||resp.status);}\u001b[39m\n\u001b[31m    inp.value='';\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${val} added ✓`,'success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Add failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function confirmRemoveBrand(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const name=brands[idx];\u001b[39m\n\u001b[31m  if(brands.length<=1){toast('Need at least one brand','error');return;}\u001b[39m\n\u001b[31m  let count=0;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(name)}&select=sub_id`,{headers:_RC_READ});\u001b[39m\n\u001b[31m    if(r.ok){const rows=await r.json();count=rows.length;}\u001b[39m\n\u001b[31m  }catch(_){}\u001b[39m\n\u001b[31m  const msg=count>0?`Delete \\\"${name}\\\" from brand list?\\\\n(${count} submission${count!==1?'s':''} reference this brand — they keep the name as text.)`:`Delete \\\"${name}\\\" from brand list?`;\u001b[39m\n\u001b[31m  if(!confirm(msg))return;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const resp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(name)}`,{method:'DELETE',headers:{'Content-Profile':'recce','Accept-Profile':'recce'}});\u001b[39m\n\u001b[31m    if(!resp.ok&&resp.status!==204){throw new Error(resp.status);}\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast(`${name} removed ✓`,'info');\u001b[39m\n\u001b[31m  }catch(e){toast(`Remove failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function loadBrandsFromDb(){\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    const r=await fetch('/db/brands?select=name,logo_url&order=sort_order',{\u001b[39m\n\u001b[31m      headers:{'Content-Profile':'recce','Accept-Profile':'recce'}\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(!r.ok) return;\u001b[39m\n\u001b[31m    const rows=await r.json();\u001b[39m\n\u001b[31m    if(!rows||!rows.length) return;\u001b[39m\n\u001b[31m    const dbNames=rows.map(r=>r.name);\u001b[39m\n\u001b[31m    const logos={};rows.forEach(r=>{if(r.logo_url)logos[r.name]=r.logo_url;});\u001b[39m\n\u001b[31m    // Merge: DB brands canonical, keep locally-added extras\u001b[39m\n\u001b[31m    const extras=brands.filter(b=>!dbNames.some(n=>n.toLowerCase()===b.toLowerCase()));\u001b[39m\n\u001b[31m    brands=[...dbNames,...extras];\u001b[39m\n\u001b[31m    _brandLogos=logos;\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    // Refresh brand chips if brand-selector is visible\u001b[39m\n\u001b[31m    const bSel=document.getElementById('brand-selector');\u001b[39m\n\u001b[31m    if(bSel&&bSel.style.display!=='none') renderBrandChips();\u001b[39m\n\u001b[31m  }catch(e){console.warn('[brands-db]',e.message);}\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction renderBrandChips(){\u001b[39m\n\u001b[31m  const bChips=document.getElementById('brand-chips');if(!bChips)return;\u001b[39m\n\u001b[31m  bChips.innerHTML=brands.map(b=>{\u001b[39m\n\u001b[31m    const logo=_brandLogos[b];\u001b[39m\n\u001b[31m    return `<div class=\\\"chip brand-chip${F.brand===b?' sel':''}\\\" onclick=\\\"selectStoreBrand('${b.replace(/'/g,\\\"\\\\\\\\'\\\")}')\\\">` +\u001b[39m\n\u001b[31m      (logo?`<img src=\\\"${logo}\\\" class=\\\"brand-chip-logo\\\" alt=\\\"\\\">`:'') +\u001b[39m\n\u001b[31m      `<span>${b}</span></div>`;\u001b[39m\n\u001b[31m  }).join('');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _editBrandIdx=null,_editBrandOld=null;\u001b[39m\n\u001b[31mfunction openEditBrandDialog(idx){\u001b[39m\n\u001b[31m  if(!_isSupervisor())return;\u001b[39m\n\u001b[31m  _editBrandIdx=idx;_editBrandOld=brands[idx];\u001b[39m\n\u001b[31m  document.getElementById('be-name').value=brands[idx];\u001b[39m\n\u001b[31m  const logo=_brandLogos[brands[idx]]||'';\u001b[39m\n\u001b[31m  document.getElementById('be-logo').value=logo;\u001b[39m\n\u001b[31m  document.getElementById('be-logo-preview').innerHTML=logo?`<img src=\\\"${logo}\\\" style=\\\"height:28px;object-fit:contain\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Current logo</span>`:'';\u001b[39m\n\u001b[31m  document.getElementById('be-cascade-info').style.display='none';\u001b[39m\n\u001b[31m  document.getElementById('brand-edit-modal').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction closeBrandEditModal(){document.getElementById('brand-edit-modal').classList.remove('open');_editBrandIdx=null;_editBrandOld=null;}\u001b[39m\n\u001b[31mfunction previewBrandLogo(){\u001b[39m\n\u001b[31m  const url=(document.getElementById('be-logo')?.value||'').trim();\u001b[39m\n\u001b[31m  const prev=document.getElementById('be-logo-preview');\u001b[39m\n\u001b[31m  if(prev)prev.innerHTML=url?`<img src=\\\"${url}\\\" style=\\\"height:28px;object-fit:contain\\\" onerror=\\\"this.style.display='none'\\\"><span style=\\\"font-size:11px;color:var(--g400);margin-left:6px\\\">Preview</span>`:'';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function saveBrandEdit(){\u001b[39m\n\u001b[31m  if(!_isSupervisor()){toast('Supervisors only','error');return;}\u001b[39m\n\u001b[31m  const oldName=_editBrandOld;\u001b[39m\n\u001b[31m  const newName=(document.getElementById('be-name').value||'').trim().toUpperCase();\u001b[39m\n\u001b[31m  const newLogo=(document.getElementById('be-logo').value||'').trim();\u001b[39m\n\u001b[31m  if(!newName){toast('Brand name required','error');return;}\u001b[39m\n\u001b[31m  const isRename=newName!==oldName;\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    // 1. Update recce.brands\u001b[39m\n\u001b[31m    const pResp=await fetch(`${_RC_BASE}/brands?name=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m      method:'PATCH',headers:{..._RC_WRITE,'Prefer':'return=minimal'},\u001b[39m\n\u001b[31m      body:JSON.stringify({name:newName,logo_url:newLogo||null})\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if(pResp.status===409){toast(`\\\"${newName}\\\" already exists`,'error');return;}\u001b[39m\n\u001b[31m    if(!pResp.ok&&pResp.status!==204){const e=await pResp.json().catch(()=>({}));throw new Error(e.message||pResp.status);}\u001b[39m\n\u001b[31m    if(isRename){\u001b[39m\n\u001b[31m      const hub=_recceHubUser();\u001b[39m\n\u001b[31m      // 2. Cascade to submissions\u001b[39m\n\u001b[31m      await fetch(`${_RC_BASE}/submissions?brand=eq.${encodeURIComponent(oldName)}`,{\u001b[39m\n\u001b[31m        method:'PATCH',headers:_RC_WRITE,body:JSON.stringify({brand:newName})\u001b[39m\n\u001b[31m      });\u001b[39m\n\u001b[31m      // 3. Cascade to stores.json + view HTML files + PDFs\u001b[39m\n\u001b[31m      toast('Cascading rename to reports…','info');\u001b[39m\n\u001b[31m      try{\u001b[39m\n\u001b[31m        const cResp=await fetch('/slides-proxy',{method:'POST',headers:{'Content-Type':'application/json'},\u001b[39m\n\u001b[31m          body:JSON.stringify({type:'cascade-rename-brand',oldName,newName,empId:hub?.empId||''})});\u001b[39m\n\u001b[31m        const cRes=cResp.ok?await cResp.json():{};\u001b[39m\n\u001b[31m        const msg=`Brand renamed ✓${cRes.viewsUpdated?` · ${cRes.viewsUpdated} reports re-queued`:''}`;\u001b[39m\n\u001b[31m        closeBrandEditModal();\u001b[39m\n\u001b[31m        await loadBrandsFromDb();\u001b[39m\n\u001b[31m        toast(msg,'success');\u001b[39m\n\u001b[31m        return;\u001b[39m\n\u001b[31m      }catch(e){console.warn('[cascade-rename]',e.message);}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    closeBrandEditModal();\u001b[39m\n\u001b[31m    await loadBrandsFromDb();\u001b[39m\n\u001b[31m    toast('Brand updated ✓','success');\u001b[39m\n\u001b[31m  }catch(e){toast(`Save failed: ${e.message}`,'error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function fetchServerBrands(){\u001b[39m\n\u001b[31m  const url=document.getElementById('brands-url')?.value.trim();\u001b[39m\n\u001b[31m  if(!url){toast('Enter a URL first','error');return;}\u001b[39m\n\u001b[31m  try{\u001b[39m\n\u001b[31m    toast('Fetching brands…','info');\u001b[39m\n\u001b[31m    const r=await fetch(url);const j=await r.json();\u001b[39m\n\u001b[31m    const list=Array.isArray(j)?j:j.brands||[];\u001b[39m\n\u001b[31m    if(!list.length){toast('No brands found in response','error');return;}\u001b[39m\n\u001b[31m    brands=list.map(b=>b.toString().toUpperCase());\u001b[39m\n\u001b[31m    await cfg('brands',JSON.stringify(brands));\u001b[39m\n\u001b[31m    renderBrandManageList();populateBrandDropdown();\u001b[39m\n\u001b[31m    toast(`${brands.length} brands loaded from server`,'success');\u001b[39m\n\u001b[31m  }catch{toast('Failed to fetch — check URL','error');}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction setImgQuality(q){\u001b[39m\n\u001b[31m  imgQuality=q;\u001b[39m\n\u001b[31m  cfg('img-quality',q);\u001b[39m\n\u001b[31m  applyQualityUI(q);\u001b[39m\n\u001b[31m  toast(q==='hd'?'HD Quality selected (~400–600 KB per photo)':'Full Compression selected (~150–200 KB per photo)','success');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction applyQualityUI(q){\u001b[39m\n\u001b[31m  ['compressed','hd'].forEach(opt=>{\u001b[39m\n\u001b[31m    const label=document.getElementById('q-opt-'+opt);\u001b[39m\n\u001b[31m    const radio=document.getElementById('q-radio-'+opt);\u001b[39m\n\u001b[31m    const dot  =document.getElementById('q-dot-'+opt);\u001b[39m\n\u001b[31m    if(!label)return;\u001b[39m\n\u001b[31m    const active=opt===q;\u001b[39m\n\u001b[31m    label.style.borderColor=active?'var(--or)':'var(--g200)';\u001b[39m\n\u001b[31m    label.style.background=active?'#fff7ed':'var(--g50)';\u001b[39m\n\u001b[31m    if(radio)radio.style.borderColor=active?'var(--or)':'var(--g300)';\u001b[39m\n\u001b[31m    if(dot)dot.style.display=active?'block':'none';\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m  const badge=document.getElementById('q-current-badge');\u001b[39m\n\u001b[31m  if(badge){\u001b[39m\n\u001b[31m    const label=q==='hd'?'HD Quality (~400–600 KB)':'Full Compression (~150–200 KB)';\u001b[39m\n\u001b[31m    badge.innerHTML=`Active: <strong>${label}</strong>`;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function clearData(){if(!confirm('Delete ALL local data?'))return;const all=await dbAll('subs');for(const s of all)await dbDel('subs',s.id);stores=[];await cfg('stores',null);toast('All cleared','success');loadHome();}\u001b[39m\n\u001b[31mif('serviceWorker' in navigator){const sw=`const C='recce-v37';self.addEventListener('install',e=>{e.waitUntil(caches.open(C).then(c=>c.add('/')));self.skipWaiting();});self.addEventListener('activate',e=>e.waitUntil(clients.claim()));self.addEventListener('fetch',e=>{if(e.request.method!=='GET')return;e.respondWith(caches.match(e.request).then(r=>{if(r)return r;return fetch(e.request).then(res=>{if(res&&res.status===200&&res.type==='basic'){const cl=res.clone();caches.open(C).then(c=>c.put(e.request,cl));}return res;}).catch(()=>caches.match('/'));}))}); `;const blob=new Blob([sw],{type:'application/javascript'});navigator.serviceWorker.register(URL.createObjectURL(blob),{scope:'/'}).catch(()=>{});}·\u001b[39m\n\u001b[31m// ── GEOLOCATION STAMP ────────────────────────────────────────\u001b[39m\n\u001b[31mfunction applyGeoStampUI(){\u001b[39m\n\u001b[31m  const tog=document.getElementById('geo-tog');\u001b[39m\n\u001b[31m  if(tog)tog.classList.toggle('on',geoStampEnabled);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function toggleGeoStamp(){\u001b[39m\n\u001b[31m  geoStampEnabled=!geoStampEnabled;\u001b[39m\n\u001b[31m  await cfg('geo-stamp',geoStampEnabled?'1':'0');\u001b[39m\n\u001b[31m  applyGeoStampUI();\u001b[39m\n\u001b[31m  toast(geoStampEnabled?'Geolocation stamp enabled':'Geolocation stamp disabled','info');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Auto-request GPS silently when a new recce starts\u001b[39m\n\u001b[31mfunction autoRequestGPS(){\u001b[39m\n\u001b[31m  if(!navigator.geolocation)return;\u001b[39m\n\u001b[31m  const statusEl=document.getElementById('geo-status');\u001b[39m\n\u001b[31m  if(statusEl)statusEl.textContent='Acquiring GPS…';\u001b[39m\n\u001b[31m  navigator.geolocation.getCurrentPosition(\u001b[39m\n\u001b[31m    pos=>{\u001b[39m\n\u001b[31m      gpsCoords={\u001b[39m\n\u001b[31m        lat:pos.coords.latitude.toFixed(6),\u001b[39m\n\u001b[31m        lng:pos.coords.longitude.toFixed(6),\u001b[39m\n\u001b[31m        acc:Math.round(pos.coords.accuracy)\u001b[39m\n\u001b[31m      };\u001b[39m\n\u001b[31m      const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m      const quality=acc<=15?'Excellent':acc<=50?'Good':acc<=200?'Fair':'Poor (cell tower)';\u001b[39m\n\u001b[31m      const color=acc<=15?'var(--gn)':acc<=50?'#16a34a':acc<=200?'var(--am)':'var(--rd)';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.innerHTML=`GPS: ${gpsCoords.lat}, ${gpsCoords.lng} · ±${acc}m · <span style=\\\"color:${color};font-weight:600\\\">${quality}</span>`;\u001b[39m\n\u001b[31m      // Update form GPS status too\u001b[39m\n\u001b[31m      const fs=document.getElementById('gps-status');\u001b[39m\n\u001b[31m      if(fs){fs.textContent=`✓ ${gpsCoords.lat}, ${gpsCoords.lng} (±${acc}m)`;fs.style.color='var(--gn)';}\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    err=>{\u001b[39m\n\u001b[31m      const msgs={1:'Location permission denied in Chrome',2:'GPS signal unavailable',3:'GPS timed out'};\u001b[39m\n\u001b[31m      const msg=msgs[err.code]||'GPS unavailable';\u001b[39m\n\u001b[31m      if(statusEl)statusEl.textContent=msg+' — stamp will use store address';\u001b[39m\n\u001b[31m      if(err.code===1)toast('Tap the lock icon in Chrome address bar → allow Location','info');\u001b[39m\n\u001b[31m    },\u001b[39m\n\u001b[31m    {enableHighAccuracy:true,timeout:20000,maximumAge:60000}\u001b[39m\n\u001b[31m  );\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Draw stamp on a photo blob — returns new blob with stamp baked in\u001b[39m\n\u001b[31mfunction roundRectPath(ctx,x,y,w,h,r){\u001b[39m\n\u001b[31m  ctx.beginPath();ctx.moveTo(x+r,y);ctx.lineTo(x+w-r,y);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y,x+w,y+r);ctx.lineTo(x+w,y+h-r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);ctx.lineTo(x+r,y+h);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y+h,x,y+h-r);ctx.lineTo(x,y+r);\u001b[39m\n\u001b[31m  ctx.quadraticCurveTo(x,y,x+r,y);ctx.closePath();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction fitText(ctx,text,maxW){\u001b[39m\n\u001b[31m  if(ctx.measureText(text).width<=maxW)return text;\u001b[39m\n\u001b[31m  while(text.length>1&&ctx.measureText(text+'…').width>maxW)text=text.slice(0,-1);\u001b[39m\n\u001b[31m  return text+'…';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction stampPhoto(blob){\u001b[39m\n\u001b[31m  if(!geoStampEnabled)return Promise.resolve(blob);\u001b[39m\n\u001b[31m  return new Promise(res=>{\u001b[39m\n\u001b[31m    const img=new Image(),url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m    img.onload=()=>{\u001b[39m\n\u001b[31m      URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m      const W=img.width,H=img.height;\u001b[39m\n\u001b[31m      const c=document.createElement('canvas');c.width=W;c.height=H;\u001b[39m\n\u001b[31m      const ctx=c.getContext('2d');\u001b[39m\n\u001b[31m      ctx.drawImage(img,0,0);·\u001b[39m\n\u001b[31m      // Stamp dimensions — 18% of image height\u001b[39m\n\u001b[31m      const SH=Math.round(H*0.18);\u001b[39m\n\u001b[31m      const pad=Math.round(W*0.03);\u001b[39m\n\u001b[31m      const SY=H-SH;·\u001b[39m\n\u001b[31m      // Semi-transparent background\u001b[39m\n\u001b[31m      ctx.fillStyle='rgba(10,18,35,0.78)';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,SH);·\u001b[39m\n\u001b[31m      // Orange top accent line\u001b[39m\n\u001b[31m      ctx.fillStyle='#f97316';\u001b[39m\n\u001b[31m      ctx.fillRect(0,SY,W,Math.max(3,Math.round(H*0.004)));·\u001b[39m\n\u001b[31m      // Font sizes scaled to image\u001b[39m\n\u001b[31m      const f1=Math.round(SH*0.26); // store name\u001b[39m\n\u001b[31m      const f2=Math.round(SH*0.22); // coords / address\u001b[39m\n\u001b[31m      const f3=Math.round(SH*0.20); // timestamp·\u001b[39m\n\u001b[31m      // Row Y centres\u001b[39m\n\u001b[31m      const r1=SY+SH*0.26;\u001b[39m\n\u001b[31m      const r2=SY+SH*0.55;\u001b[39m\n\u001b[31m      const r3=SY+SH*0.82;·\u001b[39m\n\u001b[31m      // Get stamp data\u001b[39m\n\u001b[31m      const storeName=F.storeName||selectedStore?.name||'';\u001b[39m\n\u001b[31m      const brand=F.brand||selectedStore?.brand||'';\u001b[39m\n\u001b[31m      const addr=F.address||selectedStore?.address||'';\u001b[39m\n\u001b[31m      const now=new Date();\u001b[39m\n\u001b[31m      const dateStr=now.toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric'});\u001b[39m\n\u001b[31m      const timeStr=now.toLocaleTimeString('en-IN',{hour:'2-digit',minute:'2-digit',hour12:true});·\u001b[39m\n\u001b[31m      // Badge (right side — GPS quality)\u001b[39m\n\u001b[31m      let badgeLabel='',badgeColor='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        const acc=gpsCoords.acc;\u001b[39m\n\u001b[31m        if(acc<=15){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=50){badgeLabel='GPS ±'+acc+'m';badgeColor='#16a34a';}\u001b[39m\n\u001b[31m        else if(acc<=200){badgeLabel='~'+acc+'m';badgeColor='#d97706';}\u001b[39m\n\u001b[31m        else{badgeLabel='Cell ~'+acc+'m';badgeColor='#dc2626';}\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        badgeLabel='No GPS';badgeColor='#64748b';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      const bFontSz=Math.round(SH*0.18);\u001b[39m\n\u001b[31m      ctx.font=`bold ${bFontSz}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      const bW=Math.round(ctx.measureText(badgeLabel).width+pad);\u001b[39m\n\u001b[31m      const bH=Math.round(SH*0.32);\u001b[39m\n\u001b[31m      const bX=W-bW-pad;const bY=SY+(SH-bH)/2;\u001b[39m\n\u001b[31m      ctx.fillStyle=badgeColor+'cc';\u001b[39m\n\u001b[31m      roundRectPath(ctx,bX,bY,bW,bH,4);ctx.fill();\u001b[39m\n\u001b[31m      ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';\u001b[39m\n\u001b[31m      ctx.fillText(badgeLabel,bX+bW/2,bY+bH/2);\u001b[39m\n\u001b[31m      ctx.textAlign='left';ctx.textBaseline='alphabetic';·\u001b[39m\n\u001b[31m      const textMaxW=bX-pad*2;·\u001b[39m\n\u001b[31m      // Row 1 — store name + brand\u001b[39m\n\u001b[31m      ctx.font=`bold ${f1}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#ffffff';\u001b[39m\n\u001b[31m      const nameText=storeName+(brand?' · '+brand:'');\u001b[39m\n\u001b[31m      ctx.fillText('📍 '+fitText(ctx,nameText,textMaxW-f1*1.4),pad,r1);·\u001b[39m\n\u001b[31m      // Row 2 — GPS coords OR address\u001b[39m\n\u001b[31m      ctx.font=`${f2}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#cbd5e1';\u001b[39m\n\u001b[31m      let row2='';\u001b[39m\n\u001b[31m      if(gpsCoords){\u001b[39m\n\u001b[31m        row2=`Lat ${gpsCoords.lat}°   Long ${gpsCoords.lng}°`;\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        row2=addr?fitText(ctx,addr,textMaxW):'GPS coordinates unavailable';\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m      ctx.fillText(row2,pad,r2);·\u001b[39m\n\u001b[31m      // Row 3 — date and time\u001b[39m\n\u001b[31m      ctx.font=`${f3}px Arial,sans-serif`;\u001b[39m\n\u001b[31m      ctx.fillStyle='#94a3b8';\u001b[39m\n\u001b[31m      ctx.fillText(`${dateStr}   ${timeStr}`,pad,r3);·\u001b[39m\n\u001b[31m      c.toBlob(b=>res(b||blob),'image/jpeg',imgQuality==='hd'?0.88:0.82);\u001b[39m\n\u001b[31m    };\u001b[39m\n\u001b[31m    img.onerror=()=>{URL.revokeObjectURL(url);res(blob);};\u001b[39m\n\u001b[31m    img.src=url;\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mlet _aTool='rect',_aColor='#f97316',_aWidth=4,_aTarget=-1;\u001b[39m\n\u001b[31mlet _aImg=null,_aHistory=[],_aDrawing=false,_aStart={},_aPts=[];\u001b[39m\n\u001b[31mlet _aSel=-1,_aDragMode=null,_aDragOff={x:0,y:0};\u001b[39m\n\u001b[31m// Larger hit radius on touch devices for easier finger selection\u001b[39m\n\u001b[31mconst HIT_R=()=>('ontouchstart' in window)?32:16;·\u001b[39m\n\u001b[31mfunction setATool(t){\u001b[39m\n\u001b[31m  _aTool=t;\u001b[39m\n\u001b[31m  ['rect','ellipse','line','arrow','free'].forEach(id=>{const el=document.getElementById('at-'+id);if(el)el.classList.toggle('on',id===t&&t!=='move');});\u001b[39m\n\u001b[31m  const mv=document.getElementById('at-move');if(mv)mv.classList.toggle('sel-on',t==='move');\u001b[39m\n\u001b[31m  const info=document.getElementById('annot-sel-info');if(info)info.style.display=t==='move'?'block':'none';\u001b[39m\n\u001b[31m  if(t!=='move'){_aSel=-1;redrawAnnot();}\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(cvs)cvs.style.cursor=t==='move'?'default':'crosshair';\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAColor(c){\u001b[39m\n\u001b[31m  _aColor=c;\u001b[39m\n\u001b[31m  const m={'#f97316':'or','#ef4444':'rd','#ffffff':'wh','#facc15':'yw','#22c55e':'gn'};\u001b[39m\n\u001b[31m  Object.entries(m).forEach(([col,id])=>{const el=document.getElementById('ac-'+id);if(el)el.classList.toggle('on',col===c);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction setAWidth(w){_aWidth=w;[2,4,7].forEach(v=>{const el=document.getElementById('aw-'+v);if(el)el.classList.toggle('on',v===w);});}·\u001b[39m\n\u001b[31mfunction openAnnot(idx){\u001b[39m\n\u001b[31m  _aTarget=idx;_aHistory=[];_aDrawing=false;_aPts=[];_aSel=-1;_aDragMode=null;\u001b[39m\n\u001b[31m  document.getElementById('annot-modal').classList.add('open');\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');\u001b[39m\n\u001b[31m  const img=new Image(),url=URL.createObjectURL(brandings[idx].blob);\u001b[39m\n\u001b[31m  img.onload=()=>{\u001b[39m\n\u001b[31m    const sc=Math.min(1,window.innerWidth/img.width,(window.innerHeight-185)/img.height);\u001b[39m\n\u001b[31m    cvs.width=Math.round(img.width*sc);cvs.height=Math.round(img.height*sc);\u001b[39m\n\u001b[31m    _aImg=img;redrawAnnot();URL.revokeObjectURL(url);\u001b[39m\n\u001b[31m  };\u001b[39m\n\u001b[31m  img.src=url;\u001b[39m\n\u001b[31m  cvs.ontouchstart=aDown;cvs.ontouchmove=aMove;cvs.ontouchend=aUp;\u001b[39m\n\u001b[31m  cvs.onmousedown=aDown;cvs.onmousemove=aMove;cvs.onmouseup=aUp;\u001b[39m\n\u001b[31m  setATool('rect');setAColor('#f97316');setAWidth(4);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aPos(e){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const r=cvs.getBoundingClientRect();\u001b[39m\n\u001b[31m  const src=e.touches?e.touches[0]:e;\u001b[39m\n\u001b[31m  return{x:(src.clientX-r.left)*(cvs.width/r.width),y:(src.clientY-r.top)*(cvs.height/r.height)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// Always return normalised (positive w,h) bounds\u001b[39m\n\u001b[31mfunction sBounds(s){\u001b[39m\n\u001b[31m  if(s.type==='free'){\u001b[39m\n\u001b[31m    if(!s.pts||!s.pts.length)return null;\u001b[39m\n\u001b[31m    const xs=s.pts.map(p=>p.x),ys=s.pts.map(p=>p.y);\u001b[39m\n\u001b[31m    const x=Math.min(...xs),y=Math.min(...ys);\u001b[39m\n\u001b[31m    return{x,y,w:Math.max(...xs)-x,h:Math.max(...ys)-y};\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  return{x:Math.min(s.x,s.x+s.w),y:Math.min(s.y,s.y+s.h),w:Math.abs(s.w),h:Math.abs(s.h)};\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction hitHandle(px,py,s){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return null;\u001b[39m\n\u001b[31m  const b=sBounds(s);const hr=HIT_R();\u001b[39m\n\u001b[31m  for(const[n,x,y]of[['tl',b.x,b.y],['tr',b.x+b.w,b.y],['bl',b.x,b.y+b.h],['br',b.x+b.w,b.y+b.h]])\u001b[39m\n\u001b[31m    if(Math.hypot(px-x,py-y)<hr)return n;\u001b[39m\n\u001b[31m  return null;\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction hitShape(px,py,s){\u001b[39m\n\u001b[31m  const b=sBounds(s);if(!b)return false;\u001b[39m\n\u001b[31m  const pad=HIT_R();\u001b[39m\n\u001b[31m  return px>=b.x-pad&&px<=b.x+b.w+pad&&py>=b.y-pad&&py<=b.y+b.h+pad;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aDown(e){\u001b[39m\n\u001b[31m  e.preventDefault();const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'){\u001b[39m\n\u001b[31m    // Check handles of selected shape first\u001b[39m\n\u001b[31m    if(_aSel>=0&&_aSel<_aHistory.length){\u001b[39m\n\u001b[31m      const h=hitHandle(p.x,p.y,_aHistory[_aSel]);\u001b[39m\n\u001b[31m      if(h){_aDragMode='r-'+h;_aDragOff={x:p.x,y:p.y};_aDrawing=true;return;}\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Hit test all shapes topmost first\u001b[39m\n\u001b[31m    for(let i=_aHistory.length-1;i>=0;i--){\u001b[39m\n\u001b[31m      if(hitShape(p.x,p.y,_aHistory[i])){\u001b[39m\n\u001b[31m        _aSel=i;_aDragMode='move';\u001b[39m\n\u001b[31m        const s=_aHistory[i];\u001b[39m\n\u001b[31m        const b=sBounds(s);\u001b[39m\n\u001b[31m        // Store offset from shape top-left corner (normalised)\u001b[39m\n\u001b[31m        _aDragOff={x:p.x-b.x,y:p.y-b.y};\u001b[39m\n\u001b[31m        _aDrawing=true;redrawAnnot();return;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    _aSel=-1;redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  _aDrawing=true;_aStart={x:p.x,y:p.y};if(_aTool==='free')_aPts=[{x:p.x,y:p.y}];\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction aMove(e){\u001b[39m\n\u001b[31m  e.preventDefault();if(!_aDrawing)return;const p=aPos(e);\u001b[39m\n\u001b[31m  if(_aTool==='move'&&_aDragMode){\u001b[39m\n\u001b[31m    const s=_aHistory[_aSel];if(!s)return;\u001b[39m\n\u001b[31m    if(_aDragMode==='move'){\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      // New top-left position\u001b[39m\n\u001b[31m      const nx=p.x-_aDragOff.x;\u001b[39m\n\u001b[31m      const ny=p.y-_aDragOff.y;\u001b[39m\n\u001b[31m      const dx=nx-b.x,dy=ny-b.y;\u001b[39m\n\u001b[31m      if(s.type==='free'){\u001b[39m\n\u001b[31m        s.pts=s.pts.map(pt=>({x:pt.x+dx,y:pt.y+dy}));\u001b[39m\n\u001b[31m      } else {\u001b[39m\n\u001b[31m        // Move preserving w/h sign (don't normalise — keep original drawing direction)\u001b[39m\n\u001b[31m        s.x+=dx;s.y+=dy;\u001b[39m\n\u001b[31m      }\u001b[39m\n\u001b[31m    } else {\u001b[39m\n\u001b[31m      // Resize from corner — always work on normalised bounds then re-apply\u001b[39m\n\u001b[31m      const b=sBounds(s);\u001b[39m\n\u001b[31m      const n=_aDragMode.slice(2);\u001b[39m\n\u001b[31m      let nx=b.x,ny=b.y,nw=b.w,nh=b.h;\u001b[39m\n\u001b[31m      if(n==='br'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,p.y-b.y);}\u001b[39m\n\u001b[31m      else if(n==='tl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,b.y+b.h-p.y);nx=p.x;ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='tr'){nw=Math.max(10,p.x-b.x);nh=Math.max(10,b.y+b.h-p.y);ny=p.y;}\u001b[39m\n\u001b[31m      else if(n==='bl'){nw=Math.max(10,b.x+b.w-p.x);nh=Math.max(10,p.y-b.y);nx=p.x;}\u001b[39m\n\u001b[31m      s.x=nx;s.y=ny;s.w=nw;s.h=nh; // store as normalised going forward\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    redrawAnnot();return;\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  if(_aTool==='free'){_aPts.push({x:p.x,y:p.y});redrawAnnot();drawSh({type:'free',pts:[..._aPts],color:_aColor,lw:_aWidth},true);return;}\u001b[39m\n\u001b[31m  redrawAnnot();drawSh({type:_aTool,x:_aStart.x,y:_aStart.y,w:p.x-_aStart.x,h:p.y-_aStart.y,color:_aColor,lw:_aWidth},true);\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction aUp(e){\u001b[39m\n\u001b[31m  if(!_aDrawing)return;_aDrawing=false;\u001b[39m\n\u001b[31m  if(_aTool==='move'){_aDragMode=null;return;}\u001b[39m\n\u001b[31m  const p=aPos(e||{touches:[{clientX:0,clientY:0}]});\u001b[39m\n\u001b[31m  if(_aTool==='free'){if(_aPts.length>2){_aHistory.push({type:'free',pts:[..._aPts],x:_aPts[0].x,y:_aPts[0].y,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  else{const w=p.x-_aStart.x,h=p.y-_aStart.y;if(Math.abs(w)>4||Math.abs(h)>4){_aHistory.push({type:_aTool,x:_aStart.x,y:_aStart.y,w,h,color:_aColor,lw:_aWidth});_aSel=_aHistory.length-1;}}\u001b[39m\n\u001b[31m  _aPts=[];redrawAnnot();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction redrawAnnot(){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');const ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.clearRect(0,0,cvs.width,cvs.height);if(_aImg)ctx.drawImage(_aImg,0,0,cvs.width,cvs.height);\u001b[39m\n\u001b[31m  _aHistory.forEach((s,i)=>{drawSh(s,false,ctx);if(_aTool==='move'&&i===_aSel)drawHandles(s,ctx);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawHandles(s,ctx){\u001b[39m\n\u001b[31m  if(!s||s.type==='free')return;const b=sBounds(s);ctx.save();\u001b[39m\n\u001b[31m  ctx.setLineDash([5,3]);ctx.strokeStyle='#facc15';ctx.lineWidth=1.5;ctx.strokeRect(b.x-2,b.y-2,b.w+4,b.h+4);ctx.setLineDash([]);\u001b[39m\n\u001b[31m  [[b.x,b.y],[b.x+b.w,b.y],[b.x,b.y+b.h],[b.x+b.w,b.y+b.h]].forEach(([x,y])=>{ctx.beginPath();ctx.arc(x,y,7,0,2*Math.PI);ctx.fillStyle='#f97316';ctx.fill();ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();});\u001b[39m\n\u001b[31m  ctx.restore();\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction drawSh(s,preview=false,ctx){\u001b[39m\n\u001b[31m  const cvs=document.getElementById('annot-cvs');if(!ctx)ctx=cvs.getContext('2d');\u001b[39m\n\u001b[31m  ctx.save();ctx.strokeStyle=s.color;ctx.lineWidth=preview?Math.max(s.lw||4,2):s.lw||4;\u001b[39m\n\u001b[31m  ctx.lineCap='round';ctx.lineJoin='round';ctx.setLineDash(preview?[6,3]:[]);\u001b[39m\n\u001b[31m  if(s.type==='rect'){ctx.strokeRect(s.x,s.y,s.w,s.h);ctx.fillStyle=s.color+'28';ctx.fillRect(s.x,s.y,s.w,s.h);}\u001b[39m\n\u001b[31m  else if(s.type==='ellipse'){const cx=s.x+s.w/2,cy=s.y+s.h/2;ctx.beginPath();ctx.ellipse(cx,cy,Math.abs(s.w/2),Math.abs(s.h/2),0,0,2*Math.PI);ctx.stroke();ctx.fillStyle=s.color+'28';ctx.fill();}\u001b[39m\n\u001b[31m  else if(s.type==='line'){ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(s.x+s.w,s.y+s.h);ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='arrow'){const ex=s.x+s.w,ey=s.y+s.h;ctx.beginPath();ctx.moveTo(s.x,s.y);ctx.lineTo(ex,ey);ctx.stroke();const a=Math.atan2(s.h,s.w),al=20,aa=0.4;ctx.setLineDash([]);ctx.beginPath();ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a-aa),ey-al*Math.sin(a-aa));ctx.moveTo(ex,ey);ctx.lineTo(ex-al*Math.cos(a+aa),ey-al*Math.sin(a+aa));ctx.stroke();}\u001b[39m\n\u001b[31m  else if(s.type==='free'){if(s.pts.length<2){ctx.restore();return;}ctx.beginPath();s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));ctx.stroke();}\u001b[39m\n\u001b[31m  ctx.setLineDash([]);ctx.restore();\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction undoAnnot(){if(_aHistory.length){_aHistory.pop();_aSel=Math.min(_aSel,_aHistory.length-1);redrawAnnot();}}\u001b[39m\n\u001b[31mfunction clearAnnot(){_aHistory=[];_aSel=-1;redrawAnnot();}·\u001b[39m\n\u001b[31m// Bottom dialog\u001b[39m\n\u001b[31mlet _bdCb=null;\u001b[39m\n\u001b[31mfunction showBDialog(title,sub,onYes){\u001b[39m\n\u001b[31m  document.getElementById('bdialog-title').textContent=title;\u001b[39m\n\u001b[31m  document.getElementById('bdialog-sub').textContent=sub;\u001b[39m\n\u001b[31m  _bdCb=onYes;document.getElementById('bdialog').classList.add('open');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction bdialogYes(){document.getElementById('bdialog').classList.remove('open');if(_bdCb)_bdCb();_bdCb=null;}\u001b[39m\n\u001b[31mfunction bdialogNo(){document.getElementById('bdialog').classList.remove('open');_bdCb=null;}·\u001b[39m\n\u001b[31mfunction _afterBrandingPhoto(){\u001b[39m\n\u001b[31m  const idx=_aTarget;\u001b[39m\n\u001b[31m  showBDialog(t(`Add reference photos for Branding ${idx+1}?`,`ब्रांडिंग ${idx+1} के लिए अतिरिक्त फोटो?`),t('Optional extra photos for future reference.','वैकल्पिक — भविष्य के लिए अतिरिक्त फोटो।'),()=>{showView('form-additional');setTimeout(()=>addAdditional(),200);});\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction skipAnnot(){document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo added (${fmtSz(brandings[_aTarget].blob.size)})`,'success');_afterBrandingPhoto();}\u001b[39m\n\u001b[31mfunction saveAnnot(){const cvs=document.getElementById('annot-cvs');cvs.toBlob(blob=>{brandings[_aTarget].blob=blob;brandings[_aTarget].prev=URL.createObjectURL(blob);document.getElementById('annot-modal').classList.remove('open');renderBrandings();toast(`Photo + markup saved (${fmtSz(blob.size)})`,'success');_afterBrandingPhoto();},'image/jpeg',0.88);}·\u001b[39m\n\u001b[31m// ── VIEW RECCE (read-only) ──────────────────────────────────\u001b[39m\n\u001b[31masync function viewRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  // Synced entries have a server-side rich report — open it directly\u001b[39m\n\u001b[31m  if(entry.viewUrl){window.open(entry.viewUrl,'_blank');return;}\u001b[39m\n\u001b[31m  // Offline / not-yet-synced fallback: generate from local base64 data\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  const ts=new Date(entry.timestamp).toLocaleDateString('en-IN',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'});·\u001b[39m\n\u001b[31m  async function b64ToUrl(b64){if(!b64)return'';try{const r=await fetch(b64);const bl=await r.blob();return URL.createObjectURL(bl);}catch{return'';}}·\u001b[39m\n\u001b[31m  const fvUrls=await Promise.all((d.frontPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const ivUrls=await Promise.all((d.insidePhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const brUrls=await Promise.all((d.brandings||[]).map(b=>b64ToUrl(b.photoB64)));\u001b[39m\n\u001b[31m  const adUrls=await Promise.all((d.addlPhotos||[]).map(p=>b64ToUrl(p.b64)));\u001b[39m\n\u001b[31m  const docUrl=await b64ToUrl(d.docB64);·\u001b[39m\n\u001b[31m  const brRows=(d.brandings||[]).map((b,i)=>`\u001b[39m\n\u001b[31m    <div style=\\\"margin-bottom:16px;padding:12px;background:#f8fafc;border-radius:8px;border-left:3px solid #f97316\\\">\u001b[39m\n\u001b[31m      <div style=\\\"font-weight:600;font-size:14px;color:#0f172a;margin-bottom:6px\\\">${i+1}. ${b.type||'—'}: ${b.w||'?'}\\\"×${b.h||'?'}\\\" · Qty: ${b.qty||'?'} · ${b.sqft||'?'}</div>\u001b[39m\n\u001b[31m      ${brUrls[i]?`<img src=\\\"${brUrls[i]}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:6px\\\">`:'<div style=\\\"color:#94a3b8;font-size:12px\\\">No photo</div>'}\u001b[39m\n\u001b[31m    </div>`).join('');·\u001b[39m\n\u001b[31m  const html=`<!DOCTYPE html><html><head><meta charset=\\\"UTF-8\\\"><meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1\\\">\u001b[39m\n\u001b[31m  <title>Recce — ${d.storeName||'Unknown'}</title>\u001b[39m\n\u001b[31m  <style>body{font-family:Arial,sans-serif;margin:0;padding:16px;background:#f1f5f9}\u001b[39m\n\u001b[31m  .card{background:#fff;border-radius:12px;padding:16px;margin-bottom:14px;box-shadow:0 1px 4px rgba(0,0,0,.08)}\u001b[39m\n\u001b[31m  h1{font-size:18px;color:#0f172a;margin:0 0 4px}h2{font-size:14px;color:#f97316;text-transform:uppercase;letter-spacing:.5px;margin:0 0 10px}\u001b[39m\n\u001b[31m  .meta{font-size:12px;color:#64748b;margin-bottom:12px}.photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}\u001b[39m\n\u001b[31m  img{width:100%;border-radius:8px;object-fit:cover}\u001b[39m\n\u001b[31m  .tag{display:inline-block;background:#0f172a;color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;margin-right:4px}\u001b[39m\n\u001b[31m  @media print{body{background:#fff}.card{box-shadow:none}}</style></head><body>\u001b[39m\n\u001b[31m  <div class=\\\"card\\\">\u001b[39m\n\u001b[31m    <h1>${d.storeName||'Unknown Store'}</h1>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\"><span class=\\\"tag\\\">${d.brand||'No Brand'}</span>${d.address||''}</div>\u001b[39m\n\u001b[31m    <div class=\\\"meta\\\">📞 ${d.mobile||'—'} &nbsp;|&nbsp; 📅 ${d.date||'—'} &nbsp;|&nbsp; Submitted: ${ts}</div>\u001b[39m\n\u001b[31m    ${d.gpsCoords?`<div class=\\\"meta\\\">📍 ${d.gpsCoords.lat}, ${d.gpsCoords.lng} ±${d.gpsCoords.acc}m</div>`:''}\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  ${fvUrls.length?`<div class=\\\"card\\\"><h2>Front View Photos</h2><div class=\\\"photos\\\">${fvUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${ivUrls.length?`<div class=\\\"card\\\"><h2>Inside View Photos</h2><div class=\\\"photos\\\">${ivUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${d.hasVideo?`<div class=\\\"card\\\"><h2>Video</h2><div>${d.videoNote||'Video recorded'}</div></div>`:''}\u001b[39m\n\u001b[31m  ${(d.brandings||[]).length?`<div class=\\\"card\\\"><h2>Branding Items (${(d.brandings||[]).length})</h2>${brRows}</div>`:''}\u001b[39m\n\u001b[31m  ${adUrls.length?`<div class=\\\"card\\\"><h2>Additional Photos</h2><div class=\\\"photos\\\">${adUrls.map(u=>`<img src=\\\"${u}\\\">`).join('')}</div></div>`:''}\u001b[39m\n\u001b[31m  ${docUrl?`<div class=\\\"card\\\"><h2>Submission Document</h2><img src=\\\"${docUrl}\\\" style=\\\"width:100%;max-height:300px;object-fit:contain\\\"></div>`:''}\u001b[39m\n\u001b[31m  <div style=\\\"text-align:center;margin:16px 0\\\">\u001b[39m\n\u001b[31m    <button onclick=\\\"window.print()\\\" style=\\\"background:#f97316;color:#fff;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer\\\">🖨 Print / Save as PDF</button>\u001b[39m\n\u001b[31m    <button onclick=\\\"window.close()\\\" style=\\\"background:#e2e8f0;color:#475569;border:none;padding:13px 28px;border-radius:24px;font-size:15px;font-weight:700;cursor:pointer;margin-left:10px\\\">Close</button>\u001b[39m\n\u001b[31m  </div>\u001b[39m\n\u001b[31m  </body></html>`;\u001b[39m\n\u001b[31m  const blob=new Blob([html],{type:'text/html'});\u001b[39m\n\u001b[31m  const url=URL.createObjectURL(blob);\u001b[39m\n\u001b[31m  window.open(url,'_blank');\u001b[39m\n\u001b[31m  setTimeout(()=>URL.revokeObjectURL(url),30000);\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── EDIT OLD RECCE ───────────────────────────────────────────\u001b[39m\n\u001b[31masync function editRecce(id){\u001b[39m\n\u001b[31m  const entry=await dbGet('subs',id);if(!entry){toast('Entry not found','error');return;}\u001b[39m\n\u001b[31m  const d=entry.data;\u001b[39m\n\u001b[31m  F={};frontPhotos=[];insidePhotos=[];addlPhotos=[];brandings=[];videoBlob=null;submissionDoc=null;_docExistingUrl=null;gpsCoords=d.gpsCoords||null;selectedStore=null;manualMode=false;\u001b[39m\n\u001b[31m  F.editingId=id;F.date=d.date||'';F.brand=d.brand||'';F.storeName=d.storeName||'';F.address=d.address||'';F.mobile=d.mobile||'';F.hasVideo=d.hasVideo;F.hasBranding=d.hasBranding;\u001b[39m\n\u001b[31m  async function b64ToBlob(b64){if(!b64)return null;try{const r=await fetch(b64);return await r.blob();}catch{return null;}}\u001b[39m\n\u001b[31m  toast('Loading recce data…','info');\u001b[39m\n\u001b[31m  for(const p of(d.frontPhotos||[])){const b=await b64ToBlob(p.b64);if(b)frontPhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const p of(d.insidePhotos||[])){const b=await b64ToBlob(p.b64);if(b)insidePhotos.push({blob:b,prev:URL.createObjectURL(b),cmt:p.cmt||''});}\u001b[39m\n\u001b[31m  for(const br of(d.brandings||[])){const b=await b64ToBlob(br.photoB64);brandings.push({type:br.type,w:br.w,h:br.h,qty:br.qty,blob:b,prev:b?URL.createObjectURL(b):null});}\u001b[39m\n\u001b[31m  for(const p of(d.addlPhotos||[])){const b=await b64ToBlob(p.b64);if(b)addlPhotos.push({blob:b,prev:URL.createObjectURL(b),desc:p.desc||''});}\u001b[39m\n\u001b[31m  if(d.docB64){const b=await b64ToBlob(d.docB64);if(b){submissionDoc=b;const sl=document.getElementById('doc-slot');sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${URL.createObjectURL(b)}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}}\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value=F.date;\u001b[39m\n\u001b[31m  if(F.brand)document.getElementById('f-brand').value=F.brand;\u001b[39m\n\u001b[31m  if(F.storeName)document.getElementById('f-store').value=F.storeName;\u001b[39m\n\u001b[31m  if(F.address)document.getElementById('f-addr').value=F.address;\u001b[39m\n\u001b[31m  if(F.mobile)document.getElementById('f-mobile').value=F.mobile;\u001b[39m\n\u001b[31m  if(F.hasVideo!==undefined)setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if(F.hasBranding!==undefined)setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  renderPhotos('front');renderPhotos('inside');renderBrandings();renderAddl();updAvailTag();\u001b[39m\n\u001b[31m  toast('Recce loaded — make changes and re-submit','success');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31m// ── EDIT REQUEST ────────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mlet _editReqSubId = null;·\u001b[39m\n\u001b[31mfunction _hydratePhotosFromRow(r) {\u001b[39m\n\u001b[31m  let pu={};\u001b[39m\n\u001b[31m  try{pu=typeof r.photo_urls==='string'?JSON.parse(r.photo_urls):(r.photo_urls||{});}catch(_){}\u001b[39m\n\u001b[31m  let meta={};\u001b[39m\n\u001b[31m  try{meta=typeof r.meta==='string'?JSON.parse(r.meta):(r.meta||{});}catch(_){}\u001b[39m\n\u001b[31m  frontPhotos =(pu.front   ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  insidePhotos=(pu.inside  ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,cmt:''}));\u001b[39m\n\u001b[31m  addlPhotos  =(pu.addl    ||[]).filter(Boolean).map(url=>({existingUrl:url,blob:null,prev:url,desc:''}));\u001b[39m\n\u001b[31m  brandings   =(meta.brandings||[]).map((b,i)=>({type:b.type,w:b.w,h:b.h,qty:b.qty,existingUrl:(pu.brandings||[])[i]||null,blob:null,prev:(pu.brandings||[])[i]||null}));\u001b[39m\n\u001b[31m  _docExistingUrl=pu.doc||null;\u001b[39m\n\u001b[31m  // Show retained doc in slot\u001b[39m\n\u001b[31m  const sl=document.getElementById('doc-slot');\u001b[39m\n\u001b[31m  if(sl&&_docExistingUrl){sl.classList.add('filled');sl.innerHTML=`<img src=\\\"${_docExistingUrl}\\\" style=\\\"width:100%;max-height:200px;object-fit:contain;border-radius:10px\\\">`;}\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction openEditRequestModal(subId) {\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  _editReqSubId = subId;\u001b[39m\n\u001b[31m  document.getElementById('er-store-name').textContent = r.store_name || 'Unknown';\u001b[39m\n\u001b[31m  document.getElementById('er-comment').value = '';\u001b[39m\n\u001b[31m  const hub = _recceHubUser();\u001b[39m\n\u001b[31m  const assignBtn = document.getElementById('er-assign-btn');\u001b[39m\n\u001b[31m  if (r.submitted_by && r.submitted_by !== hub?.empId) {\u001b[39m\n\u001b[31m    assignBtn.textContent = `👤 Assign to ${r.submitted_by}`;\u001b[39m\n\u001b[31m    assignBtn.style.display = '';\u001b[39m\n\u001b[31m  } else {\u001b[39m\n\u001b[31m    assignBtn.style.display = 'none';\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.add('open');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction closeEditRequestModal() {\u001b[39m\n\u001b[31m  document.getElementById('edit-req-modal').classList.remove('open');\u001b[39m\n\u001b[31m  _editReqSubId = null;\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function supervisorEditMyself() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r) return;\u001b[39m\n\u001b[31m  // Lock branding if client has reviewed (preserve their approval)\u001b[39m\n\u001b[31m  _brandingLocked = !!(r.client_status && r.client_status !== 'pending');\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function assignEditToCreator() {\u001b[39m\n\u001b[31m  const subId = _editReqSubId;\u001b[39m\n\u001b[31m  const r = _adminRows.find(x => x.sub_id === subId);\u001b[39m\n\u001b[31m  if (!r || !r.submitted_by) { toast('No creator found for this recce', 'error'); return; }\u001b[39m\n\u001b[31m  const comment = (document.getElementById('er-comment').value || '').trim();\u001b[39m\n\u001b[31m  closeEditRequestModal();\u001b[39m\n\u001b[31m  try {\u001b[39m\n\u001b[31m    const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, {\u001b[39m\n\u001b[31m      method: 'PATCH',\u001b[39m\n\u001b[31m      headers: _RC_WRITE,\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        status: 'edit_requested',\u001b[39m\n\u001b[31m        edit_assigned_to: r.submitted_by,\u001b[39m\n\u001b[31m        edit_comment: comment || null,\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    });\u001b[39m\n\u001b[31m    if (!resp.ok) throw new Error('Update failed: ' + resp.status);\u001b[39m\n\u001b[31m    const idx = _adminRows.findIndex(x => x.sub_id === subId);\u001b[39m\n\u001b[31m    if (idx >= 0) {\u001b[39m\n\u001b[31m      _adminRows[idx].status = 'edit_requested';\u001b[39m\n\u001b[31m      _adminRows[idx].edit_assigned_to = r.submitted_by;\u001b[39m\n\u001b[31m      _adminRows[idx].edit_comment = comment || null;\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    // Push notification to creator\u001b[39m\n\u001b[31m    const notifBody = comment || `Please review and re-submit: ${r.store_name || 'your recce'}`;\u001b[39m\n\u001b[31m    fetch('/push-server/notify', {\u001b[39m\n\u001b[31m      method: 'POST', headers: { 'Content-Type': 'application/json' },\u001b[39m\n\u001b[31m      body: JSON.stringify({\u001b[39m\n\u001b[31m        user_id: r.submitted_by, title: '✏ Edit Requested',\u001b[39m\n\u001b[31m        body: notifBody, tag: `recce-edit-${subId}`, url: '/recce/',\u001b[39m\n\u001b[31m        icon: '/hub/icons/icon-192.png', badge: '/hub/icons/icon-192.png',\u001b[39m\n\u001b[31m      }),\u001b[39m\n\u001b[31m    }).catch(() => {});\u001b[39m\n\u001b[31m    renderAdminList();\u001b[39m\n\u001b[31m    toast(`Edit assigned to ${r.submitted_by} ✓`, 'success');\u001b[39m\n\u001b[31m  } catch(e) {\u001b[39m\n\u001b[31m    toast(e.message || 'Assign failed', 'error');\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31masync function startCreatorEdit(subId) {\u001b[39m\n\u001b[31m  // Try local IndexedDB first (has photos)\u001b[39m\n\u001b[31m  const local = await dbGet('subs', subId);\u001b[39m\n\u001b[31m  if (local) { await editRecce(subId); return; }\u001b[39m\n\u001b[31m  // Fallback: load text fields from server row\u001b[39m\n\u001b[31m  const r = _myServerRows.find(x => x.sub_id === subId)\u001b[39m\n\u001b[31m         || (await (async () => {\u001b[39m\n\u001b[31m              try {\u001b[39m\n\u001b[31m                const resp = await fetch(`${_RC_BASE}/submissions?sub_id=eq.${subId}`, { headers: _RC_READ });\u001b[39m\n\u001b[31m                if (resp.ok) { const arr = await resp.json(); return arr[0]; }\u001b[39m\n\u001b[31m              } catch(_) {} return null;\u001b[39m\n\u001b[31m            })());\u001b[39m\n\u001b[31m  if (!r) { toast('Record not found', 'error'); return; }\u001b[39m\n\u001b[31m  let meta = {};\u001b[39m\n\u001b[31m  try { meta = typeof r.meta === 'string' ? JSON.parse(r.meta) : (r.meta || {}); } catch(_) {}·\u001b[39m\n\u001b[31m  F = {};\u001b[39m\n\u001b[31m  frontPhotos = []; insidePhotos = []; addlPhotos = []; brandings = [];\u001b[39m\n\u001b[31m  videoBlob = null; submissionDoc = null; _docExistingUrl = null; gpsCoords = null;\u001b[39m\n\u001b[31m  selectedStore = null; manualMode = false;·\u001b[39m\n\u001b[31m  F.editingId = r.sub_id;\u001b[39m\n\u001b[31m  F.date = r.visit_date || '';\u001b[39m\n\u001b[31m  F.brand = r.brand || '';\u001b[39m\n\u001b[31m  F.storeName = r.store_name || '';\u001b[39m\n\u001b[31m  F.address = r.address || '';\u001b[39m\n\u001b[31m  F.mobile = r.mobile || '';\u001b[39m\n\u001b[31m  F.clientName = r.client_name || '';\u001b[39m\n\u001b[31m  F.hasVideo = r.has_video;\u001b[39m\n\u001b[31m  F.hasBranding = r.has_branding;\u001b[39m\n\u001b[31m  F.city = r.city || '';·\u001b[39m\n\u001b[31m  _hydratePhotosFromRow(r);·\u001b[39m\n\u001b[31m  openManual('');\u001b[39m\n\u001b[31m  document.getElementById('f-date').value = F.date;\u001b[39m\n\u001b[31m  if (F.brand) document.getElementById('f-brand').value = F.brand;\u001b[39m\n\u001b[31m  if (F.storeName) document.getElementById('f-store').value = F.storeName;\u001b[39m\n\u001b[31m  if (F.address) document.getElementById('f-addr').value = F.address;\u001b[39m\n\u001b[31m  if (F.mobile) document.getElementById('f-mobile').value = F.mobile;\u001b[39m\n\u001b[31m  if (F.hasVideo !== undefined) setVideo(F.hasVideo);\u001b[39m\n\u001b[31m  if (F.hasBranding !== undefined) setBranding(F.hasBranding);\u001b[39m\n\u001b[31m  if (F.clientName) autoSetClient(F.clientName);\u001b[39m\n\u001b[31m  renderClientChips();\u001b[39m\n\u001b[31m  renderPhotos('front'); renderPhotos('inside'); renderBrandings(); renderAddl(); updAvailTag();\u001b[39m\n\u001b[31m  toast('Loaded — existing photos shown, tap ↺ to replace', 'info');\u001b[39m\n\u001b[31m  showView('form-store');\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31m// ── End edit request ─────────────────────────────────────────────────────────·\u001b[39m\n\u001b[31mfunction goToHub() { window.location.href = '/hub/'; }\u001b[39m\n\u001b[31mfunction recceLogout() {\u001b[39m\n\u001b[31m  if (!confirm('Log out?')) return;\u001b[39m\n\u001b[31m  localStorage.removeItem('lm360-session');\u001b[39m\n\u001b[31m  localStorage.removeItem('360exp-session');\u001b[39m\n\u001b[31m  window.location.href = '/hub/';\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction injectHubButtons() {\u001b[39m\n\u001b[31m  const u = _recceHubUser();\u001b[39m\n\u001b[31m  const name = u ? (u.name || '') : '';\u001b[39m\n\u001b[31m  if (name) {\u001b[39m\n\u001b[31m    const bar = document.getElementById('recce-hero-ubar');\u001b[39m\n\u001b[31m    const nm  = document.getElementById('recce-hero-name');\u001b[39m\n\u001b[31m    if (bar) { nm.textContent = name; bar.style.display = 'flex'; }\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m  document.querySelectorAll('.hdr').forEach(hdr => {\u001b[39m\n\u001b[31m    const r = document.createElement('div');\u001b[39m\n\u001b[31m    r.className = 'hdr-r';\u001b[39m\n\u001b[31m    if (name) {\u001b[39m\n\u001b[31m      const un = document.createElement('span');\u001b[39m\n\u001b[31m      un.className = 'hdr-user';\u001b[39m\n\u001b[31m      un.textContent = name;\u001b[39m\n\u001b[31m      r.appendChild(un);\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    const hub = document.createElement('button');\u001b[39m\n\u001b[31m    hub.className = 'btn-hub';\u001b[39m\n\u001b[31m    hub.innerHTML = '🏡 Hub';\u001b[39m\n\u001b[31m    hub.addEventListener('click', goToHub);\u001b[39m\n\u001b[31m    r.appendChild(hub);\u001b[39m\n\u001b[31m    const lo = document.createElement('button');\u001b[39m\n\u001b[31m    lo.className = 'btn-logout';\u001b[39m\n\u001b[31m    lo.textContent = 'Logout';\u001b[39m\n\u001b[31m    lo.addEventListener('click', recceLogout);\u001b[39m\n\u001b[31m    r.appendChild(lo);\u001b[39m\n\u001b[31m    hdr.appendChild(r);\u001b[39m\n\u001b[31m  });\u001b[39m\n\u001b[31m}·\u001b[39m\n\u001b[31mfunction checkAppUpdate(){\u001b[39m\n\u001b[31m  const seen=localStorage.getItem('recce-ver-seen');\u001b[39m\n\u001b[31m  localStorage.setItem('recce-ver-seen',CACHE_VER);\u001b[39m\n\u001b[31m  if(seen&&seen!==CACHE_VER){\u001b[39m\n\u001b[31m    const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m    if(b){b.classList.add('show');setTimeout(()=>b.classList.remove('show'),5000);}\u001b[39m\n\u001b[31m  }\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31mfunction dismissUpdateBanner(){\u001b[39m\n\u001b[31m  const b=document.getElementById('upd-banner');\u001b[39m\n\u001b[31m  if(b)b.classList.remove('show');\u001b[39m\n\u001b[31m}\u001b[39m\n\u001b[31masync function init(){\u001b[39m\n\u001b[31m  // Detect host banners (tiiny.host, etc) and raise bnav above them\u001b[39m\n\u001b[31m  (function detectHostBar(){\u001b[39m\n\u001b[31m    const h=window.location.hostname;\u001b[39m\n\u001b[31m    let extra=0;\u001b[39m\n\u001b[31m    if(h.includes('tiiny'))extra=58;\u001b[39m\n\u001b[31m    else{\u001b[39m\n\u001b[31m      // Generic detection: check if window is shorter than expected (host injected a bar)\u001b[39m\n\u001b[31m      const gap=screen.height - window.innerHeight;\u001b[39m\n\u001b[31m      if(gap>100&&gap<200)extra=58; // a fixed bar is roughly 56-60px\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m    if(extra>0){\u001b[39m\n\u001b[31m      document.documentElement.style.setProperty('--host-bar',extra+'px');\u001b[39m\n\u001b[31m    }\u001b[39m\n\u001b[31m  })();\u001b[39m\n\u001b[31m  setLang(LANG);\u001b[39m\n\u001b[31m  applyFontSize();\u001b[39m\n\u001b[31m  checkAppUpdate();\u001b[39m\n\u001b[31m  await loadRecceCfg();\u001b[39m\n\u001b[31m  _checkAccessMode();\u001b[39m\n\u001b[31m  await initDB();await loadSettings();await loadHome();await checkDraft();netStatus();window.addEventListener('online',()=>{netStatus();syncNow();});window.addEventListener('offline',netStatus);injectHubButtons();document.getElementById('today-date').textContent=new Date().toLocaleDateString('en-IN',{weekday:'long',day:'numeric',month:'long',year:'numeric'});updAvailTag();\u001b[39m\n\u001b[31m  renderSupPanel();\u001b[39m\n\u001b[31m  // Auto-fetch stores from server on every startup (uses default Netlify URL if none saved)\u001b[39m\n\u001b[31m  const su=(await cfg('srv-url'))||DEFAULT_STORES_URL;\u001b[39m\n\u001b[31m  if(su&&navigator.onLine){\u001b[39m\n\u001b[31m    fetch(su).then(r=>r.json()).then(async j=>{\u001b[39m\n\u001b[31m      const d=Array.isArray(j)?j:j.stores||[];\u001b[39m\n\u001b[31m      if(d.length){stores=d;await cfg('stores',JSON.stringify(d));await cfg('srv-url',su);updAvailTag();\u001b[39m\n\u001b[31m        document.getElementById('srv-url').value=su;}\u001b[39m\n\u001b[31m    }).catch(()=>{});\u001b[39m\n\u001b[31m  }}init();\u001b[39m\n\u001b[31m</script>\u001b[39m\n\u001b[31m</body>\u001b[39m\n\u001b[31m</html>\u001b[39m\n\u001b[31m\"\u001b[39m\n\n  335 |     const resp = await page.request.get(BASE_URL);\n  336 |     const src = await resp.text();\n> 337 |     expect(src).toContain('recce-v15');\n      |                 ^\n  338 |     expect(src).not.toContain('recce-v14');\n  339 |   });\n  340 | });\n    at /var/www/360lm/tests/recce.spec.js:337:17"
                        }
                      ],
                      "stdout": [],
                      "stderr": [],
                      "retry": 1,
                      "startTime": "2026-05-28T12:48:41.725Z",
                      "annotations": [],
                      "attachments": [
                        {
                          "name": "screenshot",
                          "contentType": "image/png",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v10-dbf60-tos-SW-version-is-recce-v15-desktop-chrome-retry1/test-failed-1.png"
                        },
                        {
                          "name": "error-context",
                          "contentType": "text/markdown",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v10-dbf60-tos-SW-version-is-recce-v15-desktop-chrome-retry1/error-context.md"
                        }
                      ],
                      "errorLocation": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "column": 17,
                        "line": 337
                      }
                    }
                  ],
                  "status": "unexpected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-3c265e083925f4819dfa",
              "file": "recce.spec.js",
              "line": 334,
              "column": 3
            }
          ]
        },
        {
          "title": "Branding Recce — v11 Restore Deleted Recce",
          "file": "recce.spec.js",
          "line": 343,
          "column": 6,
          "specs": [
            {
              "title": "restore-btn present on deleted cards for admin",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 350,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12944,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:44:32.593Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 350,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-6463bebd75c84f09c335",
              "file": "recce.spec.js",
              "line": 348,
              "column": 3
            },
            {
              "title": "restore-btn has green outline style (not red)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 365,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12583,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:44:45.819Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 365,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-48a07d43216b73bf9ac2",
              "file": "recce.spec.js",
              "line": 363,
              "column": 3
            },
            {
              "title": "restore source contains restoreRecce function",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 286,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:44:58.455Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-d74f1b14ccdf5c810915",
              "file": "recce.spec.js",
              "line": 375,
              "column": 3
            },
            {
              "title": "restore-btn present on deleted cards for admin",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 350,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 13119,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:48:44.287Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 350,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-e40fa3249ad2fc9f04a6",
              "file": "recce.spec.js",
              "line": 348,
              "column": 3
            },
            {
              "title": "restore-btn has green outline style (not red)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 365,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12822,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:48:57.664Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 365,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-490192bede51abdc7aba",
              "file": "recce.spec.js",
              "line": 363,
              "column": 3
            },
            {
              "title": "restore source contains restoreRecce function",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 268,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:10.562Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-26f3d4e4c96bc271855f",
              "file": "recce.spec.js",
              "line": 375,
              "column": 3
            }
          ]
        },
        {
          "title": "Branding Recce — v9 Sync Text (B5)",
          "file": "recce.spec.js",
          "line": 384,
          "column": 6,
          "specs": [
            {
              "title": "B5: last-sync-txt shows \"Loaded HH:MM\" after admin fetch",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 391,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12653,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:44:58.801Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 391,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-5d8091a756965e8306bc",
              "file": "recce.spec.js",
              "line": 389,
              "column": 3
            },
            {
              "title": "B5: last-sync-txt shows \"Loaded HH:MM\" after admin fetch",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [
                    {
                      "type": "skip",
                      "location": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "line": 391,
                        "column": 21
                      }
                    }
                  ],
                  "expectedStatus": "skipped",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "skipped",
                      "duration": 12539,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:10.862Z",
                      "annotations": [
                        {
                          "type": "skip",
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "line": 391,
                            "column": 21
                          }
                        }
                      ],
                      "attachments": []
                    }
                  ],
                  "status": "skipped"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-bcbabcaa47cb3989fcce",
              "file": "recce.spec.js",
              "line": 389,
              "column": 3
            }
          ]
        },
        {
          "title": "Branding Recce — v12 Supervisor Landing",
          "file": "recce.spec.js",
          "line": 399,
          "column": 6,
          "specs": [
            {
              "title": "supervisor sees 2 tiles on home",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 711,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:11.504Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-32dd12189820e577cc28",
              "file": "recce.spec.js",
              "line": 404,
              "column": 3
            },
            {
              "title": "first tile shows View All Recces label",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 786,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:12.264Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-76b71c62781d8f598e1b",
              "file": "recce.spec.js",
              "line": 411,
              "column": 3
            },
            {
              "title": "second tile shows Create Recce label",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 918,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:13.073Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-a225d403ad501b14b4c1",
              "file": "recce.spec.js",
              "line": 419,
              "column": 3
            },
            {
              "title": "new-btn is hidden on supervisor landing",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1071,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:14.022Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-7f134ebb5d9b57ad146f",
              "file": "recce.spec.js",
              "line": 427,
              "column": 3
            },
            {
              "title": "View All Recces tile opens admin list with back button",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1363,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:15.146Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-e54999ec840db1c59e8e",
              "file": "recce.spec.js",
              "line": 435,
              "column": 3
            },
            {
              "title": "source contains renderSupLanding and _isSupervisor",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 194,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:16.553Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-98438642e8d641f2a6c3",
              "file": "recce.spec.js",
              "line": 449,
              "column": 3
            },
            {
              "title": "supervisor sees 2 tiles on home",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 582,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:23.430Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-66b7a0ac658e6bcb2278",
              "file": "recce.spec.js",
              "line": 404,
              "column": 3
            },
            {
              "title": "first tile shows View All Recces label",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 510,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:24.031Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-09892f9b1425f01edfcd",
              "file": "recce.spec.js",
              "line": 411,
              "column": 3
            },
            {
              "title": "second tile shows Create Recce label",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 528,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:24.566Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-442562ce9f25ea586725",
              "file": "recce.spec.js",
              "line": 419,
              "column": 3
            },
            {
              "title": "new-btn is hidden on supervisor landing",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 522,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:25.110Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-5649d411bb93d21e8200",
              "file": "recce.spec.js",
              "line": 427,
              "column": 3
            },
            {
              "title": "View All Recces tile opens admin list with back button",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 655,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:25.655Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-b0d82362c6dae755428a",
              "file": "recce.spec.js",
              "line": 435,
              "column": 3
            },
            {
              "title": "source contains renderSupLanding and _isSupervisor",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 163,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:26.334Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-241d52c1c2b7615b4413",
              "file": "recce.spec.js",
              "line": 449,
              "column": 3
            }
          ]
        },
        {
          "title": "Branding Recce — v13 Supervisor Landing Bug Fixes",
          "file": "recce.spec.js",
          "line": 459,
          "column": 6,
          "specs": [
            {
              "title": "filter bar hidden on supervisor landing (STEP1-BUG-01)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 914,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:16.785Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-621c573624d7b4830de2",
              "file": "recce.spec.js",
              "line": 464,
              "column": 3
            },
            {
              "title": "filter bar reappears when View All Recces tapped again",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1070,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:17.730Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-17234def6ac6ea19ef0c",
              "file": "recce.spec.js",
              "line": 480,
              "column": 3
            },
            {
              "title": "source contains checkDraft call in exitSaveAndLeave (STEP3-BUG-01)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 228,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:18.836Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-e7554596fa1c08be9fe1",
              "file": "recce.spec.js",
              "line": 493,
              "column": 3
            },
            {
              "title": "filter bar hidden on supervisor landing (STEP1-BUG-01)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 702,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:26.517Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-5a3debfe5e2edf742e2a",
              "file": "recce.spec.js",
              "line": 464,
              "column": 3
            },
            {
              "title": "filter bar reappears when View All Recces tapped again",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 926,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:27.240Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-925c12b205b25c5229a9",
              "file": "recce.spec.js",
              "line": 480,
              "column": 3
            },
            {
              "title": "source contains checkDraft call in exitSaveAndLeave (STEP3-BUG-01)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 226,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:28.209Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-5db89deff03f0e8f9479",
              "file": "recce.spec.js",
              "line": 493,
              "column": 3
            }
          ]
        },
        {
          "title": "Branding Recce — Logout clears both session keys",
          "file": "recce.spec.js",
          "line": 506,
          "column": 6,
          "specs": [
            {
              "title": "after logout lm360-session is removed",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1001,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:19.105Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-b70f817f31b4f076a866",
              "file": "recce.spec.js",
              "line": 521,
              "column": 3
            },
            {
              "title": "after logout 360exp-session is also removed",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 860,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:20.160Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-98b8db8009e20bf40780",
              "file": "recce.spec.js",
              "line": 532,
              "column": 3
            },
            {
              "title": "hub shows PIN login screen after logout (not auto-logged in)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 2628,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:21.059Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-1376d88785c5b76b34f2",
              "file": "recce.spec.js",
              "line": 543,
              "column": 3
            },
            {
              "title": "dismiss logout confirm — session keys remain intact",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 948,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:23.728Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-a5b5547327cdf1e068fe",
              "file": "recce.spec.js",
              "line": 554,
              "column": 3
            },
            {
              "title": "after logout lm360-session is removed",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 750,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:28.482Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-14c414fd5c58b50e6599",
              "file": "recce.spec.js",
              "line": 521,
              "column": 3
            },
            {
              "title": "after logout 360exp-session is also removed",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 664,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:29.269Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-f083ec7a412bc4c45386",
              "file": "recce.spec.js",
              "line": 532,
              "column": 3
            },
            {
              "title": "hub shows PIN login screen after logout (not auto-logged in)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 2469,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:29.956Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-aa34efb0cf330169da86",
              "file": "recce.spec.js",
              "line": 543,
              "column": 3
            },
            {
              "title": "dismiss logout confirm — session keys remain intact",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 553,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:32.447Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-1e1deb52d1442d3306f2",
              "file": "recce.spec.js",
              "line": 554,
              "column": 3
            }
          ]
        },
        {
          "title": "Branding Recce — v14 Create Recce Field Agent View",
          "file": "recce.spec.js",
          "line": 569,
          "column": 6,
          "specs": [
            {
              "title": "Create Recce tile shows New Recce button (not direct form)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1001,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:24.702Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-639d22b29d5715c5156a",
              "file": "recce.spec.js",
              "line": 574,
              "column": 3
            },
            {
              "title": "Create Recce tile shows Back to Menu button",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 778,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:25.730Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-8b35e4667b05b9e62170",
              "file": "recce.spec.js",
              "line": 583,
              "column": 3
            },
            {
              "title": "Back to Menu on create view returns to supervisor landing",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 883,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:26.552Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-81cd562a3f5f0fb739dd",
              "file": "recce.spec.js",
              "line": 591,
              "column": 3
            },
            {
              "title": "source contains supervisorCreateView and _supCreateMode",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 187,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:27.464Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-eaea6dabebff3c0fb5cd",
              "file": "recce.spec.js",
              "line": 604,
              "column": 3
            },
            {
              "title": "Create Recce tile shows New Recce button (not direct form)",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 565,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:33.022Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-8c60b15037d387364f6b",
              "file": "recce.spec.js",
              "line": 574,
              "column": 3
            },
            {
              "title": "Create Recce tile shows Back to Menu button",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 622,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:33.608Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-668163584e360b5f816d",
              "file": "recce.spec.js",
              "line": 583,
              "column": 3
            },
            {
              "title": "Back to Menu on create view returns to supervisor landing",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 695,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:34.249Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-878f55edf147f3cf32b7",
              "file": "recce.spec.js",
              "line": 591,
              "column": 3
            },
            {
              "title": "source contains supervisorCreateView and _supCreateMode",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 153,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:34.961Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-16d2fc1b7e5fb8249617",
              "file": "recce.spec.js",
              "line": 604,
              "column": 3
            }
          ]
        },
        {
          "title": "Branding Recce — v15 Client Field",
          "file": "recce.spec.js",
          "line": 613,
          "column": 6,
          "specs": [
            {
              "title": "source contains client_name field and renderClientChips",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 152,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:27.682Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-8664dc05f6f0af92aa01",
              "file": "recce.spec.js",
              "line": 614,
              "column": 3
            },
            {
              "title": "client chip grid is present in form DOM",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 10587,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:27.853Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-1fe499ea1a43aa73afb9",
              "file": "recce.spec.js",
              "line": 623,
              "column": 3
            },
            {
              "title": "Other chip appears and reveals text input when clicked",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 11052,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:38.479Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-0c481fa381af20546351",
              "file": "recce.spec.js",
              "line": 634,
              "column": 3
            },
            {
              "title": "Next blocked and toast shown when no client selected",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 1357,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:49.548Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-5355a5f858f2ec3031e8",
              "file": "recce.spec.js",
              "line": 653,
              "column": 3
            },
            {
              "title": "admin filter bar source contains af-client dropdown",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 397,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:50.973Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-15afe091c5c5b8810043",
              "file": "recce.spec.js",
              "line": 679,
              "column": 3
            },
            {
              "title": "Group: Client option exists in group selector",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 208,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:51.468Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-96b51059abc9e575731d",
              "file": "recce.spec.js",
              "line": 687,
              "column": 3
            },
            {
              "title": "settings panel has client management section",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 254,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:51.700Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-ca077ad27f6361add759",
              "file": "recce.spec.js",
              "line": 694,
              "column": 3
            },
            {
              "title": "recce-cfg.json contains clients array",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 180,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:52.013Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-c75d823bca0e44a233a6",
              "file": "recce.spec.js",
              "line": 702,
              "column": 3
            },
            {
              "title": "source contains client_name field and renderClientChips",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 193,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:35.135Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-1e55a38eb3040c5f54bb",
              "file": "recce.spec.js",
              "line": 614,
              "column": 3
            },
            {
              "title": "client chip grid is present in form DOM",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 10386,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:35.349Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-376d9e9178e5cfe587ea",
              "file": "recce.spec.js",
              "line": 623,
              "column": 3
            },
            {
              "title": "Other chip appears and reveals text input when clicked",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 10573,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:45.747Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-e81e760851b52970239a",
              "file": "recce.spec.js",
              "line": 634,
              "column": 3
            },
            {
              "title": "Next blocked and toast shown when no client selected",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 883,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:56.333Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-87c1674be7b4292ccd02",
              "file": "recce.spec.js",
              "line": 653,
              "column": 3
            },
            {
              "title": "admin filter bar source contains af-client dropdown",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 133,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:57.231Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-2bb858090bb9f7bd31bf",
              "file": "recce.spec.js",
              "line": 679,
              "column": 3
            },
            {
              "title": "Group: Client option exists in group selector",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 142,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:57.375Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-76259ca18815bc0b4f5d",
              "file": "recce.spec.js",
              "line": 687,
              "column": 3
            },
            {
              "title": "settings panel has client management section",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 187,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:57.535Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-f9196413e362edc15f28",
              "file": "recce.spec.js",
              "line": 694,
              "column": 3
            },
            {
              "title": "recce-cfg.json contains clients array",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 133,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:57.735Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-019d6edb9b3f2d5d487f",
              "file": "recce.spec.js",
              "line": 702,
              "column": 3
            }
          ]
        },
        {
          "title": "Branding Recce — v36/v37 Campaign + Approval Features",
          "file": "recce.spec.js",
          "line": 710,
          "column": 6,
          "specs": [
            {
              "title": "SW cache is recce-v37",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 27,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:52.209Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-fc4afaa84844e2ed78b8",
              "file": "recce.spec.js",
              "line": 711,
              "column": 3
            },
            {
              "title": "source contains campaign dropdown elements and helpers",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 31,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:52.250Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-7de6f8071f72ab3bc529",
              "file": "recce.spec.js",
              "line": 719,
              "column": 3
            },
            {
              "title": "campaign dropdown exists in form-store DOM",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 12591,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:45:52.294Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-be9782b6d75792e6efcd",
              "file": "recce.spec.js",
              "line": 731,
              "column": 3
            },
            {
              "title": "source contains branding lock banner and override",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 36,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:04.915Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-65db8b20579bfdb75f23",
              "file": "recce.spec.js",
              "line": 742,
              "column": 3
            },
            {
              "title": "branding lock banner is in form-branding view DOM",
              "ok": false,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 2,
                      "parallelIndex": 0,
                      "status": "failed",
                      "duration": 5849,
                      "error": {
                        "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#branding-lock-banner')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#branding-lock-banner')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n",
                        "stack": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#branding-lock-banner')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#branding-lock-banner')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n    at /var/www/360lm/tests/recce.spec.js:755:57",
                        "location": {
                          "file": "/var/www/360lm/tests/recce.spec.js",
                          "column": 57,
                          "line": 755
                        },
                        "snippet": "  753 |   test('branding lock banner is in form-branding view DOM', async ({ page }) => {\n  754 |     await page.goto(BASE_URL);\n> 755 |     await expect(page.locator('#branding-lock-banner')).toHaveCount(1);\n      |                                                         ^\n  756 |     // Hidden by default (not locked on fresh load)\n  757 |     await expect(page.locator('#branding-lock-banner')).toBeHidden();\n  758 |   });"
                      },
                      "errors": [
                        {
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "column": 57,
                            "line": 755
                          },
                          "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#branding-lock-banner')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#branding-lock-banner')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n\n  753 |   test('branding lock banner is in form-branding view DOM', async ({ page }) => {\n  754 |     await page.goto(BASE_URL);\n> 755 |     await expect(page.locator('#branding-lock-banner')).toHaveCount(1);\n      |                                                         ^\n  756 |     // Hidden by default (not locked on fresh load)\n  757 |     await expect(page.locator('#branding-lock-banner')).toBeHidden();\n  758 |   });\n    at /var/www/360lm/tests/recce.spec.js:755:57"
                        }
                      ],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:04.976Z",
                      "annotations": [],
                      "attachments": [
                        {
                          "name": "screenshot",
                          "contentType": "image/png",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-70ae7-s-in-form-branding-view-DOM-android-chrome/test-failed-1.png"
                        },
                        {
                          "name": "error-context",
                          "contentType": "text/markdown",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-70ae7-s-in-form-branding-view-DOM-android-chrome/error-context.md"
                        }
                      ],
                      "errorLocation": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "column": 57,
                        "line": 755
                      }
                    },
                    {
                      "workerIndex": 3,
                      "parallelIndex": 0,
                      "status": "failed",
                      "duration": 6020,
                      "error": {
                        "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#branding-lock-banner')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#branding-lock-banner')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n",
                        "stack": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#branding-lock-banner')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#branding-lock-banner')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n    at /var/www/360lm/tests/recce.spec.js:755:57",
                        "location": {
                          "file": "/var/www/360lm/tests/recce.spec.js",
                          "column": 57,
                          "line": 755
                        },
                        "snippet": "  753 |   test('branding lock banner is in form-branding view DOM', async ({ page }) => {\n  754 |     await page.goto(BASE_URL);\n> 755 |     await expect(page.locator('#branding-lock-banner')).toHaveCount(1);\n      |                                                         ^\n  756 |     // Hidden by default (not locked on fresh load)\n  757 |     await expect(page.locator('#branding-lock-banner')).toBeHidden();\n  758 |   });"
                      },
                      "errors": [
                        {
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "column": 57,
                            "line": 755
                          },
                          "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#branding-lock-banner')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#branding-lock-banner')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n\n  753 |   test('branding lock banner is in form-branding view DOM', async ({ page }) => {\n  754 |     await page.goto(BASE_URL);\n> 755 |     await expect(page.locator('#branding-lock-banner')).toHaveCount(1);\n      |                                                         ^\n  756 |     // Hidden by default (not locked on fresh load)\n  757 |     await expect(page.locator('#branding-lock-banner')).toBeHidden();\n  758 |   });\n    at /var/www/360lm/tests/recce.spec.js:755:57"
                        }
                      ],
                      "stdout": [],
                      "stderr": [],
                      "retry": 1,
                      "startTime": "2026-05-28T12:46:12.102Z",
                      "annotations": [],
                      "attachments": [
                        {
                          "name": "screenshot",
                          "contentType": "image/png",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-70ae7-s-in-form-branding-view-DOM-android-chrome-retry1/test-failed-1.png"
                        },
                        {
                          "name": "error-context",
                          "contentType": "text/markdown",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-70ae7-s-in-form-branding-view-DOM-android-chrome-retry1/error-context.md"
                        }
                      ],
                      "errorLocation": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "column": 57,
                        "line": 755
                      }
                    }
                  ],
                  "status": "unexpected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-55bd5d2613db61a4214c",
              "file": "recce.spec.js",
              "line": 753,
              "column": 3
            },
            {
              "title": "source contains pending job tab, link job modal, archiving",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 4,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 179,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:19.637Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-bf977b6024f1f78c8c05",
              "file": "recce.spec.js",
              "line": 760,
              "column": 3
            },
            {
              "title": "source contains client_status admin badges",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 4,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 33,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:19.914Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-b9e5a52b0ffe1706a1ca",
              "file": "recce.spec.js",
              "line": 773,
              "column": 3
            },
            {
              "title": "link-job modal exists in DOM",
              "ok": false,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "android-chrome",
                  "projectName": "android-chrome",
                  "results": [
                    {
                      "workerIndex": 4,
                      "parallelIndex": 0,
                      "status": "failed",
                      "duration": 6371,
                      "error": {
                        "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#modal-link-job')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#modal-link-job')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n",
                        "stack": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#modal-link-job')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#modal-link-job')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n    at /var/www/360lm/tests/recce.spec.js:786:51",
                        "location": {
                          "file": "/var/www/360lm/tests/recce.spec.js",
                          "column": 51,
                          "line": 786
                        },
                        "snippet": "  784 |   test('link-job modal exists in DOM', async ({ page }) => {\n  785 |     await page.goto(BASE_URL);\n> 786 |     await expect(page.locator('#modal-link-job')).toHaveCount(1);\n      |                                                   ^\n  787 |     await expect(page.locator('#link-job-sel')).toHaveCount(1);\n  788 |   });\n  789 | });"
                      },
                      "errors": [
                        {
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "column": 51,
                            "line": 786
                          },
                          "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#modal-link-job')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#modal-link-job')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n\n  784 |   test('link-job modal exists in DOM', async ({ page }) => {\n  785 |     await page.goto(BASE_URL);\n> 786 |     await expect(page.locator('#modal-link-job')).toHaveCount(1);\n      |                                                   ^\n  787 |     await expect(page.locator('#link-job-sel')).toHaveCount(1);\n  788 |   });\n  789 | });\n    at /var/www/360lm/tests/recce.spec.js:786:51"
                        }
                      ],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:46:20.016Z",
                      "annotations": [],
                      "attachments": [
                        {
                          "name": "screenshot",
                          "contentType": "image/png",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-30656-ink-job-modal-exists-in-DOM-android-chrome/test-failed-1.png"
                        },
                        {
                          "name": "error-context",
                          "contentType": "text/markdown",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-30656-ink-job-modal-exists-in-DOM-android-chrome/error-context.md"
                        }
                      ],
                      "errorLocation": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "column": 51,
                        "line": 786
                      }
                    },
                    {
                      "workerIndex": 5,
                      "parallelIndex": 0,
                      "status": "failed",
                      "duration": 6168,
                      "error": {
                        "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#modal-link-job')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#modal-link-job')\u001b[22m\n\u001b[2m    13 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n",
                        "stack": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#modal-link-job')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#modal-link-job')\u001b[22m\n\u001b[2m    13 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n    at /var/www/360lm/tests/recce.spec.js:786:51",
                        "location": {
                          "file": "/var/www/360lm/tests/recce.spec.js",
                          "column": 51,
                          "line": 786
                        },
                        "snippet": "  784 |   test('link-job modal exists in DOM', async ({ page }) => {\n  785 |     await page.goto(BASE_URL);\n> 786 |     await expect(page.locator('#modal-link-job')).toHaveCount(1);\n      |                                                   ^\n  787 |     await expect(page.locator('#link-job-sel')).toHaveCount(1);\n  788 |   });\n  789 | });"
                      },
                      "errors": [
                        {
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "column": 51,
                            "line": 786
                          },
                          "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#modal-link-job')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#modal-link-job')\u001b[22m\n\u001b[2m    13 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n\n  784 |   test('link-job modal exists in DOM', async ({ page }) => {\n  785 |     await page.goto(BASE_URL);\n> 786 |     await expect(page.locator('#modal-link-job')).toHaveCount(1);\n      |                                                   ^\n  787 |     await expect(page.locator('#link-job-sel')).toHaveCount(1);\n  788 |   });\n  789 | });\n    at /var/www/360lm/tests/recce.spec.js:786:51"
                        }
                      ],
                      "stdout": [],
                      "stderr": [],
                      "retry": 1,
                      "startTime": "2026-05-28T12:46:28.268Z",
                      "annotations": [],
                      "attachments": [
                        {
                          "name": "screenshot",
                          "contentType": "image/png",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-30656-ink-job-modal-exists-in-DOM-android-chrome-retry1/test-failed-1.png"
                        },
                        {
                          "name": "error-context",
                          "contentType": "text/markdown",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-30656-ink-job-modal-exists-in-DOM-android-chrome-retry1/error-context.md"
                        }
                      ],
                      "errorLocation": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "column": 51,
                        "line": 786
                      }
                    }
                  ],
                  "status": "unexpected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-c4e080fd50fc2ef478eb",
              "file": "recce.spec.js",
              "line": 784,
              "column": 3
            },
            {
              "title": "SW cache is recce-v37",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 16,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:57.880Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-5e017fa2b2cec5f3f0ac",
              "file": "recce.spec.js",
              "line": 711,
              "column": 3
            },
            {
              "title": "source contains campaign dropdown elements and helpers",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 14,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:57.906Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-db723a7c281d8e4d2cb4",
              "file": "recce.spec.js",
              "line": 719,
              "column": 3
            },
            {
              "title": "campaign dropdown exists in form-store DOM",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 12407,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:49:57.933Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-8351168d74430d3aabd9",
              "file": "recce.spec.js",
              "line": 731,
              "column": 3
            },
            {
              "title": "source contains branding lock banner and override",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 14,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:50:10.353Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-e17fae73222d6de2acca",
              "file": "recce.spec.js",
              "line": 742,
              "column": 3
            },
            {
              "title": "branding lock banner is in form-branding view DOM",
              "ok": false,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 8,
                      "parallelIndex": 0,
                      "status": "failed",
                      "duration": 5452,
                      "error": {
                        "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#branding-lock-banner')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#branding-lock-banner')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n",
                        "stack": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#branding-lock-banner')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#branding-lock-banner')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n    at /var/www/360lm/tests/recce.spec.js:755:57",
                        "location": {
                          "file": "/var/www/360lm/tests/recce.spec.js",
                          "column": 57,
                          "line": 755
                        },
                        "snippet": "  753 |   test('branding lock banner is in form-branding view DOM', async ({ page }) => {\n  754 |     await page.goto(BASE_URL);\n> 755 |     await expect(page.locator('#branding-lock-banner')).toHaveCount(1);\n      |                                                         ^\n  756 |     // Hidden by default (not locked on fresh load)\n  757 |     await expect(page.locator('#branding-lock-banner')).toBeHidden();\n  758 |   });"
                      },
                      "errors": [
                        {
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "column": 57,
                            "line": 755
                          },
                          "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#branding-lock-banner')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#branding-lock-banner')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n\n  753 |   test('branding lock banner is in form-branding view DOM', async ({ page }) => {\n  754 |     await page.goto(BASE_URL);\n> 755 |     await expect(page.locator('#branding-lock-banner')).toHaveCount(1);\n      |                                                         ^\n  756 |     // Hidden by default (not locked on fresh load)\n  757 |     await expect(page.locator('#branding-lock-banner')).toBeHidden();\n  758 |   });\n    at /var/www/360lm/tests/recce.spec.js:755:57"
                        }
                      ],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:50:10.383Z",
                      "annotations": [],
                      "attachments": [
                        {
                          "name": "screenshot",
                          "contentType": "image/png",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-70ae7-s-in-form-branding-view-DOM-desktop-chrome/test-failed-1.png"
                        },
                        {
                          "name": "error-context",
                          "contentType": "text/markdown",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-70ae7-s-in-form-branding-view-DOM-desktop-chrome/error-context.md"
                        }
                      ],
                      "errorLocation": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "column": 57,
                        "line": 755
                      }
                    },
                    {
                      "workerIndex": 9,
                      "parallelIndex": 0,
                      "status": "failed",
                      "duration": 5612,
                      "error": {
                        "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#branding-lock-banner')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#branding-lock-banner')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n",
                        "stack": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#branding-lock-banner')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#branding-lock-banner')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n    at /var/www/360lm/tests/recce.spec.js:755:57",
                        "location": {
                          "file": "/var/www/360lm/tests/recce.spec.js",
                          "column": 57,
                          "line": 755
                        },
                        "snippet": "  753 |   test('branding lock banner is in form-branding view DOM', async ({ page }) => {\n  754 |     await page.goto(BASE_URL);\n> 755 |     await expect(page.locator('#branding-lock-banner')).toHaveCount(1);\n      |                                                         ^\n  756 |     // Hidden by default (not locked on fresh load)\n  757 |     await expect(page.locator('#branding-lock-banner')).toBeHidden();\n  758 |   });"
                      },
                      "errors": [
                        {
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "column": 57,
                            "line": 755
                          },
                          "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#branding-lock-banner')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#branding-lock-banner')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n\n  753 |   test('branding lock banner is in form-branding view DOM', async ({ page }) => {\n  754 |     await page.goto(BASE_URL);\n> 755 |     await expect(page.locator('#branding-lock-banner')).toHaveCount(1);\n      |                                                         ^\n  756 |     // Hidden by default (not locked on fresh load)\n  757 |     await expect(page.locator('#branding-lock-banner')).toBeHidden();\n  758 |   });\n    at /var/www/360lm/tests/recce.spec.js:755:57"
                        }
                      ],
                      "stdout": [],
                      "stderr": [],
                      "retry": 1,
                      "startTime": "2026-05-28T12:50:16.799Z",
                      "annotations": [],
                      "attachments": [
                        {
                          "name": "screenshot",
                          "contentType": "image/png",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-70ae7-s-in-form-branding-view-DOM-desktop-chrome-retry1/test-failed-1.png"
                        },
                        {
                          "name": "error-context",
                          "contentType": "text/markdown",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-70ae7-s-in-form-branding-view-DOM-desktop-chrome-retry1/error-context.md"
                        }
                      ],
                      "errorLocation": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "column": 57,
                        "line": 755
                      }
                    }
                  ],
                  "status": "unexpected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-ddb3ddc4610757fd8ddb",
              "file": "recce.spec.js",
              "line": 753,
              "column": 3
            },
            {
              "title": "source contains pending job tab, link job modal, archiving",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 10,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 60,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:50:23.501Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-296a5f80cf12fccb204c",
              "file": "recce.spec.js",
              "line": 760,
              "column": 3
            },
            {
              "title": "source contains client_status admin badges",
              "ok": true,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 10,
                      "parallelIndex": 0,
                      "status": "passed",
                      "duration": 32,
                      "errors": [],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:50:23.603Z",
                      "annotations": [],
                      "attachments": []
                    }
                  ],
                  "status": "expected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-4b9b0923e6fbc9ac200f",
              "file": "recce.spec.js",
              "line": 773,
              "column": 3
            },
            {
              "title": "link-job modal exists in DOM",
              "ok": false,
              "tags": [],
              "tests": [
                {
                  "timeout": 30000,
                  "annotations": [],
                  "expectedStatus": "passed",
                  "projectId": "desktop-chrome",
                  "projectName": "desktop-chrome",
                  "results": [
                    {
                      "workerIndex": 10,
                      "parallelIndex": 0,
                      "status": "failed",
                      "duration": 5543,
                      "error": {
                        "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#modal-link-job')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#modal-link-job')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n",
                        "stack": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#modal-link-job')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#modal-link-job')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n    at /var/www/360lm/tests/recce.spec.js:786:51",
                        "location": {
                          "file": "/var/www/360lm/tests/recce.spec.js",
                          "column": 51,
                          "line": 786
                        },
                        "snippet": "  784 |   test('link-job modal exists in DOM', async ({ page }) => {\n  785 |     await page.goto(BASE_URL);\n> 786 |     await expect(page.locator('#modal-link-job')).toHaveCount(1);\n      |                                                   ^\n  787 |     await expect(page.locator('#link-job-sel')).toHaveCount(1);\n  788 |   });\n  789 | });"
                      },
                      "errors": [
                        {
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "column": 51,
                            "line": 786
                          },
                          "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#modal-link-job')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#modal-link-job')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n\n  784 |   test('link-job modal exists in DOM', async ({ page }) => {\n  785 |     await page.goto(BASE_URL);\n> 786 |     await expect(page.locator('#modal-link-job')).toHaveCount(1);\n      |                                                   ^\n  787 |     await expect(page.locator('#link-job-sel')).toHaveCount(1);\n  788 |   });\n  789 | });\n    at /var/www/360lm/tests/recce.spec.js:786:51"
                        }
                      ],
                      "stdout": [],
                      "stderr": [],
                      "retry": 0,
                      "startTime": "2026-05-28T12:50:23.677Z",
                      "annotations": [],
                      "attachments": [
                        {
                          "name": "screenshot",
                          "contentType": "image/png",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-30656-ink-job-modal-exists-in-DOM-desktop-chrome/test-failed-1.png"
                        },
                        {
                          "name": "error-context",
                          "contentType": "text/markdown",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-30656-ink-job-modal-exists-in-DOM-desktop-chrome/error-context.md"
                        }
                      ],
                      "errorLocation": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "column": 51,
                        "line": 786
                      }
                    },
                    {
                      "workerIndex": 11,
                      "parallelIndex": 0,
                      "status": "failed",
                      "duration": 5643,
                      "error": {
                        "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#modal-link-job')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#modal-link-job')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n",
                        "stack": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#modal-link-job')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#modal-link-job')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n    at /var/www/360lm/tests/recce.spec.js:786:51",
                        "location": {
                          "file": "/var/www/360lm/tests/recce.spec.js",
                          "column": 51,
                          "line": 786
                        },
                        "snippet": "  784 |   test('link-job modal exists in DOM', async ({ page }) => {\n  785 |     await page.goto(BASE_URL);\n> 786 |     await expect(page.locator('#modal-link-job')).toHaveCount(1);\n      |                                                   ^\n  787 |     await expect(page.locator('#link-job-sel')).toHaveCount(1);\n  788 |   });\n  789 | });"
                      },
                      "errors": [
                        {
                          "location": {
                            "file": "/var/www/360lm/tests/recce.spec.js",
                            "column": 51,
                            "line": 786
                          },
                          "message": "Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoHaveCount\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator:  locator('#modal-link-job')\nExpected: \u001b[32m1\u001b[39m\nReceived: \u001b[31m0\u001b[39m\nTimeout:  5000ms\n\nCall log:\n\u001b[2m  - Expect \"toHaveCount\" with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('#modal-link-job')\u001b[22m\n\u001b[2m    14 × locator resolved to 0 elements\u001b[22m\n\u001b[2m       - unexpected value \"0\"\u001b[22m\n\n\n  784 |   test('link-job modal exists in DOM', async ({ page }) => {\n  785 |     await page.goto(BASE_URL);\n> 786 |     await expect(page.locator('#modal-link-job')).toHaveCount(1);\n      |                                                   ^\n  787 |     await expect(page.locator('#link-job-sel')).toHaveCount(1);\n  788 |   });\n  789 | });\n    at /var/www/360lm/tests/recce.spec.js:786:51"
                        }
                      ],
                      "stdout": [],
                      "stderr": [],
                      "retry": 1,
                      "startTime": "2026-05-28T12:50:30.256Z",
                      "annotations": [],
                      "attachments": [
                        {
                          "name": "screenshot",
                          "contentType": "image/png",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-30656-ink-job-modal-exists-in-DOM-desktop-chrome-retry1/test-failed-1.png"
                        },
                        {
                          "name": "error-context",
                          "contentType": "text/markdown",
                          "path": "/var/www/360lm/test-results/recce-Branding-Recce-—-v36-30656-ink-job-modal-exists-in-DOM-desktop-chrome-retry1/error-context.md"
                        }
                      ],
                      "errorLocation": {
                        "file": "/var/www/360lm/tests/recce.spec.js",
                        "column": 51,
                        "line": 786
                      }
                    }
                  ],
                  "status": "unexpected"
                }
              ],
              "id": "bb27ca683ce0a15e9d22-ab14eab4ad22c0bd9512",
              "file": "recce.spec.js",
              "line": 784,
              "column": 3
            }
          ]
        }
      ]
    }
  ],
  "errors": [],
  "stats": {
    "startTime": "2026-05-28T12:42:14.808Z",
    "duration": 501354.545,
    "expected": 98,
    "skipped": 20,
    "unexpected": 6,
    "flaky": 0
  }
}
