{
  "version": 3,
  "sources": ["/cdn/shop/t/12/assets/mimosa-map-necklace.js?mimosa=v18"],
  "sourcesContent": ["/* Moved out of sections/mimosa-talisa-map-necklace.liquid.\n   Shopify caps a single template/section file at 256KB and that file had\n   reached it (a 263,326-byte push was rejected), which blocked any further\n   change. Nothing here was rewritten \u2014 it is the same script, in a file that\n   does not count against the template.\n\n   LOAD ORDER MATTERS. This is a classic (non-module) script, so its\n   top-level declarations share one global lexical scope with the other\n   classic scripts on the page. It must load AFTER:\n     - mimosa-glyphs.js       (MIMOSA_GLYPH_PATHS)\n     - mimosa-shape-rings.js  (MIMOSA_RING_POINTS, MIMOSA_*_OUTER/_INNER)\n     - the inline block in the section that declares MIMOSA_HER_IMAGES and\n       MIMOSA_HIM_IMAGES (those need Liquid's asset_url, so they cannot live\n       in a static file)\n   and AFTER the section's markup, which it reads from on load.\n   Do not add defer/async: that would break both of those orderings. */\n\n  const SINGLE_PRICE = 98.00;\n  const SINGLE_COMPARE = 128.00;\n  const PAIR_PRICE = 98.00;\n  const PAIR_COMPARE = 196.00;\n  const BACKPLATE_PRICE_PAIR = 30.00;\n  const BACKPLATE_PRICE_SINGLE = 15.00;\n  function mimosaBackplateCharge() {\n    return currentSet === 'pair' ? BACKPLATE_PRICE_PAIR : BACKPLATE_PRICE_SINGLE;\n  }\n  function mimosaSyncBackplateUpsellText() {\n    const isPair = currentSet === 'pair';\n    const priceEl = document.getElementById('mimosa-backplate-price');\n    const subEl = document.getElementById('mimosa-backplate-sub');\n    if (priceEl) priceEl.textContent = isPair ? '(+$30)' : '(+$15)';\n    if (subEl) {\n      subEl.textContent = isPair\n        ? 'Two engraved plates \u2014 one for her, one for him. Each layers behind the openwork, or can be worn alone.'\n        : 'One engraved plate that layers behind the openwork, or can be worn alone.';\n    }\n  }\n  let currentSet = 'pair';\n  let backplateOn = false;\n  let mapZoomLevel = 14;\n\n  let isLocationConfirmed = false;\n  let confirmedLocationName = '';\n  let confirmedLocationCoords = null;\n  let isMapTransitioning = false;\n  let mapTransitionTarget = null;\n  let isGeocodingUrl = false;\n  let urlGeocodePromise = null;\n\n  function mimosaShowAddressError(message) {\n    const errEl = document.getElementById('mimosa-address-error');\n    const searchWrap = document.querySelector('.mimosa-map-search-wrap');\n    const input = document.getElementById('mimosa-map-search-input');\n    if (errEl) {\n      const span = errEl.querySelector('span');\n      if (span) span.textContent = message || 'Please select a location from the suggestions to continue.';\n      errEl.style.display = 'flex';\n    }\n    if (searchWrap) searchWrap.classList.add('has-error');\n    if (input) {\n      input.focus();\n      input.scrollIntoView({ behavior: 'smooth', block: 'center' });\n    }\n  }\n\n  function mimosaHideAddressError() {\n    const errEl = document.getElementById('mimosa-address-error');\n    const searchWrap = document.querySelector('.mimosa-map-search-wrap');\n    if (errEl) errEl.style.display = 'none';\n    if (searchWrap) searchWrap.classList.remove('has-error');\n  }\n\n  function mimosaValidateLocationForAtc() {\n    const input = document.getElementById('mimosa-map-search-input');\n    const hiddenLoc = document.getElementById('mimosa-hidden-location');\n    const hiddenCoords = document.getElementById('mimosa-hidden-coords');\n    const typed = (input && input.value ? input.value.trim() : '');\n\n    const isValid = isLocationConfirmed &&\n      Boolean(confirmedLocationName) &&\n      Boolean(typed) &&\n      typed === confirmedLocationName &&\n      Boolean(hiddenLoc && hiddenLoc.value.trim()) &&\n      Boolean(hiddenCoords && hiddenCoords.value.trim());\n\n    if (!isValid) {\n      mimosaShowAddressError('Please select a location from the suggestions to continue.');\n      return false;\n    }\n    mimosaHideAddressError();\n    return true;\n  }\n\n  const MAPBOX_TOKEN = 'pk.eyJ1IjoidGFsaXNhY29ubmVjdCIsImEiOiJjbG00ejlycDgwMG0wM2tsNnQzNnl4ZzZ1In0.e0T3LCiOSEmVKw40gPBrkA';\n  const TALISA_MAP_STYLE_LIGHT = 'mapbox://styles/talisaconnect/clpmijpks00xq01o07iyeccmz'; // Talisa Clean Map View\n  const TALISA_MAP_STYLE_GOLD = 'mapbox://styles/talisaconnect/cmav3ag8c003e01qx1ytjf8ke'; // Talisa 18K Solid Gold Lines on Black Velvet\n  // Muted champagne gold (matches product photo \u2014 not neon yellow)\n  const MAP_LINE_YELLOW = '#C8A84B';\n  const MAP_LINE_SILVER = '#C8D0D8'; // same as jewelry frame\n  const MAP_LAND_WHITE = '#F5F3EF'; // enamel face (matches finished product)\n  let currentMetal = 'gold';\n  let currentDesign = 'openwork'; // locked openwork (cut-through) product\n  let currentStone = 'none';\n  /** Stone seat on pendant face \u2014 % of jewelry map (0\u2013100). Customer can drag. */\n  let stonePos = { x: 50, y: 48 };\n  const STONE_LABELS = { none: 'None', clear: 'Clear CZ', ruby: 'Ruby', sapphire: 'Sapphire', emerald: 'Emerald', amethyst: 'Amethyst', topaz: 'Champagne Topaz' };\n  /** Physical pendant width \u2014 artboard 100 units = 25mm (was 35mm). */\n  const PENDANT_WIDTH_MM = 25;\n  // The His shield is a BIGGER piece than Hers (\"\u7537\u6B3E\u4EA7\u54C1\u6BD4\u5973\u6B3E\u4EA7\u54C1\u5927\u54E6\u00B7\u73B0\u5728\u7684\n  // \u6BD4\u4F8B\u662F\u6B63\u786E\u7684\"): it is drawn at the heart's scale, so its 67-unit span is\n  // 25 x 67 / 61.9 \u2248 27.1mm wide. Treating it as 25mm made every mm-based\n  // feature on His (ribs, stone, slots) ~8% larger than on Hers, and sized the\n  // His factory DXF 8% too small.\n  const MIMOSA_HIS_WIDTH_MM = PENDANT_WIDTH_MM * 67 / 61.9;\n  function mimosaPieceWidthMm(shape) {\n    return shape === 'shield' ? MIMOSA_HIS_WIDTH_MM : PENDANT_WIDTH_MM;\n  }\n  /** Minimum manufacturable street line (mm) \u2014 factory-confirmed etch floor.\n   *  Shared with the factory DXF/SVG export \u2014 do not shrink this to narrow\n   *  the on-screen road gap, or the production file ends up specifying a\n   *  line thinner than the factory can actually cut. */\n  const MIN_LINE_MM = 0.5;\n  /** viewBox stroke for MIN_LINE_MM on the current artboard width */\n  // Artboard units for MIN_LINE_MM. NOT (mm / PENDANT_WIDTH_MM) * 100 \u2014 that\n  // is the same mistake note 57 fixed in mimosaMmToPx: the piece spans ~61.9\n  // of the 100 units, so that formula made the export's minimum-feature\n  // filters think 0.5mm was 2 units when it is 1.24. Everything derived from\n  // it (sliver dropping, the simplify tolerance) was therefore 1.6x too coarse.\n  const MIMOSA_PENDANT_UNITS = 61.9;\n  const MIN_LINE_VB = MIN_LINE_MM * (MIMOSA_PENDANT_UNITS / PENDANT_WIDTH_MM);\n  // Preview road ribbon width (true metres via mimosaPxToMeters \u2014 no 2\u00D7 tile\n  // fudge). Tuned dense to match the finished filigree photo; spacing formula\n  // below must use GAP once (not 2\u00D7GAP), or most streets get culled.\n  // In OPENWORK this is the metal RIB itself (the street is the metal).\n  // Factory floor is MIN_LINE_MM (0.5). Keep ribbons at that floor \u2014 thicker\n  // (and the old morphological bridge) fused neighbouring streets into a\n  // solid blob so the circle read as \"\u6CA1\u6709\u8857\u9053\".\n  const MIMOSA_ROAD_GAP_PREVIEW_MM = MIN_LINE_MM;\n  // Centre-to-centre valley between parallel ribbons. Same 0.5mm floor as\n  // the rib itself: rib + void pitch = 1.0mm \u2192 up to 25 streets on 25mm face.\n  const MIMOSA_ROAD_MIN_SPACING_MM = 0.5;\n  // Open space the road PACKING keeps between parallel ribbons. Separate from\n  // the 0.5mm cutting floor above: packing at the floor filled a zoomed-out\n  // face with streets 1mm apart, the blocks between them fell under the\n  // minimum slot and were filled in, and the preview became solid patches\n  // (\"\u9884\u89C8\u56FE\u4E00\u7F29\u5C0F\u00B7\u5168\u90E8\u662F\u5757\u9762\u7C98\u4F4F\u4E00\u8D77\u00B7\u53EF\u4EE5\u5168\u90E8\u53EA\u51FA\u73B0\u7EBF\u6761\u5417\").\n  // 1.5 then dropped real zoomed-in streets; 0.8 still cut ~9% of Paris street\n  // length at zoom 14 where the gap was cuttable (\"\u4E3A\u4EC0\u4E48\u6709\u4E9B\u8DEF\u65AD\u4E86\u00B7\u660E\u660E\u6709\u4F4D\u7F6E\").\n  // Now the cutting floor: a street is only simplified where it physically\n  // cannot be separated from its neighbour.\n  const MIMOSA_ROAD_PACK_VOID_MM = MIMOSA_ROAD_MIN_SPACING_MM;\n  // Coarsest first. Must match mimosaSimplifiedRoadFilter (incl. local streets).\n  const MIMOSA_ROAD_CLASS_TIERS = [\n    ['motorway', 'trunk', 'motorway_link', 'trunk_link'],\n    ['primary', 'primary_link'],\n    ['secondary', 'secondary_link'],\n    ['tertiary', 'tertiary_link'],\n    ['street', 'street_limited']\n  ];\n  // Water narrower than this on the pendant is left off the piece entirely.\n  const MIMOSA_WATER_MIN_WIDTH_MM = 0.8;\n  // Bridge near-rim stubs without a fat collar. Turned off once (to 0) to stop\n  // edge patches when zoomed out, but that changed the look of the frame and\n  // the user asked for the old frame back (\"\u6539\u56DE\u4EE5\u524D\u7684\u5916\u6846\").\n  const MIMOSA_RIM_CONNECT_MM = 1.0;\n  // The continuous frame along the pendant edge. It is real metal on a cut\n  // piece, so it cannot be under MIN_LINE_MM \u2014 it was 0.40mm.\n  const MIMOSA_RIM_SPINE_MM = 0.5;\n  // The closing pass can span twice this radius. Keep it below half\n  // the 0.5mm cuttable gap so parallel roads cannot merge across it.\n  const MIMOSA_METAL_BRIDGE_MM = 0.12;\n  // ---- Location badge --------------------------------------------------\n  // Location bezel, in REAL millimetres now that mimosaUnitsPerMm and the\n  // 512-tile scale are honest (note: before that fix these drew 3.2x oversize,\n  // which is why 1.4 / 0.5 looked right on screen \u2014 measured, the stone seat\n  // was only 1.0mm across and the metal around it 0.2mm, under MIN_LINE_MM).\n  // 2.0mm stone + MIN_LINE_MM of metal all round = a 3.0mm seat.\n  const MIMOSA_PIN_STONE_MM = 2.0;\n  const MIMOSA_PIN_HOLE_R_MM = MIMOSA_PIN_STONE_MM / 2;\n  // The seat is a COLLAR, not a disc: on the real piece the stone sits in the\n  // metal of a street/river ribbon, so the bezel only has to be a hair bigger\n  // than the stone \u2014 the user's own number, \"\u94BB\u77F3\u53EA\u67092mm\u00B7\u4E0B\u9762\u7684\u5708\u5E94\u8BE5\u53EA\u6709\n  // 2.2mm\". Note this leaves only 0.1mm of collar on its own; it is only\n  // sound where the seat merges into a ribbon, which is how the sample is set.\n  const MIMOSA_PIN_BODY_MM = 2.2;\n  // Through-hole cut in the factory file under the 2mm stone: 1.6mm leaves a\n  // 0.2mm ledge all round for the stone to sit on.\n  const MIMOSA_FACTORY_STONE_HOLE_MM = 1.6;\n  // Solid metal ring round that hole in the CUT file: MIN_LINE_MM (0.5mm) on\n  // each side (\"\u5C31\u662F\u89810.5mm\u5427\"), so the seat is 2.6mm across.\n  const MIMOSA_FACTORY_SEAT_MM = MIMOSA_FACTORY_STONE_HOLE_MM + 2 * MIN_LINE_MM;\n  const MIMOSA_PIN_BRIDGE_MM = MIN_LINE_MM;\n  // Legacy teardrop path kept for Map View marker silhouette only.\n  const MIMOSA_PIN_OUTER_D = 'M28 8.4C19.2 8.4 12.4 15.4 12.4 23.4C12.4 32.6 20.8 42.6 26.2 50.6C26.7 51.4 29.3 51.4 29.8 50.6C35.2 42.6 43.6 32.6 43.6 23.4C43.6 15.4 36.8 8.4 28 8.4Z';\n  const MIMOSA_PIN_LOCAL_W = 31.2;\n  const MIMOSA_PIN_CENTER_X = 28;\n  const MIMOSA_PIN_TIP_Y = 51.4;\n  const MIMOSA_PIN_CIRCLE_CY = 23.8;\n  // Jewelry seat hole ratio (used for factory / openwork geometry sizing).\n  const MIMOSA_PIN_CIRCLE_R = (MIMOSA_PIN_HOLE_R_MM / MIMOSA_PIN_BODY_MM) * MIMOSA_PIN_LOCAL_W;\n  // Map View marker gem \u2014 much smaller than the jewelry seat ratio. Using\n  // MIMOSA_PIN_CIRCLE_R (~14 on a 31-wide head) made a huge flat white disc\n  // (\"\u4E2D\u95F4\u7684\u5708\u90A3\u4E48\u767D\u00B7\u5E94\u8BE5\u5C0F\u4E9B\").\n  const MIMOSA_MAP_PIN_GEM_R = 5.6;\n\n  // Badge as real lng/lat polygons, anchored with the teardrop's tip on the\n  // chosen point and sized in pendant-mm \u2014 so it holds one physical size on\n  // the piece at any zoom, and is rebuilt from scratch on every recompute,\n  // which is what lets the surrounding structure follow the marker instead\n  // of being baked in at one position.\n  //   body \u2192 the raised island\n  //   ring \u2192 body dilated by the groove width; subtracting (ring \u2212 body)\n  //          from the land is what carves the channel around it\n  //   hole \u2192 the circle punched through the island's head\n  // Screen pixels \u2192 metres, measured off the map itself rather than from a\n  // tile-size formula. The metersPerPixel expression used elsewhere in this\n  // file (mimosaBuildRoadBufferPolys, mimosaCleanSpikes) is the 256px-tile\n  // one while Mapbox GL renders 512px tiles, so it comes out at exactly 2x\n  // the true value: every buffered feature on this pendant is drawn at twice\n  // its nominal mm, and the design has been tuned with that in place \u2014 the\n  // \"0.32mm\" road gap really renders ~0.64mm. Harmless there, but it\n  // silently doubled the badge's circle to 24px across a 27px-wide head,\n  // swallowing it whole. Anything the badge needs in metres goes through\n  // here; anything that must line up with a road keeps using the road's own\n  // expression, so the two track each other whatever that convention is.\n  function mimosaPxToMeters(map, px) {\n    const c = map.getCenter();\n    const p = map.project([c.lng, c.lat]);\n    const a = map.unproject([p.x, p.y]);\n    const b = map.unproject([p.x + 100, p.y]);\n    return px * (turf.distance(turf.point([a.lng, a.lat]), turf.point([b.lng, b.lat]), { units: 'meters' }) / 100);\n  }\n\n  // Circular bezel at the pin (matches finished openwork): solid metal disk\n  // with a 2mm diamond hole. No teardrop channel \u2014 that ate the map and\n  // read as a fat floating bar next to the real piece.\n  function mimosaPinGeoShapes(map, ringPxOverride) {\n    if (typeof turf === 'undefined' || !map || !map.project) return null;\n    try {\n      const pin = mimosaReadPinLatLng();\n      const bodyR = mimosaMmToMeters(map, MIMOSA_FACTORY_SEAT_MM / 2);\n      const holeR = mimosaMmToMeters(map, MIMOSA_FACTORY_STONE_HOLE_MM / 2);\n      if (!(bodyR > 0)) return null;\n      const body = turf.circle([pin.lng, pin.lat], bodyR, { units: 'meters', steps: 64 });\n      let hole = null;\n      if (holeR > 0 && holeR < bodyR) {\n        hole = turf.circle([pin.lng, pin.lat], holeR, { units: 'meters', steps: 48 });\n      }\n      // No isolating ring \u2014 the bezel sits IN the street/river metal.\n      return { body: body, ring: null, hole: hole };\n    } catch (e) { return null; }\n  }\n  // The mm-based width above is right for the physical 35mm pendant, but on\n  // the small on-screen preview canvas it reads as thick/blobby \u2014 same fix\n  // as the openwork product: a fixed, thin screen-pixel width just for the\n  // live preview. The factory DXF/SVG export still uses MIN_LINE_MM.\n  // Bumped once already for boldness, but on the actual pendant that read\n  // as too heavy/wide relative to the engraving \u2014 back off partway.\n  const MIMOSA_ETCHED_PREVIEW_LINE_PX = 1.8;\n  // Reference photo: dark engraved lines on the gold pendant, not gold\n  // lines on white enamel. Warm dark brown, not flat black \u2014 reads as an\n  // engraved groove picking up shadow, not a graphic-design black stroke.\n  // One shared color for every line (roads/blocks and water alike) so\n  // nothing on the pendant reads as a mismatched tone.\n  const MIMOSA_LINE_COLOR = '#B8953A';\n  // Match the real openwork photo: GOLD metal ribbons (streets + river + pin)\n  // on WHITE cut-through voids. Never multiply \u2014 white must stay white.\n  // Use a richer gold than pale champagne \u2014 thin ribs of #E2C56A washed out\n  // against white and read as grey (\"\u8981\u5168\u90E8\u628A\u8FD9\u4E2A\u7070\u8272\u6539\u6210\u9EC4\u8272\").\n  const MIMOSA_METAL_FILL = '#D4B24A';\n  const MIMOSA_CANVAS_BASE = '#FFFFFF';\n  const MIMOSA_BLOCK_FILL = '#FFFFFF';\n\n  // Which road classes still read as separate ribbons on a 25mm face at this\n  // camera. Finer streets stay when zoomed in; zoomed out they would sit\n  // closer than a cuttable gap and turn the piece into a solid patch, so\n  // they drop. Arteries always stay, so the map never goes empty.\n  function mimosaDensityRoadClasses(map) {\n    const scaleShape = mimosaRoadScaleShape();\n    let gapM = 0;\n    try { gapM = mimosaMmToMeters(map, MIMOSA_ROAD_GAP_PREVIEW_MM + MIMOSA_ROAD_PACK_VOID_MM, scaleShape); } catch (eG) { gapM = 0; }\n    if (map && map._mimosaDensityClasses && map._mimosaDensityScaleShape === scaleShape\n        && Math.abs((map._mimosaDensityZoom || 0) - (map.getZoom ? map.getZoom() : 0)) < 0.04) {\n      return map._mimosaDensityClasses;\n    }\n    const classes = ['motorway', 'trunk', 'primary', 'motorway_link', 'trunk_link', 'primary_link', 'bridge'];\n    // Typical centre-to-centre spacing of that class in a city, in metres.\n    const finer = [\n      { spacing: 420, classes: ['secondary', 'secondary_link'] },\n      { spacing: 190, classes: ['tertiary', 'tertiary_link'] },\n      { spacing: 75, classes: ['street', 'street_limited'] }\n    ];\n    finer.forEach(function (tier) {\n      if (!(gapM > 0) || tier.spacing >= gapM * 0.85) classes.push.apply(classes, tier.classes);\n    });\n    if (map) {\n      map._mimosaDensityZoom = map.getZoom ? map.getZoom() : 0;\n      map._mimosaDensityClasses = classes;\n      map._mimosaDensityScaleShape = scaleShape;\n    }\n    return classes;\n  }\n\n  function mimosaDensityRoadFilter(map) {\n    return ['match', ['coalesce', ['get', 'class'], ''], mimosaDensityRoadClasses(map), true, false];\n  }\n\n  // Roads render as gaps in the gold surface (same color as the pendant,\n  // effectively invisible on their own) \u2014 what's actually outlined is the\n  // opposite: the land \"blocks\" the road network carves the map into. That\n  // means computing the road buffers, unioning them into one shape, then\n  // subtracting that from a bounding rectangle to get the block shapes.\n  // Async so a pan/zoom can keep painting between roads. The returned value\n  // is always a Promise of polygon features.\n  async function mimosaBuildRoadBufferPolys(map, roadLayerIds, shouldAbort) {\n    if (typeof turf === 'undefined') return [];\n\n    // True metres off the pendant outline \u2014 same physical mm on Hers and His.\n    const radiusMeters = mimosaMmToMeters(map, MIMOSA_ROAD_GAP_PREVIEW_MM / 2, mimosaRoadScaleShape());\n    if (!(radiusMeters > 0)) return [];\n\n    // ---- Constant detail at any zoom -----------------------------------\n    // A fixed class whitelist cannot do this. Zoomed in, or over a city whose\n    // major roads are sparse, it leaves the pendant nearly empty (measured 11\n    // roads reaching the pendant at a Guangzhou camera). Zoomed out, the same\n    // list is far too much: the grooves are a fixed physical width, so once\n    // the streets are closer together than a groove is wide they eat all the\n    // land between them and the pendant breaks up into little islands \u2014 the\n    // user's \"\u73B0\u5728\u5168\u90E8\u662F\u5C0F\u5C0F\u7684\u6D1E\".\n    //\n    // So neither the class list nor the zoom decides. The classes are ordered\n    // coarse to fine and taken one tier at a time, counting only the roads\n    // that actually reach the PENDANT, and the last tier that would push that\n    // count past MIMOSA_ROADS_ON_PENDANT_MAX is left out. Zoom out and the\n    // finer tiers drop away by themselves; zoom in and they come back.\n    // The first tier is always kept, even alone, so there is always a map.\n    // One pool: features RENDERED at the current zoom only.\n    let pool = [];\n    // ONLY features painted at the current zoom. querySourceFeatures also\n    // returns leftover parent tiles from earlier zooms \u2014 after a few\n    // zoom-in/out cycles those simplified streets sit on top of the current\n    // network and fuse into overlapping blobs (\"\u653E\u5927\u7F29\u5C0F\u51E0\u6B21\u540E\u53C8\u91CD\u53E0\").\n    if (roadLayerIds && roadLayerIds.length) {\n      try { pool = map.queryRenderedFeatures({ layers: roadLayerIds }); } catch (eR0) { pool = []; }\n    }\n    if (!pool.length) return [];\n\n    // Dedupe: mimosaIsMapRoadLine matches several stacked style layers drawing\n    // the SAME geometry (tunnel / road / bridge-case / bridge), and a source\n    // query returns one copy per loaded tile as well.\n    const tierOf = function (cls) {\n      // Bridge segments keep the road's continuity. Dropping class \"bridge\"\n      // left a hole wherever a street crossed a river or another road.\n      if (cls === 'bridge') return 0;\n      for (let t = 0; t < MIMOSA_ROAD_CLASS_TIERS.length; t++) {\n        if (MIMOSA_ROAD_CLASS_TIERS[t].indexOf(cls) !== -1) return t;\n      }\n      return -1;\n    };\n    // Quantize coords so parent-tile + child-tile near-duplicates of the same\n    // street collapse (exact JSON.stringify misses them and they double-buffer).\n    const quantKey = function (geom) {\n      try {\n        const q = function (n) { return Math.round(Number(n) * 2e4) / 2e4; };\n        const walk = function (c) {\n          if (typeof c[0] === 'number') return [q(c[0]), q(c[1])];\n          return c.map(walk);\n        };\n        return geom.type + ':' + JSON.stringify(walk(geom.coordinates));\n      } catch (eK) { return null; }\n    };\n    // Group by the vector tile's feature id, NOT by geometry: one road comes\n    // back as a separate piece per tile it crosses, and the pieces have to be\n    // taken or dropped together. Left ungrouped, the first piece stamps the\n    // spacing grid and every other piece of the SAME road then reads as\n    // \"too close\" and is thrown away \u2014 measured 302 candidates for a small\n    // area, of which only 77 survived, chopping real avenues into stubs.\n    const seenGeom = new Set();\n    const byTier = MIMOSA_ROAD_CLASS_TIERS.map(function () { return []; });\n    const roadsById = new Map();\n    const keepClass = new Set(mimosaDensityRoadClasses(map));\n    pool.forEach(function (feat) {\n      const geom = feat.geometry;\n      if (!geom || (geom.type !== 'LineString' && geom.type !== 'MultiLineString')) return;\n      const cls = (feat.properties && feat.properties.class) || '';\n      if (!keepClass.has(cls)) return;\n      const tier = tierOf(cls);\n      if (tier < 0) return;\n      const gkey = quantKey(geom);\n      if (gkey) {\n        if (seenGeom.has(gkey)) return;\n        seenGeom.add(gkey);\n      }\n      // Key on the street's NAME, not the tile's feature id \u2014 vector tile ids\n      // are only unique inside their own tile, so keying on them merges\n      // unrelated roads from different tiles into one candidate. A name plus a\n      // class groups the pieces of one avenue and nothing else that matters.\n      const props = feat.properties || {};\n      const name = (props.name || props.name_en || '').trim();\n      const id = name ? (name + '|' + (props.class || '')) : (gkey || Math.random());\n      let road = roadsById.get(id);\n      if (!road) {\n        road = { tier: tier, geoms: [] };\n        roadsById.set(id, road);\n        byTier[tier].push(road);\n      }\n      road.geoms.push(geom);\n    });\n\n    // ---- Pack the face as tight as the metal allows ---------------------\n    // An occupancy grid in pendant units, one cell per quarter millimetre.\n    // Each accepted road stamps its centre line into it; a candidate is\n    // measured against it and dropped only if most of its length has no room.\n    // Roads are offered coarsest class first, and longest first inside a\n    // class, so what survives a crowded area is the road a person would name.\n    const canvasEl = map.getCanvas();\n    const cw = (canvasEl && canvasEl.clientWidth) || 400;\n    const ch = (canvasEl && canvasEl.clientHeight) || 400;\n    const unitsPerMm = mimosaUnitsPerMm(mimosaRoadScaleShape());\n    const cellUnits = 0.25 * unitsPerMm;\n    // The grid covers the whole canvas, not just the pendant: blocks have to\n    // close cleanly a little past the rim.\n    const GRID_MIN = -20, GRID_MAX = 120;\n    const gridN = Math.ceil((GRID_MAX - GRID_MIN) / cellUnits);\n    // Each cell stores 1 + the direction bin of the road that claimed it, so\n    // \"too close\" can be asked of PARALLEL roads only. Without the direction\n    // this packing silently deletes one whole axis of a grid: the horizontals\n    // are placed first at the minimum spacing, and then every vertical street\n    // is inside some horizontal's spacing circle along its entire length, so\n    // it is rejected end to end \u2014 the user saw a downtown grid come out as\n    // nothing but parallel stripes (\"\u8FD9\u4E2A\u660E\u660E\u662F\u4EA4\u53C9\u7684\u8DEF\u00B7\u4E3A\u4EC0\u4E48\u6211\u4EEC\u751F\u4EA7\u4E86\n    // \u4E00\u6761\u6761\u5E73\u884C\u7684\u8DEF\").\n    const DIR_BINS = 8;\n    const occupied = new Uint8Array(gridN * gridN);\n    const dirBinOf = function (dx, dy) {\n      let a = Math.atan2(dy, dx);\n      if (a < 0) a += Math.PI;            // direction, not heading\n      if (a >= Math.PI) a -= Math.PI;\n      return Math.min(DIR_BINS - 1, Math.floor(a / (Math.PI / DIR_BINS)));\n    };\n    const nearlyParallel = function (binA, binB) {\n      const d = Math.abs(binA - binB);\n      return d <= 1 || d >= DIR_BINS - 1;  // within ~22.5 degrees, wrapping\n    };\n    // Centre-to-centre = ribbon width + land ridge. Radius is already true\n    // metres (GAP/2); do NOT double GAP \u2014 that leftover from the old 256-tile\n    // formula was throwing away most of the street grid (\"\u6CA1\u6709\u8857\u9053\u7684\u7EC6\u8282\u4E86\").\n    const spacingUnits = (MIMOSA_ROAD_GAP_PREVIEW_MM + MIMOSA_ROAD_PACK_VOID_MM) * unitsPerMm;\n    const spacingCells = Math.max(1, Math.round(spacingUnits / cellUnits));\n    // Main roads are packed only to the cutting floor (rib + 0.5mm slot) so they\n    // always show; the wider MIMOSA_ROAD_PACK_VOID_MM applies to small streets\n    // only \u2014 \"\u4FDD\u7559\u4E3B\u5E72\u9053\u00B7\u5C0F\u8DEF\u5982\u679C\u5BC6\u96C6\u7684\u5C31\u7B80\u5316\". Set per tier below.\n    const floorCells = Math.max(1, Math.round((MIMOSA_ROAD_GAP_PREVIEW_MM + MIMOSA_ROAD_MIN_SPACING_MM) * unitsPerMm / cellUnits));\n    // A divided highway is several carriageways in one corridor. Packing them\n    // at the 1mm floor collapsed the whole bundle into the single longest\n    // ribbon (\"\u597D\u51E0\u6761\u9AD8\u901F\u516C\u8DEF\u770B\u4E0D\u51FA\u4E86\"). Keep a second line: anything closer than\n    // this pitch slides out to it, so 4 close highways read as 2, not 1.\n    // Pitch stays under a full millimetre and above the 0.65mm weld, so the\n    // pair does not fuse back into one bar and does not get stitched end to end.\n    const highwayCells = Math.max(2, Math.round(0.75 * unitsPerMm / cellUnits));\n    let reach = spacingCells;\n    const cellOf = function (u) { return Math.floor((u - GRID_MIN) / cellUnits); };\n\n    const toUnits = function (coord) {\n      const p = map.project(coord);\n      return [p.x / cw * 100, p.y / ch * 100];\n    };\n    // Only the pendant face takes part in crowding. The grid spans the whole\n    // canvas, so a street just outside the outline (cut away later anyway)\n    // could mark a parallel street INSIDE as \"too close\" and cut it into a\n    // stub near the edge \u2014 \"\u4E3A\u4EC0\u4E48\u6709\u4E9B\u8DEF\u65AD\u4E86\u00B7\u660E\u660E\u6709\u4F4D\u7F6E\".\n    const fieldMask = (function () {\n      try {\n        // Hers and His must keep the same streets. Pack against both outlines\n        // together (filled separately \u2014 evenodd would punch out the overlap).\n        const shapes = [];\n        const addShape = function (name) {\n          if (name && shapes.indexOf(name) < 0) shapes.push(name);\n        };\n        addShape(currentSet === 'pair' ? mimosaHersShape() : currentShape);\n        if (currentSet === 'pair') addShape('shield');\n        const cv = document.createElement('canvas');\n        cv.width = gridN; cv.height = gridN;\n        const ctx = cv.getContext('2d');\n        ctx.fillStyle = '#000';\n        let drew = false;\n        shapes.forEach(function (shapeName) {\n          const fp = mimosaFieldPolygon(map, shapeName);\n          if (!fp || !fp.geometry) return;\n          const g = fp.geometry;\n          const rings = g.type === 'Polygon' ? g.coordinates : [].concat.apply([], g.coordinates);\n          ctx.beginPath();\n          rings.forEach(function (ring) {\n            ring.forEach(function (c, i) {\n              const u = toUnits(c);\n              const x = (u[0] - GRID_MIN) / cellUnits, y = (u[1] - GRID_MIN) / cellUnits;\n              if (i) ctx.lineTo(x, y); else ctx.moveTo(x, y);\n            });\n            ctx.closePath();\n          });\n          ctx.fill();\n          drew = true;\n        });\n        if (!drew) return null;\n        const px = ctx.getImageData(0, 0, gridN, gridN).data;\n        const mask = new Uint8Array(gridN * gridN);\n        for (let k = 0; k < mask.length; k++) mask[k] = px[k * 4 + 3] > 0 ? 1 : 0;\n        return mask;\n      } catch (eMask) { return null; }\n    })();\n    const inFaceCell = function (gx, gy) { return !fieldMask || fieldMask[gy * gridN + gx] === 1; };\n    // Roads that never touch the pendant still used to be buffered and unioned.\n    // That is most of the viewport at a city zoom, and it is what made the\n    // rebuild stall. A ~1.6mm margin keeps a street that only clips the rim.\n    const pendantReach = Math.max(2, Math.round(1.6 * unitsPerMm / cellUnits));\n    const hitsPendant = function (samples) {\n      if (!fieldMask) return true;\n      // Step was 1/16 of the line, so a street that only clipped the heart\n      // between samples was thrown away and looked cut off at the frame.\n      const step = Math.max(1, Math.floor(samples.length / 48));\n      for (let i = 0; i < samples.length; ) {\n        const gx = cellOf(samples[i][0]), gy = cellOf(samples[i][1]);\n        for (let dy = -pendantReach; dy <= pendantReach; dy += 2) {\n          const y = gy + dy;\n          if (y < 0 || y >= gridN) continue;\n          const row = y * gridN;\n          for (let dx = -pendantReach; dx <= pendantReach; dx += 2) {\n            const x = gx + dx;\n            if (x >= 0 && x < gridN && fieldMask[row + x]) return true;\n          }\n        }\n        if (i === samples.length - 1) break;\n        i = Math.min(samples.length - 1, i + step);\n      }\n      return false;\n    };\n    const samplesOf = function (geom) {\n      const lines = geom.type === 'LineString' ? [geom.coordinates] : geom.coordinates;\n      const out = [];\n      lines.forEach(function (line) {\n        let prev = null;\n        for (let i = 0; i < line.length; i++) {\n          const pt = toUnits(line[i]);\n          if (prev) {\n            const dx = pt[0] - prev[0], dy = pt[1] - prev[1];\n            const steps = Math.max(1, Math.ceil(Math.hypot(dx, dy) / cellUnits));\n            for (let k = 1; k <= steps; k++) out.push([prev[0] + dx * k / steps, prev[1] + dy * k / steps]);\n          } else {\n            out.push(pt);\n          }\n          prev = pt;\n        }\n      });\n      return out;\n    };\n    const blockedAt = function (gx, gy, bin) {\n      const x0 = Math.max(0, gx - reach), x1 = Math.min(gridN - 1, gx + reach);\n      const y0 = Math.max(0, gy - reach), y1 = Math.min(gridN - 1, gy + reach);\n      for (let y = y0; y <= y1; y++) {\n        const row = y * gridN;\n        for (let x = x0; x <= x1; x++) {\n          const cell = occupied[row + x];\n          if (!cell) continue;\n          if (!nearlyParallel(bin, cell - 1)) continue;   // a crossing is not crowding\n          const dx = x - gx, dy = y - gy;\n          if (dx * dx + dy * dy <= reach * reach) return true;\n        }\n      }\n      return false;\n    };\n    // The direction of the road at each sample, so both the test and the\n    // stamp know which way the road is running there.\n    const binsFor = function (samples) {\n      const bins = new Array(samples.length);\n      for (let i = 0; i < samples.length; i++) {\n        const a = samples[Math.max(0, i - 1)], b = samples[Math.min(samples.length - 1, i + 1)];\n        bins[i] = dirBinOf(b[0] - a[0], b[1] - a[1]);\n      }\n      return bins;\n    };\n\n    const polys = [];\n    const centerlines = [];\n    for (let tierIndex = 0; tierIndex < byTier.length; tierIndex++) {\n      if (shouldAbort && shouldAbort()) return [];\n      const tier = byTier[tierIndex];\n      const splitCarriageways = tierIndex === 0;\n      reach = splitCarriageways\n        ? highwayCells\n        : ((tierIndex < MIMOSA_ROAD_CLASS_TIERS.length - 1) ? floorCells : spacingCells);\n      // Longest first: inside one class the long through-road is the one that\n      // gives the map its shape, and it should win the space.\n      // PIECE-level packing, not whole roads (\"\u5982\u679C\u5730\u56FE\u653E\u5927\u00B7\u90A3\u5C31\u770B\u5230\u6BCF\u4E2A\u8DEF\u4EA4\u53C9\n      // \u7684\u5404\u79CD\u7EBF\u6761\u00B7\u00B7\u5982\u679C\u8DEF\u5F88\u6324\u5230\u4E00\u8D77\u5C31\u7B80\u5316\u00B7\u4F8B\u59823\u6761\u8DEF\u7B80\u5316\u52302\u6761\u00B7\u6700\u7EC8\u7684\u6548\u679C\u8981\u770B\n      // \u5230\u7EBF\u00B7\u4E0D\u8981\u7C98\u4F4F\u4E00\u8D77\u00B7\u4E5F\u4E0D\u80FD\u2026\u8DEF\u76F4\u63A5\u6CA1\u6709\u4E86\u00B7\u65AD\u4E86\"). Keeping or dropping a\n      // road as one unit lost every road that ran beside another for a short\n      // stretch, and left the streets that crossed it as dead-end stubs.\n      //\n      // Now each road is walked sample by sample: only the stretch that runs\n      // alongside an already-kept PARALLEL road is dropped; everything else of\n      // it stays. Where a kept stretch was cut, a short link is drawn from its\n      // end into that neighbour, so the dropped stretch reads as the two roads\n      // merging \u2014 3 close roads become 2, never a gap.\n      const unitsToLngLat = function (u) {\n        const ll = map.unproject([u[0] / 100 * cw, u[1] / 100 * ch]);\n        return [ll.lng, ll.lat];\n      };\n      // Douglas-Peucker in pendant units; 0.05mm is far below anything visible\n      // on a 0.5mm rib.\n      // 0.12mm is still well under the 0.5mm rib, and it cuts the vertex\n      // count that made turf.buffer + union stall the zoom.\n      const simplifyUnits = 0.12 * unitsPerMm;\n      const rdpUnits = function (pts, tol) {\n        if (pts.length <= 2) return pts;\n        const keep = new Uint8Array(pts.length);\n        keep[0] = 1; keep[pts.length - 1] = 1;\n        const stack = [[0, pts.length - 1]];\n        while (stack.length) {\n          const seg = stack.pop(), a = seg[0], b = seg[1];\n          const ax = pts[a][0], ay = pts[a][1], dx = pts[b][0] - ax, dy = pts[b][1] - ay;\n          const len = Math.hypot(dx, dy) || 1e-9;\n          let far = -1, farD = tol;\n          for (let i = a + 1; i < b; i++) {\n            const d = Math.abs((pts[i][0] - ax) * dy - (pts[i][1] - ay) * dx) / len;\n            if (d > farD) { farD = d; far = i; }\n          }\n          if (far > 0) { keep[far] = 1; stack.push([a, far], [far, b]); }\n        }\n        return pts.filter(function (p, i) { return keep[i]; });\n      };\n      const cellCentre = function (c) { return GRID_MIN + (c + 0.5) * cellUnits; };\n      const onGridAt = function (gx, gy) { return gx >= 0 && gy >= 0 && gx < gridN && gy < gridN; };\n      // Nearest occupied PARALLEL cell within the spacing radius \u2014 the\n      // neighbour a cut stretch should join.\n      const nearestParallelCell = function (gx, gy, bin) {\n        let best = null, bestD = Infinity;\n        const x0 = Math.max(0, gx - reach), x1 = Math.min(gridN - 1, gx + reach);\n        const y0 = Math.max(0, gy - reach), y1 = Math.min(gridN - 1, gy + reach);\n        for (let y = y0; y <= y1; y++) {\n          for (let x = x0; x <= x1; x++) {\n            const cell = occupied[y * gridN + x];\n            if (!cell || !nearlyParallel(bin, cell - 1)) continue;\n            const d = (x - gx) * (x - gx) + (y - gy) * (y - gy);\n            if (d < bestD) { bestD = d; best = [x, y]; }\n          }\n        }\n        return best;\n      };\n      // Join centre lines whose ends fall within this distance. Tile seams and\n      // a road that changes class used to stop short of the next piece\n      // (\"\u6709\u4E9B\u8DEF\u8FD8\u662F\u65AD\u7684\"). 0.65mm is under the 1mm packing pitch, so two\n      // parallel ribbons are not stitched into one bar. A wider gap is closed\n      // only when the two ends point the same way \u2014 one road that was split,\n      // not two carriageways side by side (\"\u8DEF\u672C\u6765\u662F\u8FDE\u8D2F\u7684\u00B7\u4E0D\u80FD\u65AD\u5F00\").\n      const joinUnits = 0.65 * unitsPerMm;\n      const continueUnits = 2.0 * unitsPerMm;\n      const dist2 = function (p, q) {\n        const dx = p[0] - q[0], dy = p[1] - q[1];\n        return dx * dx + dy * dy;\n      };\n      const sameWay = function (d1x, d1y, d2x, d2y) {\n        const m1 = Math.hypot(d1x, d1y), m2 = Math.hypot(d2x, d2y);\n        if (m1 < 1e-6 || m2 < 1e-6) return true;\n        return (d1x * d2x + d1y * d2y) / (m1 * m2) > 0.7;\n      };\n      const continues = function (run, atEnd, other, otherAtStart, gap2) {\n        if (gap2 > continueUnits * continueUnits) return false;\n        const dir = function (pts, fromEnd) {\n          const n = pts.length;\n          const a = fromEnd ? pts[n - 2] : pts[1];\n          const b = fromEnd ? pts[n - 1] : pts[0];\n          return [b[0] - a[0], b[1] - a[1]];\n        };\n        if (run.length < 2 || other.length < 2) return gap2 <= joinUnits * joinUnits;\n        const dA = dir(run, atEnd);\n        const dB = dir(other, !otherAtStart);\n        const end = atEnd ? run[run.length - 1] : run[0];\n        const start = otherAtStart ? other[0] : other[other.length - 1];\n        const cross = Math.abs(dA[0] * (start[1] - end[1]) - dA[1] * (start[0] - end[0])) / (Math.hypot(dA[0], dA[1]) || 1);\n        if (cross > 0.35 * unitsPerMm) return false;\n        return sameWay(dA[0], dA[1], start[0] - end[0], start[1] - end[1])\n          && sameWay(dA[0], dA[1], dB[0], dB[1]);\n      };\n      const weldRuns = function (runs) {\n        const close2 = joinUnits * joinUnits;\n        const left = runs.map(function (r) { return r.slice(); });\n        let guard = 0;\n        while (guard++ < left.length + 2) {\n          let merged = false;\n          for (let a = 0; a < left.length && !merged; a++) {\n            const A = left[a];\n            if (A.length < 2) continue;\n            const a0 = A[0], a1 = A[A.length - 1];\n            for (let b = a + 1; b < left.length; b++) {\n              const B = left[b];\n              if (B.length < 2) continue;\n              const b0 = B[0], b1 = B[B.length - 1];\n              let next = null;\n              const g10 = dist2(a1, b0), g11 = dist2(a1, b1), g01 = dist2(a0, b1), g00 = dist2(a0, b0);\n              if (g10 <= close2 || continues(A, true, B, true, g10)) next = A.concat(B);\n              else if (g11 <= close2 || continues(A, true, B, false, g11)) next = A.concat(B.slice().reverse());\n              else if (g01 <= close2 || continues(B, true, A, true, g01)) next = B.concat(A);\n              else if (g00 <= close2 || continues(B, true, A, false, g00)) next = B.slice().reverse().concat(A);\n              if (!next) continue;\n              left[a] = next;\n              left.splice(b, 1);\n              merged = true;\n              break;\n            }\n          }\n          if (!merged) break;\n        }\n        return left;\n      };\n\n      const ordered = tier.map(function (road) {\n        const lines = [];\n        let total = 0;\n        road.geoms.forEach(function (g) {\n          const parts = g.type === 'LineString' ? [g.coordinates] : g.coordinates;\n          parts.forEach(function (coords) {\n            const s = samplesOf({ type: 'LineString', coordinates: coords });\n            if (s.length >= 2 && hitsPendant(s)) { lines.push(s); total += s.length; }\n          });\n        });\n        return { lines: lines, total: total };\n      }).sort(function (a, b) { return b.total - a.total; });\n\n      const tierPieces = [];\n      for (let roadIndex = 0; roadIndex < ordered.length; roadIndex++) {\n        if (shouldAbort && shouldAbort()) return [];\n        if (roadIndex > 0 && roadIndex % 6 === 0) await mimosaYield();\n        const road = ordered[roadIndex];\n        const pieces = [];\n        const stamps = [];\n        road.lines.forEach(function (samples) {\n          const bins = binsFor(samples);\n          const cells = samples.map(function (s) { return [cellOf(s[0]), cellOf(s[1])]; });\n          const blocked = samples.map(function (s, i) {\n            const c = cells[i];\n            return onGridAt(c[0], c[1]) && inFaceCell(c[0], c[1]) && blockedAt(c[0], c[1], bins[i]);\n          });\n          // Arterials stay on their own centre line, start to end. Sliding the\n          // middle onto a neighbour is what made a big road look cut in half\n          // (\"\u8FD9\u4E48\u5927\u7684\u8DEF\u90FD\u65AD\u4E86\"). Only a minor street that runs beside one\n          // already kept for almost its whole length is left out, and then the\n          // whole street goes \u2014 never a hole in the middle.\n          let faceN = 0, blockedN = 0;\n          for (let i = 0; i < samples.length; i++) {\n            const c = cells[i];\n            if (!onGridAt(c[0], c[1]) || !inFaceCell(c[0], c[1])) continue;\n            faceN++;\n            if (blocked[i]) blockedN++;\n          }\n          const keepWhole = tierIndex <= 2 || !(faceN && blockedN / faceN > 0.85);\n          if (!keepWhole) return;\n          const tiny2 = (0.05 * unitsPerMm) * (0.05 * unitsPerMm);\n          const merged = [];\n          for (let i = 0; i < samples.length; i++) {\n            const pt = samples[i];\n            const prev = merged[merged.length - 1];\n            if (prev && dist2(prev, pt) <= tiny2) continue;\n            merged.push(pt);\n            const c = cells[i];\n            if (onGridAt(c[0], c[1]) && inFaceCell(c[0], c[1])) stamps.push(c[1] * gridN + c[0], bins[i] + 1);\n          }\n          if (merged.length >= 2) pieces.push(merged);\n        });\n        // Stamp after the whole road, so a road never blocks itself.\n        for (let s = 0; s < stamps.length; s += 2) occupied[stamps[s]] = stamps[s + 1];\n        pieces.forEach(function (run) {\n          if (run.length >= 2) tierPieces.push(run);\n        });\n      }\n      // Weld within the class first. Buffering waits until every class is in,\n      // so a road that changes class can be joined before it is drawn.\n      weldRuns(tierPieces).forEach(function (run) {\n        if (run.length >= 2) centerlines.push(run);\n      });\n      await mimosaYield();\n    }\n    // Close gaps between classes the same way: only a continuation, so two\n    // parallel carriageways are not pulled into one bar.\n    const joined = [];\n    centerlines.forEach(function (run) { joined.push(run); });\n    // weldRuns is closed over the last tier's helpers; re-join here with the\n    // same rule by walking endpoints in pendant units.\n    const continueUnits = 2.0 * unitsPerMm;\n    const joinUnits = 0.65 * unitsPerMm;\n    const dist2 = function (p, q) {\n      const dx = p[0] - q[0], dy = p[1] - q[1];\n      return dx * dx + dy * dy;\n    };\n    const sameWay = function (d1x, d1y, d2x, d2y) {\n      const m1 = Math.hypot(d1x, d1y), m2 = Math.hypot(d2x, d2y);\n      if (m1 < 1e-6 || m2 < 1e-6) return true;\n      return (d1x * d2x + d1y * d2y) / (m1 * m2) > 0.7;\n    };\n    const dirOf = function (pts, fromEnd) {\n      const n = pts.length;\n      const a = fromEnd ? pts[Math.max(0, n - 2)] : pts[Math.min(1, n - 1)];\n      const b = fromEnd ? pts[n - 1] : pts[0];\n      return [b[0] - a[0], b[1] - a[1]];\n    };\n    const canJoin = function (A, atEndA, B, atStartB) {\n      const end = atEndA ? A[A.length - 1] : A[0];\n      const start = atStartB ? B[0] : B[B.length - 1];\n      const gap2 = dist2(end, start);\n      if (gap2 > continueUnits * continueUnits || A.length < 2 || B.length < 2) return false;\n      const dA = dirOf(A, atEndA);\n      const dB = dirOf(B, !atStartB);\n      const cross = Math.abs(dA[0] * (start[1] - end[1]) - dA[1] * (start[0] - end[0])) / (Math.hypot(dA[0], dA[1]) || 1);\n      if (cross > 0.35 * unitsPerMm) return gap2 <= joinUnits * joinUnits;\n      return sameWay(dA[0], dA[1], start[0] - end[0], start[1] - end[1])\n        && sameWay(dA[0], dA[1], dB[0], dB[1]);\n    };\n    let guard = 0;\n    while (guard++ < joined.length + 2) {\n      let merged = false;\n      for (let a = 0; a < joined.length && !merged; a++) {\n        const A = joined[a];\n        for (let b = a + 1; b < joined.length; b++) {\n          const B = joined[b];\n          let next = null;\n          if (canJoin(A, true, B, true)) next = A.concat(B);\n          else if (canJoin(A, true, B, false)) next = A.concat(B.slice().reverse());\n          else if (canJoin(B, true, A, true)) next = B.concat(A);\n          else if (canJoin(A, false, B, true)) next = B.slice().reverse().concat(A);\n          if (!next) continue;\n          joined[a] = next;\n          joined.splice(b, 1);\n          merged = true;\n          break;\n        }\n      }\n      if (!merged) break;\n    }\n    const unitsToLngLat = function (u) {\n      const ll = map.unproject([u[0] / 100 * cw, u[1] / 100 * ch]);\n      return [ll.lng, ll.lat];\n    };\n    const rdpUnits = function (pts, tol) {\n      if (pts.length <= 2) return pts;\n      const keep = new Uint8Array(pts.length);\n      keep[0] = 1; keep[pts.length - 1] = 1;\n      const stack = [[0, pts.length - 1]];\n      while (stack.length) {\n        const seg = stack.pop(), a = seg[0], b = seg[1];\n        const ax = pts[a][0], ay = pts[a][1], dx = pts[b][0] - ax, dy = pts[b][1] - ay;\n        const len = Math.hypot(dx, dy) || 1e-9;\n        let far = -1, farD = tol;\n        for (let i = a + 1; i < b; i++) {\n          const d = Math.abs((pts[i][0] - ax) * dy - (pts[i][1] - ay) * dx) / len;\n          if (d > farD) { farD = d; far = i; }\n        }\n        if (far > 0) { keep[far] = 1; stack.push([a, far], [far, b]); }\n      }\n      return pts.filter(function (p, i) { return keep[i]; });\n    };\n    for (let wi = 0; wi < joined.length; wi++) {\n      if (shouldAbort && shouldAbort()) return [];\n      if (wi > 0 && wi % 8 === 0) await mimosaYield();\n      const s = rdpUnits(joined[wi], 0.12 * unitsPerMm);\n      if (s.length < 2) continue;\n      try {\n        const buffered = turf.buffer(turf.lineString(s.map(unitsToLngLat)), radiusMeters, { units: 'meters', steps: 4 });\n        if (buffered) polys.push(buffered);\n      } catch (eBuf) {}\n    }\n    return polys;\n  }\n\n  // Subtracting each road buffer from the box one at a time (instead of\n  // unioning them first) was tried to sidestep rare turf.union failures on\n  // near-duplicate/collinear vertices (\"Unable to find segment ... in\n  // SweepLine tree\") \u2014 but at a dense location (750 road segments) it took\n  // 7.6 SECONDS, because each difference operates against an accumulator\n  // that gets more fragmented (more disjoint pieces) as more roads cut\n  // through it, and every later difference has to process the whole\n  // fragmented shape regardless of where the next road actually falls.\n  // Divide-and-conquer union avoids that: pairing similarly-sized shapes\n  // each round keeps every individual op cheap (measured ~380ms total for\n  // the same 750-road location, a ~20x difference), and skipping a failed\n  // pair (real road networks have a few \u2014 ~1% in testing) just leaves\n  // that one road's cut out of the final shape rather than freezing the\n  // whole preview.\n  function mimosaSafeUnion(a, b) {\n    try { return turf.union(a, b) || a; } catch (eUnion) { return a; }\n  }\n  // Hand the browser a frame. Used between the union's rounds below.\n  function mimosaYield() {\n    return new Promise(function (resolve) {\n      if (typeof requestAnimationFrame === 'function') requestAnimationFrame(function () { resolve(); });\n      else setTimeout(resolve, 0);\n    });\n  }\n\n  // Same divide-and-conquer union, but yielding after each round. Done in one\n  // go it is a single ~100ms call \u2014 measured, the largest single cost in a\n  // recompute and the whole of the stutter left after a pan (\"\u79FB\u52A8\u5730\u56FE\u7684\u65F6\u5019\u5361\").\n  // A round is a batch of independent pairwise unions, so there is a natural\n  // seam between them: pausing there costs nothing and keeps any one task\n  // short enough that the map stays interactive while the engraving catches up.\n  //\n  // shouldAbort lets a newer recompute cancel an older one mid-flight \u2014\n  // without it, two overlapping runs would both write their result and the\n  // stale one could land last.\n  async function mimosaUnionAllChunked(polys, shouldAbort) {\n    let list = polys;\n    while (list.length > 1) {\n      if (shouldAbort && shouldAbort()) return null;\n      const next = [];\n      for (let i = 0; i < list.length; i += 2) {\n        next.push(i + 1 < list.length ? mimosaSafeUnion(list[i], list[i + 1]) : list[i]);\n      }\n      list = next;\n      if (list.length > 1) await mimosaYield();\n    }\n    return list[0];\n  }\n\n  // roadPolysIn: buffers already built for this recompute. One pass over the\n  // roads used to be built THREE times per paint \u2014 once here, once for the\n  // second mimosaEnsureRoadChannelLayer call that applyEtchedStreetLines made\n  // on top of mimosaApplyRoadFilter's, and once more for the boundary ring \u2014\n  // each one re-querying, re-deduping and re-buffering every road in view.\n  // Callers that have them pass them down; anything else still builds its own.\n  // Water, back by request: \"\u6211\u60F3\u628A\u6CB3\u6D41\u52A0\u5165\u8FDB\u6765...\u8FD9\u6837\u53EF\u4EE5\u660E\u786E\u770B\u51FA\u6709\u6CB3\u6D41\u4E0E\u6D77\".\n  // It was dropped once before, when it was drawn as its own traced outline\n  // and never looked right (a river's fill polygon is continuous with the bay,\n  // so tracing its boundary gave jagged, self-crossing lines). This time it is\n  // not traced at all \u2014 it is subtracted from the land exactly like a road, so\n  // the shoreline falls out of the same difference as every other contour and\n  // is closed by construction.\n  function mimosaBuildWaterPolys(map, boxPoly) {\n    if (typeof turf === 'undefined') return [];\n    const layers = (map.getStyle() && map.getStyle().layers) || [];\n    const spec = function (l) { return { id: l.id, source: l.source, sourceLayer: l['source-layer'] }; };\n    const fillIds = layers.filter(function (l) { return l.type === 'fill' && l.source && mimosaIsWaterFill(l.id, l); }).map(spec);\n    const out = [];\n    const clip = function (poly) {\n      if (!poly) return null;\n      if (!boxPoly) return poly;\n      try { return turf.intersect(poly, boxPoly); } catch (eC) { return null; }\n    };\n    let simplifyTol = 0;\n    try {\n      const c0 = map.getCenter();\n      const p0 = map.project([c0.lng, c0.lat]);\n      const a0 = map.unproject([p0.x, p0.y]);\n      const b0 = map.unproject([p0.x + 100, p0.y]);\n      simplifyTol = Math.abs(b0.lng - a0.lng) / 100 * 1.5;\n    } catch (eT) { simplifyTol = 0; }\n\n    let viewBox = null;\n    try {\n      const b = map.getBounds();\n      const padLng = (b.getEast() - b.getWest()) * 0.25;\n      const padLat = (b.getNorth() - b.getSouth()) * 0.25;\n      viewBox = [b.getWest() - padLng, b.getSouth() - padLat, b.getEast() + padLng, b.getNorth() + padLat];\n    } catch (eView) { viewBox = null; }\n    const pushFeat = function (feat) {\n      const geom = feat && feat.geometry;\n      if (!geom) return;\n      const isPoly = geom.type === 'Polygon' || geom.type === 'MultiPolygon';\n      if (!isPoly) return;\n      // Reject water that does not meet the viewport before turf.intersect.\n      // querySourceFeatures returns every loaded tile, including oceans far\n      // off screen, and intersecting each one was a large part of the stall.\n      let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity, n = 0;\n      const walk = function (c) {\n        if (!c) return;\n        if (typeof c[0] === 'number') {\n          const x = c[0], y = c[1];\n          if (x < minX) minX = x;\n          if (y < minY) minY = y;\n          if (x > maxX) maxX = x;\n          if (y > maxY) maxY = y;\n          n++;\n          return;\n        }\n        for (let i = 0; i < c.length; i++) walk(c[i]);\n      };\n      try { walk(geom.coordinates); } catch (eWalk) { return; }\n      if (!n) return;\n      if (viewBox && (maxX < viewBox[0] || minX > viewBox[2] || maxY < viewBox[1] || minY > viewBox[3])) return;\n      const key = geom.type + ':' + minX.toFixed(4) + ',' + minY.toFixed(4) + ',' + maxX.toFixed(4) + ',' + maxY.toFixed(4) + ':' + n;\n      if (pushFeat._seen.has(key)) return;\n      pushFeat._seen.add(key);\n      try {\n        let c = clip(turf.feature(geom));\n        if (c && simplifyTol > 0) {\n          try { c = turf.simplify(c, { tolerance: simplifyTol, highQuality: false }) || c; } catch (eSimp) {}\n        }\n        if (c) out.push(c);\n      } catch (eS) {}\n    };\n    pushFeat._seen = new Set();\n\n    // Style fill layers (may be hidden in etched mode \u2014 querySourceFeatures\n    // still returns them).\n    fillIds.forEach(function (sp) {\n      try {\n        (map.querySourceFeatures(sp.source, sp.sourceLayer ? { sourceLayer: sp.sourceLayer } : {}) || [])\n          .forEach(pushFeat);\n      } catch (eQ) {}\n    });\n    // Direct composite/water fallback \u2014 Miami River etc. live here even when\n    // no matching fill layer id is classified.\n    if (!out.length) {\n      const tried = new Set();\n      layers.forEach(function (l) {\n        if (!l.source || tried.has(l.source)) return;\n        tried.add(l.source);\n        try {\n          (map.querySourceFeatures(l.source, { sourceLayer: 'water' }) || []).forEach(pushFeat);\n        } catch (eW) {}\n      });\n    }\n    if (!out.length) {\n      try {\n        (map.queryRenderedFeatures({ layers: fillIds.map(function (sp) { return sp.id; }) }) || [])\n          .forEach(pushFeat);\n      } catch (eR) {}\n    }\n\n    // True metres (mimosaPxToMeters), NOT the 256-tile formula that doubles\n    // and used to erode Miami River out of existence (\"\u6CB3\u6D41\u4E0D\u89C1\u4E86\").\n    const halfMeters = mimosaMmToMeters(map, MIMOSA_WATER_MIN_WIDTH_MM / 2);\n    return out.filter(function (w) {\n      if (!(halfMeters > 0)) return true;\n      try {\n        const bb = turf.bbox(w);\n        const midLat = ((bb[1] + bb[3]) / 2) * Math.PI / 180;\n        const wM = Math.abs(bb[2] - bb[0]) * 111320 * Math.cos(midLat);\n        const hM = Math.abs(bb[3] - bb[1]) * 111320;\n        const minor = Math.min(wM, hM);\n        const major = Math.max(wM, hM);\n        if (minor >= halfMeters * 4) return true;\n        if (major < halfMeters * 2) return false;\n        const core = turf.buffer(w, -halfMeters, { units: 'meters', steps: 4 });\n        return !!(core && core.geometry && core.geometry.coordinates && core.geometry.coordinates.length);\n      } catch (eWide) { return true; }\n    });\n  }\n\n  // A road that runs ALONG a river (same direction) doubles the channel and\n  // makes the river look thickened \u2014 drop it: \"\u4E0E\u6CB3\u6D41\u540C\u6D41\u5411\u7684\u9053\u8DEF\u5C31\u7701\u7565\u6389\".\n  // A road that CROSSES the river must stay intact so the two merge into one\n  // continuous channel in the union (\"\u6CB3\u6D41\u4E0E\u9053\u8DEF\u672C\u6765\u662F\u4EA4\u53C9\u8FDE\u7740\u7684\u8981\u8FDE\u5728\u4E00\u8D77\").\n  // Trimming crossings at the bank used to leave a gap equal to the bank\n  // buffer and broke that join. Water itself is never dilated for the cut \u2014\n  // rivers keep their true polygon size (\"\u6CB3\u6D41\u8981\u4FDD\u6301\u539F\u672C\u7684\u5927\u5C0F\u00B7\u4E0D\u8981\u52A0\u7C97\").\n  async function mimosaResolveRoadWaterConflicts(map, roadPolys, water) {\n    if (!water || !roadPolys.length) return roadPolys;\n    let guard = water;\n    try {\n      // Same physical bank pad on every piece (not the 256-tile fudge).\n      const bankMeters = mimosaMmToMeters(map, MIMOSA_ROAD_GAP_PREVIEW_MM);\n      guard = turf.buffer(water, bankMeters, { units: 'meters', steps: 4 }) || water;\n    } catch (eG) { guard = water; }\n    let guardBox = null;\n    try { guardBox = turf.bbox(guard); } catch (eB) { return roadPolys; }\n    const kept = [];\n    // Yield every so often: this sweep measured ~77ms at a coastal location,\n    // enough on its own to put a long task back on a pan (note 27 got the\n    // recompute down to none, and it stays that way).\n    for (let i = 0; i < roadPolys.length; i++) {\n      if (i > 0 && i % 40 === 0) await mimosaYield();\n      const rp = roadPolys[i];\n      try {\n        const bb = turf.bbox(rp);\n        if (bb[2] < guardBox[0] || bb[0] > guardBox[2] || bb[3] < guardBox[1] || bb[1] > guardBox[3]) { kept.push(rp); continue; }\n        const inter = turf.intersect(rp, guard);\n        if (!inter) { kept.push(rp); continue; }\n        const ratio = turf.area(inter) / Math.max(turf.area(rp), 1e-9);\n        // Everything is kept now, including roads that run ALONGSIDE the\n        // water. Dropping those is what made the streets by the river look\n        // cut short (\"\u9760\u8FD1\u6CB3\u8FB9\u7684\u8DEF\u5982\u679C\u52A0\u4E0A\u4E0D\u597D\u50CF\u8DEF\u77ED\u4E86\"), and on a cut piece\n        // it is not needed: water is metal here too, so a riverside road\n        // simply fuses into the bank instead of leaving a thin ridge. The one\n        // real hazard \u2014 a slot too narrow to cut between the road and the\n        // bank \u2014 is handled for the whole piece by the minimum-slot pass in\n        // mimosaBuildOpenworkMetal, not by throwing roads away here.\n        if (ratio > 0.98) continue;  // sits entirely inside the water: nothing to draw\n        kept.push(rp);\n      } catch (eR) { kept.push(rp); }\n    }\n    return kept;\n  }\n\n  async function mimosaBuildBlockPolygons(map, roadLayerIds, roadPolysIn, shouldAbort) {\n    const empty = { type: 'FeatureCollection', features: [] };\n    if (typeof turf === 'undefined') return empty;\n    let roadPolys = roadPolysIn;\n    if (!roadPolys) roadPolys = await mimosaBuildRoadBufferPolys(map, roadLayerIds, shouldAbort);\n    if (shouldAbort && shouldAbort()) return empty;\n    if (!roadPolys.length) return empty;\n\n    let bounds;\n    try { bounds = map.getBounds(); } catch (eB) { return empty; }\n    // Pad the box past the visible viewport so block shapes at the pendant\n    // edge don't get an artificial straight cut right at the frame.\n    const padLng = (bounds.getEast() - bounds.getWest()) * 0.15;\n    const padLat = (bounds.getNorth() - bounds.getSouth()) * 0.15;\n    const boxPoly = turf.bboxPolygon([\n      bounds.getWest() - padLng, bounds.getSouth() - padLat,\n      bounds.getEast() + padLng, bounds.getNorth() + padLat\n    ]);\n\n    // Water first: it decides which roads survive. Measured at a real coastal\n    // location: 9 pieces, 4ms to union and 77ms to resolve the road conflicts,\n    // and folding the water into the roads' own union costs nothing (60ms\n    // either way) \u2014 so it does NOT get a second chunked union pass of its own.\n    // (Beware timing this from a hidden tab: requestAnimationFrame is\n    // throttled there, so mimosaUnionAllChunked appears to take SECONDS when\n    // the real work is tens of milliseconds. Measure with the tab in front.)\n    let water = null;\n    const waterPolys = mimosaBuildWaterPolys(map, boxPoly);\n    if (waterPolys.length) {\n      waterPolys.forEach(function (w) { water = water ? mimosaSafeUnion(water, w) : w; });\n      await mimosaYield();\n      if (shouldAbort && shouldAbort()) return empty;\n      if (water) roadPolys = await mimosaResolveRoadWaterConflicts(map, roadPolys, water);\n      if (shouldAbort && shouldAbort()) return empty;\n    }\n    if (!roadPolys.length && !water) return empty;\n\n    // The water rides along in the SAME union as the roads, so the shoreline is\n    // just another edge of the land and comes back as part of the same closed\n    // contours \u2014 no separate pass, no separate layer.\n    const cutPolys = water ? roadPolys.concat([water]) : roadPolys;\n    let unioned;\n    try { unioned = await mimosaUnionAllChunked(cutPolys, shouldAbort); } catch (eUnion) { unioned = null; }\n    if (!unioned) return empty;\n    if (shouldAbort && shouldAbort()) return empty;\n    await mimosaYield();\n\n    // Location bezel: small circular pad with diamond hole. No isolating\n    // teardrop ring (that made a fat floating bar on the preview).\n    // Openwork builds the seat itself (mimosaBuildOpenworkMetal unions the\n    // body and punches the hole), so folding the pin in HERE as well left a\n    // seat-sized mark behind at the old spot every time the stone was dragged\n    // \u2014 \"\u94BB\u77F3\u79FB\u52A8\u7684\u65F6\u5019\u7559\u4E0B\u5F88\u591A\u6B8B\u5F71\". One place owns the pin.\n    const stageEl = document.getElementById('mimosa-stage');\n    const pinShapes = (stageEl && stageEl.classList.contains('is-openwork')) ? null : mimosaPinGeoShapes(map);\n    if (pinShapes) {\n      if (pinShapes.ring) {\n        unioned = mimosaSafeUnion(unioned, pinShapes.ring);\n        try {\n          const carved = turf.difference(unioned, pinShapes.body);\n          if (carved) unioned = carved;\n        } catch (eBody) {}\n      }\n      if (pinShapes.hole) unioned = mimosaSafeUnion(unioned, pinShapes.hole);\n    }\n\n    let blocks;\n    try { blocks = turf.difference(boxPoly, unioned); } catch (eDiff) { return empty; }\n    if (!blocks) return empty;\n    // With several hundred road buffers in the union, turf.difference\n    // sometimes hands back a GeometryCollection (polygons plus degenerate\n    // line/point scraps) instead of a polygon. Bailing out on that blanked the\n    // whole pendant; salvage the polygonal parts instead.\n    if (blocks.geometry.type === 'GeometryCollection') {\n      const parts = [];\n      (blocks.geometry.geometries || []).forEach(function (g) {\n        if (!g) return;\n        if (g.type === 'Polygon') parts.push(g.coordinates);\n        else if (g.type === 'MultiPolygon') parts.push.apply(parts, g.coordinates);\n      });\n      if (!parts.length) return empty;\n      blocks = turf.multiPolygon(parts);\n    }\n    return { type: 'FeatureCollection', features: [blocks], water: water || null, roadMetal: unioned };\n  }\n\n  // Two roads meeting at a shallow angle leave a thin sliver of a block\n  // behind after the difference \u2014 its boundary has a genuinely sharp\n  // corner where the sliver comes to a point, which renders as a stray\n  // \"spike\" jutting out. A full erode-then-dilate (\"opening\") pass on the\n  // block polygons was tried first and rejected: at real map scale it\n  // doesn't just round off slivers, it shatters thin block edges into a\n  // field of tiny circular speckles. This instead walks each already-\n  // traced line's points directly and drops just the apex of any sharp\n  // angle (< angleThresholdDeg) whose two adjacent segments are both\n  // shorter than maxSpikeLenMeters \u2014 the signature of a genuine sliver\n  // spike, not a real (longer) sharp corner that belongs in the design.\n  function mimosaRemoveSpikes(coordsIn, angleThresholdDeg, maxSpikeLenMeters) {\n    const coords = coordsIn.slice();\n    let changed = true;\n    let guard = 0;\n    while (changed && guard < 50) {\n      changed = false;\n      guard++;\n      for (let i = 1; i < coords.length - 1; i++) {\n        const a = coords[i - 1], b = coords[i], c = coords[i + 1];\n        const v1x = a[0] - b[0], v1y = a[1] - b[1];\n        const v2x = c[0] - b[0], v2y = c[1] - b[1];\n        const m1 = Math.hypot(v1x, v1y), m2 = Math.hypot(v2x, v2y);\n        if (!m1 || !m2) continue;\n        const cos = Math.max(-1, Math.min(1, (v1x * v2x + v1y * v2y) / (m1 * m2)));\n        const angleDeg = Math.acos(cos) * 180 / Math.PI;\n        if (angleDeg < angleThresholdDeg) {\n          let lenAB, lenBC;\n          try {\n            lenAB = turf.distance(turf.point(a), turf.point(b), { units: 'meters' });\n            lenBC = turf.distance(turf.point(b), turf.point(c), { units: 'meters' });\n          } catch (eD) { continue; }\n          if (Math.min(lenAB, lenBC) < maxSpikeLenMeters) {\n            coords.splice(i, 1);\n            changed = true;\n            break;\n          }\n        }\n      }\n    }\n    return coords;\n  }\n\n  // Boolean unions leave short teeth and stair-steps on the metal.\n  // Preserve the seat-to-street junction: removing even a short arc vertex\n  // there can replace a long road edge with a diagonal through the block.\n  function mimosaDeburrMetal(map, metal) {\n    if (!metal || !metal.geometry || !map) return metal;\n    const maxLen = mimosaMmToMeters(map, 1.35);\n    const maxDeviation = mimosaMmToMeters(map, 0.15);\n    if (!(maxLen > 0) || !(maxDeviation > 0)) return metal;\n    let mLng = 111320, mLat = 110540;\n    try {\n      const lat = map.getCenter().lat * Math.PI / 180;\n      mLng = 111320 * Math.cos(lat);\n    } catch (eC) {}\n    const pin = mimosaReadPinLatLng();\n    const seatRadius = mimosaMmToMeters(map, MIMOSA_FACTORY_SEAT_MM / 2);\n    const protectedRadius = seatRadius * 1.05;\n    let removed = 0;\n    const cleanRing = function (ring) {\n      if (!ring || ring.length < 5) return ring;\n      const coords = ring.slice();\n      const n0 = coords.length;\n      const a0 = coords[0], b0 = coords[n0 - 1];\n      if (a0[0] === b0[0] && a0[1] === b0[1]) coords.pop();\n      let changed = true;\n      let guard = 0;\n      while (changed && guard < 16 && coords.length > 4) {\n        changed = false;\n        guard++;\n        for (let i = 0; i < coords.length; i++) {\n          const a = coords[(i - 1 + coords.length) % coords.length];\n          const b = coords[i];\n          const c = coords[(i + 1) % coords.length];\n          const ax = (a[0] - b[0]) * mLng, ay = (a[1] - b[1]) * mLat;\n          const cx = (c[0] - b[0]) * mLng, cy = (c[1] - b[1]) * mLat;\n          const m1 = Math.hypot(ax, ay), m2 = Math.hypot(cx, cy);\n          if (!m1 || !m2) {\n            coords.splice(i, 1);\n            removed++;\n            changed = true;\n            break;\n          }\n          const pinDistance = Math.hypot((b[0] - pin.lng) * mLng, (b[1] - pin.lat) * mLat);\n          if (pinDistance <= protectedRadius) continue;\n          // A short edge next to a long one may be a real block corner.\n          // Limit both the span and the change in the outline.\n          if (Math.max(m1, m2) >= maxLen) continue;\n          const chord = Math.hypot(cx - ax, cy - ay);\n          if (chord >= maxLen) continue;\n          const deviation = chord > 0 ? Math.abs(ax * cy - ay * cx) / chord : m1;\n          if (deviation > maxDeviation) continue;\n          const cos = Math.max(-1, Math.min(1, (ax * cx + ay * cy) / (m1 * m2)));\n          const angleDeg = Math.acos(cos) * 180 / Math.PI;\n          if (angleDeg < 80) {\n            coords.splice(i, 1);\n            removed++;\n            changed = true;\n            break;\n          }\n        }\n      }\n      if (coords.length < 4) return ring;\n      const out = coords.slice();\n      out.push([out[0][0], out[0][1]]);\n      return out;\n    };\n    try {\n      const g = metal.geometry;\n      let next = null;\n      if (g.type === 'Polygon') next = turf.polygon(g.coordinates.map(cleanRing), metal.properties);\n      else if (g.type === 'MultiPolygon') {\n        next = turf.multiPolygon(g.coordinates.map(function (poly) {\n          return poly.map(cleanRing);\n        }), metal.properties);\n      }\n      return removed > 0 && next ? next : metal;\n    } catch (eB) { return metal; }\n  }\n\n  function mimosaCleanSpikes(map, featureCollection) {\n    if (typeof turf === 'undefined' || !turf.distance) return featureCollection;\n    const center = map.getCenter();\n    const zoom = map.getZoom();\n    // 512px tiles: the classic 256px formula is exactly 2x the real value.\n    // With this halved and mimosaMmToPx measuring against the real outline, a\n    // constant in mm finally means that many mm on the metal.\n    const metersPerPixel = 156543.03392 * Math.cos(center.lat * Math.PI / 180) / Math.pow(2, zoom) / 2;\n    const maxSpikeLenMeters = 3 * metersPerPixel; // ~3 screen px \u2014 comfortably under any real block edge\n    const cleaned = featureCollection.features.map(function (f) {\n      const geomType = f.geometry && f.geometry.type;\n      try {\n        if (geomType === 'LineString') {\n          return turf.lineString(mimosaRemoveSpikes(f.geometry.coordinates, 20, maxSpikeLenMeters), f.properties);\n        }\n        // Cutting the location badge into the blocks gives them an island\n        // (the raised teardrop) for the first time, so the difference now\n        // returns a MultiPolygon and polygonToLine hands back\n        // MultiLineString features \u2014 it was always LineString before.\n        // Without this branch the early-return below would quietly skip\n        // spike cleanup on every block edge on the pendant, not just the\n        // badge's.\n        if (geomType === 'MultiLineString') {\n          return turf.multiLineString(f.geometry.coordinates.map(function (line) {\n            return mimosaRemoveSpikes(line, 20, maxSpikeLenMeters);\n          }), f.properties);\n        }\n      } catch (eC) { return f; }\n      return f;\n    });\n    return { type: 'FeatureCollection', features: cleaned };\n  }\n\n  // fill-outline-color always draws a fixed 1-device-pixel hairline that\n  // Mapbox won't let you resize via a paint property \u2014 it read as a\n  // different weight than the water/river line next to it, drawn with an\n  // explicit line-width. Tracing the block polygons' boundary into its own\n  // line source instead means both use the exact same line-width paint\n  // property, so they're guaranteed to match.\n  //\n  // Grow street/river metal out to the pendant rim wherever a ribbon already\n  // comes within MIMOSA_RIM_CONNECT_MM \u2014 openwork must attach to the frame.\n  // Also lays a thin continuous rim spine so the edge stays a fine gold\n  // border (not a fat collar).\n  function mimosaConnectMetalToRim(map, metal, field) {\n    if (!metal || !field || typeof turf === 'undefined') return metal;\n    try {\n      const connectM = mimosaMmToMeters(map, MIMOSA_RIM_CONNECT_MM);\n      const spineM = mimosaMmToMeters(map, MIMOSA_RIM_SPINE_MM);\n      if (!(spineM > 0)) return metal;\n      // Thin continuous spine along the field edge (= inner face of the frame).\n      const spineInner = turf.buffer(field, -spineM, { units: 'meters', steps: 8 });\n      if (spineInner) {\n        const spine = turf.difference(field, spineInner);\n        if (spine) metal = mimosaSafeUnion(metal, spine);\n      }\n      if (!(connectM > 0)) return metal;\n      const rimW = Math.max(connectM, spineM * 2);\n      const inset = turf.buffer(field, -rimW, { units: 'meters', steps: 8 });\n      if (!inset) return metal;\n      const rimBand = turf.difference(field, inset);\n      if (!rimBand) return metal;\n      const grown = turf.buffer(metal, connectM, { units: 'meters', steps: 6 });\n      if (!grown) return metal;\n      let bridges = null;\n      try { bridges = turf.intersect(rimBand, grown); } catch (eI) { bridges = null; }\n      if (bridges) metal = mimosaSafeUnion(metal, bridges);\n      try {\n        const clipped = turf.intersect(metal, field);\n        if (clipped) metal = clipped;\n      } catch (eC) {}\n      return metal;\n    } catch (eRim) { return metal; }\n  }\n\n  // Manufacturing rule for openwork: every gold ribbon must touch the rim\n  // (or touch metal that does). Floating stubs fall out of the laser bed \u2014\n  // \"\u4E0D\u80FD\u6709\u65AD\u7684\u60AC\u7A7A\u7684\u5730\u65B9\". Close hairline gaps, then drop any polygon that\n  // still does not intersect the rim band.\n  function mimosaDropFloatingMetal(map, metal, field) {\n    if (!metal || !field || typeof turf === 'undefined') return metal;\n    try {\n      const spineM = mimosaMmToMeters(map, MIMOSA_RIM_SPINE_MM);\n      const bridgeM = mimosaMmToMeters(map, MIMOSA_METAL_BRIDGE_MM, mimosaRoadScaleShape());\n      if (!(spineM > 0)) return metal;\n\n      const spineInner = turf.buffer(field, -spineM * 2.5, { units: 'meters', steps: 8 });\n      if (!spineInner) return metal;\n      const rim = turf.difference(field, spineInner);\n      if (!rim) return metal;\n\n      let fused = metal;\n      if (bridgeM > 0) {\n        // Close hairline breaks without widening the existing ribbons.\n        const grown = turf.buffer(metal, bridgeM, { units: 'meters', steps: 6 });\n        if (grown) {\n          const pulled = turf.buffer(grown, -bridgeM, { units: 'meters', steps: 6 });\n          if (pulled) fused = mimosaSafeUnion(metal, pulled) || metal;\n        }\n      }\n      try {\n        const clipped = turf.intersect(fused, field);\n        if (clipped) fused = clipped;\n      } catch (eClip) {}\n\n      const parts = [];\n      const g = fused.geometry;\n      if (!g) return metal;\n      if (g.type === 'Polygon') parts.push(turf.feature(g));\n      else if (g.type === 'MultiPolygon') {\n        (g.coordinates || []).forEach(function (c) {\n          try { parts.push(turf.polygon(c)); } catch (eP) {}\n        });\n      } else if (g.type === 'GeometryCollection') {\n        (g.geometries || []).forEach(function (gg) {\n          if (!gg) return;\n          if (gg.type === 'Polygon') {\n            try { parts.push(turf.feature(gg)); } catch (eG) {}\n          } else if (gg.type === 'MultiPolygon') {\n            (gg.coordinates || []).forEach(function (c) {\n              try { parts.push(turf.polygon(c)); } catch (eM) {}\n            });\n          }\n        });\n      } else {\n        return metal;\n      }\n      if (!parts.length) return metal;\n\n      const kept = [];\n      for (let i = 0; i < parts.length; i++) {\n        const p = parts[i];\n        let touches = false;\n        try {\n          if (typeof turf.booleanIntersects === 'function') {\n            touches = !!turf.booleanIntersects(p, rim);\n          } else {\n            touches = !!turf.intersect(p, rim);\n          }\n        } catch (eT) {\n          try { touches = !!turf.intersect(p, rim); } catch (eT2) { touches = false; }\n        }\n        if (touches) kept.push(p);\n      }\n      // Never blank the pendant if the rim test fails for every part.\n      if (!kept.length) return metal;\n      if (kept.length === 1) return kept[0];\n      let out = kept[0];\n      for (let i = 1; i < kept.length; i++) out = mimosaSafeUnion(out, kept[i]);\n      return out || metal;\n    } catch (eDrop) { return metal; }\n  }\n\n  // The pendant OUTLINE as a turf polygon in lng/lat (the field is the same\n  // thing inset 3.5). Needed for the bail: the knob and its neck live between\n  // the two, so nothing in the openwork pipeline \u2014 which works inside the\n  // field \u2014 ever produced metal there and the bail hung off the piece\n  // (\"\u6C34\u6EF4\u7684\u65AD\u4E86\").\n  function mimosaOutlinePolygonLngLat(map, shape) {\n    try {\n      const canvas = map.getCanvas();\n      const w = (canvas && canvas.clientWidth) || 400;\n      const h = (canvas && canvas.clientHeight) || 400;\n      const subs = mimosaParsePathD(mimosaPathForShape(shape));\n      const pts = (subs[0] || []);\n      if (pts.length < 4) return null;\n      const coords = pts.map(function (p) {\n        const ll = map.unproject([(p.x / 100) * w, (p.y / 100) * h]);\n        return [ll.lng, ll.lat];\n      });\n      const a = coords[0], b = coords[coords.length - 1];\n      if (a[0] !== b[0] || a[1] !== b[1]) coords.push(a);\n      return turf.polygon([coords]);\n    } catch (eO) { return null; }\n  }\n\n  // Solid metal for the bail: everything between the outline and the field\n  // that sits ABOVE the field (north of it), i.e. the knob and the neck that\n  // joins it to the rim. The hole through it is punched by the caller.\n  function mimosaBailPatchPolygon(map, shape, field) {\n    try {\n      const outline = mimosaOutlinePolygonLngLat(map, shape);\n      if (!outline || !field) return null;\n      const band = turf.difference(outline, field);\n      if (!band) return null;\n      const fb = turf.bbox(field), ob = turf.bbox(outline);\n      const pad = Math.max(1e-6, (ob[2] - ob[0]) * 0.02);\n      const north = turf.bboxPolygon([ob[0] - pad, fb[3] - pad * 0.15, ob[2] + pad, ob[3] + pad]);\n      return turf.intersect(band, north);\n    } catch (eB) { return null; }\n  }\n\n  function mimosaBailHoleLngLat(map, shape) {\n    try {\n      const spec = mimosaBailSpec(shape);\n      if (!spec || !(spec.r > 0)) return null;\n      const canvas = map.getCanvas();\n      const w = (canvas && canvas.clientWidth) || 400;\n      const h = (canvas && canvas.clientHeight) || 400;\n      const centre = map.unproject([(spec.cx / 100) * w, (spec.cy / 100) * h]);\n      const edge = map.unproject([((spec.cx + spec.r) / 100) * w, (spec.cy / 100) * h]);\n      const radiusM = turf.distance([centre.lng, centre.lat], [edge.lng, edge.lat], { units: 'meters' });\n      if (!(radiusM > 0)) return null;\n      return turf.circle([centre.lng, centre.lat], radiusM, { units: 'meters', steps: 40 });\n    } catch (eH) { return null; }\n  }\n\n  // turf.union often throws on the openwork MultiPolygon; mimosaSafeUnion then\n  // silently returns the pre-seat metal and the diamond floats in a void \u2014\n  // drop shapes hit this a lot because the narrower clip leaves messier rings.\n  // Fall back to a MultiPolygon so the seat / bridge geometry is never lost.\n  function mimosaForceMerge(a, b) {\n    if (!a) return b || null;\n    if (!b) return a;\n    const merged = mimosaSafeUnion(a, b);\n    if (merged) {\n      try {\n        const c = turf.centroid(b);\n        if (c && turf.booleanPointInPolygon(c, merged)) return merged;\n      } catch (eIn) {\n        if (merged !== a) return merged;\n      }\n    }\n    try {\n      const parts = [];\n      const collect = function (f) {\n        if (!f || !f.geometry) return;\n        const g = f.geometry;\n        if (g.type === 'Polygon') parts.push(g.coordinates);\n        else if (g.type === 'MultiPolygon') Array.prototype.push.apply(parts, g.coordinates);\n      };\n      collect(a);\n      collect(b);\n      if (!parts.length) return a;\n      return turf.multiPolygon(parts);\n    } catch (eParts) {\n      return a;\n    }\n  }\n\n  function mimosaBoundaryLines(poly) {\n    if (!poly) return [];\n    try {\n      const boundary = turf.polygonToLine(poly);\n      if (!boundary) return [];\n      if (boundary.type === 'FeatureCollection') return boundary.features || [];\n      if (boundary.geometry && boundary.geometry.type === 'MultiLineString') {\n        return (boundary.geometry.coordinates || []).map(function (c) {\n          return turf.lineString(c);\n        });\n      }\n      return [boundary];\n    } catch (eB) {\n      return [];\n    }\n  }\n\n  // Walk along `bearing` in small steps until a sample lands on street metal.\n  // Avoids turf.lineIntersect misses on messy hole-rings (common on drop).\n  // Bridge starts at the seat rim (not the pin centre) so the capsule does not\n  // fatten into a triangular fillet where it meets the circular seat.\n  function mimosaDiamondBridgeWalk(pinPt, pin, bearing, streets, maxProbeM, minW, seatR) {\n    if (!(maxProbeM > 0) || !(minW > 0) || !streets) return null;\n    try {\n      const step = Math.max(minW * 0.18, seatR * 0.08);\n      let hitDist = null;\n      for (let d = Math.max(step, seatR * 0.95); d <= maxProbeM; d += step) {\n        const sample = turf.destination(pinPt, d, bearing, { units: 'meters' });\n        let on = false;\n        try { on = turf.booleanPointInPolygon(sample, streets); } catch (eOn) { on = false; }\n        if (on) {\n          hitDist = d;\n          break;\n        }\n      }\n      if (!(hitDist > 0)) return null;\n      const start = turf.destination(pinPt, Math.max(seatR * 0.9, minW * 0.5), bearing, { units: 'meters' });\n      const ext = hitDist + minW * 0.75;\n      const target = turf.destination(pinPt, ext, bearing, { units: 'meters' });\n      const line = turf.lineString([\n        start.geometry.coordinates,\n        target.geometry.coordinates\n      ]);\n      // steps:16 keeps a constant-width ribbon; low steps read as triangular\n      // wedges after union with angled streets.\n      return turf.buffer(line, minW / 2, { units: 'meters', steps: 16 });\n    } catch (eWalk) {\n      return null;\n    }\n  }\n\n  // Prefer SafeUnion so road width stays uniform. ForceMerge only when turf\n  // throws \u2014 and only for thin braces, never as a way to paste a round pad\n  // onto the lattice (that melted corners into triangles on heart/shield/drop).\n  function mimosaMergeRibbon(base, add) {\n    if (!add) return base;\n    if (!base) return add;\n    const u = mimosaSafeUnion(base, add);\n    if (u && u !== base) {\n      try {\n        const c = turf.centroid(add);\n        if (!c || turf.booleanPointInPolygon(c, u)) return u;\n      } catch (eIn) {\n        return u;\n      }\n    }\n    return mimosaForceMerge(base, add) || base;\n  }\n\n  // After the stone hole is punched, pinPt sits IN the hole \u2014 booleanPointInPolygon\n  // is false on the seat annulus. Find the seat island by nearest centroid /\n  // ring-point within one seat radius instead.\n  function mimosaFindPinMetalPoly(metal, pinPt, seatR) {\n    if (!metal || !metal.geometry || !pinPt) return null;\n    const g = metal.geometry;\n    const parts = g.type === 'Polygon' ? [g.coordinates]\n      : (g.type === 'MultiPolygon' ? g.coordinates : []);\n    if (!parts.length) return null;\n    let best = null;\n    let bestDist = Infinity;\n    const maxDist = (seatR > 0 ? seatR : 0) * 1.35;\n    parts.forEach(function (rings) {\n      let poly = null;\n      try { poly = turf.polygon(rings); } catch (eP) { return; }\n      try {\n        if (turf.booleanPointInPolygon(pinPt, poly)) {\n          best = poly;\n          bestDist = 0;\n          return;\n        }\n      } catch (eIn) {}\n      try {\n        const c = turf.centroid(poly);\n        const d = turf.distance(pinPt, c, { units: 'meters' });\n        if (d < bestDist) {\n          bestDist = d;\n          best = poly;\n        }\n      } catch (eC) {}\n    });\n    if (!best) return null;\n    if (bestDist === 0) return best;\n    if (!(maxDist > 0) || bestDist <= maxDist) return best;\n    return null;\n  }\n\n  // If the seat landed as its own MultiPolygon island (union refused to weld),\n  // fire one more brace from that island into the largest sheet so the laser\n  // bed keeps a single piece \u2014 same rule as heart / shield.\n  function mimosaWeldDiamondIsland(map, metal, pinPt, minW) {\n    if (!metal || !metal.geometry || metal.geometry.type !== 'MultiPolygon') return metal;\n    const coords = metal.geometry.coordinates || [];\n    if (coords.length < 2 || !(minW > 0)) return metal;\n    try {\n      const seatR = mimosaMmToMeters(map, MIMOSA_FACTORY_SEAT_MM / 2);\n      let pinPoly = mimosaFindPinMetalPoly(metal, pinPt, seatR);\n      let mainPoly = null;\n      let mainArea = -1;\n      let pinIdx = -1;\n      let mainIdx = -1;\n      let pinCentroid = null;\n      try { if (pinPoly) pinCentroid = turf.centroid(pinPoly); } catch (ePc) {}\n      coords.forEach(function (rings, idx) {\n        let poly = null;\n        try { poly = turf.polygon(rings); } catch (eP) { return; }\n        const area = turf.area(poly);\n        if (area > mainArea) {\n          mainArea = area;\n          mainPoly = poly;\n          mainIdx = idx;\n        }\n        if (pinCentroid) {\n          try {\n            const c = turf.centroid(poly);\n            if (turf.distance(pinCentroid, c, { units: 'meters' }) < 1e-4) {\n              pinPoly = poly;\n              pinIdx = idx;\n            }\n          } catch (eM) {}\n        }\n      });\n      if (!pinPoly || !mainPoly || pinIdx < 0 || pinIdx === mainIdx) return metal;\n      try {\n        if (turf.booleanIntersects(pinPoly, mainPoly)) {\n          // Soft join only \u2014 ForceMerge of two big polygons rebuilt corners\n          // as solid triangles across heart / shield / drop.\n          return mimosaMergeRibbon(mainPoly, pinPoly) || metal;\n        }\n      } catch (eOv) {}\n      const from = turf.centroid(pinPoly);\n      const lines = mimosaBoundaryLines(mainPoly);\n      let nearest = null;\n      let minDist = Infinity;\n      lines.forEach(function (ln) {\n        const np = turf.nearestPointOnLine(ln, from, { units: 'meters' });\n        if (np && np.properties.dist < minDist) {\n          minDist = np.properties.dist;\n          nearest = np;\n        }\n      });\n      if (!nearest || !(minDist < Infinity)) return metal;\n      const bearing = turf.bearing(from, nearest);\n      const start = turf.destination(from, Math.max((seatR || 0) * 0.85, minW * 0.4), bearing, { units: 'meters' });\n      const ext = minDist + minW * 0.8;\n      const target = turf.destination(from, ext, bearing, { units: 'meters' });\n      const line = turf.lineString([\n        start.geometry.coordinates,\n        target.geometry.coordinates\n      ]);\n      const bridge = turf.buffer(line, minW / 2, { units: 'meters', steps: 16 });\n      if (!bridge) return metal;\n      return mimosaMergeRibbon(metal, bridge) || metal;\n    } catch (eWeld) {\n      return metal;\n    }\n  }\n\n  // All shapes (heart / drop / shield): stone sits IN a street or river ribbon.\n  // If the pin is over a void, slide it onto the nearest ribbon \u2014 same rule for\n  // drop as heart/shield. No cardinal \"bridges\"; those left metal spikes around\n  // the bezel. Returns true when the pin moved.\n  function mimosaSnapPinToMetal(map, streets, field) {\n    if (typeof turf === 'undefined' || !streets || !streets.geometry) return false;\n    try {\n      const pin = mimosaReadPinLatLng();\n      const pt = turf.point([pin.lng, pin.lat]);\n      // Prefer ribbons a whole seat in from the edge so the hole does not cut\n      // the rim. Drop's narrow field can make that inset empty \u2014 fall back to\n      // the full street set so snap still works like heart/shield.\n      if (field) {\n        try {\n          const seatM = mimosaMmToMeters(map, MIMOSA_FACTORY_SEAT_MM / 2);\n          const inner = seatM > 0 ? turf.buffer(field, -seatM, { units: 'meters', steps: 8 }) : null;\n          const usable = inner ? turf.intersect(streets, inner) : null;\n          if (usable && usable.geometry) {\n            const ug = usable.geometry;\n            const hasArea = (ug.type === 'Polygon' && ug.coordinates && ug.coordinates.length)\n              || (ug.type === 'MultiPolygon' && ug.coordinates && ug.coordinates.length);\n            if (hasArea) streets = usable;\n          }\n        } catch (eInner) {}\n      }\n      if (turf.booleanPointInPolygon(pt, streets)) return false;\n      const lines = mimosaBoundaryLines(streets);\n      let best = null;\n      lines.forEach(function (ln) {\n        try {\n          const np = turf.nearestPointOnLine(ln, pt, { units: 'meters' });\n          if (np && (!best || np.properties.dist < best.properties.dist)) best = np;\n        } catch (eN) {}\n      });\n      if (!best) return false;\n      let target = best.geometry.coordinates;\n      const pushM = mimosaMmToMeters(map, 0.25);\n      if (pushM > 0 && best.properties.dist > 0) {\n        const inward = turf.destination(best, pushM, turf.bearing(pt, best), { units: 'meters' });\n        if (turf.booleanPointInPolygon(inward, streets)) target = inward.geometry.coordinates;\n      }\n      const lngLat = { lng: target[0], lat: target[1] };\n      const coordsEl = document.getElementById('mimosa-hidden-coords');\n      if (coordsEl) coordsEl.value = lngLat.lat.toFixed(6) + ', ' + lngLat.lng.toFixed(6);\n      [diamondMarkerBefore, diamondMarkerAfter, diamondMarkerHis].forEach(function (m) {\n        if (m && m.setLngLat) m.setLngLat([lngLat.lng, lngLat.lat]);\n      });\n      try {\n        if (map && map.project) {\n          const canvas = map.getCanvas();\n          const w = (canvas && canvas.clientWidth) || 0;\n          const h = (canvas && canvas.clientHeight) || 0;\n          if (w > 0 && h > 0) {\n            const px = map.project([lngLat.lng, lngLat.lat]);\n            stonePos.x = Math.max(0, Math.min(100, (px.x / w) * 100));\n            stonePos.y = Math.max(0, Math.min(100, (px.y / h) * 100));\n          }\n        }\n      } catch (ePos) {}\n      try { mimosaUpdateMapPreviewLink(); } catch (eL) {}\n      try { mimosaUpdateBackPreview(); } catch (eB) {}\n      try { mimosaUpdateStoneOverlay(); } catch (eS) {}\n      return true;\n    } catch (eSnap) {\n      return false;\n    }\n  }\n\n  // After snap: circular seat + stone hole only. No N/E/S/W braces \u2014 drop uses\n  // the same snap-to-road rule as heart/shield. Never ForceMerge a round pad\n  // into the lattice (that made triangular fillets).\n  function mimosaSeatPinInMetal(map, metal) {\n    if (!metal || !map) return metal;\n    try {\n      const pinShapes = mimosaPinGeoShapes(map);\n      if (!pinShapes || !pinShapes.body) return metal;\n      const pin = mimosaReadPinLatLng();\n      const pinPt = turf.point([pin.lng, pin.lat]);\n      const minW = mimosaMmToMeters(map, MIN_LINE_MM);\n      if (!(minW > 0)) return metal;\n\n      let next = metal;\n      const seated = mimosaSafeUnion(next, pinShapes.body);\n      if (seated) {\n        next = seated;\n      } else {\n        // Keep seat as its own part; thin weld joins it without a round pad.\n        next = mimosaForceMerge(next, pinShapes.body) || next;\n      }\n      next = mimosaWeldDiamondIsland(map, next, pinPt, minW) || next;\n      if (pinShapes.hole) {\n        try {\n          const punched = turf.difference(next, pinShapes.hole);\n          if (punched) next = punched;\n        } catch (eHole) {}\n      }\n      next = mimosaWeldDiamondIsland(map, next, pinPt, minW) || next;\n      return next;\n    } catch (eSeat) {\n      return metal;\n    }\n  }\n\n  // A neck the erode deletes is under the cutting floor. Grow just that neck\n  // until it is MIN_LINE_MM wide. The healthy 0.5mm ribbons survive the erode,\n  // so they are not in `thin` and do not get fatter.\n  function mimosaRaiseThinMetal(map, metal, field) {\n    if (!metal || !metal.geometry || !map || typeof turf === 'undefined' || !turf.buffer) return metal;\n    const half = mimosaMmToMeters(map, MIN_LINE_MM / 2, mimosaRoadScaleShape());\n    if (!(half > 0)) return metal;\n    const probe = half * 0.84;\n    let core = null;\n    try { core = turf.buffer(metal, -probe, { units: 'meters', steps: 4 }); } catch (eE) { return metal; }\n    if (!core) return metal;\n    let restored = null;\n    try { restored = turf.buffer(core, probe * 1.22, { units: 'meters', steps: 4 }); } catch (eD) { return metal; }\n    if (!restored) return metal;\n    let thin = null;\n    try { thin = turf.difference(metal, restored); } catch (eT) { return metal; }\n    if (!thin || !thin.geometry) return metal;\n    const g = thin.geometry;\n    const parts = g.type === 'Polygon' ? [g.coordinates] : (g.type === 'MultiPolygon' ? g.coordinates : []);\n    if (!parts.length) return metal;\n    const dust = mimosaMmToMeters(map, 1.6, mimosaRoadScaleShape());\n    const dustArea = dust * dust;\n    const pads = [];\n    parts.forEach(function (rings) {\n      try {\n        const poly = turf.polygon(rings);\n        const area = turf.area(poly);\n        if (!(area > 0)) return;\n        const perim = turf.length(turf.polygonToLine(poly), { units: 'meters' });\n        if (!perim) return;\n        const thickness = 2 * area / perim;\n        if (thickness >= half * 2) return;\n        // The erode/dilate leaves a paper-thin skin on healthy edges. That\n        // skin is long and almost zero-width; growing it would fatten every\n        // street. A real neck is short enough to have some area.\n        if (thickness < half * 0.12 && area > dustArea) return;\n        const pad = Math.max(half * 0.15, half - thickness / 2);\n        const fat = turf.buffer(poly, pad, { units: 'meters', steps: 8 });\n        if (fat) pads.push(fat);\n      } catch (eP) {}\n    });\n    if (!pads.length) return metal;\n    let next = metal;\n    for (let i = 0; i < pads.length; i++) next = mimosaSafeUnion(next, pads[i]) || next;\n    if (field) {\n      try {\n        const clipped = turf.intersect(next, field);\n        if (clipped) next = clipped;\n      } catch (eC) {}\n    }\n    return next;\n  }\n\n  // Shared openwork geometry for live preview AND factory CUT files.\n  //   metal = keep (streets \u222A river \u222A pin \u222A rim), all attached to the frame\n  //   voids = cut-through holes (land blocks + diamond seat)\n  async function mimosaBuildOpenworkMetal(map, shape, roadLayerIds, roadPolysIn, shouldAbort) {\n    const blocks = await mimosaBuildBlockPolygons(map, roadLayerIds, roadPolysIn, shouldAbort);\n    if (shouldAbort && shouldAbort()) return null;\n    if (!blocks.features.length || typeof turf === 'undefined') return null;\n    try {\n      let solid = blocks.features[0];\n      const field = mimosaFieldPolygon(map, shape);\n      if (!field) return null;\n      try {\n        const cut = turf.intersect(solid, field);\n        if (cut) solid = cut;\n      } catch (eCut) {}\n      let metal = null;\n      try { metal = turf.difference(field, solid); } catch (eMetal) { metal = null; }\n      // Complex block rings can make the inverse cut fail on one outline.\n      // Recover by clipping the original road network to that outline.\n      if (!metal && blocks.roadMetal) {\n        try { metal = turf.intersect(blocks.roadMetal, field); } catch (eRoadClip) {}\n      }\n      // Safety net: re-add water explicitly so a missed cut never blanks\n      // the river (\"\u6CB3\u6D41\u4E0D\u89C1\u4E86\"). True polygon size, no dilation.\n      // Reuse the union already built with the roads \u2014 querying and buffering\n      // the water a second time was a full extra stall on every zoom.\n      let water = null;\n      if (blocks && Object.prototype.hasOwnProperty.call(blocks, 'water')) {\n        water = blocks.water;\n      } else {\n        mimosaBuildWaterPolys(map, field).forEach(function (w) {\n          water = water ? mimosaSafeUnion(water, w) : w;\n        });\n      }\n      if (water) {\n        try {\n          const wClip = turf.intersect(water, field);\n          if (wClip) metal = metal ? mimosaSafeUnion(metal, wClip) : wClip;\n        } catch (eW) {}\n      }\n      // Roads / water / rim-connect / drop-floating FIRST \u2014 without the pin.\n      // If the pin seat is unioned before dropFloatingMetal and streets are\n      // still sparse (mid-zoom tile race), the seat is an island that does\n      // not touch the rim and gets deleted \u2014 HTML gem stays, metal hole gone\n      // (\"\u521A\u70B9\u8FDB\u6765\u5BF9\u7684\u00B7\u7F29\u653E\u540E\u77F3\u5934\u4E5F\u4E0D\u5BF9\u4E86\"). Re-add the seat after the drop.\n      if (metal) metal = mimosaConnectMetalToRim(map, metal, field);\n      if (metal) metal = mimosaDropFloatingMetal(map, metal, field);\n      // All shapes: snap gem onto nearest ribbon (drop = same as heart/shield),\n      // then seat disc + hole. No cardinal bridges.\n      // Hers only: the pin is shared; His must not snap it again after Hers.\n      if (metal && map !== mapHis) mimosaSnapPinToMetal(map, metal, field);\n      if (metal) metal = mimosaSeatPinInMetal(map, metal);\n\n      if (metal && metal.geometry && metal.geometry.type === 'GeometryCollection') {\n        const parts = [];\n        (metal.geometry.geometries || []).forEach(function (g) {\n          if (!g) return;\n          if (g.type === 'Polygon') parts.push(g.coordinates);\n          else if (g.type === 'MultiPolygon') parts.push.apply(parts, g.coordinates);\n        });\n        metal = parts.length ? turf.multiPolygon(parts) : null;\n      }\n      let voids = null;\n      if (metal) {\n        try { voids = turf.difference(field, metal); } catch (eV) { voids = null; }\n      }\n      // Minimum slot, cheaply. A void narrower than MIMOSA_ROAD_MIN_SPACING_MM\n      // cannot be cut and has to become metal. Doing that with a real\n      // morphological opening (buffer -h then +h over the whole void set) cost\n      // two turf.buffer passes on a complex MultiPolygon EVERY recompute and\n      // made the preview crawl \u2014 the user: \"\u975E\u5E38\u5361\u548C\u6162\". A ring's mean\n      // thickness is ~2 x area / perimeter, which is pure arithmetic, so thin\n      // rings are simply dropped from the void set instead.\n      if (voids) {\n        try {\n          const minSlotM = mimosaMmToMeters(map, MIMOSA_ROAD_MIN_SPACING_MM, mimosaRoadScaleShape());\n          const g = voids.geometry;\n          const polys = g.type === 'Polygon' ? [g.coordinates] : (g.type === 'MultiPolygon' ? g.coordinates : []);\n          const keep = [];\n          polys.forEach(function (rings) {\n            try {\n              const poly = turf.polygon(rings);\n              const area = turf.area(poly);\n              const perim = turf.length(turf.polygonToLine(poly), { units: 'meters' });\n              if (!perim) return;\n              // 2A/P is a fair thickness proxy for a sliver but it badly\n              // UNDER-estimates a big block whose outline follows curving\n              // streets (long perimeter, large area). Using it alone swallowed\n              // real blocks and the face fused into one mass \u2014 the user:\n              // \"\u73B0\u5728\u6CB3\u6D41\u548C\u9053\u8DEF\u5168\u90E8\u5728\u4E00\u8D77\u4E86\u00B7\u4E0A\u4E2A\u7248\u672C\u8FD8\u53EF\u4EE5\u770B\u5230\u5F88\u591A\u7EC6\u8282\".\n              // So a ring is only dropped when it is thin AND small enough to\n              // actually be a sliver (no longer than ~8mm at the minimum slot).\n              // Only a true hairline is filled in. Anything that still reads\n              // as a shape stays a hole \u2014 the user watched small streets turn\n              // into solid squares (\"\u6709\u4E9B\u5C0F\u9053\u8DEF\u4E3A\u4EC0\u4E48\u53D8\u6210\u4E86\u5B9E\u5FC3\u7684\u65B9\u5757\").\n              const thickness = 2 * area / perim;\n              const metresPerMm = minSlotM / MIMOSA_ROAD_MIN_SPACING_MM;\n              const sliverArea = minSlotM * (3 * metresPerMm);\n              if (thickness >= 0.6 * minSlotM || area > sliverArea) keep.push(rings);\n            } catch (eR) { keep.push(rings); }\n          });\n          if (keep.length !== polys.length) {\n            voids = keep.length ? turf.multiPolygon(keep) : null;\n            const remetal = voids ? turf.difference(field, voids) : field;\n            if (remetal) metal = remetal;\n          }\n        } catch (eSlot) {}\n      }\n      // The bail is added LAST: mimosaConnectMetalToRim and the slot pass both\n      // clip back to the field, which would cut it straight off again.\n      if (metal) {\n        // The piece's outer edge is METAL, not a drawn line: the band between\n        // the outline and the engraved field is solid on the real cut pendant,\n        // which is what gives it a gold rim. Without it the silhouette showed\n        // only the page's pale shadow and read as a grey outline \u2014 the user:\n        // \"\u6211\u770B\u5230\u4F60\u628A\u8F6E\u5ED3\u7EBF\u53D8\u8272\u7070\u767D\u8272\u4E86\u00B7\u5176\u5B9E\u662F\u8F6E\u5ED3\u7EBF\". Adding the whole band\n        // also guarantees every ribbon that reaches the edge is attached.\n        try {\n          const outlinePoly = mimosaOutlinePolygonLngLat(map, shape);\n          if (outlinePoly) {\n            const rimBand = turf.difference(outlinePoly, field);\n            if (rimBand) metal = mimosaSafeUnion(metal, rimBand) || metal;\n          }\n        } catch (eRim2) {}\n        const bailPatch = mimosaBailPatchPolygon(map, shape, field);\n        if (bailPatch) metal = mimosaSafeUnion(metal, bailPatch) || metal;\n        const bailHole = mimosaBailHoleLngLat(map, shape);\n        if (bailHole) {\n          try {\n            const punched = turf.difference(metal, bailHole);\n            if (punched) metal = punched;\n          } catch (eBH) {}\n        }\n      }\n      // A cut piece is ONE sheet: anything not joined to the frame falls out.\n      // Weld the diamond island FIRST \u2014 otherwise keep-largest throws away the\n      // seat/bridges on drop maps and the stone floats in a void again.\n      if (metal && metal.geometry && metal.geometry.type === 'MultiPolygon'\n          && metal.geometry.coordinates.length > 1) {\n        try {\n          const pin = mimosaReadPinLatLng();\n          const pinPt = turf.point([pin.lng, pin.lat]);\n          const minW = mimosaMmToMeters(map, MIN_LINE_MM);\n          metal = mimosaWeldDiamondIsland(map, metal, pinPt, minW) || metal;\n        } catch (eWeldPre) {}\n      }\n      if (metal && metal.geometry && metal.geometry.type === 'MultiPolygon'\n          && metal.geometry.coordinates.length > 1) {\n        try {\n          const pin = mimosaReadPinLatLng();\n          const pinPt = turf.point([pin.lng, pin.lat]);\n          const seatR = mimosaMmToMeters(map, MIMOSA_FACTORY_SEAT_MM / 2);\n          const minW = mimosaMmToMeters(map, MIN_LINE_MM);\n          metal = mimosaWeldDiamondIsland(map, metal, pinPt, minW) || metal;\n          if (metal.geometry && metal.geometry.type === 'MultiPolygon'\n              && metal.geometry.coordinates.length > 1) {\n            let bestRings = null, bestArea = -1;\n            metal.geometry.coordinates.forEach(function (rings) {\n              const a = turf.area(turf.polygon(rings));\n              if (a > bestArea) { bestArea = a; bestRings = rings; }\n            });\n            const pinPoly = mimosaFindPinMetalPoly(metal, pinPt, seatR);\n            if (pinPoly && bestRings\n                && JSON.stringify(pinPoly.geometry.coordinates) !== JSON.stringify(bestRings)) {\n              // Thin-brace weld only \u2014 never ForceMerge the two sheets (triangles).\n              metal = mimosaWeldDiamondIsland(map, metal, pinPt, minW) || metal;\n              if (metal.geometry && metal.geometry.type === 'MultiPolygon'\n                  && metal.geometry.coordinates.length > 1) {\n                // Last resort: keep the main sheet; seat was already welded once\n                // above and will be re-added by the final mimosaSeatPinInMetal.\n                metal = turf.polygon(bestRings);\n              }\n            } else if (bestRings) {\n              metal = turf.polygon(bestRings);\n            }\n          }\n          const v2 = turf.difference(field, metal);\n          voids = v2 || null;\n        } catch (eOne) {}\n      }\n      // Clip leftover teeth after the sheet is one piece, then rebuild the\n      // holes so the preview and the factory file describe the same edge.\n      if (metal) {\n        const deburred = mimosaDeburrMetal(map, metal);\n        if (deburred && deburred !== metal) {\n          try {\n            const v3 = turf.difference(field, deburred);\n            if (v3) { metal = deburred; voids = v3; }\n          } catch (eBurr) {}\n        }\n      }\n      // Factory floor: a ribbon under 0.5mm burns away on the laser.\n      if (metal) {\n        let raised = mimosaRaiseThinMetal(map, metal, field);\n        if (raised && raised !== metal) {\n          try {\n            const bailHole = mimosaBailHoleLngLat(map, shape);\n            if (bailHole) {\n              const punched = turf.difference(raised, bailHole);\n              if (punched) raised = punched;\n            }\n          } catch (eBail) {}\n          metal = raised;\n        }\n      }\n      // Seat can be chewed by raise/deburr \u2014 re-seat with SafeUnion only.\n      if (metal) metal = mimosaSeatPinInMetal(map, metal);\n      if (metal) {\n        try { voids = turf.difference(field, metal); } catch (eVoids) { voids = null; }\n      }\n      if (voids) {\n        const kept = mimosaKeepVoidsInFace(map, shape, voids);\n        if (kept !== voids) {\n          try {\n            const back = kept ? turf.difference(voids, kept) : voids;\n            if (back && metal) metal = mimosaSafeUnion(metal, back) || metal;\n          } catch (eBack) {}\n          voids = kept;\n        }\n      }\n      return { metal: metal, field: field, voids: voids, solid: solid };\n    } catch (eBuild) { return null; }\n  }\n\n  // Preview matches the real openwork pendant photo:\n  //   GOLD fill  = metal ribbons (streets \u222A river \u222A pin body, hole punched)\n  //   WHITE bg   = cut-through voids between the ribbons\n  // Metal ribbons are GeoJSON in lng/lat. If the previous zoom's geometry stays\n  // on screen while the camera zooms in, those metre-wide buffers appear 2\u20134\u00D7\n  // thicker and the diamond seat hole balloons \u2014 \"\u653E\u5927\u00B7\u7EBF\u6761\u5C31\u53D8\u7C97\u00B7\u94BB\u77F3\u4E5F\u53D8\u4E86\".\n  // During the gesture, hide that stale fill and draw Mapbox's own roads and\n  // rivers at the jewelry millimetre width. Those are GPU lines, so pan and\n  // zoom stay immediate, and the diamond is never left alone on a blank face.\n  // The closed cut geometry replaces them once the camera stops.\n  function mimosaClearOpenworkMetal(map) {\n    if (!map) return;\n    try {\n      const src = map.getSource('mimosa-road-channel-src');\n      if (src && typeof src.setData === 'function') {\n        src.setData({ type: 'FeatureCollection', features: [] });\n      }\n    } catch (eClr) {}\n  }\n\n  function mimosaShowLiveLattice(map) {\n    if (!map || !map.getStyle) return;\n    map._mimosaLiveLattice = true;\n    try {\n      if (map.getLayer('mimosa-road-channel-fill')) {\n        map.setLayoutProperty('mimosa-road-channel-fill', 'visibility', 'none');\n      }\n    } catch (eHide) {}\n    const metalColor = currentMetal === 'silver' ? MAP_LINE_SILVER : MIMOSA_METAL_FILL;\n    let width = 1.2;\n    try { width = Math.max(0.75, mimosaMmToPx(map, MIMOSA_ROAD_GAP_PREVIEW_MM, mimosaRoadScaleShape())); } catch (eW) {}\n    const classes = mimosaDensityRoadClasses(map);\n    const key = classes.join(',') + '|' + width.toFixed(2) + '|' + metalColor;\n    if (map._mimosaLiveKey === key) return;\n    map._mimosaLiveKey = key;\n    const filter = mimosaDensityRoadFilter(map);\n    const layers = (map.getStyle() && map.getStyle().layers) || [];\n    layers.forEach(function (layer) {\n      const id = layer.id;\n      if (layer.type === 'line' && mimosaIsMapRoadLine(id)) {\n        try {\n          if (/case/.test(String(id).toLowerCase())) {\n            map.setPaintProperty(id, 'line-opacity', 0);\n            return;\n          }\n          map.setLayoutProperty(id, 'visibility', 'visible');\n          try { map.setFilter(id, filter); } catch (eF) {}\n          map.setPaintProperty(id, 'line-opacity', 1);\n          map.setPaintProperty(id, 'line-color', metalColor);\n          map.setPaintProperty(id, 'line-width', width);\n          try { map.setPaintProperty(id, 'line-blur', 0); } catch (eB) {}\n          try { map.setPaintProperty(id, 'line-gap-width', 0); } catch (eGap) {}\n          try { map.setLayoutProperty(id, 'line-cap', 'round'); } catch (eC) {}\n          try { map.setLayoutProperty(id, 'line-join', 'round'); } catch (eJ) {}\n        } catch (eR) {}\n        return;\n      }\n      if (layer.type === 'fill' && mimosaIsWaterFill(id, layer)) {\n        try {\n          map.setLayoutProperty(id, 'visibility', 'visible');\n          map.setPaintProperty(id, 'fill-color', metalColor);\n          map.setPaintProperty(id, 'fill-opacity', 1);\n          try { map.setPaintProperty(id, 'fill-outline-color', metalColor); } catch (eO) {}\n        } catch (eFill) {}\n      }\n    });\n  }\n\n  function mimosaHideLiveLattice(map) {\n    if (!map || !map.getStyle) return;\n    map._mimosaLiveLattice = false;\n    map._mimosaLiveKey = '';\n    const layers = (map.getStyle() && map.getStyle().layers) || [];\n    layers.forEach(function (layer) {\n      if (layer.type === 'line' && mimosaIsMapRoadLine(layer.id)) {\n        try {\n          map.setLayoutProperty(layer.id, 'visibility', 'visible');\n          map.setPaintProperty(layer.id, 'line-opacity', 0);\n        } catch (eL) {}\n      } else if (layer.type === 'fill' && mimosaIsWaterFill(layer.id, layer)) {\n        try { map.setLayoutProperty(layer.id, 'visibility', 'none'); } catch (eW) {}\n      }\n    });\n  }\n\n  async function mimosaEnsureRoadChannelLayer(map, roadLayerIds, roadPolysIn, shouldAbort) {\n    const sourceId = 'mimosa-road-channel-src';\n    const fillLayerId = 'mimosa-road-channel-fill';\n    const layerId = 'mimosa-road-channel';\n    const lineSourceId = 'mimosa-road-channel-line-src';\n    const built = await mimosaBuildOpenworkMetal(\n      map,\n      mimosaMapPieceShape(map),\n      roadLayerIds,\n      roadPolysIn,\n      shouldAbort\n    );\n    if (shouldAbort && shouldAbort()) return;\n    let fillData = { type: 'FeatureCollection', features: [] };\n    if (built && built.metal) {\n      fillData = { type: 'FeatureCollection', features: [built.metal] };\n    }\n    try {\n      const metalColor = currentMetal === 'silver' ? MAP_LINE_SILVER : MIMOSA_METAL_FILL;\n      if (!map.getSource(sourceId)) {\n        map.addSource(sourceId, { type: 'geojson', data: fillData });\n      } else {\n        map.getSource(sourceId).setData(fillData);\n      }\n      try { map._mimosaMetalZoom = map.getZoom ? map.getZoom() : null; } catch (eZ) {}\n      if (!map.getLayer(fillLayerId)) {\n        map.addLayer({\n          id: fillLayerId,\n          type: 'fill',\n          source: sourceId,\n          paint: {\n            'fill-color': metalColor,\n            'fill-opacity': 1,\n            'fill-outline-color': metalColor,\n            'fill-antialias': true\n          }\n        });\n      } else {\n        map.setPaintProperty(fillLayerId, 'fill-color', metalColor);\n        map.setPaintProperty(fillLayerId, 'fill-opacity', 1);\n        try { map.setPaintProperty(fillLayerId, 'fill-outline-color', metalColor); } catch (eOut) {}\n        map.setLayoutProperty(fillLayerId, 'visibility', 'visible');\n      }\n\n      // Closed ribbons replace the live lines in the same turn, so the\n      // diamond never sits on an empty face. If the cut geometry came back\n      // empty, keep the live roads and rivers up.\n      if (fillData.features.length) {\n        try { map.setLayoutProperty(fillLayerId, 'visibility', 'visible'); } catch (eVis) {}\n        mimosaHideLiveLattice(map);\n        map._mimosaRenderedOpenwork = mimosaOpenworkViewKey(map);\n        mimosaEndShapeSwitch();\n      } else {\n        try {\n          if (map.getLayer(fillLayerId)) map.setLayoutProperty(fillLayerId, 'visibility', 'none');\n        } catch (eVis) {}\n        mimosaShowLiveLattice(map);\n        mimosaEndShapeSwitch();\n      }\n\n      // No outline stroke layer \u2014 it drew the \"\u5916\u9762\u53C8\u591A\u4E86\u4E00\u5708\u9ED1\u7EBF\" halo around\n      // the pendant and every void, and polygonToLine was expensive (\"\u592A\u5361\").\n      if (map.getLayer(layerId)) {\n        try { map.removeLayer(layerId); } catch (eRm) {}\n      }\n      if (map.getSource(lineSourceId)) {\n        try { map.removeSource(lineSourceId); } catch (eRs) {}\n      }\n    } catch (eLayer) {}\n  }\n\n  // Every contour the etched pipeline draws is a closed ring; make sure the\n  // coordinates say so, whatever turf handed back.\n  function mimosaCloseRings(fc) {\n    const close = function (coords) {\n      if (!coords || coords.length < 3) return coords;\n      const a = coords[0], b = coords[coords.length - 1];\n      if (a[0] !== b[0] || a[1] !== b[1]) return coords.concat([[a[0], a[1]]]);\n      return coords;\n    };\n    (fc.features || []).forEach(function (f) {\n      const g = f && f.geometry;\n      if (!g) return;\n      if (g.type === 'LineString') g.coordinates = close(g.coordinates);\n      else if (g.type === 'MultiLineString') g.coordinates = g.coordinates.map(close);\n    });\n    return fc;\n  }\n\n  function mimosaJewelryAccent() {\n    return currentMetal === 'silver' ? MAP_LINE_SILVER : MAP_LINE_YELLOW;\n  }\n\n  // Large pendant shapes \u2014 fill most of the jewelry preview like Talisa.\n  // Top bail is a thick metal pad; punch hole with mimosaBailHolePath (evenodd).\n  // Heart pad \u2248 product photo: solid ring around jump-ring hole in the cleft.\n  // Chubby rounded heart (teal/blue ref): wide, soft cleft, blunt U-bottom\n  // Factory HERS etch heart \u2014 Guangzhou factory cut-outline path\n  // Crest: concave top edge, straight tapering sides, pointed bottom \u2014 the\n  // shape in the user's reference photo. The old outline was a boxy heater\n  // shield with shoulders and its own protruding bail tab. Everything that\n  // draws a shield (clip paths, masks, preview layers, factory export) reads\n  // this one constant now \u2014 see mimosaSyncShapeOutlines.\n\n  /**\n   * Chain eyelet: hole radius + outer pad radius (metal ring width = outerR - r).\n   * Heart matches product: ~2.5 units of gold around the jump-ring hole.\n   */\n  function mimosaBailSpec(shape) {\n    if (shape === 'circle') return { cx: 50, cy: 14.2, r: 1.45, outerR: 3.6 };\n    if (shape === 'drop') return { cx: 50, cy: 12.8, r: 1.5, outerR: 3.8 };\n    // Straight through the body, under the concave top edge (which reaches\n    // y=23 at the centre) \u2014 no protruding tab, same construction as the heart.\n    if (shape === 'shield') return { cx: 50, cy: 17, r: 1.98, outerR: 4.6 };\n    // Straight through the body, close under the cleft \u2014 no protruding\n    // tab. The chain's jump ring threads this hole; the metal left above\n    // it along the centre line is ~4 x the hole radius. It was 8.5, which\n    // on this outline is in the NOTCH between the lobes, off the piece\n    // entirely \u2014 the cause of the floating hole outline, the floating gold\n    // disc punched out of svg-white-mask's veil, and a chain that ended in\n    // mid-air. Any bail coordinate here must land inside the outline.\n    return { cx: 50, cy: 25.1, r: 1.43, outerR: 3.31 }; // heart \u2014 through the bail knob\n  }\n\n  // One closed ring of unique points. Two SVG arcs used to meet at a seam,\n  // and the close vertex was written twice \u2014 the factory viewer drew that\n  // join as a scribble instead of a circle.\n  function mimosaCirclePath(cx, cy, r, steps) {\n    const n = steps || 64;\n    let d = '';\n    for (let k = 0; k < n; k++) {\n      const a = (k / n) * Math.PI * 2;\n      const x = cx + r * Math.cos(a);\n      const y = cy + r * Math.sin(a);\n      d += (k === 0 ? 'M ' : ' L ') + x.toFixed(3) + ',' + y.toFixed(3);\n    }\n    return d + ' Z';\n  }\n\n  function mimosaBailHolePath(shape) {\n    const h = mimosaBailSpec(shape);\n    return mimosaCirclePath(h.cx, h.cy, h.r, 64);\n  }\n\n  /** Bail fused into the pendant metal: gold FILL only (no outer stroke that\n   *  would cut a dark line across the rim join). Outer silhouette comes from\n   *  shape-path-gold \u2014 one continuous outline. Inner hole keeps the ribbon edge. */\n  function mimosaSyncBailVisuals(shape) {\n    const metal = currentMetal === 'silver' ? '#C5CDD4' : MIMOSA_METAL_FILL;\n    const edge = currentMetal === 'silver' ? '#9AA3AA' : MIMOSA_LINE_COLOR;\n    const apply = function (padId, holeId, spec) {\n      const pad = document.getElementById(padId);\n      const hole = document.getElementById(holeId);\n      if (pad && spec) {\n        pad.setAttribute('cx', spec.cx);\n        pad.setAttribute('cy', spec.cy);\n        // Slightly oversized so gold bleeds into the rim and hides any seam.\n        pad.setAttribute('r', (spec.outerR * 1.08).toFixed(2));\n        pad.setAttribute('fill', metal);\n        pad.setAttribute('stroke', 'none');\n        // The drop outline already includes its bail. A second circle sits above it.\n        const dropNeck = padId === 'svg-bail-pad-gold' && (shape || currentShape) === 'drop';\n        pad.style.display = dropNeck ? 'none' : '';\n      }\n      if (hole && spec) {\n        hole.setAttribute('cx', spec.cx);\n        hole.setAttribute('cy', spec.cy);\n        hole.setAttribute('r', spec.r);\n        const dropEyelet = holeId === 'svg-bail-hole-gold' && (shape || currentShape) === 'drop';\n        hole.setAttribute('fill', '#FFFFFF');\n        hole.setAttribute('stroke', dropEyelet ? 'none' : edge);\n        hole.setAttribute('stroke-width', dropEyelet ? '0' : '0.55');\n        hole.style.display = '';\n      }\n    };\n    const s = mimosaBailSpec(shape || currentShape || 'heart');\n    apply('svg-bail-pad-gold', 'svg-bail-hole-gold', s);\n    apply('svg-bail-pad-gold-his', 'svg-bail-hole-gold-his', mimosaBailSpec('shield'));\n    ['svg-bail-pad-map', 'svg-bail-hole-map'].forEach(function (id) {\n      const el = document.getElementById(id);\n      if (el) el.style.display = 'none';\n    });\n  }\n\n  /** Outer silhouette + bail hole (factory cut / filled metal with eyelet). */\n  function mimosaCutPathWithBail(shape) {\n    return mimosaPathForShape(shape) + ' ' + mimosaBailHolePath(shape);\n  }\n\n  // Flatten A/C arcs to L polylines. CSS mask/clip-path with elliptical arcs\n  // silently drops the map on Circle (and sometimes Drop) in WebKit \u2014 the\n  // geometry was fine, the silhouette mask was empty, so streets \"vanished\".\n  function mimosaPathDToPolyline(d) {\n    try {\n      const subs = mimosaParsePathD(d);\n      if (!subs.length) return d;\n      return subs.map(function (pts) {\n        if (!pts || pts.length < 2) return '';\n        let s = 'M ' + pts[0].x.toFixed(2) + ',' + pts[0].y.toFixed(2);\n        for (let i = 1; i < pts.length; i++) {\n          s += ' L ' + pts[i].x.toFixed(2) + ',' + pts[i].y.toFixed(2);\n        }\n        return s + ' Z';\n      }).filter(Boolean).join(' ');\n    } catch (eFlat) { return d; }\n  }\n\n  function mimosaStyleGoldOutline(el, shape, accent) {\n    if (!el) return;\n    el.removeAttribute('fill-rule');\n    el.style.fill = 'none';\n    // Openwork: no rim line at all. The piece is CUT, so its edge is the cut\n    // itself \u2014 the silhouette already reads against the background and a drawn\n    // outline just looks like a black ring around the pendant (\"\u5916\u9762\u600E\u4E48\u6709\u4E00\u5708\n    // \u9ED1\u7EBF\u00B7\u8FD9\u4E2A\u53BB\u6389\"). The stylesheet already says `stroke: none` for\n    // .is-openwork, but this function writes an INLINE stroke, which wins over\n    // the rule \u2014 so it has to opt out here, not in the CSS.\n    const stage = document.getElementById('mimosa-stage');\n    if (stage && stage.classList.contains('is-openwork')) {\n      el.style.stroke = 'none';\n      el.style.strokeWidth = '0';\n      el.style.filter = 'none';\n      return;\n    }\n    // Etched: the OUTER rim keeps its own lighter gold-brown \u2014 the user wants\n    // it distinct from the engraved lines. (Do not \"unify\" this with\n    // MIMOSA_LINE_COLOR again; the thin/faint rim complaint was about the\n    // INNER boundary ring, not this.)\n    const groove = currentMetal === 'silver' ? '#6A7278' : '#8A6A28';\n    el.style.stroke = groove;\n    // Thin outer rim \u2014 matches the real cut pendant, not a fat collar.\n    el.style.strokeWidth = '1.15px';\n    el.style.strokeLinejoin = 'round';\n    el.style.strokeLinecap = 'round';\n    el.style.vectorEffect = 'non-scaling-stroke';\n  }\n\n  // The simulated chain is gone. It was two strokes plus a jump ring drawn\n  // over the pendant, and it never stopped colliding with what it sits on \u2014\n  // latest: the ring's stroke cut across the bail knob's hole so the hole\n  // read as a half circle. The knob and its hole are real product geometry\n  // and speak for themselves; a fake chain on top only had to be kept in\n  // agreement with them. Per the user: \"\u8FD8\u4E0D\u5982\u5220\u6389\".\n  function mimosaChainSvgForShape(shape, color) {\n    return '';\n  }\n\n  function mimosaUpdateChainForShape(shape) {\n    const svg = document.getElementById('mimosa-chain-svg');\n    if (!svg) return;\n    svg.innerHTML = mimosaChainSvgForShape(shape, mimosaJewelryAccent());\n  }\n\n  function mimosaPaintJewelryMetal() {\n    const accent = mimosaJewelryAccent();\n    const paintFn = applyEtchedStreetLines;\n    if (mapAfter) paintFn(mapAfter);\n    if (mapHis) paintFn(mapHis);\n    mimosaApplyMapViewRoadFilter(mapBefore);\n    mimosaUpdateStoneOverlay();\n    mimosaUpdateChainForShape(currentShape);\n    const chainHis = document.getElementById('mimosa-chain-svg-his');\n    if (chainHis) chainHis.innerHTML = mimosaChainSvgForShape('shield', accent);\n    const goldOutline = document.getElementById('svg-shape-path-gold');\n    if (goldOutline) {\n      goldOutline.style.filter = currentMetal === 'silver'\n        ? 'drop-shadow(0 1px 2px rgba(0,0,0,0.18))'\n        : 'drop-shadow(0 1px 2px rgba(80,55,10,0.22))';\n      mimosaStyleGoldOutline(goldOutline, currentShape, accent);\n    }\n    const goldOutlineHis = document.getElementById('svg-shape-path-gold-his');\n    if (goldOutlineHis) {\n      goldOutlineHis.style.filter = currentMetal === 'silver'\n        ? 'drop-shadow(0 1px 2px rgba(0,0,0,0.18))'\n        : 'drop-shadow(0 1px 2px rgba(80,55,10,0.22))';\n      mimosaStyleGoldOutline(goldOutlineHis, 'shield', accent);\n    }\n    document.querySelectorAll('.mimosa-jewelry-map-silhouette').forEach(function (silhouette) {\n      silhouette.style.filter = 'drop-shadow(0 10px 18px rgba(40, 30, 10, 0.22))';\n    });\n    document.querySelectorAll('.mimosa-layer-jewelry .mimosa-map-canvas').forEach(function (canvas) {\n      canvas.style.filter = 'none';\n      canvas.style.background = MIMOSA_CANVAS_BASE;\n    });\n    // \u9542\u7A7A preview needs real white voids \u2014 multiply would swallow them.\n    document.querySelectorAll('.mimosa-jewelry-map-mask').forEach(function (el) {\n      el.style.mixBlendMode = 'normal';\n    });\n    const plate = document.getElementById('mimosa-jewelry-metal-plate');\n    const plateHis = document.getElementById('mimosa-jewelry-metal-plate-his');\n    // Rim stays gold; the map face itself paints white voids + gold metal.\n    const whitePlate = false;\n    [plate, plateHis].forEach(function (p) {\n      if (!p) return;\n      p.classList.toggle('is-silver', currentMetal === 'silver');\n      p.classList.toggle('is-white-plate', whitePlate);\n      p.classList.remove('is-black-plate');\n      if (whitePlate) {\n        p.style.background = 'radial-gradient(130% 100% at 32% 20%, #FFFFFF 0%, #F8F6F2 40%, #EDE8E0 100%)';\n      } else {\n        p.style.background = '';\n      }\n    });\n    const stage = document.getElementById('mimosa-stage');\n    if (stage) stage.classList.toggle('is-silver-metal', currentMetal === 'silver');\n    mimosaSyncBailVisuals(currentShape);\n    mimosaRefreshPins();\n  }\n\n  function mimosaDiamondAssetUrl() {\n    try {\n      if (typeof MIMOSA_DIAMOND_URL === 'string' && MIMOSA_DIAMOND_URL) return MIMOSA_DIAMOND_URL;\n    } catch (e) {}\n    return '';\n  }\n\n  // Jewelry gem + factory-sized gold collar. The openwork lattice also carries\n  // the seat for DXF, but on sparse drop maps the disc often failed to weld\n  // and the oversized 2mm gem covered what little gold remained \u2014 so the\n  // preview showed a naked diamond on a hairline road (\"\u4E3A\u4EC0\u4E48\u5C31\u4E0D\u80FD\u597D\u50CF\u5FC3\u5F62\n  // \u90A3\u6837\u94BB\u77F3\u65C1\u8FB9\u6709\u4E00\u5708\u91D1\u5C5E\u5462\"). Draw the 2.6mm seat / 1.6mm hole here so the\n  // collar is always visible and concentric with the stone.\n  function mimosaDiamondSvgMarkup(sizePx, withSeat) {\n    const s = Math.max(10, Math.round(sizePx || 16));\n    const metal = currentMetal === 'silver' ? MAP_LINE_SILVER : MIMOSA_METAL_FILL;\n    // viewBox units: outer seat r=32, hole scaled to factory hole/seat ratio.\n    const holeR = 32 * (MIMOSA_FACTORY_STONE_HOLE_MM / MIMOSA_FACTORY_SEAT_MM);\n    const facetScale = (0.86 * holeR / 18).toFixed(4);\n    // Outer gold disc + slightly darker rim so the 0.5mm collar still reads\n    // clearly on the small jewelry preview (user: white gem, no metal ring).\n    const seat = withSeat\n      ? '<circle cx=\"32\" cy=\"32\" r=\"32\" fill=\"' + metal + '\" shape-rendering=\"geometricPrecision\"/>'\n        + '<circle cx=\"32\" cy=\"32\" r=\"31\" fill=\"none\" stroke=\"' + metal + '\" stroke-width=\"2.5\" shape-rendering=\"geometricPrecision\"/>'\n      : '';\n    return '<svg class=\"mimosa-pin-diamond\" viewBox=\"0 0 64 64\" width=\"' + s + '\" height=\"' + s + '\" xmlns=\"http://www.w3.org/2000/svg\" overflow=\"visible\" aria-hidden=\"true\">'\n      + seat\n      + '<circle cx=\"32\" cy=\"32\" r=\"' + holeR.toFixed(2) + '\" fill=\"#FFFFFF\" stroke=\"none\"/>'\n      + '<g transform=\"translate(32 32) scale(' + facetScale + ') translate(-32 -32)\" stroke=\"#2A2A2A\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\" fill=\"none\" shape-rendering=\"geometricPrecision\">'\n      + '<polygon points=\"32,22 40,26 40,38 32,42 24,38 24,26\"/>'\n      + '<polygon points=\"32,14 44,19.5 40,26 32,22\"/>'\n      + '<polygon points=\"44,19.5 49,32 40,38 40,26\"/>'\n      + '<polygon points=\"49,32 44,44.5 40,38\"/>'\n      + '<polygon points=\"44,44.5 32,50 32,42 40,38\"/>'\n      + '<polygon points=\"32,50 20,44.5 24,38 32,42\"/>'\n      + '<polygon points=\"20,44.5 15,32 24,38\"/>'\n      + '<polygon points=\"15,32 20,19.5 24,26 24,38\"/>'\n      + '<polygon points=\"20,19.5 32,14 32,22 24,26\"/>'\n      + '</g></svg>';\n  }\n\n  function mimosaGemBoxPx(mapRef) {\n    // Marker box = factory seat outer diameter so the gold collar is not clipped.\n    return Math.max(14, mimosaMmToPx(mapRef, MIMOSA_FACTORY_SEAT_MM));\n  }\n\n  function mimosaPinSvg(forJewelry) {\n    // Jewelry View: gold seat disc + white stone hole + facet pattern.\n    if (forJewelry) {\n      const mapRef = mapAfter || mapHis;\n      const box = mimosaGemBoxPx(mapRef);\n      const gem = mimosaDiamondSvgMarkup(box, true);\n      return '<div class=\"mimosa-pin-jewelry\" style=\"width:' + box.toFixed(1) + 'px;height:' + box.toFixed(1) + 'px;display:flex;align-items:center;justify-content:center;position:relative;pointer-events:none\">'\n        + gem\n        + '</div>';\n    }\n    // Map view: gold pin, clearly visible on the light map background.\n    // The viewBox ends at the teardrop's TIP (MIMOSA_PIN_TIP_Y), and the box\n    // keeps that aspect ratio, so with anchor:'bottom' the tip is what sits on\n    // the chosen lng/lat \u2014 exactly like the etched badge, which anchors its\n    // tip too. It used to be a 56x64 viewBox in a 37x44 box: the tip sat 12.6\n    // viewBox units above the bottom edge, so the marker pointed at a spot\n    // ~9px above the coordinate it actually stored, and the badge in Jewelry\n    // View (tip-anchored) did not line up with it. The coordinates engraved on\n    // the back read from the same stored point, so this made those wrong too.\n    const w = 37;\n    const h = +(37 * (MIMOSA_PIN_TIP_Y / 56)).toFixed(2);\n    const uid = 'mp';\n    return `\n      <svg viewBox=\"0 0 56 ${MIMOSA_PIN_TIP_Y}\" width=\"${w}\" height=\"${h}\" xmlns=\"http://www.w3.org/2000/svg\" overflow=\"visible\">\n        <defs>\n          <linearGradient id=\"mimosa-pin-gold-${uid}\" x1=\"0.18\" y1=\"0\" x2=\"0.82\" y2=\"1\">\n            <stop offset=\"0%\" stop-color=\"#F5E070\"/>\n            <stop offset=\"35%\" stop-color=\"#E8C84A\"/>\n            <stop offset=\"70%\" stop-color=\"#C8A030\"/>\n            <stop offset=\"100%\" stop-color=\"#A07820\"/>\n          </linearGradient>\n          <filter id=\"mimosa-pin-glow-${uid}\" x=\"-30%\" y=\"-30%\" width=\"160%\" height=\"160%\">\n            <feDropShadow dx=\"0\" dy=\"1.5\" stdDeviation=\"2\" flood-color=\"#000000\" flood-opacity=\"0.35\"/>\n          </filter>\n        </defs>\n        <path d=\"${MIMOSA_PIN_OUTER_D}\" fill=\"url(#mimosa-pin-gold-${uid})\" stroke=\"#8A6010\" stroke-width=\"1.6\" filter=\"url(#mimosa-pin-glow-${uid})\"/>\n        <circle cx=\"${MIMOSA_PIN_CENTER_X}\" cy=\"${MIMOSA_PIN_CIRCLE_CY}\" r=\"${MIMOSA_MAP_PIN_GEM_R}\" fill=\"#F3E6C0\" stroke=\"#8A6010\" stroke-width=\"1\"/>\n        <circle cx=\"${(MIMOSA_PIN_CENTER_X - MIMOSA_MAP_PIN_GEM_R * 0.32).toFixed(2)}\" cy=\"${(MIMOSA_PIN_CIRCLE_CY - MIMOSA_MAP_PIN_GEM_R * 0.32).toFixed(2)}\" r=\"${(MIMOSA_MAP_PIN_GEM_R * 0.28).toFixed(2)}\" fill=\"#FFF8E8\" opacity=\"0.75\"/>\n      </svg>\n    `;\n  }\n\n  // Recompute the etched geometry after the badge has moved. The badge is\n  // part of the block polygons now, so moving it means redoing the same\n  // union/difference the streets go through \u2014 hundreds of ms at a dense\n  // location, which is why this runs on drag *end* and not per frame (the\n  // 7.6s/UI-freeze lesson from the road work applies here too). Debounced so\n  // a click-then-drag, or both markers reporting the same move, only pays\n  // for one rebuild.\n  function mimosaMapHasSize(map) {\n    try {\n      const c = map && map.getCanvas && map.getCanvas();\n      return !!c && c.clientWidth > 10 && c.clientHeight > 10;\n    } catch (e) { return false; }\n  }\n\n  let mimosaShapeSwitchTimer = null;\n  function mimosaBeginShapeSwitch() {\n    const stage = document.getElementById('mimosa-stage');\n    if (stage) {\n      stage.classList.add('is-shape-transitioning');\n      if (mimosaShapeSwitchTimer) clearTimeout(mimosaShapeSwitchTimer);\n      mimosaShapeSwitchTimer = setTimeout(function () {\n        stage.classList.remove('is-shape-transitioning');\n      }, 550);\n    }\n  }\n\n  function mimosaEndShapeSwitch() {\n    const stage = document.getElementById('mimosa-stage');\n    if (stage && stage.classList.contains('is-shape-transitioning')) {\n      if (mimosaShapeSwitchTimer) clearTimeout(mimosaShapeSwitchTimer);\n      requestAnimationFrame(function () {\n        requestAnimationFrame(function () {\n          stage.classList.remove('is-shape-transitioning');\n        });\n      });\n    }\n  }\n\n  // Recompute a map that was skipped while hidden, once it has a size again.\n  // Called after the view switcher resizes it \u2014 immediately if canvas already\n  // has size, with a short fallback if still sizing.\n  function mimosaRebuildIfPending(map) {\n    if (!map || !map._mimosaNeedsEtchRebuild) return;\n    map._mimosaNeedsEtchRebuild = false;\n    if (mimosaMapHasSize(map)) {\n      try { mimosaApplyRoadFilter(map, 'etched'); } catch (e) {}\n    } else {\n      setTimeout(function () {\n        if (!mimosaMapHasSize(map)) return;\n        try { mimosaApplyRoadFilter(map, 'etched'); } catch (e) {}\n      }, 30);\n    }\n  }\n\n  let mimosaPinRebuildTimer = null;\n  function mimosaRebuildEtchedGeometry(delayMs) {\n    if (mimosaPinRebuildTimer) clearTimeout(mimosaPinRebuildTimer);\n    // Trailing debounce, re-armed by every 'drag' event, so the rebuild runs\n    // once the pin comes to rest. Deliberately NOT driven by 'dragend'\n    // alone: a drag that ends without one (pointer released off-canvas, a\n    // synthetic drag, a cancelled gesture) would otherwise leave the ghost\n    // stuck on screen next to a badge still etched at the old spot \u2014 which\n    // is exactly what happened the first time this was wired up.\n    mimosaPinRebuildTimer = setTimeout(function () {\n      mimosaPinRebuildTimer = null;\n      mimosaSetPinDragging(false);\n      // Hers + His share one pin \u2014 rebuild both seats so neither keeps a\n      // stale second diamond hole (\"\u5973\u6B3E\u4E0E\u7537\u6B3E\u7684\u94BB\u77F3\u8981\u53D8\u00B7\u4E0D\u80FD\u67092\u4E2A\").\n      [mapAfter, mapHis].forEach(function (m) {\n        try {\n          if (!m || !m.isStyleLoaded || !m.isStyleLoaded()) return;\n          if (!mimosaMapHasSize(m)) {\n            m._mimosaNeedsEtchRebuild = true;\n            return;\n          }\n          mimosaApplyRoadFilter(m, 'etched');\n        } catch (eRb) {}\n      });\n    }, isFinite(delayMs) ? delayMs : 320);\n  }\n\n  // Show/hide the drag ghost on the jewelry markers (see mimosaPinSvg).\n  function mimosaSetPinDragging(on) {\n    [diamondMarkerAfter, diamondMarkerHis].forEach(function (m) {\n      if (!m || !m.getElement) return;\n      const el = m.getElement();\n      if (el) el.classList.toggle('is-pin-dragging', !!on);\n    });\n  }\n\n  function mimosaRefreshPins() {\n    if (diamondMarkerBefore) {\n      const el = diamondMarkerBefore.getElement();\n      if (el) el.innerHTML = mimosaPinSvg(false);\n    }\n    [diamondMarkerAfter, diamondMarkerHis].forEach(function (marker) {\n      if (!marker) return;\n      const el = marker.getElement();\n      if (!el) return;\n      const mapRef = mapAfter || mapHis;\n      const box = mimosaGemBoxPx(mapRef);\n      el.style.width = box.toFixed(1) + 'px';\n      el.style.height = box.toFixed(1) + 'px';\n      el.innerHTML = mimosaPinSvg(true);\n    });\n  }\n\n  /**\n   * Convert physical mm \u2192 CSS px on the jewelry map canvas.\n   * Artboard assumption: the PIECE's bounding width = mimosaPieceWidthMm(shape) (25mm; His \u224827.1mm).\n   */\n  // Artboard units spanned by the pendant outline (not the full 0\u2013100 viewBox).\n  // Treating 100 units as PENDANT_WIDTH_MM made every mm-based feature ~1.6\u00D7\n  // oversized (heart only spans ~62 units). Measure the outline instead.\n  // Circle/drop use SVG arcs \u2014 naively reading every other number treats the\n  // arc radius/flags as X coords (circle collapsed to span 53.7 instead of 64)\n  // and threw road mm\u2192px off for that shape alone.\n  function mimosaShapeSpanUnits(shape) {\n    const key = shape || currentShape || 'heart';\n    const known = { heart: 61.9, circle: 64, drop: 46.5, shield: 67 };\n    if (known[key]) return known[key];\n    const d = mimosaPathForShape(key);\n    let wide = MIMOSA_PENDANT_UNITS;\n    try {\n      const subs = mimosaParsePathD(d);\n      let minX = Infinity, maxX = -Infinity;\n      subs.forEach(function (pts) {\n        pts.forEach(function (p) {\n          if (p.x < minX) minX = p.x;\n          if (p.x > maxX) maxX = p.x;\n        });\n      });\n      const span = maxX - minX;\n      if (span > 5 && span <= 100) wide = span;\n    } catch (eU) {}\n    return wide;\n  }\n\n  function mimosaUnitsPerMm(shape) {\n    return mimosaShapeSpanUnits(shape) / mimosaPieceWidthMm(shape);\n  }\n\n  function mimosaMapPieceShape(map) {\n    return map === mapHis ? 'shield' : (currentSet === 'pair' ? mimosaHersShape() : currentShape);\n  }\n\n  function mimosaRoadScaleShape() {\n    // At equal zoom, use the shield's road width for both pieces so the\n    // smaller drop's ribbons are never treated as thin necks on the shield.\n    return currentSet === 'pair' ? 'shield' : currentShape;\n  }\n\n  function mimosaMmToPx(map, mm, shapeHint) {\n    const w = (map && map.getCanvas && map.getCanvas() && map.getCanvas().clientWidth) || 400;\n    const shape = shapeHint || mimosaMapPieceShape(map);\n    return mm * mimosaUnitsPerMm(shape) * (w / 100);\n  }\n\n  // Physical mm \u2192 metres on the CURRENT camera. Measure with the artboard\n  // span (not by re-parsing arc outlines): circle/drop A-commands used to\n  // make outline bbox flaky, and a 0-metre width aborted the whole road\n  // buffer pass \u2014 blank pendant (\"\u6C34\u6EF4\u4E0E\u5706\u5F62\u90FD\u4E0D\u89C1\u4E86\u5730\u56FE\").\n  function mimosaMmToMeters(map, mm, shapeHint) {\n    if (!(mm > 0) || !map) return 0;\n    const shape = shapeHint || mimosaMapPieceShape(map) || 'heart';\n    try {\n      const canvas = map.getCanvas && map.getCanvas();\n      const w = (canvas && canvas.clientWidth) || 0;\n      const h = (canvas && canvas.clientHeight) || 0;\n      if (w > 10 && h > 10 && typeof turf !== 'undefined') {\n        const span = mimosaShapeSpanUnits(shape);\n        const y = h * 0.5;\n        const left = map.unproject([((50 - span / 2) / 100) * w, y]);\n        const right = map.unproject([((50 + span / 2) / 100) * w, y]);\n        const widthM = turf.distance(\n          turf.point([left.lng, left.lat]),\n          turf.point([right.lng, right.lat]),\n          { units: 'meters' }\n        );\n        if (widthM > 0) return mm * (widthM / mimosaPieceWidthMm(shape));\n      }\n    } catch (eM) {}\n    try {\n      return mimosaPxToMeters(map, mimosaMmToPx(map, mm, shape));\n    } catch (e2) { return 0; }\n  }\n\n  function mimosaEtchLineWidth(map) {\n    const street = mimosaMmToPx(map, 0.6);\n    const major = mimosaMmToPx(map, 0.8);\n    return [\n      'match', ['coalesce', ['get', 'class'], 'street'],\n      ['motorway', 'trunk', 'primary', 'motorway_link', 'trunk_link', 'primary_link'], major,\n      street\n    ];\n  }\n\n  /** Openwork: same physical caps \u2014 0.6mm / 0.8mm only */\n  function mimosaOpenworkLineWidth(map) {\n    return mimosaEtchLineWidth(map);\n  }\n\n  function mimosaIsMapRoadLine(id) {\n    const n = String(id || '').toLowerCase();\n    if (/label|name|shield|icon|admin|boundary|rail|ferry|building|house|landuse/.test(n)) return false;\n    return /^(road-simple|tunnel-simple|bridge-simple)$/.test(n)\n      || (/road|street|motorway|trunk|primary|secondary|tertiary|bridge|tunnel/.test(n) && /simple|case|line/.test(n));\n  }\n\n  /**\n   * Keep the street grid visible at every zoom \u2014 only drop true clutter.\n   * Openwork is MUCH stricter: only connected arteries (no floating street crumbs).\n   *\n   * Checked Talisa's own live configurator (the actual reference site) at a\n   * matching tight, single-block zoom: they do NOT add more road classes\n   * in close \u2014 the same 1-2 arterial streets stay engraved. A building-\n   * footprint layer was tried as the \"more detail at zoom\" answer instead,\n   * but was dropped per explicit user direction \u2014 streets only, no\n   * buildings. So the road whitelist stays a single fixed tier regardless\n   * of zoom, and there's no other detail source layered on top of it.\n   */\n  function mimosaSimplifiedRoadFilter(mode) {\n    if (mode === 'openwork') {\n      // Factory openwork: only spines that stay attached to the rim / river\n      return [\n        'match',\n        ['coalesce', ['get', 'class'], ''],\n        [\n          'motorway', 'trunk', 'primary', 'secondary',\n          'motorway_link', 'trunk_link', 'primary_link', 'secondary_link',\n          'bridge'\n        ],\n        true,\n        false\n      ];\n    }\n    // Must list exactly the classes in MIMOSA_ROAD_CLASS_TIERS (plus 'bridge').\n    // This filter is what Map View shows the customer while they place the\n    // pin, and the tiers are what the pendant may engrave \u2014 if the pendant's\n    // set is the wider one, it draws streets that simply are not on the map\n    // they were looking at. Named streets are in; driveways, service aisles\n    // and footpaths stay out of both.\n    return [\n      'match',\n      ['coalesce', ['get', 'class'], ''],\n      [\n        'motorway', 'trunk', 'primary', 'secondary', 'tertiary',\n        'motorway_link', 'trunk_link', 'primary_link', 'secondary_link', 'tertiary_link',\n        'street', 'street_limited',\n        'bridge'\n      ],\n      true,\n      false\n    ];\n  }\n\n  /** Fallback if step/zoom filter unsupported \u2014 apply by current zoom number */\n  function mimosaRoadFilterForZoom(z, mode) {\n    z = typeof z === 'number' ? z : 14;\n    if (mode === 'openwork') {\n      return [\n        'match',\n        ['coalesce', ['get', 'class'], ''],\n        ['motorway', 'trunk', 'primary', 'secondary', 'motorway_link', 'trunk_link', 'primary_link', 'secondary_link', 'bridge'],\n        true,\n        false\n      ];\n    }\n    return [\n      'match',\n      ['coalesce', ['get', 'class'], ''],\n      [\n        'motorway', 'trunk', 'primary', 'secondary', 'tertiary',\n        'motorway_link', 'trunk_link', 'primary_link', 'secondary_link', 'tertiary_link',\n        'street', 'street_limited',\n        'bridge'\n      ],\n      true,\n      false\n    ];\n  }\n\n  // Same erosion approach for every pendant shape: each array is the\n  // shape's outer path eroded inward by a uniform margin (computed\n  // offline via turf.buffer on the shape's own bezier/arc-flattened\n  // outline, in 0-100 pendant-space units, same margin as the content\n  // mask erosion). Kept here so each can be projected into real lng/lat\n  // and cut wherever it crosses actual map content.\n  // MIMOSA_RING_POINTS and the MIMOSA_*_OUTER / _INNER outline constants all\n  // live in assets/mimosa-shape-rings.js \u2014 pure data, moved out to keep this\n  // template under Shopify's 256KB limit. See that file.\n\n  // The decorative boundary ring (between the engraved area and the plain\n  // rim) used to be a static SVG shape, always a solid closed line \u2014 but a\n  // solid line crossing straight through road/building/water lines reads\n  // as clutter, not as the clean \"separate facets\" look real engraved\n  // jewelry has. Real pieces leave a small gap in the ring wherever an\n  // internal line reaches it, so each area between streets reads as its\n  // own distinct block. Since where those gaps belong depends on the\n  // actual streets at the current location/zoom, the ring can't be a\n  // static shape any more \u2014 project it into the map's real lng/lat (via\n  // the same pixel mapping the SVG overlay itself uses), buffer it into a\n  // thin strip, and subtract the (already-computed) road/water/building\n  // line buffers from that strip, same difference-based approach as the\n  // block/road geometry above.\n  function mimosaRingLngLat(map, shape) {\n    const canvas = map.getCanvas();\n    const w = (canvas && canvas.clientWidth) || 400;\n    const h = (canvas && canvas.clientHeight) || 400;\n    const points = MIMOSA_RING_POINTS[shape] || MIMOSA_RING_POINTS.heart;\n    return points.map(function (p) {\n      const px = (p[0] / 100) * w;\n      const py = (p[1] / 100) * h;\n      const ll = map.unproject([px, py]);\n      return [ll.lng, ll.lat];\n    });\n  }\n\n  // The engraved field as a real turf polygon in lng/lat \u2014 the boundary ring,\n  // unprojected through the current camera. Both the preview and the factory\n  // export cut their block geometry against this, so the two are the same\n  // drawing.\n  //\n  // RING_POINTS is inset 3.5 from the outer outline. The map mask only erodes\n  // ~1 unit, so the leftover band showed as a fat white collar inside a thick\n  // gold frame (\"\u8FB9\u7F18\u592A\u7C97\u4E86\"). Expand the field back toward the mask edge so\n  // the visible rim stays a thin gold border like the real cut piece.\n  // The rim is solid metal: no void may sit in it. Every real block stops at\n  // the boundary ring (inset 3.5), but a sharp tip could still leave a scrap\n  // of void between the tip and the field's chord, cut as a tiny extra\n  // triangle in the corner of the shield (\"\u8FD8\u662F\u6709\u4E00\u4E2A\u591A\u4F59\u5C0F\u7684\u4E09\u89D2\u5F62\u5728\u5DE6\u4E0A\u89D2\").\n  // Clip the voids to the ring plus a small margin; whatever falls outside\n  // goes back to metal. Shield only: its tips are the sharp corners where\n  // this happens, and the heart's cleft has real blocks just past the margin.\n  function mimosaKeepVoidsInFace(map, shape, voids) {\n    if (shape !== 'shield' || !voids || !map || typeof turf === 'undefined') return voids;\n    try {\n      const coords = mimosaRingLngLat(map, shape);\n      if (!coords || coords.length < 4) return voids;\n      const a = coords[0], b = coords[coords.length - 1];\n      if (a[0] !== b[0] || a[1] !== b[1]) coords.push(a);\n      let face = turf.polygon([coords]);\n      const marginM = mimosaMmToMeters(map, 0.5);\n      if (marginM > 0) {\n        const grown = turf.buffer(face, marginM, { units: 'meters', steps: 8 });\n        if (grown) face = grown;\n      }\n      const before = turf.area(voids);\n      const kept = turf.intersect(voids, face);\n      if (!kept) return null;\n      if (Math.abs(turf.area(kept) - before) < before * 1e-6) return voids;\n      return kept;\n    } catch (eFace) { return voids; }\n  }\n\n  // The shield's two upper points. The round 1.5mm field buffer cannot\n  // reach them, so it leaves a chord, and that chord is the extra triangle\n  // on the factory cut (\"\u5DE6\u8FB9\u5C16\u89D2\u591A\u4E86\u4E00\u4E2A\u4E09\u89D2\u5F62\").\n  function mimosaShieldTipTris() {\n    const subs = mimosaParsePathD(mimosaPathForShape('shield'));\n    const pts = (subs && subs[0]) ? subs[0].slice() : [];\n    if (pts.length < 4) return [];\n    if (Math.hypot(pts[0].x - pts[pts.length - 1].x, pts[0].y - pts[pts.length - 1].y) < 0.05) pts.pop();\n    let minX = Infinity, maxX = -Infinity;\n    pts.forEach(function (p) { minX = Math.min(minX, p.x); maxX = Math.max(maxX, p.x); });\n    const tris = [];\n    const n = pts.length;\n    for (let i = 0; i < n; i++) {\n      const a = pts[(i - 1 + n) % n], b = pts[i], c = pts[(i + 1) % n];\n      if (b.x - minX > 3 && maxX - b.x > 3) continue;\n      const v1x = a.x - b.x, v1y = a.y - b.y, v2x = c.x - b.x, v2y = c.y - b.y;\n      const m1 = Math.hypot(v1x, v1y), m2 = Math.hypot(v2x, v2y);\n      if (!m1 || !m2) continue;\n      const cos = Math.max(-1, Math.min(1, (v1x * v2x + v1y * v2y) / (m1 * m2)));\n      if (Math.acos(cos) * 180 / Math.PI >= 85) continue;\n      tris.push({ tip: [b.x, b.y], prev: [a.x, a.y], next: [c.x, c.y] });\n    }\n    return tris;\n  }\n\n  function mimosaTipArtboardToLngLat(map, p) {\n    const canvas = map.getCanvas();\n    const w = (canvas && canvas.clientWidth) || 400;\n    const h = (canvas && canvas.clientHeight) || 400;\n    const ll = map.unproject([(p[0] / 100) * w, (p[1] / 100) * h]);\n    return [ll.lng, ll.lat];\n  }\n\n  function mimosaTipFillers(map, shape) {\n    if (shape !== 'shield') return [];\n    const fillers = [];\n    mimosaShieldTipTris().forEach(function (tri) {\n      const ring = [tri.tip, tri.prev, tri.next].map(function (p) {\n        return mimosaTipArtboardToLngLat(map, p);\n      });\n      ring.push(ring[0]);\n      try { fillers.push(turf.polygon([ring])); } catch (eTip) {}\n    });\n    return fillers;\n  }\n\n  function mimosaFieldPolygon(map, shape) {\n    try {\n      const coords = mimosaRingLngLat(map, shape);\n      if (!coords || coords.length < 4) return null;\n      const a = coords[0], b = coords[coords.length - 1];\n      if (a[0] !== b[0] || a[1] !== b[1]) coords.push(a);\n      let field = turf.polygon([coords]);\n      const expandM = mimosaMmToMeters(map, 1.5);\n      if (expandM > 0) {\n        try {\n          const grown = turf.buffer(field, expandM, { units: 'meters', steps: 8 });\n          if (grown) field = grown;\n        } catch (eExp) {}\n      }\n      // The 1.5mm grow is a round buffer. On the shield's sharp tips it both\n      // steps outside the silhouette and leaves a chord across the point. That\n      // chord is the extra triangle (\"\u5DE6\u8FB9\u5C16\u89D2\u591A\u4E86\u4E00\u4E2A\u4E09\u89D2\u5F62\"). Fill the tip,\n      // then keep the field inside the blank.\n      mimosaTipFillers(map, shape).forEach(function (tip) {\n        try {\n          const filled = turf.union(field, tip);\n          if (filled && filled.geometry) field = filled;\n        } catch (eTip) {}\n      });\n      try {\n        const outline = mimosaOutlinePolygonLngLat(map, shape);\n        if (outline) {\n          const clipped = turf.intersect(field, outline);\n          if (clipped && clipped.geometry) field = clipped;\n        }\n      } catch (eClip) {}\n      return field;\n    } catch (eField) { return null; }\n  }\n\n  // One street network for Hers and His. Each piece still clips to its own\n  // outline, but the roads are chosen once per camera. Rebuilding the hidden\n  // piece on its own tiles made the two previews diverge (\"\u7537\u5973\u6B3E\u6709\u4E9B\u65F6\u5019\u8FD8\u662F\u4E0D\u4E00\u6837\").\n  let mimosaSharedRoads = null;\n  function mimosaCameraMatches(map, saved) {\n    if (!map || !saved) return false;\n    try {\n      const c = map.getCenter();\n      return Math.abs(c.lng - saved.lng) < 1e-5\n        && Math.abs(c.lat - saved.lat) < 1e-5\n        && Math.abs((map.getZoom() || 0) - saved.zoom) < 0.05;\n    } catch (eCam) { return false; }\n  }\n  function mimosaRoadNetwork(map) {\n    const center = map.getCenter();\n    const camera = { lng: center.lng, lat: center.lat, zoom: map.getZoom() };\n    const set = currentSet;\n    const paired = set === 'pair';\n    const source = paired && mimosaMapHasSize(mapAfter) && mimosaCameraMatches(mapAfter, camera) ? mapAfter : map;\n    const canvas = source.getCanvas();\n    const shape = paired ? mimosaHersShape() : currentShape;\n    const cached = paired ? mimosaSharedRoads : map._mimosaRoadNetwork;\n    if (cached && cached.source === source && cached.shape === shape\n        && cached.width === canvas.clientWidth && cached.height === canvas.clientHeight\n        && mimosaCameraMatches(source, cached.camera)) {\n      return cached.promise;\n    }\n\n    const entry = { source, shape, width: canvas.clientWidth, height: canvas.clientHeight, camera };\n    if (paired) mimosaSharedRoads = entry;\n    else map._mimosaRoadNetwork = entry;\n    const current = () => paired ? mimosaSharedRoads : map._mimosaRoadNetwork;\n    const stale = () => current() !== entry || !mimosaCameraMatches(source, camera)\n      || currentSet !== set\n      || shape !== (paired ? mimosaHersShape() : currentShape);\n    entry.promise = (async function () {\n      if (typeof source.areTilesLoaded === 'function' && !source.areTilesLoaded()) {\n        await mimosaWaitMapIdle(source, 1500);\n      }\n      if (stale()) return [];\n      const roadLayers = (source.getStyle()?.layers || [])\n        .filter(layer => layer.type === 'line' && mimosaIsMapRoadLine(layer.id))\n        .map(layer => layer.id);\n      const roads = await mimosaBuildRoadBufferPolys(source, roadLayers, stale);\n      if (!roads.length && current() === entry) {\n        if (paired) mimosaSharedRoads = null;\n        else map._mimosaRoadNetwork = null;\n      }\n      return roads;\n    })();\n    return entry.promise;\n  }\n\n  function mimosaOpenworkViewKey(map) {\n    const center = map.getCenter();\n    const canvas = map.getCanvas();\n    const pin = mimosaReadPinLatLng();\n    return [\n      center.lng.toFixed(7), center.lat.toFixed(7), map.getZoom().toFixed(4),\n      canvas.clientWidth, canvas.clientHeight, mimosaMapPieceShape(map), currentSet,\n      currentSet === 'pair' ? mimosaHersShape() : '', pin.lng, pin.lat\n    ].join('|');\n  }\n\n  function mimosaApplyRoadFilter(map, mode) {\n    if (mode === 'etched' && !map._mimosaLiveLattice\n        && map.getSource('mimosa-road-channel-src')\n        && map._mimosaRenderedOpenwork === mimosaOpenworkViewKey(map)) {\n      return Promise.resolve();\n    }\n    const layers = (map.getStyle() && map.getStyle().layers) || [];\n    const z = map.getZoom ? map.getZoom() : 14;\n    // While the customer is still moving, the live lattice is the picture.\n    // Zeroing these lines here used to blank the face for the whole rebuild,\n    // so the diamond showed up first and the streets followed (\"\u4E0D\u80FD\u51FA\u73B0\u94BB\u77F3\n    // \u518D\u51FA\u73B0\u9053\u8DEF\").\n    const live = mode === 'etched' && map._mimosaLiveLattice;\n    if (live) mimosaShowLiveLattice(map);\n    layers.forEach(function (layer) {\n      if (layer.type !== 'line' || !mimosaIsMapRoadLine(layer.id)) return;\n      if (live) return;\n      try {\n        map.setFilter(layer.id, mimosaSimplifiedRoadFilter(mode));\n      } catch (e1) {\n        try { map.setFilter(layer.id, mimosaRoadFilterForZoom(z, mode)); } catch (e2) {}\n      }\n      try {\n        map.setPaintProperty(layer.id, 'line-opacity', 0);\n      } catch (eW) {}\n    });\n    if (mode === 'etched') {\n      const roadLayerIds = layers\n        .filter(function (l) { return l.type === 'line' && mimosaIsMapRoadLine(l.id); })\n        .map(function (l) { return l.id; });\n      // A map whose canvas has no size on screen \u2014 the His piece whenever its\n      // tab is closed \u2014 still answers queryRenderedFeatures (measured: 572\n      // features, 124ms per recompute, MORE than the visible piece costs) and\n      // was rebuilding its blocks, ring and badge on every pan, zoom and pin\n      // move to produce geometry nobody can see. That alone more than doubled\n      // the cost of every interaction. Skip it and note that it owes a\n      // rebuild for when its tab is opened.\n      if (!mimosaMapHasSize(map)) {\n        map._mimosaNeedsEtchRebuild = true;\n        return;\n      }\n      // Newest recompute wins: bump a generation token and let any run still\n      // in flight notice it is stale and drop out rather than overwrite the\n      // fresher result. Needed now that the union spans several frames.\n      // Also abort if the camera zoom moved mid-build \u2014 otherwise a slow\n      // rebuild from zoom N lands on zoom N+2 and overlaps the live lattice.\n      const gen = (map._mimosaGen = (map._mimosaGen || 0) + 1);\n      const center = map.getCenter();\n      const cameraAtStart = { lng: center.lng, lat: center.lat, zoom: map.getZoom() };\n      const shouldAbort = function () {\n        return map._mimosaGen !== gen || !mimosaCameraMatches(map, cameraAtStart);\n      };\n      return mimosaRoadNetwork(map)\n        .then(function (roadPolys) {\n          if (shouldAbort() || !roadPolys) return;\n          return mimosaEnsureRoadChannelLayer(map, roadLayerIds, roadPolys, shouldAbort);\n        })\n        .catch(function (eAsync) { console.warn('etched recompute', eAsync); });\n    }\n    return Promise.resolve();\n  }\n\n  // Map View (the location-picker map) was left showing Mapbox's full,\n  // unfiltered street grid while the Jewelry View only engraves the major-\n  // class whitelist \u2014 so a customer picking a spot saw far more streets\n  // than would actually end up on the pendant. Apply the same whitelist\n  // here (filter only \u2014 keep normal visible strokes, no etched styling)\n  // so Map View previews exactly what the necklace will carry.\n  function mimosaApplyMapViewRoadFilter(map) {\n    if (!map) return;\n    function apply() {\n      const layers = (map.getStyle() && map.getStyle().layers) || [];\n      const filter = mimosaSimplifiedRoadFilter('etched');\n      layers.forEach(function (layer) {\n        if (layer.type !== 'line' || !mimosaIsMapRoadLine(layer.id)) return;\n        try { map.setFilter(layer.id, filter); } catch (e1) {\n          try { map.setFilter(layer.id, mimosaRoadFilterForZoom(map.getZoom ? map.getZoom() : 14, 'etched')); } catch (e2) {}\n        }\n      });\n    }\n    if (map.isStyleLoaded()) apply();\n    else map.once('load', apply);\n    if (!map._mimosaMapViewFilterBound) {\n      map._mimosaMapViewFilterBound = true;\n      map.on('style.load', apply);\n    }\n  }\n\n  function mimosaIsWaterFill(id, layer) {\n    const name = String(id || '').toLowerCase();\n    const srcLayer = String((layer && layer['source-layer']) || '').toLowerCase();\n    if (/label|shadow|pattern/.test(name + srcLayer)) return false;\n    return /water|ocean|lake|river|bay|harbour|harbor|reservoir|sea/.test(name)\n      || /water|ocean|lake/.test(srcLayer);\n  }\n\n\n  /**\n   * Openwork preview matching the real pendant photo:\n   * white cut voids + gold metal street/river ribbons.\n   */\n  function applyEtchedStreetLines(map) {\n    function paint() {\n      // White canvas = hollow cutouts. Gold metal fill from\n      // mimosaEnsureRoadChannelLayer. Force normal blend so white stays white.\n      const plate = MIMOSA_CANVAS_BASE;\n      document.querySelectorAll('.mimosa-jewelry-map-mask').forEach(function (el) {\n        el.style.mixBlendMode = 'normal';\n      });\n      document.querySelectorAll('.mimosa-layer-jewelry .mimosa-map-canvas, .mimosa-layer-jewelry .mapboxgl-canvas').forEach(function (el) {\n        el.style.background = plate;\n      });\n      const layers = (map.getStyle() && map.getStyle().layers) || [];\n      const roadLayerIds = [];\n      layers.forEach(function (layer) {\n        const id = layer.id;\n        const type = layer.type;\n        if (id === 'mimosa-road-channel' || id === 'mimosa-road-channel-fill') return;\n        try {\n          if (String(id).indexOf('mimosa-shore-') === 0 || String(id).indexOf('mimosa-water-outline-') === 0 || String(id).indexOf('mimosa-water-line') === 0) {\n            try { map.removeLayer(id); } catch (eRm) {}\n            return;\n          }\n          if (type === 'background') {\n            map.setPaintProperty(id, 'background-color', plate);\n            try { map.setPaintProperty(id, 'background-opacity', 1); } catch (eBg) {}\n          } else if (type === 'symbol') {\n            map.setLayoutProperty(id, 'visibility', 'none');\n          } else if (type === 'fill') {\n            map.setLayoutProperty(id, 'visibility', 'none');\n            try { map.setPaintProperty(id, 'fill-opacity', 0); } catch (eFc) {}\n          } else if (type === 'line' && mimosaIsMapRoadLine(id)) {\n            // Keep layers VISIBLE (opacity 0) so Mapbox still fetches the\n            // road vector tiles. visibility:none stopped tile loading and the\n            // openwork metal rebuild got an empty road pool \u2014 blank pendant\n            // (\"\u7A81\u7136\u4E0D\u663E\u793A\u4E86\"). Color them gold as a safety net if opacity\n            // ever flickers.\n            map.setLayoutProperty(id, 'visibility', 'visible');\n            try {\n              map.setPaintProperty(id, 'line-color', currentMetal === 'silver' ? MAP_LINE_SILVER : MIMOSA_METAL_FILL);\n            } catch (eCol) {}\n            roadLayerIds.push(id);\n          } else if (type === 'line') {\n            map.setLayoutProperty(id, 'visibility', 'none');\n          }\n        } catch (err) {}\n      });\n      if (!map.getLayer('mimosa-road-channel-fill')) {\n        mimosaShowLiveLattice(map);\n      }\n      mimosaApplyRoadFilter(map, 'etched');\n      const canvas = document.querySelector('.mimosa-layer-jewelry .mimosa-map-canvas');\n      if (canvas) canvas.style.background = plate;\n      try {\n        const c = map.getCanvas();\n        if (c) c.style.background = plate;\n      } catch (eC) {}\n    }\n\n    if (map.isStyleLoaded()) paint();\n    else map.once('load', paint);\n    if (!map._mimosaEtchBound) {\n      map._mimosaEtchBound = true;\n      map.on('style.load', paint);\n    }\n    if (!map._mimosaZoomSimplifyBound) {\n      map._mimosaZoomSimplifyBound = true;\n      map._mimosaZoomToken = 0;\n      function mimosaWaitTilesThen(map, token, cb) {\n        let tries = 0;\n        let done = false;\n        const finish = function () {\n          if (done || map._mimosaZoomToken !== token) return;\n          done = true;\n          // Let Mapbox commit the new tile set before we query features.\n          requestAnimationFrame(function () {\n            if (map._mimosaZoomToken !== token) return;\n            cb();\n          });\n        };\n        const check = function () {\n          if (map._mimosaZoomToken !== token) return;\n          tries++;\n          let tilesReady = true;\n          try {\n            if (typeof map.areTilesLoaded === 'function') tilesReady = !!map.areTilesLoaded();\n          } catch (eT) {}\n          if (tilesReady) {\n            let idleHandled = false;\n            try {\n              map.once('idle', function () {\n                idleHandled = true;\n                finish();\n              });\n            } catch (eI) {}\n            // The live lattice is already on screen, so this wait only gates\n            // the closed-ribbon swap. 700ms plus a second full rebuild was\n            // the stall after every zoom.\n            setTimeout(function () {\n              if (!idleHandled) finish();\n            }, 420);\n            return;\n          }\n          if (tries > 80) { finish(); return; }\n          setTimeout(check, 50);\n        };\n        check();\n      }\n      function mimosaBeginLiveGesture(e) {\n        // Only switch to live lattice for physical user drag/pinch gestures.\n        // Programmatic movements (sync, resize, camera jumpTo) must never wipe out the metal layer!\n        if (e && !e.originalEvent) return;\n        map._mimosaGen = (map._mimosaGen || 0) + 1;\n        map._mimosaZoomToken = (map._mimosaZoomToken || 0) + 1;\n        if (map._mimosaZoomTimer) {\n          clearTimeout(map._mimosaZoomTimer);\n          map._mimosaZoomTimer = null;\n        }\n        mimosaShowLiveLattice(map);\n      }\n      function scheduleRefilter() {\n        // One rebuild after the camera stops. Skip while an address fly/jump\n        // is in flight or a sync jumpTo is echoing moveend \u2014 otherwise the\n        // openwork rebuilds at mid-flight centres and the necklace \"changes\n        // by itself\" while the search box already shows the new place.\n        if (isMapTransitioning || mimosaCameraSyncDepth > 0) return;\n        if (map._mimosaZoomTimer) clearTimeout(map._mimosaZoomTimer);\n        const token = (map._mimosaZoomToken = (map._mimosaZoomToken || 0) + 1);\n        map._mimosaZoomTimer = setTimeout(function () {\n          map._mimosaZoomTimer = null;\n          if (isMapTransitioning || mimosaCameraSyncDepth > 0) return;\n          mimosaWaitTilesThen(map, token, function () {\n            if (map._mimosaZoomToken !== token) return;\n            if (isMapTransitioning || mimosaCameraSyncDepth > 0) return;\n            mimosaApplyRoadFilter(map, 'etched');\n          });\n        }, 60);\n      }\n      map.on('zoom', function () {\n        if (map._mimosaLiveLattice) mimosaShowLiveLattice(map);\n      });\n      map.on('zoomstart', mimosaBeginLiveGesture);\n      map.on('movestart', mimosaBeginLiveGesture);\n      map.on('moveend', scheduleRefilter);\n      map.on('resize', scheduleRefilter);\n    }\n  }\n\n  function mimosaSyncStonePosHidden() {\n    const el = document.getElementById('mimosa-hidden-stone-pos');\n    if (el) el.value = stonePos.x.toFixed(1) + '%, ' + stonePos.y.toFixed(1) + '%';\n  }\n\n  function mimosaUpdateStoneOverlay() {\n    // Seat lives in the metal lattice + map pin gem. The HTML bezel overlay\n    // was a second ring (\"\u94BB\u77F3\u73AF\u53C8\u51FA\u73B02\u4E2A\") \u2014 keep it hidden.\n    [['mimosa-stone-overlay', 'mimosa-stone-gem'],\n     ['mimosa-stone-overlay-his', 'mimosa-stone-gem-his']].forEach(function (row) {\n      const wrap = document.getElementById(row[0]);\n      if (!wrap) return;\n      wrap.hidden = true;\n      wrap.setAttribute('aria-hidden', 'true');\n    });\n    mimosaSyncStonePosHidden();\n  }\n\n  function mimosaBindStoneDrag() {\n    if (window._mimosaStoneDragBound) return;\n    window._mimosaStoneDragBound = true;\n    let dragging = null;\n\n    function onPointerDown(e) {\n      const bezel = e.target && e.target.closest && e.target.closest('.mimosa-stone-bezel');\n      if (!bezel || currentDesign !== 'openwork') return;\n      const wrap = bezel.closest('.mimosa-stone-overlay');\n      if (!wrap || wrap.hidden) return;\n      e.preventDefault();\n      e.stopPropagation();\n      dragging = { wrap: wrap, bezel: bezel, pointerId: e.pointerId };\n      bezel.classList.add('is-dragging');\n      try { bezel.setPointerCapture(e.pointerId); } catch (err) {}\n      // Pause map drag while placing stone\n      try { if (mapAfter) mapAfter.dragPan.disable(); } catch (e1) {}\n      try { if (mapHis) mapHis.dragPan.disable(); } catch (e2) {}\n    }\n\n    function onPointerMove(e) {\n      if (!dragging) return;\n      e.preventDefault();\n      const rect = dragging.wrap.getBoundingClientRect();\n      if (!rect.width || !rect.height) return;\n      let x = ((e.clientX - rect.left) / rect.width) * 100;\n      let y = ((e.clientY - rect.top) / rect.height) * 100;\n      // Keep inside pendant face (bail/top edge is sparse)\n      x = Math.max(18, Math.min(82, x));\n      y = Math.max(22, Math.min(78, y));\n      stonePos.x = x;\n      stonePos.y = y;\n      mimosaUpdateStoneOverlay();\n    }\n\n    function onPointerUp(e) {\n      if (!dragging) return;\n      if (e && dragging.pointerId != null && e.pointerId !== dragging.pointerId) return;\n      dragging.bezel.classList.remove('is-dragging');\n      try { dragging.bezel.releasePointerCapture(dragging.pointerId); } catch (err) {}\n      dragging = null;\n      try { if (mapAfter) mapAfter.dragPan.enable(); } catch (e1) {}\n      try { if (mapHis) mapHis.dragPan.enable(); } catch (e2) {}\n      mimosaSyncStonePosHidden();\n      try { mimosaScheduleFactoryFiles(); } catch (eSched) {}\n    }\n\n    document.addEventListener('pointerdown', onPointerDown, true);\n    document.addEventListener('pointermove', onPointerMove, true);\n    document.addEventListener('pointerup', onPointerUp, true);\n    document.addEventListener('pointercancel', onPointerUp, true);\n  }\n\n  function mimosaBezierPoint(p0, p1, p2, p3, t) {\n    const mt = 1 - t;\n    const a = mt * mt * mt, b = 3 * mt * mt * t, c = 3 * mt * t * t, d = t * t * t;\n    return {\n      x: a * p0.x + b * p1.x + c * p2.x + d * p3.x,\n      y: a * p0.y + b * p1.y + c * p2.y + d * p3.y\n    };\n  }\n\n  function mimosaFlattenCubic(p0, p1, p2, p3, segments) {\n    const pts = [];\n    const n = segments || 24;\n    for (let i = 1; i <= n; i++) pts.push(mimosaBezierPoint(p0, p1, p2, p3, i / n));\n    return pts;\n  }\n\n  // TrueType glyph outlines (used for the factory-etch backside text, see\n  // mimosaGlyphToDxfPath below) are built from quadratic beziers, not the\n  // cubic ones SVG paths normally use \u2014 needed here even though nothing\n  // else in this file emits a Q command.\n  function mimosaQuadraticPoint(p0, p1, p2, t) {\n    const mt = 1 - t;\n    const a = mt * mt, b = 2 * mt * t, c = t * t;\n    return { x: a * p0.x + b * p1.x + c * p2.x, y: a * p0.y + b * p1.y + c * p2.y };\n  }\n\n  function mimosaFlattenQuadratic(p0, p1, p2, segments) {\n    const pts = [];\n    const n = segments || 16;\n    for (let i = 1; i <= n; i++) pts.push(mimosaQuadraticPoint(p0, p1, p2, i / n));\n    return pts;\n  }\n\n  // SVG elliptical arc -> points, via endpoint-to-center parameterization (SVG spec F.6.5).\n  function mimosaFlattenArc(p0, rx, ry, xAxisRotDeg, largeArcFlag, sweepFlag, p1, segments) {\n    rx = Math.abs(rx); ry = Math.abs(ry);\n    if (rx < 1e-6 || ry < 1e-6) return [p1];\n    const phi = xAxisRotDeg * Math.PI / 180;\n    const cosPhi = Math.cos(phi), sinPhi = Math.sin(phi);\n    const dx2 = (p0.x - p1.x) / 2, dy2 = (p0.y - p1.y) / 2;\n    const x1p = cosPhi * dx2 + sinPhi * dy2;\n    const y1p = -sinPhi * dx2 + cosPhi * dy2;\n    let rxSq = rx * rx, rySq = ry * ry;\n    const x1pSq = x1p * x1p, y1pSq = y1p * y1p;\n    const lambda = x1pSq / rxSq + y1pSq / rySq;\n    if (lambda > 1) {\n      const s = Math.sqrt(lambda);\n      rx *= s; ry *= s;\n      rxSq = rx * rx; rySq = ry * ry;\n    }\n    const sign = (largeArcFlag !== sweepFlag) ? 1 : -1;\n    let num = rxSq * rySq - rxSq * y1pSq - rySq * x1pSq;\n    if (num < 0) num = 0;\n    const co = sign * Math.sqrt(num / (rxSq * y1pSq + rySq * x1pSq || 1e-9));\n    const cxp = co * (rx * y1p / ry);\n    const cyp = co * (-ry * x1p / rx);\n    const cx = cosPhi * cxp - sinPhi * cyp + (p0.x + p1.x) / 2;\n    const cy = sinPhi * cxp + cosPhi * cyp + (p0.y + p1.y) / 2;\n\n    const angleBetween = function (ux, uy, vx, vy) {\n      const dot = ux * vx + uy * vy;\n      const len = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy)) || 1e-9;\n      let ang = Math.acos(Math.max(-1, Math.min(1, dot / len)));\n      if (ux * vy - uy * vx < 0) ang = -ang;\n      return ang;\n    };\n\n    const theta1 = angleBetween(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);\n    let dTheta = angleBetween((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry);\n    if (!sweepFlag && dTheta > 0) dTheta -= 2 * Math.PI;\n    if (sweepFlag && dTheta < 0) dTheta += 2 * Math.PI;\n\n    const n = Math.max(6, segments || Math.ceil(Math.abs(dTheta) / (Math.PI / 24)));\n    const pts = [];\n    for (let i = 1; i <= n; i++) {\n      const t = theta1 + dTheta * (i / n);\n      const x = cx + rx * Math.cos(t) * cosPhi - ry * Math.sin(t) * sinPhi;\n      const y = cy + rx * Math.cos(t) * sinPhi + ry * Math.sin(t) * cosPhi;\n      pts.push({ x: x, y: y });\n    }\n    return pts;\n  }\n\n  // Parses an SVG path \"d\" string (M/L/C/A, upper or lowercase, Z) into\n  // subpaths of flattened {x,y} points, in absolute coordinates.\n  function mimosaParsePathD(d) {\n    const tokens = String(d).match(/[MLHVCAZQmlhvcaqz]|-?\\d*\\.?\\d+(?:e-?\\d+)?/g) || [];\n    let i = 0;\n    const next = function () { return parseFloat(tokens[i++]); };\n    const subpaths = [];\n    let current = null;\n    let cur = { x: 0, y: 0 };\n    let start = { x: 0, y: 0 };\n    let cmd = null;\n\n    while (i < tokens.length) {\n      const tok = tokens[i];\n      if (/^[MLHVCAZQmlhvcaqz]$/.test(tok)) { cmd = tok; i++; }\n      switch (cmd) {\n        case 'M': {\n          const x = next(), y = next();\n          cur = { x: x, y: y }; start = cur; current = [cur]; subpaths.push(current);\n          cmd = 'L';\n          break;\n        }\n        case 'm': {\n          const x = cur.x + next(), y = cur.y + next();\n          cur = { x: x, y: y }; start = cur; current = [cur]; subpaths.push(current);\n          cmd = 'l';\n          break;\n        }\n        case 'L': {\n          const x = next(), y = next();\n          cur = { x: x, y: y }; if (current) current.push(cur);\n          break;\n        }\n        case 'l': {\n          const x = cur.x + next(), y = cur.y + next();\n          cur = { x: x, y: y }; if (current) current.push(cur);\n          break;\n        }\n        case 'H': {\n          cur = { x: next(), y: cur.y }; if (current) current.push(cur);\n          break;\n        }\n        case 'h': {\n          cur = { x: cur.x + next(), y: cur.y }; if (current) current.push(cur);\n          break;\n        }\n        case 'V': {\n          cur = { x: cur.x, y: next() }; if (current) current.push(cur);\n          break;\n        }\n        case 'v': {\n          cur = { x: cur.x, y: cur.y + next() }; if (current) current.push(cur);\n          break;\n        }\n        case 'C': {\n          const p1 = { x: next(), y: next() };\n          const p2 = { x: next(), y: next() };\n          const p3 = { x: next(), y: next() };\n          const pts = mimosaFlattenCubic(cur, p1, p2, p3, 24);\n          if (current) current.push.apply(current, pts);\n          cur = p3;\n          break;\n        }\n        case 'c': {\n          const p1 = { x: cur.x + next(), y: cur.y + next() };\n          const p2 = { x: cur.x + next(), y: cur.y + next() };\n          const p3 = { x: cur.x + next(), y: cur.y + next() };\n          const pts = mimosaFlattenCubic(cur, p1, p2, p3, 24);\n          if (current) current.push.apply(current, pts);\n          cur = p3;\n          break;\n        }\n        case 'Q': {\n          const p1 = { x: next(), y: next() };\n          const p2 = { x: next(), y: next() };\n          const pts = mimosaFlattenQuadratic(cur, p1, p2, 16);\n          if (current) current.push.apply(current, pts);\n          cur = p2;\n          break;\n        }\n        case 'q': {\n          const p1 = { x: cur.x + next(), y: cur.y + next() };\n          const p2 = { x: cur.x + next(), y: cur.y + next() };\n          const pts = mimosaFlattenQuadratic(cur, p1, p2, 16);\n          if (current) current.push.apply(current, pts);\n          cur = p2;\n          break;\n        }\n        case 'A': {\n          const rx = next(), ry = next(), rot = next(), laf = next(), sf = next();\n          const x = next(), y = next();\n          const p1 = { x: x, y: y };\n          const pts = mimosaFlattenArc(cur, rx, ry, rot, !!laf, !!sf, p1);\n          if (current) current.push.apply(current, pts);\n          cur = p1;\n          break;\n        }\n        case 'a': {\n          const rx = next(), ry = next(), rot = next(), laf = next(), sf = next();\n          const x = cur.x + next(), y = cur.y + next();\n          const p1 = { x: x, y: y };\n          const pts = mimosaFlattenArc(cur, rx, ry, rot, !!laf, !!sf, p1);\n          if (current) current.push.apply(current, pts);\n          cur = p1;\n          break;\n        }\n        case 'Z':\n        case 'z': {\n          if (current && current.length) { current.push({ x: start.x, y: start.y }); current.closed = true; }\n          cur = start;\n          break;\n        }\n        default:\n          i++;\n      }\n    }\n    return subpaths;\n  }\n\n  function mimosaParseTransform(str) {\n    const ops = [];\n    const re = /(translate|scale)\\(([^)]+)\\)/g;\n    let m;\n    while ((m = re.exec(str || ''))) {\n      const parts = m[2].trim().split(/[\\s,]+/).map(Number);\n      ops.push({ type: m[1], values: parts });\n    }\n    return ops;\n  }\n\n  // Applies a list of translate()/scale() ops to a point, in the same\n  // order the browser would (rightmost/innermost op first).\n  function mimosaApplyTransform(pt, ops) {\n    let x = pt.x, y = pt.y;\n    for (let k = ops.length - 1; k >= 0; k--) {\n      const op = ops[k];\n      if (op.type === 'translate') {\n        x += (op.values[0] || 0); y += (op.values[1] || 0);\n      } else if (op.type === 'scale') {\n        const sx = op.values[0];\n        const sy = op.values.length > 1 ? op.values[1] : sx;\n        x *= sx; y *= sy;\n      }\n    }\n    return { x: x, y: y };\n  }\n\n  // Walks the generated SVG string (our own output, so structurally simple \u2014\n  // <path>/<circle>, optionally inside one level of <g transform=\"...\">) and\n  // returns every subpath as absolute, transformed {x,y} points.\n  function mimosaExtractSubpathsFromSvg(svgString, forceLayer) {\n    const allSubpaths = [];\n    // each entry gets .layer, consumed by mimosaSubpathsToDxf\n    let svg = svgString.replace(/<defs>[\\s\\S]*?<\\/defs>/g, '');\n    svg = svg.replace(/<rect\\b[^>]*>/g, '');\n\n    const stack = [[]];\n    const fillStack = [''];\n    let glyphSerial = 0;\n    // Which DXF layer the geometry belongs on. The factory reads CUT vs\n    // ENGRAVE from the layer name. OPENWORK front: outer silhouette + every\n    // hollow void are CUT (laser cut-through). ENGRAVE is only for backside\n    // text/icons on a solid plate \u2014 never for the openwork map face.\n    // Without that split everything landed on layer 0 and they read the whole\n    // file as a cut/openwork part with \"floating\" shapes when etch strokes\n    // were mis-tagged as cut.\n    // Front face is Solid Openwork (\u5B9E\u5FC3\u9542\u7A7A): CUT through \u2014 streets are the\n    // metal, blocks are holes. Not surface etch (\u8680\u523B). Per the user:\n    // \"\u73B0\u5728\u8FD9\u4E2A\u662F\u5207\u5272\u6B3E\u00B7\u4E0D\u662F\u8150\u8680\" / \"\u5E94\u8BE5\u662F\u5B9E\u5FC3\u9542\u7A7A\".\n    // Backplate files MUST force ENGRAVE even when the storefront stage is\n    // openwork \u2014 otherwise text/icons inherit CUT and the factory laser-\n    // cuts the lettering instead of engraving it (\"\u80CC\u9762\u662F\u6FC0\u5149\u6253\u5370\u4E0D\u662F\u9542\u7A7A\").\n    const stageEl = document.getElementById('mimosa-stage');\n    const isOpenworkCut = !!(stageEl && stageEl.classList.contains('is-openwork'));\n    const isBackEngrave = /FACTORY BACK ENGRAVING/i.test(svgString)\n      || forceLayer === 'ENGRAVE';\n    const layerStack = [forceLayer || (isBackEngrave ? 'ENGRAVE' : (isOpenworkCut ? 'CUT' : 'ENGRAVE'))];\n    const tagRe = /<(\\/?)(g|path|circle)\\b([^>]*)>/g;\n    let m;\n    while ((m = tagRe.exec(svg))) {\n      const closing = m[1] === '/';\n      const tag = m[2];\n      const attrs = m[3] || '';\n\n      if (tag === 'g') {\n        if (closing) { stack.pop(); layerStack.pop(); fillStack.pop(); }\n        else {\n          const tMatch = /transform=\"([^\"]*)\"/.exec(attrs);\n          const ops = tMatch ? mimosaParseTransform(tMatch[1]) : [];\n          stack.push(stack[stack.length - 1].concat(ops));\n          const fillAttr = (/fill=\"([^\"]*)\"/.exec(attrs) || [])[1];\n          fillStack.push(fillAttr != null ? fillAttr : fillStack[fillStack.length - 1]);\n          const gid = (/id=\"([^\"]*)\"/.exec(attrs) || [])[1] || '';\n          const gIsCut = gid === 'plate-outline' || (!isBackEngrave && (gid === 'cut-outline' || gid === 'cut-voids' || gid.indexOf('cut-') === 0));\n          const gIsEngrave = gid === 'engrave-content' || gid.indexOf('engrave-') === 0;\n          layerStack.push(gIsCut ? 'CUT' : (gIsEngrave ? 'ENGRAVE' : layerStack[layerStack.length - 1]));\n        }\n        continue;\n      }\n      const elId = (/id=\"([^\"]*)\"/.exec(attrs) || [])[1] || '';\n      const elIsCut = elId === 'plate-outline' || (!isBackEngrave && (elId === 'cut-outline' || elId === 'cut-voids' || elId.indexOf('cut-') === 0));\n      const elIsEngrave = elId === 'engrave-content' || elId.indexOf('engrave-') === 0;\n      const elLayer = elIsCut ? 'CUT' : (elIsEngrave ? 'ENGRAVE' : layerStack[layerStack.length - 1]);\n      if (closing) continue;\n      const ctxOps = stack[stack.length - 1];\n\n      if (tag === 'path') {\n        const dMatch = /\\sd=\"([^\"]*)\"/.exec(attrs);\n        if (!dMatch) continue;\n        const ownFill = (/fill=\"([^\"]*)\"/.exec(attrs) || [])[1];\n        const fill = ownFill != null ? ownFill : fillStack[fillStack.length - 1];\n        // Laser marking fills the letter, it does not trace the outline.\n        // Only filled ENGRAVE paths (the glyphs) get a solid hatch. Icon\n        // strokes and the openwork CUT file stay as contours.\n        const solid = elLayer === 'ENGRAVE' && fill !== 'none' && fill !== 'transparent';\n        const glyphId = solid ? ('glyph-' + (++glyphSerial)) : '';\n        const subs = mimosaParsePathD(dMatch[1]);\n        subs.forEach(function (pts) {\n          const transformed = pts.map(function (p) { return mimosaApplyTransform(p, ctxOps); });\n          allSubpaths.push(Object.assign(\n            { points: transformed, closed: !!pts.closed },\n            { layer: elLayer, solid: solid, glyphId: glyphId }\n          ));\n        });\n      } else if (tag === 'circle') {\n        const cx = parseFloat((/cx=\"([-\\d.]+)\"/.exec(attrs) || [0, 0])[1]);\n        const cy = parseFloat((/cy=\"([-\\d.]+)\"/.exec(attrs) || [0, 0])[1]);\n        const r = parseFloat((/\\br=\"([-\\d.]+)\"/.exec(attrs) || [0, 0])[1]);\n        if (!r) continue;\n        const n = 64;\n        const pts = [];\n        for (let k = 0; k < n; k++) {\n          const a = (k / n) * Math.PI * 2;\n          pts.push({ x: cx + r * Math.cos(a), y: cy + r * Math.sin(a) });\n        }\n        const transformed = pts.map(function (p) { return mimosaApplyTransform(p, ctxOps); });\n        allSubpaths.push(Object.assign({ points: transformed, closed: true }, { layer: elLayer }));\n      }\n    }\n\n    // Safety net: the artboard is 0-100. A location-pin marker (or any\n    // future group) transformed against a camera that's since moved\n    // somewhere else on the globe projects to wildly out-of-range pixels \u2014\n    // AutoCAD then rejects the whole file as \"invalid\" / \"empty design\"\n    // rather than just ignoring the one bad shape. Drop only the specific\n    // subpath that's out of range, not the whole export.\n    const BOUND = 200; // generous margin around the 0-100 viewBox\n    const inBounds = function (p) {\n      return isFinite(p.x) && isFinite(p.y)\n        && p.x > -BOUND && p.x < BOUND && p.y > -BOUND && p.y < BOUND;\n    };\n    const clean = allSubpaths.filter(function (sp) {\n      const ok = sp.points.length > 0 && sp.points.every(inBounds);\n      if (!ok) console.warn('mimosaExtractSubpathsFromSvg: dropped an out-of-range subpath', sp.points[0]);\n      return ok;\n    });\n    return clean;\n  }\n\n  // Emits a genuine DXF R12 (AC1009) file \u2014 classic POLYLINE/VERTEX/SEQEND\n  // per subpath, scaled from the 0-100 artboard into real millimeters, with\n  // Y flipped (SVG is Y-down; DXF/CAD convention is Y-up).\n  //\n  // An earlier version declared $ACADVER AC1015 (AutoCAD 2000) while only\n  // emitting LTYPE/LAYER tables \u2014 AC1015 formally requires a CLASSES\n  // section, a full TABLES section (VPORT/STYLE/APPID/BLOCK_RECORD, not\n  // just LTYPE/LAYER), real *Model_Space/*Paper_Space block definitions,\n  // and entity-ownership handles pointing at those blocks. The lenient\n  // `dxf-parser` npm library (and AutoCAD's own auto-repair) tolerated the\n  // omission, but a strict translator does not \u2014 it crashed outright\n  // (\"AutoCAD-InvalidFile\" / \"TranslationWorker-InternalFailure\") instead\n  // of just rejecting the file. R12 has no such requirement: no CLASSES,\n  // no OBJECTS, no BLOCK_RECORD, no entity-owner handles \u2014 it's the\n  // lowest-common-denominator DXF variant essentially every laser/CNC\n  // import pipeline targets for exactly this reason. Do not switch this\n  // back to LWPOLYLINE/AC1015 without also building out the full R2000\n  // symbol-table/block-record/object-dictionary structure it requires.\n  // Horizontal scan lines inside a glyph's closed contours. Nonzero winding\n  // keeps the holes in 0, 4, 8, A, O, P empty and fills the stroke. Spacing\n  // is ~0.035mm on a 25mm pendant \u2014 dense enough that a fiber laser marks\n  // the letter solid instead of tracing the outline.\n  function mimosaSolidHatchLines(rings, step) {\n    let minY = Infinity, maxY = -Infinity;\n    rings.forEach(function (pts) {\n      for (let i = 0; i < pts.length; i++) {\n        const y = pts[i].y;\n        if (y < minY) minY = y;\n        if (y > maxY) maxY = y;\n      }\n    });\n    if (!(maxY > minY)) return [];\n    const lines = [];\n    for (let y = minY + step * 0.5; y < maxY; y += step) {\n      const hits = [];\n      rings.forEach(function (pts) {\n        const n = pts.length;\n        if (n < 3) return;\n        for (let i = 0; i < n; i++) {\n          const a = pts[i];\n          const b = pts[(i + 1) % n];\n          if (a.y === b.y) continue;\n          if ((a.y <= y && b.y > y) || (b.y <= y && a.y > y)) {\n            const t = (y - a.y) / (b.y - a.y);\n            hits.push({ x: a.x + t * (b.x - a.x), dir: b.y > a.y ? 1 : -1 });\n          }\n        }\n      });\n      if (hits.length < 2) continue;\n      hits.sort(function (p, q) { return p.x - q.x; });\n      let wind = 0;\n      let openX = null;\n      for (let i = 0; i < hits.length; i++) {\n        const before = wind;\n        wind += hits[i].dir;\n        if (before === 0 && wind !== 0) openX = hits[i].x;\n        else if (before !== 0 && wind === 0 && openX != null) {\n          if (hits[i].x - openX > 0.015) {\n            lines.push([{ x: openX, y: y }, { x: hits[i].x, y: y }]);\n          }\n          openX = null;\n        }\n      }\n    }\n    return lines;\n  }\n\n  function mimosaSubpathsToDxf(subpaths, widthMm, shape) {\n    // Scale so the pendant outline's bounding width = widthMm (25mm), not so\n    // the whole 0\u2013100 artboard is widthMm (that shrank every piece ~1.6\u00D7).\n    const span = mimosaShapeSpanUnits(shape) || 100;\n    const scale = widthMm / span;\n    let entities = '';\n    const solidGroups = {};\n    subpaths.forEach(function (sp) {\n      let pts = sp.points;\n      if (!pts || pts.length < 2) return;\n      // Close anything whose ends nearly meet. The glyph outlines in\n      // mimosa-glyphs.js lost their Z when they were extracted offline \u2014 all\n      // 42 of them \u2014 so every letter on the backside came out as an OPEN\n      // contour, which the factory's laser software shows as broken arrows.\n      // A TrueType contour is closed by definition and its last point should\n      // return to the first, so we recover the flag from proximity.\n      // The original 0.05 tolerance was too tight: some letters (e.g. \"2\",\n      // \"3\", \"5\", \"N\") have endpoint gaps up to 0.63\u20131.5 artboard units after\n      // scale(fontSize). 2.0 units covers all known cases without accidentally\n      // closing genuinely open icon-stroke paths (whose endpoints are much\n      // farther apart).\n      let closed = sp.closed;\n      const first = pts[0], last = pts[pts.length - 1];\n      const endGap = Math.hypot(first.x - last.x, first.y - last.y);\n      // Filled letters are TrueType contours. Several Plus Jakarta glyphs\n      // (N, W, 1, \u2026) were extracted without a closing Z, and the gap back to\n      // the start is more than 2 artboard units, so they stayed open outlines\n      // while letters that did close were only sparsely hatched. A filled\n      // letter is always a closed shape; the last edge is the straight return\n      // to the first point, the same edge SVG fill draws.\n      if (sp.solid && pts.length >= 3) {\n        closed = true;\n        if (endGap < 0.05) {\n          pts = pts.slice(0, -1);\n          if (pts.length < 2) return;\n        }\n      } else if (!closed && endGap < 2.0) {\n        closed = true;\n        if (endGap < 0.05) {\n          pts = pts.slice(0, -1);\n          if (pts.length < 2) return;\n        }\n      }\n      const lay = sp.layer === 'CUT' ? 'CUT' : 'ENGRAVE';\n      // Laser cut paths have to be closed loops. Outline, voids, bail hole\n      // and the stone seat are all rings; an open CUT contour is rejected\n      // by the factory (\"\u9700\u8981\u95ED\u5408\u7684\u624D\u53EF\u4EE5\u5207\u5272\").\n      if (lay === 'CUT' && pts.length >= 3) closed = true;\n      // A closed contour must not repeat its first point. The extra vertex\n      // is a zero-length seam; laser software draws it as a tick or a knot\n      // instead of a smooth close. Letters, the eyelet, and the stone hole\n      // all used to land here.\n      if (closed && pts.length >= 3) {\n        const a0 = pts[0];\n        const aN = pts[pts.length - 1];\n        if (Math.hypot(a0.x - aN.x, a0.y - aN.y) < 0.05) {\n          pts = pts.slice(0, -1);\n        }\n      }\n      if (sp.solid && sp.glyphId && closed && pts.length >= 3) {\n        if (!solidGroups[sp.glyphId]) solidGroups[sp.glyphId] = [];\n        solidGroups[sp.glyphId].push(pts);\n      }\n      entities += '0\\nPOLYLINE\\n8\\n' + lay + '\\n66\\n1\\n70\\n' + (closed ? 1 : 0) + '\\n';\n      pts.forEach(function (p) {\n        const x = (p.x * scale).toFixed(4);\n        const y = ((100 - p.y) * scale).toFixed(4);\n        entities += '0\\nVERTEX\\n8\\n' + lay + '\\n10\\n' + x + '\\n20\\n' + y + '\\n';\n      });\n      entities += '0\\nSEQEND\\n8\\n' + lay + '\\n';\n    });\n    // Fill each letter solid black, the same as the plate preview. The contour\n    // alone is an empty outline. Scan lines of ~0.012mm (0.03 artboard units\n    // on a 25mm piece) overlap a fiber-laser spot, so the letter reads as a\n    // solid fill rather than stripes or dots.\n    const HATCH_STEP = 0.03;\n    Object.keys(solidGroups).forEach(function (id) {\n      mimosaSolidHatchLines(solidGroups[id], HATCH_STEP).forEach(function (seg) {\n        entities += '0\\nPOLYLINE\\n8\\nENGRAVE\\n66\\n1\\n70\\n0\\n';\n        seg.forEach(function (p) {\n          entities += '0\\nVERTEX\\n8\\nENGRAVE\\n10\\n' + (p.x * scale).toFixed(4) + '\\n20\\n' + ((100 - p.y) * scale).toFixed(4) + '\\n';\n        });\n        entities += '0\\nSEQEND\\n8\\nENGRAVE\\n';\n      });\n    });\n\n    const header =\n      '0\\nSECTION\\n2\\nHEADER\\n' +\n      '9\\n$ACADVER\\n1\\nAC1009\\n' +\n      '0\\nENDSEC\\n';\n\n    const tables =\n      '0\\nSECTION\\n2\\nTABLES\\n' +\n      '0\\nTABLE\\n2\\nLTYPE\\n70\\n1\\n' +\n      '0\\nLTYPE\\n2\\nCONTINUOUS\\n70\\n0\\n3\\nSolid line\\n72\\n65\\n73\\n0\\n40\\n0.0\\n' +\n      '0\\nENDTAB\\n' +\n      '0\\nTABLE\\n2\\nLAYER\\n70\\n3\\n' +\n      '0\\nLAYER\\n2\\n0\\n70\\n0\\n62\\n7\\n6\\nCONTINUOUS\\n' +\n      // CUT = pendant silhouette, bail hole, and every openwork void\n      // (red). On the plate file, CUT is that same silhouette only.\n      // ENGRAVE = backside text and icons, inside the silhouette.\n      '0\\nLAYER\\n2\\nCUT\\n70\\n0\\n62\\n1\\n6\\nCONTINUOUS\\n' +\n      '0\\nLAYER\\n2\\nENGRAVE\\n70\\n0\\n62\\n7\\n6\\nCONTINUOUS\\n' +\n      '0\\nENDTAB\\n' +\n      '0\\nENDSEC\\n';\n\n    const blocks = '0\\nSECTION\\n2\\nBLOCKS\\n0\\nENDSEC\\n';\n    const entitiesSection = '0\\nSECTION\\n2\\nENTITIES\\n' + entities + '0\\nENDSEC\\n';\n\n    return header + tables + blocks + entitiesSection + '0\\nEOF\\n';\n  }\n\n  function mimosaSvgToDxf(svgString, widthMm, forceLayer, shape) {\n    const subpaths = mimosaExtractSubpathsFromSvg(svgString, forceLayer);\n    if (!subpaths.length) console.warn('mimosaSvgToDxf: no path/circle geometry found to convert.');\n    return mimosaSubpathsToDxf(subpaths, widthMm, shape);\n  }\n\n  function mimosaSaveDxfFile(dxf, filename) {\n    const link = mimosaMakeDownloadLink(\n      new Blob([dxf], { type: 'application/octet-stream' }),\n      filename,\n      filename\n    );\n    document.body.appendChild(link);\n    link.click();\n    setTimeout(function () {\n      URL.revokeObjectURL(link.href);\n      link.remove();\n    }, 2000);\n  }\n\n  function mimosaCrc32(bytes) {\n    let c = ~0;\n    for (let i = 0; i < bytes.length; i++) {\n      c ^= bytes[i];\n      for (let k = 0; k < 8; k++) c = (c >>> 1) ^ (0xedb88320 & -(c & 1));\n    }\n    return (~c) >>> 0;\n  }\n\n  function mimosaU8Concat(list) {\n    let n = 0;\n    for (let i = 0; i < list.length; i++) n += list[i].length;\n    const out = new Uint8Array(n);\n    let o = 0;\n    for (let i = 0; i < list.length; i++) {\n      out.set(list[i], o);\n      o += list[i].length;\n    }\n    return out;\n  }\n\n  // One zip, stored (no compression). A single click can save the pack.\n  // Browsers drop automatic downloads that start after the map export await.\n  function mimosaZipStored(files) {\n    const enc = new TextEncoder();\n    const locals = [];\n    const centrals = [];\n    let offset = 0;\n    files.forEach(function (file) {\n      const name = enc.encode(file.name);\n      const data = file.bytes;\n      const crc = mimosaCrc32(data);\n      const local = new Uint8Array(30 + name.length + data.length);\n      const view = new DataView(local.buffer);\n      view.setUint32(0, 0x04034b50, true);\n      view.setUint16(4, 20, true);\n      view.setUint16(8, 0, true);\n      view.setUint32(14, crc, true);\n      view.setUint32(18, data.length, true);\n      view.setUint32(22, data.length, true);\n      view.setUint16(26, name.length, true);\n      local.set(name, 30);\n      local.set(data, 30 + name.length);\n      locals.push(local);\n      const central = new Uint8Array(46 + name.length);\n      const cv = new DataView(central.buffer);\n      cv.setUint32(0, 0x02014b50, true);\n      cv.setUint16(4, 20, true);\n      cv.setUint16(6, 20, true);\n      cv.setUint32(16, crc, true);\n      cv.setUint32(20, data.length, true);\n      cv.setUint32(24, data.length, true);\n      cv.setUint16(28, name.length, true);\n      cv.setUint32(42, offset, true);\n      central.set(name, 46);\n      centrals.push(central);\n      offset += local.length;\n    });\n    const cd = mimosaU8Concat(centrals);\n    const eocd = new Uint8Array(22);\n    const ev = new DataView(eocd.buffer);\n    ev.setUint32(0, 0x06054b50, true);\n    ev.setUint16(8, files.length, true);\n    ev.setUint16(10, files.length, true);\n    ev.setUint32(12, cd.length, true);\n    ev.setUint32(16, offset, true);\n    return mimosaU8Concat(locals.concat([cd, eocd]));\n  }\n\n  function mimosaMakeDownloadLink(blob, filename, label) {\n    const link = document.createElement('a');\n    link.href = URL.createObjectURL(blob);\n    link.download = filename;\n    link.textContent = label;\n    link.style.cssText = 'display:block;background:#0F172A;color:#fff;padding:12px 16px;border-radius:8px;text-align:center;text-decoration:none;font-weight:700;';\n    return link;\n  }\n\n  function mimosaSaveSvgFile(svg, filename) {\n    const blob = new Blob([svg], { type: 'image/svg+xml;charset=utf-8' });\n    const link = document.createElement('a');\n    link.href = URL.createObjectURL(blob);\n    link.download = filename;\n    document.body.appendChild(link);\n    link.click();\n    setTimeout(function () {\n      URL.revokeObjectURL(link.href);\n      link.remove();\n    }, 2000);\n  }\n\n  function mimosaFactoryLocSlug() {\n    return ((document.getElementById('mimosa-hidden-location') || {}).value || 'map')\n      .replace(/[^\\w]+/g, '-').replace(/^-|-$/g, '').slice(0, 40) || 'map';\n  }\n\n  // ---- One source of truth for every pendant outline ---------------------\n  // The heart's silhouette used to be hand-written in nine places: this\n  // constant, the static markup of six preview layers, and three\n  // objectBoundingBox paths in 0-1 units. mimosaChangeShape() already\n  // rewrote the 0-100 markup on every shape switch, but nothing ever touched\n  // the 0-1 clip paths \u2014 the switcher picks between them by CSS class \u2014 so a\n  // shape edit that missed those left a mismatch no later fix could find.\n  // The stray gold disc above the heart's cleft was exactly that: the bail\n  // hole was corrected in the 0-100 copy several times while the 0-1 clip\n  // path kept the old coordinate, where evenodd turned it into an ADDED\n  // region instead of a punched hole.\n  //\n  // Now every one of them is filled from the constants here. The 0-1\n  // elements carry transform=\"scale(0.01)\" and are handed the plain 0-100\n  // path, so no number ever has to be rescaled \u2014 which matters: a naive\n  // rescale would also divide an arc's large-arc and sweep FLAGS and quietly\n  // corrupt every shape that uses A/a (circle, drop, shield, and the heart's\n  // own bail hole).\n  //\n  // Not covered, because they are genuinely their own shapes rather than\n  // copies of an outline: mimosa-circle-map-mask (a plain <circle>) and\n  // mimosa-drop-map-mask (an inset drop). mimosa-heart-map-mask is covered \u2014\n  // it is the outline used twice, as fill and as a stroke, to erode a\n  // constant-width margin.\n  function mimosaSyncShapeOutlines() {\n    const set = function (id, d) {\n      const el = document.getElementById(id);\n      if (el && d) el.setAttribute('d', d);\n    };\n    ['heart', 'circle', 'drop', 'shield'].forEach(function (shape) {\n      // Clip/mask must be arc-free \u2014 see mimosaPathDToPolyline.\n      const outer = mimosaPathDToPolyline(mimosaPathForShape(shape));\n      const cut = mimosaPathDToPolyline(mimosaCutPathWithBail(shape));\n      // Drop preview stays the original outline. The extra eyelet subpath\n      // punched a white blob in the bail.\n      set('clip-' + shape + '-body', shape === 'drop' ? outer : cut);\n      set('clip-' + shape + '-fill', outer);\n      set('clip-' + shape + '-stroke', outer);\n    });\n    // The 0-100 preview layers are rewritten by mimosaChangeShape on every\n    // switch; seed them here so the first paint is not empty.\n    const shape = currentShape || 'heart';\n    const outer = mimosaPathForShape(shape);\n    const compound = mimosaCutPathWithBail(shape);\n    set('svg-shape-path', outer);\n    set('svg-shape-path-gold', outer);\n    set('svg-white-mask', 'M 0,0 L 100,0 L 100,100 L 0,100 Z ' + compound);\n    set('mimosa-back-clip-path', compound);\n    set('mimosa-back-body', compound);\n    set('mimosa-back-body-his', mimosaCutPathWithBail('shield'));\n    // The His backside CLIP path was the last hardcoded copy of the shield\n    // outline left in the markup \u2014 it kept the old silhouette, so the\n    // backside preview clipped the new shield against the old one and its\n    // right edge came out cut straight.\n    set('mimosa-back-clip-path-his', mimosaCutPathWithBail('shield'));\n    // The His piece is always the shield and has its own overlay layer \u2014 it\n    // was left out of the first pass and kept its stale static copy, so the\n    // gold fill (driven by the generated clip path) and the dark outline\n    // (driven by this element) drew two different shields on top of each\n    // other the moment MIMOSA_SHIELD_OUTER changed.\n    set('svg-shape-path-gold-his', mimosaPathForShape('shield'));\n    // The bail-hole outlines only ever got repositioned by mimosaChangeShape,\n    // so on first load they kept the static markup's old coordinate and left\n    // a stray little ring floating in the middle of the pendant after the\n    // bail moved. Same drift as every other duplicated coordinate here.\n    const bailSpec = mimosaBailSpec(currentShape || 'heart');\n    mimosaSyncBailVisuals(currentShape || 'heart');\n    // Keep legacy hole-only sync as a no-op safety for ids without pads.\n    const stageOpenwork = !!(document.getElementById('mimosa-stage') &&\n      document.getElementById('mimosa-stage').classList.contains('is-openwork'));\n    [['svg-bail-hole-gold', bailSpec], ['svg-bail-hole-map', bailSpec],\n     ['svg-bail-hole-gold-his', mimosaBailSpec('shield')]].forEach(function (pair) {\n      const el = document.getElementById(pair[0]);\n      if (!el) return;\n      // Openwork punches the bail hole in the metal itself, so this overlay\n      // circle must not draw a second outline inside the knob \u2014 the user:\n      // \"\u4E0A\u9762\u7684\u5706\u5708\u4E2D\u95F4\u4E0D\u8981\u5355\u72EC\u641E\u4E00\u4E2A\u6DF1\u8272\u7684\u5708\".\n      if (stageOpenwork) {\n        el.setAttribute('stroke', 'none');\n        el.setAttribute('fill', 'none');\n      }\n      el.setAttribute('cx', pair[1].cx);\n      el.setAttribute('cy', pair[1].cy);\n      el.setAttribute('r', pair[1].r);\n    });\n    mimosaSyncBackLayout();\n    mimosaSyncBailVisuals(currentShape || 'heart');\n  }\n\n  function mimosaOuterPathForShape(shape) {\n    return mimosaPathForShape(shape);\n  }\n\n  // Paths live in assets/mimosa-shape-rings.js (template size limit).\n  /**\n   * Intermediate openwork CUT markup (never downloaded as SVG).\n   * Converted to DXF: outer silhouette + every hollow void on layer CUT.\n   */\n  async function mimosaBuildFactoryOpenworkSvg(map, shape, role) {\n    const canvas = map.getCanvas();\n    const w = Math.max(1, canvas.clientWidth || canvas.width || 600);\n    const h = Math.max(1, canvas.clientHeight || canvas.height || 600);\n    const cssW = canvas.clientWidth > 10 ? canvas.clientWidth : w;\n    const cssH = canvas.clientHeight > 10 ? canvas.clientHeight : h;\n    const sx = 100 / cssW;\n    const sy = 100 / cssH;\n    const strokeVb = (MIMOSA_ETCHED_PREVIEW_LINE_PX * sx).toFixed(3);\n\n    const fieldShape = (role === 'his' || shape === 'shield') ? 'shield' : shape;\n    const layers = (map.getStyle() && map.getStyle().layers) || [];\n    const roadIds = layers\n      .filter(function (l) { return l.type === 'line' && mimosaIsMapRoadLine(l.id); })\n      .map(function (l) { return l.id; });\n    const roadPolys = await mimosaRoadNetwork(map);\n    const built = await mimosaBuildOpenworkMetal(map, fieldShape, roadIds, roadPolys);\n    if (!built || !built.metal) {\n      console.warn('mimosaBuildFactoryOpenworkSvg: openwork metal empty', role, shape);\n    }\n\n    const toArtboard = function (c) {\n      const pt = map.project([c[0], c[1]]);\n      return pt.x * sx + ',' + pt.y * sy;\n    };\n    const ringToPath = function (ring) {\n      if (!ring || ring.length < 4) return '';\n      return 'M' + ring.map(toArtboard).join('L') + 'Z';\n    };\n    const polyRingsToPaths = function (geom) {\n      const out = [];\n      if (!geom) return out;\n      const polys = geom.type === 'MultiPolygon'\n        ? geom.coordinates\n        : (geom.type === 'Polygon' ? [geom.coordinates] : []);\n      polys.forEach(function (rings) {\n        (rings || []).forEach(function (ring) {\n          const d = ringToPath(ring);\n          if (d) out.push(d);\n        });\n      });\n      return out;\n    };\n\n    let voidsGeom = built && built.voids ? built.voids : null;\n    if (voidsGeom) {\n      try {\n        const tol = MIN_LINE_VB / 30;\n        const c = map.getCenter();\n        const p0 = map.project([c.lng, c.lat]);\n        const a = map.unproject([p0.x, p0.y]), b = map.unproject([p0.x + 100, p0.y]);\n        const degPerUnit = Math.abs(b.lng - a.lng) / 100 * (cssW / 100);\n        voidsGeom = turf.simplify(voidsGeom, { tolerance: tol * degPerUnit, highQuality: true });\n      } catch (eSimp) {}\n    }\n    // Stone seat in the CUT file is ONE clean round hole, nothing else. The\n    // simplify pass above flattened the geometry's 2mm hole into an octagon\n    // that read as a drawn diamond (\"\u94BB\u77F3\u53BB\u6389\u00B7\u6362\u6210\u4E00\u4E2A\u91D1\u5C5E\u7684\u5C0F\u6D1E\u00B7\u65B9\u4FBF\u540E\u671F\u7C98\u8D34\n    // \u77F3\u5934\"). So a MIMOSA_FACTORY_SEAT_MM disc is cleared of voids here (solid\n    // metal) and the hole is added below as an exact circle of\n    // MIMOSA_FACTORY_STONE_HOLE_MM.\n    if (voidsGeom) {\n      try {\n        const seatPin = mimosaReadPinLatLng();\n        const seatR = mimosaMmToMeters(map, MIMOSA_FACTORY_SEAT_MM / 2);\n        if (seatR > 0) {\n          const seat = turf.circle([seatPin.lng, seatPin.lat], seatR, { units: 'meters', steps: 64 });\n          voidsGeom = turf.difference(voidsGeom, seat);\n        }\n      } catch (eSeat) {}\n    }\n    // The eyelet is already one circle on the outline. A second copy lived in\n    // the void set \u2014 simplify turned that tiny ring into a scribble sitting\n    // on the bottom of the hole (\"\u5706\u6263\u4E0D\u662F\u4E00\u4E2A\u5B8C\u6574\u7684\u5706\").\n    if (voidsGeom) {\n      try {\n        const bail = mimosaBailHoleLngLat(map, fieldShape);\n        const padMm = 0.25;\n        const cleared = bail ? turf.buffer(bail, mimosaMmToMeters(map, padMm), { units: 'meters', steps: 24 }) : null;\n        if (cleared) {\n          const next = turf.difference(voidsGeom, cleared);\n          if (next) voidsGeom = next;\n        }\n      } catch (eBailClear) {}\n    }\n    // Again after simplify, which can nudge a vertex: nothing is cut in the\n    // solid rim, so no stray triangle survives in a corner.\n    voidsGeom = mimosaKeepVoidsInFace(map, fieldShape, voidsGeom);\n    let stoneHoleMarkup = '';\n    try {\n      const pin = mimosaReadPinLatLng();\n      const pinPt = map.project([pin.lng, pin.lat]);\n      // Artboard units per mm come from the blank, not 100/PENDANT_WIDTH_MM \u2014\n      // that guess cut a 3mm hole instead of 2mm.\n      // The cut hole is SMALLER than the stone so the 2mm stone rests on a\n      // metal ledge and can be glued in (\"\u8FD9\u4E2A\u5706\u5708\u9700\u8981\u5C0F\u4E00\u70B9\u00B7\u8FD9\u6837\u624D\u80FD\u5361\u4F4F\u94BB\u77F3\").\n      const holeR = (MIMOSA_FACTORY_STONE_HOLE_MM / 2) * mimosaUnitsPerMm(fieldShape);\n      stoneHoleMarkup = '<circle id=\"cut-stone-hole\" cx=\"' + (pinPt.x * sx).toFixed(3)\n        + '\" cy=\"' + (pinPt.y * sy).toFixed(3) + '\" r=\"' + holeR.toFixed(3) + '\"/>';\n    } catch (eHoleMk) {}\n\n    let voidPaths = polyRingsToPaths(voidsGeom && voidsGeom.geometry);\n    voidPaths = voidPaths.filter(function (d) {\n      const nums = d.match(/-?\\d*\\.?\\d+/g);\n      if (!nums || nums.length < 8) return false;\n      let len = 0;\n      for (let i = 2; i + 1 < nums.length; i += 2) {\n        len += Math.hypot(nums[i] - nums[i - 2], nums[i + 1] - nums[i - 1]);\n        if (len >= MIN_LINE_VB * 4) return true;\n      }\n      return false;\n    });\n\n    const cutOutline = mimosaPathDToPolyline(mimosaCutPathWithBail(fieldShape));\n    const voidMarkup = voidPaths.map(function (d) {\n      return '<path d=\"' + d + '\"/>';\n    }).join('');\n\n    // Intermediate path markup only \u2014 mimosaSvgToDxf turns this into .dxf.\n    return '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n'\n      + '<!-- Mimosa FACTORY OPENWORK CUT \u2192 DXF \u2014 ' + role + ' / ' + fieldShape\n      + ' \u2014 W=' + mimosaPieceWidthMm(fieldShape).toFixed(1) + 'mm \u00B7 min metal=' + MIN_LINE_MM + 'mm -->\\n'\n      + '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" width=\"'\n      + PENDANT_WIDTH_MM + 'mm\" height=\"' + PENDANT_WIDTH_MM + 'mm\">'\n      + '<path id=\"cut-outline\" d=\"' + cutOutline\n      + '\" fill=\"none\" fill-rule=\"evenodd\" stroke=\"#CC0000\" stroke-width=\"'\n      + strokeVb + '\" stroke-linejoin=\"round\"/>'\n      + '<g id=\"cut-voids\" fill=\"none\" stroke=\"#000000\" stroke-width=\"'\n      + strokeVb + '\" stroke-linecap=\"round\" stroke-linejoin=\"round\">'\n      + voidMarkup\n      + stoneHoleMarkup\n      + '</g>'\n      + '</svg>';\n  }\n\n  // Precomputed TrueType glyph outlines (quadratic-bezier SVG path data,\n  // in font units normalized so fontSize=1 corresponds to 1 em) for the\n  // exact two typefaces used on the factory backside engraving \u2014\n  // extracted offline via opentype.js from the real Google Fonts TTF\n  // files (Plus Jakarta Sans Bold 700, Petit Formal Script Regular), the same\n  // offline-precompute pattern already used for MIMOSA_RING_POINTS. This\n  // is what makes the backside text real cuttable vector geometry instead\n  // of raw SVG <text> \u2014 the DXF converter has no font engine and can't\n  // rasterize or outline a live web font itself; only characters actually\n  // used by this product (digits, N/S/E/W, '.', '\u00B0', and A-Z) are included.\n  //\n  // The data itself (~72KB) lives in assets/mimosa-glyphs.js, loaded via a\n  // <script src> tag earlier in this file \u2014 inlining it here pushed this\n  // section over Shopify's 256KB per-template limit. MIMOSA_GLYPH_PATHS\n  // is that script's top-level const, visible here as an ordinary global\n  // (classic scripts on one page share a lexical scope) as long as the\n  // asset tag stays before this inline <script> block in the HTML.\n  // Lays out `str` as a row of individual glyph <path> elements, centered\n  // at (cx, y) in the same units as fontSize (matches text-anchor=\"middle\"\n  // on the <text> elements this replaces). Silently skips any character\n  // missing from the glyph table (still advances the cursor by a rough\n  // fallback width so spacing doesn't collapse) \u2014 input to this function\n  // is always pre-sanitized to the supported character set, so this\n  // should never actually trigger in production.\n  function mimosaTextRunToPaths(str, fontKey, fontSize, cx, y, letterSpacing) {\n    const table = MIMOSA_GLYPH_PATHS[fontKey] || {};\n    const chars = Array.from(String(str));\n    const ls = letterSpacing || 0;\n    const advances = chars.map(function (ch) {\n      const g = table[ch];\n      return g ? g.adv * fontSize : fontSize * 0.6;\n    });\n    const totalW = advances.reduce(function (a, b) { return a + b; }, 0) + ls * Math.max(0, chars.length - 1);\n    let x = cx - totalW / 2;\n    let out = '';\n    chars.forEach(function (ch, idx) {\n      const g = table[ch];\n      if (g) {\n        // Transform MUST be on a wrapping <g>, not the <path> itself \u2014\n        // mimosaExtractSubpathsFromSvg (used by the DXF converter) only\n        // reads transform off <g> elements when walking the tree; a\n        // transform placed directly on a <path> is silently ignored,\n        // which left every glyph's raw ~0-1-unit local coordinates\n        // un-translated/un-scaled (collapsed near the origin, invisible\n        // at pendant scale) the first time this shipped.\n        out += '<g transform=\"translate(' + x.toFixed(3) + ' ' + y.toFixed(3) + ') scale(' + fontSize.toFixed(4) + ')\"><path d=\"' + g.d + '\"/></g>';\n      }\n      x += advances[idx] + ls;\n    });\n    return out;\n  }\n\n  // Backside layout, in artboard units. ONE table, used by both the on-page\n  // preview and the factory file. They used to carry two hand-kept sets of\n  // numbers and had drifted: the export put the pattern icon at y=61 scale\n  // 0.72 while the preview had it at y=70 scale 0.60, so in the exported file\n  // the icon sat right on top of the second name row \u2014 and the export ignored\n  // `role` entirely, giving the His piece the Hers positions even though the\n  // preview lays His out differently. Same class of bug as the front face\n  // (see mimosaBuildFactoryOpenworkSvg): two pipelines drawing one product.\n  const MIMOSA_BACK_LAYOUT = {\n    // Re-fitted to the redrawn blanks (2026-09-22). Every row is checked by\n    // intersecting a horizontal line with the outline inset 5 and taking the\n    // segment that contains x=50 (the heart's cleft splits the top rows into\n    // two, so a plain chord length lies). On the heart that usable band is\n    // y 32.6-74.3, at most 51.9 wide at y=39.6 and tapering to nothing at the\n    // tip \u2014 the old rows were laid out for the taller, narrower blank and put\n    // the coordinate line above the metal entirely.\n    // Measured, not eyeballed: at the old numbers the two name rows overlapped\n    // by 2.5 units (1.0mm) and the script letters overlapped each other by up\n    // to 3.5 units (1.4mm) \u2014 \"\u80CC\u9762\u7684\u5973\u6B3E\u7684\u5B57\u6709\u4E9B\u7C98\u8D34\u5728\u4E00\u8D77\u4E86\". The rows were\n    // re-stacked (and the coordinates shrunk) so nothing touches inside the\n    // 25mm heart. Names are Petit Formal Script: a formal handwritten script\n    // with clearer capitals. Spacing is a small gap so the swashes do not\n    // sit on top of each other.\n    // Coordinates moved up to the top of the usable band so the names get the\n    // middle of the face (\"\u4F60\u53EF\u4EE5\u628A\u5750\u6807\u79FB\u52A8\u4E0A\u53BB\u554A\").\n    hers: { latY: 34, lngY: 40, name1Y: 51, name2Y: 63, patternY: 71, patternScale: 0.35,\n            coordSize: 5.5, coordSpacing: 0.6, nameSize: 10, nameSpacing: 1.8 },\n    // The drop is a neck at the heart's coordinate rows (about 24 units wide\n    // at y=34). Those lines sat on the point and ran off both sides. They sit\n    // in the bulb instead, and mimosaFittedCoordPair shrinks a long longitude\n    // until it fits that row.\n    // Wider and more open than the first drop fit. Size 4 sat in a tight\n    // block under a lot of empty gold (\"\u662F\u4E0D\u662F\u592A\u6324\u4E86\u00B7\u00B7\u6587\u5B57\u5F88\u5C0F\"). Coordinates\n    // are back near the heart's size, on rows wide enough to hold them.\n    // Names stay in the belly; a six-letter script line still shrinks to\n    // the row, but the rows themselves are no longer stacked on the taper.\n    // Metal ends at y\u224875.9. The icon sits under the names with a gap, and\n    // its lowest point stays about 4 units inside the tip.\n    // 2026-11 re-fit: coordinates poked through the narrow upper edge, the\n    // initials were small and their rows overlapped (descender of row 1 on\n    // the capitals of row 2), and the icon was too big (\"\u623F\u5C4Bkiss\u7684\u9700\u8981\u7F29\u5C0F\n    // 30%\", \"\u540D\u5B57\u7F29\u5199\u73B0\u5728\u592A\u6324\u592A\u5C0F\u4E86\"). Coordinates now sit a little lower on\n    // wider chords and are fitted point-by-point to the outline; initials are\n    // larger with open tracking and a real gap between rows; the icon is 30%\n    // smaller (0.58 \u2192 0.41).\n    drop: { latY: 41.4, lngY: 46.8, name1Y: 55.2, name2Y: 64.8, patternY: 71.0, patternScale: 0.41,\n            coordSize: 4.6, coordSpacing: 0.3, nameSize: 8.2, nameSpacing: 1.9 },\n    his:  { latY: 33, lngY: 40, name1Y: 55, name2Y: 68, patternY: 79, patternScale: 0.55,\n            coordSize: 5.2, coordSpacing: 0.65, nameSize: 10, nameSpacing: 1.8 }\n  };\n\n  function mimosaBackLayout(shape, role) {\n    if (role === 'his' || shape === 'shield') return MIMOSA_BACK_LAYOUT.his;\n    if (shape === 'drop') return MIMOSA_BACK_LAYOUT.drop;\n    return MIMOSA_BACK_LAYOUT.hers;\n  }\n\n  // Push the table into the preview's static <text>/<g> elements so the two\n  // cannot drift again. Text CONTENT is still updated by mimosaUpdateBackPreview.\n  function mimosaPlateNameRows() {\n    const read = function (id) {\n      return Array.from(String((document.getElementById(id) || {}).value || '')).slice(0, 6).join('');\n    };\n    const raw1 = read('mimosa-name-row-1');\n    const raw2 = read('mimosa-name-row-2');\n    // JL / MK are only the empty-plate sample. Once either row is filled,\n    // the other row stays blank instead of keeping the sample name.\n    if (!raw1 && !raw2) return { n1: 'JL', n2: 'MK' };\n    return { n1: raw1, n2: raw2 };\n  }\n\n  function mimosaSyncBackLayout() {\n    [['', 'hers'], ['-his', 'his']].forEach(function (pair) {\n      const sfx = pair[0];\n      const shapeForRole = (pair[1] === 'his') ? 'shield' : mimosaHersShape();\n      const L = mimosaBackLayout(shapeForRole, pair[1]);\n      const set = function (id, attrs) {\n        const el = document.getElementById(id + sfx);\n        if (!el) return;\n        Object.keys(attrs).forEach(function (k) { el.setAttribute(k, attrs[k]); });\n      };\n      const pin = mimosaReadPinLatLng();\n      const coords = mimosaCoordPairFromLatLng(pin.lat, pin.lng);\n      const coordFit = mimosaFittedCoordPair(shapeForRole, pair[1], coords.latLabel, coords.lngLabel);\n      const coordX = (50 + coordFit.spacing / 2).toFixed(2);\n      set('mimosa-back-coord-lat', { x: coordX, y: L.latY, 'font-size': coordFit.size, 'letter-spacing': coordFit.spacing });\n      set('mimosa-back-coord-lng', { x: coordX, y: L.lngY, 'font-size': coordFit.size, 'letter-spacing': coordFit.spacing });\n      // Position only \u2014 the SIZE comes from the fit, because this function runs\n      // after mimosaUpdateBackPreview on some paths and was putting the table's\n      // full size back on a long name that had been shrunk to fit.\n      const names = mimosaPlateNameRows();\n      const fitted = mimosaFittedNamePair(shapeForRole, pair[1], names.n1, names.n2);\n      const anchorX = (50 + fitted.spacing / 2).toFixed(2);\n      set('mimosa-back-name-1', { x: anchorX, y: L.name1Y, 'font-size': fitted.size, 'letter-spacing': fitted.spacing });\n      set('mimosa-back-name-2', { x: anchorX, y: L.name2Y, 'font-size': fitted.size, 'letter-spacing': fitted.spacing });\n      set('mimosa-back-pattern', { transform: 'translate(50, ' + L.patternY + ') scale(' + mimosaPatternScale(L) + ')' });\n    });\n  }\n\n  function mimosaBuildFactoryBackSvg(shape, role) {\n    const compound = mimosaPathDToPolyline(mimosaCutPathWithBail(shape));\n    const pin = mimosaReadPinLatLng();\n    const pair = mimosaCoordPairFromLatLng(pin.lat, pin.lng);\n    const plateNames = mimosaPlateNameRows();\n    const n1 = plateNames.n1;\n    const n2 = plateNames.n2;\n    const pattern = mimosaPatternSvgMarkup(currentBackPattern);\n    const L = mimosaBackLayout(shape, role);\n    const coordFit = mimosaFittedCoordPair(shape, role, pair.latLabel, pair.lngLabel);\n    // Both plates use the same faces: Plus Jakarta Sans Bold for the\n    // coordinates, Petit Formal Script for the names. His only differs in size\n    // and position.\n    //\n    // Same silhouette the plate preview draws (outer edge + bail hole).\n    // CUT is that contour only. Lettering stays ENGRAVE, inside it.\n    return '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n'\n      + '<!-- Mimosa FACTORY BACK ENGRAVING \u2014 laser etch on solid plate \u2014 ' + role + ' \u2014 W=' + mimosaPieceWidthMm(shape).toFixed(1) + 'mm -->\\n'\n      + '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" width=\"' + PENDANT_WIDTH_MM + 'mm\" height=\"' + PENDANT_WIDTH_MM + 'mm\">'\n      + '<path id=\"plate-outline\" fill=\"none\" stroke=\"#000000\" d=\"' + compound + '\"/>'\n      + '<g id=\"engrave-content\" fill=\"#000000\" stroke=\"none\">'\n      + mimosaTextRunToPaths(pair.latLabel, 'plusJakartaSansBold', coordFit.size, 50, L.latY, coordFit.spacing)\n      + mimosaTextRunToPaths(pair.lngLabel, 'plusJakartaSansBold', coordFit.size, 50, L.lngY, coordFit.spacing)\n      + (function () {\n          // Same auto-fit the preview uses, so a long name cannot come out of\n          // the factory file wider than the blank.\n          const fit = mimosaFittedNamePair(shape, role, n1, n2);\n          return mimosaTextRunToPaths(n1, 'petitFormalScript', fit.size, 50, L.name1Y, fit.spacing)\n               + mimosaTextRunToPaths(n2, 'petitFormalScript', fit.size, 50, L.name2Y, fit.spacing);\n        })()\n      + '<g id=\"engrave-icon\" transform=\"translate(50, ' + L.patternY + ') scale(' + mimosaPatternScale(L) + ')\" fill=\"none\" stroke=\"#000000\" stroke-width=\"1.15\" stroke-linejoin=\"round\" stroke-linecap=\"round\">' + pattern + '</g>'\n      + '</g></svg>';\n  }\n\n  function mimosaSourceMapCamera() {\n    // Prefer the map the customer just interacted with\n    if (currentViewMode === 'his' && mapHis) return mapHis;\n    if (currentViewMode === 'jewelry' && mapAfter) return mapAfter;\n    if (mapBefore) return mapBefore;\n    return mapAfter || mapHis;\n  }\n\n  // jumpTo fires moveend \u2192 factory prebuild \u2192 more jumpTo. Count depth so\n  // those programmatic moveends do not re-schedule and yank the camera.\n  let mimosaCameraSyncDepth = 0;\n  function mimosaSyncMapCamera(target, source) {\n    if (!target || !source || target === source) return;\n    mimosaCameraSyncDepth += 1;\n    try {\n      target.jumpTo({\n        center: source.getCenter(),\n        zoom: source.getZoom(),\n        bearing: 0,\n        pitch: 0\n      });\n    } finally {\n      setTimeout(function () {\n        mimosaCameraSyncDepth = Math.max(0, mimosaCameraSyncDepth - 1);\n      }, 0);\n    }\n  }\n\n  function mimosaAnyMapMoving() {\n    try {\n      return [mapBefore, mapAfter, mapHis].some(function (m) {\n        return m && typeof m.isMoving === 'function' && m.isMoving();\n      });\n    } catch (eM) {\n      return false;\n    }\n  }\n\n  function mimosaMapIsIdle(map) {\n    try {\n      if (!map || !map.loaded() || !map.isStyleLoaded()) return false;\n      if (typeof map.isMoving === 'function' && map.isMoving()) return false;\n      if (typeof map.areTilesLoaded === 'function' && !map.areTilesLoaded()) return false;\n      return true;\n    } catch (eIdle) {\n      return false;\n    }\n  }\n\n  function mimosaWaitMapIdle(map, timeoutMs) {\n    return new Promise(function (resolve) {\n      if (!map || mimosaMapIsIdle(map)) return resolve();\n      const finish = function () {\n        clearTimeout(timer);\n        map.off('idle', finish);\n        resolve();\n      };\n      const timer = setTimeout(finish, timeoutMs || 900);\n      map.once('idle', finish);\n    });\n  }\n\n  async function mimosaPrepareMapForExport(map) {\n    if (!map) return null;\n    try { map.resize(); } catch (e) {}\n    mimosaSyncMapCamera(map, mimosaSourceMapCamera());\n    try { map.resize(); } catch (e2) {}\n    if (mimosaMapIsIdle(map)) return map;\n    await mimosaWaitMapIdle(map, 700);\n    return map;\n  }\n\n  // Builds the factory pack in memory: [{ name, dxf }]. Shared by the\n  // download button and by the add-to-cart hook that attaches the same files\n  // to the order \u2014 they must be the identical bytes, so there is one builder.\n  // Builds the factory pack in memory: [{ name, dxf, svg, svgName }]. Shared by the\n  // download button, admin regeneration tool, and add-to-cart hook.\n  async function mimosaBuildFactoryFiles(options) {\n    const prevMode = currentViewMode;\n    const keepView = !!(options && options.keepView);\n    let switchedView = false;\n    const canvasWide = function (map) {\n      try {\n        return !!(map && map.getCanvas && map.getCanvas() && map.getCanvas().clientWidth > 40);\n      } catch (eW) {\n        return false;\n      }\n    };\n    try {\n    const loc = (options && options.locSlug) || mimosaFactoryLocSlug();\n    const orderPrefix = (options && options.orderNumber)\n      ? ('ORDER-' + options.orderNumber + '-REGENERATED-')\n      : 'FACTORY-';\n    // A pair is her shape plus his shield. Clicking the shield card used to\n    // overwrite currentShape, so both downloads came out as shields.\n    const hersShape = currentSet === 'pair' ? mimosaHersShape() : (currentShape || 'heart');\n\n    // Quiet prebuild (keepView): NEVER flip Your Map \u2192 Her/His. mapAfter is\n    // often 0\u00D70 under the Map tab; the old check `!canvasWide(mapAfter) &&\n    // !canvasWide(mapBefore)` treated a wide mapBefore as \"ready\" and skipped\n    // the jewelry switch \u2014 then ATC exported a 0\u00D70 hers canvas and failed with\n    // \"Could not add to cart\" / missing factory files. ATC/download (!keepView)\n    // must switch whenever mapAfter itself is not sized, even if Your Map is.\n    if (!keepView) {\n      if (!canvasWide(mapAfter)) {\n        switchedView = true;\n        mimosaSetViewMode('jewelry');\n        mimosaShowJewelryPiece('hers');\n        await new Promise(function (r) { setTimeout(r, 200); });\n      }\n    } else {\n      // Size hidden jewelry canvases in place \u2014 do not change currentViewMode.\n      if (mapAfter && !canvasWide(mapAfter)) {\n        try { mapAfter.resize(); } catch (eRz) {}\n        await new Promise(function (r) { requestAnimationFrame(function () { r(); }); });\n      }\n    }\n    if (mapAfter) { try { mapAfter.resize(); } catch (e) {} }\n    // Quiet prebuild: only pull hidden/export canvases toward the map the\n    // customer is looking at. Never jump the visible camera to a stale sibling\n    // (that fought flyTo and made the pin/address disagree with the basemap).\n    const source = mimosaSourceMapCamera() || mapBefore || mapAfter;\n    if (keepView) {\n      if (source === mapBefore) {\n        if (mapAfter) mimosaSyncMapCamera(mapAfter, mapBefore);\n        if (mapHis) mimosaSyncMapCamera(mapHis, mapBefore);\n      } else if (source === mapAfter) {\n        if (mapHis) mimosaSyncMapCamera(mapHis, mapAfter);\n      } else if (source === mapHis) {\n        /* his tab \u2014 leave hers alone */\n      }\n    } else {\n      if (mapAfter && source) mimosaSyncMapCamera(mapAfter, source);\n      if (mapBefore && source && source !== mapBefore) mimosaSyncMapCamera(mapBefore, source);\n      if (mapHis && source) mimosaSyncMapCamera(mapHis, source);\n    }\n\n    const mapHers = await mimosaPrepareMapForExport(mapAfter || mapBefore);\n    if (!mapHers || !mapHers.isStyleLoaded()) throw new Error('map not ready');\n    // Same guard as His below: in a slow or background tab 120ms is not always\n    // enough for the view switch, and a 0x0 canvas silently produced a Hers\n    // file with the stone hole thrown to the edge and cut lines through it.\n    let hersW = (mapHers.getCanvas() && mapHers.getCanvas().clientWidth) || 0;\n    if (!(hersW > 40)) {\n      try { mapHers.resize(); } catch (eHR) {}\n      await mimosaWaitMapIdle(mapHers, 1500);\n      hersW = (mapHers.getCanvas() && mapHers.getCanvas().clientWidth) || 0;\n    }\n    if (!(hersW > 40)) throw new Error('hers map not sized for export');\n    // The preview skips repainting when the current geometry is already on screen.\n    try { await mimosaApplyRoadFilter(mapHers, 'etched'); } catch (eHersEtch) {}\n\n    // Factory front = OPENWORK CUT (same lattice the customer sees).\n    // Back = ENGRAVE text/icons on a solid plate (laser etch, not cut-through).\n    // Only attach back DXFs when the customer added the engraved plate.\n    const out = [];\n    out.push({\n      slot: 1,\n      name: orderPrefix + loc + '-HERS-openwork-CUT-' + hersShape + '.dxf',\n      svgName: orderPrefix + loc + '-HERS-front-openwork-CUT-' + hersShape + '.svg',\n      svg: await mimosaBuildFactoryOpenworkSvg(mapHers, hersShape, 'hers'),\n      forceLayer: 'CUT',\n      shape: hersShape\n    });\n    if (backplateOn) {\n      out.push({\n        slot: 2,\n        name: orderPrefix + loc + '-HERS-back-ENGRAVE-' + hersShape + '.dxf',\n        svgName: orderPrefix + loc + '-HERS-back-ENGRAVE-' + hersShape + '.svg',\n        svg: mimosaBuildFactoryBackSvg(hersShape, 'hers'),\n        forceLayer: 'ENGRAVE',\n        shape: hersShape\n      });\n    }\n\n    if (currentSet === 'pair') {\n      // His MUST use mapHis. Falling back to mapHers produced a near-empty\n      // shield DXF while the live His preview looked fine.\n      // Quiet prebuild (keepView) must NEVER flip the tab to His/shield \u2014\n      // that was why tapping Drop jumped the preview to the shield. Pair CSS\n      // keeps #mimosa-jewelry-his laid out while hidden; only the download\n      // path may switch the visible tab when the canvas is still 0\u00D70.\n      const hisPiece = document.getElementById('mimosa-jewelry-his');\n      if (hisPiece) hisPiece.removeAttribute('hidden');\n      if (!canvasWide(mapHis)) {\n        try { if (mapHis) mapHis.resize(); } catch (eR0) {}\n        await new Promise(function (r) { requestAnimationFrame(function () { r(); }); });\n      }\n      if (!canvasWide(mapHis) && !keepView) {\n        switchedView = true;\n        mimosaSetViewMode('his');\n        mimosaShowJewelryPiece('his');\n        await new Promise(function (r) { setTimeout(r, 120); });\n      }\n      try { if (mapHis) mapHis.resize(); } catch (eR1) {}\n      await new Promise(function (r) { requestAnimationFrame(function () { r(); }); });\n      if (!mapHis) throw new Error('his map missing');\n      mimosaSyncMapCamera(mapHis, mapHers);\n      await mimosaPrepareMapForExport(mapHis);\n      let hisW = (mapHis.getCanvas() && mapHis.getCanvas().clientWidth) || 0;\n      if (!(hisW > 40)) {\n        try { mapHis.resize(); } catch (eR) {}\n        await mimosaWaitMapIdle(mapHis, 1500);\n        hisW = (mapHis.getCanvas() && mapHis.getCanvas().clientWidth) || 0;\n      }\n      if (!(hisW > 40)) {\n        // Quiet prebuild: skip His this round rather than steal the Drop/Heart tab.\n        // A later schedule (or the download button) will retry once sized.\n        throw new Error('his map not sized for export');\n      } else {\n        try { await mimosaApplyRoadFilter(mapHis, 'etched'); } catch (eEtch) {}\n        out.push({\n          slot: 3,\n          name: orderPrefix + loc + '-HIS-openwork-CUT-shield.dxf',\n          svgName: orderPrefix + loc + '-HIS-front-openwork-CUT-shield.svg',\n          svg: await mimosaBuildFactoryOpenworkSvg(mapHis, 'shield', 'his'),\n          forceLayer: 'CUT',\n          shape: 'shield'\n        });\n        if (backplateOn) {\n          out.push({\n            slot: 4,\n            name: orderPrefix + loc + '-HIS-back-ENGRAVE-shield.dxf',\n            svgName: orderPrefix + loc + '-HIS-back-ENGRAVE-shield.svg',\n            svg: mimosaBuildFactoryBackSvg('shield', 'his'),\n            forceLayer: 'ENGRAVE',\n            shape: 'shield'\n          });\n        }\n      }\n    }\n\n    return out.map(function (f) {\n      return {\n        slot: f.slot,\n        name: f.name,\n        svgName: f.svgName,\n        svg: f.svg,\n        forceLayer: f.forceLayer,\n        shape: f.shape,\n        dxf: mimosaSvgToDxf(f.svg, mimosaPieceWidthMm(f.shape), f.forceLayer, f.shape)\n      };\n    });\n    } finally {\n      if (switchedView) {\n        mimosaSetViewMode(prevMode === 'his' ? 'his' : (prevMode === 'jewelry' ? 'jewelry' : 'map'));\n      }\n    }\n  }\n\n  // Files are built while the customer is still looking at the map, so Add to\n  // Cart can post them and leave for /cart without a \"Preparing\u2026\" wait.\n  let mimosaFactoryCache = null;\n  let mimosaFactoryInflight = null;\n  let mimosaFactoryTimer = 0;\n  let mimosaFactoryBuilding = 0;\n\n  function mimosaFactorySignature() {\n    const loc = ((document.getElementById('mimosa-hidden-location') || {}).value || '');\n    const coords = ((document.getElementById('mimosa-hidden-coords') || {}).value || '');\n    const zoom = String(mapZoomLevel);\n    let shape = 'heart';\n    try { shape = currentSet === 'pair' ? mimosaHersShape() : (currentShape || 'heart'); } catch (eS) {}\n    const n1 = backplateOn ? ((document.getElementById('mimosa-name-row-1') || {}).value || '') : '';\n    const n2 = backplateOn ? ((document.getElementById('mimosa-name-row-2') || {}).value || '') : '';\n    let pattern = '';\n    try { pattern = backplateOn ? (currentBackPattern || '') : ''; } catch (eP) { pattern = ''; }\n    const stone = (stonePos ? stonePos.x.toFixed(1) + ',' + stonePos.y.toFixed(1) : '') + ':' + (currentStone || '');\n    let camera = '';\n    try {\n      const map = mimosaSourceMapCamera();\n      const center = map.getCenter();\n      camera = [center.lng.toFixed(6), center.lat.toFixed(6), map.getZoom().toFixed(4)].join(',');\n    } catch (eCamera) {}\n    return [loc, coords, zoom, camera, currentSet, shape, backplateOn ? '1' : '0', n1, n2, pattern, stone].join('::');\n  }\n\n  function mimosaFactoryFilesComplete(files) {\n    const required = currentSet === 'pair' ? [1, 3] : [1];\n    if (backplateOn) {\n      required.push(2);\n      if (currentSet === 'pair') required.push(4);\n    }\n    return Array.isArray(files) && files.length === required.length && required.every(function (slot) {\n      return files.some(function (file) { return file.slot === slot && !!file.dxf; });\n    });\n  }\n\n  // Diagnostic state stays on this page; no customer data is sent anywhere.\n  function mimosaFactoryState(state, files, elapsed) {\n    const form = document.getElementById('mimosa-customizer-form');\n    if (!form) return;\n    form.dataset.factoryState = state;\n    form.dataset.factoryFileCount = String((files || []).length);\n    if (elapsed != null) form.dataset.factoryBuildMs = String(Math.round(elapsed));\n  }\n\n  function mimosaReadyFactoryFiles() {\n    const sig = mimosaFactorySignature();\n    if (mimosaFactoryCache && mimosaFactoryCache.sig === sig && mimosaFactoryFilesComplete(mimosaFactoryCache.files)) {\n      return mimosaFactoryCache.files;\n    }\n    return null;\n  }\n\n  function mimosaScheduleFactoryFiles() {\n    clearTimeout(mimosaFactoryTimer);\n    if (!isLocationConfirmed) return;\n    const ready = mimosaReadyFactoryFiles();\n    if (ready) {\n      mimosaFactoryState('ready', ready);\n      return;\n    }\n    // Queue even during a camera sync. Returning early here used to lose the\n    // location-selection event, leaving all generation until Add to Cart.\n    if (!mimosaFactoryInflight) mimosaFactoryState('scheduled');\n    mimosaFactoryTimer = setTimeout(function () {\n      if (isMapTransitioning || mimosaCameraSyncDepth > 0 || mimosaAnyMapMoving()) {\n        mimosaScheduleFactoryFiles();\n        return;\n      }\n      mimosaEnsureFactoryFiles().catch(function (error) {\n        mimosaFactoryState('error');\n        console.warn('factory prebuild', error);\n      });\n    }, 300);\n  }\n\n  async function mimosaEnsureFactoryFiles() {\n    // All callers share one build. If the customer edits during it, discard\n    // that result and build the latest design before returning to any caller.\n    while (isLocationConfirmed) {\n      const ready = mimosaReadyFactoryFiles();\n      if (ready) return ready;\n      if (mimosaFactoryInflight) {\n        await mimosaFactoryInflight;\n        continue;\n      }\n      const runSig = mimosaFactorySignature();\n      const started = performance.now();\n      mimosaFactoryBuilding += 1;\n      mimosaFactoryState('building');\n      const promise = mimosaBuildFactoryFiles({ keepView: true }).then(function (files) {\n        if (runSig !== mimosaFactorySignature() || !isLocationConfirmed) return;\n        if (!mimosaFactoryFilesComplete(files)) throw new Error('map files incomplete');\n        mimosaFactoryCache = { sig: runSig, files: files };\n        mimosaFactoryState('ready', files, performance.now() - started);\n      });\n      mimosaFactoryInflight = promise;\n      try {\n        await promise;\n      } finally {\n        mimosaFactoryBuilding = Math.max(0, mimosaFactoryBuilding - 1);\n        if (mimosaFactoryInflight === promise) mimosaFactoryInflight = null;\n      }\n    }\n    throw new Error('map location not confirmed');\n  }\n\n  function mimosaFactoryDownloadBox() {\n    let box = document.getElementById('mimosa-factory-download-links');\n    if (box) return box;\n    const btn = document.getElementById('mimosa-factory-download-btn');\n    box = document.createElement('div');\n    box.id = 'mimosa-factory-download-links';\n    box.style.cssText = 'display:flex;flex-direction:column;gap:8px;margin-top:10px;';\n    if (btn && btn.parentNode) btn.insertAdjacentElement('afterend', box);\n    return box;\n  }\n\n  function mimosaDownloadFactoryPrintPack() {\n    const btn = document.getElementById('mimosa-factory-download-btn');\n    if (btn) {\n      btn.disabled = true;\n      btn.textContent = 'Generating Production DXFs\u2026';\n    }\n    (async function () {\n      try {\n        const files = await mimosaBuildFactoryFiles();\n        const box = mimosaFactoryDownloadBox();\n        box.replaceChildren();\n        const enc = new TextEncoder();\n        const zipBytes = mimosaZipStored(files.map(function (f) {\n          return { name: f.name, bytes: enc.encode(f.dxf) };\n        }));\n        const zipName = 'FACTORY-dxf-pack.zip';\n        box.appendChild(mimosaMakeDownloadLink(\n          new Blob([zipBytes], { type: 'application/zip' }),\n          zipName,\n          '\u2B07 Download all DXFs (zip)'\n        ));\n        files.forEach(function (f) {\n          box.appendChild(mimosaMakeDownloadLink(\n            new Blob([f.dxf], { type: 'application/octet-stream' }),\n            f.name,\n            f.name\n          ));\n        });\n        const note = document.querySelector('.mimosa-factory-tools .mimosa-svg-download-note');\n        if (note) note.textContent = 'Click a link above to save. Automatic downloads are blocked after the map finishes generating.';\n      } catch (err) {\n        console.warn('factory download', err);\n        alert('Download failed (' + ((err && err.message) || 'unknown') + '). Switch to Her Necklace view once, let it settle, then try again.');\n      } finally {\n        if (btn) {\n          btn.disabled = false;\n          btn.textContent = '\u2B07 Download Production DXFs';\n        }\n      }\n    })();\n  }\n\n\n\n  // Declared here because mimosaOnAbbrInput used it without ever defining it:\n  // every keystroke in the name fields threw \"mimosaBackPreviewTimer is not\n  // defined\" and the backside preview never refreshed from typing at all.\n  let mimosaBackPreviewTimer = null;\n\n  function mimosaOnAbbrInput(el) {\n    if (!el) return;\n    try {\n      // Skip while IME is composing \u2014 rewriting value mid-composition can crash mobile WebKit\n      if (el.isComposing || (el.dataset && el.dataset.composing === '1')) return;\n      const cleaned = Array.from(String(el.value || '')).slice(0, 6).join('');\n      if (el.value !== cleaned) {\n        const start = el.selectionStart;\n        el.value = cleaned;\n        if (typeof start === 'number') {\n          const pos = Math.min(cleaned.length, start);\n          try { el.setSelectionRange(pos, pos); } catch (e) {}\n        }\n      }\n      if (mimosaBackPreviewTimer) clearTimeout(mimosaBackPreviewTimer);   // declared above\n      mimosaBackPreviewTimer = setTimeout(function () {\n        mimosaUpdateBackPreview();\n        try { mimosaScheduleFactoryFiles(); } catch (eSched) {}\n      }, 50);\n    } catch (err) {\n      console.warn('mimosaOnAbbrInput', err);\n    }\n  }\n\n  let currentBackPattern = 'house';\n\n  // The house and the heart are about as tall as they are wide; the lips are\n  // half as tall, so at the shared scale they come out visually much smaller\n  // and their mouth opening shrinks below what can be etched. Give them their\n  // own factor \u2014 the blank has the width to spare at the pattern row.\n  function mimosaPatternScale(L) {\n    return +(L.patternScale * (currentBackPattern === 'kiss' ? 1.5 : 1)).toFixed(3);\n  }\n\n  function mimosaPatternSvgMarkup(pattern) {\n    if (pattern === 'none') return '';\n    const key = pattern === 'mouth' ? 'kiss' : (pattern || 'house');\n    if (key === 'kiss') {\n      // Full lips, drawn from the user's reference: cupid's-bow upper lip with\n      // two full lobes, pointed corners on the mouth line, a deep lower lip,\n      // and the mouth opening as a wavy lens. ONE compound path with evenodd,\n      // so the opening is punched out of the silhouette instead of being drawn\n      // over it \u2014 which also hands the factory file two clean closed contours\n      // rather than two overlapping filled shapes (note 12's rule).\n      return '<path fill-rule=\"evenodd\" fill=\"#1A1512\" stroke=\"none\" d=\"'\n        + 'M -6.1,0.05 C -5.4,-1.35 -4.3,-2.8 -3.15,-3.35 C -2.3,-3.78 -1.55,-3.5 -1.0,-2.95 '\n        + 'C -0.62,-2.55 -0.3,-2.2 0,-2.2 C 0.3,-2.2 0.62,-2.55 1.0,-2.95 '\n        + 'C 1.55,-3.5 2.3,-3.78 3.15,-3.35 C 4.3,-2.8 5.4,-1.35 6.1,0.05 '\n        + 'C 5.3,2.4 3.05,4.55 0,4.55 C -3.05,4.55 -5.3,2.4 -6.1,0.05 Z '\n        // Mouth opening winds the opposite way from the lips. The plate\n        // preview punches it with evenodd; the factory hatch uses nonzero\n        // winding, so the hole only stays open if this contour reverses.\n        + 'M -5.15,0.05 C -3.6,0.44 -1.95,0.58 0,0.58 C 1.95,0.58 3.6,0.44 5.15,0.05 '\n        + 'C 3.7,-0.35 2.25,-0.42 1.35,-0.12 C 0.75,0.08 0.38,0.16 0,0.16 '\n        + 'C -0.38,0.16 -0.75,0.08 -1.35,-0.12 C -2.25,-0.42 -3.7,-0.35 -5.15,0.05 Z\"/>';\n    }\n    if (key === 'heart') {\n      return '<path d=\"M0 5.2 C-3.6 2.4 -5.8 0.1 -5.8 -2.4 C-5.8 -4.2 -4.5 -5.4 -2.9 -5.4 C-1.8 -5.4 -0.85 -4.75 0 -3.6 C0.85 -4.75 1.8 -5.4 2.9 -5.4 C4.5 -5.4 5.8 -4.2 5.8 -2.4 C5.8 0.1 3.6 2.4 0 5.2 Z\"/>';\n    }\n    // House \u2014 tiny cottage with chimney puff\n    return ''\n      + '<path d=\"M-5.2 -0.4 L0 -5.4 L5.2 -0.4\"/>'\n      + '<path d=\"M-4 -0.1 V5.4 H4 V-0.1\"/>'\n      + '<path d=\"M-1.35 5.4 V1.5 H1.35 V5.4\"/>'\n      + '<path d=\"M3.1 -4.2 V-5.6\"/>'\n      + '<path d=\"M2.35 -5.85 C2.75 -6.7 3.85 -6.75 4.15 -5.9\"/>';\n  }\n\n  /** One coordinate pair from the customer's pin (not a street address). */\n  function mimosaCoordPairFromLatLng(lat, lng) {\n    const n = Number(lat);\n    const e = Number(lng);\n    if (!isFinite(n) || !isFinite(e)) {\n      return { latLabel: 'N25.7771\u00B0', lngLabel: 'W80.2002\u00B0', text: 'N25.7771\u00B0 \u00B7 W80.2002\u00B0' };\n    }\n    const ns = n >= 0 ? 'N' : 'S';\n    const ew = e >= 0 ? 'E' : 'W';\n    const latLabel = ns + Math.abs(n).toFixed(4) + '\u00B0';\n    const lngLabel = ew + Math.abs(e).toFixed(4) + '\u00B0';\n    return { latLabel: latLabel, lngLabel: lngLabel, text: latLabel + ' \u00B7 ' + lngLabel };\n  }\n\n  function mimosaReadPinLatLng() {\n    const raw = ((document.getElementById('mimosa-hidden-coords') || {}).value || '').trim();\n    const parts = raw.split(',').map(function (s) { return parseFloat(String(s).trim()); });\n    if (parts.length >= 2 && isFinite(parts[0]) && isFinite(parts[1])) {\n      return { lat: parts[0], lng: parts[1] };\n    }\n    return { lat: 25.7771, lng: -80.2002 };\n  }\n\n  function mimosaSetTextContent(el, content) {\n    if (!el) return;\n    el.textContent = content;\n  }\n\n  function mimosaPathForShape(shape) {\n    if (shape === 'circle') return MIMOSA_CIRCLE_OUTER;\n    if (shape === 'drop') return MIMOSA_DROP_OUTER;\n    if (shape === 'shield') return MIMOSA_SHIELD_OUTER;\n    return MIMOSA_HEART_OUTER;\n  }\n\n  function mimosaSyncBackShape() {\n    const compound = mimosaCutPathWithBail(mimosaHersShape());\n    const body = document.getElementById('mimosa-back-body');\n    const clip = document.getElementById('mimosa-back-clip-path');\n    if (body) {\n      body.setAttribute('d', compound);\n      body.setAttribute('fill-rule', 'evenodd');\n    }\n    if (clip) {\n      clip.setAttribute('d', compound);\n      clip.setAttribute('fill-rule', 'evenodd');\n    }\n    // His shield always with bail\n    const bodyHis = document.getElementById('mimosa-back-body-his');\n    const clipHis = document.querySelector('#mimosa-back-clip-his path');\n    const hisCompound = mimosaCutPathWithBail('shield');\n    if (bodyHis) {\n      bodyHis.setAttribute('d', hisCompound);\n      bodyHis.setAttribute('fill-rule', 'evenodd');\n    }\n    if (clipHis) {\n      clipHis.setAttribute('d', hisCompound);\n      clipHis.setAttribute('fill-rule', 'evenodd');\n    }\n    mimosaFitShownPlates(document.getElementById('mimosa-back-svg'), body, document.getElementById('mimosa-back-svg-his'), bodyHis);\n  }\n\n  function mimosaPlateBox(path) {\n    if (!path || typeof path.getBBox !== 'function') return null;\n    let box;\n    try { box = path.getBBox(); } catch (e) { return null; }\n    if (!box || box.width < 1 || box.height < 1) return null;\n    return box;\n  }\n\n  function mimosaApplyPlateViewBox(svg, x, y, w, h) {\n    if (!svg) return;\n    svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');\n    svg.setAttribute('viewBox', x + ' ' + y + ' ' + w + ' ' + h);\n  }\n\n  // Side by side, both plates share one viewBox so a heart stays smaller than\n  // a shield. Fitting each shape to its own box made them the same size.\n  function mimosaFitShownPlates(svgHer, pathHer, svgHis, pathHis) {\n    const a = mimosaPlateBox(pathHer);\n    const b = mimosaPlateBox(pathHis);\n    const pad = 2;\n    if (currentSet === 'pair' && a && b) {\n      const x = Math.min(a.x, b.x) - pad;\n      const y = Math.min(a.y, b.y) - pad;\n      const w = Math.max(a.x + a.width, b.x + b.width) + pad - x;\n      const h = Math.max(a.y + a.height, b.y + b.height) + pad - y;\n      mimosaApplyPlateViewBox(svgHer, x, y, w, h);\n      mimosaApplyPlateViewBox(svgHis, x, y, w, h);\n      return;\n    }\n    if (a) mimosaApplyPlateViewBox(svgHer, a.x - pad, a.y - pad, a.width + pad * 2, a.height + pad * 2);\n    if (b) mimosaApplyPlateViewBox(svgHis, b.x - pad, b.y - pad, b.width + pad * 2, b.height + pad * 2);\n  }\n\n  // Width of the engraved field at a given row, in artboard units: intersect a\n  // horizontal line with the shape outline and take the span that contains the\n  // centre line, minus a margin on each side. The heart's cleft splits the top\n  // rows into two lobes, so a plain chord length would lie.\n  function mimosaRowWidthUnits(shape, y, marginUnits) {\n    try {\n      const subs = mimosaParsePathD(mimosaPathForShape(shape));\n      const pts = (subs[0] || []).map(function (p) { return [p.x, p.y]; });\n      if (pts.length < 3) return 0;\n      const xs = [];\n      for (let i = 0; i < pts.length; i++) {\n        const a = pts[i], b = pts[(i + 1) % pts.length];\n        if ((a[1] - y) * (b[1] - y) > 0) continue;       // no crossing\n        if (a[1] === b[1]) continue;\n        xs.push(a[0] + (b[0] - a[0]) * (y - a[1]) / (b[1] - a[1]));\n      }\n      if (xs.length < 2) return 0;\n      xs.sort(function (m, n) { return m - n; });\n      let left = null, right = null;\n      for (let i = 0; i + 1 < xs.length; i += 2) {\n        if (xs[i] <= 50 && xs[i + 1] >= 50) { left = xs[i]; right = xs[i + 1]; break; }\n      }\n      if (left === null) { left = xs[0]; right = xs[xs.length - 1]; }\n      return Math.max(0, (right - left) - 2 * (marginUnits || 0));\n    } catch (eW) { return 0; }\n  }\n\n  // The drop narrows going UP, so a row measured at its baseline lies: the\n  // tops of the digits sit on a narrower chord and poked through the edge\n  // (\"\u6C34\u6EF4\u5F62\u72B6\u7684\u523B\u5B57\u4E0D\u884C\u00B7\u6570\u5B57\u8981\u5728\u6846\u67B6\u5185\"). For the drop, every glyph point is\n  // checked against the outline at that point's own height. Returns the\n  // scale (\u22641 means shrink by that much) that brings the run inside the\n  // outline inset by `margin`; text is centred on x=50, so scaling the size\n  // scales every point's distance from the centre line.\n  const mimosaOutlineCache = {};\n  function mimosaOutlineHalfAt(shape, y) {\n    let pts = mimosaOutlineCache[shape];\n    if (!pts) {\n      pts = (mimosaParsePathD(mimosaPathForShape(shape))[0] || []).map(function (p) { return [p.x, p.y]; });\n      mimosaOutlineCache[shape] = pts;\n    }\n    const xs = [];\n    for (let i = 0; i < pts.length; i++) {\n      const a = pts[i], b = pts[(i + 1) % pts.length];\n      if ((a[1] - y) * (b[1] - y) > 0 || a[1] === b[1]) continue;\n      xs.push(a[0] + (b[0] - a[0]) * (y - a[1]) / (b[1] - a[1]));\n    }\n    if (xs.length < 2) return 0;\n    xs.sort(function (m, n) { return m - n; });\n    for (let i = 0; i + 1 < xs.length; i += 2) {\n      if (xs[i] <= 50 && xs[i + 1] >= 50) return Math.min(50 - xs[i], xs[i + 1] - 50);\n    }\n    return 0;\n  }\n\n  function mimosaRunFitScale(markup, shape, margin) {\n    const subs = mimosaExtractSubpathsFromSvg('<svg xmlns=\"http://www.w3.org/2000/svg\">' + markup + '</svg>');\n    let scale = Infinity;\n    subs.forEach(function (sp) {\n      sp.points.forEach(function (pt) {\n        const dx = Math.abs(pt.x - 50);\n        if (dx < 0.5) return;\n        const half = mimosaOutlineHalfAt(shape, pt.y) - margin;\n        scale = Math.min(scale, half > 0 ? half / dx : 0.5);\n      });\n    });\n    return isFinite(scale) ? scale : 1;\n  }\n\n  // Shrinks size (spacing follows it) until the whole run sits inside the\n  // drop outline. Iterates because shrinking also lowers the glyph tops onto\n  // a wider chord.\n  function mimosaFitRunInsideDrop(text, fontKey, y, style, margin, minSize) {\n    const ratio = style.size > 0 ? (style.spacing / style.size) : 0;\n    for (let i = 0; i < 16; i++) {\n      const k = mimosaRunFitScale(mimosaTextRunToPaths(text, fontKey, style.size, 50, y, style.spacing), 'drop', margin);\n      if (k >= 1) break;\n      style.size = +(style.size * Math.max(0.8, k * 0.995)).toFixed(2);\n      style.spacing = +(style.size * ratio).toFixed(2);\n      if (style.size < minSize) break;\n    }\n    return style;\n  }\n\n  // Names are customer input: six letters of a connecting script are far wider\n  // than a 25mm heart (\"\u8F93\u51655\u4E2A\u5B57\u7684\u65F6\u5019\u5DE6\u8FB9\u51FA\u754C\u4E86\"). Measure the real glyph\n  // run and shrink the size (spacing follows it) until the row fits its own\n  // width on the blank. Used by BOTH the preview and the factory file so they\n  // cannot disagree.\n  function mimosaFitNameStyle(text, shape, y, baseSize, baseSpacing) {\n    const letters = Array.from(String(text || ''));\n    const long = letters.length >= 4;\n    const style = {\n      size: long ? Math.min(baseSize, 11 - letters.length) : baseSize,\n      spacing: long ? Math.min(baseSpacing, 1.2) : baseSpacing\n    };\n    try {\n      if (!text) return style;\n      if (shape === 'drop') return mimosaFitRunInsideDrop(text, 'petitFormalScript', y, style, 3.0, 2.2);\n      const avail = mimosaRowWidthUnits(shape, y, shape === 'drop' ? 3.2 : 5.5);\n      if (!(avail > 0)) return style;\n      const ratio = style.size > 0 ? (style.spacing / style.size) : 0;\n      for (let i = 0; i < 20; i++) {\n        const markup = mimosaTextRunToPaths(text, 'petitFormalScript', style.size, 50, y, style.spacing);\n        const subs = mimosaExtractSubpathsFromSvg('<svg xmlns=\"http://www.w3.org/2000/svg\">' + markup + '</svg>');\n        if (!subs.length) break;\n        let lo = Infinity, hi = -Infinity;\n        subs.forEach(function (sp) { sp.points.forEach(function (pt) { if (pt.x < lo) lo = pt.x; if (pt.x > hi) hi = pt.x; }); });\n        const w = hi - lo;\n        if (w <= avail || !(w > 0)) return style;\n        style.size = +(style.size * (avail / w)).toFixed(2);\n        style.spacing = +(style.size * ratio).toFixed(2);\n        if (style.size < 2.2) break;\n      }\n    } catch (eF) {}\n    return style;\n  }\n\n  function mimosaClampNameInside(el, shape, y) {\n    if (!el || typeof el.getComputedTextLength !== 'function') return;\n    const avail = mimosaRowWidthUnits(shape, y, shape === 'drop' ? 3.2 : 5.5);\n    if (!(avail > 0)) return;\n    const apply = function () {\n      el.removeAttribute('textLength');\n      el.removeAttribute('lengthAdjust');\n      let len = 0;\n      try { len = el.getComputedTextLength(); } catch (eLen) { return; }\n      if (!(len > 0)) return;\n      if (len <= avail) return;\n      el.setAttribute('textLength', avail.toFixed(2));\n      el.setAttribute('lengthAdjust', 'spacingAndGlyphs');\n    };\n    apply();\n    requestAnimationFrame(apply);\n  }\n\n  // BOTH rows share one size \u2014 fitting them separately gave the two names\n  // different type sizes on the same pendant (\"\u4E0A\u4E0B\u6392\u540D\u5B57\u5B57\u4F53\u5927\u5C0F\u4E0D\u4E00\u6837\").\n  // The tighter row wins.\n  function mimosaFittedNamePair(shape, role, n1, n2) {\n    const L = mimosaBackLayout(shape, role);\n    const a = mimosaFitNameStyle(n1, shape, L.name1Y, L.nameSize, L.nameSpacing);\n    const b = mimosaFitNameStyle(n2, shape, L.name2Y, L.nameSize, L.nameSpacing);\n    return (a.size <= b.size) ? a : b;\n  }\n\n  // Longitude is the wider line (E113.2644\u00B0). Both rows share that size so\n  // the pair matches, and so a drop's narrow row cannot push the text out.\n  function mimosaFitCoordStyle(text, shape, y, baseSize, baseSpacing) {\n    const style = { size: baseSize, spacing: baseSpacing };\n    try {\n      if (!text) return style;\n      if (shape === 'drop') return mimosaFitRunInsideDrop(text, 'plusJakartaSansBold', y, style, 2.6, 2.6);\n      const avail = mimosaRowWidthUnits(shape, y, shape === 'drop' ? 2.3 : 3.2);\n      if (!(avail > 0)) return style;\n      const ratio = baseSize > 0 ? (baseSpacing / baseSize) : 0;\n      for (let i = 0; i < 12; i++) {\n        const markup = mimosaTextRunToPaths(text, 'plusJakartaSansBold', style.size, 50, y, style.spacing);\n        const subs = mimosaExtractSubpathsFromSvg('<svg xmlns=\"http://www.w3.org/2000/svg\">' + markup + '</svg>');\n        if (!subs.length) return style;\n        let lo = Infinity, hi = -Infinity;\n        subs.forEach(function (sp) { sp.points.forEach(function (pt) { if (pt.x < lo) lo = pt.x; if (pt.x > hi) hi = pt.x; }); });\n        const w = hi - lo;\n        if (w <= avail || !(w > 0)) return style;\n        const shrink = Math.max(0.82, avail / w);\n        style.size = +(style.size * shrink).toFixed(2);\n        style.spacing = +(style.size * ratio).toFixed(2);\n        if (style.size < 2.6) return style;\n      }\n    } catch (eC) {}\n    return style;\n  }\n\n  function mimosaFittedCoordPair(shape, role, latLabel, lngLabel) {\n    const L = mimosaBackLayout(shape, role);\n    const a = mimosaFitCoordStyle(latLabel, shape, L.latY, L.coordSize, L.coordSpacing);\n    const b = mimosaFitCoordStyle(lngLabel, shape, L.lngY, L.coordSize, L.coordSpacing);\n    return (a.size <= b.size) ? a : b;\n  }\n\n  function mimosaApplyFittedCoords(sfx, shape, role, latLabel, lngLabel) {\n    const L = mimosaBackLayout(shape, role);\n    const fit = mimosaFittedCoordPair(shape, role, latLabel, lngLabel);\n    const anchorX = (50 + fit.spacing / 2).toFixed(2);\n    [[L.latY, 'mimosa-back-coord-lat' + sfx], [L.lngY, 'mimosa-back-coord-lng' + sfx]].forEach(function (row) {\n      const el = document.getElementById(row[1]);\n      if (!el) return;\n      el.setAttribute('y', row[0]);\n      el.setAttribute('x', anchorX);\n      el.setAttribute('font-size', fit.size);\n      el.setAttribute('letter-spacing', fit.spacing);\n    });\n  }\n\n  function mimosaApplyFittedNames(sfx, shape, role, n1, n2) {\n    const L = mimosaBackLayout(shape, role);\n    if (!L) return;\n    const fit = mimosaFittedNamePair(shape, role, n1, n2);\n    [[L.name1Y, 'mimosa-back-name-1' + sfx, n1], [L.name2Y, 'mimosa-back-name-2' + sfx, n2]].forEach(function (row) {\n      const el = document.getElementById(row[1]);\n      if (!el) return;\n      el.setAttribute('font-size', fit.size);\n      el.setAttribute('letter-spacing', fit.spacing);\n      // SVG letter-spacing is added AFTER the last glyph too, so a\n      // text-anchor=\"middle\" run is pushed left by half of it \u2014 which is what\n      // pushed a long name off the left edge. Nudge the anchor back.\n      el.setAttribute('x', (50 + fit.spacing / 2).toFixed(2));\n      // The drop fit already checks every glyph point against the outline;\n      // the baseline-chord clamp would only squash the letters together.\n      if (shape !== 'drop') mimosaClampNameInside(el, shape, row[0]);\n      else { el.removeAttribute('textLength'); el.removeAttribute('lengthAdjust'); }\n    });\n  }\n\n  function mimosaRevealFactoryToolsIfRequested() {\n    try {\n      const show = /[?&](factory|dxf)(=1)?\\b/i.test(location.search);\n      document.querySelectorAll('.mimosa-factory-tools').forEach(function (el) {\n        if (!show) {\n          el.setAttribute('hidden', '');\n          el.style.setProperty('display', 'none', 'important');\n          return;\n        }\n        el.removeAttribute('hidden');\n        el.style.setProperty('display', 'block', 'important');\n      });\n    } catch (eF) {}\n  }\n\n  function mimosaUpdateBackPreview() {\n    try {\n      const plateNames = mimosaPlateNameRows();\n      const n1 = plateNames.n1;\n      const n2 = plateNames.n2;\n      const pin = mimosaReadPinLatLng();\n      const pair = mimosaCoordPairFromLatLng(pin.lat, pin.lng);\n      const ringField = document.getElementById('mimosa-hidden-coord-ring');\n      if (ringField) ringField.value = pair.text;\n\n      mimosaSyncBackShape();\n\n      mimosaSetTextContent(document.getElementById('mimosa-back-coord-lat'), pair.latLabel);\n      mimosaSetTextContent(document.getElementById('mimosa-back-coord-lng'), pair.lngLabel);\n      mimosaSetTextContent(document.getElementById('mimosa-back-name-1'), n1);\n      mimosaSetTextContent(document.getElementById('mimosa-back-name-2'), n2);\n      const patternEl = document.getElementById('mimosa-back-pattern');\n      if (patternEl) patternEl.innerHTML = mimosaPatternSvgMarkup(currentBackPattern);\n\n      mimosaSetTextContent(document.getElementById('mimosa-back-coord-lat-his'), pair.latLabel);\n      mimosaSetTextContent(document.getElementById('mimosa-back-coord-lng-his'), pair.lngLabel);\n      mimosaSetTextContent(document.getElementById('mimosa-back-name-1-his'), n1);\n      mimosaSetTextContent(document.getElementById('mimosa-back-name-2-his'), n2);\n      const patternHis = document.getElementById('mimosa-back-pattern-his');\n      if (patternHis) patternHis.innerHTML = mimosaPatternSvgMarkup(currentBackPattern);\n\n      const metalStop0 = currentMetal === 'silver' ? '#F4F6F7' : '#F0DC9A';\n      const metalStop1 = currentMetal === 'silver' ? '#C9D0D6' : '#D2B056';\n      const metalStop2 = currentMetal === 'silver' ? '#AEB6BD' : '#B8923C';\n      const stroke = currentMetal === 'silver' ? '#C8D0D8' : '#C8A84B';\n      ['mimosa-back-metal', 'mimosa-back-metal-his'].forEach(function (id) {\n        const grad = document.getElementById(id);\n        if (!grad) return;\n        const stops = grad.querySelectorAll('stop');\n        if (stops[0]) stops[0].setAttribute('stop-color', metalStop0);\n        if (stops[1]) stops[1].setAttribute('stop-color', metalStop1);\n        if (stops[2]) stops[2].setAttribute('stop-color', metalStop2);\n      });\n      const body = document.getElementById('mimosa-back-body');\n      const bodyHis = document.getElementById('mimosa-back-body-his');\n      if (body) body.setAttribute('stroke', stroke);\n      if (bodyHis) bodyHis.setAttribute('stroke', stroke);\n      // LAST: mimosaSyncBackLayout (called earlier in this pass) writes the\n      // table's own font-size back onto the name rows, so the fitted size has\n      // to be applied after it or a long name stays at full size and runs off\n      // the blank.\n      mimosaApplyFittedNames('', mimosaHersShape(), 'hers', n1, n2);\n      mimosaApplyFittedNames('-his', 'shield', 'his', n1, n2);\n      mimosaApplyFittedCoords('', mimosaHersShape(), 'hers', pair.latLabel, pair.lngLabel);\n      mimosaApplyFittedCoords('-his', 'shield', 'his', pair.latLabel, pair.lngLabel);\n      if (backplateOn) mimosaSyncSetShapeIcons();\n    } catch (err) {\n      console.warn('mimosaUpdateBackPreview', err);\n    }\n  }\n\n  function mimosaSelectPattern(pattern, btn) {\n    // mouth \u2192 kiss (legacy)\n    currentBackPattern = pattern === 'mouth' ? 'kiss' : (pattern || 'none');\n    const labels = { none: 'None', house: 'House', kiss: 'Kiss', mouth: 'Kiss', heart: 'Heart' };\n    const field = document.getElementById('mimosa-hidden-pattern');\n    if (field) field.value = labels[currentBackPattern] || 'None';\n    document.querySelectorAll('.mimosa-pattern-card').forEach(function (card) {\n      const key = card.getAttribute('data-pattern');\n      card.classList.toggle('active', key === currentBackPattern || (currentBackPattern === 'kiss' && key === 'mouth'));\n    });\n    if (btn) btn.classList.add('active');\n    mimosaUpdateBackPreview();\n    try { mimosaScheduleFactoryFiles(); } catch (eSched) {}\n  }\n\n  const ICON_EYE = `<svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>`;\n  const ICON_EYE_SLASH = `<svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>`;\n  let currentShape = 'heart';\n  // Women's pendant. The shield card is his piece, and must not replace this.\n  let currentHersShape = 'heart';\n\n  function mimosaHersShape() {\n    if (currentHersShape && currentHersShape !== 'shield') return currentHersShape;\n    if (currentShape && currentShape !== 'shield') return currentShape;\n    return 'heart';\n  }\n\n  function mimosaShapeOrderLabel() {\n    const labels = { heart: 'Heart', circle: 'Circle', drop: 'Small Drop', shield: 'Shield' };\n    if (currentSet === 'pair') return (labels[mimosaHersShape()] || 'Heart') + ' + Shield';\n    return labels[currentShape] || 'Heart';\n  }\n  let mapBefore = null;\n  let mapAfter = null;\n  let mapHis = null;\n  let diamondMarkerBefore = null;\n  let diamondMarkerAfter = null;\n  let diamondMarkerHis = null;\n  let currentSliderPercent = 50;\n  let isDraggingSlider = false;\n\n  let currentViewMode = 'map';\n\n  function mimosaSyncPairJewelryVisibility() {\n    const isPair = currentSet === 'pair';\n    const stage = document.getElementById('mimosa-stage');\n    const hisPiece = document.getElementById('mimosa-jewelry-his');\n    const backHis = document.getElementById('mimosa-back-his');\n    const backRow = document.getElementById('mimosa-back-preview-row');\n    const hisTab = document.getElementById('btn-his-view');\n    const jewelryLabel = document.getElementById('tab-label-jewelry');\n    const switcher = document.getElementById('mimosa-view-switcher');\n\n    if (stage) stage.classList.toggle('is-pair-set', isPair);\n    if (backHis) {\n      if (isPair) backHis.removeAttribute('hidden');\n      else backHis.setAttribute('hidden', '');\n    }\n    if (backRow) backRow.classList.toggle('is-pair', isPair);\n    if (hisTab) {\n      if (isPair) hisTab.removeAttribute('hidden');\n      else hisTab.setAttribute('hidden', '');\n    }\n    if (jewelryLabel) jewelryLabel.textContent = 'Her Necklace';\n    if (switcher) switcher.classList.toggle('is-pair-tabs', isPair);\n\n    // His piece stays in DOM for map init, but only shows in His View\n    if (hisPiece && !isPair) {\n      hisPiece.setAttribute('hidden', '');\n      hisPiece.classList.remove('is-active');\n      if (currentViewMode === 'his') mimosaSetViewMode('jewelry');\n    } else if (hisPiece && isPair) {\n      hisPiece.removeAttribute('hidden');\n    }\n\n    if (isPair && mapHis) {\n      requestAnimationFrame(function () {\n        try { mapHis.resize(); } catch (e) {}\n        if (mapAfter) {\n          mapHis.jumpTo({\n            center: mapAfter.getCenter(),\n            zoom: mapAfter.getZoom(),\n            bearing: 0,\n            pitch: 0\n          });\n        }\n      });\n    }\n  }\n\n  function mimosaShowJewelryPiece(which) {\n    const hers = document.getElementById('mimosa-jewelry-hers');\n    const his = document.getElementById('mimosa-jewelry-his');\n    if (hers) hers.classList.toggle('is-active', which === 'hers');\n    if (his) {\n      // Pair mode keeps the node in the DOM without [hidden]; still clear it\n      // so factory export can size mapHis (display:none \u2192 0\u00D70 canvas \u2192 empty DXF).\n      if (which === 'his' && currentSet === 'pair') his.removeAttribute('hidden');\n      his.classList.toggle('is-active', which === 'his');\n    }\n  }\n\n  function mimosaWatchStageSize() {\n    const stage = document.getElementById('mimosa-stage');\n    const fit = function () {\n      [mapBefore, mapAfter, mapHis].forEach(function (m) {\n        if (!m) return;\n        try { m.resize(); } catch (e) {}\n      });\n    };\n    if (!stage || typeof ResizeObserver === 'undefined') {\n      fit();\n      return;\n    }\n    let frame = 0;\n    const observer = new ResizeObserver(function () {\n      if (frame) cancelAnimationFrame(frame);\n      frame = requestAnimationFrame(function () {\n        frame = 0;\n        fit();\n      });\n    });\n    observer.observe(stage);\n    fit();\n  }\n\n  function initMimosaMap() {\n    mimosaRevealFactoryToolsIfRequested();\n    if (typeof mapboxgl === 'undefined') {\n      setTimeout(initMimosaMap, 200);\n      return;\n    }\n\n    mapboxgl.accessToken = MAPBOX_TOKEN;\n\n    const initialLat = 25.7771;\n    const initialLng = -80.2002;\n\n    // 1. Initialize Map Before (Map View / Light Style) \u2014 flat 2D only\n    mapBefore = new mapboxgl.Map({\n      container: 'mimosa-map-before',\n      style: TALISA_MAP_STYLE_LIGHT,\n      center: [initialLng, initialLat],\n      zoom: mapZoomLevel,\n      pitch: 0,\n      bearing: 0,\n      maxPitch: 0,\n      dragRotate: false,\n      pitchWithRotate: false,\n      touchPitch: false,\n      attributionControl: false\n    });\n\n    // 2. Jewelry View \u2014 hers map + optional his shield map\n    mapAfter = new mapboxgl.Map({\n      container: 'mimosa-map-after',\n      style: TALISA_MAP_STYLE_LIGHT,\n      center: [initialLng, initialLat],\n      zoom: mapZoomLevel,\n      pitch: 0,\n      bearing: 0,\n      maxPitch: 0,\n      dragRotate: false,\n      pitchWithRotate: false,\n      touchPitch: false,\n      attributionControl: false,\n      preserveDrawingBuffer: true\n    });\n\n    mapHis = new mapboxgl.Map({\n      container: 'mimosa-map-after-his',\n      style: TALISA_MAP_STYLE_LIGHT,\n      center: [initialLng, initialLat],\n      zoom: mapZoomLevel,\n      pitch: 0,\n      bearing: 0,\n      maxPitch: 0,\n      interactive: false,\n      attributionControl: false,\n      preserveDrawingBuffer: true\n    });\n\n    // Keep camera strictly top-down (no 3D tilt / rotate)\n    [mapBefore, mapAfter, mapHis].forEach(function (m) {\n      if (!m) return;\n      if (m.dragRotate) m.dragRotate.disable();\n      if (m.touchZoomRotate) m.touchZoomRotate.disableRotation();\n      if (m.touchPitch) m.touchPitch.disable();\n      m.on('pitch', function () { if (m.getPitch() !== 0) m.setPitch(0); });\n      m.on('rotate', function () { if (m.getBearing() !== 0) m.setBearing(0); });\n    });\n\n    // Jewelry View: gold/silver line strokes. Map View keeps original Talisa light style.\n    mimosaPaintJewelryMetal();\n    if (mapAfter) mapAfter.on('idle', mimosaScheduleFrontThumbs);\n    if (mapHis) {\n      mapHis.on('load', function () {\n        try { mapHis.resize(); } catch (eResize) {}\n        mimosaScheduleFrontThumbs();\n      });\n      mapHis.on('idle', mimosaScheduleFrontThumbs);\n    }\n\n    // 3. Synchronize Pan and Zoom Between Maps (never tilt / rotate)\n    function syncMaps(map1, map2) {\n      function moveTo(source, target) {\n        target.jumpTo({\n          center: source.getCenter(),\n          zoom: source.getZoom(),\n          bearing: 0,\n          pitch: 0\n        });\n        if (mapHis && target !== mapHis && source !== mapHis) {\n          mapHis.jumpTo({\n            center: source.getCenter(),\n            zoom: source.getZoom(),\n            bearing: 0,\n            pitch: 0\n          });\n        }\n      }\n\n      let isMap1Moving = false;\n      let isMap2Moving = false;\n\n      map1.on('movestart', () => { isMap1Moving = true; });\n      map1.on('move', () => { if (isMap1Moving && !isMap2Moving) moveTo(map1, map2); });\n      map1.on('moveend', () => { isMap1Moving = false; });\n\n      map2.on('movestart', () => { isMap2Moving = true; });\n      map2.on('move', () => { if (isMap2Moving && !isMap1Moving) moveTo(map2, map1); });\n      map2.on('moveend', () => { isMap2Moving = false; });\n    }\n    syncMaps(mapBefore, mapAfter);\n\n    [mapAfter, mapHis].forEach(function (m) {\n      if (!m) return;\n      // Only on idle \u2014 per-frame 'move' was updating overlays during pan (\"\u592A\u5361\").\n      m.on('idle', function () { mimosaUpdateStoneOverlay(); });\n    });\n\n    // 4. Create Interactive Location Pin Markers on Both Maps\n    function createPinElement(forJewelry) {\n      const el = document.createElement('div');\n      el.className = 'mimosa-interactive-pin-marker';\n      if (forJewelry) {\n        // Marker box = the gem's own box (see mimosaGemBoxPx), so 'center'\n        // anchoring puts the stone on the hole.\n        const mapRef = mapAfter || mapHis;\n        const box = mimosaGemBoxPx(mapRef);\n        el.style.width = box.toFixed(1) + 'px';\n        el.style.height = box.toFixed(1) + 'px';\n      } else {\n        el.style.width = '37px';\n        el.style.height = (37 * (MIMOSA_PIN_TIP_Y / 56)).toFixed(1) + 'px';\n      }\n      el.style.cursor = 'grab';\n      el.style.zIndex = '30';\n      el.innerHTML = mimosaPinSvg(!!forJewelry);\n      return el;\n    }\n\n    diamondMarkerBefore = new mapboxgl.Marker({\n      element: createPinElement(false),\n      draggable: true,\n      anchor: 'bottom'\n    }).setLngLat([initialLng, initialLat]).addTo(mapBefore);\n\n    diamondMarkerAfter = new mapboxgl.Marker({\n      element: createPinElement(true),\n      draggable: true,\n      anchor: 'center'\n    }).setLngLat([initialLng, initialLat]).addTo(mapAfter);\n\n    // His map: non-draggable pin that mirrors the pair location\n    const hisPinEl = createPinElement(true);\n    hisPinEl.style.cursor = 'default';\n    hisPinEl.style.pointerEvents = 'none';\n    diamondMarkerHis = new mapboxgl.Marker({\n      element: hisPinEl,\n      draggable: false,\n      anchor: 'center'\n    }).setLngLat([initialLng, initialLat]).addTo(mapHis);\n\n    function syncMarker(sourceMarker, targetMarker) {\n      sourceMarker.on('drag', () => {\n        const lngLat = sourceMarker.getLngLat();\n        targetMarker.setLngLat(lngLat);\n        if (diamondMarkerHis) diamondMarkerHis.setLngLat(lngLat);\n        document.getElementById('mimosa-hidden-coords').value = `${lngLat.lat.toFixed(4)}, ${lngLat.lng.toFixed(4)}`;\n        // Skip back-preview + etch rebuild mid-drag \u2014 those blocked the main\n        // thread and made \"\u6309\u4E0B\u5730\u56FE\u5C31\u5F88\u5361\". Ghost follows; rebuild on dragend.\n        mimosaSetPinDragging(true);\n        mimosaRebuildEtchedGeometry(700);\n      });\n      sourceMarker.on('dragend', () => {\n        const lngLat = sourceMarker.getLngLat();\n        targetMarker.setLngLat(lngLat);\n        if (diamondMarkerHis) diamondMarkerHis.setLngLat(lngLat);\n        document.getElementById('mimosa-hidden-coords').value = `${lngLat.lat.toFixed(4)}, ${lngLat.lng.toFixed(4)}`;\n        mimosaUpdateMapPreviewLink();\n        mimosaUpdateBackPreview();\n        mimosaUpdateStoneOverlay();\n        mimosaSetPinDragging(false);\n        mimosaRebuildEtchedGeometry(400);\n        mimosaScheduleFactoryFiles();\n      });\n    }\n    syncMarker(diamondMarkerBefore, diamondMarkerAfter);\n    syncMarker(diamondMarkerAfter, diamondMarkerBefore);\n\n    // Map clicks move both pins\n    function handleMapClick(e) {\n      if (diamondMarkerBefore) diamondMarkerBefore.setLngLat(e.lngLat);\n      if (diamondMarkerAfter) diamondMarkerAfter.setLngLat(e.lngLat);\n      if (diamondMarkerHis) diamondMarkerHis.setLngLat(e.lngLat);\n      document.getElementById('mimosa-hidden-coords').value = `${e.lngLat.lat.toFixed(4)}, ${e.lngLat.lng.toFixed(4)}`;\n      mimosaUpdateMapPreviewLink();\n      mimosaUpdateBackPreview();\n      mimosaRebuildEtchedGeometry(280);\n      mimosaScheduleFactoryFiles();\n    }\n    mapBefore.on('click', handleMapClick);\n    mapAfter.on('click', handleMapClick);\n\n    setupAddressSearch();\n    setupComparisonSlider();\n    mimosaSyncPairJewelryVisibility();\n    mimosaWatchStageSize();\n\n    // Ensure the fulfillment link matches the default pin even if the\n    // customer never touches the map before adding to cart.\n    mimosaUpdateMapPreviewLink();\n    [mapBefore, mapAfter, mapHis].forEach(function (m) {\n      if (!m || m._mimosaFactoryMove) return;\n      m._mimosaFactoryMove = true;\n      m.on('moveend', function () {\n        if (isMapTransitioning || mimosaCameraSyncDepth > 0) return;\n        mimosaScheduleFactoryFiles();\n      });\n    });\n    try { mimosaScheduleFactoryFiles(); } catch (eSched) {}\n  }\n\n  function mimosaZoomBy(delta) {\n    const maps = [mapBefore, mapAfter, mapHis].filter(Boolean);\n    if (!maps.length) return;\n    const next = Math.max(3, Math.min(18, (maps[0].getZoom() || mapZoomLevel) + delta));\n    mapZoomLevel = next;\n    const zoomField = document.getElementById('mimosa-hidden-zoom');\n    if (zoomField) zoomField.value = String(Math.round(next * 10) / 10);\n    // Drop the stale closed ribbons before jumpTo so they cannot stack, but\n    // put the live gold roads up in the same turn \u2014 clearing used to leave\n    // only the diamond until the rebuild finished.\n    [mapAfter, mapHis].forEach(function (m) {\n      if (!m) return;\n      try { m._mimosaGen = (m._mimosaGen || 0) + 1; } catch (eG) {}\n      try { m._mimosaZoomToken = (m._mimosaZoomToken || 0) + 1; } catch (eT) {}\n      mimosaShowLiveLattice(m);\n    });\n    // jumpTo (not easeTo): animated zoom stacked 3 maps + long rebuild debounce\n    // and felt frozen with stale thick streets until idle finally ran.\n    maps.forEach(function (m) {\n      try {\n        m.jumpTo({ center: m.getCenter(), zoom: next, pitch: 0, bearing: 0 });\n      } catch (eZ) {}\n    });\n    mimosaUpdateMapPreviewLink();\n    [mapAfter, mapHis].forEach(function (m) {\n      if (m) mimosaShowLiveLattice(m);\n    });\n  }\n\n  function setupComparisonSlider() {\n    const stage = document.getElementById('mimosa-stage');\n    const divider = document.getElementById('mimosa-slider-divider');\n    const handle = document.getElementById('mimosa-slider-handle');\n    const afterLayer = document.getElementById('mimosa-map-after-wrap');\n\n    let rafPending = false;\n    function updateSliderPosition(percent) {\n      currentSliderPercent = Math.max(0, Math.min(100, percent));\n      if (!rafPending) {\n        rafPending = true;\n        requestAnimationFrame(() => {\n          if (divider) divider.style.left = currentSliderPercent + '%';\n          if (afterLayer) {\n            afterLayer.style.clipPath = 'inset(0 0 0 ' + currentSliderPercent + '%)';\n            afterLayer.style.webkitClipPath = 'inset(0 0 0 ' + currentSliderPercent + '%)';\n          }\n          rafPending = false;\n        });\n      }\n    }\n\n    function getPercentFromEvent(e) {\n      const rect = stage.getBoundingClientRect();\n      const clientX = (e.touches && e.touches.length > 0) ? e.touches[0].clientX : e.clientX;\n      const x = clientX - rect.left;\n      return (x / rect.width) * 100;\n    }\n\n    function onPointerMove(e) {\n      if (!isDraggingSlider) return;\n      if (e.cancelable) e.preventDefault();\n      const percent = getPercentFromEvent(e);\n      updateSliderPosition(percent);\n    }\n\n    function onPointerUp(e) {\n      if (isDraggingSlider) {\n        isDraggingSlider = false;\n        if (stage) stage.classList.remove('is-dragging');\n        window.removeEventListener('mousemove', onPointerMove);\n        window.removeEventListener('mouseup', onPointerUp);\n        window.removeEventListener('touchmove', onPointerMove);\n        window.removeEventListener('touchend', onPointerUp);\n        window.removeEventListener('touchcancel', onPointerUp);\n      }\n    }\n\n    function startDragging(e) {\n      if (e.cancelable) e.preventDefault();\n      e.stopPropagation();\n      isDraggingSlider = true;\n      if (stage) stage.classList.add('is-dragging');\n      const percent = getPercentFromEvent(e);\n      updateSliderPosition(percent);\n\n      window.addEventListener('mousemove', onPointerMove, { passive: false });\n      window.addEventListener('mouseup', onPointerUp);\n      window.addEventListener('touchmove', onPointerMove, { passive: false });\n      window.addEventListener('touchend', onPointerUp);\n      window.addEventListener('touchcancel', onPointerUp);\n    }\n\n    if (divider) {\n      divider.addEventListener('mousedown', startDragging);\n      divider.addEventListener('touchstart', startDragging, { passive: false });\n    }\n    if (handle) {\n      handle.addEventListener('mousedown', startDragging);\n      handle.addEventListener('touchstart', startDragging, { passive: false });\n    }\n\n    window.mimosaUpdateSliderPosition = updateSliderPosition;\n  }\n\n  function mimosaFlyToPlace(lng, lat, placeName) {\n    if (!isFinite(lng) || !isFinite(lat)) return;\n    const input = document.getElementById('mimosa-map-search-input');\n    const hiddenLoc = document.getElementById('mimosa-hidden-location');\n    const hiddenCoords = document.getElementById('mimosa-hidden-coords');\n    if (placeName) {\n      isLocationConfirmed = true;\n      confirmedLocationName = placeName;\n      confirmedLocationCoords = { lat: lat, lng: lng };\n      if (input) input.value = placeName;\n      if (hiddenLoc) hiddenLoc.value = placeName;\n      mimosaHideAddressError();\n      mimosaRecalculatePrice();\n    }\n    if (hiddenCoords) hiddenCoords.value = lat.toFixed(4) + ', ' + lng.toFixed(4);\n\n    // New place: drop stale DXF + shared road cache, abort in-flight openwork\n    // rebuilds. jumpTo (not 1.2s flyTo) so address text and basemap agree in\n    // one frame \u2014 flyTo used to rebuild the lattice at every mid-flight centre\n    // (\"\u8F93\u5165\u5730\u5740\u5730\u56FE\u4E0D\u5BF9\u00B7\u5730\u56FE\u81EA\u5DF1\u5728\u90A3\u91CC\u53D8\u6765\u53D8\u53BB\u7684\").\n    mimosaFactoryCache = null;\n    mimosaSharedRoads = null;\n    clearTimeout(mimosaFactoryTimer);\n    isMapTransitioning = true;\n    mapTransitionTarget = { lng: lng, lat: lat };\n    [mapBefore, mapAfter, mapHis].forEach(function (m) {\n      if (!m) return;\n      try { m._mimosaGen = (m._mimosaGen || 0) + 1; } catch (eG) {}\n      try { m._mimosaZoomToken = (m._mimosaZoomToken || 0) + 1; } catch (eT) {}\n      if (m._mimosaZoomTimer) {\n        clearTimeout(m._mimosaZoomTimer);\n        m._mimosaZoomTimer = null;\n      }\n    });\n\n    const cam = { center: [lng, lat], zoom: mapZoomLevel, pitch: 0, bearing: 0 };\n    let pendingJumps = 0;\n    let finished = false;\n    const finishJump = function () {\n      pendingJumps -= 1;\n      if (pendingJumps > 0 || finished) return;\n      finished = true;\n      isMapTransitioning = false;\n      // One etched rebuild at the FINAL camera only.\n      [mapAfter, mapHis].forEach(function (m) {\n        if (!m) return;\n        try { mimosaApplyRoadFilter(m, 'etched'); } catch (eEtch) {}\n      });\n      try { mimosaScheduleFactoryFiles(); } catch (eSched) {}\n    };\n    mimosaCameraSyncDepth += 1;\n    [mapBefore, mapAfter, mapHis].forEach(function (m) {\n      if (!m) return;\n      pendingJumps += 1;\n      m.once('moveend', finishJump);\n      try {\n        m.jumpTo(cam);\n      } catch (eJump) {\n        finishJump();\n      }\n    });\n    setTimeout(function () {\n      mimosaCameraSyncDepth = Math.max(0, mimosaCameraSyncDepth - 1);\n    }, 0);\n    if (!pendingJumps) {\n      finished = true;\n      isMapTransitioning = false;\n      [mapAfter, mapHis].forEach(function (m) {\n        if (!m) return;\n        try { mimosaApplyRoadFilter(m, 'etched'); } catch (eEtch) {}\n      });\n      try { mimosaScheduleFactoryFiles(); } catch (eSched) {}\n    } else {\n      setTimeout(function () {\n        if (finished) return;\n        finished = true;\n        isMapTransitioning = false;\n        [mapAfter, mapHis].forEach(function (m) {\n          if (!m) return;\n          try { mimosaApplyRoadFilter(m, 'etched'); } catch (eEtch) {}\n        });\n        try { mimosaScheduleFactoryFiles(); } catch (eSched) {}\n      }, 900);\n    }\n    if (diamondMarkerBefore) diamondMarkerBefore.setLngLat([lng, lat]);\n    if (diamondMarkerAfter) diamondMarkerAfter.setLngLat([lng, lat]);\n    if (diamondMarkerHis) diamondMarkerHis.setLngLat([lng, lat]);\n    try { mimosaUpdateMapPreviewLink(); } catch (eL) {}\n    try { mimosaUpdateBackPreview(); } catch (eB) {}\n  }\n\n  // Curated landmarks dictionary for top worldwide landmarks with known aliasing/geocoding quirks\n  const TOP_LANDMARKS = [\n    {\n      names: ['grand central station', 'grand central terminal', 'grand central'],\n      label: 'Grand Central Terminal, 89 E 42nd St, New York, NY 10017, United States',\n      lng: -73.977253,\n      lat: 40.752694,\n      cityTerms: ['new york', 'nyc', 'manhattan', 'ny']\n    },\n    {\n      names: ['eiffel tower', 'tour eiffel'],\n      label: 'Eiffel Tower (Tour Eiffel), Champ de Mars, 75007 Paris, France',\n      lng: 2.2945006,\n      lat: 48.8582599,\n      cityTerms: ['paris', 'france']\n    },\n    {\n      names: ['times square', 'times sq'],\n      label: 'Times Square, Manhattan, New York, NY 10036, United States',\n      lng: -73.9855,\n      lat: 40.7580,\n      cityTerms: ['new york', 'nyc', 'manhattan', 'ny']\n    },\n    {\n      names: ['statue of liberty'],\n      label: 'Statue of Liberty, New York, NY 10004, United States',\n      lng: -74.0445,\n      lat: 40.6892,\n      cityTerms: ['new york', 'nyc', 'ny']\n    },\n    {\n      names: ['empire state building'],\n      label: 'Empire State Building, 20 W 34th St, New York, NY 10001, United States',\n      lng: -73.9857,\n      lat: 40.7484,\n      cityTerms: ['new york', 'nyc', 'manhattan', 'ny']\n    },\n    {\n      names: ['one world trade center', 'world trade center', 'freedom tower'],\n      label: 'One World Trade Center, 285 Fulton St, New York, NY 10007, United States',\n      lng: -74.0134,\n      lat: 40.7127,\n      cityTerms: ['new york', 'nyc', 'manhattan', 'ny']\n    },\n    {\n      names: ['brooklyn bridge'],\n      label: 'Brooklyn Bridge, New York, NY 10038, United States',\n      lng: -73.9969,\n      lat: 40.7061,\n      cityTerms: ['new york', 'nyc', 'brooklyn', 'ny']\n    },\n    {\n      names: ['central park'],\n      label: 'Central Park, Manhattan, New York, NY, United States',\n      lng: -73.9665,\n      lat: 40.7812,\n      cityTerms: ['new york', 'nyc', 'manhattan', 'ny']\n    },\n    {\n      names: ['colosseum', 'coliseum'],\n      label: 'Colosseum, Piazza del Colosseo, 00184 Rome, Italy',\n      lng: 12.4924,\n      lat: 41.8902,\n      cityTerms: ['rome', 'roma', 'italy', 'italia']\n    },\n    {\n      names: ['louvre', 'louvre museum', 'musee du louvre'],\n      label: 'Louvre Museum (Mus\u00E9e du Louvre), 75001 Paris, France',\n      lng: 2.3376,\n      lat: 48.8606,\n      cityTerms: ['paris', 'france']\n    },\n    {\n      names: ['sydney opera house'],\n      label: 'Sydney Opera House, Bennelong Point, Sydney NSW 2000, Australia',\n      lng: 151.2153,\n      lat: -33.8568,\n      cityTerms: ['sydney', 'australia', 'nsw']\n    },\n    {\n      names: ['golden gate bridge'],\n      label: 'Golden Gate Bridge, San Francisco, CA 94129, United States',\n      lng: -122.4783,\n      lat: 37.8199,\n      cityTerms: ['san francisco', 'sf', 'california', 'ca']\n    }\n  ];\n\n  function mimosaMatchLandmark(rawQuery) {\n    const q = rawQuery.trim().toLowerCase();\n    const parts = q.split(',').map(function (s) { return s.trim(); }).filter(Boolean);\n    const mainPart = parts[0];\n    const geoParts = parts.slice(1);\n\n    for (let i = 0; i < TOP_LANDMARKS.length; i++) {\n      const lm = TOP_LANDMARKS[i];\n      const nameMatch = lm.names.some(function (name) {\n        return mainPart === name || q === name || mainPart.startsWith(name) || q.startsWith(name);\n      });\n      if (nameMatch) {\n        if (geoParts.length > 0) {\n          const matchesCity = geoParts.some(function (gp) {\n            return lm.cityTerms.some(function (ct) { return gp.indexOf(ct) !== -1; });\n          });\n          if (!matchesCity) continue;\n        }\n        return {\n          label: lm.label,\n          lng: lm.lng,\n          lat: lm.lat,\n          isLandmark: true\n        };\n      }\n    }\n    return null;\n  }\n\n  function mimosaGetExpandedQueries(rawQuery) {\n    const q = rawQuery.trim();\n    const list = [q];\n    if (/\\bgrand\\s+central\\s+station\\b/i.test(q)) {\n      const t = q.replace(/\\bgrand\\s+central\\s+station\\b/i, 'Grand Central Terminal');\n      if (list.indexOf(t) === -1) list.push(t);\n      if (!/,|new york|nyc/i.test(q)) {\n        list.push('Grand Central Terminal, New York');\n      }\n    }\n    if (/\\beiffel\\s+tower\\b/i.test(q)) {\n      const t = q.replace(/\\beiffel\\s+tower\\b/i, 'Tour Eiffel');\n      if (list.indexOf(t) === -1) list.push(t);\n      if (!/,|paris|france/i.test(q)) {\n        list.push('Tour Eiffel, Paris');\n      }\n    }\n    if (q.indexOf('\u5E7F\u5DDE') !== -1 && /\u804C\u4E1A|\u5927\u5B66|\u5B66\u9662|\u5B66\u6821|\u8F7B\u5DE5/.test(q)) {\n      list.push(q.split('\u5E7F\u5DDE').join('\u5E7F\u4E1C'));\n    }\n    return list;\n  }\n\n  function mimosaFetchMapboxPlaces(query) {\n    const mapboxUrl = 'https://api.mapbox.com/geocoding/v5/mapbox.places/'\n      + encodeURIComponent(query)\n      + '.json?access_token=' + MAPBOX_TOKEN + '&limit=5&language=en';\n    return fetch(mapboxUrl)\n      .then(function (res) { return res.json(); })\n      .then(function (data) {\n        return ((data && data.features) || []).map(function (f) {\n          return {\n            label: f.place_name,\n            name: f.text || '',\n            lng: f.center[0],\n            lat: f.center[1],\n            relevance: f.relevance || 0.5,\n            types: f.place_type || []\n          };\n        });\n      })\n      .catch(function () { return []; });\n  }\n\n  function mimosaFetchPhotonPlaces(query) {\n    return fetch('https://photon.komoot.io/api/?limit=6&q=' + encodeURIComponent(query))\n      .then(function (res) { return res.json(); })\n      .then(function (data) {\n        return ((data && data.features) || []).map(function (item) {\n          const props = item.properties || {};\n          const coords = (item.geometry && item.geometry.coordinates) || [];\n          const bits = [props.name, props.street, props.city || props.locality, props.state, props.country].filter(Boolean);\n          const label = bits.filter(function (bit, index) { return bits.indexOf(bit) === index; }).join(', ');\n          return {\n            label: label,\n            name: props.name || '',\n            lng: coords[0],\n            lat: coords[1],\n            relevance: 0.85,\n            types: [props.osm_value || '']\n          };\n        }).filter(function (item) {\n          return item.label && isFinite(item.lng) && isFinite(item.lat);\n        });\n      })\n      .catch(function () { return []; });\n  }\n\n  function mimosaSearchPlaces(rawQuery) {\n    const query = (rawQuery || '').trim();\n    if (query.length < 2) return Promise.resolve([]);\n\n    const results = [];\n    const seenLabels = {};\n\n    // 1. Instant Landmark Match for recognized famous landmark aliases\n    const landmarkHit = mimosaMatchLandmark(query);\n    if (landmarkHit) {\n      results.push(landmarkHit);\n      seenLabels[landmarkHit.label.toLowerCase()] = 1;\n    }\n\n    // 2. Query expansion\n    const expansions = mimosaGetExpandedQueries(query);\n    const isChinese = /[\\u4e00-\\u9fa5]/.test(query);\n\n    return Promise.all(expansions.map(mimosaFetchMapboxPlaces)).then(function (mapboxLists) {\n      let merged = [];\n      mapboxLists.forEach(function (list) { merged = merged.concat(list); });\n\n      const parts = query.split(',').map(function (s) { return s.trim().toLowerCase(); }).filter(Boolean);\n      const geoTerms = parts.length > 1 ? parts.slice(1) : [];\n\n      merged.forEach(function (item) {\n        let score = item.relevance || 0.5;\n        const lowerLabel = (item.label || '').toLowerCase();\n        const lowerName = (item.name || '').toLowerCase();\n\n        // Chinese specific validation to filter unrelated fuzzy character hits\n        if (isChinese) {\n          if (lowerLabel.indexOf(query.toLowerCase()) === -1 && lowerName.indexOf(query.toLowerCase()) === -1) {\n            score -= 2.0;\n          }\n        }\n\n        // Geographic Context Scoring: boost requested city, penalize other states/countries\n        if (geoTerms.length > 0) {\n          const matchesGeo = geoTerms.some(function (g) {\n            const cleanG = g.replace(/\\bcity\\b/gi, '').trim();\n            return lowerLabel.indexOf(cleanG) !== -1 || lowerLabel.indexOf(g) !== -1;\n          });\n          if (matchesGeo) {\n            score += 3.0;\n          } else {\n            score -= 3.0;\n          }\n        }\n\n        // Street suffix penalty when user typed a landmark query\n        if (landmarkHit && /\\b(lane|dr|drive|ave|avenue|rd|road|way|ct|court)\\b/i.test(lowerName)) {\n          score -= 2.5;\n        }\n\n        item.score = score;\n      });\n\n      merged.sort(function (a, b) { return b.score - a.score; });\n\n      merged.forEach(function (item) {\n        const key = item.label.toLowerCase();\n        if (!seenLabels[key] && item.score > 0) {\n          seenLabels[key] = 1;\n          results.push({\n            label: item.label,\n            lng: item.lng,\n            lat: item.lat\n          });\n        }\n      });\n\n      // If no valid results yet, attempt Photon fallback\n      if (results.length === 0) {\n        return Promise.all(expansions.map(mimosaFetchPhotonPlaces)).then(function (photonLists) {\n          let photonMerged = [];\n          photonLists.forEach(function (list) { photonMerged = photonMerged.concat(list); });\n          photonMerged.forEach(function (item) {\n            const key = item.label.toLowerCase();\n            if (!seenLabels[key]) {\n              seenLabels[key] = 1;\n              results.push({\n                label: item.label,\n                lng: item.lng,\n                lat: item.lat\n              });\n            }\n          });\n          return results.slice(0, 5);\n        });\n      }\n\n      return results.slice(0, 5);\n    });\n  }\n\n  function mimosaRenderSearchResults(resultsBox, places) {\n    resultsBox.innerHTML = '';\n    if (!places.length) {\n      resultsBox.classList.add('hidden');\n      return;\n    }\n    places.forEach(function (item) {\n      const div = document.createElement('div');\n      div.className = 'mimosa-search-item';\n      div.innerText = item.label;\n      div.onclick = function () {\n        resultsBox.classList.add('hidden');\n        mimosaFlyToPlace(item.lng, item.lat, item.label);\n      };\n      resultsBox.appendChild(div);\n    });\n    resultsBox.classList.remove('hidden');\n  }\n\n  function setupAddressSearch() {\n    const input = document.getElementById('mimosa-map-search-input');\n    const resultsBox = document.getElementById('mimosa-search-results');\n    if (!input || !resultsBox) return;\n    let debounceTimer;\n    let searchGen = 0;\n\n    input.addEventListener('input', function() {\n      clearTimeout(debounceTimer);\n      const query = this.value.trim();\n\n      // Typing an address alone must NOT count as selecting a location.\n      // If customer edits address after selecting a valid location, invalidate it.\n      if (!confirmedLocationName || query !== confirmedLocationName) {\n        isLocationConfirmed = false;\n        confirmedLocationName = '';\n        confirmedLocationCoords = null;\n        mimosaFactoryCache = null;\n        clearTimeout(mimosaFactoryTimer);\n        const hiddenLoc = document.getElementById('mimosa-hidden-location');\n        if (hiddenLoc) hiddenLoc.value = '';\n        const hiddenCoords = document.getElementById('mimosa-hidden-coords');\n        if (hiddenCoords) hiddenCoords.value = '';\n        const ringField = document.getElementById('mimosa-hidden-coord-ring');\n        if (ringField) ringField.value = '';\n        const linkField = document.getElementById('mimosa-hidden-maplink');\n        if (linkField) linkField.value = '';\n      }\n\n      mimosaHideAddressError();\n      mimosaRecalculatePrice();\n\n      if (query.length < 2) {\n        searchGen += 1;\n        resultsBox.classList.add('hidden');\n        return;\n      }\n\n      debounceTimer = setTimeout(function () {\n        const gen = ++searchGen;\n        mimosaSearchPlaces(query).then(function (places) {\n          if (gen !== searchGen || input.value.trim() !== query) return;\n          mimosaRenderSearchResults(resultsBox, places);\n        });\n      }, 300);\n    });\n\n    input.addEventListener('focus', function () {\n      if (!isLocationConfirmed && resultsBox.children.length > 0) {\n        resultsBox.classList.remove('hidden');\n      }\n    });\n\n    input.addEventListener('keydown', function (e) {\n      if (e.key !== 'Enter') return;\n      e.preventDefault();\n      const first = resultsBox.querySelector('.mimosa-search-item');\n      if (first) {\n        first.click();\n        return;\n      }\n      // Results not loaded yet \u2014 search once and take the top hit.\n      const query = input.value.trim();\n      if (query.length < 2) return;\n      mimosaSearchPlaces(query).then(function (places) {\n        if (!places || !places.length) return;\n        if (input.value.trim() !== query) return;\n        mimosaFlyToPlace(places[0].lng, places[0].lat, places[0].label);\n        resultsBox.classList.add('hidden');\n      });\n    });\n\n    document.addEventListener('click', function(e) {\n      if (!input.contains(e.target) && !resultsBox.contains(e.target)) {\n        resultsBox.classList.add('hidden');\n      }\n    });\n  }\n\n  function mimosaSetViewMode(mode) {\n    if (mode === 'his' && currentSet !== 'pair') mode = 'jewelry';\n    currentViewMode = mode;\n\n    const btnMap = document.getElementById('btn-map-view');\n    const btnJewelry = document.getElementById('btn-jewelry-view');\n    const btnHis = document.getElementById('btn-his-view');\n    const iconMap = document.getElementById('tab-icon-map');\n    const iconJewelry = document.getElementById('tab-icon-jewelry');\n    const iconHis = document.getElementById('tab-icon-his');\n\n    [btnMap, btnJewelry, btnHis].forEach(function (btn) {\n      if (btn) btn.classList.remove('active');\n    });\n\n    if (mode === 'his') {\n      if (btnHis) btnHis.classList.add('active');\n      if (iconHis) iconHis.innerHTML = ICON_EYE;\n      if (iconMap) iconMap.innerHTML = ICON_EYE_SLASH;\n      if (iconJewelry) iconJewelry.innerHTML = ICON_EYE_SLASH;\n      mimosaShowJewelryPiece('his');\n      mimosaSetMapOverlayShape('shield');\n      animateSliderTo(0);\n      requestAnimationFrame(function () {\n        if (mapHis) {\n          try {\n            mapHis.resize();\n            const ref = mapBefore || mapAfter;\n            if (ref) {\n              mapHis.jumpTo({\n                center: ref.getCenter(),\n                zoom: ref.getZoom(),\n                bearing: 0,\n                pitch: 0\n              });\n            }\n          } catch (e) {}\n          if (diamondMarkerBefore && diamondMarkerHis) {\n            diamondMarkerHis.setLngLat(diamondMarkerBefore.getLngLat());\n          }\n          mimosaRebuildIfPending(mapHis);\n        }\n      });\n    } else if (mode === 'jewelry') {\n      if (btnJewelry) btnJewelry.classList.add('active');\n      if (iconJewelry) iconJewelry.innerHTML = ICON_EYE;\n      if (iconMap) iconMap.innerHTML = ICON_EYE_SLASH;\n      if (iconHis) iconHis.innerHTML = ICON_EYE_SLASH;\n      mimosaShowJewelryPiece('hers');\n      mimosaSetMapOverlayShape(mimosaMapPieceShape(mapAfter) || 'heart');\n      animateSliderTo(0);\n      requestAnimationFrame(function () {\n        if (mapAfter) { try { mapAfter.resize(); } catch (e) {} mimosaRebuildIfPending(mapAfter); }\n      });\n    } else {\n      if (btnMap) btnMap.classList.add('active');\n      if (iconMap) iconMap.innerHTML = ICON_EYE;\n      if (iconJewelry) iconJewelry.innerHTML = ICON_EYE_SLASH;\n      if (iconHis) iconHis.innerHTML = ICON_EYE_SLASH;\n      mimosaShowMapPiece();\n      animateSliderTo(100);\n    }\n  }\n\n  function animateSliderTo(targetPercent) {\n    const startPercent = currentSliderPercent;\n    const duration = 400;\n    const startTime = performance.now();\n\n    function step(currentTime) {\n      const elapsed = currentTime - startTime;\n      const progress = Math.min(elapsed / duration, 1);\n      const ease = 0.5 - Math.cos(progress * Math.PI) / 2; // Smooth easeInOut\n      const current = startPercent + (targetPercent - startPercent) * ease;\n      if (window.mimosaUpdateSliderPosition) {\n        window.mimosaUpdateSliderPosition(current);\n      }\n      if (progress < 1) {\n        requestAnimationFrame(step);\n      }\n    }\n    requestAnimationFrame(step);\n  }\n\n  if (document.readyState === 'loading') {\n    document.addEventListener('DOMContentLoaded', mimosaSyncShapeOutlines);\n  } else {\n    mimosaSyncShapeOutlines();\n  }\n\n  // The Map View outline shows the piece being designed. In a pair that can\n  // be His shield while Hers stays a heart or drop, so it is set on its own\n  // (\"\u70B9\u51FB\u76FE\u724C\u56FE\u6848\u7684\u65F6\u5019\u00B7\u5730\u56FE\u4E0A\u9762\u7684\u56FE\u6848\u8FD8\u662F\u5FC3\u6216\u8005\u6C34\u6EF4\").\n  let mimosaMapPiece = 'hers';\n\n  function mimosaSetMapOverlayShape(shape) {\n    mimosaMapPiece = (shape === 'shield' && currentSet === 'pair') ? 'his' : 'hers';\n    const svgPath = document.getElementById('svg-shape-path');\n    const whiteMask = document.getElementById('svg-white-mask');\n    if (svgPath) svgPath.setAttribute('d', mimosaPathDToPolyline(mimosaPathForShape(shape)));\n    if (whiteMask) {\n      whiteMask.setAttribute('d', 'M 0,0 L 100,0 L 100,100 L 0,100 Z ' + mimosaPathDToPolyline(mimosaCutPathWithBail(shape)));\n      whiteMask.setAttribute('fill-rule', 'evenodd');\n    }\n  }\n\n  // Map View's slider reveals the jewelry layer underneath; it must be the\n  // piece whose outline is on the map, His shield included.\n  function mimosaShowMapPiece() {\n    const which = (mimosaMapPiece === 'his' && currentSet === 'pair') ? 'his' : 'hers';\n    mimosaShowJewelryPiece(which);\n    const m = which === 'his' ? mapHis : mapAfter;\n    requestAnimationFrame(function () {\n      if (m) {\n        try {\n          m.resize();\n          if (which === 'his' && mapBefore) {\n            m.jumpTo({\n              center: mapBefore.getCenter(),\n              zoom: mapBefore.getZoom(),\n              bearing: 0,\n              pitch: 0\n            });\n          }\n        } catch (e) {}\n        if (which === 'his' && diamondMarkerBefore && diamondMarkerHis) {\n          diamondMarkerHis.setLngLat(diamondMarkerBefore.getLngLat());\n        }\n        mimosaRebuildIfPending(m);\n      }\n    });\n  }\n\n  function mimosaChangeShape(shape) {\n    const isSameShape = (shape === currentShape);\n    const targetMode = (shape === 'shield' && currentSet === 'pair') ? 'his' : 'jewelry';\n    const isSameMode = (currentViewMode === targetMode);\n    if (!isSameShape || !isSameMode) {\n      mimosaBeginShapeSwitch();\n    }\n    if (shape === 'heart' || shape === 'drop' || shape === 'circle') currentHersShape = shape;\n    currentShape = shape;\n    const stage = document.getElementById('mimosa-stage');\n    const svgPathGold = document.getElementById('svg-shape-path-gold');\n    const bailHoleGold = document.getElementById('svg-bail-hole-gold');\n    const bailHoleMap = document.getElementById('svg-bail-hole-map');\n\n    document.querySelectorAll('.mimosa-shape-card').forEach(c => c.classList.remove('active'));\n    if (event && event.currentTarget) {\n      event.currentTarget.classList.add('active');\n    }\n\n    stage.classList.remove('circle-shape', 'drop-shape', 'shield-shape');\n\n    const d = mimosaPathForShape(shape);\n    // Arc-free for evenodd veil / clip reliability (same reason as masks).\n    const dDraw = mimosaPathDToPolyline(d);\n    const bail = mimosaBailSpec(shape);\n\n    const hersShape = mimosaMapPieceShape(mapAfter);\n    if (hersShape === 'circle') stage.classList.add('circle-shape');\n    else if (hersShape === 'drop') stage.classList.add('drop-shape');\n    else if (hersShape === 'shield') stage.classList.add('shield-shape');\n\n    mimosaSetMapOverlayShape(shape);\n    if (currentViewMode === 'map') mimosaShowMapPiece();\n    if (svgPathGold) svgPathGold.setAttribute('d', dDraw);\n    [bailHoleGold, bailHoleMap].forEach(function (el) {\n      if (!el) return;\n      el.setAttribute('cx', bail.cx);\n      el.setAttribute('cy', bail.cy);\n      el.setAttribute('r', bail.r);\n      el.style.display = '';\n    });\n    mimosaSyncBailVisuals(shape);\n\n    // Sync shape to order property + check the matching radio (do NOT leave a\n    // stale first radio as the querySelector match for add-ons).\n    const shapeLabels = { heart: 'Heart', circle: 'Circle', drop: 'Small Drop', shield: 'Shield' };\n    const shapeField = document.getElementById('mimosa-hidden-shape');\n    if (shapeField) shapeField.value = mimosaShapeOrderLabel();\n    const selected = currentSet === 'pair' ? mimosaHersShape() : shape;\n    const selectedLabel = shapeLabels[selected] || 'Heart';\n    document.querySelectorAll('input[name=\"mimosa-shape-choice\"]').forEach(function (r) {\n      r.checked = (r.value === selectedLabel);\n    });\n    document.querySelectorAll('.mimosa-shape-card').forEach(function (c) {\n      const inp = c.querySelector('input[name=\"mimosa-shape-choice\"]');\n      c.classList.toggle('active', !!(inp && inp.checked));\n    });\n    mimosaUpdateChainForShape(shape);\n    mimosaSyncStyleFromChoice();\n    mimosaSyncSetShapeIcons();\n    mimosaScheduleFrontThumbs();\n    mimosaStyleGoldOutline(svgPathGold, shape);\n    mimosaUpdateMapPreviewLink();\n    mimosaUpdateBackPreview();\n    // Refresh 0\u20131 clip/mask paths for the new shape (circle/drop must stay\n    // arc-free polylines or WebKit clips the map to nothing).\n    try { mimosaSyncShapeOutlines(); } catch (eSync) {}\n    // Rebuild metal for the new outline. Do NOT clear here: clearing causes an\n    // immediate blank that lasts until the async rebuild finishes (1\u20135 s on\n    // mobile), making every shape switch feel unresponsive. The CSS clip-mask\n    // updates immediately, so old metal is already cropped to the new shape \u2014\n    // there is no true shape overlap visible to the customer. Newest gen still\n    // wins inside mimosaApplyRoadFilter so any in-flight build is cancelled.\n    [mapAfter, mapHis].forEach(function (m) {\n      if (!m) return;\n      try { m._mimosaGen = (m._mimosaGen || 0) + 1; } catch (eG) {}\n    });\n    mimosaRebuildEtchedGeometry(0);\n    // Automatically switch top preview to the corresponding jewelry view\n    mimosaSetViewMode(targetMode);\n    try { mimosaScheduleFactoryFiles(); } catch (eSched) {}\n  }\n\n  function mimosaUpdateMapPreviewLink() {\n    const coordsField = document.getElementById('mimosa-hidden-coords');\n    const zoomField = document.getElementById('mimosa-hidden-zoom');\n    const linkField = document.getElementById('mimosa-hidden-maplink');\n    if (!coordsField || !linkField) return;\n    const parts = coordsField.value.split(',').map(s => s.trim());\n    if (parts.length === 2) {\n      const zoom = (zoomField ? zoomField.value : 14);\n      linkField.value = 'https://www.google.com/maps/@' + parts[0] + ',' + parts[1] + ',' + zoom + 'z';\n    }\n  }\n\n  function mimosaOnMetalChange(input) {\n    let color = input && input.dataset ? input.dataset.color : '';\n    if (!color && input && input.selectedOptions && input.selectedOptions[0]) {\n      color = input.selectedOptions[0].dataset.color;\n    }\n    const jewelryLayer = document.getElementById('mimosa-map-after-wrap');\n    currentMetal = color === 'silver' ? 'silver' : 'gold';\n\n    document.querySelectorAll('.mimosa-finish-card').forEach(function (card) {\n      const inp = card.querySelector('input');\n      card.classList.toggle('active', !!(inp && inp.checked));\n    });\n\n    mimosaPaintJewelryMetal();\n    [mapAfter, mapHis].forEach(function (m) {\n      if (!m || !m.getLayer) return;\n      const metalColor = currentMetal === 'silver' ? MAP_LINE_SILVER : MIMOSA_METAL_FILL;\n      try {\n        if (m.getLayer('mimosa-road-channel-fill')) {\n          m.setPaintProperty('mimosa-road-channel-fill', 'fill-color', metalColor);\n          m.setPaintProperty('mimosa-road-channel-fill', 'fill-outline-color', metalColor);\n        }\n      } catch (eFill) {}\n      if (m._mimosaLiveLattice) {\n        m._mimosaLiveKey = '';\n        mimosaShowLiveLattice(m);\n      }\n    });\n    mimosaUpdateBackPreview();\n    mimosaRetintFrontThumbs();\n    mimosaScheduleFrontThumbs();\n\n    if (jewelryLayer) {\n      jewelryLayer.style.background = '#ffffff';\n    }\n\n    mimosaRecalculatePrice();\n  }\n\n\n\n  function mimosaPairVariantId() {\n    if (typeof PAIR_VARIANT_ID !== 'undefined' && PAIR_VARIANT_ID && String(PAIR_VARIANT_ID) !== '50884605903087') {\n      return String(PAIR_VARIANT_ID);\n    }\n    return String(window._mimosaSingleVariantId || '');\n  }\n\n  function mimosaSelectedVariantId() {\n    const pairId = mimosaPairVariantId();\n    if (currentSet === 'pair' && pairId) return pairId;\n    return String(window._mimosaSingleVariantId || '');\n  }\n\n  // The form is born with the $98 necklace. Choosing the pair rewrites\n  // that one field to the pair variant ($98).\n  function mimosaSyncCartVariantId() {\n    const form = document.getElementById('mimosa-customizer-form');\n    if (!form) return '';\n    const inputs = form.querySelectorAll('input[name=\"id\"]');\n    if (!inputs.length) return '';\n    if (!window._mimosaSingleVariantId) {\n      window._mimosaSingleVariantId = inputs[0].value;\n    }\n    const want = mimosaSelectedVariantId();\n    inputs.forEach(function (input, index) {\n      if (index === 0) input.value = want;\n      else input.remove();\n    });\n    let qty = form.querySelector('input[name=\"quantity\"]');\n    if (!qty) {\n      qty = document.createElement('input');\n      qty.type = 'hidden';\n      qty.name = 'quantity';\n      form.appendChild(qty);\n    }\n    qty.value = '1';\n    return want;\n  }\n\n  function mimosaDropUnselectedNecklace() {\n    const legacyPairId = '50884605903087';\n    return fetch('/cart.js', { credentials: 'same-origin', headers: { Accept: 'application/json' } })\n      .then(function (res) { return res.json(); })\n      .then(function (cart) {\n        const updates = {};\n        ((cart && cart.items) || []).forEach(function (item) {\n          if (String(item.variant_id) === legacyPairId) updates[item.key] = 0;\n        });\n        if (!Object.keys(updates).length) return null;\n        return fetch('/cart/update.js', {\n          method: 'POST',\n          credentials: 'same-origin',\n          headers: { 'Content-Type': 'application/json', Accept: 'application/json' },\n          body: JSON.stringify({ updates: updates })\n        });\n      });\n  }\n\n  function mimosaOnSetChange(set) {\n    currentSet = set;\n    const isPair = set === 'pair';\n    const singleRadio = document.querySelector('#mimosa-set-single input');\n    const pairRadio = document.querySelector('#mimosa-set-pair input');\n    if (singleRadio && pairRadio) {\n      singleRadio.checked = !isPair;\n      pairRadio.checked = isPair;\n    }\n    const pairNote = document.getElementById('mimosa-pair-note');\n    document.getElementById('mimosa-set-single').classList.toggle('active', !isPair);\n    document.getElementById('mimosa-set-pair').classList.toggle('active', isPair);\n    if (pairNote) pairNote.hidden = !isPair;\n    mimosaSyncStyleFromChoice();\n    if (isPair && currentShape === 'shield') mimosaChangeShape(mimosaHersShape());\n    else {\n      const shapeField = document.getElementById('mimosa-hidden-shape');\n      if (shapeField) shapeField.value = mimosaShapeOrderLabel();\n    }\n    const hisPendant = document.getElementById('mimosa-his-pendant');\n    if (hisPendant) hisPendant.disabled = !isPair;\n    const stickySet = document.getElementById('mimosa-sticky-set');\n    if (stickySet && stickySet.value !== set) stickySet.value = set;\n    mimosaSyncCartVariantId();\n    mimosaSyncPairJewelryVisibility();\n    mimosaSyncBackplateUpsellText();\n    mimosaRecalculatePrice();\n    try { mimosaScheduleFactoryFiles(); } catch (eSched) {}\n  }\n\n  function mimosaOnStickySetChange(select) {\n    if (!select) return;\n    mimosaOnSetChange(select.value === 'single' ? 'single' : 'pair');\n  }\n\n  function mimosaStickyAddToCart() {\n    if (!mimosaValidateLocationForAtc()) {\n      return;\n    }\n    if (typeof window.mimosaRunAddToCart === 'function') {\n      window.mimosaRunAddToCart();\n      return;\n    }\n    const btn = document.getElementById('mimosa-atc-btn');\n    if (btn) btn.click();\n  }\n\n  function mimosaSyncStickyThumb(url) {\n    const stickyThumb = document.getElementById('mimosa-sticky-thumb');\n    if (stickyThumb && url) stickyThumb.src = url;\n  }\n\n  function mimosaInitStickyAtc() {\n    const bar = document.getElementById('mimosa-sticky-atc');\n    const trigger = document.getElementById('mimosa-atc-btn');\n    const root = document.querySelector('.mimosa-warmth-pdp');\n    if (!bar || !trigger) return;\n\n    const setVisible = function (visible) {\n      bar.classList.toggle('is-visible', visible);\n      bar.setAttribute('aria-hidden', visible ? 'false' : 'true');\n      if (root) root.classList.toggle('has-sticky-atc', visible);\n    };\n\n    if ('IntersectionObserver' in window) {\n      const io = new IntersectionObserver(function (entries) {\n        entries.forEach(function (entry) {\n          // Show sticky bar once the main ATC is mostly out of view\n          setVisible(!entry.isIntersecting);\n        });\n      }, { root: null, threshold: 0.15, rootMargin: '0px 0px -8% 0px' });\n      io.observe(trigger);\n    } else {\n      const onScroll = function () {\n        const rect = trigger.getBoundingClientRect();\n        setVisible(rect.bottom < 0 || rect.top > window.innerHeight);\n      };\n      window.addEventListener('scroll', onScroll, { passive: true });\n      onScroll();\n    }\n\n    const activeImg = document.getElementById('mimosa-active-img');\n    if (activeImg) mimosaSyncStickyThumb(activeImg.src);\n  }\n\n  let galleryMode = 'pair';\n  const mimosaPairVideoThumb = document.querySelector('.mimosa-thumb-btn[data-gallery-video]')?.cloneNode(true);\n\n  function mimosaSyncStyleFromChoice() {\n    const styleValue = document.getElementById('mimosa-style-value');\n    const mode = currentSet === 'pair' ? 'pair' : (currentShape === 'shield' ? 'him' : 'her');\n    if (currentSet === 'pair') {\n      if (styleValue) styleValue.value = 'His & Hers Pair';\n    } else if (styleValue) {\n      styleValue.value = mode === 'him' ? 'For Him' : 'For Her';\n    }\n    if (mode !== galleryMode) mimosaSwapGallery(mode);\n  }\n\n  function mimosaSwapGallery(mode) {\n    const images = mode === 'him'\n      ? MIMOSA_HIM_IMAGES\n      : mode === 'her'\n        ? MIMOSA_HER_IMAGES\n        : (typeof MIMOSA_PAIR_IMAGES !== 'undefined' ? MIMOSA_PAIR_IMAGES : MIMOSA_HER_IMAGES);\n    const alt = mode === 'him' ? 'His necklace' : mode === 'her' ? 'Her necklace' : 'His and Hers necklace';\n    const thumbsRow = document.querySelector('.mimosa-thumbnails-row');\n    if (thumbsRow) {\n      thumbsRow.innerHTML = images.map((imgUrl, index) => `\n        <button type=\"button\" class=\"mimosa-thumb-btn ${index === 0 ? 'active' : ''}\" onclick=\"mimosaChangeImg(this, '${imgUrl}')\">\n          <img src=\"${imgUrl}\" alt=\"${alt} ${index + 1}\">\n        </button>\n      `).join('');\n      if (mode === 'pair' && mimosaPairVideoThumb) {\n        thumbsRow.firstElementChild?.after(mimosaPairVideoThumb.cloneNode(true));\n      }\n    }\n    if (images.length) mimosaChangeImg(thumbsRow?.firstElementChild, images[0]);\n    galleryMode = mode;\n  }\n\n  function mimosaShapeIconMarkup(shape) {\n    if (shape === 'shield') {\n      if (typeof MIMOSA_SHIELD_OUTER === 'undefined') return '';\n      return '<svg viewBox=\"18 4 64 96\" fill=\"none\"><path d=\"' + MIMOSA_SHIELD_OUTER + '\" stroke=\"currentColor\" stroke-width=\"4.2\" stroke-linejoin=\"round\"/><circle cx=\"50\" cy=\"10.2\" r=\"1.5\" stroke=\"currentColor\" stroke-width=\"2.4\"/></svg>';\n    }\n    const labels = { heart: 'Heart', circle: 'Circle', drop: 'Small Drop' };\n    const radio = document.querySelector('.mimosa-shape-card input[value=\"' + (labels[shape] || 'Heart') + '\"]');\n    const wrap = radio && radio.closest('.mimosa-shape-card') && radio.closest('.mimosa-shape-card').querySelector('.mimosa-shape-icon-wrap');\n    return wrap ? wrap.innerHTML : '';\n  }\n\n  function mimosaBackThumbMarkup(which) {\n    const src = document.getElementById(which === 'his' ? 'mimosa-back-svg-his' : 'mimosa-back-svg');\n    if (!src) return '';\n    const clone = src.cloneNode(true);\n    const stamp = which + Math.random().toString(36).slice(2, 7);\n    const idMap = {};\n    clone.querySelectorAll('[id]').forEach(function (el) {\n      idMap[el.id] = el.id + '-' + stamp;\n    });\n    clone.querySelectorAll('[id]').forEach(function (el) {\n      if (idMap[el.id]) el.id = idMap[el.id];\n    });\n    function rewriteUrl(value) {\n      return value.replace(/url\\(#([^)]+)\\)/g, function (_, id) {\n        return 'url(#' + (idMap[id] || id) + ')';\n      });\n    }\n    clone.querySelectorAll('*').forEach(function (el) {\n      ['clip-path', 'fill', 'stroke', 'filter', 'mask'].forEach(function (attr) {\n        const value = el.getAttribute(attr);\n        if (value && value.indexOf('url(#') !== -1) el.setAttribute(attr, rewriteUrl(value));\n      });\n    });\n    clone.removeAttribute('id');\n    // The live plate preview tightens its viewBox around each shape, so a heart\n    // and a shield zoom by different amounts. Set-card thumbs must stay on the\n    // same 0\u2013100 artboard as the openwork snapshot, or the plate looks bigger\n    // than the front and the heart's initials look bigger than the shield's.\n    clone.setAttribute('viewBox', '0 0 100 100');\n    clone.setAttribute('preserveAspectRatio', 'xMidYMid meet');\n    clone.setAttribute('width', '100%');\n    clone.setAttribute('height', '100%');\n    return clone.outerHTML;\n  }\n\n  let mimosaFrontThumbUrl = { hers: '', his: '' };\n  let mimosaFrontThumbTimer = null;\n  let mimosaThumbGen = 0;\n\n  function mimosaMetalTint() {\n    return currentMetal === 'silver' ? [197, 205, 212] : [212, 178, 74];\n  }\n\n  // Price thumbs are a snapshot of the map canvas. Switching finish leaves\n  // the previous frame in that buffer, and the hers map (the one on screen)\n  // is the one that gets copied too early \u2014 \"\u70B9\u51FB\u94F6\u8272\u518D\u70B9\u91D1\u8272\u00B7\u5973\u6B3E\u8FD8\u662F\u94F6\u8272\".\n  // White voids stay white. Every other pixel becomes the finish just chosen.\n  function mimosaRetintImageData(px) {\n    const tint = mimosaMetalTint();\n    for (let i = 0; i < px.length; i += 4) {\n      if (px[i + 3] < 16) continue;\n      if (px[i] + px[i + 1] + px[i + 2] >= 700) continue;\n      px[i] = tint[0];\n      px[i + 1] = tint[1];\n      px[i + 2] = tint[2];\n    }\n  }\n\n  function mimosaRetintFrontThumbs() {\n    const seen = {};\n    document.querySelectorAll('img[data-front-thumb]').forEach(function (img) {\n      const key = img.getAttribute('data-front-thumb');\n      if (!key || seen[key] || !img.src || img.src.indexOf('data:') !== 0) return;\n      seen[key] = 1;\n      const w = img.naturalWidth || 128;\n      const h = img.naturalHeight || 128;\n      if (w < 8 || h < 8) return;\n      const c = document.createElement('canvas');\n      c.width = w;\n      c.height = h;\n      const ctx = c.getContext('2d');\n      try {\n        ctx.drawImage(img, 0, 0, w, h);\n        const bmp = ctx.getImageData(0, 0, w, h);\n        mimosaRetintImageData(bmp.data);\n        ctx.putImageData(bmp, 0, 0);\n        const url = c.toDataURL('image/png');\n        if (!url || url.length < 80) return;\n        mimosaFrontThumbUrl[key] = url;\n        document.querySelectorAll('img[data-front-thumb=\"' + key + '\"]').forEach(function (el) {\n          el.src = url;\n        });\n      } catch (eTint) {}\n    });\n  }\n\n  function mimosaScheduleFrontThumbs() {\n    if (mimosaFrontThumbTimer) clearTimeout(mimosaFrontThumbTimer);\n    mimosaFrontThumbTimer = setTimeout(mimosaCaptureFrontThumbs, 220);\n  }\n\n  function mimosaCaptureFrontThumbs() {\n    const gen = ++mimosaThumbGen;\n    const jobs = [\n      { map: mapAfter, shape: mimosaHersShape(), key: 'hers' },\n      { map: mapHis, shape: 'shield', key: 'his' }\n    ];\n    let pending = jobs.length;\n    let finished = false;\n    function done() {\n      if (gen !== mimosaThumbGen) return;\n      pending -= 1;\n      if (pending > 0 || finished) return;\n      finished = true;\n      const needsBuild = !document.querySelector('img[data-front-thumb]') && (mimosaFrontThumbUrl.hers || mimosaFrontThumbUrl.his);\n      if (needsBuild) {\n        mimosaSyncSetShapeIcons();\n        return;\n      }\n      document.querySelectorAll('img[data-front-thumb]').forEach(function (img) {\n        const url = mimosaFrontThumbUrl[img.getAttribute('data-front-thumb')];\n        if (url) img.src = url;\n      });\n    }\n    jobs.forEach(function (job) {\n      if (!job.map || typeof job.map.getCanvas !== 'function' || typeof job.map.triggerRepaint !== 'function') {\n        done();\n        return;\n      }\n      const paint = function () {\n        if (gen !== mimosaThumbGen) return;\n        mimosaPaintJewelryThumb(job.map, job.shape, job.key);\n        done();\n      };\n      job.map.once('render', paint);\n      try { job.map.triggerRepaint(); } catch (eRepaint) { done(); }\n    });\n    setTimeout(function () {\n      if (gen !== mimosaThumbGen || finished) return;\n      pending = 1;\n      done();\n    }, 700);\n  }\n\n  function mimosaPaintJewelryThumb(map, shape, key) {\n    if (typeof Path2D === 'undefined') return;\n    let src;\n    try { src = map.getCanvas(); } catch (eGrab) { return; }\n    if (!src || src.width < 8 || src.height < 8) return;\n    const size = 128;\n    const canvas = document.createElement('canvas');\n    canvas.width = size;\n    canvas.height = size;\n    const ctx = canvas.getContext('2d');\n    const d = mimosaPathDToPolyline(shape === 'drop' ? mimosaPathForShape(shape) : mimosaCutPathWithBail(shape));\n    if (!d) return;\n    const metal = currentMetal === 'silver' ? '#C5CDD4' : '#D4B24A';\n    const rim = currentMetal === 'silver' ? '#8E979E' : '#A88242';\n    ctx.save();\n    ctx.scale(size / 100, size / 100);\n    try {\n      const clip = new Path2D(d);\n      ctx.fillStyle = metal;\n      ctx.fill(clip);\n      ctx.save();\n      ctx.clip(clip);\n      ctx.drawImage(src, 0, 0, 100, 100);\n      if (shape === 'drop') {\n        ctx.strokeStyle = metal;\n        ctx.lineWidth = 3;\n        ctx.lineJoin = 'round';\n        ctx.stroke(clip);\n        const eye = mimosaBailSpec('drop');\n        ctx.globalCompositeOperation = 'destination-out';\n        ctx.beginPath();\n        ctx.arc(eye.cx, eye.cy, eye.r, 0, Math.PI * 2);\n        ctx.fill();\n        ctx.globalCompositeOperation = 'source-over';\n      }\n      ctx.restore();\n      ctx.strokeStyle = rim;\n      ctx.lineWidth = 1.6;\n      ctx.stroke(clip);\n      // The map canvas still has grey basemap casings and, right after a\n      // finish change, a frame of the previous metal. The price thumb must\n      // be one finish: white voids stay white, everything else becomes the\n      // selected metal (\"\u70B9\u4E86\u91D1\u8272\u00B7\u5973\u6B3E\u8FD8\u6709\u90E8\u5206\u94F6\u8272\").\n      const flat = document.createElement('canvas');\n      flat.width = size;\n      flat.height = size;\n      const fctx = flat.getContext('2d');\n      fctx.drawImage(canvas, 0, 0);\n      const bmp = fctx.getImageData(0, 0, size, size);\n      mimosaRetintImageData(bmp.data);\n      fctx.putImageData(bmp, 0, 0);\n      ctx.setTransform(1, 0, 0, 1, 0, 0);\n      ctx.clearRect(0, 0, size, size);\n      ctx.drawImage(flat, 0, 0);\n    } catch (eDraw) {\n      ctx.restore();\n      return;\n    }\n    ctx.restore();\n    try {\n      const url = canvas.toDataURL('image/png');\n      if (url && url.length > 80) mimosaFrontThumbUrl[key] = url;\n    } catch (eUrl) {}\n  }\n\n  function mimosaFrontFace(which) {\n    const shape = which === 'his' ? 'shield' : mimosaHersShape();\n    const who = which === 'his' ? 'For Him' : 'For Her';\n    const url = mimosaFrontThumbUrl[which] || '';\n    if (!url) {\n      return '<span class=\"mimosa-set-shape\" title=\"' + who + ' front\">' + mimosaShapeIconMarkup(shape) + '</span>';\n    }\n    return '<span class=\"mimosa-set-shape is-front\" title=\"' + who + ' front\"><img data-front-thumb=\"' + which + '\" alt=\"\" src=\"' + url + '\"></span>';\n  }\n\n  function mimosaBackShapeThumb(which) {\n    const who = which === 'his' ? 'For Him' : 'For Her';\n    const markup = mimosaBackThumbMarkup(which === 'his' ? 'his' : 'hers');\n    if (!markup) return '';\n    return '<span class=\"mimosa-set-shape is-back\" title=\"' + who + ' engraved plate\">' + markup + '</span>';\n  }\n\n  function mimosaPieceColumn(which) {\n    const front = mimosaFrontFace(which);\n    const engraved = backplateOn ? mimosaBackShapeThumb(which) : '';\n    if (!engraved) {\n      return '<span class=\"mimosa-set-piece\">' + front + '</span>';\n    }\n    return '<span class=\"mimosa-set-piece\"><span class=\"mimosa-set-piece-faces\"><span class=\"mimosa-set-piece-face\">' + front + '<span class=\"mimosa-set-piece-cap\">Openwork</span></span><span class=\"mimosa-set-piece-face\">' + engraved + '<span class=\"mimosa-set-piece-cap\">Plate</span></span></span></span>';\n  }\n\n  function mimosaSyncSetShapeIcons() {\n    const shape = currentShape || 'heart';\n    const single = document.getElementById('mimosa-set-shapes-single');\n    const pair = document.getElementById('mimosa-set-shapes-pair');\n    const singleHtml = mimosaPieceColumn(shape === 'shield' ? 'his' : 'hers');\n    const pairHtml = mimosaPieceColumn('hers') + mimosaPieceColumn('his');\n    if (single) {\n      single.classList.toggle('is-with-back', backplateOn);\n      single.innerHTML = singleHtml;\n    }\n    if (pair) {\n      pair.classList.toggle('is-with-back', backplateOn);\n      pair.innerHTML = pairHtml;\n    }\n    const layerNote = document.getElementById('mimosa-set-layer-note');\n    if (layerNote) layerNote.hidden = !backplateOn;\n  }\n\n  function mimosaPaintShieldShapeIcon() {\n    const icon = document.getElementById('mimosa-shape-shield-icon');\n    if (!icon || typeof MIMOSA_SHIELD_OUTER === 'undefined') return;\n    icon.innerHTML = '<svg width=\"32\" height=\"32\" viewBox=\"18 4 64 96\" fill=\"none\"><path d=\"' + MIMOSA_SHIELD_OUTER + '\" stroke=\"currentColor\" stroke-width=\"4.2\" stroke-linejoin=\"round\"/><circle cx=\"50\" cy=\"10.2\" r=\"1.5\" stroke=\"currentColor\" stroke-width=\"2.4\"/></svg>';\n  }\n\n  function mimosaSelectShieldShape() {\n    if (currentSet === 'pair') {\n      if (currentViewMode !== 'his') {\n        mimosaBeginShapeSwitch();\n      }\n      document.querySelectorAll('.mimosa-shape-card').forEach(function (c) {\n        c.classList.toggle('active', c.id === 'mimosa-shape-card-shield');\n      });\n      mimosaSetViewMode('his');\n      return;\n    }\n    if (currentShape !== 'shield' || currentViewMode !== 'jewelry') {\n      mimosaBeginShapeSwitch();\n    }\n    mimosaChangeShape('shield');\n    mimosaSetViewMode('jewelry');\n  }\n\n  let currentGalleryIndex = 0;\n  let mimosaGalleryTimer = null;\n  let mimosaGalleryPaused = false;\n  const MIMOSA_GALLERY_MS = 3800;\n\n  function mimosaStartGalleryAutoplay() {\n    // Disabled per user request: customer clicks thumbnails or swipes manually\n    if (mimosaGalleryTimer) {\n      clearInterval(mimosaGalleryTimer);\n      mimosaGalleryTimer = null;\n    }\n  }\n\n  function mimosaBumpGalleryAutoplay() {\n    // Disabled\n  }\n\n  function mimosaChangeImg(btn, url) {\n    const thumbs = Array.from(document.querySelectorAll('.mimosa-thumb-btn'));\n    currentGalleryIndex = thumbs.indexOf(btn);\n    if (currentGalleryIndex === -1) currentGalleryIndex = 0;\n    \n    const activeImg = document.getElementById('mimosa-active-img');\n    const video = document.getElementById('mimosa-gallery-video');\n    const showVideo = Boolean(video && btn?.hasAttribute('data-gallery-video'));\n    if (activeImg) {\n      activeImg.hidden = showVideo;\n      if (!showVideo) activeImg.src = url;\n    }\n    if (video) {\n      video.hidden = !showVideo;\n      if (showVideo) {\n        if (!video.hasAttribute('src')) video.src = video.dataset.src;\n        video.play().catch(() => {});\n      } else {\n        video.pause();\n      }\n    }\n    if (url) mimosaSyncStickyThumb(url);\n\n    thumbs.forEach(b => b.classList.remove('active'));\n    if (btn) btn.classList.add('active');\n    mimosaBumpGalleryAutoplay();\n  }\n\n  function mimosaNavImg(direction, fromAutoplay) {\n    const thumbs = Array.from(document.querySelectorAll('.mimosa-thumb-btn'));\n    if (!thumbs.length) return;\n    \n    currentGalleryIndex = (currentGalleryIndex + direction + thumbs.length) % thumbs.length;\n    const targetThumb = thumbs[currentGalleryIndex];\n    if (targetThumb) {\n      const img = targetThumb.querySelector('img');\n      if (img || targetThumb.hasAttribute('data-gallery-video')) {\n        mimosaChangeImg(targetThumb, img?.src);\n      }\n      const row = targetThumb.parentElement;\n      if (row) {\n        const left = targetThumb.offsetLeft - (row.clientWidth - targetThumb.clientWidth) / 2;\n        row.scrollTo({ left: Math.max(0, left), behavior: 'smooth' });\n      }\n    }\n  }\n\n  // Swipe gesture support on mobile for main image\n  document.addEventListener('DOMContentLoaded', () => {\n    const mainWrap = document.querySelector('.mimosa-main-image-wrap');\n    if (!mainWrap) return;\n    let touchStartX = 0;\n    let touchEndX = 0;\n    mainWrap.addEventListener('touchstart', e => {\n      touchStartX = e.changedTouches[0].screenX;\n    }, { passive: true });\n    mainWrap.addEventListener('touchend', e => {\n      touchEndX = e.changedTouches[0].screenX;\n      if (touchStartX - touchEndX > 40) {\n        mimosaNavImg(1); // swipe left -> next\n      } else if (touchEndX - touchStartX > 40) {\n        mimosaNavImg(-1); // swipe right -> prev\n      }\n    }, { passive: true });\n\n    const gallery = document.querySelector('.mimosa-gallery-col');\n    if (gallery) {\n      gallery.addEventListener('mouseenter', function () { mimosaGalleryPaused = true; });\n      gallery.addEventListener('mouseleave', function () {\n        mimosaGalleryPaused = false;\n        mimosaBumpGalleryAutoplay();\n      });\n    }\n    mimosaStartGalleryAutoplay();\n  });\n\n  function mimosaOnBackplateChange(on) {\n    backplateOn = !!on;\n    const card = document.getElementById('mimosa-backplate-card');\n    const panel = document.getElementById('mimosa-backplate-customize');\n    const hidden = document.getElementById('mimosa-hidden-backplate');\n    const check = document.getElementById('mimosa-backplate-check');\n    if (card) card.classList.toggle('is-on', backplateOn);\n    if (check) check.checked = backplateOn;\n    if (panel) panel.hidden = !backplateOn;\n    if (hidden) hidden.value = backplateOn ? ('Yes (+$' + mimosaBackplateCharge() + ')') : 'No';\n    ['mimosa-name-row-1', 'mimosa-name-row-2', 'mimosa-hidden-pattern', 'mimosa-hidden-coord-ring'].forEach(function (id) {\n      const el = document.getElementById(id);\n      if (el) el.disabled = !backplateOn;\n    });\n    mimosaRecalculatePrice();\n    try { mimosaSyncSetShapeIcons(); } catch (eIcons) {}\n    try { mimosaScheduleFactoryFiles(); } catch (eSched) {}\n    if (backplateOn) {\n      try { mimosaUpdateBackPreview(); } catch (ePrev) {}\n      const first = document.getElementById('mimosa-name-row-1');\n      if (first && !first.disabled && !window.matchMedia('(max-width: 900px), (pointer: coarse)').matches) {\n        first.focus();\n        try { first.scrollIntoView({ block: 'nearest', inline: 'nearest' }); } catch (eScroll) {}\n      }\n    }\n  }\n\n  function mimosaRecalculatePrice() {\n    let metalDelta = 0;\n    const metalInput = document.querySelector('input[name=\"properties[Finish / Color]\"]:checked');\n    if (metalInput && metalInput.dataset.delta) {\n      metalDelta = parseFloat(metalInput.dataset.delta);\n    }\n    let stoneDelta = 0;\n    if (currentDesign === 'openwork' && currentStone !== 'none') {\n      const activeStone = document.querySelector('.mimosa-stone-swatch.active');\n      if (activeStone && activeStone.dataset.delta) stoneDelta = parseFloat(activeStone.dataset.delta) || 0;\n      else stoneDelta = 12;\n    }\n    const singlePlate = backplateOn ? 15 : 0;\n    const pairPlate = backplateOn ? 30 : 0;\n    const money = function (n) {\n      const rounded = Math.round(n * 100) / 100;\n      return '$' + (rounded % 1 === 0 ? rounded.toFixed(0) : rounded.toFixed(2));\n    };\n\n    const isPair = currentSet === 'pair';\n    const singleSale = SINGLE_PRICE + metalDelta + stoneDelta + singlePlate;\n    const pairSale = PAIR_PRICE + metalDelta + stoneDelta + pairPlate;\n    const pairCompare = PAIR_COMPARE + metalDelta + stoneDelta + pairPlate;\n    const currentSale = isPair ? pairSale : singleSale;\n    const currentCompare = (isPair ? PAIR_COMPARE : SINGLE_COMPARE) + metalDelta + stoneDelta + (isPair ? pairPlate : singlePlate);\n    const savePct = Math.round((1 - currentSale / currentCompare) * 100);\n    const pairSave = Math.round(pairCompare - pairSale);\n\n    const priceEl = document.getElementById('mimosa-display-price');\n    const compareEl = document.getElementById('mimosa-compare-price');\n    const saveEl = document.getElementById('mimosa-save-pill');\n    const atcEl = document.getElementById('mimosa-atc-text');\n    const stickyPrice = document.getElementById('mimosa-sticky-price');\n    const stickyCompare = document.getElementById('mimosa-sticky-compare');\n    const stickySave = document.getElementById('mimosa-sticky-save');\n    if (priceEl) {\n      priceEl.innerText = money(currentSale);\n      priceEl.hidden = isPair;\n    }\n    if (compareEl) compareEl.innerText = '$' + currentCompare.toFixed(2);\n    if (saveEl) saveEl.innerText = 'SAVE ' + savePct + '%';\n    const atcBtn = document.getElementById('mimosa-atc-btn');\n    const atcPrice = document.getElementById('mimosa-atc-price');\n    if (!(atcBtn && atcBtn.classList.contains('is-busy'))) {\n      if (atcEl) atcEl.textContent = 'Add to Cart \u2014 ';\n      if (atcPrice) {\n        atcPrice.hidden = false;\n        atcPrice.textContent = money(currentSale);\n      }\n    }\n    const offerEl = document.getElementById('mimosa-offer-line');\n    const offerWas = document.getElementById('mimosa-offer-was');\n    const offerNow = document.getElementById('mimosa-offer-now');\n    if (offerEl) offerEl.hidden = !isPair;\n    if (offerWas) offerWas.textContent = money(PAIR_COMPARE);\n    if (offerNow) offerNow.textContent = money(PAIR_PRICE);\n\n    const hasAddress = isLocationConfirmed && Boolean(\n      (document.getElementById('mimosa-hidden-location') && document.getElementById('mimosa-hidden-location').value.trim())\n    );\n\n    const stickySub = document.getElementById('mimosa-sticky-sub-mobile');\n    if (stickySub) {\n      stickySub.textContent = isPair ? 'His & Hers' : 'For Her';\n    }\n\n    const stickyBtn = document.getElementById('mimosa-sticky-btn');\n    const stickyLabel = document.getElementById('mimosa-sticky-btn-label');\n    if (stickyBtn && !stickyBtn.classList.contains('is-busy')) {\n      const nextLabel = !hasAddress ? 'Create Your Map \u2192' : ('Add to Cart \u2014 ' + money(currentSale));\n      if (stickyLabel) stickyLabel.textContent = nextLabel;\n      else stickyBtn.textContent = nextLabel;\n    }\n    if (stickyPrice) stickyPrice.innerText = money(currentSale);\n    if (stickyCompare) stickyCompare.innerText = money(currentCompare);\n    if (stickySave) stickySave.innerText = 'SAVE ' + savePct + '%';\n\n    const singleNow = document.getElementById('mimosa-single-now');\n    const pairNow = document.getElementById('mimosa-pair-now');\n    const pairWas = document.getElementById('mimosa-pair-was');\n    const pairSaveEl = document.getElementById('mimosa-pair-save');\n    const ribbonAmount = document.getElementById('mimosa-ribbon-amount');\n    const singleTitle = document.getElementById('mimosa-single-title');\n    if (singleTitle) singleTitle.textContent = (currentSet === 'single' && currentShape === 'shield') ? 'For Him' : 'For Her';\n    if (singleNow) singleNow.textContent = money(SINGLE_PRICE);\n    if (pairNow) pairNow.textContent = money(PAIR_PRICE);\n    if (pairWas) pairWas.textContent = money(PAIR_COMPARE);\n    if (pairSaveEl) pairSaveEl.textContent = 'Buy 1 Get 1 \u00B7 ' + money(PAIR_PRICE);\n    if (ribbonAmount) ribbonAmount.textContent = '2 Necklaces for ' + money(PAIR_PRICE);\n    const pairOpt = document.querySelector('#mimosa-sticky-set option[value=\"pair\"]');\n    const singleOpt = document.querySelector('#mimosa-sticky-set option[value=\"single\"]');\n    if (pairOpt) pairOpt.textContent = 'His & Hers \u2014 Buy 1 Get 1 \u00B7 ' + money(PAIR_PRICE);\n    if (singleOpt) singleOpt.textContent = 'For Her \u2014 ' + money(SINGLE_PRICE);\n    const isPairSet = currentSet === 'pair';\n    const platePrice = document.getElementById('mimosa-backplate-price');\n    const plateSub = document.getElementById('mimosa-backplate-sub');\n    if (platePrice) platePrice.textContent = isPairSet ? '(+$30)' : '(+$15)';\n    if (plateSub) {\n      plateSub.textContent = isPairSet\n        ? 'Two engraved plates \u2014 one for her, one for him. Each layers behind the openwork, or can be worn alone.'\n        : 'One engraved plate that layers behind the openwork, or can be worn alone.';\n    }\n    const plateHidden = document.getElementById('mimosa-hidden-backplate');\n    if (plateHidden) plateHidden.value = backplateOn ? ('Yes (+$' + mimosaBackplateCharge() + ')') : 'No';\n  }\n\n  function mimosaWaitForUrlGeocoding() {\n    return urlGeocodePromise || Promise.resolve();\n  }\n\n  // Parse URL parameters (e.g. ?style=him, ?location=Paris) and apply them.\n  function mimosaApplyLocationFromUrl() {\n    const urlParams = new URLSearchParams(window.location.search);\n    const raw = (urlParams.get('location') || urlParams.get('place') || urlParams.get('q') || '').trim();\n    if (!raw) return;\n    const input = document.getElementById('mimosa-map-search-input');\n    if (input) input.value = raw;\n\n    isGeocodingUrl = true;\n    urlGeocodePromise = mimosaSearchPlaces(raw)\n      .then(function (places) {\n        const feat = places && places[0];\n        if (!feat) return;\n        const lng = feat.lng, lat = feat.lat;\n        const name = feat.label || raw;\n        const tryFly = function (tries) {\n          if (mapBefore || mapAfter) {\n            mimosaFlyToPlace(lng, lat, name);\n            return;\n          }\n          if (tries <= 0) return;\n          setTimeout(function () { tryFly(tries - 1); }, 200);\n        };\n        tryFly(25);\n      })\n      .catch(function (err) { console.warn('location from url', err); })\n      .finally(function () {\n        isGeocodingUrl = false;\n      });\n  }\n\n  function checkUrlStyleParam() {\n    const urlParams = new URLSearchParams(window.location.search);\n    const styleParam = urlParams.get('style');\n    if (styleParam === 'him' || styleParam === 'men' || styleParam === 'her') {\n      mimosaOnSetChange('single');\n      mimosaChangeShape(styleParam === 'her' ? 'heart' : 'shield');\n    }\n    mimosaApplyLocationFromUrl();\n  }\n\n  function mimosaApplyCircleVisibility() {\n    const card = document.getElementById('mimosa-shape-card-circle');\n    if (!card) return;\n    const show = (typeof MIMOSA_SHOW_CIRCLE !== 'undefined') && !!MIMOSA_SHOW_CIRCLE;\n    card.hidden = !show;\n    card.style.display = show ? '' : 'none';\n    const radio = card.querySelector('input[type=\"radio\"]');\n    if (radio) {\n      radio.disabled = !show;\n      if (!show && radio.checked) {\n        mimosaChangeShape('heart');\n      }\n    }\n  }\n\n  document.addEventListener('DOMContentLoaded', () => {\n    mimosaApplyCircleVisibility();\n    mimosaSyncBackplateUpsellText();\n    mimosaPaintShieldShapeIcon();\n    mimosaSyncSetShapeIcons();\n    mimosaSyncPairJewelryVisibility();\n    initMimosaMap();\n    checkUrlStyleParam();\n    mimosaOnBackplateChange(false);\n    mimosaInitStickyAtc();\n    mimosaBindStoneDrag();\n    mimosaSyncCartVariantId();\n    mimosaRecalculatePrice();\n\n    // The DXFs are generated in the customer's browser. Shopify stores them as\n    // file line-item properties (<input type=\"file\" name=\"properties[...]\">).\n    // They have to be on the line BEFORE it enters the cart: a later swap can\n    // lose the race to checkout, and the order then stays \"_Factory Files:\n    // Pending\" with no download links. Post the files to /cart/add.js \u2014 the\n    // form action is /cart/add, which returns HTML and the file line never\n    // parses. A failed export must still let the sale through.\n    async function mimosaAttachFactoryFiles() {\n      // Reset all four slots first \u2014 back ENGRAVE files are only filled when\n      // the customer added the engraved plate.\n      for (let i = 1; i <= 4; i++) {\n        const input = document.getElementById('mimosa-file-' + i);\n        if (!input) continue;\n        input.disabled = true;\n        try { input.value = ''; } catch (eClr) {}\n      }\n      const files = await mimosaBuildFactoryFiles();\n      files.forEach(function (f) {\n        const input = document.getElementById('mimosa-file-' + f.slot);\n        if (!input) return;\n        const dt = new DataTransfer();\n        dt.items.add(new File([f.dxf], f.name, { type: 'application/dxf' }));\n        input.files = dt.files;\n        input.disabled = false;\n      });\n      return files.length;\n    }\n\n    function mimosaSetAtcBusy(busy, message) {\n      const btn = document.getElementById('mimosa-atc-btn');\n      const label = document.getElementById('mimosa-atc-text');\n      const sticky = document.getElementById('mimosa-sticky-btn');\n      if (btn) {\n        btn.disabled = !!busy;\n        btn.classList.toggle('is-busy', !!busy);\n        btn.setAttribute('aria-busy', busy ? 'true' : 'false');\n      }\n      if (sticky) {\n        sticky.disabled = !!busy;\n        sticky.classList.toggle('is-busy', !!busy);\n      }\n      const stickyLabel = document.getElementById('mimosa-sticky-btn-label');\n      const atcPrice = document.getElementById('mimosa-atc-price');\n      if (busy && message) {\n        if (label) label.textContent = message;\n        if (atcPrice) atcPrice.hidden = true;\n        if (stickyLabel) stickyLabel.textContent = message;\n        else if (sticky) sticky.textContent = message;\n      } else if (!busy) {\n        if (atcPrice) atcPrice.hidden = false;\n        mimosaRecalculatePrice();\n      }\n    }\n\n    // Radios share a name; querySelector() always hits the FIRST radio whose\n    // .value is its own option (e.g. Circle), not the checked one. Prefer\n    // :checked, then dedicated hidden ids, then non-radio fields.\n    function mimosaReadLineProperty(key) {\n      if (key === 'Pendant Shape') {\n        const shapeHidden = document.getElementById('mimosa-hidden-shape');\n        if (shapeHidden && shapeHidden.value) return shapeHidden.value;\n      }\n      if (key === 'Backside Pattern') {\n        const patternHidden = document.getElementById('mimosa-hidden-pattern');\n        if (patternHidden && !patternHidden.disabled && patternHidden.value) return patternHidden.value;\n      }\n      const checked = form.querySelector('[name=\"properties[' + key + ']\"]:checked');\n      if (checked && !checked.disabled && checked.value) return checked.value;\n      const nodes = form.querySelectorAll('[name=\"properties[' + key + ']\"]');\n      for (let i = 0; i < nodes.length; i++) {\n        const input = nodes[i];\n        if (!input || input.disabled) continue;\n        const type = (input.type || '').toLowerCase();\n        if (type === 'radio' || type === 'checkbox') continue;\n        if (input.value) return input.value;\n      }\n      return '';\n    }\n\n    function mimosaAddBackplateLine() {\n      const variantId = (typeof BACKPLATE_VARIANT_ID !== 'undefined' && BACKPLATE_VARIANT_ID)\n        ? Number(BACKPLATE_VARIANT_ID)\n        : null;\n      if (!backplateOn || !variantId) return Promise.resolve();\n      const props = {};\n      ['Backside Name Row 1', 'Backside Name Row 2', 'Backside Pattern', 'Backside Coordinate Ring', 'Finish / Color', 'Pendant Shape'].forEach(function (key) {\n        const val = mimosaReadLineProperty(key);\n        if (val) props[key] = val;\n      });\n      props['For'] = 'Map Necklace';\n      const isPair = currentSet === 'pair';\n      const qty = isPair ? 2 : 1;\n      if (isPair) {\n        props['Set'] = 'His & Hers Pair';\n        props['Plates'] = 'Hers plate and His plate included.';\n      } else {\n        props['Set'] = 'Single Necklace';\n        props['Plates'] = 'Single engraved plate.';\n      }\n      return fetch('/cart/add.js', {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json', Accept: 'application/json' },\n        body: JSON.stringify({\n          items: [{ id: variantId, quantity: qty, properties: props }]\n        })\n      }).then(function (res) {\n        if (!res.ok) throw new Error('backplate add failed');\n      });\n    }\n\n    // Pair is one $98 line (PAIR_VARIANT_ID). Single is the page product $98.\n    // Engraved backplate is +$30 (1 variant line for a single, qty 2 for a pair).\n    // Factory DXFs are built first, while the map is still on screen, then the\n    // necklace is added with those files already attached.\n\n    const form = document.getElementById('mimosa-customizer-form');\n    if (form) {\n      mimosaSyncCartVariantId();\n\n      function mimosaCollectLineProperties() {\n        const props = {};\n        const fd = new FormData(form);\n        fd.forEach(function (value, key) {\n          const match = /^properties\\[(.+)\\]$/.exec(key);\n          if (!match || value instanceof File) return;\n          const text = String(value);\n          if (!text) return;\n          props[match[1]] = text;\n        });\n        return props;\n      }\n\n      function mimosaBackplateProperties() {\n        const props = {};\n        ['Backside Name Row 1', 'Backside Name Row 2', 'Backside Pattern', 'Backside Coordinate Ring', 'Finish / Color', 'Pendant Shape'].forEach(function (key) {\n          const val = mimosaReadLineProperty(key);\n          if (val) props[key] = val;\n        });\n        props['For'] = 'Map Necklace';\n        if (currentSet === 'pair') {\n          props['Set'] = 'His & Hers Pair';\n          props['Plates'] = 'Hers plate and His plate included.';\n        } else {\n          props['Set'] = 'Single Necklace';\n          props['Plates'] = 'Single engraved plate.';\n        }\n        return props;\n      }\n\n      function mimosaReleaseAtc() {\n        form.dataset.mimosaSubmitting = '';\n        mimosaSetAtcBusy(false, '');\n        mimosaRecalculatePrice();\n      }\n\n      const MIMOSA_FACTORY_SLOTS = {\n        1: '_Factory Hers Front CUT',\n        2: '_Factory Hers Back ENGRAVE',\n        3: '_Factory His Front CUT',\n        4: '_Factory His Back ENGRAVE'\n      };\n\n      function mimosaExpectedFactorySlots(files) {\n        const slots = {};\n        (files || []).forEach(function (f) {\n          if (f && MIMOSA_FACTORY_SLOTS[f.slot] && f.dxf) slots[f.slot] = MIMOSA_FACTORY_SLOTS[f.slot];\n        });\n        return slots;\n      }\n\n      function mimosaFactoryUrlOk(val) {\n        const s = String(val || '');\n        return s.indexOf('.dxf') !== -1 && (s.indexOf('cdn.shopify.com') !== -1 || /^https?:\\/\\//i.test(s));\n      }\n\n      function mimosaPropsHaveFactoryFiles(props, files) {\n        const expected = mimosaExpectedFactorySlots(files);\n        const keys = Object.keys(expected);\n        if (!keys.length) return false;\n        if (!props || props['_Factory Files'] !== 'Attached') return false;\n        for (let i = 0; i < keys.length; i++) {\n          if (!mimosaFactoryUrlOk(props[expected[keys[i]]])) return false;\n        }\n        return true;\n      }\n\n      async function mimosaRemoveCartKey(key) {\n        if (!key) return;\n        await fetch('/cart/update.js', {\n          method: 'POST',\n          credentials: 'same-origin',\n          headers: { 'Content-Type': 'application/json', Accept: 'application/json' },\n          body: JSON.stringify({ updates: { [key]: 0 } })\n        }).catch(function () { return null; });\n      }\n\n      // After Shopify stores the uploaded DXFs, rewrite the same cart line as\n      // plain CDN URL strings via /cart/change.js. Do NOT delete the multipart\n      // line first \u2014 a failed remove/re-add left customers with text-only\n      // necklaces (or empty carts) and no download links on the order.\n      async function mimosaPersistFactoryUrls(lineKey, props, files) {\n        const next = {};\n        Object.keys(props || {}).forEach(function (key) {\n          const val = props[key];\n          if (val == null || val === '') return;\n          next[key] = String(val);\n        });\n        next['_Factory Files'] = 'Attached';\n        next['Factory Files'] = 'Attached';\n        const expected = mimosaExpectedFactorySlots(files);\n        Object.keys(expected).forEach(function (slot) {\n          const name = expected[slot];\n          if (mimosaFactoryUrlOk(props[name])) next[name] = String(props[name]);\n        });\n        if (!mimosaPropsHaveFactoryFiles(next, files)) {\n          throw new Error('map files were not kept in the cart');\n        }\n\n        const changeRes = await fetch('/cart/change.js', {\n          method: 'POST',\n          credentials: 'same-origin',\n          headers: { 'Content-Type': 'application/json', Accept: 'application/json' },\n          body: JSON.stringify({ id: lineKey, quantity: 1, properties: next })\n        });\n        const cart = await changeRes.json().catch(function () { return {}; });\n        if (!changeRes.ok || cart.status) {\n          // Keep the original multipart line \u2014 it already has CDN .dxf URLs.\n          if (mimosaPropsHaveFactoryFiles(props, files)) return { key: lineKey, properties: props };\n          throw new Error((cart && (cart.description || cart.message)) || 'map files were not kept in the cart');\n        }\n        const loc = next['Custom Map Location'] || '';\n        const line = ((cart && cart.items) || []).find(function (item) {\n          const p = (item && item.properties) || {};\n          return mimosaPropsHaveFactoryFiles(p, files) && (!loc || p['Custom Map Location'] === loc);\n        });\n        if (line) return line;\n        // Change.js responded but dropped factory props \u2014 keep multipart line.\n        if (mimosaPropsHaveFactoryFiles(props, files)) return { key: lineKey, properties: props };\n        throw new Error('map files were not kept in the cart');\n      }\n\n      // Build the multipart body directly. Assigning File objects onto the\n      // hidden <input type=\"file\"> fails in some browsers, the inputs stay\n      // disabled, and the order is saved as \"_Factory Files: Pending\".\n      async function mimosaAddNecklaceWithFiles(files) {\n        if (!files || !files.length) throw new Error('map files were not created');\n\n        const fd = new FormData();\n        fd.set('id', String(mimosaSelectedVariantId()));\n        fd.set('quantity', '1');\n        const props = mimosaCollectLineProperties();\n        props['_Factory Files'] = 'Attached';\n        props['Factory Files'] = 'Attached';\n        Object.keys(props).forEach(function (key) {\n          if (props[key]) fd.append('properties[' + key + ']', props[key]);\n        });\n        files.forEach(function (f) {\n          const key = MIMOSA_FACTORY_SLOTS[f.slot];\n          if (!key || !f.dxf) return;\n          fd.append(\n            'properties[' + key + ']',\n            new File([f.dxf], f.name, { type: 'application/octet-stream' })\n          );\n        });\n        const addRes = await fetch('/cart/add.js', {\n          method: 'POST',\n          body: fd,\n          credentials: 'same-origin',\n          headers: { Accept: 'application/json' }\n        });\n        const data = await addRes.json().catch(function () { return {}; });\n        if (!addRes.ok || data.status) {\n          throw new Error((data && (data.description || data.message)) || 'add failed');\n        }\n        const added = (data.items && data.items[0]) || data;\n        const addedProps = (added && added.properties) || {};\n        if (!mimosaPropsHaveFactoryFiles(addedProps, files)) {\n          await mimosaRemoveCartKey(added && added.key);\n          throw new Error('map files were not attached');\n        }\n        try {\n          await mimosaPersistFactoryUrls(added.key, addedProps, files);\n        } catch (ePersist) {\n          // Multipart line already has CDN DXF URLs \u2014 keep it for the order.\n          if (mimosaPropsHaveFactoryFiles(addedProps, files)) {\n            console.warn('factory url persist', ePersist);\n          } else {\n            await mimosaRemoveCartKey(added && added.key);\n            throw ePersist;\n          }\n        }\n        const status = document.getElementById('mimosa-factory-status');\n        if (status) status.value = 'Attached';\n        return data;\n      }\n\n      async function mimosaRunAddToCart() {\n        if (form.dataset.mimosaSubmitting === '1') return;\n        if (!mimosaValidateLocationForAtc()) return;\n\n        form.dataset.mimosaSubmitting = '1';\n        const errorMessage = document.getElementById('mimosa-atc-error');\n        if (errorMessage) errorMessage.hidden = true;\n        const atcBtn = document.getElementById('mimosa-atc-btn');\n        const stickyBtn = document.getElementById('mimosa-sticky-btn');\n        if (atcBtn) atcBtn.disabled = true;\n        if (stickyBtn) stickyBtn.disabled = true;\n\n        try {\n          if (isGeocodingUrl) {\n            try { await mimosaWaitForUrlGeocoding(); } catch (eGeo) {}\n            if (!mimosaValidateLocationForAtc()) {\n              mimosaReleaseAtc();\n              return;\n            }\n          }\n\n          if (isMapTransitioning && mapTransitionTarget) {\n            [mapBefore, mapAfter, mapHis].forEach(function (m) {\n              if (!m) return;\n              try {\n                m.jumpTo({ center: [mapTransitionTarget.lng, mapTransitionTarget.lat], zoom: mapZoomLevel, pitch: 0, bearing: 0 });\n              } catch (eJ) {}\n            });\n            isMapTransitioning = false;\n          }\n\n          const hiddenLoc = document.getElementById('mimosa-hidden-location');\n          if (hiddenLoc && confirmedLocationName) hiddenLoc.value = confirmedLocationName;\n          mimosaSyncCartVariantId();\n          mimosaUpdateMapPreviewLink();\n          mimosaUpdateBackPreview();\n\n          const plateId = (typeof BACKPLATE_VARIANT_ID !== 'undefined' && BACKPLATE_VARIANT_ID)\n            ? Number(BACKPLATE_VARIANT_ID)\n            : 0;\n          const withPlate = !!(backplateOn && plateId);\n          const plateItem = withPlate ? {\n            id: plateId,\n            quantity: currentSet === 'pair' ? 2 : 1,\n            properties: mimosaBackplateProperties()\n          } : null;\n          // Files are usually already built while they looked at the map.\n          mimosaSetAtcBusy(true, 'Adding your item to the cart. Please wait\u2026');\n          const atcStarted = performance.now();\n          let files = mimosaReadyFactoryFiles();\n          form.dataset.factoryCacheHit = files ? 'true' : 'false';\n          if (!files) {\n            try { files = await mimosaEnsureFactoryFiles(); } catch (eReady) { files = null; }\n          }\n          if (!files || !files.length) {\n            try { files = await mimosaBuildFactoryFiles(); } catch (eBuild) {\n              console.warn('factory build', eBuild);\n              files = null;\n            }\n          }\n          if (!files || !files.length) {\n            throw new Error('map files were not created');\n          }\n          if (!mimosaFactoryFilesComplete(files)) throw new Error('map files incomplete');\n          form.dataset.factoryWaitMs = String(Math.round(performance.now() - atcStarted));\n          await mimosaAddNecklaceWithFiles(files);\n          if (plateItem) {\n            await fetch('/cart/add.js', {\n              method: 'POST',\n              credentials: 'same-origin',\n              headers: { 'Content-Type': 'application/json', Accept: 'application/json' },\n              body: JSON.stringify({ items: [plateItem] })\n            });\n          }\n\n          // Final guard: never send the customer to cart/checkout without DXFs.\n          const cart = await fetch('/cart.js', { credentials: 'same-origin' }).then(function (r) { return r.json(); });\n          const neck = ((cart && cart.items) || []).find(function (item) {\n            return mimosaPropsHaveFactoryFiles((item && item.properties) || {}, files);\n          });\n          if (!neck) throw new Error('map files were not kept in the cart');\n\n          window.location.assign(window.routes?.cart_url || '/cart');\n        } catch (err) {\n          console.warn(err);\n          mimosaReleaseAtc();\n          const msg = String((err && err.message) || err || '');\n          const customerMessage = /map files|factory|not created|not attached|not kept|not sized/i.test(msg)\n            ? 'We could not prepare your map. Please wait for it to finish loading, then try adding it again.'\n            : 'We could not add your item to the cart. Please try again.';\n          if (errorMessage) {\n            errorMessage.textContent = customerMessage;\n            errorMessage.hidden = false;\n            errorMessage.focus();\n          } else {\n            alert(customerMessage);\n          }\n        }\n      }\n\n      window.mimosaRunAddToCart = mimosaRunAddToCart;\n\n      // type=\"button\" ATC \u2014 never allow a native /cart/add submit that drops DXFs.\n      const atcBtnBind = document.getElementById('mimosa-atc-btn');\n      if (atcBtnBind) {\n        atcBtnBind.addEventListener('click', function (e) {\n          e.preventDefault();\n          mimosaRunAddToCart();\n        });\n      }\n      form.addEventListener('submit', function (e) {\n        e.preventDefault();\n        e.stopPropagation();\n        mimosaRunAddToCart();\n      });\n      form.addEventListener('keydown', function (e) {\n        if (e.key !== 'Enter') return;\n        const t = e.target;\n        if (!t || t.tagName !== 'INPUT') return;\n        const type = (t.getAttribute('type') || 'text').toLowerCase();\n        if (type === 'submit' || type === 'button' || type === 'checkbox' || type === 'radio') return;\n        e.preventDefault();\n      });\n    }\n\n    document.querySelectorAll('.mimosa-abbr-field').forEach(function (field) {\n      field.addEventListener('compositionstart', function () {\n        field.dataset.composing = '1';\n      });\n      field.addEventListener('compositionend', function () {\n        field.dataset.composing = '0';\n        mimosaOnAbbrInput(field);\n      });\n    });\n\n    document.querySelectorAll('.mimosa-desc-media video').forEach((video) => {\n      video.setAttribute('playsinline', '');\n      video.setAttribute('muted', '');\n      video.muted = true;\n      video.play().catch(() => {});\n    });\n  });\n  if (document.readyState === 'complete' || document.readyState === 'interactive') {\n    setTimeout(() => {\n      initMimosaMap();\n      checkUrlStyleParam();\n      mimosaUpdateBackPreview();\n    }, 300);\n  }\n"],
  "mappings": "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",
  "names": ["unitsToLngLat", "rdpUnits", "joinUnits", "continueUnits", "dist2", "sameWay", "guard", "mimosaWaitTilesThen", "map", "mimosaBeginLiveGesture", "scheduleRefilter", "shape", "outer", "mimosaCollectLineProperties", "mimosaBackplateProperties", "mimosaReleaseAtc", "mimosaExpectedFactorySlots", "mimosaFactoryUrlOk", "mimosaPropsHaveFactoryFiles"]
}
