@chrtco/sdk 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -20,14 +20,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ BAND_DRAW_ORDER: () => BAND_DRAW_ORDER,
24
+ BAND_PRIORITY_RANGES: () => BAND_PRIORITY_RANGES,
23
25
  BUILD_MAXZOOM: () => BUILD_MAXZOOM,
24
26
  BUILD_MINZOOM: () => BUILD_MINZOOM,
27
+ CHART_BAND_CODES: () => CHART_BAND_CODES,
28
+ CHART_CASCADE_CODES: () => CHART_CASCADE_CODES,
25
29
  CHART_SECTIONS: () => CHART_SECTIONS,
26
30
  Chrt: () => Chrt,
27
31
  ChrtError: () => ChrtError,
28
32
  DEFAULT_REGION: () => DEFAULT_REGION,
29
33
  DEFAULT_TILE_BASE_URL: () => DEFAULT_TILE_BASE_URL,
30
34
  LABELED_LAYERS: () => LABELED_LAYERS,
35
+ LABEL_BEHAVIOR: () => LABEL_BEHAVIOR,
31
36
  NAUTICAL_SYMBOLS: () => NAUTICAL_SYMBOLS,
32
37
  OfflineError: () => OfflineError,
33
38
  OfflineStyleError: () => OfflineStyleError,
