@chrtco/sdk 0.10.42 → 0.10.44

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
@@ -2228,6 +2228,22 @@ var S52_NIGHT = {
2228
2228
  CHBRN: "#382410",
2229
2229
  CHGRF: "#2a2a22",
2230
2230
  CHGRD: "#1e1e18",
2231
+ // The NIGHT ink — linework, symbol outlines, navigation text, the shoal
2232
+ // soundings (SNDG2 below). Light warm on dark water: a deliberate deviation
2233
+ // from the spec's near-black (#1f2223), so a NIGHT chart is legible on a
2234
+ // screen nobody has dimmed. It is the brightest thing NIGHT draws on purpose,
2235
+ // and `night-luminance.test.ts` holds everything else under its muted level.
2236
+ //
2237
+ // ⚠ RED NIGHT DOES NOT DIM IT, AND THAT WAS DECIDED, NOT MISSED (2026-10-01).
2238
+ // Red night composes this same NIGHT chart with red chrome, as iOS does
2239
+ // (ContentView `effectiveChartTheme`). Dimming the ink for red night alone
2240
+ // would (1) drop SNDG2 out of the deeper soundings' legibility window — SNDG1
2241
+ // is pinned to 43% of this light by `sounding-legibility.test.ts` — and the
2242
+ // owner's red-night report of 2026-09-30 asked for MORE sounding legibility,
2243
+ // not less; and (2) dim the hazard outlines (OBSTRN, WRECKS) and coastline
2244
+ // that a night chart must keep. What red night was missing was everything
2245
+ // that did NOT follow this palette: labels, house marks, hatches, sector
2246
+ // bearings. Those follow it now.
2231
2247
  CHBLK: "#c8aa78",
2232
2248
  CSTLN: "#c8aa78",
2233
2249
  OUTLW: "#c8aa78",
@@ -4972,6 +4988,45 @@ var InteractClient = class {
4972
4988
  }
4973
4989
  };
4974
4990
 
4991
+ // src/atlas/palette-light.ts
4992
+ var HEX6 = /^#?([0-9a-f]{6})$/i;
4993
+ function channels(hex) {
4994
+ const m = HEX6.exec(hex);
4995
+ if (!m) throw new Error(`palette-light: "${hex}" is not a #rrggbb colour`);
4996
+ const h = m[1];
4997
+ return [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16));
4998
+ }
4999
+ function toLinear(c) {
5000
+ const v = c / 255;
5001
+ return v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
5002
+ }
5003
+ function toEncoded(v) {
5004
+ const c = v <= 31308e-7 ? v * 12.92 : 1.055 * v ** (1 / 2.4) - 0.055;
5005
+ return Math.round(Math.min(1, Math.max(0, c)) * 255);
5006
+ }
5007
+ function hex2(n) {
5008
+ return n.toString(16).padStart(2, "0");
5009
+ }
5010
+ function relativeLuminance(hex) {
5011
+ const [r, g2, b] = channels(hex).map(toLinear);
5012
+ return 0.2126 * r + 0.7152 * g2 + 0.0722 * b;
5013
+ }
5014
+ function contrastRatio(a, b) {
5015
+ const [hi, lo] = [relativeLuminance(a), relativeLuminance(b)].sort((x, y) => y - x);
5016
+ return (hi + 0.05) / (lo + 0.05);
5017
+ }
5018
+ function scaleLinearLight(hex, factor) {
5019
+ const [r, g2, b] = channels(hex).map((c) => toEncoded(toLinear(c) * factor));
5020
+ return `#${hex2(r)}${hex2(g2)}${hex2(b)}`;
5021
+ }
5022
+ function capLuminance(hex, ceiling) {
5023
+ const l = relativeLuminance(hex);
5024
+ if (l <= ceiling) return scaleLinearLight(hex, 1);
5025
+ return scaleLinearLight(hex, ceiling / l);
5026
+ }
5027
+ var NIGHT_INK = S52_NIGHT.CHBLK;
5028
+ var NIGHT_MUTED_INK = scaleLinearLight(S52_NIGHT.CHBLK, 0.43);
5029
+
4975
5030
  // src/atlas/s52-linestyles-generated.ts
