@chrtco/sdk 0.10.41 → 0.10.43

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
@@ -1107,6 +1107,14 @@ function requireManifestPath(manifestPath) {
1107
1107
  // src/endpoints/offline.ts
1108
1108
  var PROGRESS_MIN_BYTES = 1024 * 1024;
1109
1109
  var PROGRESS_MIN_FRACTION = 0.01;
1110
+ function noStoreInit() {
1111
+ try {
1112
+ new Request("http://localhost/", { cache: "no-store" });
1113
+ return { cache: "no-store" };
1114
+ } catch {
1115
+ return {};
1116
+ }
1117
+ }
1110
1118
  var OfflineEndpoint = class {
1111
1119
  constructor(http, deviceId, manifestPath) {
1112
1120
  this.http = http;
@@ -1393,7 +1401,7 @@ var OfflineEndpoint = class {
1393
1401
  resumed = true;
1394
1402
  }
1395
1403
  }
1396
- const fetchInit = { method: "GET", signal };
1404
+ const fetchInit = { method: "GET", signal, ...noStoreInit() };
1397
1405
  if (startByte > 0) {
1398
1406
  fetchInit.headers = { Range: `bytes=${startByte}-` };
1399
1407
  }
@@ -2172,7 +2180,12 @@ var S52_DUSK = {
2172
2180
  CHMGF: "#905090",
2173
2181
  CHWHT: "#90a0a0",
2174
2182
  CHCOR: "#a06030",
2175
- SNDG1: "#606060",
2183
+ // Deeper-than-safety soundings. Was #606060, which measured 2.39:1 on this
2184
+ // palette's DEPMD (#7ba6b8). DUSK water is LIGHT, so the only way to 3:1 is
2185
+ // darker: #505050 = 3.07:1 on DEPMD, 4.09:1 on DEPDW (spec: #292e2e). The
2186
+ // shoaler SNDG2 stays the louder numeral through its UIBCK halo cut-out.
2187
+ // Guarded with NIGHT's by `sounding-legibility.test.ts`; see S52_NIGHT.SNDG1.
2188
+ SNDG1: "#505050",
2176
2189
  SNDG2: "#b0b0b0",
2177
2190
  DEPSC: "#606060",
2178
2191
  DEPCN: "#2E2E2E",
@@ -2215,6 +2228,22 @@ var S52_NIGHT = {
2215
2228
  CHBRN: "#382410",
2216
2229
  CHGRF: "#2a2a22",
2217
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.
2218
2247
  CHBLK: "#c8aa78",
2219
2248
  CSTLN: "#c8aa78",
2220
2249
  OUTLW: "#c8aa78",
@@ -2243,7 +2272,24 @@ var S52_NIGHT = {
2243
2272
  CHMGF: "#482848",
2244
2273
  CHWHT: "#484840",
2245
2274
  CHCOR: "#683818",
2246
- SNDG1: "#383028",
2275
+ // ⚠ DELIBERATE DEVIATION from the published S-52 NIGHT value (#1f2223),
2276
+ // for the reason DEPCN's below gives, on the deeper-than-safety soundings.
2277
+ //
2278
+ // Reported 2026-09-30 at night on CHRTdesktop (Raspberry Pi 4): "we mute
2279
+ // out the ones that are 'deep' but I need to still be able to see them."
2280
+ // The previous value, #383028, measured 1.37:1 on DEPDW and 1.08:1 on
2281
+ // DEPMD: the muted soundings had disappeared entirely.
2282
+ //
2283
+ // #897350 is SNDG2 (#c8aa78) scaled to 43% of its linear light, so it keeps
2284
+ // SNDG2's hue (the NIGHT table's warm linework family, kind to a
2285
+ // dark-adapted eye and to red night). Against this palette's water it
2286
+ // measures 3.10:1 on DEPMD and 3.91:1 on DEPDW, which clears the 3:1 floor.
2287
+ // It is 0.49x SNDG2's contrast on any of them, so the eye still goes to
2288
+ // the shoal soundings first. On the lighter DEPMS/DEPVS water the UIBCK
2289
+ // halo carries it: fill against halo is 4.37:1.
2290
+ // The window is narrow (luminance 0.175-0.187 meets both conditions), and
2291
+ // `sounding-legibility.test.ts` pins both ends for every symbol family.
2292
+ SNDG1: "#897350",
2247
2293
  SNDG2: "#c8aa78",
2248
2294
  DEPSC: "#383028",
2249
2295
  // ⚠ DELIBERATE DEVIATION from the published S-52 NIGHT value (#1f2223),
@@ -4942,6 +4988,45 @@ var InteractClient = class {
4942
4988
  }
4943
4989
  };
4944
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
+
4945
5030
  // src/atlas/s52-linestyles-generated.ts
4946
5031
  var S52_LINESTYLES = {
4947
5032
  ACHARE51: {
@@ -22752,14 +22837,60 @@ var NATQUA_ABBR = [
22752
22837
  // hard
22753
22838
  ];
22754
22839
  var DARK_BG = "#1a1d23";
22755
- var NAV_HALO = {
22756
- WHITE: { bright: "#ffffff", night: "#b8b0a0" },
22757
- CREAM: { bright: "#fdf0b0", night: "#a89868" },
22758
- YELLOW: { bright: "#eab308", night: "#806020" },
22759
- BLUE: { bright: "#b0c8e8", night: "#7088a0" }
22840
+ var NIGHT_MUTED = NIGHT_MUTED_INK;
22841
+ var NIGHT_KNOCKOUT = resolveColor("UIBCK", "NIGHT");
22842
+ var LABEL_TINT = {
22843
+ WATER: { day: "#9ec1d8", night: "muted" },
22844
+ // halo — lakes, rivers, canals
22845
+ WATER_DEEP: { day: "#8fb8d0", night: "muted" },
22846
+ // halo — sea areas, water place names
22847
+ LAND_REGION: { day: "#e8d8b8", night: "muted" },
22848
+ // halo — land regions, land place names
22849
+ LAND_NATURAL: { day: "#e0d8c8", night: "muted" },
22850
+ // halo — islands
22851
+ CITY: { day: "#f1e7d2", night: "muted" },
22852
+ // halo — built-up areas
22853
+ AIRPORT: { day: "#d4c9b0", night: "muted" },
22854
+ // halo — airports, landmarks, harbour facilities
22855
+ STRUCTURE: { day: "#bfa88a", night: "muted" },
22856
+ // glyph — bridges, shoreline constructions
22857
+ STRUCTURE_LIGHT: { day: "#c8c0b0", night: "muted" },
22858
+ // glyph — piles, moorings; halo — single buildings
22859
+ SOUNDING: { day: "#c8c8c8", night: "muted" },
22860
+ // halo — seabed, contour values; glyph — variation
22861
+ MAGENTA: { day: "#c545c3", night: "hue" },
22862
+ // glyph — production areas, overhead cables
22863
+ PIPELINE: { day: "#7fbf3f", night: "hue" },
22864
+ // glyph — overhead pipelines
22865
+ KELP: { day: "#3f8a34", night: "hue" },
22866
+ // halo — weed / kelp
22867
+ NAV_WHITE: { day: "#ffffff", night: "ink" },
22868
+ // halo — lateral, isolated danger, safe water
22869
+ NAV_CREAM: { day: "#fdf0b0", night: "ink" },
22870
+ // halo — cardinals, light characteristics
22871
+ NAV_YELLOW: { day: "#eab308", night: "hue" },
22872
+ // halo — special-purpose marks
22873
+ NAV_BLUE: { day: "#b0c8e8", night: "muted" }
22874
+ // halo — fog signals
22760
22875
  };
22761
- function navHalo(palette, ct) {
22762
- return ct === "NIGHT" ? NAV_HALO[palette].night : NAV_HALO[palette].bright;
22876
+ function tintFor(tint, ct) {
22877
+ const day = LABEL_TINT[tint].day;
22878
+ if (ct === "DAY") return day;
22879
+ return capLuminance(day, relativeLuminance(resolveColor("CHBLK", ct)));
22880
+ }
22881
+ function nightText(tint) {
22882
+ const role = LABEL_TINT[tint].night;
22883
+ if (role === "ink") return NIGHT_INK;
22884
+ if (role === "muted") return NIGHT_MUTED;
22885
+ return capLuminance(LABEL_TINT[tint].day, relativeLuminance(NIGHT_MUTED));
22886
+ }
22887
+ function onHalo(tint, ct) {
22888
+ if (ct === "NIGHT") return { textColor: nightText(tint), textHaloColor: NIGHT_KNOCKOUT };
22889
+ return { textColor: DARK_BG, textHaloColor: tintFor(tint, ct) };
22890
+ }
22891
+ function onKnockout(tint, ct) {
22892
+ if (ct === "NIGHT") return { textColor: nightText(tint), textHaloColor: NIGHT_KNOCKOUT };
22893
+ return { textColor: tintFor(tint, ct), textHaloColor: DARK_BG };
22763
22894
  }
22764
22895
  var NAV_AID_LABEL_TEXT_SIZE = [
22765
22896
  "interpolate",
@@ -23041,21 +23172,6 @@ function buildAirportTierExpression() {
23041
23172
  2
23042
23173
  ];
23043
23174
  }
23044
- var COLOR = {
23045
- WATER: "#9ec1d8",
23046
- WATER_DEEP: "#8fb8d0",
23047
- LAND_REGION: "#e8d8b8",
23048
- LAND_NATURAL: "#e0d8c8",
23049
- CITY: "#f1e7d2",
23050
- AIRPORT: "#d4c9b0",
23051
- STRUCTURE: "#bfa88a",
23052
- STRUCTURE_LIGHT: "#c8c0b0",
23053
- SOUNDING: "#c8c8c8",
23054
- NAV_NUMBER: "#ffffff",
23055
- NAV_CARDINAL: "#fdf0b0",
23056
- NAV_SPECIAL: "#eab308",
23057
- LIGHT: "#fdf0b0"
23058
- };
23059
23175
  var ORIENTATION_BAND_SORT_KEY = [
23060
23176
  "to-number",
23061
23177
  ["slice", ["coalesce", ["get", "_cell_id"], "??9???"], 2, 3],
@@ -23400,8 +23516,7 @@ function getLabelConfig(layerName, opts = {}) {
23400
23516
  [13, [11.5, 11.5]],
23401
23517
  [16, [10.5, 11.5]]
23402
23518
  ]),
23403
- textColor: DARK_BG,
23404
- textHaloColor: COLOR.LAND_REGION,
23519
+ ...onHalo("LAND_REGION", ct),
23405
23520
  // Land halo, not the shared taper — see LAND_HALO_WIDTH.
23406
23521
  textHaloWidth: LAND_HALO_WIDTH,
23407
23522
  textOffset: [0, 0],
@@ -23415,8 +23530,7 @@ function getLabelConfig(layerName, opts = {}) {
23415
23530
  type: "symbol",
23416
23531
  textField: buildLandmarkLabelExpression(),
23417
23532
  textSize: 9,
23418
- textColor: DARK_BG,
23419
- textHaloColor: "#d4c9b0",
23533
+ ...onHalo("AIRPORT", ct),
23420
23534
  textHaloWidth: 1.5,
23421
23535
  textOffset: [0, 0],
23422
23536
  minzoom: 9,
@@ -23436,8 +23550,7 @@ function getLabelConfig(layerName, opts = {}) {
23436
23550
  type: "symbol",
23437
23551
  textField: buildHarbourFacilityLabelExpression(),
23438
23552
  textSize: 9,
23439
- textColor: DARK_BG,
23440
- textHaloColor: "#d4c9b0",
23553
+ ...onHalo("AIRPORT", ct),
23441
23554
  textHaloWidth: 1.5,
23442
23555
  textOffset: [0, 0],
23443
23556
  minzoom: 12,
@@ -23454,8 +23567,7 @@ function getLabelConfig(layerName, opts = {}) {
23454
23567
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23455
23568
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23456
23569
  textFont: NAV_AID_LABEL_FONT,
23457
- textColor: DARK_BG,
23458
- textHaloColor: navHalo("WHITE", ct),
23570
+ ...onHalo("NAV_WHITE", ct),
23459
23571
  textHaloWidth: 1.5,
23460
23572
  textOffset: [0, 1.5],
23461
23573
  minzoom: 10,
@@ -23467,8 +23579,7 @@ function getLabelConfig(layerName, opts = {}) {
23467
23579
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23468
23580
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23469
23581
  textFont: NAV_AID_LABEL_FONT,
23470
- textColor: DARK_BG,
23471
- textHaloColor: navHalo("WHITE", ct),
23582
+ ...onHalo("NAV_WHITE", ct),
23472
23583
  textHaloWidth: 1.5,
23473
23584
  textOffset: [0, 1.5],
23474
23585
  minzoom: 10,
@@ -23481,8 +23592,7 @@ function getLabelConfig(layerName, opts = {}) {
23481
23592
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23482
23593
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23483
23594
  textFont: NAV_AID_LABEL_FONT,
23484
- textColor: DARK_BG,
23485
- textHaloColor: navHalo("CREAM", ct),
23595
+ ...onHalo("NAV_CREAM", ct),
23486
23596
  textHaloWidth: 1.5,
23487
23597
  textOffset: [0, 1.5],
23488
23598
  minzoom: 10,
@@ -23495,8 +23605,7 @@ function getLabelConfig(layerName, opts = {}) {
23495
23605
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23496
23606
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23497
23607
  textFont: NAV_AID_LABEL_FONT,
23498
- textColor: DARK_BG,
23499
- textHaloColor: navHalo("YELLOW", ct),
23608
+ ...onHalo("NAV_YELLOW", ct),
23500
23609
  textHaloWidth: 1.5,
23501
23610
  textOffset: [0, 1.5],
23502
23611
  minzoom: 10,
@@ -23509,8 +23618,7 @@ function getLabelConfig(layerName, opts = {}) {
23509
23618
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23510
23619
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23511
23620
  textFont: NAV_AID_LABEL_FONT,
23512
- textColor: DARK_BG,
23513
- textHaloColor: navHalo("WHITE", ct),
23621
+ ...onHalo("NAV_WHITE", ct),
23514
23622
  textHaloWidth: 1.5,
23515
23623
  textOffset: [0, 1.5],
23516
23624
  minzoom: 10,
@@ -23522,8 +23630,7 @@ function getLabelConfig(layerName, opts = {}) {
23522
23630
  textField: ["get", "_lightLabel"],
23523
23631
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23524
23632
  textFont: NAV_AID_LABEL_FONT,
23525
- textColor: DARK_BG,
23526
- textHaloColor: navHalo("CREAM", ct),
23633
+ ...onHalo("NAV_CREAM", ct),
23527
23634
  textHaloWidth: 1.5,
23528
23635
  textOffset: [2, 0],
23529
23636
  minzoom: 9,
@@ -23547,8 +23654,7 @@ function getLabelConfig(layerName, opts = {}) {
23547
23654
  textField: catfogExpr,
23548
23655
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23549
23656
  textFont: NAV_AID_LABEL_FONT,
23550
- textColor: DARK_BG,
23551
- textHaloColor: navHalo("BLUE", ct),
23657
+ ...onHalo("NAV_BLUE", ct),
23552
23658
  textHaloWidth: 1.5,
23553
23659
  textOffset: [2, 1.2],
23554
23660
  minzoom: 11,
@@ -23623,8 +23729,7 @@ function getLabelConfig(layerName, opts = {}) {
23623
23729
  [13, [0, 0, 13, 10, 11]],
23624
23730
  [16, [0, 0, 12, 11, 10]]
23625
23731
  ]),
23626
- textColor: DARK_BG,
23627
- textHaloColor: COLOR.WATER_DEEP,
23732
+ ...onHalo("WATER_DEEP", ct),
23628
23733
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23629
23734
  textOffset: [0, 0],
23630
23735
  textFont: ["Open Sans Italic"],
@@ -23694,8 +23799,7 @@ function getLabelConfig(layerName, opts = {}) {
23694
23799
  [13, [10, 11]],
23695
23800
  [16, [9, 10]]
23696
23801
  ]),
23697
- textColor: DARK_BG,
23698
- textHaloColor: COLOR.WATER,
23802
+ ...onHalo("WATER", ct),
23699
23803
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23700
23804
  textOffset: [0, 0],
23701
23805
  textFont: ["Open Sans Italic"],
@@ -23715,8 +23819,7 @@ function getLabelConfig(layerName, opts = {}) {
23715
23819
  [13, [10, 10]],
23716
23820
  [16, [9, 10]]
23717
23821
  ]),
23718
- textColor: DARK_BG,
23719
- textHaloColor: COLOR.WATER,
23822
+ ...onHalo("WATER", ct),
23720
23823
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23721
23824
  textOffset: [0, 0],
23722
23825
  textFont: ["Open Sans Italic"],
@@ -23739,8 +23842,7 @@ function getLabelConfig(layerName, opts = {}) {
23739
23842
  16,
23740
23843
  9
23741
23844
  ],
23742
- textColor: DARK_BG,
23743
- textHaloColor: COLOR.WATER,
23845
+ ...onHalo("WATER", ct),
23744
23846
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23745
23847
  textOffset: [0, 0],
23746
23848
  textFont: ["Open Sans Italic"],
@@ -23769,8 +23871,7 @@ function getLabelConfig(layerName, opts = {}) {
23769
23871
  [13, [11.5, 11.5]],
23770
23872
  [16, [10.5, 11.5]]
23771
23873
  ]),
23772
- textColor: DARK_BG,
23773
- textHaloColor: COLOR.LAND_NATURAL,
23874
+ ...onHalo("LAND_NATURAL", ct),
23774
23875
  // Land halo, not the shared taper — see LAND_HALO_WIDTH.
23775
23876
  textHaloWidth: LAND_HALO_WIDTH,
23776
23877
  textOffset: [0, 0],
@@ -23793,8 +23894,7 @@ function getLabelConfig(layerName, opts = {}) {
23793
23894
  [13, [10, 11, 12]],
23794
23895
  [16, [10, 10, 11]]
23795
23896
  ]),
23796
- textColor: DARK_BG,
23797
- textHaloColor: COLOR.CITY,
23897
+ ...onHalo("CITY", ct),
23798
23898
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23799
23899
  textOffset: [0, 0],
23800
23900
  textFont: ["Open Sans Regular"],
@@ -23809,8 +23909,7 @@ function getLabelConfig(layerName, opts = {}) {
23809
23909
  type: "symbol",
23810
23910
  textField: OBJNAM_TEXT,
23811
23911
  textSize: 9,
23812
- textColor: "#bfa88a",
23813
- textHaloColor: DARK_BG,
23912
+ ...onKnockout("STRUCTURE", ct),
23814
23913
  textHaloWidth: 1.5,
23815
23914
  textOffset: [0, 0],
23816
23915
  minzoom: 12,
@@ -23828,8 +23927,7 @@ function getLabelConfig(layerName, opts = {}) {
23828
23927
  type: "symbol",
23829
23928
  textField: OBJNAM_TEXT,
23830
23929
  textSize: 8,
23831
- textColor: "#c8c0b0",
23832
- textHaloColor: DARK_BG,
23930
+ ...onKnockout("STRUCTURE_LIGHT", ct),
23833
23931
  textHaloWidth: 1.2,
23834
23932
  textOffset: [0, 1.2],
23835
23933
  minzoom: 13
@@ -23839,8 +23937,7 @@ function getLabelConfig(layerName, opts = {}) {
23839
23937
  type: "symbol",
23840
23938
  textField: OBJNAM_TEXT,
23841
23939
  textSize: 8,
23842
- textColor: "#c8c0b0",
23843
- textHaloColor: DARK_BG,
23940
+ ...onKnockout("STRUCTURE_LIGHT", ct),
23844
23941
  textHaloWidth: 1.2,
23845
23942
  textOffset: [0, 1.2],
23846
23943
  minzoom: 13
@@ -23850,8 +23947,7 @@ function getLabelConfig(layerName, opts = {}) {
23850
23947
  type: "symbol",
23851
23948
  textField: OBJNAM_TEXT,
23852
23949
  textSize: 8,
23853
- textColor: "#bfa88a",
23854
- textHaloColor: DARK_BG,
23950
+ ...onKnockout("STRUCTURE", ct),
23855
23951
  textHaloWidth: 1.2,
23856
23952
  textOffset: [0, 1],
23857
23953
  minzoom: 13,
@@ -23865,8 +23961,7 @@ function getLabelConfig(layerName, opts = {}) {
23865
23961
  type: "symbol",
23866
23962
  textField: OBJNAM_TEXT,
23867
23963
  textSize: 8,
23868
- textColor: DARK_BG,
23869
- textHaloColor: "#c8c0b0",
23964
+ ...onHalo("STRUCTURE_LIGHT", ct),
23870
23965
  textHaloWidth: 1.2,
23871
23966
  textOffset: [0, 1.2],
23872
23967
  minzoom: 14,
@@ -23887,8 +23982,7 @@ function getLabelConfig(layerName, opts = {}) {
23887
23982
  [13, [10, 10]],
23888
23983
  [16, [9, 9]]
23889
23984
  ]),
23890
- textColor: DARK_BG,
23891
- textHaloColor: COLOR.AIRPORT,
23985
+ ...onHalo("AIRPORT", ct),
23892
23986
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23893
23987
  textOffset: [0, 0],
23894
23988
  textFont: ["Open Sans Regular"],
@@ -23909,8 +24003,7 @@ function getLabelConfig(layerName, opts = {}) {
23909
24003
  16,
23910
24004
  11
23911
24005
  ],
23912
- textColor: DARK_BG,
23913
- textHaloColor: COLOR.SOUNDING,
24006
+ ...onHalo("SOUNDING", ct),
23914
24007
  textHaloWidth: 1,
23915
24008
  textOffset: [0, 0],
23916
24009
  textFont: ["Open Sans Italic"],
@@ -23944,8 +24037,7 @@ function getLabelConfig(layerName, opts = {}) {
23944
24037
  14,
23945
24038
  11
23946
24039
  ],
23947
- textColor: COLOR.SOUNDING,
23948
- textHaloColor: DARK_BG,
24040
+ ...onKnockout("SOUNDING", ct),
23949
24041
  textHaloWidth: 1,
23950
24042
  textOffset: [0, 0],
23951
24043
  textFont: ["Open Sans Italic"],
@@ -23975,8 +24067,7 @@ function getLabelConfig(layerName, opts = {}) {
23975
24067
  16,
23976
24068
  8
23977
24069
  ],
23978
- textColor: "#c545c3",
23979
- textHaloColor: DARK_BG,
24070
+ ...onKnockout("MAGENTA", ct),
23980
24071
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23981
24072
  textOffset: [0, 0],
23982
24073
  textFont: ["Open Sans Italic"],
@@ -23996,8 +24087,7 @@ function getLabelConfig(layerName, opts = {}) {
23996
24087
  16,
23997
24088
  11
23998
24089
  ],
23999
- textColor: DARK_BG,
24000
- textHaloColor: "#3f8a34",
24090
+ ...onHalo("KELP", ct),
24001
24091
  textHaloWidth: 1,
24002
24092
  textOffset: [0, 0],
24003
24093
  textFont: ["Open Sans Italic"],
@@ -24089,8 +24179,7 @@ function getLabelConfig(layerName, opts = {}) {
24089
24179
  17,
24090
24180
  11
24091
24181
  ],
24092
- textColor: isCBL ? "#c545c3" : "#7fbf3f",
24093
- textHaloColor: DARK_BG,
24182
+ ...onKnockout(isCBL ? "MAGENTA" : "PIPELINE", ct),
24094
24183
  textHaloWidth: 1.4,
24095
24184
  textOffset: [0, 0],
24096
24185
  textFont: ["Open Sans Regular"],
@@ -24125,8 +24214,7 @@ function getLabelConfig(layerName, opts = {}) {
24125
24214
  14,
24126
24215
  10
24127
24216
  ],
24128
- textColor: DARK_BG,
24129
- textHaloColor: "#c8c8c8",
24217
+ ...onHalo("SOUNDING", ct),
24130
24218
  textHaloWidth: 1.2,
24131
24219
  textOffset: [0, 0],
24132
24220
  textFont: ["Open Sans Regular"],
@@ -24431,9 +24519,9 @@ var PLACENAME_LAND_SIZE_STOPS = [
24431
24519
  [13, [0, 0, 10, 11, 10, 11, 10, 10, 10, 10]],
24432
24520
  [16, [0, 0, 10, 10, 9, 10, 9, 9, 9, 9]]
24433
24521
  ];
24434
- function buildPlaceNameLayers(sourceId) {
24522
+ function buildPlaceNameLayers(sourceId, ct = "DAY") {
24435
24523
  const sortKey = ["to-number", ["coalesce", ["get", "rank"], 9999999]];
24436
- const make = (idSuffix, classes, font, haloColor, letterSpacing, stops) => ({
24524
+ const make = (idSuffix, classes, font, tint, letterSpacing, stops) => ({
24437
24525
  id: `chrt-placename-${idSuffix}`,
24438
24526
  type: "symbol",
24439
24527
  source: sourceId,
@@ -24461,8 +24549,8 @@ function buildPlaceNameLayers(sourceId) {
24461
24549
  "symbol-sort-key": sortKey
24462
24550
  },
24463
24551
  paint: {
24464
- "text-color": DARK_BG,
24465
- "text-halo-color": haloColor,
24552
+ "text-color": onHalo(tint, ct).textColor,
24553
+ "text-halo-color": onHalo(tint, ct).textHaloColor,
24466
24554
  "text-halo-width": ORIENTATION_HALO_WIDTH,
24467
24555
  "text-opacity": PLACENAME_TEXT_OPACITY
24468
24556
  },
@@ -24472,8 +24560,8 @@ function buildPlaceNameLayers(sourceId) {
24472
24560
  }
24473
24561
  });
24474
24562
  return [
24475
- make("water", PLACENAME_WATER_CLASSES, ["Open Sans Italic"], COLOR.WATER_DEEP, 0.05, PLACENAME_WATER_SIZE_STOPS),
24476
- make("land", PLACENAME_LAND_CLASSES, ["Open Sans Regular"], COLOR.LAND_REGION, 0.02, PLACENAME_LAND_SIZE_STOPS)
24563
+ make("water", PLACENAME_WATER_CLASSES, ["Open Sans Italic"], "WATER_DEEP", 0.05, PLACENAME_WATER_SIZE_STOPS),
24564
+ make("land", PLACENAME_LAND_CLASSES, ["Open Sans Regular"], "LAND_REGION", 0.02, PLACENAME_LAND_SIZE_STOPS)
24477
24565
  ];
24478
24566
  }
24479
24567
  var DRGNOTE_SOURCE_LAYER = "DRGNOTE";
@@ -27197,37 +27285,58 @@ var CHRT_ATON_COLORS = {
27197
27285
  // pink (magenta-ish)
27198
27286
  };
27199
27287
  var CHRT_UNKNOWN_TINT = "#8B9298";
27200
- function chrtAtonTintExpression() {
27288
+ var HOUSE_BLACK = "#101418";
27289
+ function chrtHouseColor(dayHex, palette = "DAY") {
27290
+ if (palette === "DAY") return dayHex;
27291
+ const isBlack = dayHex.toLowerCase() === HOUSE_BLACK.toLowerCase();
27292
+ if (palette === "DUSK") {
27293
+ return isBlack ? dayHex : capLuminance(dayHex, relativeLuminance(resolveColor("CHBLK", "DUSK")));
27294
+ }
27295
+ return isBlack ? NIGHT_INK : capLuminance(dayHex, relativeLuminance(NIGHT_MUTED_INK));
27296
+ }
27297
+ function themeChrtGlyph(svg3, palette = "DAY") {
27298
+ if (palette === "DAY") return svg3;
27299
+ return svg3.replace(
27300
+ /(fill|stroke)="(#[0-9a-fA-F]{3}|#[0-9a-fA-F]{6})"/g,
27301
+ (_m, attr, hex) => {
27302
+ const six = hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex;
27303
+ return `${attr}="${chrtHouseColor(six, palette)}"`;
27304
+ }
27305
+ );
27306
+ }
27307
+ function chrtAtonTintExpression(palette = "DAY") {
27308
+ const c = (code) => chrtHouseColor(CHRT_ATON_COLORS[code], palette);
27201
27309
  return colourCodeCase(
27202
27310
  [
27203
- ["3", CHRT_ATON_COLORS["3"]],
27204
- ["4", CHRT_ATON_COLORS["4"]],
27205
- ["6", CHRT_ATON_COLORS["6"]],
27206
- ["11", CHRT_ATON_COLORS["11"]],
27207
- ["9", CHRT_ATON_COLORS["9"]],
27208
- ["5", CHRT_ATON_COLORS["5"]],
27209
- ["1", CHRT_ATON_COLORS["1"]],
27210
- ["2", CHRT_ATON_COLORS["2"]],
27211
- ["8", CHRT_ATON_COLORS["8"]],
27212
- ["10", CHRT_ATON_COLORS["10"]],
27213
- ["12", CHRT_ATON_COLORS["12"]],
27214
- ["7", CHRT_ATON_COLORS["7"]]
27311
+ ["3", c("3")],
27312
+ ["4", c("4")],
27313
+ ["6", c("6")],
27314
+ ["11", c("11")],
27315
+ ["9", c("9")],
27316
+ ["5", c("5")],
27317
+ ["1", c("1")],
27318
+ ["2", c("2")],
27319
+ ["8", c("8")],
27320
+ ["10", c("10")],
27321
+ ["12", c("12")],
27322
+ ["7", c("7")]
27215
27323
  ],
27216
- CHRT_UNKNOWN_TINT
27324
+ chrtHouseColor(CHRT_UNKNOWN_TINT, palette)
27217
27325
  );
27218
27326
  }
27219
- function chrtLightTintExpression() {
27327
+ function chrtLightTintExpression(palette = "DAY") {
27328
+ const c = (code) => chrtHouseColor(CHRT_ATON_COLORS[code], palette);
27220
27329
  return colourCodeCase(
27221
27330
  [
27222
- ["3", CHRT_ATON_COLORS["3"]],
27223
- ["4", CHRT_ATON_COLORS["4"]],
27224
- ["6", CHRT_ATON_COLORS["6"]],
27225
- ["11", CHRT_ATON_COLORS["11"]],
27226
- ["9", CHRT_ATON_COLORS["9"]],
27227
- ["5", CHRT_ATON_COLORS["5"]],
27228
- ["1", CHRT_ATON_COLORS["1"]]
27331
+ ["3", c("3")],
27332
+ ["4", c("4")],
27333
+ ["6", c("6")],
27334
+ ["11", c("11")],
27335
+ ["9", c("9")],
27336
+ ["5", c("5")],
27337
+ ["1", c("1")]
27229
27338
  ],
27230
- CHRT_ATON_COLORS["1"]
27339
+ c("1")
27231
27340
  );
27232
27341
  }
27233
27342
  function scalar(attr) {
@@ -27329,7 +27438,7 @@ var TINTED_CLASSES = /* @__PURE__ */ new Set([
27329
27438
  "BCNSPP",
27330
27439
  "DAYMAR"
27331
27440
  ]);
27332
- var CHRT_HALO = { color: "#101418", width: 1 };
27441
+ var CHRT_HALO = { color: HOUSE_BLACK, width: 1 };
27333
27442
  var CHRT_LINE_DASH = {
27334
27443
  CBLSUB: { color: "CHMGD", width: 0.8, dash: [6, 3] },
27335
27444
  PIPSOL: { color: "PIPLN", width: 0.8, dash: [6, 3] }
@@ -27357,11 +27466,11 @@ function applyChrtSymbolSet(style, palette = "DAY") {
27357
27466
  layout["icon-image"] = CHRT_ICON_EXPRESSIONS[objectClass]();
27358
27467
  const paint = layer.paint ?? {};
27359
27468
  if (TINTED_CLASSES.has(objectClass)) {
27360
- paint["icon-color"] = chrtAtonTintExpression();
27469
+ paint["icon-color"] = chrtAtonTintExpression(palette);
27361
27470
  paint["icon-halo-color"] = CHRT_HALO.color;
27362
27471
  paint["icon-halo-width"] = CHRT_HALO.width;
27363
27472
  } else if (objectClass === "LIGHTS") {
27364
- paint["icon-color"] = chrtLightTintExpression();
27473
+ paint["icon-color"] = chrtLightTintExpression(palette);
27365
27474
  paint["icon-halo-color"] = CHRT_HALO.color;
27366
27475
  paint["icon-halo-width"] = CHRT_HALO.width;
27367
27476
  }
@@ -30513,7 +30622,7 @@ function generateStyle(palette = "DAY", opts = {}) {
30513
30622
  )
30514
30623
  );
30515
30624
  if (opts.labels === "placename") {
30516
- labelLayers.push(...buildPlaceNameLayers(sourceId));
30625
+ labelLayers.push(...buildPlaceNameLayers(sourceId, palette));
30517
30626
  }
30518
30627
  for (const { label } of chartLabelBundles) {
30519
30628
  if (bandFan === "collapsed") {
@@ -30603,7 +30712,7 @@ function generateStyle(palette = "DAY", opts = {}) {
30603
30712
  }
30604
30713
  }
30605
30714
  if (opts.labels === "placename") {
30606
- labelLayers.push(...buildPlaceNameLayers(sourceId));
30715
+ labelLayers.push(...buildPlaceNameLayers(sourceId, palette));
30607
30716
  } else {
30608
30717
  for (const { objectClass, label } of bundles) {
30609
30718
  if (!label) continue;
@@ -31775,6 +31884,8 @@ export {
31775
31884
  NAUTICAL_SYMBOLS,
31776
31885
  NAV_AID_LAYER_GROUPS,
31777
31886
  NAV_AID_QUERY_LAYERS,
31887
+ NIGHT_INK,
31888
+ NIGHT_MUTED_INK,
31778
31889
  NON_SOLAS_DISCLAIMER,
31779
31890
  NON_SOLAS_DISCLAIMER_SHORT,
31780
31891
  OfflineError,
@@ -31845,13 +31956,16 @@ export {
31845
31956
  buildSectorsFromFeatures,
31846
31957
  buildSources,
31847
31958
  candidateRank,
31959
+ capLuminance,
31848
31960
  cellBandCharacters,
31849
31961
  cellBandMatch,
31850
31962
  chrtAtonTintExpression,
31963
+ chrtHouseColor,
31851
31964
  chrtLightTintExpression,
31852
31965
  collectCandidates,
31853
31966
  collectClickCandidates,
31854
31967
  combineWithBandFilter,
31968
+ contrastRatio,
31855
31969
  daymarkColor,
31856
31970
  decimateFeatures,
31857
31971
  decodeAreaFeatureProps,
@@ -31923,6 +32037,7 @@ export {
31923
32037
  preprocessSoundings,
31924
32038
  preprocessWaterBodies,
31925
32039
  rasterAtonIconExpression,
32040
+ relativeLuminance,
31926
32041
  resolveColor,
31927
32042
  resolveCustomTheme,
31928
32043
  resolveRasterImage,
@@ -31932,11 +32047,13 @@ export {
31932
32047
  rhythmProperties,
31933
32048
  s101ArtworkProvenance,
31934
32049
  sanitizeCustomStyleConfig,
32050
+ scaleLinearLight,
31935
32051
  scaleSizeValue,
31936
32052
  scaminToMinZoom,
31937
32053
  sectorLimitToArcBearing,
31938
32054
  styleModeBand,
31939
32055
  terrainStackCount,
32056
+ themeChrtGlyph,
31940
32057
  tileTemplate,
31941
32058
  uncoveredSectorArcs,
31942
32059
  withinBboxFilter,