@@ -44,10 +49,12 @@ __export(index_exports, {
44
49
  SYMBOL_GROUPS: () => SYMBOL_GROUPS,
45
50
  SYMBOL_MAP: () => SYMBOL_MAP,
46
51
  applyColorTheme: () => applyColorTheme,
52
+ bandFilterExpression: () => bandFilterExpression,
47
53
  buildLabelLayer: () => buildLabelLayer,
48
54
  buildLayersForClass: () => buildLayersForClass,
49
55
  buildOfflineStyle: () => buildOfflineStyle,
50
56
  buildSources: () => buildSources,
57
+ combineWithBandFilter: () => combineWithBandFilter,
51
58
  daymarkColor: () => daymarkColor,
52
59
  decimateFeatures: () => decimateFeatures,
53
60
  depareColor: () => depareColor,
@@ -64,6 +71,7 @@ __export(index_exports, {
64
71
  getDrawPriority: () => getDrawPriority,
65
72
  getGridSizeForZoom: () => getGridSizeForZoom,
66
73
  getIconExpression: () => getIconExpression,
74
+ getLabelBehavior: () => getLabelBehavior,
67
75
  getLabelConfig: () => getLabelConfig,
68
76
  getLookupEntry: () => getLookupEntry,
69
77
  getMaxCellsForZoom: () => getMaxCellsForZoom,
@@ -89,7 +97,9 @@ __export(index_exports, {
89
97
  preprocessWaterBodies: () => preprocessWaterBodies,
90
98
  resolveColor: () => resolveColor,
91
99
  resolveStyle: () => resolveStyle,
92
- scaminToMinZoom: () => scaminToMinZoom
100
+ scaminToMinZoom: () => scaminToMinZoom,
101
+ withinBboxFilter: () => withinBboxFilter,
102
+ worldMinusBboxPolygon: () => worldMinusBboxPolygon
93
103
  });
94
104
  module.exports = __toCommonJS(index_exports);
95
105
 
@@ -1376,9 +1386,11 @@ var S52_LOOKUP = {
1376
1386
  category: "Depths",
1377
1387
  displayCategory: "BASE",
1378
1388
  int1Ref: "I10",
1389
+ // Rendered as depth-number text via labels.ts, not as a visible dot.
1379
1390
  style: { type: "circle", paint: { "circle-color": "CHBLK", "circle-radius": 0, "circle-opacity": 0, "circle-stroke-width": 0 } },
1380
1391
  viewingGroup: 13010,
1381
- scamin: 0
1392
+ scamin: 0,
1393
+ auditIgnore: true
1382
1394
  },
1383
1395
  DRGARE: {
1384
1396
  objectClass: "DRGARE",
@@ -1439,8 +1451,28 @@ var S52_LOOKUP = {
1439
1451
  category: "Land",
1440
1452
  displayCategory: "OTHER",
1441
1453
  int1Ref: "C20",
1454
+ // Rendered as region NAME label only via labels.ts — no visible shape.
1455
+ // scamin raised from 45_000 → 90_000 so place-name labels (Provincetown,
1456
+ // Plymouth, Marblehead, …) surface at coastal scale (z10) instead of
1457
+ // waiting for z11. NOAA paper charts show major place names at this
1458
+ // scale; one-step-down was masking landfall context for mariners.
1442
1459
  style: { type: "circle", paint: { "circle-color": "CHBRN", "circle-radius": 0, "circle-opacity": 0 } },
1443
1460
  viewingGroup: 12070,
1461
+ scamin: 9e4,
1462
+ auditIgnore: true
1463
+ },
1464
+ SLOGRD: {
1465
+ // Sloping ground — beach gradient / sloping terrain at landfall. Subtle
1466
+ // LANDA tint so it reads as a beach-context cue without competing with
1467
+ // safety-critical layers. Polygon main + Point variant (NOAA encodes 7
1468
+ // Point and 8 Polygon SLOGRD features).
1469
+ objectClass: "SLOGRD",
1470
+ name: "Sloping Ground",
1471
+ category: "Land",
1472
+ displayCategory: "OTHER",
1473
+ int1Ref: "C8",
1474
+ style: { type: "fill", paint: { "fill-color": "LANDA", "fill-opacity": 0.3 } },
1475
+ viewingGroup: 12070,
1444
1476
  scamin: 45e3
1445
1477
  },
1446
1478
  BUAARE: {
@@ -1449,9 +1481,13 @@ var S52_LOOKUP = {
1449
1481
  category: "Land",
1450
1482
  displayCategory: "STANDARD",
1451
1483
  int1Ref: "D1",
1484
+ // scamin dropped (was 45_000 → z11): built-up areas are infrequent at
1485
+ // low zooms and the label config's text-size interpolation already keeps
1486
+ // them readable. Without this drop, town labels were hidden until z11,
1487
+ // one step too aggressive for coastal-scale orientation.
1452
1488
  style: { type: "fill", paint: { "fill-color": "CHGRF", "fill-opacity": 0.25 } },
1453
1489
  viewingGroup: 12210,
1454
- scamin: 45e3
1490
+ scamin: 0
1455
1491
  },
1456
1492
  BUISGL: {
1457
1493
  objectClass: "BUISGL",
@@ -1463,6 +1499,21 @@ var S52_LOOKUP = {
1463
1499
  viewingGroup: 12210,
1464
1500
  scamin: 22e3
1465
1501
  },
1502
+ FORSTC: {
1503
+ // Fortified structure — coastal fortifications and historic forts. Useful
1504
+ // for visual orientation at landfall. Treated like a building footprint
1505
+ // (CHBRN fill + darker outline) per S-52 F13 portrayal. NOAA encodes 2
1506
+ // Line and 2 Polygon FORSTC features; the Line variant is added in
1507
+ // layer-builder.ts following the LNDARE Line pattern.
1508
+ objectClass: "FORSTC",
1509
+ name: "Fortified Structure",
1510
+ category: "Land",
1511
+ displayCategory: "OTHER",
1512
+ int1Ref: "F13",
1513
+ style: { type: "fill", paint: { "fill-color": "CHBRN", "fill-opacity": 0.4 } },
1514
+ viewingGroup: 12410,
1515
+ scamin: 22e3
1516
+ },
1466
1517
  LAKARE: {
1467
1518
  objectClass: "LAKARE",
1468
1519
  name: "Lake",
@@ -1726,7 +1777,10 @@ var S52_LOOKUP = {
1726
1777
  category: "Hazards",
1727
1778
  displayCategory: "STANDARD",
1728
1779
  int1Ref: "K40",
1729
- style: { type: "symbol", paint: {}, layout: { "icon-size": 0.6, "icon-allow-overlap": true }, iconImage: "OBSTRN01" },
1780
+ // Step expression hides rocks below zoom 12 (where dense coastal fields render
1781
+ // as solid black masses), then scales linearly through harbor-approach zooms.
1782
+ // Aligns with typical NOAA ENC SCAMIN of 22000 (≈ zoom 12) for these features.
1783
+ style: { type: "symbol", paint: {}, layout: { "icon-size": ["interpolate", ["linear"], ["zoom"], 11.99, 0, 12, 0.3, 14, 0.5, 16, 0.7], "icon-allow-overlap": true }, iconImage: "OBSTRN01" },
1730
1784
  hasConditional: true,
1731
1785
  conditionalAttributes: ["WATLEV", "VALSOU"],
1732
1786
  viewingGroup: 24020,
@@ -1738,7 +1792,7 @@ var S52_LOOKUP = {
1738
1792
  category: "Hazards",
1739
1793
  displayCategory: "STANDARD",
1740
1794
  int1Ref: "K12",
1741
- style: { type: "symbol", paint: {}, layout: { "icon-size": 0.6, "icon-allow-overlap": true }, iconImage: "UWTROC03" },
1795
+ style: { type: "symbol", paint: {}, layout: { "icon-size": ["interpolate", ["linear"], ["zoom"], 11.99, 0, 12, 0.3, 14, 0.5, 16, 0.7], "icon-allow-overlap": true }, iconImage: "UWTROC03" },
1742
1796
  hasConditional: true,
1743
1797
  conditionalAttributes: ["WATLEV", "VALSOU"],
1744
1798
  viewingGroup: 24020,
@@ -1756,6 +1810,42 @@ var S52_LOOKUP = {
1756
1810
  viewingGroup: 24020,
1757
1811
  scamin: 0
1758
1812
  },
1813
+ WATTUR: {
1814
+ // Water turbulence (tide rips, eddies, overfalls, breakers, bombora) per
1815
+ // S-52 PresLib H44. Safety-relevant for small craft — these features can
1816
+ // swamp a boat that didn't expect them. NOAA paper-chart convention is a
1817
+ // small wavy-line cluster with the abbreviation noted in the label
1818
+ // (`Br` for breakers, `Eddies`, `Overfalls`, `Tide rips`).
1819
+ //
1820
+ // Symbol layer drives the dominant Point geometry; the Polygon variant is
1821
+ // emitted from layer-builder via the same multi-geom pattern as PR #388.
1822
+ objectClass: "WATTUR",
1823
+ name: "Water Turbulence",
1824
+ category: "Hazards",
1825
+ displayCategory: "STANDARD",
1826
+ int1Ref: "H44",
1827
+ style: { type: "symbol", paint: {}, layout: { "icon-size": 0.7, "icon-allow-overlap": true }, iconImage: "WATTUR01" },
1828
+ hasConditional: true,
1829
+ conditionalAttributes: ["CATWAT"],
1830
+ viewingGroup: 24020,
1831
+ scamin: 22e3
1832
+ },
1833
+ FSHFAC: {
1834
+ // Fishing facility — weirs, stake fences, fish traps. Small-craft hazard,
1835
+ // so safety-critical viewing group 24020 (matches OBSTRN/UWTROC/WRECKS).
1836
+ // Subtle water-feature tint (DEPVS @0.25) + Point variant for stake-fence
1837
+ // markers. NOAA encodes 1 Point and 3 Polygon FSHFAC features.
1838
+ objectClass: "FSHFAC",
1839
+ name: "Fishing Facility",
1840
+ category: "Hazards",
1841
+ displayCategory: "STANDARD",
1842
+ int1Ref: "K44",
1843
+ style: { type: "fill", paint: { "fill-color": "DEPVS", "fill-opacity": 0.25 } },
1844
+ hasConditional: true,
1845
+ conditionalAttributes: ["CATFIF"],
1846
+ viewingGroup: 24020,
1847
+ scamin: 22e3
1848
+ },
1759
1849
  SBDARE: {
1760
1850
  objectClass: "SBDARE",
1761
1851
  name: "Seabed Area",
@@ -1766,8 +1856,32 @@ var S52_LOOKUP = {
1766
1856
  viewingGroup: 14010,
1767
1857
  scamin: 22e3
1768
1858
  },
1859
+ WEDKLP: {
1860
+ // Translucent green fill suggests kelp/vegetation; Point variant (the
1861
+ // dominant geometry — 85 of 88 features) is emitted by layer-builder as
1862
+ // a circle, mirroring the LNDARE Point precedent from PR #388.
1863
+ objectClass: "WEDKLP",
1864
+ name: "Weed / Kelp",
1865
+ category: "Land",
1866
+ displayCategory: "STANDARD",
1867
+ int1Ref: "K43",
1868
+ style: { type: "fill", paint: { "fill-color": "CHGRN", "fill-opacity": 0.35 } },
1869
+ hasConditional: true,
1870
+ conditionalAttributes: ["CATWED", "WATLEV"],
1871
+ viewingGroup: 14010,
1872
+ scamin: 22e3
1873
+ },
1769
1874
  // ── Regulated Areas (INT1 Section N) ────────────────────
1770
1875
  ACHARE: {
1876
+ // Anchorages are conventionally rendered as a subtle filled region in
1877
+ // S-52 with an anchor symbol at centroid and a dashed magenta boundary
1878
+ // (PresLib N12, NOAA Chart No. 1 §N). The fill stays low-opacity so
1879
+ // multiple overlapping anchorages can't compound into a flood — see
1880
+ // comments on CTNARE / RESARE below — but 0.04 left the area effectively
1881
+ // invisible. 0.10 produces a faint NOAA-style tint that still reads
1882
+ // against a busy harbor without stacking into purple wash; the dashed
1883
+ // magenta boundary and centroid anchor icon are emitted as companion
1884
+ // layers in layer-builder.ts so the "anchorage here" cue is unambiguous.
1771
1885
  objectClass: "ACHARE",
1772
1886
  name: "Anchorage Area",
1773
1887
  category: "Regulated Areas",
@@ -1778,32 +1892,71 @@ var S52_LOOKUP = {
1778
1892
  scamin: 9e4
1779
1893
  },
1780
1894
  RESARE: {
1895
+ // S-52 spec: restricted areas render as a solid magenta boundary line
1896
+ // (often with T-marks pointing inward). The previous flood-fill at
1897
+ // opacity 0.12 was a major source of the Boston Harbor purple wash —
1898
+ // Logan Airport's aircraft-vicinity restricted zones are RESARE
1899
+ // polygons that overlap the security-zone CTNARE polygons; with both
1900
+ // as flood fills, the harbor inner waters disappeared under stacked
1901
+ // magenta. Same boundary-only treatment as CTNARE.
1781
1902
  objectClass: "RESARE",
1782
1903
  name: "Restricted Area",
1783
1904
  category: "Regulated Areas",
1784
1905
  displayCategory: "STANDARD",
1785
1906
  int1Ref: "N2",
1786
- style: { type: "fill", paint: { "fill-color": "TRFCD", "fill-opacity": 0.12 } },
1907
+ style: {
1908
+ type: "line",
1909
+ paint: {
1910
+ "line-color": "TRFCD",
1911
+ "line-width": 1.2,
1912
+ "line-opacity": 0.7
1913
+ }
1914
+ },
1787
1915
  viewingGroup: 26040,
1788
1916
  scamin: 9e4
1789
1917
  },
1790
1918
  CTNARE: {
1919
+ // S-52 IHO INT1 N30 spec: caution areas render as a magenta dashed
1920
+ // boundary + centroid "!" symbol — NOT a flood fill. Our previous
1921
+ // `type: "fill"` with `fill-opacity: 0.08` looked harmless in
1922
+ // isolation but Boston-area Harbor cells have many overlapping CTNARE
1923
+ // features (Logan Airport security zones, harbor traffic regulated
1924
+ // areas, etc.). Each at 8% stacks: 5+ overlapping features → a 35%+
1925
+ // magenta wash that obliterates the underlying depth shading.
1926
+ //
1927
+ // Boundary-only (line) is the correct S-52 portrayal and removes the
1928
+ // stacking-flood-fill problem entirely. Hit-testing for the polygon
1929
+ // interior is lost — if we want it back, add a separate invisible
1930
+ // fill layer with `fill-opacity: 0`. Not worth the cost yet.
1791
1931
  objectClass: "CTNARE",
1792
1932
  name: "Caution Area",
1793
1933
  category: "Regulated Areas",
1794
1934
  displayCategory: "STANDARD",
1795
1935
  int1Ref: "N30",
1796
- style: { type: "fill", paint: { "fill-color": "TRFCD", "fill-opacity": 0.08 } },
1936
+ style: {
1937
+ type: "line",
1938
+ paint: {
1939
+ "line-color": "TRFCD",
1940
+ "line-width": 1.2,
1941
+ "line-dasharray": [4, 3],
1942
+ "line-opacity": 0.7
1943
+ }
1944
+ },
1797
1945
  viewingGroup: 26050,
1798
1946
  scamin: 9e4
1799
1947
  },
1800
1948
  FAIRWY: {
1949
+ // Fairways stay as a subtle fill (S-52 convention: very low-opacity
1950
+ // tint so ships can see the bounds of the navigable channel without
1951
+ // obscuring soundings). Reduced from 0.06 → 0.03 to limit stacking.
1952
+ // Long-term: fairway color should arguably be a neutral grey rather
1953
+ // than TRFCD magenta — separate followup.
1801
1954
  objectClass: "FAIRWY",
1802
1955
  name: "Fairway",
1803
1956
  category: "Regulated Areas",
1804
1957
  displayCategory: "STANDARD",
1805
1958
  int1Ref: "M18",
1806
- style: { type: "fill", paint: { "fill-color": "TRFCD", "fill-opacity": 0.06 } },
1959
+ style: { type: "fill", paint: { "fill-color": "TRFCD", "fill-opacity": 0.03 } },
1807
1960
  viewingGroup: 25020,
1808
1961
  scamin: 9e4
1809
1962
  },
@@ -1818,12 +1971,15 @@ var S52_LOOKUP = {
1818
1971
  scamin: 22e3
1819
1972
  },
1820
1973
  TSSLPT: {
1974
+ // Traffic separation lane. Light fill so the directional arrows (rendered
1975
+ // separately) read against it; reduced from 0.08 → 0.04 to avoid stacking
1976
+ // with adjacent TSSLPT/TSSRON polygons.
1821
1977
  objectClass: "TSSLPT",
1822
1978
  name: "TSS Lane Part",
1823
1979
  category: "Regulated Areas",
1824
1980
  displayCategory: "STANDARD",
1825
1981
  int1Ref: "M25",
1826
- style: { type: "fill", paint: { "fill-color": "TRFCD", "fill-opacity": 0.08 } },
1982
+ style: { type: "fill", paint: { "fill-color": "TRFCD", "fill-opacity": 0.04 } },
1827
1983
  viewingGroup: 25010,
1828
1984
  scamin: 9e4
1829
1985
  },
@@ -1833,7 +1989,7 @@ var S52_LOOKUP = {
1833
1989
  category: "Regulated Areas",
1834
1990
  displayCategory: "STANDARD",
1835
1991
  int1Ref: "M26",
1836
- style: { type: "fill", paint: { "fill-color": "TRFCD", "fill-opacity": 0.08 } },
1992
+ style: { type: "fill", paint: { "fill-color": "TRFCD", "fill-opacity": 0.04 } },
1837
1993
  viewingGroup: 25010,
1838
1994
  scamin: 9e4
1839
1995
  },
@@ -1848,22 +2004,43 @@ var S52_LOOKUP = {
1848
2004
  scamin: 9e4
1849
2005
  },
1850
2006
  TESARE: {
2007
+ // S-52 spec: territorial sea boundaries render as a magenta dashed
2008
+ // line (not a fill). Same reasoning as CTNARE/RESARE — even at 0.04
2009
+ // opacity, multiple territorial-sea lobes can stack.
1851
2010
  objectClass: "TESARE",
1852
2011
  name: "Territorial Sea Area",
1853
2012
  category: "Regulated Areas",
1854
2013
  displayCategory: "OTHER",
1855
2014
  int1Ref: "N40",
1856
- style: { type: "fill", paint: { "fill-color": "TRFCD", "fill-opacity": 0.04 } },
2015
+ style: {
2016
+ type: "line",
2017
+ paint: {
2018
+ "line-color": "TRFCD",
2019
+ "line-width": 1,
2020
+ "line-dasharray": [6, 4],
2021
+ "line-opacity": 0.6
2022
+ }
2023
+ },
1857
2024
  viewingGroup: 26050,
1858
2025
  scamin: 9e4
1859
2026
  },
1860
2027
  MIPARE: {
2028
+ // S-52 spec: military practice area renders as a magenta dashed
2029
+ // boundary + centroid symbol — boundary-only here, matches CTNARE.
1861
2030
  objectClass: "MIPARE",
1862
2031
  name: "Military Practice Area",
1863
2032
  category: "Regulated Areas",
1864
2033
  displayCategory: "OTHER",
1865
2034
  int1Ref: "N30",
1866
- style: { type: "fill", paint: { "fill-color": "TRFCD", "fill-opacity": 0.1 } },
2035
+ style: {
2036
+ type: "line",
2037
+ paint: {
2038
+ "line-color": "TRFCD",
2039
+ "line-width": 1.2,
2040
+ "line-dasharray": [4, 3],
2041
+ "line-opacity": 0.7
2042
+ }
2043
+ },
1867
2044
  viewingGroup: 26050,
1868
2045
  scamin: 9e4
1869
2046
  },
@@ -1880,45 +2057,101 @@ var S52_LOOKUP = {
1880
2057
  hasConditional: true,
1881
2058
  conditionalAttributes: ["CATBRG", "VERCLR"]
1882
2059
  },
2060
+ PYLONS: {
2061
+ objectClass: "PYLONS",
2062
+ name: "Pylon / Bridge Support",
2063
+ category: "Infrastructure",
2064
+ displayCategory: "STANDARD",
2065
+ int1Ref: "D27",
2066
+ // Default fill style — layer-builder emits the Point variant via the
2067
+ // same multi-geom pattern from PR #388 (LNDARE Point fix).
2068
+ style: { type: "fill", paint: { "fill-color": "CHBRN", "fill-opacity": 0.5 } },
2069
+ hasConditional: true,
2070
+ conditionalAttributes: ["CATPYL", "VERLEN"],
2071
+ viewingGroup: 12410,
2072
+ scamin: 22e3
2073
+ },
2074
+ // Submarine cable — S-52 INT1 L30 portrayal: thin dashed CHMGD line.
2075
+ // Matches NOAA ENC Online's portrayal — a clean continuous dashed line,
2076
+ // no periodic pictogram overlays (those proved visually noisy at z14+ when
2077
+ // many parallel cables run in a corridor). Previous TRFCD colour was wrong:
2078
+ // submarine cables are charted in CHMGD per S-52.
2079
+ // scamin 90_000 (→ z10) matches the regulated-area family (CTNARE, FAIRWY,
2080
+ // RESARE, PRDARE) so cables appear at Approach scale alongside the other
2081
+ // navigation hazards mariners route around. Previous 22_000 (→ z12) hid
2082
+ // them at Approach band even though the data is in tiles from z7.
1883
2083
  CBLSUB: {
1884
2084
  objectClass: "CBLSUB",
1885
2085
  name: "Submarine Cable",
1886
2086
  category: "Infrastructure",
1887
- displayCategory: "OTHER",
2087
+ displayCategory: "STANDARD",
1888
2088
  int1Ref: "L30",
1889
- style: { type: "line", paint: { "line-color": "TRFCD", "line-width": 1, "line-dasharray": [5, 3] } },
1890
- viewingGroup: 24010,
1891
- scamin: 22e3
2089
+ style: { type: "line", paint: { "line-color": "CHMGD", "line-width": 0.8, "line-dasharray": [6, 3] } },
2090
+ hasConditional: true,
2091
+ conditionalAttributes: ["CATCBL", "STATUS"],
2092
+ viewingGroup: 24090,
2093
+ scamin: 9e4
1892
2094
  },
1893
2095
  CBLARE: {
1894
2096
  objectClass: "CBLARE",
1895
2097
  name: "Cable Area",
1896
- category: "Infrastructure",
1897
- displayCategory: "OTHER",
1898
- int1Ref: "L31",
1899
- style: { type: "fill", paint: { "fill-color": "TRFCD", "fill-opacity": 0.08 } },
1900
- viewingGroup: 24010,
1901
- scamin: 22e3
2098
+ category: "Regulated Areas",
2099
+ displayCategory: "STANDARD",
2100
+ int1Ref: "L32",
2101
+ // S-52 PresLib L32: dashed magenta boundary + diagonal hatching pattern.
2102
+ // The CHMGD fill is a low-opacity wash under the pattern; layer-builder
2103
+ // emits a dashed CHMGD boundary line for the polygon edge (see
2104
+ // REGULATED_AREA_BOUNDARY_LAYERS).
2105
+ style: { type: "fill", paint: { "fill-color": "CHMGD", "fill-opacity": 0.08, "fill-pattern": "CBLARE01" } },
2106
+ hasConditional: true,
2107
+ conditionalAttributes: ["CATCBL", "STATUS"],
2108
+ viewingGroup: 26010,
2109
+ scamin: 9e4
1902
2110
  },
2111
+ // Submarine pipeline — S-52 INT1 L40 portrayal: thin dashed PIPLN line.
2112
+ // Same family as CBLSUB but PIPLN-coloured. Clean continuous dashed line
2113
+ // without periodic pictograms — matches NOAA portrayal.
1903
2114
  PIPSOL: {
1904
2115
  objectClass: "PIPSOL",
1905
- name: "Pipeline, Submarine",
2116
+ name: "Submarine Pipeline",
1906
2117
  category: "Infrastructure",
1907
- displayCategory: "OTHER",
2118
+ displayCategory: "STANDARD",
1908
2119
  int1Ref: "L40",
1909
- style: { type: "line", paint: { "line-color": "PIPLN", "line-width": 1, "line-dasharray": [6, 3] } },
1910
- viewingGroup: 24010,
1911
- scamin: 22e3
2120
+ style: { type: "line", paint: { "line-color": "PIPLN", "line-width": 0.8, "line-dasharray": [6, 3] } },
2121
+ hasConditional: true,
2122
+ conditionalAttributes: ["CATPIP", "STATUS"],
2123
+ viewingGroup: 24090,
2124
+ scamin: 9e4
2125
+ },
2126
+ // Overhead pipeline — S-52 INT1 L41 portrayal: solid thin PIPLN line.
2127
+ // VERCLR clearance label rendered along the line via labels.ts.
2128
+ // Previously absent from the lookup entirely — the 2 NOAA LineString
2129
+ // features were silently dropped.
2130
+ PIPOHD: {
2131
+ objectClass: "PIPOHD",
2132
+ name: "Overhead Pipeline",
2133
+ category: "Infrastructure",
2134
+ displayCategory: "STANDARD",
2135
+ int1Ref: "L41",
2136
+ style: { type: "line", paint: { "line-color": "PIPLN", "line-width": 1 } },
2137
+ hasConditional: true,
2138
+ conditionalAttributes: ["CATPIP", "VERCLR", "STATUS"],
2139
+ viewingGroup: 24070,
2140
+ scamin: 9e4
1912
2141
  },
1913
2142
  PIPARE: {
1914
2143
  objectClass: "PIPARE",
1915
2144
  name: "Pipeline Area",
1916
- category: "Infrastructure",
1917
- displayCategory: "OTHER",
1918
- int1Ref: "L41",
1919
- style: { type: "fill", paint: { "fill-color": "PIPLN", "fill-opacity": 0.08 } },
1920
- viewingGroup: 24010,
1921
- scamin: 22e3
2145
+ category: "Regulated Areas",
2146
+ displayCategory: "STANDARD",
2147
+ int1Ref: "L42",
2148
+ // S-52 PresLib L42: dashed pipeline-colour boundary + diagonal hatching.
2149
+ // PIPLN wash under the pattern; layer-builder emits the dashed boundary.
2150
+ style: { type: "fill", paint: { "fill-color": "PIPLN", "fill-opacity": 0.08, "fill-pattern": "PIPARE01" } },
2151
+ hasConditional: true,
2152
+ conditionalAttributes: ["CATPIP", "STATUS"],
2153
+ viewingGroup: 26010,
2154
+ scamin: 9e4
1922
2155
  },
1923
2156
  MORFAC: {
1924
2157
  objectClass: "MORFAC",
@@ -2006,7 +2239,9 @@ var S52_LOOKUP = {
2006
2239
  category: "Land",
2007
2240
  displayCategory: "OTHER",
2008
2241
  int1Ref: "E33",
2009
- style: { type: "circle", paint: { "circle-color": "CHBLK", "circle-radius": 3, "circle-stroke-width": 0 } },
2242
+ style: { type: "symbol", paint: {}, layout: { "icon-size": 0.6, "icon-allow-overlap": true }, iconImage: "TNKCON02" },
2243
+ hasConditional: true,
2244
+ conditionalAttributes: ["CATSIL", "CONVIS"],
2010
2245
  viewingGroup: 12210,
2011
2246
  scamin: 22e3
2012
2247
  },
@@ -2118,15 +2353,22 @@ var S52_LOOKUP = {
2118
2353
  scamin: 22e3
2119
2354
  },
2120
2355
  // ── Overhead & Underground (INT1 Section L) ─────────────
2356
+ // Overhead cable — S-52 INT1 L31 portrayal: solid thin magenta line
2357
+ // (not dashed) because overhead cables are an in-air navigation hazard
2358
+ // (mast clearance), not a submerged one. The VERCLR clearance label is
2359
+ // emitted along the line via labels.ts. Previous CHBLK + dash pattern
2360
+ // was wrong.
2121
2361
  CBLOHD: {
2122
2362
  objectClass: "CBLOHD",
2123
- name: "Cable, Overhead",
2363
+ name: "Overhead Cable",
2124
2364
  category: "Infrastructure",
2125
2365
  displayCategory: "STANDARD",
2126
- int1Ref: "D26",
2127
- style: { type: "line", paint: { "line-color": "CHBLK", "line-width": 1, "line-dasharray": [4, 2] } },
2128
- viewingGroup: 24010,
2129
- scamin: 22e3
2366
+ int1Ref: "L31",
2367
+ style: { type: "line", paint: { "line-color": "CHMGD", "line-width": 1 } },
2368
+ hasConditional: true,
2369
+ conditionalAttributes: ["CATCBL", "VERCLR", "STATUS"],
2370
+ viewingGroup: 24070,
2371
+ scamin: 9e4
2130
2372
  },
2131
2373
  // ── Routes (INT1 Section M) ─────────────────────────────
2132
2374
  FERYRT: {
@@ -2156,19 +2398,41 @@ var S52_LOOKUP = {
2156
2398
  category: "Land",
2157
2399
  displayCategory: "OTHER",
2158
2400
  int1Ref: "C31",
2159
- style: { type: "fill", paint: { "fill-color": "LANDF", "fill-opacity": 0.2 } },
2401
+ // Pattern fill driven by CATVEG (resolved in `style-resolver.ts` via
2402
+ // `vegatnPatternExpression`). `fill-color` is the MapLibre fallback for
2403
+ // when the sprite image is missing; `fill-pattern` here is the default
2404
+ // used if the conditional expression isn't applied for some reason
2405
+ // (e.g. a consumer that bypasses `resolvePaint`).
2406
+ style: {
2407
+ type: "fill",
2408
+ paint: { "fill-color": "LANDF", "fill-opacity": 0.6, "fill-pattern": "VEGATN03" }
2409
+ },
2410
+ hasConditional: true,
2411
+ conditionalAttributes: ["CATVEG"],
2160
2412
  viewingGroup: 12050,
2161
2413
  scamin: 22e3
2162
2414
  },
2163
2415
  SEAARE: {
2416
+ // Cross-band water base. SEAARE polygons tile the sea below the
2417
+ // detailed DEPARE depth-area features, so where DEPARE has coverage
2418
+ // the depth bins win on top; where it doesn't (the coverage hole
2419
+ // between Coastal and Approach cells, etc.), SEAARE paints the
2420
+ // "deep water" colour instead of leaving the basemap to bleed
2421
+ // through. Drawn before DEPARE — see `draw-order.ts`. Opaque,
2422
+ // forced via `OPAQUE_FILL_LAYERS` in `style-resolver.ts`.
2423
+ //
2424
+ // `scamin: 0` so the base fill renders at every continuous zoom,
2425
+ // gated only by the band-priority window. The label config in
2426
+ // `labels.ts` keeps its own `minzoom: 5` so the OBJNAM doesn't
2427
+ // splash at low zooms.
2164
2428
  objectClass: "SEAARE",
2165
2429
  name: "Sea Area",
2166
2430
  category: "Depths",
2167
2431
  displayCategory: "OTHER",
2168
2432
  int1Ref: "O1",
2169
- style: { type: "fill", paint: { "fill-color": "DEPMD", "fill-opacity": 0 } },
2433
+ style: { type: "fill", paint: { "fill-color": "DEPDW", "fill-opacity": 1 } },
2170
2434
  viewingGroup: 12070,
2171
- scamin: 9e4
2435
+ scamin: 0
2172
2436
  },
2173
2437
  MARCUL: {
2174
2438
  objectClass: "MARCUL",
@@ -2230,6 +2494,27 @@ var S52_LOOKUP = {
2230
2494
  viewingGroup: 25010,
2231
2495
  scamin: 9e4
2232
2496
  },
2497
+ PRDARE: {
2498
+ // Production Area — offshore oil/gas platforms, offshore wind farms (or
2499
+ // their exclusion zones), aquaculture, and other industrial production
2500
+ // areas mariners must not enter. Safety-critical: a vessel transiting
2501
+ // Boston-NYC should see Block Island / Vineyard Wind exclusion zones.
2502
+ //
2503
+ // Boundary-only dashed magenta — matches RESARE/CTNARE/MIPARE/TESARE
2504
+ // convention via LINE_FROM_POLYGON_LAYERS (see layer-builder.ts). Avoids
2505
+ // the flood-fill stacking problem where multiple regulated areas overlap
2506
+ // and obliterate underlying depth shading.
2507
+ objectClass: "PRDARE",
2508
+ name: "Production Area",
2509
+ category: "Regulated Areas",
2510
+ displayCategory: "STANDARD",
2511
+ int1Ref: "L5",
2512
+ style: { type: "line", paint: { "line-color": "CHMGD", "line-width": 1.4, "line-dasharray": [4, 2] } },
2513
+ hasConditional: true,
2514
+ conditionalAttributes: ["CATPRA", "STATUS"],
2515
+ viewingGroup: 26010,
2516
+ scamin: 9e4
2517
+ },
2233
2518
  OSPARE: {
2234
2519
  objectClass: "OSPARE",
2235
2520
  name: "Offshore Production Area",
@@ -2260,6 +2545,21 @@ var S52_LOOKUP = {
2260
2545
  viewingGroup: 12210,
2261
2546
  scamin: 22e3
2262
2547
  },
2548
+ RUNWAY: {
2549
+ // Airport runway near coast — navigation reference, not a navigable
2550
+ // feature. Distinct from ROADWY (which is `type: "line"`) — runways are
2551
+ // typically polygon-encoded showing the actual paved extent. NOAA encodes
2552
+ // 1 Line and 5 Polygon RUNWAY features; the Line variant is added in
2553
+ // layer-builder.ts so neither geometry type is silently dropped.
2554
+ objectClass: "RUNWAY",
2555
+ name: "Runway",
2556
+ category: "Infrastructure",
2557
+ displayCategory: "OTHER",
2558
+ int1Ref: "D20",
2559
+ style: { type: "fill", paint: { "fill-color": "CHGRF", "fill-opacity": 0.3 } },
2560
+ viewingGroup: 12250,
2561
+ scamin: 22e3
2562
+ },
2263
2563
  DAMCON: {
2264
2564
  objectClass: "DAMCON",
2265
2565
  name: "Dam",
@@ -2270,48 +2570,78 @@ var S52_LOOKUP = {
2270
2570
  viewingGroup: 12410,
2271
2571
  scamin: 22e3
2272
2572
  },
2573
+ // ── Magnetic Variation (INT1 Section B) ─────────────────
2574
+ // Polygon features (~136 in NOAA corpus) are isogonic zones — areas of
2575
+ // constant magnetic variation. The line style here is drawn as the
2576
+ // polygon BOUNDARY (LINE_FROM_POLYGON_LAYERS in layer-builder.ts), giving
2577
+ // the faint dashed magenta isogonic lines mariners read for compass
2578
+ // correction. Point features (~58) get their own circle layer in
2579
+ // layer-builder.ts. The VALMAG label is rendered via labels.ts.
2580
+ MAGVAR: {
2581
+ objectClass: "MAGVAR",
2582
+ name: "Magnetic Variation",
2583
+ category: "Meta",
2584
+ displayCategory: "OTHER",
2585
+ int1Ref: "B68",
2586
+ style: { type: "line", paint: { "line-color": "CHMGD", "line-width": 0.5, "line-opacity": 0.5, "line-dasharray": [4, 2] } },
2587
+ hasConditional: true,
2588
+ conditionalAttributes: ["VALMAG", "VALACM", "RYRMGV"],
2589
+ viewingGroup: 23010,
2590
+ scamin: 0
2591
+ },
2273
2592
  // ── Meta (hidden by default) ────────────────────────────
2593
+ // M_* and DSID are S-57 metadata classes — they describe the dataset
2594
+ // (coverage extent, survey reliability, source publication, etc.) and
2595
+ // carry attributes for click-query lookups, but never draw a visible
2596
+ // shape. `auditIgnore` keeps the layer-coverage audit from flagging
2597
+ // their geometry-type rows as gaps.
2274
2598
  M_COVR: {
2275
2599
  objectClass: "M_COVR",
2276
2600
  name: "Coverage",
2277
2601
  category: "Meta",
2278
2602
  displayCategory: "META",
2279
- style: { type: "line", paint: { "line-color": "CHGRF", "line-width": 0.5, "line-opacity": 0.3 } }
2603
+ style: { type: "line", paint: { "line-color": "CHGRF", "line-width": 0.5, "line-opacity": 0.3 } },
2604
+ auditIgnore: true
2280
2605
  },
2281
2606
  M_NPUB: {
2282
2607
  objectClass: "M_NPUB",
2283
2608
  name: "Nautical Publication",
2284
2609
  category: "Meta",
2285
2610
  displayCategory: "META",
2286
- style: { type: "fill", paint: { "fill-color": "CHGRF", "fill-opacity": 0 } }
2611
+ style: { type: "fill", paint: { "fill-color": "CHGRF", "fill-opacity": 0 } },
2612
+ auditIgnore: true
2287
2613
  },
2288
2614
  M_NSYS: {
2289
2615
  objectClass: "M_NSYS",
2290
2616
  name: "Nav System of Marks",
2291
2617
  category: "Meta",
2292
2618
  displayCategory: "META",
2293
- style: { type: "fill", paint: { "fill-color": "CHGRF", "fill-opacity": 0 } }
2619
+ style: { type: "fill", paint: { "fill-color": "CHGRF", "fill-opacity": 0 } },
2620
+ auditIgnore: true
2294
2621
  },
2295
2622
  M_QUAL: {
2296
2623
  objectClass: "M_QUAL",
2297
2624
  name: "Quality of Data",
2298
2625
  category: "Meta",
2299
2626
  displayCategory: "META",
2300
- style: { type: "fill", paint: { "fill-color": "CHGRF", "fill-opacity": 0 } }
2627
+ style: { type: "fill", paint: { "fill-color": "CHGRF", "fill-opacity": 0 } },
2628
+ auditIgnore: true
2301
2629
  },
2302
2630
  M_SREL: {
2303
2631
  objectClass: "M_SREL",
2304
2632
  name: "Survey Reliability",
2305
2633
  category: "Meta",
2306
2634
  displayCategory: "META",
2307
- style: { type: "fill", paint: { "fill-color": "CHGRF", "fill-opacity": 0 } }
2635
+ style: { type: "fill", paint: { "fill-color": "CHGRF", "fill-opacity": 0 } },
2636
+ auditIgnore: true
2308
2637
  },
2309
2638
  DSID: {
2310
2639
  objectClass: "DSID",
2311
2640
  name: "Dataset ID",
2312
2641
  category: "Meta",
2313
2642
  displayCategory: "META",
2314
- style: { type: "fill", paint: { "fill-color": "CHGRF", "fill-opacity": 0 } }
2643
+ style: { type: "fill", paint: { "fill-color": "CHGRF", "fill-opacity": 0 } },
2644
+ auditIgnore: true
2315
2645
  }
2316
2646
  };
2317
2647
 
@@ -2324,25 +2654,38 @@ var S52_DRAW_ORDER = [
2324
2654
  "M_NSYS",
2325
2655
  "M_QUAL",
2326
2656
  "M_SREL",
2327
- // 2. Depth areas – deepest first (fill)
2328
- "DEPARE",
2657
+ // 2. Depth areas – broadest first (fill).
2658
+ //
2659
+ // SEAARE goes BEFORE DEPARE so its uniform "deep water" base fill paints
2660
+ // under DEPARE's depth-tier bins. Where DEPARE has coverage, the bin
2661
+ // colour wins on top; where DEPARE doesn't (cross-band coverage gaps —
2662
+ // e.g. between Coastal and Approach cell extents), SEAARE provides a
2663
+ // chart-coloured base instead of the basemap bleeding through. This is
2664
+ // the visual-coherence fix for hard charcoal-vs-vector-blue seams at
2665
+ // scale-band boundaries — see `s52-lookup.ts`'s SEAARE entry for the
2666
+ // paired paint-spec change (fill-opacity 0 → 1, color → DEPDW).
2329
2667
  "SEAARE",
2668
+ "DEPARE",
2330
2669
  // 3. Dredged / swept areas (fill)
2331
2670
  "DRGARE",
2332
2671
  "SWPARE",
2333
2672
  "SBDARE",
2673
+ "WEDKLP",
2334
2674
  // 4. Land (fill)
2335
2675
  "LNDARE",
2676
+ "SLOGRD",
2336
2677
  "BUAARE",
2337
2678
  "LAKARE",
2338
2679
  "RIVERS",
2339
2680
  "CANALS",
2340
2681
  "VEGATN",
2341
2682
  "AIRARE",
2683
+ "RUNWAY",
2342
2684
  // 5. Area hazards (fill)
2343
2685
  "OBSTRN",
2344
2686
  "UWTROC",
2345
2687
  "MARCUL",
2688
+ "FSHFAC",
2346
2689
  // 6. Regulated areas (fill)
2347
2690
  "TESARE",
2348
2691
  "MIPARE",
@@ -2355,6 +2698,7 @@ var S52_DRAW_ORDER = [
2355
2698
  "ACHARE",
2356
2699
  "RESARE",
2357
2700
  "CTNARE",
2701
+ "PRDARE",
2358
2702
  "OSPARE",
2359
2703
  "LOGPON",
2360
2704
  "CBLARE",
@@ -2365,6 +2709,8 @@ var S52_DRAW_ORDER = [
2365
2709
  "DRYDOC",
2366
2710
  "FLODOC",
2367
2711
  "BRIDGE",
2712
+ "PYLONS",
2713
+ "FORSTC",
2368
2714
  // 8. Coastline / shore (line)
2369
2715
  "COALNE",
2370
2716
  "SLCONS",
@@ -2372,6 +2718,11 @@ var S52_DRAW_ORDER = [
2372
2718
  // 9. Depth contours (line)
2373
2719
  "DEPCNT",
2374
2720
  "LNDELV",
2721
+ // 9a. Magnetic-variation isogonic lines (background reference annotations,
2722
+ // drawn above depth contours so the magenta dashes read against the
2723
+ // depth-fill ladder, but below nav lines / nav aids so safety-critical
2724
+ // routing and aids-to-nav win the visual hierarchy).
2725
+ "MAGVAR",
2375
2726
  // 10. Navigation lines (line)
2376
2727
  "NAVLNE",
2377
2728
  "TSSBND",
@@ -2381,6 +2732,7 @@ var S52_DRAW_ORDER = [
2381
2732
  "FERYRT",
2382
2733
  "RECTRC",
2383
2734
  "PIPSOL",
2735
+ "PIPOHD",
2384
2736
  "CBLSUB",
2385
2737
  "CBLOHD",
2386
2738
  "GATCON",
@@ -2423,7 +2775,8 @@ var S52_DRAW_ORDER = [
2423
2775
  "LITFLT",
2424
2776
  "LIGHTS",
2425
2777
  // 13. Hazard points (very top)
2426
- "WRECKS"
2778
+ "WRECKS",
2779
+ "WATTUR"
2427
2780
  ];
2428
2781
  function getDrawPriority(layerName) {
2429
2782
  const idx = S52_DRAW_ORDER.indexOf(layerName);
@@ -2458,9 +2811,22 @@ function depareFillExpression(ct = "DAY") {
2458
2811
  resolveColor("DEPDW", ct)
2459
2812
  ];
2460
2813
  }
2814
+ function colourCodeCase(cases, fallback) {
2815
+ const colourStr = ["to-string", ["coalesce", ["get", "COLOUR"], ["get", "colour"], ""]];
2816
+ const expr = ["case"];
2817
+ for (const [code, value] of cases) {
2818
+ expr.push([">=", ["index-of", `"${code}"`, colourStr], 0], value);
2819
+ }
2820
+ for (const [code, value] of cases) {
2821
+ expr.push(["==", colourStr, code], value);
2822
+ }
2823
+ expr.push(fallback);
2824
+ return expr;
2825
+ }
2461
2826
  function lightColor(props, ct = "DAY") {
2462
- const colour = Number(props.COLOUR ?? props.colour ?? 0);
2463
- switch (colour) {
2827
+ const raw = props.COLOUR ?? props.colour;
2828
+ const code = Array.isArray(raw) ? Number(raw[0]) : typeof raw === "string" && raw.startsWith("[") ? Number(JSON.parse(raw)[0]) : Number(raw ?? 0);
2829
+ switch (code) {
2464
2830
  case 1:
2465
2831
  return resolveColor("LITWT", ct);
2466
2832
  case 3:
@@ -2478,23 +2844,17 @@ function lightColor(props, ct = "DAY") {
2478
2844
  }
2479
2845
  }
2480
2846
  function lightFillExpression(ct = "DAY") {
2481
- return [
2482
- "match",
2483
- ["coalesce", ["get", "COLOUR"], ["get", "colour"], 0],
2484
- 1,
2485
- resolveColor("LITWT", ct),
2486
- 3,
2487
- resolveColor("LITRD", ct),
2488
- 4,
2489
- resolveColor("LITGN", ct),
2490
- 5,
2491
- resolveColor("LITBL", ct),
2492
- 6,
2493
- resolveColor("LITYW", ct),
2494
- 11,
2495
- resolveColor("LITOR", ct),
2847
+ return colourCodeCase(
2848
+ [
2849
+ ["3", resolveColor("LITRD", ct)],
2850
+ ["4", resolveColor("LITGN", ct)],
2851
+ ["6", resolveColor("LITYW", ct)],
2852
+ ["11", resolveColor("LITOR", ct)],
2853
+ ["5", resolveColor("LITBL", ct)],
2854
+ ["1", resolveColor("LITWT", ct)]
2855
+ ],
2496
2856
  resolveColor("LITYW", ct)
2497
- ];
2857
+ );
2498
2858
  }
2499
2859
  function lateralColor(props, ct = "DAY") {
2500
2860
  const catlam = Number(props.CATLAM ?? props.catlam ?? 0);
@@ -2538,9 +2898,54 @@ function hazardFillExpression(ct = "DAY") {
2538
2898
  resolveColor("RESBL", ct)
2539
2899
  ];
2540
2900
  }
2901
+ function vegatnPatternExpression() {
2902
+ return [
2903
+ "match",
2904
+ ["coalesce", ["get", "CATVEG"], ["get", "catveg"], 0],
2905
+ 1,
2906
+ "VEGATN03",
2907
+ // grass
2908
+ 3,
2909
+ "VEGATN03",
2910
+ // bush
2911
+ 4,
2912
+ "VEGATN04",
2913
+ // deciduous wood
2914
+ 5,
2915
+ "VEGATN04",
2916
+ // coniferous wood
2917
+ 6,
2918
+ "VEGATN04",
2919
+ // wood (mixed)
2920
+ 7,
2921
+ "MARSHES1",
2922
+ // mangroves
2923
+ 10,
2924
+ "VEGATN03",
2925
+ // scrub
2926
+ 11,
2927
+ "VEGATN04",
2928
+ // tree
2929
+ 12,
2930
+ "VEGATN04",
2931
+ // evergreen
2932
+ 16,
2933
+ "MARSHES1",
2934
+ // swamp
2935
+ 17,
2936
+ "MARSHES1",
2937
+ // marsh
2938
+ 21,
2939
+ "VEGATN04",
2940
+ // savannah
2941
+ "VEGATN03"
2942
+ // default: grass pattern
2943
+ ];
2944
+ }
2541
2945
  function daymarkColor(props, ct = "DAY") {
2542
- const colour = Number(props.COLOUR ?? props.colour ?? 0);
2543
- switch (colour) {
2946
+ const raw = props.COLOUR ?? props.colour;
2947
+ const code = Array.isArray(raw) ? Number(raw[0]) : typeof raw === "string" && raw.startsWith("[") ? Number(JSON.parse(raw)[0]) : Number(raw ?? 0);
2948
+ switch (code) {
2544
2949
  case 1:
2545
2950
  return resolveColor("LITWT", ct);
2546
2951
  case 3:
@@ -2827,14 +3232,14 @@ function topmarkXShape() {
2827
3232
  }
2828
3233
  function lightMajor() {
2829
3234
  return svg(`
2830
- <circle cx="16" cy="22" r="3" fill="#d200d2"/>
2831
- <path d="M16,22 L12.5,12 Q16,2 19.5,12 Z" fill="#d200d2"/>
3235
+ <circle cx="16" cy="16" r="2.5" fill="#d200d2"/>
3236
+ <path d="M16,16 L20.6,25.5 Q30,30 25.5,20.6 Z" fill="#d200d2"/>
2832
3237
  `);
2833
3238
  }
2834
3239
  function lightMinor() {
2835
3240
  return svg(`
2836
- <circle cx="16" cy="22" r="2.5" fill="#d200d2"/>
2837
- <path d="M16,22 L14,14 Q16,7 18,14 Z" fill="#d200d2"/>
3241
+ <circle cx="16" cy="16" r="2" fill="#d200d2"/>
3242
+ <path d="M16,16 L20.3,23.1 Q26.6,26.6 23.1,20.3 Z" fill="#d200d2"/>
2838
3243
  `);
2839
3244
  }
2840
3245
  function lightSector() {
@@ -4952,6 +5357,7 @@ var SYMBOL_MAP = {
4952
5357
  WRECKS: "WRECKS04",
4953
5358
  OBSTRN: "OBSTRN01",
4954
5359
  UWTROC: "UWTROC03",
5360
+ WATTUR: "WATTUR01",
4955
5361
  // Landmarks
4956
5362
  LNDMRK: "BCNTOW01",
4957
5363
  // Infrastructure
@@ -4964,7 +5370,7 @@ var SYMBOL_MAP = {
4964
5370
  SISTAT: "SISTAT02",
4965
5371
  SMCFAC: "ACHARE02",
4966
5372
  // Land infrastructure
4967
- SILTNK: "BCNTOW01",
5373
+ SILTNK: "TNKCON02",
4968
5374
  BUISGL: "BCNTOW01",
4969
5375
  HRBFAC: "ACHARE02",
4970
5376
  // Areas
@@ -5052,20 +5458,69 @@ function getIconExpression(layerName) {
5052
5458
  // Default: submerged/dangerous
5053
5459
  ];
5054
5460
  }
5461
+ if (layerName === "SILTNK") {
5462
+ const catsil = ["coalesce", ["get", "CATSIL"], ["get", "catsil"], 0];
5463
+ const convis = ["coalesce", ["get", "CONVIS"], ["get", "convis"], 0];
5464
+ return [
5465
+ "case",
5466
+ ["==", convis, 1],
5467
+ [
5468
+ "match",
5469
+ catsil,
5470
+ 1,
5471
+ "SILBUI11",
5472
+ // Silo, conspicuous
5473
+ 2,
5474
+ "TNKCON12",
5475
+ // Tank, conspicuous
5476
+ 3,
5477
+ "TOWERS03",
5478
+ // Grain elevator, conspicuous
5479
+ 4,
5480
+ "TOWERS12",
5481
+ // Water tower, conspicuous
5482
+ "TNKCON12"
5483
+ // CONVIS=1 but no CATSIL → conspicuous tank
5484
+ ],
5485
+ [
5486
+ "match",
5487
+ catsil,
5488
+ 1,
5489
+ "SILBUI01",
5490
+ // Silo
5491
+ 2,
5492
+ "TNKCON02",
5493
+ // Tank
5494
+ 3,
5495
+ "TOWERS01",
5496
+ // Grain elevator
5497
+ 4,
5498
+ "TOWERS02",
5499
+ // Water tower
5500
+ "TNKCON02"
5501
+ // Default: non-conspicuous tank
5502
+ ]
5503
+ ];
5504
+ }
5055
5505
  if (layerName === "LNDMRK") {
5056
5506
  return [
5057
5507
  "match",
5058
5508
  ["coalesce", ["get", "CATLMK"], ["get", "catlmk"], 0],
5059
- // Most LNDMRK types → generic tower beacon (best available S-52 vector)
5060
5509
  1,
5061
5510
  "CAIRNS11",
5062
5511
  // Cairn
5063
5512
  17,
5064
5513
  "BCNTOW01",
5065
- // Spire → tower
5514
+ // Tower
5515
+ 18,
5516
+ "LNDMRK18",
5517
+ // Windmill (4-vane)
5518
+ 19,
5519
+ "LNDMRK19",
5520
+ // Wind motor / turbine (3-blade)
5066
5521
  20,
5067
5522
  "BCNTOW01",
5068
- // Tower
5523
+ // Spire → tower
5069
5524
  "BCNTOW01"
5070
5525
  // Default: tower
5071
5526
  ];
@@ -5140,13 +5595,13 @@ function getIconExpression(layerName) {
5140
5595
  "match",
5141
5596
  ["coalesce", ["get", "WATLEV"], ["get", "watlev"], 0],
5142
5597
  4,
5143
- "UWTROC03",
5144
- // Awash
5598
+ "UWTROC01",
5599
+ // Covers and uncovers — dotted-circle + cross (K11)
5145
5600
  5,
5146
- "UWTROC04",
5147
- // Covers and uncovers
5601
+ "UWTROC03",
5602
+ // Awash at chart datum — solid-circle + cross (K12)
5148
5603
  "UWTROC04"
5149
- // Default: underwater
5604
+ // Default / always submerged — asterisk (K13)
5150
5605
  ];
5151
5606
  }
5152
5607
  if (layerName === "OBSTRN") {
@@ -5185,7 +5640,27 @@ function getIconExpression(layerName) {
5185
5640
  ];
5186
5641
  }
5187
5642
  if (layerName === "BRIDGE") {
5188
- return "BRIDGE01";
5643
+ return [
5644
+ "match",
5645
+ ["coalesce", ["get", "CATBRG"], ["get", "catbrg"], 1],
5646
+ 1,
5647
+ "BRIDGE01",
5648
+ // Fixed bridge (D20)
5649
+ 2,
5650
+ "BRIDGE02",
5651
+ // Opening bridge — generic movable (D21)
5652
+ 3,
5653
+ "BRIDGE03",
5654
+ // Swing bridge (D23.3)
5655
+ 4,
5656
+ "BRIDGE04",
5657
+ // Lifting bridge (D23.1)
5658
+ 5,
5659
+ "BRIDGE05",
5660
+ // Bascule bridge (D23.2)
5661
+ "BRIDGE01"
5662
+ // Default: fixed
5663
+ ];
5189
5664
  }
5190
5665
  if (layerName === "LIGHTS") {
5191
5666
  return [
@@ -5290,7 +5765,7 @@ function scaminToMinZoom(scamin) {
5290
5765
  return void 0;
5291
5766
  }
5292
5767
  var SAFETY_CRITICAL_GROUPS = /* @__PURE__ */ new Set([24020, 27010, 27070, 27080]);
5293
- var OPAQUE_FILL_LAYERS = /* @__PURE__ */ new Set(["DEPARE", "LNDARE", "UNSARE", "LAKARE", "DRGARE"]);
5768
+ var OPAQUE_FILL_LAYERS = /* @__PURE__ */ new Set(["DEPARE", "LNDARE", "UNSARE", "LAKARE", "DRGARE", "SEAARE"]);
5294
5769
  var SCAMIN_OVERRIDE_LAYERS = /* @__PURE__ */ new Set([
5295
5770
  "BOYLAT",
5296
5771
  "BOYCAR",
@@ -5338,6 +5813,8 @@ function resolvePaint(layerName, paint, geomType, ct = "DAY") {
5338
5813
  resolved["circle-color"] = lateralFillExpression(ct);
5339
5814
  } else if ((layerName === "OBSTRN" || layerName === "UWTROC" || layerName === "WRECKS") && geomType === "circle") {
5340
5815
  resolved["circle-color"] = hazardFillExpression(ct);
5816
+ } else if (layerName === "VEGATN" && geomType === "fill") {
5817
+ resolved["fill-pattern"] = vegatnPatternExpression();
5341
5818
  }
5342
5819
  return resolved;
5343
5820
  }
@@ -5358,7 +5835,7 @@ function resolveStyle(layerName, geomKind, ct = "DAY") {
5358
5835
  paint: {},
5359
5836
  layout: {
5360
5837
  "icon-image": iconExpr,
5361
- "icon-size": ["interpolate", ["linear"], ["zoom"], 8, 0.4, 14, 0.8],
5838
+ "icon-size": ["interpolate", ["linear"], ["zoom"], 6, 0.32, 13, 0.32, 14, 0.36, 18, 1.04],
5362
5839
  "icon-allow-overlap": true,
5363
5840
  "icon-ignore-placement": false,
5364
5841
  ...entry.style.layout ?? {}
@@ -5439,13 +5916,200 @@ var COLOUR_ABBR = {
5439
5916
  6: "Y",
5440
5917
  11: "Or"
5441
5918
  };
5919
+ var NATSUR_ABBR = [
5920
+ [1, "M"],
5921
+ // mud
5922
+ [2, "Cy"],
5923
+ // clay
5924
+ [3, "Si"],
5925
+ // silt
5926
+ [4, "S"],
5927
+ // sand
5928
+ [5, "St"],
5929
+ // stones
5930
+ [6, "G"],
5931
+ // gravel
5932
+ [7, "P"],
5933
+ // pebbles
5934
+ [8, "Cb"],
5935
+ // cobbles
5936
+ [9, "R"],
5937
+ // rock
5938
+ [11, "La"],
5939
+ // lava
5940
+ [14, "Co"],
5941
+ // coral
5942
+ [17, "Sh"],
5943
+ // shells
5944
+ [18, "Bo"]
5945
+ // boulder
5946
+ ];
5947
+ var NATQUA_ABBR = [
5948
+ [1, "f"],
5949
+ // fine
5950
+ [2, "m"],
5951
+ // medium
5952
+ [3, "c"],
5953
+ // coarse
5954
+ [4, "bk"],
5955
+ // broken
5956
+ [5, "sy"],
5957
+ // sticky
5958
+ [6, "so"],
5959
+ // soft
5960
+ [7, "sf"],
5961
+ // stiff
5962
+ [8, "v"],
5963
+ // volcanic
5964
+ [9, "ca"],
5965
+ // calcareous
5966
+ [10, "h"]
5967
+ // hard
5968
+ ];
5442
5969
  var DARK_BG = "#1a1d23";
5443
- function getLabelConfig(layerName) {
5970
+ var NAV_AID_LABEL_TEXT_SIZE = [
5971
+ "interpolate",
5972
+ ["linear"],
5973
+ ["zoom"],
5974
+ 10,
5975
+ 8,
5976
+ 14,
5977
+ 10,
5978
+ 18,
5979
+ 13
5980
+ ];
5981
+ var NAV_AID_LABEL_FONT = ["Open Sans Semibold"];
5982
+ function listAttrHasCode(stringified, code) {
5983
+ return [
5984
+ "any",
5985
+ [">=", ["index-of", `"${code}"`, stringified], 0],
5986
+ [
5987
+ ">=",
5988
+ ["index-of", `,${code},`, ["concat", ",", stringified, ","]],
5989
+ 0
5990
+ ]
5991
+ ];
5992
+ }
5993
+ function buildSeabedLabelExpression() {
5994
+ const natsurStr = [
5995
+ "to-string",
5996
+ ["coalesce", ["get", "NATSUR"], ["get", "natsur"], ""]
5997
+ ];
5998
+ const natquaStr = [
5999
+ "to-string",
6000
+ ["coalesce", ["get", "NATQUA"], ["get", "natqua"], ""]
6001
+ ];
6002
+ const natquaPrefix = ["case"];
6003
+ for (const [code, abbr] of NATQUA_ABBR) {
6004
+ natquaPrefix.push(listAttrHasCode(natquaStr, code), abbr);
6005
+ }
6006
+ natquaPrefix.push("");
6007
+ const natsurParts = ["concat"];
6008
+ for (const [code, abbr] of NATSUR_ABBR) {
6009
+ natsurParts.push([
6010
+ "case",
6011
+ listAttrHasCode(natsurStr, code),
6012
+ `.${abbr}`,
6013
+ ""
6014
+ ]);
6015
+ }
6016
+ const natsurJoined = ["slice", natsurParts, 1];
6017
+ return ["concat", natquaPrefix, natsurJoined];
6018
+ }
6019
+ var COLOR = {
6020
+ WATER: "#9ec1d8",
6021
+ WATER_DEEP: "#8fb8d0",
6022
+ LAND_REGION: "#e8d8b8",
6023
+ LAND_NATURAL: "#e0d8c8",
6024
+ CITY: "#f1e7d2",
6025
+ AIRPORT: "#d4c9b0",
6026
+ STRUCTURE: "#bfa88a",
6027
+ STRUCTURE_LIGHT: "#c8c0b0",
6028
+ SOUNDING: "#c8c8c8",
6029
+ NAV_NUMBER: "#ffffff",
6030
+ NAV_CARDINAL: "#fdf0b0",
6031
+ NAV_SPECIAL: "#eab308",
6032
+ LIGHT: "#fdf0b0"
6033
+ };
6034
+ var ORIENTATION_BAND_SORT_KEY = [
6035
+ "to-number",
6036
+ ["slice", ["coalesce", ["get", "_cell_id"], "??9???"], 2, 3],
6037
+ 9
6038
+ ];
6039
+ var LABEL_BEHAVIOR = {
6040
+ // Orientation labels — render once across all bands.
6041
+ SEAARE: "orientation-cross-band",
6042
+ LNDRGN: "orientation-cross-band",
6043
+ LAKARE: "orientation-cross-band",
6044
+ RIVERS: "orientation-cross-band",
6045
+ CANALS: "orientation-cross-band",
6046
+ BUAARE: "orientation-cross-band",
6047
+ AIRARE: "orientation-cross-band",
6048
+ LNDARE: "orientation-cross-band",
6049
+ // Production areas (offshore wind farms, oil/gas platforms) — rare but
6050
+ // named. Use polygon-centroid placement across bands so "Block Island
6051
+ // Wind Farm" / "Vineyard Wind" labels show when the area renders.
6052
+ PRDARE: "orientation-cross-band",
6053
+ // Feature-specific labels — fan by band so only the dominant band shows.
6054
+ SOUNDG: "feature-band-gated",
6055
+ DEPCNT: "feature-band-gated",
6056
+ LIGHTS: "feature-band-gated",
6057
+ BOYLAT: "feature-band-gated",
6058
+ BCNLAT: "feature-band-gated",
6059
+ BOYCAR: "feature-band-gated",
6060
+ BCNCAR: "feature-band-gated",
6061
+ BOYSPP: "feature-band-gated",
6062
+ BCNSPP: "feature-band-gated",
6063
+ BOYISD: "feature-band-gated",
6064
+ BOYSAW: "feature-band-gated",
6065
+ BRIDGE: "feature-band-gated",
6066
+ PILPNT: "feature-band-gated",
6067
+ MORFAC: "feature-band-gated",
6068
+ SLCONS: "feature-band-gated",
6069
+ BUISGL: "feature-band-gated",
6070
+ LNDMRK: "feature-band-gated"
6071
+ };
6072
+ function getLabelBehavior(layerName) {
6073
+ return LABEL_BEHAVIOR[layerName] ?? "feature-band-gated";
6074
+ }
6075
+ function getLabelConfig(layerName, opts = {}) {
5444
6076
  switch (layerName) {
5445
- case "SOUNDG":
6077
+ case "SOUNDG": {
6078
+ const ct = opts.colorTable ?? "DAY";
6079
+ const safetyContour = opts.safetyContour ?? 10;
6080
+ const twoShade = opts.twoShadeSoundings ?? true;
6081
+ const weight = opts.soundingFontWeight ?? "semibold";
6082
+ const screenColors = ct === "DAY" ? { shoaler: DARK_BG, deeper: "#4a5560", halo: "#ffffff" } : { shoaler: resolveColor("SNDG2", ct), deeper: resolveColor("SNDG1", ct), halo: resolveColor("UIBCK", ct) };
6083
+ const depthExpr = [
6084
+ "to-number",
6085
+ ["coalesce", ["get", "depth"], ["get", "DEPTH"], ["get", "VALSOU"]],
6086
+ 9999
6087
+ ];
6088
+ const textColor = twoShade ? [
6089
+ "case",
6090
+ ["<", depthExpr, safetyContour],
6091
+ screenColors.shoaler,
6092
+ screenColors.deeper
6093
+ ] : screenColors.shoaler;
6094
+ const haloColor = screenColors.halo;
6095
+ const fontStack = weight === "semibold" ? ["Open Sans Semibold", "Open Sans Regular"] : ["Open Sans Regular"];
5446
6096
  return {
5447
6097
  type: "symbol",
5448
- textField: ["get", "depth"],
6098
+ // Property name varies by source path:
6099
+ // GeoJSON path → preprocessSoundings adds lowercase `depth` (string)
6100
+ // PMTiles path → baremetal ingest writes uppercase `DEPTH` (number)
6101
+ // raw S-57 → `VALSOU` last-resort fallback
6102
+ textField: [
6103
+ "coalesce",
6104
+ ["get", "depth"],
6105
+ ["get", "DEPTH"],
6106
+ ["get", "VALSOU"]
6107
+ ],
6108
+ // Compact ladder tuned for screen DPI — small but legible against
6109
+ // dense depth-contour fields. 0.5 px halo proved too thin (text
6110
+ // disappeared into contours); 2.0+ px proved too thick (fuzzy
6111
+ // blob). Settled here: 7/8/10/12 across z8/z11/z14/z16 with a
6112
+ // flat 1.0 px halo — enough cut-out for separation without bulk.
5449
6113
  textSize: [
5450
6114
  "interpolate",
5451
6115
  ["linear"],
@@ -5453,39 +6117,67 @@ function getLabelConfig(layerName) {
5453
6117
  8,
5454
6118
  7,
5455
6119
  11,
5456
- 9,
6120
+ 8,
5457
6121
  14,
5458
- 11
6122
+ 10,
6123
+ 16,
6124
+ 12
5459
6125
  ],
5460
- textColor: "#c8c8c8",
5461
- textHaloColor: DARK_BG,
5462
- textHaloWidth: 1.2,
6126
+ textColor,
6127
+ textHaloColor: haloColor,
6128
+ textHaloWidth: 1,
5463
6129
  textOffset: [0, 0],
5464
- textFont: ["Open Sans Regular", "Arial Unicode MS Regular"],
6130
+ textFont: fontStack,
5465
6131
  minzoom: 8,
5466
6132
  layout: {
5467
6133
  "text-anchor": "center",
5468
6134
  "text-allow-overlap": false,
5469
- "text-padding": 5,
6135
+ // Slightly more breathing room around the (now larger) glyphs.
6136
+ "text-padding": 6,
5470
6137
  "text-optional": true,
6138
+ // Small positive tracking opens up dense numerals at small
6139
+ // sizes — established cartographic typography practice.
6140
+ "text-letter-spacing": 0.02,
5471
6141
  // Shallowest-wins: Mapbox GL renders lower sort keys first and
5472
6142
  // gives them collision priority. Using depth directly ensures
5473
6143
  // the shallowest sounding in a cluster is always the one shown,
5474
6144
  // even when labels are hidden due to overlap.
5475
- "symbol-sort-key": ["to-number", ["get", "depth"], 999]
6145
+ "symbol-sort-key": [
6146
+ "to-number",
6147
+ ["coalesce", ["get", "depth"], ["get", "DEPTH"], ["get", "VALSOU"]],
6148
+ 999
6149
+ ]
5476
6150
  }
5477
6151
  };
6152
+ }
5478
6153
  case "LNDRGN":
5479
6154
  return {
5480
6155
  type: "symbol",
5481
6156
  textField: ["get", "OBJNAM"],
5482
- textSize: 11,
5483
- textColor: "#e0d8c8",
6157
+ textSize: [
6158
+ "interpolate",
6159
+ ["linear"],
6160
+ ["zoom"],
6161
+ 8,
6162
+ 10,
6163
+ 12,
6164
+ 12,
6165
+ 15,
6166
+ 14
6167
+ ],
6168
+ textColor: COLOR.LAND_REGION,
5484
6169
  textHaloColor: DARK_BG,
5485
- textHaloWidth: 1.5,
6170
+ textHaloWidth: 1.4,
5486
6171
  textOffset: [0, 0],
5487
- textFont: ["Open Sans Italic", "Arial Unicode MS Regular"],
5488
- minzoom: 9
6172
+ textFont: ["Open Sans Regular"],
6173
+ minzoom: 8,
6174
+ layout: {
6175
+ "text-anchor": "center",
6176
+ "text-allow-overlap": false,
6177
+ "text-padding": 6,
6178
+ "text-optional": true,
6179
+ "symbol-sort-key": ORIENTATION_BAND_SORT_KEY
6180
+ }
5489
6181
  };
5490
6182
  case "LNDMRK":
5491
6183
  return {
@@ -5496,166 +6188,300 @@ function getLabelConfig(layerName) {
5496
6188
  textHaloColor: DARK_BG,
5497
6189
  textHaloWidth: 1.5,
5498
6190
  textOffset: [0, 1.2],
5499
- minzoom: 10
6191
+ minzoom: 9
5500
6192
  };
5501
6193
  case "BOYLAT":
5502
6194
  return {
5503
6195
  type: "symbol",
5504
6196
  textField: ["coalesce", ["get", "_navAidLabel"], ["get", "OBJNAM"]],
5505
- textSize: 8,
5506
- textColor: "#ffffff",
5507
- textHaloColor: DARK_BG,
6197
+ textSize: NAV_AID_LABEL_TEXT_SIZE,
6198
+ textFont: NAV_AID_LABEL_FONT,
6199
+ textColor: DARK_BG,
6200
+ textHaloColor: "#ffffff",
5508
6201
  textHaloWidth: 1.5,
5509
6202
  textOffset: [0, 1.5],
5510
- minzoom: 12
6203
+ minzoom: 10
5511
6204
  };
5512
6205
  case "BCNLAT":
5513
6206
  return {
5514
6207
  type: "symbol",
5515
6208
  textField: ["coalesce", ["get", "_navAidLabel"], ["get", "OBJNAM"]],
5516
- textSize: 8,
5517
- textColor: "#ffffff",
5518
- textHaloColor: DARK_BG,
6209
+ textSize: NAV_AID_LABEL_TEXT_SIZE,
6210
+ textFont: NAV_AID_LABEL_FONT,
6211
+ textColor: DARK_BG,
6212
+ textHaloColor: "#ffffff",
5519
6213
  textHaloWidth: 1.5,
5520
6214
  textOffset: [0, 1.5],
5521
- minzoom: 12
6215
+ minzoom: 10
5522
6216
  };
5523
6217
  case "BOYCAR":
5524
6218
  case "BCNCAR":
5525
6219
  return {
5526
6220
  type: "symbol",
5527
6221
  textField: ["coalesce", ["get", "_navAidLabel"], ["get", "OBJNAM"]],
5528
- textSize: 8,
5529
- textColor: "#fdf0b0",
5530
- textHaloColor: DARK_BG,
6222
+ textSize: NAV_AID_LABEL_TEXT_SIZE,
6223
+ textFont: NAV_AID_LABEL_FONT,
6224
+ textColor: DARK_BG,
6225
+ textHaloColor: "#fdf0b0",
5531
6226
  textHaloWidth: 1.5,
5532
6227
  textOffset: [0, 1.5],
5533
- minzoom: 12
6228
+ minzoom: 10
5534
6229
  };
5535
6230
  case "BOYSPP":
5536
6231
  case "BCNSPP":
5537
6232
  return {
5538
6233
  type: "symbol",
5539
6234
  textField: ["coalesce", ["get", "_navAidLabel"], ["get", "OBJNAM"]],
5540
- textSize: 8,
5541
- textColor: "#eab308",
5542
- textHaloColor: DARK_BG,
6235
+ textSize: NAV_AID_LABEL_TEXT_SIZE,
6236
+ textFont: NAV_AID_LABEL_FONT,
6237
+ textColor: DARK_BG,
6238
+ textHaloColor: "#eab308",
5543
6239
  textHaloWidth: 1.5,
5544
6240
  textOffset: [0, 1.5],
5545
- minzoom: 12
6241
+ minzoom: 10
5546
6242
  };
5547
6243
  case "BOYISD":
5548
6244
  case "BOYSAW":
5549
6245
  return {
5550
6246
  type: "symbol",
5551
6247
  textField: ["coalesce", ["get", "_navAidLabel"], ["get", "OBJNAM"]],
5552
- textSize: 8,
5553
- textColor: "#ffffff",
5554
- textHaloColor: DARK_BG,
6248
+ textSize: NAV_AID_LABEL_TEXT_SIZE,
6249
+ textFont: NAV_AID_LABEL_FONT,
6250
+ textColor: DARK_BG,
6251
+ textHaloColor: "#ffffff",
5555
6252
  textHaloWidth: 1.5,
5556
6253
  textOffset: [0, 1.5],
5557
- minzoom: 12
6254
+ minzoom: 10
5558
6255
  };
5559
6256
  case "LIGHTS":
5560
6257
  return {
5561
6258
  type: "symbol",
5562
6259
  textField: ["get", "_lightLabel"],
5563
- textSize: 8,
5564
- textColor: "#fdf0b0",
5565
- textHaloColor: DARK_BG,
6260
+ textSize: NAV_AID_LABEL_TEXT_SIZE,
6261
+ textFont: NAV_AID_LABEL_FONT,
6262
+ textColor: DARK_BG,
6263
+ textHaloColor: "#fdf0b0",
6264
+ textHaloWidth: 1.5,
6265
+ textOffset: [2, 0],
6266
+ minzoom: 9,
6267
+ layout: {
6268
+ "text-anchor": "left"
6269
+ }
6270
+ };
6271
+ case "FOGSIG": {
6272
+ const catfogExpr = [
6273
+ "match",
6274
+ ["to-number", ["coalesce", ["get", "CATFOG"], 0], 0],
6275
+ 2,
6276
+ "DIA",
6277
+ 3,
6278
+ "SIREN",
6279
+ 4,
6280
+ "NAUTO",
6281
+ 5,
6282
+ "BELL",
6283
+ 6,
6284
+ "WHIS",
6285
+ 7,
6286
+ "REED",
6287
+ 8,
6288
+ "GONG",
6289
+ 9,
6290
+ "HORN",
6291
+ ""
6292
+ ];
6293
+ return {
6294
+ type: "symbol",
6295
+ textField: catfogExpr,
6296
+ textSize: NAV_AID_LABEL_TEXT_SIZE,
6297
+ textFont: NAV_AID_LABEL_FONT,
6298
+ textColor: DARK_BG,
6299
+ textHaloColor: "#b0c8e8",
5566
6300
  textHaloWidth: 1.5,
5567
- textOffset: [1.5, 0],
5568
- minzoom: 11
6301
+ textOffset: [2, 1.2],
6302
+ minzoom: 11,
6303
+ layout: {
6304
+ "text-anchor": "left",
6305
+ "text-allow-overlap": false,
6306
+ "text-optional": true
6307
+ }
5569
6308
  };
6309
+ }
5570
6310
  case "SEAARE":
5571
6311
  return {
5572
6312
  type: "symbol",
5573
6313
  textField: ["get", "OBJNAM"],
5574
- textSize: 13,
5575
- textColor: "#8fb8d0",
6314
+ textSize: [
6315
+ "interpolate",
6316
+ ["linear"],
6317
+ ["zoom"],
6318
+ 5,
6319
+ 11,
6320
+ 8,
6321
+ 13,
6322
+ 11,
6323
+ 15,
6324
+ 14,
6325
+ 17
6326
+ ],
6327
+ textColor: COLOR.WATER_DEEP,
5576
6328
  textHaloColor: DARK_BG,
5577
6329
  textHaloWidth: 1.8,
5578
6330
  textOffset: [0, 0],
5579
- textFont: ["Open Sans Italic", "Arial Unicode MS Regular"],
5580
- minzoom: 6,
6331
+ textFont: ["Open Sans Italic"],
6332
+ minzoom: 5,
5581
6333
  layout: {
5582
6334
  "text-anchor": "center",
5583
6335
  "text-allow-overlap": false,
5584
- "text-padding": 8,
6336
+ "text-padding": 10,
5585
6337
  "text-optional": true,
5586
- "text-letter-spacing": 0.15
6338
+ "text-letter-spacing": 0.15,
6339
+ "text-max-width": 9,
6340
+ "symbol-sort-key": ORIENTATION_BAND_SORT_KEY
5587
6341
  }
5588
6342
  };
5589
6343
  case "LAKARE":
5590
6344
  return {
5591
6345
  type: "symbol",
5592
6346
  textField: ["get", "OBJNAM"],
5593
- textSize: 11,
5594
- textColor: "#8fb8d0",
6347
+ textSize: [
6348
+ "interpolate",
6349
+ ["linear"],
6350
+ ["zoom"],
6351
+ 8,
6352
+ 10,
6353
+ 12,
6354
+ 12,
6355
+ 15,
6356
+ 14
6357
+ ],
6358
+ textColor: COLOR.WATER,
5595
6359
  textHaloColor: DARK_BG,
5596
6360
  textHaloWidth: 1.5,
5597
6361
  textOffset: [0, 0],
5598
- textFont: ["Open Sans Italic", "Arial Unicode MS Regular"],
5599
- minzoom: 9,
6362
+ textFont: ["Open Sans Italic"],
6363
+ minzoom: 8,
5600
6364
  layout: {
5601
6365
  "text-anchor": "center",
5602
6366
  "text-allow-overlap": false,
5603
6367
  "text-padding": 6,
5604
- "text-optional": true
6368
+ "text-optional": true,
6369
+ "symbol-sort-key": ORIENTATION_BAND_SORT_KEY
5605
6370
  }
5606
6371
  };
5607
6372
  case "RIVERS":
5608
6373
  return {
5609
6374
  type: "symbol",
5610
6375
  textField: ["get", "OBJNAM"],
5611
- textSize: 10,
5612
- textColor: "#8fb8d0",
6376
+ textSize: [
6377
+ "interpolate",
6378
+ ["linear"],
6379
+ ["zoom"],
6380
+ 9,
6381
+ 9,
6382
+ 12,
6383
+ 11,
6384
+ 15,
6385
+ 13
6386
+ ],
6387
+ textColor: COLOR.WATER,
5613
6388
  textHaloColor: DARK_BG,
5614
- textHaloWidth: 1.5,
6389
+ textHaloWidth: 1.4,
5615
6390
  textOffset: [0, 0],
5616
- textFont: ["Open Sans Italic", "Arial Unicode MS Regular"],
5617
- minzoom: 10,
6391
+ textFont: ["Open Sans Italic"],
6392
+ minzoom: 9,
5618
6393
  layout: {
5619
6394
  "text-anchor": "center",
5620
6395
  "text-allow-overlap": false,
5621
6396
  "text-padding": 4,
5622
- "text-optional": true
6397
+ "text-optional": true,
6398
+ "symbol-sort-key": ORIENTATION_BAND_SORT_KEY
5623
6399
  }
5624
6400
  };
5625
6401
  case "CANALS":
5626
6402
  return {
5627
6403
  type: "symbol",
5628
6404
  textField: ["get", "OBJNAM"],
5629
- textSize: 9,
5630
- textColor: "#8fb8d0",
6405
+ textSize: [
6406
+ "interpolate",
6407
+ ["linear"],
6408
+ ["zoom"],
6409
+ 11,
6410
+ 9,
6411
+ 14,
6412
+ 11
6413
+ ],
6414
+ textColor: COLOR.WATER,
5631
6415
  textHaloColor: DARK_BG,
5632
- textHaloWidth: 1.5,
6416
+ textHaloWidth: 1.3,
5633
6417
  textOffset: [0, 0],
5634
- textFont: ["Open Sans Italic", "Arial Unicode MS Regular"],
6418
+ textFont: ["Open Sans Italic"],
5635
6419
  minzoom: 11,
5636
6420
  layout: {
5637
6421
  "text-anchor": "center",
5638
6422
  "text-allow-overlap": false,
5639
6423
  "text-padding": 4,
5640
- "text-optional": true
6424
+ "text-optional": true,
6425
+ "symbol-sort-key": ORIENTATION_BAND_SORT_KEY
5641
6426
  }
5642
6427
  };
5643
6428
  case "LNDARE":
5644
6429
  return {
5645
6430
  type: "symbol",
5646
6431
  textField: ["get", "OBJNAM"],
5647
- textSize: 10,
5648
- textColor: "#e0d8c8",
6432
+ textSize: [
6433
+ "interpolate",
6434
+ ["linear"],
6435
+ ["zoom"],
6436
+ 8,
6437
+ 9,
6438
+ 12,
6439
+ 11,
6440
+ 15,
6441
+ 13
6442
+ ],
6443
+ textColor: COLOR.LAND_NATURAL,
5649
6444
  textHaloColor: DARK_BG,
5650
- textHaloWidth: 1.5,
6445
+ textHaloWidth: 1.4,
5651
6446
  textOffset: [0, 0],
5652
- textFont: ["Open Sans Regular", "Arial Unicode MS Regular"],
5653
- minzoom: 10,
6447
+ textFont: ["Open Sans Regular"],
6448
+ minzoom: 8,
5654
6449
  layout: {
5655
6450
  "text-anchor": "center",
5656
6451
  "text-allow-overlap": false,
5657
6452
  "text-padding": 6,
5658
- "text-optional": true
6453
+ "text-optional": true,
6454
+ "symbol-sort-key": ORIENTATION_BAND_SORT_KEY
6455
+ }
6456
+ };
6457
+ case "BUAARE":
6458
+ return {
6459
+ type: "symbol",
6460
+ textField: ["get", "OBJNAM"],
6461
+ textSize: [
6462
+ "interpolate",
6463
+ ["linear"],
6464
+ ["zoom"],
6465
+ 7,
6466
+ 11,
6467
+ 10,
6468
+ 13,
6469
+ 13,
6470
+ 15
6471
+ ],
6472
+ textColor: COLOR.CITY,
6473
+ textHaloColor: DARK_BG,
6474
+ textHaloWidth: 1.6,
6475
+ textOffset: [0, 0],
6476
+ textFont: ["Open Sans Regular"],
6477
+ minzoom: 7,
6478
+ layout: {
6479
+ "text-anchor": "center",
6480
+ "text-allow-overlap": false,
6481
+ "text-padding": 8,
6482
+ "text-optional": true,
6483
+ "text-letter-spacing": 0.05,
6484
+ "symbol-sort-key": ORIENTATION_BAND_SORT_KEY
5659
6485
  }
5660
6486
  };
5661
6487
  case "BRIDGE":
@@ -5729,19 +6555,236 @@ function getLabelConfig(layerName) {
5729
6555
  return {
5730
6556
  type: "symbol",
5731
6557
  textField: ["get", "OBJNAM"],
5732
- textSize: 10,
5733
- textColor: "#d4c9b0",
6558
+ textSize: [
6559
+ "interpolate",
6560
+ ["linear"],
6561
+ ["zoom"],
6562
+ 9,
6563
+ 9,
6564
+ 13,
6565
+ 11
6566
+ ],
6567
+ textColor: COLOR.AIRPORT,
5734
6568
  textHaloColor: DARK_BG,
5735
- textHaloWidth: 1.5,
6569
+ textHaloWidth: 1.4,
6570
+ textOffset: [0, 0],
6571
+ textFont: ["Open Sans Regular"],
6572
+ minzoom: 9,
6573
+ layout: {
6574
+ "text-anchor": "center",
6575
+ "text-allow-overlap": false,
6576
+ "text-padding": 5,
6577
+ "text-optional": true,
6578
+ "symbol-sort-key": ORIENTATION_BAND_SORT_KEY
6579
+ }
6580
+ };
6581
+ case "SBDARE":
6582
+ return {
6583
+ type: "symbol",
6584
+ textField: buildSeabedLabelExpression(),
6585
+ textSize: [
6586
+ "interpolate",
6587
+ ["linear"],
6588
+ ["zoom"],
6589
+ 12,
6590
+ 9,
6591
+ 16,
6592
+ 11
6593
+ ],
6594
+ textColor: COLOR.SOUNDING,
6595
+ textHaloColor: DARK_BG,
6596
+ textHaloWidth: 1,
6597
+ textOffset: [0, 0],
6598
+ textFont: ["Open Sans Italic"],
6599
+ minzoom: 12,
6600
+ layout: {
6601
+ "symbol-placement": "point",
6602
+ "text-anchor": "center",
6603
+ "text-allow-overlap": false,
6604
+ "text-padding": 4,
6605
+ "text-optional": true,
6606
+ "text-letter-spacing": 0.02
6607
+ }
6608
+ };
6609
+ case "MAGVAR": {
6610
+ const valmag = ["coalesce", ["get", "VALMAG"], 0];
6611
+ const variationText = [
6612
+ "case",
6613
+ [">=", valmag, 0],
6614
+ ["concat", ["to-string", ["floor", valmag]], "\xB0E"],
6615
+ ["concat", ["to-string", ["floor", ["abs", valmag]]], "\xB0W"]
6616
+ ];
6617
+ return {
6618
+ type: "symbol",
6619
+ textField: variationText,
6620
+ textSize: [
6621
+ "interpolate",
6622
+ ["linear"],
6623
+ ["zoom"],
6624
+ 10,
6625
+ 9,
6626
+ 14,
6627
+ 11
6628
+ ],
6629
+ textColor: COLOR.SOUNDING,
6630
+ textHaloColor: DARK_BG,
6631
+ textHaloWidth: 1,
5736
6632
  textOffset: [0, 0],
6633
+ textFont: ["Open Sans Italic"],
5737
6634
  minzoom: 10,
5738
6635
  layout: {
6636
+ "symbol-placement": "point",
5739
6637
  "text-anchor": "center",
5740
6638
  "text-allow-overlap": false,
5741
6639
  "text-padding": 6,
5742
- "text-optional": true
6640
+ "text-optional": true,
6641
+ "text-letter-spacing": 0.02
6642
+ }
6643
+ };
6644
+ }
6645
+ case "PRDARE":
6646
+ return {
6647
+ type: "symbol",
6648
+ textField: ["get", "OBJNAM"],
6649
+ textSize: [
6650
+ "interpolate",
6651
+ ["linear"],
6652
+ ["zoom"],
6653
+ 8,
6654
+ 10,
6655
+ 12,
6656
+ 12,
6657
+ 15,
6658
+ 14
6659
+ ],
6660
+ textColor: "#c545c3",
6661
+ textHaloColor: DARK_BG,
6662
+ textHaloWidth: 1.4,
6663
+ textOffset: [0, 0],
6664
+ textFont: ["Open Sans Italic"],
6665
+ minzoom: 8,
6666
+ layout: {
6667
+ "text-anchor": "center",
6668
+ "text-allow-overlap": false,
6669
+ "text-padding": 6,
6670
+ "text-optional": true,
6671
+ "symbol-sort-key": ORIENTATION_BAND_SORT_KEY
6672
+ }
6673
+ };
6674
+ case "WEDKLP":
6675
+ return {
6676
+ type: "symbol",
6677
+ textField: "Wd",
6678
+ textSize: [
6679
+ "interpolate",
6680
+ ["linear"],
6681
+ ["zoom"],
6682
+ 12,
6683
+ 9,
6684
+ 16,
6685
+ 11
6686
+ ],
6687
+ textColor: "#3f8a34",
6688
+ textHaloColor: DARK_BG,
6689
+ textHaloWidth: 1,
6690
+ textOffset: [0, 0],
6691
+ textFont: ["Open Sans Italic"],
6692
+ minzoom: 12,
6693
+ layout: {
6694
+ "symbol-placement": "point",
6695
+ "text-anchor": "center",
6696
+ "text-allow-overlap": false,
6697
+ "text-padding": 4,
6698
+ "text-optional": true,
6699
+ "text-letter-spacing": 0.02
6700
+ }
6701
+ };
6702
+ case "UWTROC":
6703
+ case "OBSTRN":
6704
+ case "WRECKS": {
6705
+ const ct = opts.colorTable ?? "DAY";
6706
+ const valsou = [
6707
+ "to-number",
6708
+ ["coalesce", ["get", "VALSOU"], ["get", "valsou"], 0],
6709
+ 0
6710
+ ];
6711
+ return {
6712
+ type: "symbol",
6713
+ textField: [
6714
+ "case",
6715
+ [">", valsou, 0],
6716
+ [
6717
+ "concat",
6718
+ ["to-string", ["/", ["round", ["*", valsou, 10]], 10]],
6719
+ "m"
6720
+ ],
6721
+ ""
6722
+ ],
6723
+ textSize: [
6724
+ "interpolate",
6725
+ ["linear"],
6726
+ ["zoom"],
6727
+ 12,
6728
+ 9,
6729
+ 16,
6730
+ 11
6731
+ ],
6732
+ textColor: resolveColor("CHBLK", ct),
6733
+ textHaloColor: resolveColor("CHWHT", ct),
6734
+ textHaloWidth: 1.2,
6735
+ // Place to the upper-right of the symbol so it doesn't sit on top
6736
+ // of the asterisk / cross. Anchor top-left so the offset grows
6737
+ // away from the symbol as text-size grows.
6738
+ textOffset: [0.8, -0.4],
6739
+ textFont: ["Open Sans Regular"],
6740
+ minzoom: 12,
6741
+ layout: {
6742
+ "text-anchor": "top-left",
6743
+ "text-allow-overlap": false,
6744
+ "text-optional": true,
6745
+ "text-padding": 2
6746
+ }
6747
+ };
6748
+ }
6749
+ case "CBLOHD":
6750
+ case "PIPOHD": {
6751
+ const isCBL = layerName === "CBLOHD";
6752
+ return {
6753
+ type: "symbol",
6754
+ textField: [
6755
+ "case",
6756
+ ["has", "VERCLR"],
6757
+ ["concat", ["to-string", ["get", "VERCLR"]], "m"],
6758
+ ""
6759
+ ],
6760
+ textSize: [
6761
+ "interpolate",
6762
+ ["linear"],
6763
+ ["zoom"],
6764
+ 11,
6765
+ 8,
6766
+ 14,
6767
+ 10,
6768
+ 17,
6769
+ 11
6770
+ ],
6771
+ textColor: isCBL ? "#c545c3" : "#7fbf3f",
6772
+ textHaloColor: DARK_BG,
6773
+ textHaloWidth: 1.4,
6774
+ textOffset: [0, 0],
6775
+ textFont: ["Open Sans Regular"],
6776
+ minzoom: 11,
6777
+ layout: {
6778
+ "symbol-placement": "line",
6779
+ "text-anchor": "center",
6780
+ "symbol-spacing": 250,
6781
+ "text-rotation-alignment": "map",
6782
+ "text-allow-overlap": false,
6783
+ "text-optional": true,
6784
+ "text-letter-spacing": 0.02
5743
6785
  }
5744
6786
  };
6787
+ }
5745
6788
  case "DEPCNT":
5746
6789
  return {
5747
6790
  type: "symbol",
@@ -5755,12 +6798,12 @@ function getLabelConfig(layerName) {
5755
6798
  14,
5756
6799
  10
5757
6800
  ],
5758
- textColor: "#c8c8c8",
5759
- textHaloColor: DARK_BG,
6801
+ textColor: DARK_BG,
6802
+ textHaloColor: "#c8c8c8",
5760
6803
  textHaloWidth: 1.2,
5761
6804
  textOffset: [0, 0],
5762
- textFont: ["Open Sans Regular", "Arial Unicode MS Regular"],
5763
- minzoom: 10,
6805
+ textFont: ["Open Sans Regular"],
6806
+ minzoom: 9,
5764
6807
  layout: {
5765
6808
  "symbol-placement": "line",
5766
6809
  "text-anchor": "center",
@@ -5791,7 +6834,7 @@ function buildLabelLayer(layerId, sourceId, config, visible, overrides) {
5791
6834
  visibility: visible ? "visible" : "none",
5792
6835
  "text-field": config.textField,
5793
6836
  "text-size": textSize,
5794
- "text-font": config.textFont ?? ["Open Sans Regular", "Arial Unicode MS Regular"],
6837
+ "text-font": config.textFont ?? ["Open Sans Regular"],
5795
6838
  "text-offset": config.textOffset,
5796
6839
  "text-anchor": "top",
5797
6840
  "text-allow-overlap": overrides?.allowOverlap ?? false,
@@ -5874,6 +6917,7 @@ var LABELED_LAYERS = /* @__PURE__ */ new Set([
5874
6917
  "LNDRGN",
5875
6918
  "LNDMRK",
5876
6919
  "LNDARE",
6920
+ "BUAARE",
5877
6921
  "BOYLAT",
5878
6922
  "BCNLAT",
5879
6923
  "BOYCAR",
@@ -5883,6 +6927,7 @@ var LABELED_LAYERS = /* @__PURE__ */ new Set([
5883
6927
  "BCNCAR",
5884
6928
  "BCNSPP",
5885
6929
  "LIGHTS",
6930
+ "FOGSIG",
5886
6931
  "SEAARE",
5887
6932
  "LAKARE",
5888
6933
  "RIVERS",
@@ -5893,7 +6938,16 @@ var LABELED_LAYERS = /* @__PURE__ */ new Set([
5893
6938
  "SLCONS",
5894
6939
  "BUISGL",
5895
6940
  "AIRARE",
5896
- "DEPCNT"
6941
+ "DEPCNT",
6942
+ "SBDARE",
6943
+ "MAGVAR",
6944
+ "PRDARE",
6945
+ "WEDKLP",
6946
+ "UWTROC",
6947
+ "OBSTRN",
6948
+ "WRECKS",
6949
+ "CBLOHD",
6950
+ "PIPOHD"
5897
6951
  ]);
5898
6952
  var NAV_AID_LABEL_LAYERS = /* @__PURE__ */ new Set([
5899
6953
  "BOYLAT",
@@ -7209,7 +8263,7 @@ var S52_POINT_SVGS = {
7209
8263
  "BOYDEF03": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 21.8 10.8 L 22.4 9.6 L 22.9 8.6 L 23.6 7.9 L 24.3 7.2 L 25.4 6.8 L 26.4 6.9 L 27.6 7.2 L 28.8 7.5 L 29.8 8.9 L 30.5 9.7 L 31.0 10.6 L 31.0 11.7 L 30.5 12.7 L 30.0 13.5 L 29.1 14.5 L 28.2 15.6 L 27.3 16.6 L 26.8 17.4 L 26.3 18.1 L 26.2 19.1 L 26.2 20.0 L 26.2 20.7 L 26.3 21.6 L 26.3 21.7" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 25.4 25.2 L 27.6 25.2" fill="none" stroke="CHMGD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <circle cx="9.45" cy="16.19" r="8.45" fill="none" stroke="CHGRD" stroke-width="0.8" />\n <path d="M 9.4 16.2 Z" fill="CHGRD" />\n <circle cx="9.45" cy="16.19" r="8.45" fill="none" stroke="OUTLW" stroke-width="0.8" />\n <circle cx="9.45" cy="16.19" r="0.62" fill="none" stroke="OUTLW" stroke-width="0.8" />\n <path d="M 9.4 16.2 Z" fill="OUTLW" />\n</svg>\n',
7210
8264
  "BOYGEN03": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 22.4 10.5 L 22.9 9.4 L 23.4 8.4 L 24.1 7.7 L 24.7 7.1 L 25.7 6.7 L 26.6 6.8 L 27.8 7.1 L 28.9 7.4 L 29.8 8.7 L 30.5 9.5 L 31.0 10.3 L 31.0 11.3 L 30.5 12.2 L 30.0 13.1 L 29.2 14.0 L 28.3 15.0 L 27.5 16.0 L 27.0 16.7 L 26.6 17.4 L 26.5 18.3 L 26.5 19.2 L 26.5 19.8 L 26.6 20.7 L 26.6 20.8" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 25.7 24.1 L 27.8 24.1" fill="none" stroke="CHMGD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <circle cx="11.24" cy="14.16" r="6.78" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <circle cx="11.31" cy="23.14" r="2.16" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <path d="M 13.5 23.1 L 21.6 23.1" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 23.1 L 9.1 23.1" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7211
8265
  "BOYINB01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.02" cy="22.46" r="2.28" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <circle cx="16.02" cy="9.75" r="2.49" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <path d="M 1.0 22.5 L 13.6 22.5" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 18.1 22.5 L 31.0 22.5" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 2.6 22.5 L 6.0 12.5 L 26.0 12.5 L 29.4 22.5" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7212
- "BOYISD12": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="20.52" cy="7.07" r="6.07" fill="none" stroke="CHRED" stroke-width="0.8" />\n <path d="M 20.5 7.1 Z" fill="CHRED" />\n <circle cx="11.48" cy="24.93" r="6.07" fill="none" stroke="CHRED" stroke-width="0.8" />\n <path d="M 11.5 24.9 Z" fill="CHRED" />\n <circle cx="20.52" cy="7.07" r="6.07" fill="none" stroke="OUTLW" stroke-width="0.8" />\n <circle cx="11.48" cy="24.93" r="6.07" fill="none" stroke="OUTLW" stroke-width="0.8" />\n</svg>\n',
8266
+ "BOYISD12": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 27.0 L 12.5 27.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" />\n <path d="M 19.5 27.0 L 31.0 27.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" />\n <path d="M 10.5 27.0 L 12.5 15.0 L 19.5 15.0 L 21.5 27.0 Z" fill="CHBLK" stroke="CHBLK" stroke-width="0.8" stroke-linejoin="round" />\n <rect x="11.4" y="19.0" width="9.2" height="3.5" fill="LITRD" />\n <line x1="16" y1="15.0" x2="16" y2="11.0" stroke="CHBLK" stroke-width="0.8" />\n <circle cx="16" cy="8.5" r="2.0" fill="CHBLK" />\n <circle cx="16" cy="3.5" r="2.0" fill="CHBLK" />\n</svg>\n',
7213
8267
  "BOYLAT13": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 30.8 31.0 L 30.8 1.0 L 1.2 31.0 L 30.8 31.0 Z" fill="CHGRN" />\n <path d="M 30.8 31.0 L 30.8 1.0 L 1.2 31.0 L 30.8 31.0" fill="none" stroke="CHGRN" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 30.8 31.0 L 30.8 1.0 L 1.2 31.0 L 30.8 31.0" fill="none" stroke="OUTLW" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <circle cx="22.32" cy="21.30" r="1.03" fill="none" stroke="OUTLW" stroke-width="0.8" />\n <path d="M 22.3 21.3 Z" fill="OUTLW" />\n</svg>\n',
7214
8268
  "BOYLAT14": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 30.8 31.0 L 30.8 1.0 L 1.2 31.0 L 30.8 31.0 Z" fill="CHRED" />\n <path d="M 30.8 31.0 L 30.8 1.0 L 1.2 31.0 L 30.8 31.0" fill="none" stroke="CHRED" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 30.8 31.0 L 30.8 1.0 L 1.2 31.0 L 30.8 31.0" fill="none" stroke="OUTLW" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <circle cx="22.32" cy="21.30" r="1.03" fill="none" stroke="OUTLW" stroke-width="0.8" />\n <path d="M 22.3 21.3 Z" fill="OUTLW" />\n</svg>\n',
7215
8269
  "BOYLAT23": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 27.3 L 9.6 4.7 L 31.0 4.7 L 23.8 27.3 L 1.0 27.3 Z" fill="CHGRN" />\n <path d="M 1.0 27.3 L 9.6 4.7 L 31.0 4.7 L 23.8 27.3 L 1.0 27.3" fill="none" stroke="CHGRN" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 27.3 L 9.6 4.7 L 31.0 4.7 L 23.8 27.3 L 1.0 27.3" fill="none" stroke="OUTLW" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <circle cx="16.63" cy="15.52" r="0.85" fill="none" stroke="OUTLW" stroke-width="0.8" />\n <path d="M 16.6 15.5 Z" fill="OUTLW" />\n</svg>\n',
@@ -7220,7 +8274,7 @@ var S52_POINT_SVGS = {
7220
8274
  "BOYMOR03": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="14.88" cy="26.37" r="3.17" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <circle cx="19.41" cy="6.11" r="3.65" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <path d="M 1.0 26.4 L 11.5 26.4" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 17.8 26.4 L 28.7 26.4" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 3.3 26.4 L 7.9 10.2 L 31.0 10.2 L 26.6 26.4" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7221
8275
  "BOYMOR11": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.30" cy="11.89" r="2.81" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <path d="M 16.3 11.9 Z" fill="CHBLK" />\n <path d="M 1.0 22.9 L 3.6 15.1 L 28.4 15.1 L 31.0 22.9 L 1.0 22.9 Z" fill="CHBLK" />\n <path d="M 1.0 22.9 L 3.6 15.1 L 28.4 15.1 L 31.0 22.9 L 1.0 22.9" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7222
8276
  "BOYPIL01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.43" cy="25.37" r="2.96" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <path d="M 1.0 25.4 L 13.6 25.4" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 19.1 25.4 L 31.0 25.4" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 4.3 25.4 L 15.3 13.6 L 18.6 3.7 L 23.5 3.7 L 23.5 15.6 L 28.2 25.4" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7223
- "BOYSAW12": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="14.78" fill="none" stroke="CHRED" stroke-width="0.8" />\n <path d="M 16.0 16.0 Z" fill="CHRED" />\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="OUTLW" stroke-width="0.8" />\n <circle cx="16.00" cy="16.00" r="1.11" fill="none" stroke="OUTLW" stroke-width="0.8" />\n <path d="M 16.0 16.0 Z" fill="OUTLW" />\n</svg>\n',
8277
+ "BOYSAW12": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 27.0 L 12.5 27.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" />\n <path d="M 19.5 27.0 L 31.0 27.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" />\n <path d="M 10.5 27.0 L 12.5 14.0 L 19.5 14.0 L 21.5 27.0 Z" fill="LITWT" stroke="CHBLK" stroke-width="0.8" stroke-linejoin="round" />\n <rect x="13.2" y="14.0" width="2.0" height="13.0" fill="LITRD" />\n <rect x="16.8" y="14.0" width="2.0" height="13.0" fill="LITRD" />\n <line x1="16" y1="14.0" x2="16" y2="8.0" stroke="CHBLK" stroke-width="0.8" />\n <circle cx="16" cy="5.5" r="2.5" fill="LITRD" stroke="CHBLK" stroke-width="0.6" />\n</svg>\n',
7224
8278
  "BOYSPH01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="15.76" cy="26.22" r="2.81" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <path d="M 18.7 26.2 L 31.0 26.2" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 4.1 26.2 L 2.6 22.6 L 2.2 19.6 L 1.8 16.4 L 2.5 12.9 L 3.5 10.5 L 5.3 8.1 L 7.3 6.1 L 9.8 4.5 L 12.1 3.7 L 14.9 3.0 L 17.9 3.0 L 20.9 3.7 L 24.2 5.1 L 26.4 6.8 L 27.9 9.0 L 29.7 11.8 L 30.7 14.6 L 30.8 17.7 L 30.5 21.5 L 29.4 24.2 L 28.3 26.2" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 26.2 L 12.9 26.2" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7225
8279
  "BOYSPP11": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="CHYLW" stroke-width="0.8" />\n <path d="M 16.0 16.0 Z" fill="CHYLW" />\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="OUTLW" stroke-width="0.8" />\n <circle cx="16.00" cy="16.00" r="1.13" fill="none" stroke="OUTLW" stroke-width="0.8" />\n <path d="M 16.0 16.0 Z" fill="OUTLW" />\n</svg>\n',
7226
8280
  "BOYSPP15": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 30.8 31.0 L 30.8 1.0 L 1.2 31.0 L 30.8 31.0 Z" fill="CHYLW" />\n <path d="M 30.8 31.0 L 30.8 1.0 L 1.2 31.0 L 30.8 31.0" fill="none" stroke="CHYLW" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 30.8 31.0 L 30.8 1.0 L 1.2 31.0 L 30.8 31.0" fill="none" stroke="OUTLW" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <circle cx="20.95" cy="21.30" r="1.03" fill="none" stroke="OUTLW" stroke-width="0.8" />\n <path d="M 21.0 21.3 Z" fill="OUTLW" />\n</svg>\n',
@@ -7229,7 +8283,11 @@ var S52_POINT_SVGS = {
7229
8283
  "BOYSUP01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.02" cy="23.18" r="2.28" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <path d="M 1.0 23.2 L 13.6 23.2" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 18.1 23.2 L 31.0 23.2" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 2.6 23.2 L 6.0 13.2 L 26.0 13.2 L 29.4 23.2" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.0 13.2 L 16.0 6.5" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7230
8284
  "BOYSUP02": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.1 25.3 L 4.9 14.1 L 27.2 14.1 L 31.0 25.3" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.1 14.1 L 16.1 6.7" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 25.2 L 4.9 14.0 L 27.2 14.1 L 31.0 25.2 L 1.0 25.2 Z" fill="CHBLK" />\n <path d="M 1.0 25.2 L 4.9 14.0 L 27.2 14.1 L 31.0 25.2 L 1.0 25.2" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7231
8285
  "BOYSUP03": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.12" cy="24.98" r="2.07" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <path d="M 16.1 9.9 L 16.1 5.0" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 12.7 6.6 L 19.3 9.9" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 12.7 9.9 L 19.3 6.6" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 25.0 L 14.0 25.0" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 18.0 25.0 L 31.0 25.0" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 2.6 25.0 L 6.0 14.9 L 26.0 14.9 L 29.4 25.0" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.1 14.9 L 16.1 8.0" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7232
- "BRIDGE01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="CHMGD" stroke-width="0.8" />\n <circle cx="16.07" cy="15.70" r="8.63" fill="none" stroke="CHMGD" stroke-width="0.8" />\n</svg>\n',
8286
+ "BRIDGE01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <line x1="4" y1="14" x2="28" y2="14" stroke="CHBLK" stroke-width="2" />\n <line x1="8" y1="14" x2="8" y2="24" stroke="CHBLK" stroke-width="1.8" />\n <line x1="24" y1="14" x2="24" y2="24" stroke="CHBLK" stroke-width="1.8" />\n <path d="M8,14 Q16,6 24,14" fill="none" stroke="CHBLK" stroke-width="1.5" />\n</svg>\n',
8287
+ "BRIDGE02": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <line x1="4" y1="14" x2="28" y2="14" stroke="CHBLK" stroke-width="2" />\n <line x1="8" y1="14" x2="8" y2="24" stroke="CHBLK" stroke-width="1.8" />\n <line x1="24" y1="14" x2="24" y2="24" stroke="CHBLK" stroke-width="1.8" />\n <path d="M8,14 Q16,6 24,14" fill="none" stroke="TRFCD" stroke-width="1.5" stroke-dasharray="3,2" />\n</svg>\n',
8288
+ "BRIDGE03": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <line x1="4" y1="14" x2="28" y2="14" stroke="CHBLK" stroke-width="2" />\n <line x1="8" y1="14" x2="8" y2="24" stroke="CHBLK" stroke-width="1.8" />\n <line x1="24" y1="14" x2="24" y2="24" stroke="CHBLK" stroke-width="1.8" />\n <circle cx="16" cy="14" r="3" fill="none" stroke="TRFCD" stroke-width="1.5" />\n <circle cx="16" cy="14" r="1" fill="TRFCD" />\n</svg>\n',
8289
+ "BRIDGE04": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <line x1="4" y1="16" x2="28" y2="16" stroke="CHBLK" stroke-width="2" />\n <line x1="8" y1="16" x2="8" y2="24" stroke="CHBLK" stroke-width="1.8" />\n <line x1="24" y1="16" x2="24" y2="24" stroke="CHBLK" stroke-width="1.8" />\n <line x1="12" y1="16" x2="12" y2="6" stroke="TRFCD" stroke-width="1.5" />\n <polygon points="12,4 9,8 15,8" fill="TRFCD" />\n <line x1="20" y1="16" x2="20" y2="6" stroke="TRFCD" stroke-width="1.5" />\n <polygon points="20,4 17,8 23,8" fill="TRFCD" />\n</svg>\n',
8290
+ "BRIDGE05": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <line x1="4" y1="14" x2="28" y2="14" stroke="CHBLK" stroke-width="2" />\n <line x1="8" y1="14" x2="8" y2="24" stroke="CHBLK" stroke-width="1.8" />\n <line x1="24" y1="14" x2="24" y2="24" stroke="CHBLK" stroke-width="1.8" />\n <line x1="14" y1="14" x2="20" y2="6" stroke="TRFCD" stroke-width="2" />\n <circle cx="14" cy="14" r="1.5" fill="TRFCD" />\n</svg>\n',
7233
8291
  "BRTHNO01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="CHMGD" stroke-width="0.8" />\n</svg>\n',
7234
8292
  "BUAARE02": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="LANDF" stroke-width="0.8" />\n <path d="M 16.0 16.0 Z" fill="LANDF" />\n</svg>\n',
7235
8293
  "BUIREL01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 8.5 1.0 L 23.5 1.0 L 16.0 8.5 L 8.5 1.0 Z" fill="LANDF" />\n <path d="M 8.5 1.0 L 23.5 1.0 L 16.0 8.5 L 8.5 1.0" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 31.0 8.5 L 31.0 23.5 L 23.5 16.0 L 31.0 8.5 Z" fill="LANDF" />\n <path d="M 31.0 8.5 L 31.0 23.5 L 23.5 16.0 L 31.0 8.5" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 8.5 31.0 L 23.5 31.0 L 16.0 23.5 L 8.5 31.0 Z" fill="LANDF" />\n <path d="M 8.5 31.0 L 23.5 31.0 L 16.0 23.5 L 8.5 31.0" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 8.5 L 1.0 23.5 L 8.5 16.0 L 1.0 8.5 Z" fill="LANDF" />\n <path d="M 1.0 8.5 L 1.0 23.5 L 8.5 16.0 L 1.0 8.5" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 8.5 16.0 L 23.5 16.0" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.0 8.5 L 16.0 23.5" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 8.5 1.0 L 23.5 1.0 L 16.0 8.5 L 8.5 1.0" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 31.0 8.5 L 31.0 23.5 L 23.5 16.0 L 31.0 8.5" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 23.5 31.0 L 8.5 31.0 L 16.0 23.5 L 23.5 31.0" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 8.5 L 1.0 23.5 L 8.5 16.0 L 1.0 8.5" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
@@ -7240,6 +8298,8 @@ var S52_POINT_SVGS = {
7240
8298
  "BUIREL15": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 4.8 1.0 L 6.5 3.2 L 8.4 4.9 L 10.6 6.0 L 12.8 6.9 L 15.2 7.2 L 17.1 7.1 L 19.1 6.9 L 21.3 6.2 L 23.0 5.1 L 24.5 4.2 L 25.8 2.8 L 26.7 1.7 L 27.2 1.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <circle cx="16.48" cy="24.63" r="6.37" fill="none" stroke="CHBLK" stroke-width="0.8" />\n <path d="M 16.5 17.9 L 16.5 7.1" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <circle cx="16.61" cy="24.56" r="1.29" fill="none" stroke="CHBLK" stroke-width="0.8" />\n <path d="M 16.6 24.6 Z" fill="CHBLK" />\n</svg>\n',
7241
8299
  "BUISGL01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 1.0 L 31.0 1.0 L 31.0 31.0 L 1.0 31.0 L 1.0 1.0 Z" fill="CHBRN" />\n <path d="M 1.0 1.0 L 31.0 1.0 L 31.0 31.0 L 1.0 31.0 L 1.0 1.0" fill="none" stroke="CHBRN" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 1.0 L 31.0 1.0 L 31.0 31.0 L 1.0 31.0 L 1.0 1.0" fill="none" stroke="LANDF" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7242
8300
  "BUISGL11": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 1.0 L 31.0 1.0 L 31.0 31.0 L 1.0 31.0 L 1.0 1.0 Z" fill="LANDF" />\n <path d="M 1.0 1.0 L 31.0 1.0 L 31.0 31.0 L 1.0 31.0 L 1.0 1.0" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 1.0 L 31.0 1.0 L 31.0 31.0 L 1.0 31.0 L 1.0 1.0" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
8301
+ "CABLE01": '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">\n <path d="M 10 2 L 5 8 L 9 8 L 6 14 L 11 6 L 7 6 Z" fill="CHMGD" stroke="CHMGD" stroke-width="0.4" stroke-linejoin="round" />\n</svg>\n',
8302
+ "CABOHD01": '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">\n <path d="M 3 5 L 8 11 L 13 5" fill="none" stroke="CHMGD" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7243
8303
  "CAIRNS01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 17.5 1.1 L 20.1 1.9 L 21.7 2.7 L 23.2 4.6 L 23.8 6.2 L 24.2 7.4 L 24.2 9.4 L 23.4 10.9 L 22.9 12.1 L 21.8 13.5 L 21.3 14.1 L 21.8 12.5 L 22.7 10.9 L 22.9 9.8 L 22.9 7.8 L 22.2 5.8 L 21.7 4.6 L 20.7 3.5 L 19.1 2.1 L 17.5 1.1 Z" fill="LANDF" />\n <path d="M 17.5 1.1 L 20.1 1.9 L 21.7 2.7 L 23.2 4.6 L 23.8 6.2 L 24.2 7.4 L 24.2 9.4 L 23.4 10.9 L 22.9 12.1 L 21.8 13.5 L 21.3 14.1 L 21.8 12.5 L 22.7 10.9 L 22.9 9.8 L 22.9 7.8 L 22.2 5.8 L 21.7 4.6 L 20.7 3.5 L 19.1 2.1 L 17.5 1.1" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 11.7 13.7 L 13.2 15.1 L 14.8 16.3 L 15.4 17.2 L 15.9 18.8 L 16.4 20.4 L 16.4 21.6 L 15.6 23.5 L 15.0 25.1 L 14.0 26.3 L 12.2 27.7 L 13.2 26.1 L 14.0 24.5 L 14.8 21.4 L 14.8 19.8 L 14.0 17.9 L 13.4 16.7 L 12.2 14.7 L 11.7 13.7 Z" fill="LANDF" />\n <path d="M 11.7 13.7 L 13.2 15.1 L 14.8 16.3 L 15.4 17.2 L 15.9 18.8 L 16.4 20.4 L 16.4 21.6 L 15.6 23.5 L 15.0 25.1 L 14.0 26.3 L 12.2 27.7 L 13.2 26.1 L 14.0 24.5 L 14.8 21.4 L 14.8 19.8 L 14.0 17.9 L 13.4 16.7 L 12.2 14.7 L 11.7 13.7" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 24.4 14.5 L 26.0 14.7 L 27.6 15.3 L 29.1 16.8 L 29.7 17.9 L 30.5 19.4 L 30.7 21.0 L 30.5 22.6 L 30.1 24.0 L 29.5 25.1 L 28.5 26.1 L 27.4 27.7 L 28.5 25.5 L 29.1 23.5 L 29.5 21.4 L 29.0 18.8 L 27.9 17.2 L 26.6 15.7 L 25.4 15.1 L 24.4 14.5 Z" fill="LANDF" />\n <path d="M 24.4 14.5 L 26.0 14.7 L 27.6 15.3 L 29.1 16.8 L 29.7 17.9 L 30.5 19.4 L 30.7 21.0 L 30.5 22.6 L 30.1 24.0 L 29.5 25.1 L 28.5 26.1 L 27.4 27.7 L 28.5 25.5 L 29.1 23.5 L 29.5 21.4 L 29.0 18.8 L 27.9 17.2 L 26.6 15.7 L 25.4 15.1 L 24.4 14.5" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <circle cx="16.38" cy="28.67" r="2.33" fill="none" stroke="LANDF" stroke-width="1.2" />\n <circle cx="8.70" cy="21.00" r="7.42" fill="none" stroke="LANDF" stroke-width="1.2" />\n <circle cx="16.75" cy="8.23" r="7.23" fill="none" stroke="LANDF" stroke-width="1.2" />\n <circle cx="23.80" cy="21.38" r="6.86" fill="none" stroke="LANDF" stroke-width="1.2" />\n <path d="M 2.4 28.7 L 13.8 28.7" fill="none" stroke="LANDF" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 18.7 28.7 L 29.7 28.7" fill="none" stroke="LANDF" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7244
8304
  "CAIRNS11": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 17.5 1.1 L 20.1 1.9 L 21.7 2.7 L 23.2 4.6 L 23.8 6.2 L 24.2 7.4 L 24.2 9.4 L 23.4 10.9 L 22.9 12.1 L 21.8 13.5 L 21.3 14.1 L 21.8 12.5 L 22.7 10.9 L 22.9 9.8 L 22.9 7.8 L 22.2 5.8 L 21.7 4.6 L 20.7 3.5 L 19.1 2.1 L 17.5 1.1 Z" fill="CHBLK" />\n <path d="M 17.5 1.1 L 20.1 1.9 L 21.7 2.7 L 23.2 4.6 L 23.8 6.2 L 24.2 7.4 L 24.2 9.4 L 23.4 10.9 L 22.9 12.1 L 21.8 13.5 L 21.3 14.1 L 21.8 12.5 L 22.7 10.9 L 22.9 9.8 L 22.9 7.8 L 22.2 5.8 L 21.7 4.6 L 20.7 3.5 L 19.1 2.1 L 17.5 1.1" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 11.7 13.7 L 13.2 15.1 L 14.8 16.3 L 15.4 17.2 L 15.9 18.8 L 16.4 20.4 L 16.4 21.6 L 15.6 23.5 L 15.0 25.1 L 14.0 26.3 L 12.2 27.7 L 13.2 26.1 L 14.0 24.5 L 14.8 21.4 L 14.8 19.8 L 14.0 17.9 L 13.4 16.7 L 12.2 14.7 L 11.7 13.7 Z" fill="CHBLK" />\n <path d="M 11.7 13.7 L 13.2 15.1 L 14.8 16.3 L 15.4 17.2 L 15.9 18.8 L 16.4 20.4 L 16.4 21.6 L 15.6 23.5 L 15.0 25.1 L 14.0 26.3 L 12.2 27.7 L 13.2 26.1 L 14.0 24.5 L 14.8 21.4 L 14.8 19.8 L 14.0 17.9 L 13.4 16.7 L 12.2 14.7 L 11.7 13.7" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 24.4 14.5 L 26.0 14.7 L 27.6 15.3 L 29.1 16.8 L 29.7 17.9 L 30.5 19.4 L 30.7 21.0 L 30.5 22.6 L 30.1 24.0 L 29.5 25.1 L 28.5 26.1 L 27.4 27.7 L 28.5 25.5 L 29.1 23.5 L 29.5 21.4 L 29.0 18.8 L 27.9 17.2 L 26.6 15.7 L 25.4 15.1 L 24.4 14.5 Z" fill="CHBLK" />\n <path d="M 24.4 14.5 L 26.0 14.7 L 27.6 15.3 L 29.1 16.8 L 29.7 17.9 L 30.5 19.4 L 30.7 21.0 L 30.5 22.6 L 30.1 24.0 L 29.5 25.1 L 28.5 26.1 L 27.4 27.7 L 28.5 25.5 L 29.1 23.5 L 29.5 21.4 L 29.0 18.8 L 27.9 17.2 L 26.6 15.7 L 25.4 15.1 L 24.4 14.5" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <circle cx="16.38" cy="28.67" r="2.33" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <circle cx="8.70" cy="21.00" r="7.42" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <circle cx="16.75" cy="8.23" r="7.23" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <circle cx="23.80" cy="21.38" r="6.86" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <path d="M 2.4 28.7 L 13.8 28.7" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 18.7 28.7 L 29.7 28.7" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7245
8305
  "CBLARE51": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 19.5 1.0 L 11.0 14.5 L 21.0 18.1 L 13.0 31.0" fill="none" stroke="CHMGF" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
@@ -7278,6 +8338,18 @@ var S52_POINT_SVGS = {
7278
8338
  "DIRBOYB1": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 9.0 20.9 L 2.2 20.9 L 16.0 7.1 L 29.7 20.9 L 22.7 20.9 L 22.7 25.5 L 9.0 25.5 L 9.0 20.9" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <circle cx="4.48" cy="10.02" r="3.48" fill="none" stroke="CHGRN" stroke-width="1.8" />\n <circle cx="27.59" cy="10.02" r="3.41" fill="none" stroke="CHRED" stroke-width="1.8" />\n</svg>\n',
7279
8339
  "DISMAR03": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="CHMGD" stroke-width="1.2" />\n</svg>\n',
7280
8340
  "DISMAR04": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 5.1 L 1.0 26.9" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 8.4 13.3 L 1.0 21.5" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 3.5 18.7 L 9.2 26.9" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 14.6 13.3 L 14.6 26.9" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 14.6 15.5 L 16.5 13.5 L 18.2 13.0 L 19.3 13.0 L 21.6 14.1 L 22.8 15.7 L 22.8 26.9" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 22.8 16.0 L 23.9 13.8 L 26.1 12.8 L 27.5 12.8 L 29.7 13.8 L 31.0 16.0 L 31.0 26.9" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
8341
+ "DNGCIR01": `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
8342
+ <!-- S-52 PresLib \xA7CSYM02 isolated-danger ring. Per IHO S-52 spec, hazards
8343
+ (UWTROC / OBSTRN / WRECKS) whose VALSOU is shallower than the
8344
+ mariner's safety contour, OR that cover-and-uncover with the tide
8345
+ (always dangerous regardless of sounded depth), get a thin DASHED
8346
+ MAGENTA RING overlaid on top of the base hazard icon.
8347
+ Thin 1.0-px stroke (no fill) at r=14 surrounds the 18-unit base
8348
+ hazard asterisks/crosses with ~3 px of breathing room at z16,
8349
+ reading as the standard NOAA / ECDIS isolated-danger marker. -->
8350
+ <circle cx="16" cy="16" r="14" fill="none" stroke="CHMGD" stroke-width="1.0" stroke-dasharray="2,2" />
8351
+ </svg>
8352
+ `,
7281
8353
  "DNGHILIT": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 1.0 L 31.0 1.0 L 31.0 31.0 L 1.0 31.0 L 1.0 1.0 Z" fill="DNGHL" />\n <path d="M 1.0 1.0 L 31.0 1.0 L 31.0 31.0 L 1.0 31.0 L 1.0 1.0" fill="none" stroke="DNGHL" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 31.0 L 31.0 31.0 L 31.0 1.0 L 1.0 1.0 L 1.0 31.0" fill="none" stroke="DNGHL" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7282
8354
  "DOMES001": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="15.73" cy="25.99" r="2.56" fill="none" stroke="LANDF" stroke-width="0.8" />\n <path d="M 13.2 25.8 L 3.4 25.8" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 3.4 25.8 L 2.8 24.9 L 2.0 22.8 L 1.2 20.7 L 1.0 19.0 L 1.0 16.6 L 1.6 14.1 L 2.7 11.2 L 3.6 9.4 L 5.3 7.6 L 7.1 6.1 L 8.8 5.2 L 11.6 4.2 L 14.0 3.7 L 16.6 3.4 L 19.5 3.9 L 22.3 4.8 L 25.0 6.5 L 27.5 8.9 L 28.9 10.8 L 30.2 13.3 L 30.9 16.4 L 31.0 20.1 L 30.4 22.6 L 29.6 24.6 L 28.7 25.6" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 18.2 25.8 L 28.6 25.8 L 28.8 25.3" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7283
8355
  "DOMES011": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="15.73" cy="25.99" r="2.56" fill="none" stroke="CHBLK" stroke-width="0.8" />\n <path d="M 13.2 25.8 L 3.4 25.8" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 3.4 25.8 L 2.8 24.9 L 2.0 22.8 L 1.2 20.7 L 1.0 19.0 L 1.0 16.6 L 1.6 14.1 L 2.7 11.2 L 3.6 9.4 L 5.3 7.6 L 7.1 6.1 L 8.8 5.2 L 11.6 4.2 L 14.0 3.7 L 16.6 3.4 L 19.5 3.9 L 22.3 4.8 L 25.0 6.5 L 27.5 8.9 L 28.9 10.8 L 30.2 13.3 L 30.9 16.4 L 31.0 20.1 L 30.4 22.6 L 29.6 24.6 L 28.7 25.6" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 18.2 25.8 L 28.6 25.8 L 28.8 25.3" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
@@ -7322,9 +8394,10 @@ var S52_POINT_SVGS = {
7322
8394
  "ISODGR01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 16.0 1.0 L 26.7 5.3 L 31.0 16.0 L 26.7 26.7 L 16.0 31.0 L 5.3 26.7 L 1.0 16.0 L 5.3 5.3 L 16.0 1.0 L 16.0 12.8 L 21.9 6.9 L 25.1 10.1 L 19.2 16.0 L 25.1 21.9 L 21.9 25.1 L 16.0 19.2 L 10.1 25.1 L 6.9 21.9 L 12.8 16.0 L 6.9 10.1 L 10.1 6.9 L 16.0 12.8 L 16.0 1.0 Z" fill="ISDNG" />\n <path d="M 16.0 1.0 L 26.7 5.3 L 31.0 16.0 L 26.7 26.7 L 16.0 31.0 L 5.3 26.7 L 1.0 16.0 L 5.3 5.3 L 16.0 1.0 L 16.0 12.8 L 21.9 6.9 L 25.1 10.1 L 19.2 16.0 L 25.1 21.9 L 21.9 25.1 L 16.0 19.2 L 10.1 25.1 L 6.9 21.9 L 12.8 16.0 L 6.9 10.1 L 10.1 6.9 L 16.0 12.8 L 16.0 1.0" fill="none" stroke="ISDNG" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 16.0 L 5.3 5.3 L 16.0 1.0 L 26.7 5.3 L 31.0 16.0 L 26.7 26.7 L 16.0 31.0 L 5.3 26.7 L 1.0 16.0" fill="none" stroke="ISDNG" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7323
8395
  "ITZARE51": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 4.7 27.8 L 4.7 4.2" fill="none" stroke="CHMGF" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 23.1 4.3 L 23.1 27.8" fill="none" stroke="CHMGF" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 4.3 L 8.7 4.3" fill="none" stroke="CHMGF" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.3 27.7 L 8.7 27.7" fill="none" stroke="CHMGF" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 15.1 4.3 L 31.0 4.3" fill="none" stroke="CHMGF" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7324
8396
  "LIGHTDEF": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 16.3 31.0 L 10.9 6.9 L 10.9 5.8 L 11.2 4.2 L 12.0 2.8 L 12.8 2.1 L 14.1 1.0 L 16.0 1.0 L 17.6 1.0 L 18.7 1.3 L 20.3 2.3 L 20.8 3.9 L 21.1 5.3 L 21.1 6.6 L 16.3 31.0 Z" fill="CHMGD" />\n <path d="M 16.3 31.0 L 10.9 6.9 L 10.9 5.8 L 11.2 4.2 L 12.0 2.8 L 12.8 2.1 L 14.1 1.0 L 16.0 1.0 L 17.6 1.0 L 18.7 1.3 L 20.3 2.3 L 20.8 3.9 L 21.1 5.3 L 21.1 6.6 L 16.3 31.0" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.3 31.0 L 10.9 6.4 L 10.9 4.7 L 11.4 3.1 L 12.3 2.3 L 13.6 1.3 L 15.2 1.0 L 16.3 1.0 L 17.6 1.0 L 18.9 1.5 L 20.0 2.6 L 20.8 4.2 L 21.1 5.3 L 20.8 7.7 L 16.3 31.0" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7325
- "LIGHTS11": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 16.3 28.0 L 11.8 7.1 L 11.8 6.3 L 11.8 4.9 L 12.4 3.5 L 13.2 3.0 L 14.3 2.1 L 16.0 1.9 L 17.4 2.1 L 18.5 2.4 L 19.6 3.2 L 20.2 4.6 L 20.4 5.7 L 20.4 6.9 L 16.3 28.0 Z" fill="LITRD" />\n <path d="M 16.3 28.0 L 11.8 7.1 L 11.8 6.3 L 11.8 4.9 L 12.4 3.5 L 13.2 3.0 L 14.3 2.1 L 16.0 1.9 L 17.4 2.1 L 18.5 2.4 L 19.6 3.2 L 20.2 4.6 L 20.4 5.7 L 20.4 6.9 L 16.3 28.0" fill="none" stroke="LITRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 21.3 5.2 L 21.0 6.6 L 16.3 31.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.3 28.0 L 11.5 6.6 L 11.8 5.2 L 12.1 4.1 L 12.9 3.2 L 14.1 2.1 L 15.4 1.9 L 16.3 1.9 L 17.4 2.1 L 18.8 2.7 L 19.6 3.5 L 20.2 4.6 L 20.4 5.7 L 20.2 7.7 L 16.3 28.0" fill="none" stroke="LITRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.3 31.0 L 10.7 6.0 L 11.5 3.5 L 13.8 1.6 L 16.3 1.0 L 18.5 1.9 L 19.9 2.7 L 21.0 4.9" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
8397
+ "LIGHTHOUSE01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <rect x="6" y="26" width="20" height="4" fill="CHBLK" />\n <path d="M 9 26 L 12 8 L 20 8 L 23 26 Z" fill="CHBLK" />\n <rect x="13" y="4" width="6" height="4" fill="CHBLK" />\n <path d="M 12 4 L 16 1 L 20 4 Z" fill="CHBLK" />\n</svg>\n',
8398
+ "LIGHTS11": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <g transform="translate(10 10) rotate(135) scale(0.9) translate(-16.3 -28)" fill="LITRD">\n <path d="M 16.3 28 L 11.8 7.1 L 11.8 6.3 L 11.8 4.9 L 12.4 3.5 L 13.2 3 L 14.3 2.1 L 16 1.9 L 17.4 2.1 L 18.5 2.4 L 19.6 3.2 L 20.2 4.6 L 20.4 5.7 L 20.4 6.9 L 16.3 28 Z" />\n </g>\n</svg>\n',
7326
8399
  "LIGHTS12": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 16.3 28.0 L 11.8 7.1 L 11.8 6.3 L 11.8 4.9 L 12.4 3.5 L 13.2 3.0 L 14.3 2.1 L 16.0 1.9 L 17.4 2.1 L 18.5 2.4 L 19.6 3.2 L 20.2 4.6 L 20.4 5.7 L 20.4 6.9 L 16.3 28.0 Z" fill="LITGN" />\n <path d="M 16.3 28.0 L 11.8 7.1 L 11.8 6.3 L 11.8 4.9 L 12.4 3.5 L 13.2 3.0 L 14.3 2.1 L 16.0 1.9 L 17.4 2.1 L 18.5 2.4 L 19.6 3.2 L 20.2 4.6 L 20.4 5.7 L 20.4 6.9 L 16.3 28.0" fill="none" stroke="LITGN" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 21.3 5.2 L 21.0 6.6 L 16.3 31.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.3 28.0 L 11.5 6.6 L 11.8 5.2 L 12.1 4.1 L 12.9 3.2 L 14.1 2.1 L 15.4 1.9 L 16.3 1.9 L 17.4 2.1 L 18.8 2.7 L 19.6 3.5 L 20.2 4.6 L 20.4 5.7 L 20.2 7.7 L 16.3 28.0" fill="none" stroke="LITGN" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.3 31.0 L 10.7 6.0 L 11.5 3.5 L 13.8 1.6 L 16.3 1.0 L 18.5 1.9 L 19.9 2.7 L 21.0 4.9" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7327
- "LIGHTS13": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 16.3 28.0 L 11.8 7.1 L 11.8 6.3 L 11.8 4.9 L 12.4 3.5 L 13.2 3.0 L 14.3 2.1 L 16.0 1.9 L 17.4 2.1 L 18.5 2.4 L 19.6 3.2 L 20.2 4.6 L 20.4 5.7 L 20.4 6.9 L 16.3 28.0 Z" fill="LITYW" />\n <path d="M 16.3 28.0 L 11.8 7.1 L 11.8 6.3 L 11.8 4.9 L 12.4 3.5 L 13.2 3.0 L 14.3 2.1 L 16.0 1.9 L 17.4 2.1 L 18.5 2.4 L 19.6 3.2 L 20.2 4.6 L 20.4 5.7 L 20.4 6.9 L 16.3 28.0" fill="none" stroke="LITYW" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 21.3 5.2 L 21.0 6.6 L 16.3 31.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.3 28.0 L 11.5 6.6 L 11.8 5.2 L 12.1 4.1 L 12.9 3.2 L 14.1 2.1 L 15.4 1.9 L 16.3 1.9 L 17.4 2.1 L 18.8 2.7 L 19.6 3.5 L 20.2 4.6 L 20.4 5.7 L 20.2 7.7 L 16.3 28.0" fill="none" stroke="LITYW" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.3 31.0 L 10.7 6.0 L 11.5 3.5 L 13.8 1.6 L 16.3 1.0 L 18.5 1.9 L 19.9 2.7 L 21.0 4.9" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
8400
+ "LIGHTS13": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <g transform="translate(10 10) rotate(135) scale(0.9) translate(-16.3 -28)" fill="LITYW">\n <path d="M 16.3 28 L 11.8 7.1 L 11.8 6.3 L 11.8 4.9 L 12.4 3.5 L 13.2 3 L 14.3 2.1 L 16 1.9 L 17.4 2.1 L 18.5 2.4 L 19.6 3.2 L 20.2 4.6 L 20.4 5.7 L 20.4 6.9 L 16.3 28 Z" />\n </g>\n</svg>\n',
7328
8401
  "LIGHTS14": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 16.3 28.0 L 11.8 7.1 L 11.8 6.3 L 11.8 4.9 L 12.4 3.5 L 13.2 3.0 L 14.3 2.1 L 16.0 1.9 L 17.4 2.1 L 18.5 2.4 L 19.6 3.2 L 20.2 4.6 L 20.4 5.7 L 20.4 6.9 L 16.3 28.0 Z" fill="CHMGD" />\n <path d="M 16.3 28.0 L 11.8 7.1 L 11.8 6.3 L 11.8 4.9 L 12.4 3.5 L 13.2 3.0 L 14.3 2.1 L 16.0 1.9 L 17.4 2.1 L 18.5 2.4 L 19.6 3.2 L 20.2 4.6 L 20.4 5.7 L 20.4 6.9 L 16.3 28.0" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 21.3 5.2 L 21.0 6.6 L 16.3 31.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.3 28.0 L 11.5 6.6 L 11.8 5.2 L 12.1 4.1 L 12.9 3.2 L 14.1 2.1 L 15.4 1.9 L 16.3 1.9 L 17.4 2.1 L 18.8 2.7 L 19.6 3.5 L 20.2 4.6 L 20.4 5.7 L 20.2 7.7 L 16.3 28.0" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.3 31.0 L 10.7 6.0 L 11.5 3.5 L 13.8 1.6 L 16.3 1.0 L 18.5 1.9 L 19.9 2.7 L 21.0 4.9" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7329
8402
  "LIGHTS81": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 25.9 L 6.9 5.9 L 12.9 26.0 L 19.0 5.9 L 25.0 26.1 L 31.0 5.9" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7330
8403
  "LIGHTS82": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="6.96" cy="17.80" r="5.96" fill="none" stroke="CHMGD" stroke-width="1.2" />\n <path d="M 14.9 23.1 L 25.9 23.5" fill="none" stroke="CHMGD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 13.3 12.1 L 28.0 8.2" fill="none" stroke="CHMGD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 15.8 17.5 L 31.0 16.0" fill="none" stroke="CHMGD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
@@ -7334,6 +8407,8 @@ var S52_POINT_SVGS = {
7334
8407
  "LITVES01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="24.83" r="2.33" fill="none" stroke="CHBLK" stroke-width="1.2" />\n <path d="M 1.0 24.8 L 12.7 24.8" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 6.0 24.8 L 2.7 16.5" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 26.0 24.8 L 29.3 16.5" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.0 19.0 L 16.0 9.8" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 9.3 19.0 L 9.3 13.0" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 22.7 19.0 L 22.7 13.2" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.0 9.8 L 16.0 4.8" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 12.7 6.5 L 19.3 9.8" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 12.7 9.8 L 19.3 6.5" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 4.7 21.5 L 10.2 21.5" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 21.8 21.5 L 27.3 21.5" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 2.7 16.5 L 9.2 19.0 L 16.0 19.0 L 22.7 19.0 L 29.3 16.5" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 19.3 24.8 L 31.0 24.8" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7335
8408
  "LITVES02": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 5.9 23.3 L 1.0 15.1 L 31.0 15.1 L 25.6 23.3 L 5.9 23.3 Z" fill="CHBLK" />\n <path d="M 5.9 23.3 L 1.0 15.1 L 31.0 15.1 L 25.6 23.3 L 5.9 23.3" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.0 15.1 L 16.0 8.7" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7336
8409
  "LNDARE01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="13.54" fill="none" stroke="LANDA" stroke-width="0.8" />\n <path d="M 16.0 16.0 Z" fill="LANDA" />\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="CSTLN" stroke-width="1.2" />\n</svg>\n',
8410
+ "LNDMRK18": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <line x1="16" y1="28" x2="16" y2="10" stroke="CHBLK" stroke-width="1.5"/>\n <circle cx="16" cy="10" r="2" fill="CHBLK"/>\n <line x1="16" y1="10" x2="6" y2="2" stroke="CHBLK" stroke-width="1.2"/>\n <line x1="16" y1="10" x2="26" y2="2" stroke="CHBLK" stroke-width="1.2"/>\n <line x1="16" y1="10" x2="6" y2="18" stroke="CHBLK" stroke-width="1.2"/>\n <line x1="16" y1="10" x2="26" y2="18" stroke="CHBLK" stroke-width="1.2"/>\n <circle cx="16" cy="16" r="7" fill="none" stroke="CHBLK" stroke-width="0.6" stroke-dasharray="2,2"/>\n</svg>\n',
8411
+ "LNDMRK19": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <line x1="16" y1="28" x2="16" y2="10" stroke="CHBLK" stroke-width="1.5"/>\n <circle cx="16" cy="10" r="1.5" fill="CHBLK"/>\n <line x1="16" y1="10" x2="16" y2="2" stroke="CHBLK" stroke-width="1.2"/>\n <line x1="16" y1="10" x2="9" y2="17" stroke="CHBLK" stroke-width="1.2"/>\n <line x1="16" y1="10" x2="23" y2="17" stroke="CHBLK" stroke-width="1.2"/>\n <circle cx="16" cy="16" r="7" fill="none" stroke="CHBLK" stroke-width="0.6" stroke-dasharray="2,2"/>\n</svg>\n',
7337
8412
  "LOCMAG01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 18.9 22.5 L 18.9 31.0" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 18.9 23.4 L 18.9 1.0 L 13.1 17.9 L 14.2 18.3 L 15.1 18.7 L 15.9 19.4 L 16.4 20.0 L 17.0 20.6 L 17.8 21.6 L 18.3 22.4 L 18.8 23.3" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7338
8413
  "LOCMAG51": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 18.9 23.6 L 18.9 1.0 L 13.0 18.1 L 14.1 18.5 L 15.0 18.9 L 15.8 19.6 L 16.4 20.2 L 17.0 20.8 L 17.7 21.8 L 18.3 22.6 L 18.8 23.5" fill="none" stroke="CHMGF" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 19.0 23.5 L 19.0 31.0" fill="none" stroke="CHMGF" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7339
8414
  "LOWACC01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 4.5 10.2 L 5.8 10.2" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 5.0 8.0 L 5.0 6.6 L 5.0 6.1 L 5.4 5.6 L 5.7 5.2 L 6.3 4.5 L 6.6 3.9 L 6.8 3.2 L 6.6 2.5 L 6.3 2.0 L 5.8 1.5 L 5.3 1.1 L 4.8 1.1 L 4.2 1.0 L 3.7 1.1 L 3.2 1.4 L 2.7 1.9 L 2.4 2.4 L 2.3 2.8 L 2.3 3.3 L 2.4 3.7 L 2.5 3.8" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 6.8 8.1 L 29.7 31.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
@@ -7356,9 +8431,19 @@ var S52_POINT_SVGS = {
7356
8431
  "NMKRCD04": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 16.0 L 16.0 1.0 L 16.0 31.0 L 1.0 16.0 Z" fill="CHGRN" />\n <path d="M 1.0 16.0 L 16.0 1.0 L 16.0 31.0 L 1.0 16.0" fill="none" stroke="CHGRN" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 31.0 16.0 L 16.0 31.0 L 16.0 1.0 L 31.0 16.0 Z" fill="CHWHT" />\n <path d="M 31.0 16.0 L 16.0 31.0 L 16.0 1.0 L 31.0 16.0" fill="none" stroke="CHWHT" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 16.0 L 16.0 1.0 L 31.0 16.0 L 16.0 31.0 L 1.0 16.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7357
8432
  "NORTHAR1": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 16.3 31.0 L 16.3 1.0" fill="none" stroke="SCLBR" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 12.8 20.7 L 12.8 14.1 L 19.6 20.7 L 19.6 14.2" fill="none" stroke="SCLBR" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 12.4 8.9 L 19.6 8.9 L 16.2 1.1 L 12.4 8.9 Z" fill="SCLBR" />\n <path d="M 12.4 8.9 L 19.6 8.9 L 16.2 1.1 L 12.4 8.9" fill="none" stroke="SCLBR" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7358
8433
  "NOTBRD11": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 8.5 31.0 L 23.5 31.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.0 31.0 L 16.0 16.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 4.8 16.0 L 27.3 16.0 L 27.3 1.0 L 4.8 1.0 L 4.8 16.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7359
- "OBSTRN01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="DEPVS" stroke-width="0.8" />\n <path d="M 16.0 16.0 Z" fill="DEPVS" />\n</svg>\n',
8434
+ "OBSTRN01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <!-- S-52 PresLib OBSTRN01 / INT1 K40: obstruction, position-fixed (fish weir,\n snag, sunken object, foul ground point). NOAA portrayal: bold "+" cross\n inside a dashed oval. The dashed boundary (longer dashes than the dotted\n K41 variant) signals "area of obstruction" \u2014 mariners should give the\n feature a wide berth even when its precise extent is unclear. 18-unit\n cross with 1.6 stroke for harbor-zoom visibility. -->\n <ellipse cx="16" cy="16" rx="13" ry="10" fill="none" stroke="CHBLK" stroke-width="1.0" stroke-dasharray="1.8,1.4" />\n <path d="M 16 7 L 16 25" fill="none" stroke="CHBLK" stroke-width="1.6" stroke-linecap="round" />\n <path d="M 7 16 L 25 16" fill="none" stroke="CHBLK" stroke-width="1.6" stroke-linecap="round" />\n</svg>\n',
7360
8435
  "OBSTRN02": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"></svg>\n',
7361
- "OBSTRN03": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="DEPIT" stroke-width="0.8" />\n <path d="M 16.0 16.0 Z" fill="DEPIT" />\n</svg>\n',
8436
+ "OBSTRN03": `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
8437
+ <!-- S-52 PresLib OBSTRN03 / INT1 K41: obstruction always submerged with
8438
+ sounded depth (WATLEV=3). NOAA portrayal: bold "+" cross inside a
8439
+ DOTTED oval (shorter, tighter dashes than OBSTRN01's dashed style).
8440
+ Depth rendered separately via VALSOU label. 18-unit cross matching
8441
+ UWTROC bold weight for visual hazard consistency. -->
8442
+ <ellipse cx="16" cy="16" rx="13" ry="10" fill="none" stroke="CHBLK" stroke-width="0.9" stroke-dasharray="1.0,1.2" />
8443
+ <path d="M 16 7 L 16 25" fill="none" stroke="CHBLK" stroke-width="1.6" stroke-linecap="round" />
8444
+ <path d="M 7 16 L 25 16" fill="none" stroke="CHBLK" stroke-width="1.6" stroke-linecap="round" />
8445
+ </svg>
8446
+ `,
7362
8447
  "OBSTRN18": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 1.0 L 1.0 31.0 L 31.0 31.0 L 30.8 1.0 L 1.0 1.0 Z" fill="LANDA" />\n <path d="M 1.0 1.0 L 1.0 31.0 L 31.0 31.0 L 30.8 1.0 L 1.0 1.0" fill="none" stroke="LANDA" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 1.0 L 1.0 31.0 L 31.0 31.0 L 30.8 1.0 L 1.0 1.0" fill="none" stroke="CSTLN" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7363
8448
  "OFSPLF01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="3.75" fill="none" stroke="CHBLK" stroke-width="0.8" />\n <path d="M 16.0 16.0 Z" fill="CHBLK" />\n <path d="M 1.0 1.0 L 31.0 1.0 L 31.0 31.0 L 1.0 31.0 L 1.0 1.0" fill="none" stroke="CHBLK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7364
8449
  "OSPONE02": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 16.0 L 31.0 16.0" fill="none" stroke="SHIPS" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
@@ -7369,6 +8454,8 @@ var S52_POINT_SVGS = {
7369
8454
  "PASTRK02": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 16.0 L 31.0 16.0" fill="none" stroke="SYTRK" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7370
8455
  "PILBOP02": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 16.0 1.0 L 10.2 16.2 L 16.0 31.0 L 22.1 16.2 L 16.0 1.0 Z" fill="CHMGD" />\n <path d="M 16.0 1.0 L 10.2 16.2 L 16.0 31.0 L 22.1 16.2 L 16.0 1.0" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <circle cx="16.00" cy="16.17" r="14.77" fill="none" stroke="CHMGD" stroke-width="0.8" />\n</svg>\n',
7371
8456
  "PILPNT02": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="CHBLK" stroke-width="0.8" />\n <path d="M 16.0 16.0 Z" fill="CHBLK" />\n</svg>\n',
8457
+ "PIPLIN01": '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">\n <circle cx="8" cy="8" r="3.5" fill="none" stroke="PIPLN" stroke-width="1.6" />\n</svg>\n',
8458
+ "PIPOHD01": '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">\n <path d="M 3 12 L 8 5 L 13 12" fill="none" stroke="PIPLN" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" />\n <line x1="3" y1="13" x2="5" y2="13" stroke="PIPLN" stroke-width="1.4" stroke-linecap="round" />\n <line x1="11" y1="13" x2="13" y2="13" stroke="PIPLN" stroke-width="1.4" stroke-linecap="round" />\n</svg>\n',
7372
8459
  "PLNPOS01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 15.9 L 1.4 14.3 L 3.4 12.5 L 6.7 11.2 L 10.2 10.6 L 15.6 10.2 L 21.2 10.6 L 25.0 11.2 L 28.2 12.5 L 30.3 14.3 L 31.0 15.9 L 30.8 18.0 L 28.2 19.7 L 25.0 20.8 L 21.2 21.8 L 15.6 21.8 L 10.2 21.8 L 6.7 21.0 L 2.9 19.7 L 1.1 18.1 L 1.0 15.9" fill="none" stroke="PLRTE" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7373
8460
  "PLNPOS02": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 16.0 L 31.0 16.0" fill="none" stroke="PLRTE" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7374
8461
  "PLNSPD03": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 26.1 L 1.1 5.8 L 31.0 5.8 L 31.0 26.2 L 1.0 26.1" fill="none" stroke="PLRTE" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
@@ -7482,12 +8569,14 @@ var S52_POINT_SVGS = {
7482
8569
  "TWRTPT53": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 13.3 4.5 L 16.0 1.0 L 18.6 4.5" fill="none" stroke="TRFCD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 11.3 7.0 L 9.6 9.5 L 12.8 9.5" fill="none" stroke="TRFCD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 18.9 9.4 L 22.4 9.4 L 20.4 6.8" fill="none" stroke="TRFCD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 12.7 26.9 L 12.7 31.0 L 19.2 31.0 L 19.2 27.0" fill="none" stroke="TRFCD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 12.7 23.7 L 12.7 20.3" fill="none" stroke="TRFCD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 12.7 13.0 L 12.7 16.2" fill="none" stroke="TRFCD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 19.6 12.8 L 19.6 15.9" fill="none" stroke="TRFCD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 19.5 20.1 L 19.5 23.4" fill="none" stroke="TRFCD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7483
8570
  "UNITFTH1": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 6.3 14.0 L 25.7 14.0" fill="none" stroke="SCLBR" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 25.8 1.0 L 6.3 1.0 L 6.2 31.0" fill="none" stroke="SCLBR" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7484
8571
  "UNITMTR1": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 3.1 31.0 L 3.1 1.0 L 16.1 25.2 L 28.9 1.4 L 28.9 30.6" fill="none" stroke="SCLBR" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7485
- "UWTROC03": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="DEPVS" stroke-width="0.8" />\n <path d="M 16.0 16.0 Z" fill="DEPVS" />\n <path d="M 16.1 6.4 L 16.1 27.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 5.9 16.4 L 26.2 16.4" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7486
- "UWTROC04": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 31.0 16.1 L 1.0 16.1" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 24.8 3.9 L 7.1 28.2" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 24.8 27.7 L 6.8 3.8" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
8572
+ "UWTROC01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <!-- S-52 PresLib UWTROC01 / INT1 K11: rock that covers and uncovers\n (WATLEV=4). Per IHO S-52 PresLib Edition 4.0 Annex A, the symbol is a\n plain 4-line asterisk \u2014 geometrically identical to UWTROC04 (K13).\n The K11/K13 distinction is conveyed by attribute context: K11 has no\n VALSOU (depth varies with tide so no fixed sounding), K13 carries a\n VALSOU label rendered separately. 18-unit asterisk, 1.6 stroke. -->\n <path d="M 16 7 L 16 25" fill="none" stroke="CHBLK" stroke-width="1.6" stroke-linecap="round" />\n <path d="M 7 16 L 25 16" fill="none" stroke="CHBLK" stroke-width="1.6" stroke-linecap="round" />\n <path d="M 9.5 9.5 L 22.5 22.5" fill="none" stroke="CHBLK" stroke-width="1.6" stroke-linecap="round" />\n <path d="M 22.5 9.5 L 9.5 22.5" fill="none" stroke="CHBLK" stroke-width="1.6" stroke-linecap="round" />\n</svg>\n',
8573
+ "UWTROC03": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <!-- S-52 PresLib UWTROC03 / INT1 K12: rock awash at chart datum (WATLEV=5).\n NOAA portrayal: bold 4-line asterisk enclosed in a dotted oval \u2014 the\n oval signals "at chart datum, dangerous" and visually distinguishes\n awash rocks from sounded submerged rocks (UWTROC04). 18-unit asterisk\n inside a 28\xD722 dotted oval. -->\n <ellipse cx="16" cy="16" rx="14" ry="11" fill="none" stroke="CHBLK" stroke-width="1.0" stroke-dasharray="1.0,1.2" />\n <path d="M 16 7 L 16 25" fill="none" stroke="CHBLK" stroke-width="1.5" stroke-linecap="round" />\n <path d="M 7 16 L 25 16" fill="none" stroke="CHBLK" stroke-width="1.5" stroke-linecap="round" />\n <path d="M 9.5 9.5 L 22.5 22.5" fill="none" stroke="CHBLK" stroke-width="1.5" stroke-linecap="round" />\n <path d="M 22.5 9.5 L 9.5 22.5" fill="none" stroke="CHBLK" stroke-width="1.5" stroke-linecap="round" />\n</svg>\n',
8574
+ "UWTROC04": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <!-- S-52 PresLib UWTROC04 / INT1 K13: underwater rock always submerged with\n sounded depth (WATLEV=3, dangerous to surface navigation). NOAA portrayal:\n bold 4-line asterisk, depth value rendered separately by VALSOU label.\n 18-unit span with 1.6 stroke for clear visibility at harbor zoom \u2014 these\n are safety-critical hazards and need to read like NOAA paper-chart\n asterisks (~2 mm at 1:5000 \u2248 18 px on screen at z16). -->\n <path d="M 16 7 L 16 25" fill="none" stroke="CHBLK" stroke-width="1.6" stroke-linecap="round" />\n <path d="M 7 16 L 25 16" fill="none" stroke="CHBLK" stroke-width="1.6" stroke-linecap="round" />\n <path d="M 9.5 9.5 L 22.5 22.5" fill="none" stroke="CHBLK" stroke-width="1.6" stroke-linecap="round" />\n <path d="M 22.5 9.5 L 9.5 22.5" fill="none" stroke="CHBLK" stroke-width="1.6" stroke-linecap="round" />\n</svg>\n',
7487
8575
  "VECGND01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 7.5 26.4 L 15.9 15.8 L 24.6 26.6" fill="none" stroke="SHIPS" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 23.3 L 15.8 5.4 L 31.0 23.4" fill="none" stroke="SHIPS" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7488
8576
  "VECGND21": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 7.5 26.4 L 15.9 15.8 L 24.6 26.6" fill="none" stroke="ARPAT" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 23.3 L 15.8 5.4 L 31.0 23.4" fill="none" stroke="ARPAT" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7489
8577
  "VECWTR01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 24.9 L 15.8 7.0 L 31.0 25.0" fill="none" stroke="SHIPS" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7490
8578
  "VECWTR21": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 24.9 L 15.8 7.0 L 31.0 25.0" fill="none" stroke="ARPAT" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
8579
+ "WATTUR01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 8 11 Q 12 9 16 11 T 24 11" fill="none" stroke="CHBLK" stroke-width="1.4" stroke-linecap="round" />\n <path d="M 8 16 Q 12 14 16 16 T 24 16" fill="none" stroke="CHBLK" stroke-width="1.4" stroke-linecap="round" />\n <path d="M 8 21 Q 12 19 16 21 T 24 21" fill="none" stroke="CHBLK" stroke-width="1.4" stroke-linecap="round" />\n</svg>\n',
7491
8580
  "WATTUR02": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 1.0 18.9 L 2.8 18.3 L 5.0 16.8 L 7.0 13.9 L 9.0 12.9 L 11.2 13.1 L 9.0 15.1 L 9.0 17.0 L 11.3 19.1 L 13.2 18.3 L 15.0 17.1 L 17.1 13.9 L 19.3 13.0 L 21.1 13.1 L 19.0 15.1 L 18.9 17.2 L 21.3 19.1 L 23.3 18.2 L 25.0 17.1 L 27.0 14.1 L 29.3 13.0 L 31.0 13.2 L 29.0 15.7 L 29.1 17.2 L 30.9 19.1" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7492
8581
  "WAYPNT01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="PLRTE" stroke-width="1.8" />\n</svg>\n',
7493
8582
  "WAYPNT03": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <circle cx="16.00" cy="16.00" r="15.00" fill="none" stroke="APLRT" stroke-width="1.2" />\n</svg>\n',
@@ -7505,6 +8594,7 @@ var S52_POINT_SVGS = {
7505
8594
  };
7506
8595
  var S52_PATTERN_SVGS = {
7507
8596
  "AIRARE02": '<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 28 28">\n <path d="M 8.9 25.1 L 18.8 25.1 L 15.9 21.8 L 15.9 17.6 L 27.0 17.6 L 16.8 10.7 L 16.8 5.6 L 14.3 2.9 L 11.3 5.6 L 11.3 10.7 L 1.0 17.3 L 11.5 17.4 L 11.5 22.0 L 8.9 25.1" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
8597
+ "CBLARE01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 0 32 L 32 0" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-opacity="0.7" />\n <path d="M -16 32 L 16 0" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-opacity="0.7" />\n <path d="M 16 32 L 48 0" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-opacity="0.7" />\n</svg>\n',
7508
8598
  "DIAMOND1": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 8.2 1.0 L 23.8 31.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 8.2 31.0 L 23.8 1.0" fill="none" stroke="CHBLK" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7509
8599
  "DQUALA11": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 22.4 9.2 L 27.7 9.2" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 26.7 7.1 L 23.5 11.4" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 23.5 7.1 L 26.7 11.4" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 13.1 9.2 L 18.5 9.2" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 17.4 7.1 L 14.2 11.4" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 14.2 7.1 L 17.4 11.4" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 3.8 9.3 L 9.1 9.3" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 8.1 7.2 L 4.9 11.5" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 4.9 7.2 L 8.1 11.5" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 8.8 15.5 L 14.1 15.5" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 13.0 13.4 L 9.8 17.6" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 9.9 13.4 L 13.0 17.6" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 18.1 15.4 L 23.4 15.4" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 22.4 13.3 L 19.2 17.6" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 19.2 13.3 L 22.4 17.5" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 13.7 21.4 L 19.0 21.4" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 18.0 19.3 L 14.8 23.6" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 14.8 19.3 L 18.0 23.6" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.5 9.0 L 1.0 7.6 L 1.2 6.6 L 1.5 5.9 L 2.4 5.6 L 2.9 5.5 L 28.1 5.5 L 29.6 5.7 L 30.5 6.1 L 30.8 6.6 L 31.0 7.1 L 31.0 7.5 L 31.0 8.2 L 30.7 8.7 L 18.5 24.9 L 18.0 25.4 L 17.6 26.0 L 17.1 26.3 L 16.8 26.3 L 16.4 26.5 L 15.8 26.4 L 15.5 26.3 L 14.8 26.1 L 14.4 25.8 L 14.1 25.4 L 13.7 25.0 L 1.5 9.0" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7510
8600
  "DQUALA21": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 22.4 9.2 L 27.7 9.2" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 26.7 7.1 L 23.5 11.4" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 23.5 7.1 L 26.7 11.4" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 13.1 9.2 L 18.5 9.2" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 17.4 7.1 L 14.2 11.4" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 14.2 7.1 L 17.4 11.4" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 3.8 9.3 L 9.1 9.3" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 8.1 7.2 L 4.9 11.5" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 4.9 7.2 L 8.1 11.5" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 8.8 15.5 L 14.1 15.5" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 13.0 13.4 L 9.8 17.6" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 9.9 13.4 L 13.0 17.6" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 18.1 15.4 L 23.4 15.4" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 22.4 13.3 L 19.2 17.6" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 19.2 13.3 L 22.4 17.5" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.5 9.0 L 1.0 7.6 L 1.2 6.6 L 1.5 5.9 L 2.4 5.6 L 2.9 5.5 L 28.1 5.5 L 29.6 5.7 L 30.5 6.1 L 30.8 6.6 L 31.0 7.1 L 31.0 7.5 L 31.0 8.2 L 30.7 8.7 L 18.5 24.9 L 18.0 25.4 L 17.6 26.0 L 17.1 26.3 L 16.8 26.3 L 16.4 26.5 L 15.8 26.4 L 15.5 26.3 L 14.8 26.1 L 14.4 25.8 L 14.1 25.4 L 13.7 25.0 L 1.5 9.0" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
@@ -7522,6 +8612,7 @@ var S52_PATTERN_SVGS = {
7522
8612
  "MARSHES1": '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">\n <path d="M 8.0 10.4 L 8.0 1.1" fill="none" stroke="CHBRN" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 3.7 14.9 L 12.4 14.9" fill="none" stroke="CHBRN" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 1.0 12.0 L 15.0 12.0" fill="none" stroke="CHBRN" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 5.0 11.6 L 2.5 5.8" fill="none" stroke="CHBRN" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 10.8 11.6 L 13.3 6.0" fill="none" stroke="CHBRN" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7523
8613
  "NODATA03": '<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 28 28">\n <path d="M 1.0 14.1 L 27.0 13.9" fill="none" stroke="CHGRD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7524
8614
  "OVERSC01": '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">\n <path d="M 8.0 1.0 L 8.0 15.0" fill="none" stroke="CHGRD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
8615
+ "PIPARE01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 0 32 L 32 0" fill="none" stroke="PIPLN" stroke-width="0.8" stroke-opacity="0.7" />\n <path d="M -16 32 L 16 0" fill="none" stroke="PIPLN" stroke-width="0.8" stroke-opacity="0.7" />\n <path d="M 16 32 L 48 0" fill="none" stroke="PIPLN" stroke-width="0.8" stroke-opacity="0.7" />\n</svg>\n',
7525
8616
  "PRTSUR01": '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">\n <path d="M 1.0 8.0 L 15.0 8.0" fill="none" stroke="CHGRD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7526
8617
  "QUESMRK1": '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">\n <path d="M 5.5 4.9 L 6.1 3.8 L 6.6 2.7 L 7.3 2.1 L 8.0 1.4 L 9.0 1.0 L 10.0 1.1 L 11.2 1.4 L 12.3 1.7 L 13.3 3.1 L 14.0 3.8 L 14.5 4.7 L 14.5 5.8 L 14.0 6.7 L 13.5 7.6 L 12.6 8.6 L 11.7 9.6 L 10.9 10.6 L 10.3 11.4 L 9.9 12.1 L 9.8 13.0 L 9.8 13.9 L 9.8 14.6 L 9.9 15.5 L 9.9 15.6" fill="none" stroke="CHMGD" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 9.0 19.0 L 11.2 19.0" fill="none" stroke="CHMGD" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
7527
8618
  "RCKLDG01": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">\n <path d="M 5.6 29.0 L 9.8 25.7" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 4.2 7.2 L 6.2 13.2" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 16.1 14.7 L 13.0 19.2" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 13.2 7.8 L 14.7 3.1" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 17.9 22.2 L 18.9 27.8" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 28.8 21.5 L 31.0 16.5" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 29.1 9.8 L 24.2 8.2" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 6.2 13.1 L 1.0 10.4" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 13.2 19.1 L 12.7 13.9" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 5.5 29.0 L 6.0 24.0" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 18.0 22.2 L 22.1 25.5" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 30.9 16.5 L 25.7 18.7" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 24.3 8.3 L 28.3 5.6" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n <path d="M 14.7 3.0 L 16.8 7.6" fill="none" stroke="LANDF" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" />\n</svg>\n',
@@ -7672,7 +8763,20 @@ var FILL_OUTLINE_LAYERS = /* @__PURE__ */ new Set([
7672
8763
  "FAIRWY",
7673
8764
  "TESARE",
7674
8765
  "MIPARE",
7675
- "PRCARE"
8766
+ "PRCARE",
8767
+ "PYLONS"
8768
+ ]);
8769
+ var REGULATED_AREA_BOUNDARY_LAYERS = {
8770
+ CBLARE: "CHMGD",
8771
+ PIPARE: "PIPLN"
8772
+ };
8773
+ var LINE_FROM_POLYGON_LAYERS = /* @__PURE__ */ new Set([
8774
+ "CTNARE",
8775
+ "RESARE",
8776
+ "MIPARE",
8777
+ "TESARE",
8778
+ "MAGVAR",
8779
+ "PRDARE"
7676
8780
  ]);
7677
8781
  var ZOOM_SCALED_LINES2 = {
7678
8782
  DEPCNT: [8, 0.3, 14, 0.8],
@@ -7682,8 +8786,66 @@ var ZOOM_SCALED_LINES2 = {
7682
8786
  BRIDGE: [8, 1, 14, 2],
7683
8787
  DAMCON: [8, 1, 14, 2]
7684
8788
  };
7685
- var OPAQUE_FILLS = /* @__PURE__ */ new Set(["DEPARE", "LNDARE", "UNSARE", "LAKARE", "DRGARE"]);
8789
+ var OPAQUE_FILLS = /* @__PURE__ */ new Set(["DEPARE", "LNDARE", "UNSARE", "LAKARE", "DRGARE", "SEAARE"]);
7686
8790
  var SAFETY_GROUPS = /* @__PURE__ */ new Set([24020, 27010, 27070, 27080]);
8791
+ var HAZARD_GROUPS = /* @__PURE__ */ new Set([24020]);
8792
+ var CHILD_ICON_OFFSETS = {
8793
+ FOGSIG: [-22, 18],
8794
+ // lower-left quadrant of the buoy symbol
8795
+ RTPBCN: [22, 18],
8796
+ // lower-right quadrant
8797
+ TOPMAR: [0, -24],
8798
+ // directly above the buoy symbol
8799
+ DAYMAR: [0, -20],
8800
+ // directly above (like TOPMAR)
8801
+ LIGHTS: [14, 14]
8802
+ // lower-right, off the buoy hull so the flare is visible
8803
+ };
8804
+ var SAFETY_CRITICAL_LABELS = /* @__PURE__ */ new Set([
8805
+ "LIGHTS",
8806
+ "SOUNDG",
8807
+ "BOYLAT",
8808
+ "BCNLAT",
8809
+ "BOYCAR",
8810
+ "BCNCAR",
8811
+ "BOYSPP",
8812
+ "BCNSPP",
8813
+ "BOYISD",
8814
+ "BOYSAW",
8815
+ "FOGSIG",
8816
+ "RTPBCN"
8817
+ ]);
8818
+ var HIGH_DENSITY_NAV_AIDS = /* @__PURE__ */ new Set([
8819
+ "BOYLAT",
8820
+ "BOYCAR",
8821
+ "BOYSPP",
8822
+ "BOYISD",
8823
+ "BOYSAW",
8824
+ "BOYINB",
8825
+ "BCNLAT",
8826
+ "BCNCAR",
8827
+ "BCNSPP",
8828
+ "BCNISD",
8829
+ "BCNSAW"
8830
+ ]);
8831
+ function buildNavAidLabelExpression() {
8832
+ const colourPrefix = colourCodeCase(
8833
+ [
8834
+ ["3", "R "],
8835
+ ["4", "G "],
8836
+ ["6", "Y "]
8837
+ ],
8838
+ ""
8839
+ );
8840
+ return [
8841
+ "case",
8842
+ ["has", "_navAidLabel"],
8843
+ ["get", "_navAidLabel"],
8844
+ ["has", "OBJNAM"],
8845
+ ["concat", colourPrefix, ["get", "OBJNAM"]],
8846
+ ""
8847
+ ];
8848
+ }
7687
8849
  function buildLightLabelExpression() {
7688
8850
  const litchrExpr = [
7689
8851
  "match",
@@ -7712,21 +8874,26 @@ function buildLightLabelExpression() {
7712
8874
  "UQ",
7713
8875
  ""
7714
8876
  ];
7715
- const colourExpr = [
7716
- "match",
7717
- ["coalesce", ["get", "COLOUR"], 0],
7718
- 1,
7719
- " W",
7720
- 3,
7721
- " R",
7722
- 4,
7723
- " G",
7724
- 5,
7725
- " Bu",
7726
- 6,
7727
- " Y",
7728
- 11,
7729
- " Or",
8877
+ const colourExpr = colourCodeCase(
8878
+ [
8879
+ ["3", " R"],
8880
+ ["4", " G"],
8881
+ ["6", " Y"],
8882
+ ["11", " Or"],
8883
+ ["5", " Bu"],
8884
+ ["1", " W"]
8885
+ ],
8886
+ ""
8887
+ );
8888
+ const siggrpExpr = [
8889
+ "case",
8890
+ [
8891
+ "all",
8892
+ ["has", "SIGGRP"],
8893
+ ["!=", ["coalesce", ["get", "SIGGRP"], ""], ""],
8894
+ ["!=", ["coalesce", ["get", "SIGGRP"], "(1)"], "(1)"]
8895
+ ],
8896
+ ["to-string", ["get", "SIGGRP"]],
7730
8897
  ""
7731
8898
  ];
7732
8899
  const sigperExpr = [
@@ -7735,7 +8902,7 @@ function buildLightLabelExpression() {
7735
8902
  ["concat", " ", ["to-string", ["get", "SIGPER"]], "s"],
7736
8903
  ""
7737
8904
  ];
7738
- return ["concat", litchrExpr, colourExpr, sigperExpr];
8905
+ return ["concat", litchrExpr, siggrpExpr, colourExpr, sigperExpr];
7739
8906
  }
7740
8907
  function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION) {
7741
8908
  if (!S52_LOOKUP[objectClass]) return [];
@@ -7757,7 +8924,9 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION) {
7757
8924
  "s52:category": entry?.category ?? "Meta"
7758
8925
  }
7759
8926
  };
7760
- if (GEOM_FILTERS[resolved.type]) {
8927
+ if (resolved.type === "line" && LINE_FROM_POLYGON_LAYERS.has(objectClass)) {
8928
+ layer.filter = GEOM_FILTERS.fill;
8929
+ } else if (GEOM_FILTERS[resolved.type]) {
7761
8930
  layer.filter = GEOM_FILTERS[resolved.type];
7762
8931
  }
7763
8932
  if (resolved.minzoom) {
@@ -7772,17 +8941,180 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION) {
7772
8941
  }
7773
8942
  if (resolved.type === "symbol") {
7774
8943
  const iconExpr = getIconExpression(objectClass);
8944
+ const childOffset = CHILD_ICON_OFFSETS[objectClass];
8945
+ const isSafetyCritical = SAFETY_GROUPS.has(entry?.viewingGroup ?? 0);
8946
+ const safetyCriticalIconSize = [
8947
+ "interpolate",
8948
+ ["linear"],
8949
+ ["zoom"],
8950
+ 6,
8951
+ 0.4,
8952
+ 12,
8953
+ 0.45,
8954
+ 14,
8955
+ 0.6,
8956
+ 18,
8957
+ 1.1
8958
+ ];
8959
+ const defaultIconSize = [
8960
+ "interpolate",
8961
+ ["linear"],
8962
+ ["zoom"],
8963
+ 6,
8964
+ 0.32,
8965
+ 13,
8966
+ 0.32,
8967
+ 14,
8968
+ 0.36,
8969
+ 18,
8970
+ 1.04
8971
+ ];
7775
8972
  layer.layout = {
7776
8973
  "icon-image": iconExpr,
7777
- "icon-size": ["interpolate", ["linear"], ["zoom"], 8, 0.4, 14, 0.8],
7778
- "icon-allow-overlap": SAFETY_GROUPS.has(entry?.viewingGroup ?? 0),
7779
- "icon-optional": !SAFETY_GROUPS.has(entry?.viewingGroup ?? 0),
7780
- ...resolved.layout ?? {}
8974
+ "icon-size": defaultIconSize,
8975
+ "icon-allow-overlap": isSafetyCritical,
8976
+ "icon-optional": !isSafetyCritical,
8977
+ ...childOffset ? { "icon-offset": childOffset } : {},
8978
+ ...resolved.layout ?? {},
8979
+ // Safety-critical icon-size MUST be applied AFTER the resolved.layout
8980
+ // spread. Otherwise the static "icon-size" baked into safety-critical
8981
+ // lookup entries (LIGHTS 0.7, BOYLAT 0.7, BCNLAT 0.6, BCNSPP 0.6,
8982
+ // FOGSIG 0.6, RTPBCN 0.6) suppresses the coastal-scale curve and the
8983
+ // icons stay invisibly small at z9–z11 next to their large labels.
8984
+ // Non-safety classes keep the static-or-default cascade from above.
8985
+ ...isSafetyCritical ? { "icon-size": safetyCriticalIconSize } : {}
7781
8986
  };
8987
+ if (HAZARD_GROUPS.has(entry?.viewingGroup ?? 0)) {
8988
+ const watlev = ["to-number", ["coalesce", ["get", "WATLEV"], ["get", "watlev"], 0], 0];
8989
+ const valsou = ["to-number", ["coalesce", ["get", "VALSOU"], ["get", "valsou"], 99], 99];
8990
+ const hazardIconSize = [
8991
+ "interpolate",
8992
+ ["linear"],
8993
+ ["zoom"],
8994
+ 10,
8995
+ 0.3,
8996
+ 12,
8997
+ 0.5,
8998
+ 13,
8999
+ 0.65,
9000
+ 14,
9001
+ 0.9,
9002
+ 16,
9003
+ 1.2,
9004
+ 18,
9005
+ 1.5
9006
+ ];
9007
+ layer.layout = {
9008
+ ...layer.layout,
9009
+ "icon-size": hazardIconSize,
9010
+ "icon-allow-overlap": false,
9011
+ "icon-optional": true,
9012
+ // Pad each hazard's collision box so adjacent rocks don't stack
9013
+ // visually. At z12–13 a 2 px pad roughly doubles the dedupe
9014
+ // radius relative to the rendered icon, which is the difference
9015
+ // between a black mass and individually-legible hazards.
9016
+ "icon-padding": 2,
9017
+ "symbol-sort-key": [
9018
+ "case",
9019
+ ["==", watlev, 4],
9020
+ 1,
9021
+ ["==", watlev, 5],
9022
+ 2,
9023
+ // Submerged rocks: sounded depth determines priority. Shallower
9024
+ // = smaller sort-key = wins collisions. Offset by 10 so any
9025
+ // submerged rock still loses to a covers-and-uncovers / awash
9026
+ // hazard at the same point, but ranks dangerously-shallow
9027
+ // submerged rocks above deeper ones.
9028
+ ["+", 10, valsou]
9029
+ ]
9030
+ };
9031
+ }
9032
+ if (objectClass === "LIGHTS") {
9033
+ layer.paint["icon-color"] = lightFillExpression(ct);
9034
+ layer.paint["icon-halo-color"] = resolveColor("CHBLK", ct);
9035
+ layer.paint["icon-halo-width"] = 1;
9036
+ }
7782
9037
  } else if (resolved.layout) {
7783
9038
  layer.layout = resolved.layout;
7784
9039
  }
9040
+ if (objectClass === "LNDMRK" && resolved.type === "symbol") {
9041
+ const baseFilterParts = layer.filter && layer.filter[0] === "all" ? layer.filter.slice(1) : layer.filter ? [layer.filter] : [];
9042
+ const catlmk = ["coalesce", ["get", "CATLMK"], ["get", "catlmk"], 0];
9043
+ const isWind = ["any", ["==", catlmk, 18], ["==", catlmk, 19]];
9044
+ const isLighthouse = ["==", catlmk, 17];
9045
+ const scaminFloor = scaminToMinZoom(entry?.scamin);
9046
+ const windLayer = {
9047
+ ...layer,
9048
+ id: `s52-${objectClass}-wind-symbol`,
9049
+ filter: ["all", ...baseFilterParts, isWind]
9050
+ };
9051
+ delete windLayer.minzoom;
9052
+ const lighthouseLayer = {
9053
+ ...layer,
9054
+ id: `s52-${objectClass}-lighthouse-symbol`,
9055
+ filter: ["all", ...baseFilterParts, isLighthouse],
9056
+ layout: {
9057
+ ...layer.layout ?? {},
9058
+ "icon-image": "LIGHTHOUSE01"
9059
+ }
9060
+ };
9061
+ delete lighthouseLayer.minzoom;
9062
+ const otherLayer = {
9063
+ ...layer,
9064
+ id: `s52-${objectClass}-other-symbol`,
9065
+ filter: ["all", ...baseFilterParts, ["!", isWind], ["!", isLighthouse]]
9066
+ };
9067
+ if (scaminFloor !== void 0) {
9068
+ otherLayer.minzoom = scaminFloor;
9069
+ }
9070
+ layers.push(windLayer, lighthouseLayer, otherLayer);
9071
+ continue;
9072
+ }
7785
9073
  layers.push(layer);
9074
+ if (HAZARD_GROUPS.has(entry?.viewingGroup ?? 0) && resolved.type === "symbol") {
9075
+ const HAZARD_SAFETY_CONTOUR_M = 9;
9076
+ const valsouNum = ["to-number", ["coalesce", ["get", "VALSOU"], ["get", "valsou"], 999], 999];
9077
+ const watlevNum = ["to-number", ["coalesce", ["get", "WATLEV"], ["get", "watlev"], 0], 0];
9078
+ layers.push({
9079
+ id: `s52-${objectClass}-danger-ring`,
9080
+ type: "symbol",
9081
+ source: sourceId,
9082
+ "source-layer": objectClass,
9083
+ filter: [
9084
+ "all",
9085
+ GEOM_FILTERS.symbol,
9086
+ [
9087
+ "any",
9088
+ ["<", valsouNum, HAZARD_SAFETY_CONTOUR_M],
9089
+ ["==", watlevNum, 4]
9090
+ ]
9091
+ ],
9092
+ layout: {
9093
+ "icon-image": "DNGCIR01",
9094
+ "icon-size": [
9095
+ "interpolate",
9096
+ ["linear"],
9097
+ ["zoom"],
9098
+ 12.99,
9099
+ 0,
9100
+ 13,
9101
+ 0.55,
9102
+ 14,
9103
+ 0.85,
9104
+ 16,
9105
+ 1.15,
9106
+ 18,
9107
+ 1.45
9108
+ ],
9109
+ "icon-allow-overlap": true,
9110
+ "icon-ignore-placement": true,
9111
+ "icon-optional": true
9112
+ },
9113
+ paint: {},
9114
+ minzoom: 13,
9115
+ metadata: { "s52:objectClass": objectClass, "s52:role": "isolated-danger-ring" }
9116
+ });
9117
+ }
7786
9118
  if (resolved.type === "fill" && FILL_OUTLINE_LAYERS.has(objectClass)) {
7787
9119
  const outlineColor = objectClass === "DEPARE" ? resolveColor("CHGRD", ct) : resolveColor("CHGRF", ct);
7788
9120
  layers.push({
@@ -7799,12 +9131,650 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION) {
7799
9131
  metadata: { "s52:objectClass": objectClass, "s52:role": "outline" }
7800
9132
  });
7801
9133
  }
9134
+ if (resolved.type === "fill" && REGULATED_AREA_BOUNDARY_LAYERS[objectClass]) {
9135
+ const boundaryColor = resolveColor(REGULATED_AREA_BOUNDARY_LAYERS[objectClass], ct);
9136
+ layers.push({
9137
+ id: `s52-${objectClass}-boundary`,
9138
+ type: "line",
9139
+ source: sourceId,
9140
+ "source-layer": objectClass,
9141
+ filter: GEOM_FILTERS.fill,
9142
+ paint: {
9143
+ "line-color": boundaryColor,
9144
+ "line-width": 1,
9145
+ "line-dasharray": [4, 2],
9146
+ "line-opacity": 0.85
9147
+ },
9148
+ metadata: { "s52:objectClass": objectClass, "s52:role": "boundary" }
9149
+ });
9150
+ }
9151
+ if (objectClass === "ACHARE" && resolved.type === "fill") {
9152
+ layers.push({
9153
+ id: "s52-ACHARE-boundary",
9154
+ type: "line",
9155
+ source: sourceId,
9156
+ "source-layer": "ACHARE",
9157
+ filter: GEOM_FILTERS.fill,
9158
+ paint: {
9159
+ "line-color": resolveColor("CHMGD", ct),
9160
+ "line-width": 0.8,
9161
+ "line-dasharray": [3, 2],
9162
+ "line-opacity": 0.7
9163
+ },
9164
+ metadata: { "s52:objectClass": "ACHARE", "s52:role": "boundary" }
9165
+ });
9166
+ }
9167
+ if (objectClass === "ACHARE" && resolved.type === "fill") {
9168
+ layers.push({
9169
+ id: "s52-ACHARE-anchor-icon",
9170
+ type: "symbol",
9171
+ source: sourceId,
9172
+ "source-layer": "ACHARE",
9173
+ filter: GEOM_FILTERS.fill,
9174
+ layout: {
9175
+ "icon-image": "ACHARE02",
9176
+ "icon-size": ["interpolate", ["linear"], ["zoom"], 10, 0.5, 14, 0.8, 17, 1.1],
9177
+ "icon-allow-overlap": true,
9178
+ "icon-ignore-placement": false,
9179
+ "symbol-placement": "point",
9180
+ "text-field": ["case", ["has", "OBJNAM"], ["get", "OBJNAM"], ""],
9181
+ "text-size": ["interpolate", ["linear"], ["zoom"], 11, 9, 16, 11],
9182
+ "text-anchor": "top",
9183
+ "text-offset": [0, 1.4],
9184
+ "text-optional": true,
9185
+ "text-font": ["Open Sans Italic"],
9186
+ "text-allow-overlap": false
9187
+ },
9188
+ paint: {
9189
+ "text-color": resolveColor("CHMGD", ct),
9190
+ "text-halo-color": resolveColor("CHWHT", ct),
9191
+ "text-halo-width": 1
9192
+ },
9193
+ metadata: { "s52:objectClass": "ACHARE", "s52:role": "centroid-icon" }
9194
+ });
9195
+ }
9196
+ if (objectClass === "LNDARE" && resolved.type === "fill") {
9197
+ layers.push({
9198
+ id: `s52-LNDARE-point`,
9199
+ type: "circle",
9200
+ source: sourceId,
9201
+ "source-layer": "LNDARE",
9202
+ filter: GEOM_FILTERS.circle,
9203
+ paint: {
9204
+ "circle-color": resolveColor("LANDA", ct),
9205
+ "circle-radius": ["interpolate", ["linear"], ["zoom"], 12, 1.8, 14, 2.4, 17, 3.6],
9206
+ "circle-stroke-color": resolveColor("CHBLK", ct),
9207
+ "circle-stroke-width": 0.8
9208
+ },
9209
+ metadata: { "s52:objectClass": "LNDARE", "s52:role": "point" }
9210
+ });
9211
+ }
9212
+ if (objectClass === "LNDARE" && resolved.type === "fill") {
9213
+ layers.push({
9214
+ id: `s52-LNDARE-line`,
9215
+ type: "line",
9216
+ source: sourceId,
9217
+ "source-layer": "LNDARE",
9218
+ filter: GEOM_FILTERS.line,
9219
+ paint: {
9220
+ "line-color": resolveColor("CSTLN", ct),
9221
+ "line-width": ["interpolate", ["linear"], ["zoom"], 8, 0.6, 14, 1.4]
9222
+ },
9223
+ metadata: { "s52:objectClass": "LNDARE", "s52:role": "line" }
9224
+ });
9225
+ }
9226
+ if (objectClass === "BUAARE" && resolved.type === "fill") {
9227
+ layers.push({
9228
+ id: `s52-BUAARE-point`,
9229
+ type: "circle",
9230
+ source: sourceId,
9231
+ "source-layer": "BUAARE",
9232
+ filter: GEOM_FILTERS.circle,
9233
+ paint: {
9234
+ "circle-color": resolveColor("CHGRF", ct),
9235
+ "circle-radius": ["interpolate", ["linear"], ["zoom"], 8, 1.5, 12, 2.5, 16, 4],
9236
+ "circle-stroke-color": resolveColor("CHBLK", ct),
9237
+ "circle-stroke-width": 0.6
9238
+ },
9239
+ metadata: { "s52:objectClass": "BUAARE", "s52:role": "point" }
9240
+ });
9241
+ }
9242
+ if (objectClass === "RIVERS" && resolved.type === "fill") {
9243
+ layers.push({
9244
+ id: `s52-RIVERS-line`,
9245
+ type: "line",
9246
+ source: sourceId,
9247
+ "source-layer": "RIVERS",
9248
+ filter: GEOM_FILTERS.line,
9249
+ paint: {
9250
+ "line-color": resolveColor("DEPMD", ct),
9251
+ "line-width": ["interpolate", ["linear"], ["zoom"], 8, 0.5, 14, 1.2]
9252
+ },
9253
+ metadata: { "s52:objectClass": "RIVERS", "s52:role": "line" }
9254
+ });
9255
+ }
9256
+ if (objectClass === "BUISGL" && resolved.type === "circle") {
9257
+ layers.push({
9258
+ id: `s52-BUISGL-polygon`,
9259
+ type: "fill",
9260
+ source: sourceId,
9261
+ "source-layer": "BUISGL",
9262
+ filter: GEOM_FILTERS.fill,
9263
+ paint: {
9264
+ "fill-color": resolveColor("CHBRN", ct),
9265
+ "fill-opacity": 0.55
9266
+ },
9267
+ metadata: { "s52:objectClass": "BUISGL", "s52:role": "polygon" }
9268
+ });
9269
+ layers.push({
9270
+ id: `s52-BUISGL-polygon-outline`,
9271
+ type: "line",
9272
+ source: sourceId,
9273
+ "source-layer": "BUISGL",
9274
+ filter: GEOM_FILTERS.fill,
9275
+ paint: {
9276
+ "line-color": resolveColor("CHBLK", ct),
9277
+ "line-width": 0.4
9278
+ },
9279
+ metadata: { "s52:objectClass": "BUISGL", "s52:role": "polygon-outline" }
9280
+ });
9281
+ }
9282
+ if (objectClass === "BRIDGE" && resolved.type === "line") {
9283
+ layers.push({
9284
+ id: `s52-BRIDGE-polygon`,
9285
+ type: "fill",
9286
+ source: sourceId,
9287
+ "source-layer": "BRIDGE",
9288
+ filter: GEOM_FILTERS.fill,
9289
+ paint: {
9290
+ "fill-color": resolveColor("CHBRN", ct),
9291
+ "fill-opacity": 0.35
9292
+ },
9293
+ metadata: { "s52:objectClass": "BRIDGE", "s52:role": "polygon" }
9294
+ });
9295
+ layers.push({
9296
+ id: `s52-BRIDGE-polygon-outline`,
9297
+ type: "line",
9298
+ source: sourceId,
9299
+ "source-layer": "BRIDGE",
9300
+ filter: GEOM_FILTERS.fill,
9301
+ paint: {
9302
+ "line-color": resolveColor("CHBLK", ct),
9303
+ "line-width": 1
9304
+ },
9305
+ metadata: { "s52:objectClass": "BRIDGE", "s52:role": "polygon-outline" }
9306
+ });
9307
+ }
9308
+ if (objectClass === "PYLONS" && resolved.type === "fill") {
9309
+ layers.push({
9310
+ id: `s52-PYLONS-point`,
9311
+ type: "circle",
9312
+ source: sourceId,
9313
+ "source-layer": "PYLONS",
9314
+ filter: GEOM_FILTERS.circle,
9315
+ paint: {
9316
+ "circle-color": resolveColor("CHBRN", ct),
9317
+ "circle-radius": ["interpolate", ["linear"], ["zoom"], 12, 1.8, 14, 2.6, 17, 3.8],
9318
+ "circle-stroke-color": resolveColor("CHBLK", ct),
9319
+ "circle-stroke-width": 0.8
9320
+ },
9321
+ metadata: { "s52:objectClass": "PYLONS", "s52:role": "point" }
9322
+ });
9323
+ }
9324
+ if (objectClass === "WEDKLP" && resolved.type === "fill") {
9325
+ layers.push({
9326
+ id: `s52-WEDKLP-point`,
9327
+ type: "circle",
9328
+ source: sourceId,
9329
+ "source-layer": "WEDKLP",
9330
+ filter: GEOM_FILTERS.circle,
9331
+ paint: {
9332
+ "circle-color": resolveColor("CHGRN", ct),
9333
+ "circle-radius": ["interpolate", ["linear"], ["zoom"], 10, 1.5, 14, 2.5, 17, 4],
9334
+ "circle-stroke-color": resolveColor("CHBLK", ct),
9335
+ "circle-stroke-width": 0.5,
9336
+ "circle-opacity": 0.7
9337
+ },
9338
+ metadata: { "s52:objectClass": "WEDKLP", "s52:role": "point" }
9339
+ });
9340
+ }
9341
+ if (objectClass === "SLOGRD" && resolved.type === "fill") {
9342
+ layers.push({
9343
+ id: `s52-SLOGRD-point`,
9344
+ type: "circle",
9345
+ source: sourceId,
9346
+ "source-layer": "SLOGRD",
9347
+ filter: GEOM_FILTERS.circle,
9348
+ paint: {
9349
+ "circle-color": resolveColor("CHBRN", ct),
9350
+ "circle-radius": ["interpolate", ["linear"], ["zoom"], 12, 1.4, 14, 2, 17, 3],
9351
+ "circle-stroke-color": resolveColor("CHBLK", ct),
9352
+ "circle-stroke-width": 0.4,
9353
+ "circle-opacity": 0.7
9354
+ },
9355
+ metadata: { "s52:objectClass": "SLOGRD", "s52:role": "point" }
9356
+ });
9357
+ }
9358
+ if (objectClass === "RUNWAY" && resolved.type === "fill") {
9359
+ layers.push({
9360
+ id: `s52-RUNWAY-line`,
9361
+ type: "line",
9362
+ source: sourceId,
9363
+ "source-layer": "RUNWAY",
9364
+ filter: GEOM_FILTERS.line,
9365
+ paint: {
9366
+ "line-color": resolveColor("CHGRF", ct),
9367
+ "line-width": ["interpolate", ["linear"], ["zoom"], 10, 0.6, 14, 1.2, 17, 2]
9368
+ },
9369
+ metadata: { "s52:objectClass": "RUNWAY", "s52:role": "line" }
9370
+ });
9371
+ }
9372
+ if (objectClass === "FORSTC" && resolved.type === "fill") {
9373
+ layers.push({
9374
+ id: `s52-FORSTC-line`,
9375
+ type: "line",
9376
+ source: sourceId,
9377
+ "source-layer": "FORSTC",
9378
+ filter: GEOM_FILTERS.line,
9379
+ paint: {
9380
+ "line-color": resolveColor("CHBLK", ct),
9381
+ "line-width": ["interpolate", ["linear"], ["zoom"], 10, 0.6, 14, 1.2, 17, 1.8]
9382
+ },
9383
+ metadata: { "s52:objectClass": "FORSTC", "s52:role": "line" }
9384
+ });
9385
+ }
9386
+ if (objectClass === "FSHFAC" && resolved.type === "fill") {
9387
+ layers.push({
9388
+ id: `s52-FSHFAC-point`,
9389
+ type: "circle",
9390
+ source: sourceId,
9391
+ "source-layer": "FSHFAC",
9392
+ filter: GEOM_FILTERS.circle,
9393
+ paint: {
9394
+ "circle-color": resolveColor("CHBLK", ct),
9395
+ "circle-radius": ["interpolate", ["linear"], ["zoom"], 12, 1.4, 14, 2, 17, 2.8],
9396
+ "circle-stroke-color": resolveColor("CHBLK", ct),
9397
+ "circle-stroke-width": 0.4
9398
+ },
9399
+ metadata: { "s52:objectClass": "FSHFAC", "s52:role": "point" }
9400
+ });
9401
+ }
9402
+ if (objectClass === "OBSTRN" && resolved.type === "symbol") {
9403
+ layers.push({
9404
+ id: `s52-OBSTRN-polygon`,
9405
+ type: "fill",
9406
+ source: sourceId,
9407
+ "source-layer": "OBSTRN",
9408
+ filter: GEOM_FILTERS.fill,
9409
+ paint: {
9410
+ "fill-color": resolveColor("CHBLK", ct),
9411
+ "fill-opacity": 0.1
9412
+ },
9413
+ metadata: { "s52:objectClass": "OBSTRN", "s52:role": "polygon" }
9414
+ });
9415
+ layers.push({
9416
+ id: `s52-OBSTRN-polygon-outline`,
9417
+ type: "line",
9418
+ source: sourceId,
9419
+ "source-layer": "OBSTRN",
9420
+ filter: GEOM_FILTERS.fill,
9421
+ paint: {
9422
+ "line-color": resolveColor("CHBLK", ct),
9423
+ "line-width": ["interpolate", ["linear"], ["zoom"], 8, 0.8, 14, 1.4],
9424
+ "line-dasharray": [3, 2]
9425
+ },
9426
+ metadata: { "s52:objectClass": "OBSTRN", "s52:role": "polygon-outline" }
9427
+ });
9428
+ layers.push({
9429
+ id: `s52-OBSTRN-line`,
9430
+ type: "line",
9431
+ source: sourceId,
9432
+ "source-layer": "OBSTRN",
9433
+ filter: GEOM_FILTERS.line,
9434
+ paint: {
9435
+ "line-color": resolveColor("CHBLK", ct),
9436
+ "line-width": 1.2,
9437
+ "line-dasharray": [3, 2]
9438
+ },
9439
+ metadata: { "s52:objectClass": "OBSTRN", "s52:role": "line" }
9440
+ });
9441
+ }
9442
+ if (objectClass === "SLCONS" && resolved.type === "line") {
9443
+ layers.push({
9444
+ id: `s52-SLCONS-polygon`,
9445
+ type: "fill",
9446
+ source: sourceId,
9447
+ "source-layer": "SLCONS",
9448
+ filter: GEOM_FILTERS.fill,
9449
+ paint: {
9450
+ "fill-color": resolveColor("CHBRN", ct),
9451
+ "fill-opacity": 0.5
9452
+ },
9453
+ metadata: { "s52:objectClass": "SLCONS", "s52:role": "polygon" }
9454
+ });
9455
+ layers.push({
9456
+ id: `s52-SLCONS-polygon-outline`,
9457
+ type: "line",
9458
+ source: sourceId,
9459
+ "source-layer": "SLCONS",
9460
+ filter: GEOM_FILTERS.fill,
9461
+ paint: {
9462
+ "line-color": resolveColor("CHBLK", ct),
9463
+ "line-width": 0.6
9464
+ },
9465
+ metadata: { "s52:objectClass": "SLCONS", "s52:role": "polygon-outline" }
9466
+ });
9467
+ layers.push({
9468
+ id: `s52-SLCONS-point`,
9469
+ type: "circle",
9470
+ source: sourceId,
9471
+ "source-layer": "SLCONS",
9472
+ filter: GEOM_FILTERS.circle,
9473
+ paint: {
9474
+ "circle-color": resolveColor("CHBRN", ct),
9475
+ "circle-radius": ["interpolate", ["linear"], ["zoom"], 12, 1.6, 14, 2.2, 17, 3.2],
9476
+ "circle-stroke-color": resolveColor("CHBLK", ct),
9477
+ "circle-stroke-width": 0.6
9478
+ },
9479
+ metadata: { "s52:objectClass": "SLCONS", "s52:role": "point" }
9480
+ });
9481
+ }
9482
+ if (objectClass === "PRDARE" && resolved.type === "line") {
9483
+ layers.push({
9484
+ id: `s52-PRDARE-point`,
9485
+ type: "circle",
9486
+ source: sourceId,
9487
+ "source-layer": "PRDARE",
9488
+ filter: GEOM_FILTERS.circle,
9489
+ paint: {
9490
+ "circle-color": resolveColor("CHMGD", ct),
9491
+ "circle-radius": ["interpolate", ["linear"], ["zoom"], 8, 2, 14, 3.5, 17, 5],
9492
+ "circle-stroke-color": resolveColor("CHBLK", ct),
9493
+ "circle-stroke-width": 0.8,
9494
+ "circle-opacity": 0.35
9495
+ },
9496
+ metadata: { "s52:objectClass": "PRDARE", "s52:role": "point" }
9497
+ });
9498
+ }
9499
+ if (objectClass === "CTNARE" && resolved.type === "line") {
9500
+ layers.push({
9501
+ id: `s52-CTNARE-point`,
9502
+ type: "circle",
9503
+ source: sourceId,
9504
+ "source-layer": "CTNARE",
9505
+ filter: GEOM_FILTERS.circle,
9506
+ paint: {
9507
+ "circle-color": resolveColor("LITYW", ct),
9508
+ "circle-radius": ["interpolate", ["linear"], ["zoom"], 10, 1.8, 14, 2.6, 17, 4],
9509
+ "circle-stroke-color": resolveColor("CHMGD", ct),
9510
+ "circle-stroke-width": 1.2
9511
+ },
9512
+ metadata: { "s52:objectClass": "CTNARE", "s52:role": "point" }
9513
+ });
9514
+ }
9515
+ if (objectClass === "PONTON" && resolved.type === "line") {
9516
+ layers.push({
9517
+ id: `s52-PONTON-polygon`,
9518
+ type: "fill",
9519
+ source: sourceId,
9520
+ "source-layer": "PONTON",
9521
+ filter: GEOM_FILTERS.fill,
9522
+ paint: {
9523
+ "fill-color": resolveColor("CHBRN", ct),
9524
+ "fill-opacity": 0.5
9525
+ },
9526
+ metadata: { "s52:objectClass": "PONTON", "s52:role": "polygon" }
9527
+ });
9528
+ layers.push({
9529
+ id: `s52-PONTON-polygon-outline`,
9530
+ type: "line",
9531
+ source: sourceId,
9532
+ "source-layer": "PONTON",
9533
+ filter: GEOM_FILTERS.fill,
9534
+ paint: {
9535
+ "line-color": resolveColor("CHBLK", ct),
9536
+ "line-width": 0.6
9537
+ },
9538
+ metadata: { "s52:objectClass": "PONTON", "s52:role": "polygon-outline" }
9539
+ });
9540
+ }
9541
+ if (objectClass === "WRECKS" && resolved.type === "symbol") {
9542
+ layers.push({
9543
+ id: `s52-WRECKS-polygon`,
9544
+ type: "fill",
9545
+ source: sourceId,
9546
+ "source-layer": "WRECKS",
9547
+ filter: GEOM_FILTERS.fill,
9548
+ paint: {
9549
+ "fill-color": resolveColor("CHBLK", ct),
9550
+ "fill-opacity": 0.08
9551
+ },
9552
+ metadata: { "s52:objectClass": "WRECKS", "s52:role": "polygon" }
9553
+ });
9554
+ layers.push({
9555
+ id: `s52-WRECKS-polygon-outline`,
9556
+ type: "line",
9557
+ source: sourceId,
9558
+ "source-layer": "WRECKS",
9559
+ filter: GEOM_FILTERS.fill,
9560
+ paint: {
9561
+ "line-color": resolveColor("CHBLK", ct),
9562
+ "line-width": 1,
9563
+ "line-dasharray": [3, 2]
9564
+ },
9565
+ metadata: { "s52:objectClass": "WRECKS", "s52:role": "polygon-outline" }
9566
+ });
9567
+ }
9568
+ if (objectClass === "WATTUR" && resolved.type === "symbol") {
9569
+ layers.push({
9570
+ id: `s52-WATTUR-polygon`,
9571
+ type: "fill",
9572
+ source: sourceId,
9573
+ "source-layer": "WATTUR",
9574
+ filter: GEOM_FILTERS.fill,
9575
+ paint: {
9576
+ "fill-color": resolveColor("CHBLK", ct),
9577
+ "fill-opacity": 0.05
9578
+ },
9579
+ metadata: { "s52:objectClass": "WATTUR", "s52:role": "polygon" }
9580
+ });
9581
+ }
9582
+ if (objectClass === "MAGVAR" && resolved.type === "line") {
9583
+ layers.push({
9584
+ id: "s52-MAGVAR-point",
9585
+ type: "circle",
9586
+ source: sourceId,
9587
+ "source-layer": "MAGVAR",
9588
+ filter: GEOM_FILTERS.circle,
9589
+ paint: {
9590
+ "circle-color": resolveColor("CHMGD", ct),
9591
+ "circle-radius": ["interpolate", ["linear"], ["zoom"], 6, 1, 12, 2],
9592
+ "circle-stroke-color": resolveColor("CHBLK", ct),
9593
+ "circle-stroke-width": 0.4,
9594
+ "circle-opacity": 0.4
9595
+ },
9596
+ metadata: { "s52:objectClass": "MAGVAR", "s52:role": "point" }
9597
+ });
9598
+ }
9599
+ if (objectClass === "DMPGRD" && resolved.type === "fill") {
9600
+ layers.push({
9601
+ id: `s52-DMPGRD-point`,
9602
+ type: "circle",
9603
+ source: sourceId,
9604
+ "source-layer": "DMPGRD",
9605
+ filter: GEOM_FILTERS.circle,
9606
+ paint: {
9607
+ "circle-color": resolveColor("LITYW", ct),
9608
+ "circle-radius": ["interpolate", ["linear"], ["zoom"], 10, 1.5, 14, 2.5, 17, 3.6],
9609
+ "circle-stroke-color": resolveColor("CHBLK", ct),
9610
+ "circle-stroke-width": 0.5,
9611
+ "circle-opacity": 0.7
9612
+ },
9613
+ metadata: { "s52:objectClass": "DMPGRD", "s52:role": "point" }
9614
+ });
9615
+ }
9616
+ if (objectClass === "DAMCON" && resolved.type === "line") {
9617
+ layers.push({
9618
+ id: `s52-DAMCON-polygon`,
9619
+ type: "fill",
9620
+ source: sourceId,
9621
+ "source-layer": "DAMCON",
9622
+ filter: GEOM_FILTERS.fill,
9623
+ paint: {
9624
+ "fill-color": resolveColor("CHBRN", ct),
9625
+ "fill-opacity": 0.4
9626
+ },
9627
+ metadata: { "s52:objectClass": "DAMCON", "s52:role": "polygon" }
9628
+ });
9629
+ layers.push({
9630
+ id: `s52-DAMCON-polygon-outline`,
9631
+ type: "line",
9632
+ source: sourceId,
9633
+ "source-layer": "DAMCON",
9634
+ filter: GEOM_FILTERS.fill,
9635
+ paint: {
9636
+ "line-color": resolveColor("CHBLK", ct),
9637
+ "line-width": 0.6
9638
+ },
9639
+ metadata: { "s52:objectClass": "DAMCON", "s52:role": "outline" }
9640
+ });
9641
+ }
9642
+ if (objectClass === "GATCON" && resolved.type === "line") {
9643
+ layers.push({
9644
+ id: `s52-GATCON-polygon`,
9645
+ type: "fill",
9646
+ source: sourceId,
9647
+ "source-layer": "GATCON",
9648
+ filter: GEOM_FILTERS.fill,
9649
+ paint: {
9650
+ "fill-color": resolveColor("CHBRN", ct),
9651
+ "fill-opacity": 0.4
9652
+ },
9653
+ metadata: { "s52:objectClass": "GATCON", "s52:role": "polygon" }
9654
+ });
9655
+ layers.push({
9656
+ id: `s52-GATCON-polygon-outline`,
9657
+ type: "line",
9658
+ source: sourceId,
9659
+ "source-layer": "GATCON",
9660
+ filter: GEOM_FILTERS.fill,
9661
+ paint: {
9662
+ "line-color": resolveColor("CHBLK", ct),
9663
+ "line-width": 0.6
9664
+ },
9665
+ metadata: { "s52:objectClass": "GATCON", "s52:role": "outline" }
9666
+ });
9667
+ }
9668
+ if (objectClass === "CANALS" && resolved.type === "line") {
9669
+ layers.push({
9670
+ id: `s52-CANALS-polygon`,
9671
+ type: "fill",
9672
+ source: sourceId,
9673
+ "source-layer": "CANALS",
9674
+ filter: GEOM_FILTERS.fill,
9675
+ paint: {
9676
+ "fill-color": resolveColor("DEPMS", ct),
9677
+ "fill-opacity": 0.5
9678
+ },
9679
+ metadata: { "s52:objectClass": "CANALS", "s52:role": "polygon" }
9680
+ });
9681
+ }
9682
+ if (objectClass === "PILBOP" && resolved.type === "symbol") {
9683
+ layers.push({
9684
+ id: `s52-PILBOP-polygon`,
9685
+ type: "fill",
9686
+ source: sourceId,
9687
+ "source-layer": "PILBOP",
9688
+ filter: GEOM_FILTERS.fill,
9689
+ paint: {
9690
+ "fill-color": resolveColor("CHMGD", ct),
9691
+ "fill-opacity": 0.1
9692
+ },
9693
+ metadata: { "s52:objectClass": "PILBOP", "s52:role": "polygon" }
9694
+ });
9695
+ layers.push({
9696
+ id: `s52-PILBOP-polygon-outline`,
9697
+ type: "line",
9698
+ source: sourceId,
9699
+ "source-layer": "PILBOP",
9700
+ filter: GEOM_FILTERS.fill,
9701
+ paint: {
9702
+ "line-color": resolveColor("CHMGD", ct),
9703
+ "line-width": 0.8,
9704
+ "line-dasharray": [4, 2]
9705
+ },
9706
+ metadata: { "s52:objectClass": "PILBOP", "s52:role": "outline" }
9707
+ });
9708
+ }
9709
+ if (objectClass === "HRBFAC" && resolved.type === "circle") {
9710
+ layers.push({
9711
+ id: `s52-HRBFAC-polygon`,
9712
+ type: "fill",
9713
+ source: sourceId,
9714
+ "source-layer": "HRBFAC",
9715
+ filter: GEOM_FILTERS.fill,
9716
+ paint: {
9717
+ "fill-color": resolveColor("TRFCD", ct),
9718
+ "fill-opacity": 0.15
9719
+ },
9720
+ metadata: { "s52:objectClass": "HRBFAC", "s52:role": "polygon" }
9721
+ });
9722
+ }
9723
+ if (objectClass === "MARCUL" && resolved.type === "fill") {
9724
+ layers.push({
9725
+ id: `s52-MARCUL-point`,
9726
+ type: "circle",
9727
+ source: sourceId,
9728
+ "source-layer": "MARCUL",
9729
+ filter: GEOM_FILTERS.circle,
9730
+ paint: {
9731
+ "circle-color": resolveColor("CHBRN", ct),
9732
+ "circle-radius": ["interpolate", ["linear"], ["zoom"], 12, 1.2, 14, 1.8, 17, 2.6],
9733
+ "circle-stroke-color": resolveColor("CHBLK", ct),
9734
+ "circle-stroke-width": 0.4,
9735
+ "circle-opacity": 0.6
9736
+ },
9737
+ metadata: { "s52:objectClass": "MARCUL", "s52:role": "point" }
9738
+ });
9739
+ layers.push({
9740
+ id: `s52-MARCUL-line`,
9741
+ type: "line",
9742
+ source: sourceId,
9743
+ "source-layer": "MARCUL",
9744
+ filter: GEOM_FILTERS.line,
9745
+ paint: {
9746
+ "line-color": resolveColor("CHBLK", ct),
9747
+ "line-width": 0.5,
9748
+ "line-dasharray": [2, 2]
9749
+ },
9750
+ metadata: { "s52:objectClass": "MARCUL", "s52:role": "line" }
9751
+ });
9752
+ }
9753
+ if (objectClass === "RECTRC" && resolved.type === "line") {
9754
+ layers.push({
9755
+ id: `s52-RECTRC-polygon`,
9756
+ type: "fill",
9757
+ source: sourceId,
9758
+ "source-layer": "RECTRC",
9759
+ filter: GEOM_FILTERS.fill,
9760
+ paint: {
9761
+ "fill-color": resolveColor("TRFCD", ct),
9762
+ "fill-opacity": 0.05
9763
+ },
9764
+ metadata: { "s52:objectClass": "RECTRC", "s52:role": "polygon" }
9765
+ });
9766
+ }
7802
9767
  }
7803
9768
  return layers;
7804
9769
  }
7805
- function buildLabelLayer2(objectClass, ct, sourceId = DEFAULT_REGION) {
9770
+ function buildLabelLayer2(objectClass, ct, sourceId = DEFAULT_REGION, depthUnits = "meters", labelOpts = {}) {
7806
9771
  if (!LABELED_LAYERS.has(objectClass)) return null;
7807
- const config = getLabelConfig(objectClass);
9772
+ const config = getLabelConfig(objectClass, {
9773
+ colorTable: ct,
9774
+ safetyContour: labelOpts.safetyContour,
9775
+ twoShadeSoundings: labelOpts.twoShadeSoundings,
9776
+ soundingFontWeight: labelOpts.soundingFontWeight
9777
+ });
7808
9778
  if (!config) return null;
7809
9779
  let textField = config.textField;
7810
9780
  if (objectClass === "LIGHTS") {
@@ -7813,9 +9783,36 @@ function buildLabelLayer2(objectClass, ct, sourceId = DEFAULT_REGION) {
7813
9783
  if (typeof textField !== "string" && Array.isArray(textField)) {
7814
9784
  const flat = JSON.stringify(textField);
7815
9785
  if (flat.includes("_navAidLabel")) {
7816
- textField = ["get", "OBJNAM"];
9786
+ textField = buildNavAidLabelExpression();
7817
9787
  }
7818
9788
  }
9789
+ if (depthUnits === "feet") {
9790
+ if (objectClass === "SOUNDG") {
9791
+ textField = [
9792
+ "concat",
9793
+ [
9794
+ "round",
9795
+ [
9796
+ "*",
9797
+ [
9798
+ "to-number",
9799
+ ["coalesce", ["get", "depth"], ["get", "DEPTH"], ["get", "VALSOU"]],
9800
+ 0
9801
+ ],
9802
+ 3.28084
9803
+ ]
9804
+ ],
9805
+ ""
9806
+ ];
9807
+ } else if (objectClass === "DEPCNT") {
9808
+ textField = [
9809
+ "concat",
9810
+ ["round", ["*", ["to-number", ["get", "VALDCO"]], 3.28084]],
9811
+ "ft"
9812
+ ];
9813
+ }
9814
+ }
9815
+ const isSafetyCritical = SAFETY_CRITICAL_LABELS.has(objectClass);
7819
9816
  const layer = {
7820
9817
  id: `s52-${objectClass}-label`,
7821
9818
  type: "symbol",
@@ -7825,12 +9822,12 @@ function buildLabelLayer2(objectClass, ct, sourceId = DEFAULT_REGION) {
7825
9822
  layout: {
7826
9823
  "text-field": textField,
7827
9824
  "text-size": config.textSize,
7828
- "text-font": config.textFont ?? ["Open Sans Regular", "Arial Unicode MS Regular"],
9825
+ "text-font": config.textFont ?? ["Open Sans Regular"],
7829
9826
  "text-offset": config.textOffset,
7830
9827
  "text-anchor": "top",
7831
- "text-allow-overlap": false,
7832
- "text-optional": true,
7833
- "text-padding": 4,
9828
+ "text-allow-overlap": isSafetyCritical,
9829
+ "text-optional": !isSafetyCritical,
9830
+ "text-padding": isSafetyCritical ? 0 : 4,
7834
9831
  ...config.layout ?? {}
7835
9832
  },
7836
9833
  paint: {
@@ -7845,6 +9842,18 @@ function buildLabelLayer2(objectClass, ct, sourceId = DEFAULT_REGION) {
7845
9842
  if (objectClass === "DEPCNT") {
7846
9843
  layer.filter = GEOM_FILTERS.line;
7847
9844
  }
9845
+ if (objectClass === "CBLOHD" || objectClass === "PIPOHD") {
9846
+ layer.filter = GEOM_FILTERS.line;
9847
+ }
9848
+ if (objectClass === "SBDARE") {
9849
+ delete layer.filter;
9850
+ }
9851
+ if (objectClass === "MAGVAR") {
9852
+ delete layer.filter;
9853
+ }
9854
+ if (getLabelBehavior(objectClass) === "orientation-cross-band") {
9855
+ delete layer.filter;
9856
+ }
7848
9857
  return layer;
7849
9858
  }
7850
9859
  function getGeomTypesForClass(objectClass, defaultType) {
@@ -7874,6 +9883,105 @@ function getOrderedClasses() {
7874
9883
  return ordered;
7875
9884
  }
7876
9885
 
9886
+ // src/atlas/band-priority.ts
9887
+ var BAND_PRIORITY_RANGES = {
9888
+ "1": { minzoom: 3 },
9889
+ "2": { minzoom: 5 },
9890
+ "3": { minzoom: 7 },
9891
+ "4": { minzoom: 9 },
9892
+ "5": { minzoom: 11 },
9893
+ "6": { minzoom: 11 }
9894
+ };
9895
+ var BAND_DRAW_ORDER = ["1", "2", "3", "4", "5", "6"];
9896
+ var CHART_BAND_CODES = {
9897
+ Overview: ["1"],
9898
+ General: ["2"],
9899
+ Coastal: ["3"],
9900
+ Approach: ["4"],
9901
+ Harbor: ["5", "6"]
9902
+ };
9903
+ var CHART_CASCADE_CODES = {
9904
+ Overview: ["1"],
9905
+ General: ["1", "2"],
9906
+ Coastal: ["1", "2", "3"],
9907
+ Approach: ["1", "2", "3", "4"],
9908
+ Harbor: ["1", "2", "3", "4", "5", "6"]
9909
+ };
9910
+ function bandFilterExpression(codes) {
9911
+ const list = Array.isArray(codes) ? codes : [codes];
9912
+ if (list.length === 1) {
9913
+ return ["==", ["slice", ["get", "_cell_id"], 2, 3], list[0]];
9914
+ }
9915
+ return ["in", ["slice", ["get", "_cell_id"], 2, 3], ["literal", [...list]]];
9916
+ }
9917
+ function combineWithBandFilter(baseFilter, bandFilter) {
9918
+ if (!baseFilter) return bandFilter;
9919
+ if (baseFilter[0] === "all") {
9920
+ return ["all", ...baseFilter.slice(1), bandFilter];
9921
+ }
9922
+ return ["all", baseFilter, bandFilter];
9923
+ }
9924
+ var NOT_DOMINATED_FILTER = [
9925
+ "all",
9926
+ ["!", ["has", "_dominated_by_min"]],
9927
+ ["!=", ["get", "_dominated"], true]
9928
+ ];
9929
+ function dominatedByMinFilter(D) {
9930
+ const dInt = parseInt(D, 10);
9931
+ if (D === "6") {
9932
+ return [
9933
+ "any",
9934
+ ["==", ["get", "_dominated_by_min"], dInt],
9935
+ ["==", ["get", "_dominated"], true]
9936
+ ];
9937
+ }
9938
+ return ["==", ["get", "_dominated_by_min"], dInt];
9939
+ }
9940
+ function withinBboxFilter(bbox) {
9941
+ const [w, s] = bbox.sw;
9942
+ const [e, n] = bbox.ne;
9943
+ return [
9944
+ "within",
9945
+ {
9946
+ type: "Polygon",
9947
+ coordinates: [
9948
+ [
9949
+ [w, s],
9950
+ [e, s],
9951
+ [e, n],
9952
+ [w, n],
9953
+ [w, s]
9954
+ ]
9955
+ ]
9956
+ }
9957
+ ];
9958
+ }
9959
+ function worldMinusBboxPolygon(bbox) {
9960
+ const [w, s] = bbox.sw;
9961
+ const [e, n] = bbox.ne;
9962
+ return {
9963
+ type: "Polygon",
9964
+ coordinates: [
9965
+ [
9966
+ [-180, -85],
9967
+ [180, -85],
9968
+ [180, 85],
9969
+ [-180, 85],
9970
+ [-180, -85]
9971
+ ],
9972
+ // Inner ring (hole) — winding opposite to outer ring per GeoJSON
9973
+ // spec. MapLibre is permissive but we follow strict winding.
9974
+ [
9975
+ [w, s],
9976
+ [w, n],
9977
+ [e, n],
9978
+ [e, s],
9979
+ [w, s]
9980
+ ]
9981
+ ]
9982
+ };
9983
+ }
9984
+
7877
9985
  // src/atlas/style-generator.ts
7878
9986
  var META_LAYERS = /* @__PURE__ */ new Set([
7879
9987
  "DSID",
@@ -7900,28 +10008,251 @@ var PALETTE_NAMES = {
7900
10008
  DUSK: "DUSK",
7901
10009
  NIGHT: "NIGHT"
7902
10010
  };
10011
+ var DOMINANCE_EXEMPT_CLASSES = /* @__PURE__ */ new Set([
10012
+ "LNDARE",
10013
+ // Safety-critical nav-aid point classes (S-52 viewing groups 24020,
10014
+ // 27010, 27070, 27080). User-reported: offshore Mass Bay BOYSAW /
10015
+ // BOYLAT etc. disappeared at z >= 12 because the dominance index
10016
+ // tagged the coastal-band feature `_dominated_by_min` for a harbor
10017
+ // cell whose M_COVR centroid-covered the buoy but whose feature data
10018
+ // didn't actually include it — no harbor-band copy ever takes over,
10019
+ // the dominated coastal variant times out at the dominator's
10020
+ // minzoom, and the buoy vanishes. Force these classes to always
10021
+ // render their not-dominated variant regardless of `_dominated_by_min`.
10022
+ // Trade-off: where both coastal AND harbor cells genuinely have the
10023
+ // same buoy, both copies render stacked — visually indistinguishable
10024
+ // from one buoy. Safety wins over the cosmetic dedupe.
10025
+ "BOYLAT",
10026
+ "BOYCAR",
10027
+ "BOYSPP",
10028
+ "BOYISD",
10029
+ "BOYSAW",
10030
+ "BOYINB",
10031
+ "BCNLAT",
10032
+ "BCNCAR",
10033
+ "BCNSPP",
10034
+ "BCNISD",
10035
+ "BCNSAW",
10036
+ "LIGHTS",
10037
+ "LITFLT",
10038
+ "LITVES",
10039
+ "FOGSIG",
10040
+ "RTPBCN",
10041
+ "RDOSTA"
10042
+ ]);
10043
+ function isDominanceExempt(layer) {
10044
+ for (const cls of DOMINANCE_EXEMPT_CLASSES) {
10045
+ if (layer.id.startsWith(`s52-${cls}-`)) return true;
10046
+ }
10047
+ return false;
10048
+ }
10049
+ function makeBandVariants(layer, B) {
10050
+ const range = BAND_PRIORITY_RANGES[B];
10051
+ const classMinzoom = layer.minzoom ?? 0;
10052
+ const minzoom = Math.max(classMinzoom, range.minzoom);
10053
+ const variants = [];
10054
+ if (isDominanceExempt(layer)) {
10055
+ const exempt = {
10056
+ ...layer,
10057
+ id: `${layer.id}-band${B}`,
10058
+ filter: combineWithBandFilter(layer.filter, bandFilterExpression(B)),
10059
+ minzoom
10060
+ };
10061
+ delete exempt.maxzoom;
10062
+ return [exempt];
10063
+ }
10064
+ const notDom = {
10065
+ ...layer,
10066
+ id: `${layer.id}-band${B}`,
10067
+ filter: combineWithBandFilter(
10068
+ layer.filter,
10069
+ ["all", bandFilterExpression(B), NOT_DOMINATED_FILTER]
10070
+ ),
10071
+ minzoom
10072
+ };
10073
+ delete notDom.maxzoom;
10074
+ variants.push(notDom);
10075
+ const bInt = parseInt(B, 10);
10076
+ for (const D of BAND_DRAW_ORDER) {
10077
+ const dInt = parseInt(D, 10);
10078
+ if (dInt <= bInt) continue;
10079
+ const dRange = BAND_PRIORITY_RANGES[D];
10080
+ if (dRange.minzoom <= minzoom) continue;
10081
+ const domVariant = {
10082
+ ...layer,
10083
+ id: `${layer.id}-band${B}-domBy${D}`,
10084
+ filter: combineWithBandFilter(
10085
+ layer.filter,
10086
+ ["all", bandFilterExpression(B), dominatedByMinFilter(D)]
10087
+ ),
10088
+ minzoom,
10089
+ maxzoom: dRange.minzoom
10090
+ };
10091
+ variants.push(domVariant);
10092
+ }
10093
+ return variants;
10094
+ }
10095
+ function fanOrientationLabelByDominator(label) {
10096
+ const variants = [];
10097
+ variants.push({
10098
+ ...label,
10099
+ id: `${label.id}-notdom`,
10100
+ filter: combineWithBandFilter(label.filter, NOT_DOMINATED_FILTER)
10101
+ });
10102
+ for (const D of BAND_DRAW_ORDER) {
10103
+ if (D === "1") continue;
10104
+ variants.push({
10105
+ ...label,
10106
+ id: `${label.id}-domBy${D}`,
10107
+ filter: combineWithBandFilter(label.filter, dominatedByMinFilter(D)),
10108
+ maxzoom: BAND_PRIORITY_RANGES[D].minzoom
10109
+ });
10110
+ }
10111
+ return variants;
10112
+ }
10113
+ function applyHarborLabelCollisionDiscipline(variant, objectClass, code) {
10114
+ if (!HIGH_DENSITY_NAV_AIDS.has(objectClass)) return variant;
10115
+ if (code !== "5" && code !== "6") return variant;
10116
+ const oldLayout = variant.layout ?? {};
10117
+ return {
10118
+ ...variant,
10119
+ layout: {
10120
+ ...oldLayout,
10121
+ "text-allow-overlap": false,
10122
+ "text-optional": true,
10123
+ // Wider padding so even allowed labels space visually instead of
10124
+ // touching. 6 is enough to read individual buoy designations clearly
10125
+ // at z12-14 over Boston Harbor.
10126
+ "text-padding": 6,
10127
+ // Deterministic collision arbitration: prefer features with
10128
+ // longer-range nav-aid significance (VALNMR — visible nautical
10129
+ // miles), then shorter OBJNAM (tighter labels win), then FIDN as
10130
+ // tiebreaker. Lower sort-key wins in MapLibre.
10131
+ "symbol-sort-key": [
10132
+ "case",
10133
+ ["has", "VALNMR"],
10134
+ ["-", 0, ["coalesce", ["to-number", ["get", "VALNMR"]], 0]],
10135
+ ["length", ["coalesce", ["get", "OBJNAM"], ""]]
10136
+ ]
10137
+ }
10138
+ };
10139
+ }
10140
+ function chartModeFilterForBand(layer, B, higherCascadeBands, lockedBounds, isRequestedBand) {
10141
+ let filter = combineWithBandFilter(layer.filter, bandFilterExpression(B));
10142
+ if (!isDominanceExempt(layer)) {
10143
+ for (const D of higherCascadeBands) {
10144
+ filter = combineWithBandFilter(filter, ["!", dominatedByMinFilter(D)]);
10145
+ }
10146
+ }
10147
+ if (lockedBounds && isRequestedBand) {
10148
+ filter = combineWithBandFilter(filter, withinBboxFilter(lockedBounds));
10149
+ }
10150
+ return filter;
10151
+ }
7903
10152
  function generateStyle(palette = "DAY", opts = {}) {
7904
10153
  const sources = buildSources(opts);
7905
10154
  const sourceId = opts.region ?? DEFAULT_REGION;
7906
10155
  const orderedClasses = getOrderedClasses();
7907
10156
  const layers = [];
7908
10157
  const labelLayers = [];
10158
+ const chartCascade = opts.chartMode ? CHART_CASCADE_CODES[opts.chartMode.band] : null;
10159
+ const chartRequestedCodes = opts.chartMode ? CHART_BAND_CODES[opts.chartMode.band] : null;
10160
+ const lockedBounds = opts.chartMode?.lockedBounds;
10161
+ const bundles = [];
7909
10162
  for (const objectClass of orderedClasses) {
7910
10163
  if (META_LAYERS.has(objectClass)) continue;
7911
- const featureLayers = buildLayersForClass(objectClass, palette, sourceId);
7912
- layers.push(...featureLayers);
7913
- const label = buildLabelLayer2(objectClass, palette, sourceId);
7914
- if (label) labelLayers.push(label);
10164
+ bundles.push({
10165
+ objectClass,
10166
+ featureLayers: buildLayersForClass(objectClass, palette, sourceId),
10167
+ label: buildLabelLayer2(objectClass, palette, sourceId, opts.depthUnits ?? "meters", {
10168
+ safetyContour: opts.safetyContour,
10169
+ twoShadeSoundings: opts.twoShadeSoundings,
10170
+ soundingFontWeight: opts.soundingFontWeight
10171
+ })
10172
+ });
10173
+ }
10174
+ if (chartCascade && chartRequestedCodes) {
10175
+ const requestedSet = new Set(chartRequestedCodes);
10176
+ for (let i = 0; i < chartCascade.length; i++) {
10177
+ const B = chartCascade[i];
10178
+ const higher = chartCascade.slice(i + 1);
10179
+ const isRequested = requestedSet.has(B);
10180
+ for (const { featureLayers } of bundles) {
10181
+ for (const base of featureLayers) {
10182
+ const filter = chartModeFilterForBand(
10183
+ base,
10184
+ B,
10185
+ higher,
10186
+ lockedBounds,
10187
+ isRequested
10188
+ );
10189
+ const variant = {
10190
+ ...base,
10191
+ id: `${base.id}-band${B}`,
10192
+ filter
10193
+ };
10194
+ delete variant.maxzoom;
10195
+ layers.push(variant);
10196
+ }
10197
+ }
10198
+ }
10199
+ for (let i = 0; i < chartCascade.length; i++) {
10200
+ const B = chartCascade[i];
10201
+ const higher = chartCascade.slice(i + 1);
10202
+ const isRequested = requestedSet.has(B);
10203
+ for (const { label } of bundles) {
10204
+ if (!label) continue;
10205
+ const filter = chartModeFilterForBand(
10206
+ label,
10207
+ B,
10208
+ higher,
10209
+ lockedBounds,
10210
+ isRequested
10211
+ );
10212
+ const variant = {
10213
+ ...label,
10214
+ id: `${label.id}-band${B}`,
10215
+ filter
10216
+ };
10217
+ delete variant.maxzoom;
10218
+ labelLayers.push(variant);
10219
+ }
10220
+ }
10221
+ layers.push(...labelLayers);
10222
+ } else {
10223
+ for (const code of BAND_DRAW_ORDER) {
10224
+ for (const { featureLayers } of bundles) {
10225
+ for (const base of featureLayers) {
10226
+ layers.push(...makeBandVariants(base, code));
10227
+ }
10228
+ }
10229
+ }
10230
+ for (const { objectClass, label } of bundles) {
10231
+ if (!label) continue;
10232
+ if (getLabelBehavior(objectClass) === "orientation-cross-band") {
10233
+ labelLayers.push(...fanOrientationLabelByDominator(label));
10234
+ }
10235
+ }
10236
+ for (const code of BAND_DRAW_ORDER) {
10237
+ for (const { objectClass, label } of bundles) {
10238
+ if (!label) continue;
10239
+ if (getLabelBehavior(objectClass) === "orientation-cross-band") continue;
10240
+ for (const variant of makeBandVariants(label, code)) {
10241
+ labelLayers.push(applyHarborLabelCollisionDiscipline(variant, objectClass, code));
10242
+ }
10243
+ }
10244
+ }
10245
+ layers.push(...labelLayers);
7915
10246
  }
7916
- layers.push(...labelLayers);
7917
10247
  return {
7918
10248
  version: 8,
7919
- name: `CHRT S-52 ${PALETTE_NAMES[palette]}`,
10249
+ name: `CHRT S-52 ${PALETTE_NAMES[palette]}${opts.chartMode ? ` \u2014 chart:${opts.chartMode.band}` : ""}`,
7920
10250
  metadata: {
7921
10251
  "chrt:s52-edition": "4.0",
7922
10252
  "chrt:color-table": palette,
7923
10253
  "chrt:generated-at": (/* @__PURE__ */ new Date()).toISOString(),
7924
10254
  "chrt:layer-count": layers.length,
10255
+ "chrt:render-mode": opts.chartMode ? `chart:${opts.chartMode.band}` : "continuous",
7925
10256
  "chrt:description": "IHO S-52 portrayal rules for Electronic Navigational Charts (ENCs). Generated from the CHRT atlas engine."
7926
10257
  },
7927
10258
  sources,
@@ -7930,7 +10261,7 @@ function generateStyle(palette = "DAY", opts = {}) {
7930
10261
  // we're decommissioning Mapbox MTS. When the page is repurposed to
7931
10262
  // generate a MapLibre-native style for self-hosted consumers, wire the
7932
10263
  // `sprite` field back in against a CHRT-hosted sprite route (see
7933
- // `.lovable/` follow-ups). Runtime maps load S-52 symbols via
10264
+ // `.chrt/` follow-ups). Runtime maps load S-52 symbols via
7934
10265
  // `loadS52SymbolImages()` — no sprite fetch happens at runtime.
7935
10266
  glyphs: "https://fonts.openmaptiles.org/{fontstack}/{range}.pbf",
7936
10267
  layers
@@ -8102,14 +10433,19 @@ var Chrt = class {
8102
10433
  };
8103
10434
  // Annotate the CommonJS export names for ESM import in node:
8104
10435
  0 && (module.exports = {
10436
+ BAND_DRAW_ORDER,
10437
+ BAND_PRIORITY_RANGES,
8105
10438
  BUILD_MAXZOOM,
8106
10439
  BUILD_MINZOOM,
10440
+ CHART_BAND_CODES,
10441
+ CHART_CASCADE_CODES,
8107
10442
  CHART_SECTIONS,
8108
10443
  Chrt,
8109
10444
  ChrtError,
8110
10445
  DEFAULT_REGION,
8111
10446
  DEFAULT_TILE_BASE_URL,
8112
10447
  LABELED_LAYERS,
10448
+ LABEL_BEHAVIOR,
8113
10449
  NAUTICAL_SYMBOLS,
8114
10450
  OfflineError,
8115
10451
  OfflineStyleError,
@@ -8126,10 +10462,12 @@ var Chrt = class {
8126
10462
  SYMBOL_GROUPS,
8127
10463
  SYMBOL_MAP,
8128
10464
  applyColorTheme,
10465
+ bandFilterExpression,
8129
10466
  buildLabelLayer,
8130
10467
  buildLayersForClass,
8131
10468
  buildOfflineStyle,
8132
10469
  buildSources,
10470
+ combineWithBandFilter,
8133
10471
  daymarkColor,
8134
10472
  decimateFeatures,
8135
10473
  depareColor,
@@ -8146,6 +10484,7 @@ var Chrt = class {
8146
10484
  getDrawPriority,
8147
10485
  getGridSizeForZoom,
8148
10486
  getIconExpression,
10487
+ getLabelBehavior,
8149
10488
  getLabelConfig,
8150
10489
  getLookupEntry,
8151
10490
  getMaxCellsForZoom,
@@ -8171,6 +10510,8 @@ var Chrt = class {
8171
10510
  preprocessWaterBodies,
8172
10511
  resolveColor,
8173
10512
  resolveStyle,
8174
- scaminToMinZoom
10513
+ scaminToMinZoom,
10514
+ withinBboxFilter,
10515
+ worldMinusBboxPolygon
8175
10516
  });
8176
10517
  //# sourceMappingURL=index.cjs.map