@chrtco/sdk 0.10.51 → 0.10.52

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.js CHANGED
@@ -134,7 +134,7 @@ var TileTokenError = class extends Error {
134
134
  this.status = status;
135
135
  }
136
136
  };
137
- var TILE_URL_PATH = /\/v1\/tiles\/[A-Za-z0-9_]+(?:\/[a-z][a-z0-9-]*)?\/\d+\/\d+\/\d+\.(?:mvt|png)(?:\?.*)?$/i;
137
+ var TILE_URL_PATH = /\/v1\/tiles\/[A-Za-z0-9_]+(?:\/[a-z][a-z0-9-]*)?\/\d+\/\d+\/\d+\.(?:mvt|png|webp)(?:\?.*)?$/i;
138
138
  var STYLE_URL_PATH = /\/v1\/styles\/[A-Za-z0-9_]+\/style\.json(?:\?.*)?$/i;
139
139
  var REFRESH_MARGIN_SECONDS = 30;
140
140
  var STALE_GRACE_SECONDS = 1;
@@ -365,6 +365,11 @@ var LAND_BUILD_MAXZOOM = 14;
365
365
  var LAND_REGION = "CHRT_LAND";
366
366
  var RELIEF_REGION = "CHRT_RELIEF";
367
367
  var BASE_REGION = "CHRT_BASE";
368
+ var SEAFLOOR_REGION = "CHRT_SEAFLOOR";
369
+ var SEAFLOOR_ATTRIBUTION = "Seabed: NOAA OCS BlueTopo, NOAA NCEI CUDEM and Great Lakes Bathymetry, GEBCO Compilation Group (2026)";
370
+ var SEAFLOOR_MINZOOM = 4;
371
+ var SEAFLOOR_MAXZOOM = 13;
372
+ var SEAFLOOR_TILE_SIZE = 512;
368
373
  var BASE_MINZOOM = 0;
369
374
  var BASE_MAXZOOM = 11;
370
375
  var BASE_ATTRIBUTION = "\xA9 CHRT \xB7 Made with Natural Earth \xB7 \xA9 OpenStreetMap contributors";
@@ -433,6 +438,16 @@ function buildSources(opts = {}) {
433
438
  attribution: RELIEF_ATTRIBUTION
434
439
  };
435
440
  }
441
+ if (opts.seafloor) {
442
+ sources[SEAFLOOR_REGION] = {
443
+ type: "raster",
444
+ tiles: [tileTemplate(base, SEAFLOOR_REGION, "webp", buildFor(SEAFLOOR_REGION))],
445
+ tileSize: SEAFLOOR_TILE_SIZE,
446
+ minzoom: SEAFLOOR_MINZOOM,
447
+ maxzoom: SEAFLOOR_MAXZOOM,
448
+ attribution: SEAFLOOR_ATTRIBUTION
449
+ };
450
+ }
436
451
  return sources;
437
452
  }
438
453
 
@@ -1898,6 +1913,70 @@ var CONVIS_CODES = {
1898
1913
  1: { code: 1, name: "Visually conspicuous", abbr: "conspic" },
1899
1914
  2: { code: 2, name: "Not visually conspicuous" }
1900
1915
  };