4976
5031
  var S52_LINESTYLES = {
4977
5032
  ACHARE51: {
@@ -5655,8 +5710,11 @@ function depareColor(props, ct = "DAY", safetyContourM = DEFAULT_SAFETY_CONTOUR_
5655
5710
  if (drval1 < DEPARE_DEEP_CUT_M) return resolveColor("DEPMD", ct);
5656
5711
  return resolveColor("DEPDW", ct);
5657
5712
  }
5713
+ var DEPARE_FILL_BRANCH_TOKENS = ["DEPIT", "DEPVS", "DEPMS", "DEPMD"];
5714
+ var DEPARE_FILL_FALLBACK_TOKEN = "DEPDW";
5658
5715
  function depareFillExpression(ct = "DAY", safetyContourM = DEFAULT_SAFETY_CONTOUR_M) {
5659
5716
  const safety = effectiveSafetyContour(safetyContourM);
5717
+ const [it, vs, ms, md] = DEPARE_FILL_BRANCH_TOKENS;
5660
5718
  return [
5661
5719
  "case",
5662
5720
  [
@@ -5664,14 +5722,14 @@ function depareFillExpression(ct = "DAY", safetyContourM = DEFAULT_SAFETY_CONTOU
5664
5722
  ["<", ["coalesce", ["get", "DRVAL1"], ["get", "drval1"], -1], 0],
5665
5723
  ["<=", ["coalesce", ["get", "DRVAL2"], ["get", "drval2"], 0], 0]
5666
5724
  ],
5667
- resolveColor("DEPIT", ct),
5725
+ resolveColor(it, ct),
5668
5726
  ["<", ["coalesce", ["get", "DRVAL1"], ["get", "drval1"], -1], DEPARE_SHALLOW_CUT_M],
5669
- resolveColor("DEPVS", ct),
5727
+ resolveColor(vs, ct),
5670
5728
  ["<", ["coalesce", ["get", "DRVAL1"], ["get", "drval1"], -1], safety],
5671
- resolveColor("DEPMS", ct),
5729
+ resolveColor(ms, ct),
5672
5730
  ["<", ["coalesce", ["get", "DRVAL1"], ["get", "drval1"], -1], DEPARE_DEEP_CUT_M],
5673
- resolveColor("DEPMD", ct),
5674
- resolveColor("DEPDW", ct)
5731
+ resolveColor(md, ct),
5732
+ resolveColor(DEPARE_FILL_FALLBACK_TOKEN, ct)
5675
5733
  ];
5676
5734
  }
5677
5735
  function listAttrString(attr) {
@@ -22782,14 +22840,60 @@ var NATQUA_ABBR = [
22782
22840
  // hard
22783
22841
  ];
22784
22842
  var DARK_BG = "#1a1d23";
22785
- var NAV_HALO = {
22786
- WHITE: { bright: "#ffffff", night: "#b8b0a0" },
22787
- CREAM: { bright: "#fdf0b0", night: "#a89868" },
22788
- YELLOW: { bright: "#eab308", night: "#806020" },
22789
- BLUE: { bright: "#b0c8e8", night: "#7088a0" }
22843
+ var NIGHT_MUTED = NIGHT_MUTED_INK;
22844
+ var NIGHT_KNOCKOUT = resolveColor("UIBCK", "NIGHT");
22845
+ var LABEL_TINT = {
22846
+ WATER: { day: "#9ec1d8", night: "muted" },
22847
+ // halo — lakes, rivers, canals
22848
+ WATER_DEEP: { day: "#8fb8d0", night: "muted" },
22849
+ // halo — sea areas, water place names
22850
+ LAND_REGION: { day: "#e8d8b8", night: "muted" },
22851
+ // halo — land regions, land place names
22852
+ LAND_NATURAL: { day: "#e0d8c8", night: "muted" },
22853
+ // halo — islands
22854
+ CITY: { day: "#f1e7d2", night: "muted" },
22855
+ // halo — built-up areas
22856
+ AIRPORT: { day: "#d4c9b0", night: "muted" },
22857
+ // halo — airports, landmarks, harbour facilities
22858
+ STRUCTURE: { day: "#bfa88a", night: "muted" },
22859
+ // glyph — bridges, shoreline constructions
22860
+ STRUCTURE_LIGHT: { day: "#c8c0b0", night: "muted" },
22861
+ // glyph — piles, moorings; halo — single buildings
22862
+ SOUNDING: { day: "#c8c8c8", night: "muted" },
22863
+ // halo — seabed, contour values; glyph — variation
22864
+ MAGENTA: { day: "#c545c3", night: "hue" },
22865
+ // glyph — production areas, overhead cables
22866
+ PIPELINE: { day: "#7fbf3f", night: "hue" },
22867
+ // glyph — overhead pipelines
22868
+ KELP: { day: "#3f8a34", night: "hue" },
22869
+ // halo — weed / kelp
22870
+ NAV_WHITE: { day: "#ffffff", night: "ink" },
22871
+ // halo — lateral, isolated danger, safe water
22872
+ NAV_CREAM: { day: "#fdf0b0", night: "ink" },
22873
+ // halo — cardinals, light characteristics
22874
+ NAV_YELLOW: { day: "#eab308", night: "hue" },
22875
+ // halo — special-purpose marks
22876
+ NAV_BLUE: { day: "#b0c8e8", night: "muted" }
22877
+ // halo — fog signals
22790
22878
  };
22791
- function navHalo(palette, ct) {
22792
- return ct === "NIGHT" ? NAV_HALO[palette].night : NAV_HALO[palette].bright;
22879
+ function tintFor(tint, ct) {
22880
+ const day = LABEL_TINT[tint].day;
22881
+ if (ct === "DAY") return day;
22882
+ return capLuminance(day, relativeLuminance(resolveColor("CHBLK", ct)));
22883
+ }
22884
+ function nightText(tint) {
22885
+ const role = LABEL_TINT[tint].night;
22886
+ if (role === "ink") return NIGHT_INK;
22887
+ if (role === "muted") return NIGHT_MUTED;
22888
+ return capLuminance(LABEL_TINT[tint].day, relativeLuminance(NIGHT_MUTED));
22889
+ }
22890
+ function onHalo(tint, ct) {
22891
+ if (ct === "NIGHT") return { textColor: nightText(tint), textHaloColor: NIGHT_KNOCKOUT };
22892
+ return { textColor: DARK_BG, textHaloColor: tintFor(tint, ct) };
22893
+ }
22894
+ function onKnockout(tint, ct) {
22895
+ if (ct === "NIGHT") return { textColor: nightText(tint), textHaloColor: NIGHT_KNOCKOUT };
22896
+ return { textColor: tintFor(tint, ct), textHaloColor: DARK_BG };
22793
22897
  }
22794
22898
  var NAV_AID_LABEL_TEXT_SIZE = [
22795
22899
  "interpolate",
@@ -23071,21 +23175,6 @@ function buildAirportTierExpression() {
23071
23175
  2
23072
23176
  ];
23073
23177
  }
23074
- var COLOR = {
23075
- WATER: "#9ec1d8",
23076
- WATER_DEEP: "#8fb8d0",
23077
- LAND_REGION: "#e8d8b8",
23078
- LAND_NATURAL: "#e0d8c8",
23079
- CITY: "#f1e7d2",
23080
- AIRPORT: "#d4c9b0",
23081
- STRUCTURE: "#bfa88a",
23082
- STRUCTURE_LIGHT: "#c8c0b0",
23083
- SOUNDING: "#c8c8c8",
23084
- NAV_NUMBER: "#ffffff",
23085
- NAV_CARDINAL: "#fdf0b0",
23086
- NAV_SPECIAL: "#eab308",
23087
- LIGHT: "#fdf0b0"
23088
- };
23089
23178
  var ORIENTATION_BAND_SORT_KEY = [
23090
23179
  "to-number",
23091
23180
  ["slice", ["coalesce", ["get", "_cell_id"], "??9???"], 2, 3],
@@ -23430,8 +23519,7 @@ function getLabelConfig(layerName, opts = {}) {
23430
23519
  [13, [11.5, 11.5]],
23431
23520
  [16, [10.5, 11.5]]
23432
23521
  ]),
23433
- textColor: DARK_BG,
23434
- textHaloColor: COLOR.LAND_REGION,
23522
+ ...onHalo("LAND_REGION", ct),
23435
23523
  // Land halo, not the shared taper — see LAND_HALO_WIDTH.
23436
23524
  textHaloWidth: LAND_HALO_WIDTH,
23437
23525
  textOffset: [0, 0],
@@ -23445,8 +23533,7 @@ function getLabelConfig(layerName, opts = {}) {
23445
23533
  type: "symbol",
23446
23534
  textField: buildLandmarkLabelExpression(),
23447
23535
  textSize: 9,
23448
- textColor: DARK_BG,
23449
- textHaloColor: "#d4c9b0",
23536
+ ...onHalo("AIRPORT", ct),
23450
23537
  textHaloWidth: 1.5,
23451
23538
  textOffset: [0, 0],
23452
23539
  minzoom: 9,
@@ -23466,8 +23553,7 @@ function getLabelConfig(layerName, opts = {}) {
23466
23553
  type: "symbol",
23467
23554
  textField: buildHarbourFacilityLabelExpression(),
23468
23555
  textSize: 9,
23469
- textColor: DARK_BG,
23470
- textHaloColor: "#d4c9b0",
23556
+ ...onHalo("AIRPORT", ct),
23471
23557
  textHaloWidth: 1.5,
23472
23558
  textOffset: [0, 0],
23473
23559
  minzoom: 12,
@@ -23484,8 +23570,7 @@ function getLabelConfig(layerName, opts = {}) {
23484
23570
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23485
23571
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23486
23572
  textFont: NAV_AID_LABEL_FONT,
23487
- textColor: DARK_BG,
23488
- textHaloColor: navHalo("WHITE", ct),
23573
+ ...onHalo("NAV_WHITE", ct),
23489
23574
  textHaloWidth: 1.5,
23490
23575
  textOffset: [0, 1.5],
23491
23576
  minzoom: 10,
@@ -23497,8 +23582,7 @@ function getLabelConfig(layerName, opts = {}) {
23497
23582
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23498
23583
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23499
23584
  textFont: NAV_AID_LABEL_FONT,
23500
- textColor: DARK_BG,
23501
- textHaloColor: navHalo("WHITE", ct),
23585
+ ...onHalo("NAV_WHITE", ct),
23502
23586
  textHaloWidth: 1.5,
23503
23587
  textOffset: [0, 1.5],
23504
23588
  minzoom: 10,
@@ -23511,8 +23595,7 @@ function getLabelConfig(layerName, opts = {}) {
23511
23595
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23512
23596
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23513
23597
  textFont: NAV_AID_LABEL_FONT,
23514
- textColor: DARK_BG,
23515
- textHaloColor: navHalo("CREAM", ct),
23598
+ ...onHalo("NAV_CREAM", ct),
23516
23599
  textHaloWidth: 1.5,
23517
23600
  textOffset: [0, 1.5],
23518
23601
  minzoom: 10,
@@ -23525,8 +23608,7 @@ function getLabelConfig(layerName, opts = {}) {
23525
23608
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23526
23609
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23527
23610
  textFont: NAV_AID_LABEL_FONT,
23528
- textColor: DARK_BG,
23529
- textHaloColor: navHalo("YELLOW", ct),
23611
+ ...onHalo("NAV_YELLOW", ct),
23530
23612
  textHaloWidth: 1.5,
23531
23613
  textOffset: [0, 1.5],
23532
23614
  minzoom: 10,
@@ -23539,8 +23621,7 @@ function getLabelConfig(layerName, opts = {}) {
23539
23621
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23540
23622
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23541
23623
  textFont: NAV_AID_LABEL_FONT,
23542
- textColor: DARK_BG,
23543
- textHaloColor: navHalo("WHITE", ct),
23624
+ ...onHalo("NAV_WHITE", ct),
23544
23625
  textHaloWidth: 1.5,
23545
23626
  textOffset: [0, 1.5],
23546
23627
  minzoom: 10,
@@ -23552,8 +23633,7 @@ function getLabelConfig(layerName, opts = {}) {
23552
23633
  textField: ["get", "_lightLabel"],
23553
23634
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23554
23635
  textFont: NAV_AID_LABEL_FONT,
23555
- textColor: DARK_BG,
23556
- textHaloColor: navHalo("CREAM", ct),
23636
+ ...onHalo("NAV_CREAM", ct),
23557
23637
  textHaloWidth: 1.5,
23558
23638
  textOffset: [2, 0],
23559
23639
  minzoom: 9,
@@ -23577,8 +23657,7 @@ function getLabelConfig(layerName, opts = {}) {
23577
23657
  textField: catfogExpr,
23578
23658
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23579
23659
  textFont: NAV_AID_LABEL_FONT,
23580
- textColor: DARK_BG,
23581
- textHaloColor: navHalo("BLUE", ct),
23660
+ ...onHalo("NAV_BLUE", ct),
23582
23661
  textHaloWidth: 1.5,
23583
23662
  textOffset: [2, 1.2],
23584
23663
  minzoom: 11,
@@ -23653,8 +23732,7 @@ function getLabelConfig(layerName, opts = {}) {
23653
23732
  [13, [0, 0, 13, 10, 11]],
23654
23733
  [16, [0, 0, 12, 11, 10]]
23655
23734
  ]),
23656
- textColor: DARK_BG,
23657
- textHaloColor: COLOR.WATER_DEEP,
23735
+ ...onHalo("WATER_DEEP", ct),
23658
23736
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23659
23737
  textOffset: [0, 0],
23660
23738
  textFont: ["Open Sans Italic"],
@@ -23724,8 +23802,7 @@ function getLabelConfig(layerName, opts = {}) {
23724
23802
  [13, [10, 11]],
23725
23803
  [16, [9, 10]]
23726
23804
  ]),
23727
- textColor: DARK_BG,
23728
- textHaloColor: COLOR.WATER,
23805
+ ...onHalo("WATER", ct),
23729
23806
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23730
23807
  textOffset: [0, 0],
23731
23808
  textFont: ["Open Sans Italic"],
@@ -23745,8 +23822,7 @@ function getLabelConfig(layerName, opts = {}) {
23745
23822
  [13, [10, 10]],
23746
23823
  [16, [9, 10]]
23747
23824
  ]),
23748
- textColor: DARK_BG,
23749
- textHaloColor: COLOR.WATER,
23825
+ ...onHalo("WATER", ct),
23750
23826
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23751
23827
  textOffset: [0, 0],
23752
23828
  textFont: ["Open Sans Italic"],
@@ -23769,8 +23845,7 @@ function getLabelConfig(layerName, opts = {}) {
23769
23845
  16,
23770
23846
  9
23771
23847
  ],
23772
- textColor: DARK_BG,
23773
- textHaloColor: COLOR.WATER,
23848
+ ...onHalo("WATER", ct),
23774
23849
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23775
23850
  textOffset: [0, 0],
23776
23851
  textFont: ["Open Sans Italic"],
@@ -23799,8 +23874,7 @@ function getLabelConfig(layerName, opts = {}) {
23799
23874
  [13, [11.5, 11.5]],
23800
23875
  [16, [10.5, 11.5]]
23801
23876
  ]),
23802
- textColor: DARK_BG,
23803
- textHaloColor: COLOR.LAND_NATURAL,
23877
+ ...onHalo("LAND_NATURAL", ct),
23804
23878
  // Land halo, not the shared taper — see LAND_HALO_WIDTH.
23805
23879
  textHaloWidth: LAND_HALO_WIDTH,
23806
23880
  textOffset: [0, 0],
@@ -23823,8 +23897,7 @@ function getLabelConfig(layerName, opts = {}) {
23823
23897
  [13, [10, 11, 12]],
23824
23898
  [16, [10, 10, 11]]
23825
23899
  ]),
23826
- textColor: DARK_BG,
23827
- textHaloColor: COLOR.CITY,
23900
+ ...onHalo("CITY", ct),
23828
23901
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23829
23902
  textOffset: [0, 0],
23830
23903
  textFont: ["Open Sans Regular"],
@@ -23839,8 +23912,7 @@ function getLabelConfig(layerName, opts = {}) {
23839
23912
  type: "symbol",
23840
23913
  textField: OBJNAM_TEXT,
23841
23914
  textSize: 9,
23842
- textColor: "#bfa88a",
23843
- textHaloColor: DARK_BG,
23915
+ ...onKnockout("STRUCTURE", ct),
23844
23916
  textHaloWidth: 1.5,
23845
23917
  textOffset: [0, 0],
23846
23918
  minzoom: 12,
@@ -23858,8 +23930,7 @@ function getLabelConfig(layerName, opts = {}) {
23858
23930
  type: "symbol",
23859
23931
  textField: OBJNAM_TEXT,
23860
23932
  textSize: 8,
23861
- textColor: "#c8c0b0",
23862
- textHaloColor: DARK_BG,
23933
+ ...onKnockout("STRUCTURE_LIGHT", ct),
23863
23934
  textHaloWidth: 1.2,
23864
23935
  textOffset: [0, 1.2],
23865
23936
  minzoom: 13
@@ -23869,8 +23940,7 @@ function getLabelConfig(layerName, opts = {}) {
23869
23940
  type: "symbol",
23870
23941
  textField: OBJNAM_TEXT,
23871
23942
  textSize: 8,
23872
- textColor: "#c8c0b0",
23873
- textHaloColor: DARK_BG,
23943
+ ...onKnockout("STRUCTURE_LIGHT", ct),
23874
23944
  textHaloWidth: 1.2,
23875
23945
  textOffset: [0, 1.2],
23876
23946
  minzoom: 13
@@ -23880,8 +23950,7 @@ function getLabelConfig(layerName, opts = {}) {
23880
23950
  type: "symbol",
23881
23951
  textField: OBJNAM_TEXT,
23882
23952
  textSize: 8,
23883
- textColor: "#bfa88a",
23884
- textHaloColor: DARK_BG,
23953
+ ...onKnockout("STRUCTURE", ct),
23885
23954
  textHaloWidth: 1.2,
23886
23955
  textOffset: [0, 1],
23887
23956
  minzoom: 13,
@@ -23895,8 +23964,7 @@ function getLabelConfig(layerName, opts = {}) {
23895
23964
  type: "symbol",
23896
23965
  textField: OBJNAM_TEXT,
23897
23966
  textSize: 8,
23898
- textColor: DARK_BG,
23899
- textHaloColor: "#c8c0b0",
23967
+ ...onHalo("STRUCTURE_LIGHT", ct),
23900
23968
  textHaloWidth: 1.2,
23901
23969
  textOffset: [0, 1.2],
23902
23970
  minzoom: 14,
@@ -23917,8 +23985,7 @@ function getLabelConfig(layerName, opts = {}) {
23917
23985
  [13, [10, 10]],
23918
23986
  [16, [9, 9]]
23919
23987
  ]),
23920
- textColor: DARK_BG,
23921
- textHaloColor: COLOR.AIRPORT,
23988
+ ...onHalo("AIRPORT", ct),
23922
23989
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23923
23990
  textOffset: [0, 0],
23924
23991
  textFont: ["Open Sans Regular"],
@@ -23939,8 +24006,7 @@ function getLabelConfig(layerName, opts = {}) {
23939
24006
  16,
23940
24007
  11
23941
24008
  ],
23942
- textColor: DARK_BG,
23943
- textHaloColor: COLOR.SOUNDING,
24009
+ ...onHalo("SOUNDING", ct),
23944
24010
  textHaloWidth: 1,
23945
24011
  textOffset: [0, 0],
23946
24012
  textFont: ["Open Sans Italic"],
@@ -23974,8 +24040,7 @@ function getLabelConfig(layerName, opts = {}) {
23974
24040
  14,
23975
24041
  11
23976
24042
  ],
23977
- textColor: COLOR.SOUNDING,
23978
- textHaloColor: DARK_BG,
24043
+ ...onKnockout("SOUNDING", ct),
23979
24044
  textHaloWidth: 1,
23980
24045
  textOffset: [0, 0],
23981
24046
  textFont: ["Open Sans Italic"],
@@ -24005,8 +24070,7 @@ function getLabelConfig(layerName, opts = {}) {
24005
24070
  16,
24006
24071
  8
24007
24072
  ],
24008
- textColor: "#c545c3",
24009
- textHaloColor: DARK_BG,
24073
+ ...onKnockout("MAGENTA", ct),
24010
24074
  textHaloWidth: ORIENTATION_HALO_WIDTH,
24011
24075
  textOffset: [0, 0],
24012
24076
  textFont: ["Open Sans Italic"],
@@ -24026,8 +24090,7 @@ function getLabelConfig(layerName, opts = {}) {
24026
24090
  16,
24027
24091
  11
24028
24092
  ],
24029
- textColor: DARK_BG,
24030
- textHaloColor: "#3f8a34",
24093
+ ...onHalo("KELP", ct),
24031
24094
  textHaloWidth: 1,
24032
24095
  textOffset: [0, 0],
24033
24096
  textFont: ["Open Sans Italic"],
@@ -24119,8 +24182,7 @@ function getLabelConfig(layerName, opts = {}) {
24119
24182
  17,
24120
24183
  11
24121
24184
  ],
24122
- textColor: isCBL ? "#c545c3" : "#7fbf3f",
24123
- textHaloColor: DARK_BG,
24185
+ ...onKnockout(isCBL ? "MAGENTA" : "PIPELINE", ct),
24124
24186
  textHaloWidth: 1.4,
24125
24187
  textOffset: [0, 0],
24126
24188
  textFont: ["Open Sans Regular"],
@@ -24155,8 +24217,7 @@ function getLabelConfig(layerName, opts = {}) {
24155
24217
  14,
24156
24218
  10
24157
24219
  ],
24158
- textColor: DARK_BG,
24159
- textHaloColor: "#c8c8c8",
24220
+ ...onHalo("SOUNDING", ct),
24160
24221
  textHaloWidth: 1.2,
24161
24222
  textOffset: [0, 0],
24162
24223
  textFont: ["Open Sans Regular"],
@@ -24461,9 +24522,9 @@ var PLACENAME_LAND_SIZE_STOPS = [
24461
24522
  [13, [0, 0, 10, 11, 10, 11, 10, 10, 10, 10]],
24462
24523
  [16, [0, 0, 10, 10, 9, 10, 9, 9, 9, 9]]
24463
24524
  ];
24464
- function buildPlaceNameLayers(sourceId) {
24525
+ function buildPlaceNameLayers(sourceId, ct = "DAY") {
24465
24526
  const sortKey = ["to-number", ["coalesce", ["get", "rank"], 9999999]];
24466
- const make = (idSuffix, classes, font, haloColor, letterSpacing, stops) => ({
24527
+ const make = (idSuffix, classes, font, tint, letterSpacing, stops) => ({
24467
24528
  id: `chrt-placename-${idSuffix}`,
24468
24529
  type: "symbol",
24469
24530
  source: sourceId,
@@ -24491,8 +24552,8 @@ function buildPlaceNameLayers(sourceId) {
24491
24552
  "symbol-sort-key": sortKey
24492
24553
  },
24493
24554
  paint: {
24494
- "text-color": DARK_BG,
24495
- "text-halo-color": haloColor,
24555
+ "text-color": onHalo(tint, ct).textColor,
24556
+ "text-halo-color": onHalo(tint, ct).textHaloColor,
24496
24557
  "text-halo-width": ORIENTATION_HALO_WIDTH,
24497
24558
  "text-opacity": PLACENAME_TEXT_OPACITY
24498
24559
  },
@@ -24502,8 +24563,8 @@ function buildPlaceNameLayers(sourceId) {
24502
24563
  }
24503
24564
  });
24504
24565
  return [
24505
- make("water", PLACENAME_WATER_CLASSES, ["Open Sans Italic"], COLOR.WATER_DEEP, 0.05, PLACENAME_WATER_SIZE_STOPS),
24506
- make("land", PLACENAME_LAND_CLASSES, ["Open Sans Regular"], COLOR.LAND_REGION, 0.02, PLACENAME_LAND_SIZE_STOPS)
24566
+ make("water", PLACENAME_WATER_CLASSES, ["Open Sans Italic"], "WATER_DEEP", 0.05, PLACENAME_WATER_SIZE_STOPS),
24567
+ make("land", PLACENAME_LAND_CLASSES, ["Open Sans Regular"], "LAND_REGION", 0.02, PLACENAME_LAND_SIZE_STOPS)
24507
24568
  ];
24508
24569
  }
24509
24570
  var DRGNOTE_SOURCE_LAYER = "DRGNOTE";
@@ -27227,37 +27288,58 @@ var CHRT_ATON_COLORS = {
27227
27288
  // pink (magenta-ish)
27228
27289
  };
27229
27290
  var CHRT_UNKNOWN_TINT = "#8B9298";
27230
- function chrtAtonTintExpression() {
27291
+ var HOUSE_BLACK = "#101418";
27292
+ function chrtHouseColor(dayHex, palette = "DAY") {
27293
+ if (palette === "DAY") return dayHex;
27294
+ const isBlack = dayHex.toLowerCase() === HOUSE_BLACK.toLowerCase();
27295
+ if (palette === "DUSK") {
27296
+ return isBlack ? dayHex : capLuminance(dayHex, relativeLuminance(resolveColor("CHBLK", "DUSK")));
27297
+ }
27298
+ return isBlack ? NIGHT_INK : capLuminance(dayHex, relativeLuminance(NIGHT_MUTED_INK));
27299
+ }
27300
+ function themeChrtGlyph(svg3, palette = "DAY") {
27301
+ if (palette === "DAY") return svg3;
27302
+ return svg3.replace(
27303
+ /(fill|stroke)="(#[0-9a-fA-F]{3}|#[0-9a-fA-F]{6})"/g,
27304
+ (_m, attr, hex) => {
27305
+ const six = hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex;
27306
+ return `${attr}="${chrtHouseColor(six, palette)}"`;
27307
+ }
27308
+ );
27309
+ }
27310
+ function chrtAtonTintExpression(palette = "DAY") {
27311
+ const c = (code) => chrtHouseColor(CHRT_ATON_COLORS[code], palette);
27231
27312
  return colourCodeCase(
27232
27313
  [
27233
- ["3", CHRT_ATON_COLORS["3"]],
27234
- ["4", CHRT_ATON_COLORS["4"]],
27235
- ["6", CHRT_ATON_COLORS["6"]],
27236
- ["11", CHRT_ATON_COLORS["11"]],
27237
- ["9", CHRT_ATON_COLORS["9"]],
27238
- ["5", CHRT_ATON_COLORS["5"]],
27239
- ["1", CHRT_ATON_COLORS["1"]],
27240
- ["2", CHRT_ATON_COLORS["2"]],
27241
- ["8", CHRT_ATON_COLORS["8"]],
27242
- ["10", CHRT_ATON_COLORS["10"]],
27243
- ["12", CHRT_ATON_COLORS["12"]],
27244
- ["7", CHRT_ATON_COLORS["7"]]
27314
+ ["3", c("3")],
27315
+ ["4", c("4")],
27316
+ ["6", c("6")],
27317
+ ["11", c("11")],
27318
+ ["9", c("9")],
27319
+ ["5", c("5")],
27320
+ ["1", c("1")],
27321
+ ["2", c("2")],
27322
+ ["8", c("8")],
27323
+ ["10", c("10")],
27324
+ ["12", c("12")],
27325
+ ["7", c("7")]
27245
27326
  ],
27246
- CHRT_UNKNOWN_TINT
27327
+ chrtHouseColor(CHRT_UNKNOWN_TINT, palette)
27247
27328
  );
27248
27329
  }
27249
- function chrtLightTintExpression() {
27330
+ function chrtLightTintExpression(palette = "DAY") {
27331
+ const c = (code) => chrtHouseColor(CHRT_ATON_COLORS[code], palette);
27250
27332
  return colourCodeCase(
27251
27333
  [
27252
- ["3", CHRT_ATON_COLORS["3"]],
27253
- ["4", CHRT_ATON_COLORS["4"]],
27254
- ["6", CHRT_ATON_COLORS["6"]],
27255
- ["11", CHRT_ATON_COLORS["11"]],
27256
- ["9", CHRT_ATON_COLORS["9"]],
27257
- ["5", CHRT_ATON_COLORS["5"]],
27258
- ["1", CHRT_ATON_COLORS["1"]]
27334
+ ["3", c("3")],
27335
+ ["4", c("4")],
27336
+ ["6", c("6")],
27337
+ ["11", c("11")],
27338
+ ["9", c("9")],
27339
+ ["5", c("5")],
27340
+ ["1", c("1")]
27259
27341
  ],
27260
- CHRT_ATON_COLORS["1"]
27342
+ c("1")
27261
27343
  );
27262
27344
  }
27263
27345
  function scalar(attr) {
@@ -27359,7 +27441,7 @@ var TINTED_CLASSES = /* @__PURE__ */ new Set([
27359
27441
  "BCNSPP",
27360
27442
  "DAYMAR"
27361
27443
  ]);
27362
- var CHRT_HALO = { color: "#101418", width: 1 };
27444
+ var CHRT_HALO = { color: HOUSE_BLACK, width: 1 };
27363
27445
  var CHRT_LINE_DASH = {
27364
27446
  CBLSUB: { color: "CHMGD", width: 0.8, dash: [6, 3] },
27365
27447
  PIPSOL: { color: "PIPLN", width: 0.8, dash: [6, 3] }
@@ -27387,11 +27469,11 @@ function applyChrtSymbolSet(style, palette = "DAY") {
27387
27469
  layout["icon-image"] = CHRT_ICON_EXPRESSIONS[objectClass]();
27388
27470
  const paint = layer.paint ?? {};
27389
27471
  if (TINTED_CLASSES.has(objectClass)) {
27390
- paint["icon-color"] = chrtAtonTintExpression();
27472
+ paint["icon-color"] = chrtAtonTintExpression(palette);
27391
27473
  paint["icon-halo-color"] = CHRT_HALO.color;
27392
27474
  paint["icon-halo-width"] = CHRT_HALO.width;
27393
27475
  } else if (objectClass === "LIGHTS") {
27394
- paint["icon-color"] = chrtLightTintExpression();
27476
+ paint["icon-color"] = chrtLightTintExpression(palette);
27395
27477
  paint["icon-halo-color"] = CHRT_HALO.color;
27396
27478
  paint["icon-halo-width"] = CHRT_HALO.width;
27397
27479
  }
@@ -30543,7 +30625,7 @@ function generateStyle(palette = "DAY", opts = {}) {
30543
30625
  )
30544
30626
  );
30545
30627
  if (opts.labels === "placename") {
30546
- labelLayers.push(...buildPlaceNameLayers(sourceId));
30628
+ labelLayers.push(...buildPlaceNameLayers(sourceId, palette));
30547
30629
  }
30548
30630
  for (const { label } of chartLabelBundles) {
30549
30631
  if (bandFan === "collapsed") {
@@ -30633,7 +30715,7 @@ function generateStyle(palette = "DAY", opts = {}) {
30633
30715
  }
30634
30716
  }
30635
30717
  if (opts.labels === "placename") {
30636
- labelLayers.push(...buildPlaceNameLayers(sourceId));
30718
+ labelLayers.push(...buildPlaceNameLayers(sourceId, palette));
30637
30719
  } else {
30638
30720
  for (const { objectClass, label } of bundles) {
30639
30721
  if (!label) continue;
@@ -31318,6 +31400,69 @@ function generateCustomStyle(config, opts = {}) {
31318
31400
  return { style, palette, themeFellBack };
31319
31401
  }
31320
31402
 
31403
+ // src/atlas/depth-area-opaque.ts
31404
+ var OPAQUE_SPLIT_OF = "chrt:opaqueSplitOf";
31405
+ function depthAreaClassLayerId(baseId, token) {
31406
+ return `chrt-${token.toLowerCase()}-of-${baseId.replace(/-band(\d)/g, "-b$1")}`;
31407
+ }
31408
+ function depthAreaSplitIds(baseId) {
31409
+ return [...DEPARE_FILL_BRANCH_TOKENS].reverse().map((token) => depthAreaClassLayerId(baseId, token));
31410
+ }
31411
+ var CLASS_LAYER_ID = new RegExp(
31412
+ `^chrt-(?:${DEPARE_FILL_BRANCH_TOKENS.map((t) => t.toLowerCase()).join("|")})-of-`
31413
+ );
31414
+ function isDepthAreaClassLayerId(id) {
31415
+ return CLASS_LAYER_ID.test(id);
31416
+ }
31417
+ function opaqueSplitBaseOf(layer) {
31418
+ const meta = layer.metadata;
31419
+ const base = meta?.[OPAQUE_SPLIT_OF];
31420
+ return typeof base === "string" ? base : null;
31421
+ }
31422
+ function exclusiveBranches(expression) {
31423
+ if (!Array.isArray(expression) || expression[0] !== "case") return null;
31424
+ if ((expression.length - 2) / 2 !== DEPARE_FILL_BRANCH_TOKENS.length) return null;
31425
+ const branches = [];
31426
+ const earlier = [];
31427
+ for (let i = 1; i < expression.length - 1; i += 2) {
31428
+ const colour = expression[i + 1];
31429
+ if (typeof colour !== "string") return null;
31430
+ branches.push({ when: [...earlier.map((c) => ["!", c]), expression[i]], colour });
31431
+ earlier.push(expression[i]);
31432
+ }
31433
+ const fallback = expression[expression.length - 1];
31434
+ if (typeof fallback !== "string") return null;
31435
+ return { branches, fallback };
31436
+ }
31437
+ function andFilter(base, terms) {
31438
+ if (Array.isArray(base) && base[0] === "all") return ["all", ...base.slice(1), ...terms];
31439
+ if (base === void 0) return ["all", ...terms];
31440
+ return ["all", base, ...terms];
31441
+ }
31442
+ function splitOpaqueDepthAreas(layers) {
31443
+ const out = [];
31444
+ for (const raw of layers) {
31445
+ const layer = raw;
31446
+ const paint = layer.paint ?? {};
31447
+ const split = layer.type === "fill" && layer.metadata?.["s52:objectClass"] === "DEPARE" && paint["fill-pattern"] === void 0 && (paint["fill-opacity"] === void 0 || paint["fill-opacity"] === 1) ? exclusiveBranches(paint["fill-color"]) : null;
31448
+ if (split === null) {
31449
+ out.push(raw);
31450
+ continue;
31451
+ }
31452
+ out.push({ ...layer, paint: { ...paint, "fill-color": split.fallback } });
31453
+ for (let k = split.branches.length - 1; k >= 0; k -= 1) {
31454
+ out.push({
31455
+ ...layer,
31456
+ id: depthAreaClassLayerId(layer.id, DEPARE_FILL_BRANCH_TOKENS[k]),
31457
+ filter: andFilter(layer.filter, split.branches[k].when),
31458
+ paint: { ...paint, "fill-color": split.branches[k].colour },
31459
+ metadata: { ...layer.metadata ?? {}, [OPAQUE_SPLIT_OF]: layer.id }
31460
+ });
31461
+ }
31462
+ }
31463
+ return out;
31464
+ }
31465
+
31321
31466
  // src/pagination.ts
31322
31467
  async function* paginate(fetchPage, getItems, getTotalCount, options) {
31323
31468
  const pageSize = options?.pageSize ?? 100;
@@ -31786,6 +31931,8 @@ export {
31786
31931
  DEFAULT_TILE_BASE_URL,
31787
31932
  DEFAULT_TILE_REGION,
31788
31933
  DEFAULT_WATER_BODY_SETTINGS,
31934
+ DEPARE_FILL_BRANCH_TOKENS,
31935
+ DEPARE_FILL_FALLBACK_TOKEN,
31789
31936
  DRAPEABLE_LAYER_TYPES,
31790
31937
  INSPECT_CLASS_RANK,
31791
31938
  INSPECT_RANK_DEVIATIONS,
@@ -31805,8 +31952,11 @@ export {
31805
31952
  NAUTICAL_SYMBOLS,
31806
31953
  NAV_AID_LAYER_GROUPS,
31807
31954
  NAV_AID_QUERY_LAYERS,
31955
+ NIGHT_INK,
31956
+ NIGHT_MUTED_INK,
31808
31957
  NON_SOLAS_DISCLAIMER,
31809
31958
  NON_SOLAS_DISCLAIMER_SHORT,
31959
+ OPAQUE_SPLIT_OF,
31810
31960
  OfflineError,
31811
31961
  OfflineStyleError,
31812
31962
  PLACENAME_LAND_CLASSES,
@@ -31875,13 +32025,16 @@ export {
31875
32025
  buildSectorsFromFeatures,
31876
32026
  buildSources,
31877
32027
  candidateRank,
32028
+ capLuminance,
31878
32029
  cellBandCharacters,
31879
32030
  cellBandMatch,
31880
32031
  chrtAtonTintExpression,
32032
+ chrtHouseColor,
31881
32033
  chrtLightTintExpression,
31882
32034
  collectCandidates,
31883
32035
  collectClickCandidates,
31884
32036
  combineWithBandFilter,
32037
+ contrastRatio,
31885
32038
  daymarkColor,
31886
32039
  decimateFeatures,
31887
32040
  decodeAreaFeatureProps,
@@ -31890,6 +32043,8 @@ export {
31890
32043
  decodeNavAidProps,
31891
32044
  depareColor,
31892
32045
  depareFillExpression,
32046
+ depthAreaClassLayerId,
32047
+ depthAreaSplitIds,
31893
32048
  deriveMarinerName,
31894
32049
  drapeHalves,
31895
32050
  drapedFirst,
@@ -31925,6 +32080,7 @@ export {
31925
32080
  hazardColor,
31926
32081
  hazardFillExpression,
31927
32082
  iconExpressionForFamily,
32083
+ isDepthAreaClassLayerId,
31928
32084
  isDrapeable,
31929
32085
  isLabelLayerVisible,
31930
32086
  isNavAidLayer,
@@ -31942,6 +32098,7 @@ export {
31942
32098
  lightsIconExpression,
31943
32099
  normalizeStyleMode,
31944
32100
  normalizeTheme,
32101
+ opaqueSplitBaseOf,
31945
32102
  paginate,
31946
32103
  parseListCodes,
31947
32104
  parseSigseqTerms,
@@ -31953,6 +32110,7 @@ export {
31953
32110
  preprocessSoundings,
31954
32111
  preprocessWaterBodies,
31955
32112
  rasterAtonIconExpression,
32113
+ relativeLuminance,
31956
32114
  resolveColor,
31957
32115
  resolveCustomTheme,
31958
32116
  resolveRasterImage,
@@ -31962,11 +32120,14 @@ export {
31962
32120
  rhythmProperties,
31963
32121
  s101ArtworkProvenance,
31964
32122
  sanitizeCustomStyleConfig,
32123
+ scaleLinearLight,
31965
32124
  scaleSizeValue,
31966
32125
  scaminToMinZoom,
31967
32126
  sectorLimitToArcBearing,
32127
+ splitOpaqueDepthAreas,
31968
32128
  styleModeBand,
31969
32129
  terrainStackCount,
32130
+ themeChrtGlyph,
31970
32131
  tileTemplate,
31971
32132
  uncoveredSectorArcs,
31972
32133
  withinBboxFilter,