1916
+ var HORDAT_CODES = {
1917
+ 1: { code: 1, name: "WGS 72" },
1918
+ 2: { code: 2, name: "WGS 84" },
1919
+ 3: { code: 3, name: "European 1950" },
1920
+ 4: { code: 4, name: "Potsdam Datum" },
1921
+ 5: { code: 5, name: "Adindan" },
1922
+ 6: { code: 6, name: "Afgooye" },
1923
+ 7: { code: 7, name: "Ain el Abd 1970" },
1924
+ 8: { code: 8, name: "Anna 1 Astro 1965" },
1925
+ 9: { code: 9, name: "Antigua Island Astro 1943" },
1926
+ 10: { code: 10, name: "Arc 1950" },
1927
+ 11: { code: 11, name: "Arc 1960" },
1928
+ 12: { code: 12, name: "Ascension Island 1958" },
1929
+ 13: { code: 13, name: "Astro beacon \\E\\ 1945" },
1930
+ 14: { code: 14, name: "Astro DOS 71/4" },
1931
+ 15: { code: 15, name: "Astro Tern Island (FRIG) 1961" },
1932
+ 16: { code: 16, name: "Astronimical Station 1952" },
1933
+ 17: { code: 17, name: "Australian Geodetic 1966" },
1934
+ 18: { code: 18, name: "Australian Geodetic 1984" },
1935
+ 19: { code: 19, name: "Ayabelle Lighthouse" },
1936
+ 20: { code: 20, name: "Bellevue (IGN)" },
1937
+ 21: { code: 21, name: "Bermuda 1957" },
1938
+ 22: { code: 22, name: "Bissau" },
1939
+ 23: { code: 23, name: "Bogota Observatory" },
1940
+ 24: { code: 24, name: "Bukit Rimpah" },
1941
+ 25: { code: 25, name: "Camp Area Astro" },
1942
+ 26: { code: 26, name: "Campo Inchauspe 1969" },
1943
+ 27: { code: 27, name: "Canton Astro 1966" },
1944
+ 28: { code: 28, name: "Cape" },
1945
+ 29: { code: 29, name: "Cape Canaveral" },
1946
+ 30: { code: 30, name: "Carthage" },
1947
+ 31: { code: 31, name: "Chatam Island Astro 1971" },
1948
+ 32: { code: 32, name: "Chua Astro" },
1949
+ 33: { code: 33, name: "Corrego Alegre" },
1950
+ 34: { code: 34, name: "Dabola" },
1951
+ 35: { code: 35, name: "Djakarta (Batavia)" },
1952
+ 36: { code: 36, name: "DOS 1968" },
1953
+ 37: { code: 37, name: "Easter Island 1967" },
1954
+ 38: { code: 38, name: "European 1979" },
1955
+ 39: { code: 39, name: "Fort Thomas 1955" },
1956
+ 40: { code: 40, name: "Gan 1970" },
1957
+ 41: { code: 41, name: "Geodetic Datum 1949" },
1958
+ 42: { code: 42, name: "Graciosa Base SW 1948" },
1959
+ 43: { code: 43, name: "Guam 1963" },
1960
+ 44: { code: 44, name: "Ganung Segara" },
1961
+ 45: { code: 45, name: "GUX 1 Astro" },
1962
+ 46: { code: 46, name: "Herat North" },
1963
+ 47: { code: 47, name: "Hjorsey 1955" },
1964
+ 48: { code: 48, name: "Hong Kong 1963" },
1965
+ 49: { code: 49, name: "Hu-Tzu-Shan" },
1966
+ 50: { code: 50, name: "Indian" },
1967
+ 51: { code: 51, name: "Indian 1954" },
1968
+ 52: { code: 52, name: "Indian 1975" },
1969
+ 53: { code: 53, name: "Ireland 1965" },
1970
+ 54: { code: 54, name: "ISTS 061 Astro 1968" },
1971
+ 55: { code: 55, name: "ISTS 073 Astro 1969" },
1972
+ 56: { code: 56, name: "Johnston Island 1961" },
1973
+ 57: { code: 57, name: "Kandawala" },
1974
+ 58: { code: 58, name: "Kerguelen Island 1949" },
1975
+ 59: { code: 59, name: "Kertau 1948" },
1976
+ 60: { code: 60, name: "Kusaie Astro 1951" },
1977
+ 99: { code: 99, name: "South Asia" },
1978
+ 100: { code: 100, name: "Tananarive Observatory 1925" }
1979
+ };
1901
1980
  var LITCHR_CODES = {
1902
1981
  1: { code: 1, name: "Fixed", abbr: "F" },
1903
1982
  2: { code: 2, name: "Flashing", abbr: "Fl" },
@@ -2067,6 +2146,37 @@ var TRAFIC_CODES = {
2067
2146
  3: { code: 3, name: "One-way" },
2068
2147
  4: { code: 4, name: "Two-way" }
2069
2148
  };
2149
+ var VERDAT_CODES = {
2150
+ 1: { code: 1, name: "Mean low water springs" },
2151
+ 2: { code: 2, name: "Mean lower low water springs" },
2152
+ 3: { code: 3, name: "Mean sea level" },
2153
+ 4: { code: 4, name: "Lowest low water" },
2154
+ 5: { code: 5, name: "Mean low water" },
2155
+ 6: { code: 6, name: "Lowest low water springs" },
2156
+ 7: { code: 7, name: "Approximate mean low water springs" },
2157
+ 8: { code: 8, name: "Indian spring low water" },
2158
+ 9: { code: 9, name: "Low water springs" },
2159
+ 10: { code: 10, name: "Approximate lowest astronomical tide" },
2160
+ 11: { code: 11, name: "Nearly lowest low water" },
2161
+ 12: { code: 12, name: "Mean lower low water" },
2162
+ 13: { code: 13, name: "Low water" },
2163
+ 14: { code: 14, name: "Approximate mean low water" },
2164
+ 15: { code: 15, name: "Approximate mean lower low water" },
2165
+ 16: { code: 16, name: "Mean high water" },
2166
+ 17: { code: 17, name: "Mean high water springs" },
2167
+ 18: { code: 18, name: "High water" },
2168
+ 19: { code: 19, name: "Approximate mean sea level" },
2169
+ 20: { code: 20, name: "High water springs" },
2170
+ 21: { code: 21, name: "Mean higher high water" },
2171
+ 22: { code: 22, name: "Equinoctial spring low water" },
2172
+ 23: { code: 23, name: "Lowest astronomical tide" },
2173
+ 24: { code: 24, name: "Local datum" },
2174
+ 25: { code: 25, name: "International Great Lakes Datum 1985" },
2175
+ 26: { code: 26, name: "Mean water level" },
2176
+ 27: { code: 27, name: "Lower low water large tide" },
2177
+ 28: { code: 28, name: "Higher high water large tide" },
2178
+ 29: { code: 29, name: "Nearly highest high water" }
2179
+ };
2070
2180
  var WATLEV_CODES = {
2071
2181
  1: { code: 1, name: "Partly submerged at high water" },
2072
2182
  2: { code: 2, name: "Always dry" },
@@ -2102,6 +2212,7 @@ var S57_CODELISTS = /* @__PURE__ */ new Map([
2102
2212
  ["COLPAT", COLPAT_CODES],
2103
2213
  ["CONDTN", CONDTN_CODES],
2104
2214
  ["CONVIS", CONVIS_CODES],
2215
+ ["HORDAT", HORDAT_CODES],
2105
2216
  ["LITCHR", LITCHR_CODES],
2106
2217
  ["MARSYS", MARSYS_CODES],
2107
2218
  ["NATCON", NATCON_CODES],
@@ -2112,6 +2223,7 @@ var S57_CODELISTS = /* @__PURE__ */ new Map([
2112
2223
  ["STATUS", STATUS_CODES],
2113
2224
  ["TOPSHP", TOPSHP_CODES],
2114
2225
  ["TRAFIC", TRAFIC_CODES],
2226
+ ["VERDAT", VERDAT_CODES],
2115
2227
  ["WATLEV", WATLEV_CODES]
2116
2228
  ]);
2117
2229
  var S57_DOMAINS = new Map(
@@ -5344,7 +5456,7 @@ var EntitlementClient = class {
5344
5456
  }
5345
5457
  if (!res.ok) {
5346
5458
  const code = mapDenialCode(res.body?.error, res.status);
5347
- const message = typeof res.body?.message === "string" ? res.body.message : code === "interact_not_enabled" ? "CHRTinteract requires the Dev plan or above. Upgrade at https://chrt.co/pricing." : `entitlement check failed (HTTP ${res.status})`;
5459
+ const message = typeof res.body?.message === "string" ? res.body.message : code === "interact_not_enabled" ? "CHRTinteract requires the Dev plan or above. Upgrade at https://platform.chrt.co/plans." : `entitlement check failed (HTTP ${res.status})`;
5348
5460
  const plan = typeof res.body?.plan === "string" ? res.body.plan : void 0;
5349
5461
  throw new InteractError(code, message, { status: res.status, plan });
5350
5462
  }
@@ -5913,6 +6025,32 @@ var InteractClient = class {
5913
6025
  }
5914
6026
  };
5915
6027
 
6028
+ // src/atlas/seafloor-layers.ts
6029
+ var SEAFLOOR_LAYER_ID = "chrtseafloor-shade";
6030
+ var SEAFLOOR_BAKE = Object.freeze({
6031
+ rgb: Object.freeze([47, 72, 88]),
6032
+ kneeAlpha: 16,
6033
+ protectedSafetyContourM: 10,
6034
+ alphaMax: 90
6035
+ });
6036
+ var SEAFLOOR_THEME_PAINT = Object.freeze({
6037
+ DAY: { "raster-brightness-min": 0, "raster-brightness-max": 1, "raster-opacity": 1 },
6038
+ DUSK: { "raster-brightness-min": 0, "raster-brightness-max": 1, "raster-opacity": 0.8 },
6039
+ NIGHT: { "raster-brightness-min": 0.55, "raster-brightness-max": 1, "raster-opacity": 0.55 }
6040
+ });
6041
+ function seafloorLayers(palette = "DAY") {
6042
+ if (palette !== "DAY" && palette !== "DUSK" && palette !== "NIGHT") return [];
6043
+ const p = SEAFLOOR_THEME_PAINT[palette];
6044
+ const layer = {
6045
+ id: SEAFLOOR_LAYER_ID,
6046
+ type: "raster",
6047
+ source: SEAFLOOR_REGION,
6048
+ minzoom: SEAFLOOR_MINZOOM,
6049
+ paint: { ...p }
6050
+ };
6051
+ return [layer];
6052
+ }
6053
+
5916
6054
  // src/atlas/chrt-svgs-generated.ts
5917
6055
  var CHRT_GLYPH_SVGS = {
5918
6056
  "badge-radar": '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="16" cy="19" r="2.6" fill="#D200D2"/><path d="M9 19a7 7 0 0 1 14 0M5 19a11 11 0 0 1 22 0" stroke="#D200D2" stroke-width="2.4" fill="none" stroke-linecap="round" stroke-dasharray="4 3"/></svg>',
@@ -7387,7 +7525,7 @@ function applyEinkPortrayal(style, palette, opts = {}) {
7387
7525
  for (const original of style.layers) {
7388
7526
  const id = original.id;
7389
7527
  const type = original.type;
7390
- if (type === "hillshade" || id.startsWith("chrtland-fade-")) continue;
7528
+ if (type === "hillshade" || id.startsWith("chrtland-fade-") || id === SEAFLOOR_LAYER_ID) continue;
7391
7529
  const layer = structuredClone(original);
7392
7530
  const paint = layer.paint ??= {};
7393
7531
  const layout = layer.layout;
@@ -25651,6 +25789,8 @@ var ORIENTATION_LABEL_PRIORITY = 900;
25651
25789
  var MAJOR_WATER_TIER_MAX = 3;
25652
25790
  var MAJOR_WATER_LABEL_PRIORITY = 280;
25653
25791
  var ISLAND_LABEL_HOIST_MINZOOM = 12;
25792
+ var LIGHTHOUSE_NAME_LABEL_PRIORITY = 270;
25793
+ var LIGHTHOUSE_NAME_FILTER = ["all", listAttrHas("FUNCTN", ["33"]), HAS_OBJNAM];
25654
25794
  function getLabelPriority(layerName) {
25655
25795
  if (getLabelBehavior(layerName) === "orientation-cross-band") {
25656
25796
  return ORIENTATION_LABEL_PRIORITY;
@@ -26628,7 +26768,7 @@ function preprocessSoundings(fc) {
26628
26768
  geometry: { type: "Point", coordinates: [coords[0], coords[1]] },
26629
26769
  properties: {
26630
26770
  ...f.properties,
26631
- depth: Math.round(depth * 10) / 10 + ""
26771
+ depth: Math.floor(depth * 10) / 10 + ""
26632
26772
  }
26633
26773
  });
26634
26774
  }
@@ -26641,7 +26781,7 @@ function preprocessSoundings(fc) {
26641
26781
  geometry: { type: "Point", coordinates: [coords[0], coords[1]] },
26642
26782
  properties: {
26643
26783
  ...f.properties,
26644
- depth: Math.round(depth * 10) / 10 + ""
26784
+ depth: Math.floor(depth * 10) / 10 + ""
26645
26785
  }
26646
26786
  });
26647
26787
  }
@@ -26926,7 +27066,7 @@ function dredgeNoteSize() {
26926
27066
  return ["interpolate", ["exponential", 2], ["zoom"], ...stops];
26927
27067
  }
26928
27068
  function noteDepthText(prop, depthUnits) {
26929
- return depthUnits === "feet" ? ["concat", ["to-string", ["round", ["*", ["to-number", ["get", prop]], 3.28084]]], " FT"] : ["concat", ["to-string", ["get", prop]], " M"];
27069
+ return depthUnits === "feet" ? ["concat", ["to-string", ["floor", ["*", ["to-number", ["get", prop]], 3.28084]]], " FT"] : ["concat", ["to-string", ["get", prop]], " M"];
26930
27070
  }
26931
27071
  function buildDredgeNoteLayers(sourceId, palette = "DAY", depthUnits = "meters") {
26932
27072
  const widthProp = depthUnits === "feet" ? "width_ft" : "width_m";
@@ -27092,11 +27232,11 @@ function buildBridgeNoteLayers(sourceId, palette = "DAY", depthUnits = "meters")
27092
27232
  const unit = imperial ? " FT" : " M";
27093
27233
  const measure = (prop) => imperial ? [
27094
27234
  "concat",
27095
- ["to-string", ["floor", ["+", 0.5, ["*", 3.28084, ["to-number", ["get", prop]]]]]],
27235
+ ["to-string", ["floor", ["*", 3.28084, ["to-number", ["get", prop]]]]],
27096
27236
  unit
27097
27237
  ] : [
27098
27238
  "concat",
27099
- ["to-string", ["/", ["floor", ["+", 0.5, ["*", 10, ["to-number", ["get", prop]]]]], 10]],
27239
+ ["to-string", ["/", ["floor", ["*", 10, ["to-number", ["get", prop]]]], 10]],
27100
27240
  unit
27101
27241
  ];
27102
27242
  const clearance = (prop, prefix, suffix = "") => [
@@ -30102,6 +30242,15 @@ function buildLayersForClass(objectClass2, ct, sourceId = DEFAULT_REGION, opts =
30102
30242
  }
30103
30243
  return layers;
30104
30244
  }
30245
+ function dangerDepthMetresDown() {
30246
+ const valsou = ["to-number", ["coalesce", ["get", "VALSOU"], ["get", "valsou"], 0], 0];
30247
+ return [
30248
+ "case",
30249
+ [">", valsou, 0],
30250
+ ["concat", ["to-string", ["/", ["floor", ["+", ["*", valsou, 10], 1e-6]], 10]], "m"],
30251
+ ""
30252
+ ];
30253
+ }
30105
30254
  function buildLabelLayer2(objectClass2, ct, sourceId = DEFAULT_REGION, depthUnits = "meters", labelOpts = {}) {
30106
30255
  if (!LABELED_LAYERS.has(objectClass2)) return null;
30107
30256
  const config = getLabelConfig(objectClass2, {
@@ -30126,7 +30275,7 @@ function buildLabelLayer2(objectClass2, ct, sourceId = DEFAULT_REGION, depthUnit
30126
30275
  textField = [
30127
30276
  "concat",
30128
30277
  [
30129
- "round",
30278
+ "floor",
30130
30279
  [
30131
30280
  "*",
30132
30281
  [
@@ -30154,10 +30303,16 @@ function buildLabelLayer2(objectClass2, ct, sourceId = DEFAULT_REGION, depthUnit
30154
30303
  textField = [
30155
30304
  "case",
30156
30305
  [">", valsouFt, 0],
30157
- ["concat", ["to-string", ["round", ["*", valsouFt, 3.28084]]], "ft"],
30306
+ [
30307
+ "concat",
30308
+ ["to-string", [labelOpts.dangerDepthRounding === "down" ? "floor" : "round", ["*", valsouFt, 3.28084]]],
30309
+ "ft"
30310
+ ],
30158
30311
  ""
30159
30312
  ];
30160
30313
  }
30314
+ } else if (labelOpts.dangerDepthRounding === "down" && (objectClass2 === "UWTROC" || objectClass2 === "OBSTRN" || objectClass2 === "WRECKS")) {
30315
+ textField = dangerDepthMetresDown();
30161
30316
  }
30162
30317
  const labelPriority = getLabelPriority(objectClass2);
30163
30318
  const layer = {
@@ -31027,7 +31182,14 @@ var DEPTH_FIGURE_CLASSES = /* @__PURE__ */ new Set(["SOUNDG", "DEPCNT", "UWTROC"
31027
31182
  function contourValueFactor(depthNumbersFactor) {
31028
31183
  return 1 + (depthNumbersFactor - 1) / 2;
31029
31184
  }
31030
- var SERVED_FONT_STACKS = ["Open Sans Regular", "Open Sans Italic", "Open Sans Semibold"];
31185
+ var SERVED_FONT_STACKS = [
31186
+ "Open Sans Regular",
31187
+ "Open Sans Italic",
31188
+ "Open Sans Semibold",
31189
+ "Old Standard TT Regular",
31190
+ "Old Standard TT Italic",
31191
+ "Old Standard TT Bold"
31192
+ ];
31031
31193
  function semiboldFontStack(font) {
31032
31194
  if (!Array.isArray(font) || !font.every((face) => typeof face === "string")) return font;
31033
31195
  return font.map((face) => {
@@ -31956,7 +32118,7 @@ function landLayers(opts = {}) {
31956
32118
  minzoom: 11.5,
31957
32119
  filter: ["all", FITS, [">=", tileNumber("peak_m", 0), 40]],
31958
32120
  layout: {
31959
- "text-field": ["concat", ["get", "name"], "\n", ["to-string", ["get", "peak_m"]], " m"],
32121
+ "text-field": opts.heightUnits === "feet" ? ["concat", ["get", "name"], "\n", ["to-string", ["round", ["*", ["to-number", ["get", "peak_m"], 0], 3.28084]]], " ft"] : ["concat", ["get", "name"], "\n", ["to-string", ["get", "peak_m"]], " m"],
31960
32122
  "text-font": FONT,
31961
32123
  "text-size": ["interpolate", ["linear"], ["zoom"], 11.5, 8.5, 14, 11],
31962
32124
  "text-offset": anchorOffset(0.8),
@@ -32321,6 +32483,23 @@ function spliceByLabelPriority(labelLayers, incoming, priority) {
32321
32483
  if (at === -1) labelLayers.push(...incoming);
32322
32484
  else labelLayers.splice(at, 0, ...incoming);
32323
32485
  }
32486
+ function hoistLighthouseNames(labelLayers) {
32487
+ const hoisted = [];
32488
+ for (const l of labelLayers) {
32489
+ if (!l.id.startsWith("s52-LNDMRK-label")) continue;
32490
+ hoisted.push({
32491
+ ...l,
32492
+ // `s52-LNDMRK-light-label…`, keeping any `-band{B}` tail last: the shape
32493
+ // of the danger-depth placers (`s52-UWTROC-placer-label`), which
32494
+ // custom-style's bandFloor() and the band-collapse id checks read.
32495
+ id: l.id.replace("s52-LNDMRK-label", "s52-LNDMRK-light-label"),
32496
+ filter: combineWithBandFilter(l.filter, LIGHTHOUSE_NAME_FILTER),
32497
+ metadata: { ...l.metadata ?? {}, "chrt:labelPriority": LIGHTHOUSE_NAME_LABEL_PRIORITY }
32498
+ });
32499
+ l.filter = combineWithBandFilter(l.filter, ["!", LIGHTHOUSE_NAME_FILTER]);
32500
+ }
32501
+ spliceByLabelPriority(labelLayers, hoisted, LIGHTHOUSE_NAME_LABEL_PRIORITY);
32502
+ }
32324
32503
  function chartModeBandClauses(layer, B, higherCascadeBands, lockedBounds, isRequestedBand) {
32325
32504
  const parts = [bandFilterExpression(B)];
32326
32505
  if (!isDominanceExempt(layer)) {
@@ -32333,6 +32512,9 @@ function chartModeBandClauses(layer, B, higherCascadeBands, lockedBounds, isRequ
32333
32512
  }
32334
32513
  return parts;
32335
32514
  }
32515
+ function strictCascade(finest) {
32516
+ return BAND_DRAW_ORDER.slice(0, BAND_DRAW_ORDER.indexOf(finest) + 1);
32517
+ }
32336
32518
  function chartModeFilterForBand(layer, B, higherCascadeBands, lockedBounds, isRequestedBand) {
32337
32519
  const [first, ...rest] = chartModeBandClauses(
32338
32520
  layer,
@@ -32366,7 +32548,8 @@ function makeCollapsedChartLabel(label, cascade, requestedSet, lockedBounds) {
32366
32548
  return collapsed;
32367
32549
  }
32368
32550
  function generateStyle(palette = "DAY", opts = {}) {
32369
- const sources = buildSources(opts);
32551
+ const seafloor = Boolean(opts.seafloor && opts.land) && seafloorLayers(palette).length > 0;
32552
+ const sources = buildSources({ ...opts, seafloor });
32370
32553
  const sourceId = opts.region ?? DEFAULT_REGION;
32371
32554
  const orderedClasses = getOrderedClasses();
32372
32555
  const backgroundLayer = {
@@ -32408,7 +32591,8 @@ function generateStyle(palette = "DAY", opts = {}) {
32408
32591
  if (opts.land) {
32409
32592
  layers.push(...landLayers({
32410
32593
  palette,
32411
- ...opts.relief ? { relief: true } : {}
32594
+ ...opts.relief ? { relief: true } : {},
32595
+ ...opts.depthUnits === "feet" ? { heightUnits: "feet" } : {}
32412
32596
  }));
32413
32597
  }
32414
32598
  if (opts.base) {
@@ -32416,8 +32600,9 @@ function generateStyle(palette = "DAY", opts = {}) {
32416
32600
  }
32417
32601
  const labelLayers = [];
32418
32602
  const majorWaterLayers = [];
32419
- const chartCascade = opts.chartMode ? CHART_CASCADE_CODES[opts.chartMode.band] : null;
32420
- const chartRequestedCodes = opts.chartMode ? CHART_BAND_CODES[opts.chartMode.band] : null;
32603
+ const finestBand = opts.chartMode?.finestBand;
32604
+ const chartCascade = opts.chartMode ? finestBand ? strictCascade(finestBand) : CHART_CASCADE_CODES[opts.chartMode.band] : null;
32605
+ const chartRequestedCodes = opts.chartMode ? finestBand ? [finestBand] : CHART_BAND_CODES[opts.chartMode.band] : null;
32421
32606
  const bandFan = opts.bandFan ?? "collapsed";
32422
32607
  const lockedBounds = opts.chartMode?.lockedBounds;
32423
32608
  const bundles = [];
@@ -32431,7 +32616,8 @@ function generateStyle(palette = "DAY", opts = {}) {
32431
32616
  label: buildLabelLayer2(objectClass2, palette, sourceId, opts.depthUnits ?? "meters", {
32432
32617
  safetyContour: opts.safetyContour,
32433
32618
  twoShadeSoundings: opts.twoShadeSoundings,
32434
- soundingFontWeight: opts.soundingFontWeight
32619
+ soundingFontWeight: opts.soundingFontWeight,
32620
+ ...opts.dangerDepthRounding ? { dangerDepthRounding: opts.dangerDepthRounding } : {}
32435
32621
  })
32436
32622
  });
32437
32623
  }
@@ -32474,7 +32660,12 @@ function generateStyle(palette = "DAY", opts = {}) {
32474
32660
  emitChartFeatureVariants(waterBaseBundles);
32475
32661
  emitChartFeatureVariants(regularBundles);
32476
32662
  emitChartFeatureVariants(topLightBundles);
32477
- layers.push(...sectorLightLayers, ...lampLayers);
32663
+ const cascadeGate = finestBand ? bandFilterExpression(chartCascade) : null;
32664
+ layers.push(
32665
+ ...[...sectorLightLayers, ...lampLayers].map(
32666
+ (l) => cascadeGate ? { ...l, filter: combineWithBandFilter(l.filter, cascadeGate) } : l
32667
+ )
32668
+ );
32478
32669
  const chartLabelBundles = byLabelPriorityBottomUp(
32479
32670
  bundles.filter(
32480
32671
  (b) => b.label !== null && (opts.labels !== "placename" || getLabelBehavior(b.objectClass) !== "orientation-cross-band")
@@ -32528,6 +32719,7 @@ function generateStyle(palette = "DAY", opts = {}) {
32528
32719
  ),
32529
32720
  BRGNOTE_LABEL_PRIORITY
32530
32721
  );
32722
+ hoistLighthouseNames(labelLayers);
32531
32723
  layers.push(...labelLayers);
32532
32724
  } else {
32533
32725
  const emitBand = (base, code) => bandFan === "legacy" ? makeBandVariants(base, code) : makeCollapsedBandVariant(base, code, isDominanceExempt(base));
@@ -32634,6 +32826,7 @@ function generateStyle(palette = "DAY", opts = {}) {
32634
32826
  ),
32635
32827
  BRGNOTE_LABEL_PRIORITY
32636
32828
  );
32829
+ hoistLighthouseNames(labelLayers);
32637
32830
  layers.push(...labelLayers);
32638
32831
  }
32639
32832
  const symbolSet = opts.symbolSet ?? "s52";
@@ -32805,6 +32998,14 @@ function generateStyle(palette = "DAY", opts = {}) {
32805
32998
  emitted.push(layer);
32806
32999
  }
32807
33000
  }
33001
+ if (seafloor) {
33002
+ const idAt = (i) => emitted[i].id;
33003
+ let lastDepthFill = -1;
33004
+ for (let i = 0; i < emitted.length; i++) {
33005
+ if (/^s52-(DEPARE|DRGARE)-fill-band\d+/.test(idAt(i))) lastDepthFill = i;
33006
+ }
33007
+ if (lastDepthFill !== -1) emitted.splice(lastDepthFill + 1, 0, ...seafloorLayers(palette));
33008
+ }
32808
33009
  const finalLayers = drapedFirst(emitted);
32809
33010
  const style = {
32810
33011
  version: 8,
@@ -32818,6 +33019,7 @@ function generateStyle(palette = "DAY", opts = {}) {
32818
33019
  "chrt:land": Boolean(opts.land),
32819
33020
  "chrt:relief": Boolean(opts.relief),
32820
33021
  "chrt:base": Boolean(opts.base),
33022
+ "chrt:seafloor": seafloor,
32821
33023
  "chrt:render-mode": opts.chartMode ? `chart:${opts.chartMode.band}` : "continuous",
32822
33024
  "chrt:description": "IHO S-52 portrayal rules for Electronic Navigational Charts (ENCs). Generated from the CHRT atlas engine."
32823
33025
  },
@@ -33831,6 +34033,8 @@ export {
33831
34033
  LAND_BUILD_MAXZOOM,
33832
34034
  LAND_REGION,
33833
34035
  LAND_TEXT_CLASSES,
34036
+ LIGHTHOUSE_NAME_FILTER,
34037
+ LIGHTHOUSE_NAME_LABEL_PRIORITY,
33834
34038
  LIGHT_LABEL_FEET_PER_METRE,
33835
34039
  MAPLIBRE_DEFAULT_TEXT_PADDING_PX,
33836
34040
  NAUTICAL_SYMBOLS,
@@ -33876,6 +34080,14 @@ export {
33876
34080
  S52_LOOKUP,
33877
34081
  S52_NIGHT,
33878
34082
  S52_PATTERN_SPRITE_PREFIX,
34083
+ SEAFLOOR_ATTRIBUTION,
34084
+ SEAFLOOR_BAKE,
34085
+ SEAFLOOR_LAYER_ID,
34086
+ SEAFLOOR_MAXZOOM,
34087
+ SEAFLOOR_MINZOOM,
34088
+ SEAFLOOR_REGION,
34089
+ SEAFLOOR_THEME_PAINT,
34090
+ SEAFLOOR_TILE_SIZE,
33879
34091
  SECTOR_ARC_LAYER_IDS,
33880
34092
  SECTOR_LEG_LAYER_IDS,
33881
34093
  SECTOR_LIGHT_LAYER_IDS,
@@ -34055,6 +34267,7 @@ export {
34055
34267
  scaleSizeExpression,
34056
34268
  scaleSizeValue,
34057
34269
  scaminToMinZoom,
34270
+ seafloorLayers,
34058
34271
  sectorLimitToArcBearing,
34059
34272
  semiboldFontStack,
34060
34273
  snapChartSymbolScale,