@chrtco/sdk 0.10.42 → 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.cjs CHANGED
@@ -85,6 +85,8 @@ __export(index_exports, {
85
85
  NAUTICAL_SYMBOLS: () => NAUTICAL_SYMBOLS,
86
86
  NAV_AID_LAYER_GROUPS: () => NAV_AID_LAYER_GROUPS,
87
87
  NAV_AID_QUERY_LAYERS: () => NAV_AID_QUERY_LAYERS,
88
+ NIGHT_INK: () => NIGHT_INK,
89
+ NIGHT_MUTED_INK: () => NIGHT_MUTED_INK,
88
90
  NON_SOLAS_DISCLAIMER: () => NON_SOLAS_DISCLAIMER,
89
91
  NON_SOLAS_DISCLAIMER_SHORT: () => NON_SOLAS_DISCLAIMER_SHORT,
90
92
  OfflineError: () => OfflineError,
@@ -155,13 +157,16 @@ __export(index_exports, {
155
157
  buildSectorsFromFeatures: () => buildSectorsFromFeatures,
156
158
  buildSources: () => buildSources,
157
159
  candidateRank: () => candidateRank,
160
+ capLuminance: () => capLuminance,
158
161
  cellBandCharacters: () => cellBandCharacters,
159
162
  cellBandMatch: () => cellBandMatch,
160
163
  chrtAtonTintExpression: () => chrtAtonTintExpression,
164
+ chrtHouseColor: () => chrtHouseColor,
161
165
  chrtLightTintExpression: () => chrtLightTintExpression,
162
166
  collectCandidates: () => collectCandidates,
163
167
  collectClickCandidates: () => collectClickCandidates,
164
168
  combineWithBandFilter: () => combineWithBandFilter,
169
+ contrastRatio: () => contrastRatio,
165
170
  daymarkColor: () => daymarkColor,
166
171
  decimateFeatures: () => decimateFeatures,
167
172
  decodeAreaFeatureProps: () => decodeAreaFeatureProps,
@@ -233,6 +238,7 @@ __export(index_exports, {
233
238
  preprocessSoundings: () => preprocessSoundings,
234
239
  preprocessWaterBodies: () => preprocessWaterBodies,
235
240
  rasterAtonIconExpression: () => rasterAtonIconExpression,
241
+ relativeLuminance: () => relativeLuminance,
236
242
  resolveColor: () => resolveColor,
237
243
  resolveCustomTheme: () => resolveCustomTheme,
238
244
  resolveRasterImage: () => resolveRasterImage,
@@ -242,11 +248,13 @@ __export(index_exports, {
242
248
  rhythmProperties: () => rhythmProperties,
243
249
  s101ArtworkProvenance: () => s101ArtworkProvenance,
244
250
  sanitizeCustomStyleConfig: () => sanitizeCustomStyleConfig,
251
+ scaleLinearLight: () => scaleLinearLight,
245
252
  scaleSizeValue: () => scaleSizeValue,
246
253
  scaminToMinZoom: () => scaminToMinZoom,
247
254
  sectorLimitToArcBearing: () => sectorLimitToArcBearing,
248
255
  styleModeBand: () => styleModeBand,
249
256
  terrainStackCount: () => terrainStackCount,
257
+ themeChrtGlyph: () => themeChrtGlyph,
250
258
  tileTemplate: () => tileTemplate,
251
259
  uncoveredSectorArcs: () => uncoveredSectorArcs,
252
260
  withinBboxFilter: () => withinBboxFilter,
@@ -2484,6 +2492,22 @@ var S52_NIGHT = {
2484
2492
  CHBRN: "#382410",
2485
2493
  CHGRF: "#2a2a22",
2486
2494
  CHGRD: "#1e1e18",
2495
+ // The NIGHT ink — linework, symbol outlines, navigation text, the shoal
2496
+ // soundings (SNDG2 below). Light warm on dark water: a deliberate deviation
2497
+ // from the spec's near-black (#1f2223), so a NIGHT chart is legible on a
2498
+ // screen nobody has dimmed. It is the brightest thing NIGHT draws on purpose,
2499
+ // and `night-luminance.test.ts` holds everything else under its muted level.
2500
+ //
2501
+ // ⚠ RED NIGHT DOES NOT DIM IT, AND THAT WAS DECIDED, NOT MISSED (2026-10-01).
2502
+ // Red night composes this same NIGHT chart with red chrome, as iOS does
2503
+ // (ContentView `effectiveChartTheme`). Dimming the ink for red night alone
2504
+ // would (1) drop SNDG2 out of the deeper soundings' legibility window — SNDG1
2505
+ // is pinned to 43% of this light by `sounding-legibility.test.ts` — and the
2506
+ // owner's red-night report of 2026-09-30 asked for MORE sounding legibility,
2507
+ // not less; and (2) dim the hazard outlines (OBSTRN, WRECKS) and coastline
2508
+ // that a night chart must keep. What red night was missing was everything
2509
+ // that did NOT follow this palette: labels, house marks, hatches, sector
2510
+ // bearings. Those follow it now.
2487
2511
  CHBLK: "#c8aa78",
2488
2512
  CSTLN: "#c8aa78",
2489
2513
  OUTLW: "#c8aa78",
@@ -5228,6 +5252,45 @@ var InteractClient = class {
5228
5252
  }
5229
5253
  };
5230
5254
 
5255
+ // src/atlas/palette-light.ts
5256
+ var HEX6 = /^#?([0-9a-f]{6})$/i;
5257
+ function channels(hex) {
5258
+ const m = HEX6.exec(hex);
5259
+ if (!m) throw new Error(`palette-light: "${hex}" is not a #rrggbb colour`);
5260
+ const h = m[1];
5261
+ return [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16));
5262
+ }
5263
+ function toLinear(c) {
5264
+ const v = c / 255;
5265
+ return v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
5266
+ }
5267
+ function toEncoded(v) {
5268
+ const c = v <= 31308e-7 ? v * 12.92 : 1.055 * v ** (1 / 2.4) - 0.055;
5269
+ return Math.round(Math.min(1, Math.max(0, c)) * 255);
5270
+ }
5271
+ function hex2(n) {
5272
+ return n.toString(16).padStart(2, "0");
5273
+ }
5274
+ function relativeLuminance(hex) {
5275
+ const [r, g2, b] = channels(hex).map(toLinear);
5276
+ return 0.2126 * r + 0.7152 * g2 + 0.0722 * b;
5277
+ }
5278
+ function contrastRatio(a, b) {
5279
+ const [hi, lo] = [relativeLuminance(a), relativeLuminance(b)].sort((x, y) => y - x);
5280
+ return (hi + 0.05) / (lo + 0.05);
5281
+ }
5282
+ function scaleLinearLight(hex, factor) {
5283
+ const [r, g2, b] = channels(hex).map((c) => toEncoded(toLinear(c) * factor));
5284
+ return `#${hex2(r)}${hex2(g2)}${hex2(b)}`;
5285
+ }
5286
+ function capLuminance(hex, ceiling) {
5287
+ const l = relativeLuminance(hex);
5288
+ if (l <= ceiling) return scaleLinearLight(hex, 1);
5289
+ return scaleLinearLight(hex, ceiling / l);
5290
+ }
5291
+ var NIGHT_INK = S52_NIGHT.CHBLK;
5292
+ var NIGHT_MUTED_INK = scaleLinearLight(S52_NIGHT.CHBLK, 0.43);
5293
+
5231
5294
  // src/atlas/s52-linestyles-generated.ts
5232
5295
  var S52_LINESTYLES = {
5233
5296
  ACHARE51: {
@@ -23038,14 +23101,60 @@ var NATQUA_ABBR = [
23038
23101
  // hard
23039
23102
  ];
23040
23103
  var DARK_BG = "#1a1d23";
23041
- var NAV_HALO = {
23042
- WHITE: { bright: "#ffffff", night: "#b8b0a0" },
23043
- CREAM: { bright: "#fdf0b0", night: "#a89868" },
23044
- YELLOW: { bright: "#eab308", night: "#806020" },
23045
- BLUE: { bright: "#b0c8e8", night: "#7088a0" }
23104
+ var NIGHT_MUTED = NIGHT_MUTED_INK;
23105
+ var NIGHT_KNOCKOUT = resolveColor("UIBCK", "NIGHT");
23106
+ var LABEL_TINT = {
23107
+ WATER: { day: "#9ec1d8", night: "muted" },
23108
+ // halo — lakes, rivers, canals
23109
+ WATER_DEEP: { day: "#8fb8d0", night: "muted" },
23110
+ // halo — sea areas, water place names
23111
+ LAND_REGION: { day: "#e8d8b8", night: "muted" },
23112
+ // halo — land regions, land place names
23113
+ LAND_NATURAL: { day: "#e0d8c8", night: "muted" },
23114
+ // halo — islands
23115
+ CITY: { day: "#f1e7d2", night: "muted" },
23116
+ // halo — built-up areas
23117
+ AIRPORT: { day: "#d4c9b0", night: "muted" },
23118
+ // halo — airports, landmarks, harbour facilities
23119
+ STRUCTURE: { day: "#bfa88a", night: "muted" },
23120
+ // glyph — bridges, shoreline constructions
23121
+ STRUCTURE_LIGHT: { day: "#c8c0b0", night: "muted" },
23122
+ // glyph — piles, moorings; halo — single buildings
23123
+ SOUNDING: { day: "#c8c8c8", night: "muted" },
23124
+ // halo — seabed, contour values; glyph — variation
23125
+ MAGENTA: { day: "#c545c3", night: "hue" },
23126
+ // glyph — production areas, overhead cables
23127
+ PIPELINE: { day: "#7fbf3f", night: "hue" },
23128
+ // glyph — overhead pipelines
23129
+ KELP: { day: "#3f8a34", night: "hue" },
23130
+ // halo — weed / kelp
23131
+ NAV_WHITE: { day: "#ffffff", night: "ink" },
23132
+ // halo — lateral, isolated danger, safe water
23133
+ NAV_CREAM: { day: "#fdf0b0", night: "ink" },
23134
+ // halo — cardinals, light characteristics
23135
+ NAV_YELLOW: { day: "#eab308", night: "hue" },
23136
+ // halo — special-purpose marks
23137
+ NAV_BLUE: { day: "#b0c8e8", night: "muted" }
23138
+ // halo — fog signals
23046
23139
  };
23047
- function navHalo(palette, ct) {
23048
- return ct === "NIGHT" ? NAV_HALO[palette].night : NAV_HALO[palette].bright;
23140
+ function tintFor(tint, ct) {
23141
+ const day = LABEL_TINT[tint].day;
23142
+ if (ct === "DAY") return day;
23143
+ return capLuminance(day, relativeLuminance(resolveColor("CHBLK", ct)));
23144
+ }
23145
+ function nightText(tint) {
23146
+ const role = LABEL_TINT[tint].night;
23147
+ if (role === "ink") return NIGHT_INK;
23148
+ if (role === "muted") return NIGHT_MUTED;
23149
+ return capLuminance(LABEL_TINT[tint].day, relativeLuminance(NIGHT_MUTED));
23150
+ }
23151
+ function onHalo(tint, ct) {
23152
+ if (ct === "NIGHT") return { textColor: nightText(tint), textHaloColor: NIGHT_KNOCKOUT };
23153
+ return { textColor: DARK_BG, textHaloColor: tintFor(tint, ct) };
23154
+ }
23155
+ function onKnockout(tint, ct) {
23156
+ if (ct === "NIGHT") return { textColor: nightText(tint), textHaloColor: NIGHT_KNOCKOUT };
23157
+ return { textColor: tintFor(tint, ct), textHaloColor: DARK_BG };
23049
23158
  }
23050
23159
  var NAV_AID_LABEL_TEXT_SIZE = [
23051
23160
  "interpolate",
@@ -23327,21 +23436,6 @@ function buildAirportTierExpression() {
23327
23436
  2
23328
23437
  ];
23329
23438
  }
23330
- var COLOR = {
23331
- WATER: "#9ec1d8",
23332
- WATER_DEEP: "#8fb8d0",
23333
- LAND_REGION: "#e8d8b8",
23334
- LAND_NATURAL: "#e0d8c8",
23335
- CITY: "#f1e7d2",
23336
- AIRPORT: "#d4c9b0",
23337
- STRUCTURE: "#bfa88a",
23338
- STRUCTURE_LIGHT: "#c8c0b0",
23339
- SOUNDING: "#c8c8c8",
23340
- NAV_NUMBER: "#ffffff",
23341
- NAV_CARDINAL: "#fdf0b0",
23342
- NAV_SPECIAL: "#eab308",
23343
- LIGHT: "#fdf0b0"
23344
- };
23345
23439
  var ORIENTATION_BAND_SORT_KEY = [
23346
23440
  "to-number",
23347
23441
  ["slice", ["coalesce", ["get", "_cell_id"], "??9???"], 2, 3],
@@ -23686,8 +23780,7 @@ function getLabelConfig(layerName, opts = {}) {
23686
23780
  [13, [11.5, 11.5]],
23687
23781
  [16, [10.5, 11.5]]
23688
23782
  ]),
23689
- textColor: DARK_BG,
23690
- textHaloColor: COLOR.LAND_REGION,
23783
+ ...onHalo("LAND_REGION", ct),
23691
23784
  // Land halo, not the shared taper — see LAND_HALO_WIDTH.
23692
23785
  textHaloWidth: LAND_HALO_WIDTH,
23693
23786
  textOffset: [0, 0],
@@ -23701,8 +23794,7 @@ function getLabelConfig(layerName, opts = {}) {
23701
23794
  type: "symbol",
23702
23795
  textField: buildLandmarkLabelExpression(),
23703
23796
  textSize: 9,
23704
- textColor: DARK_BG,
23705
- textHaloColor: "#d4c9b0",
23797
+ ...onHalo("AIRPORT", ct),
23706
23798
  textHaloWidth: 1.5,
23707
23799
  textOffset: [0, 0],
23708
23800
  minzoom: 9,
@@ -23722,8 +23814,7 @@ function getLabelConfig(layerName, opts = {}) {
23722
23814
  type: "symbol",
23723
23815
  textField: buildHarbourFacilityLabelExpression(),
23724
23816
  textSize: 9,
23725
- textColor: DARK_BG,
23726
- textHaloColor: "#d4c9b0",
23817
+ ...onHalo("AIRPORT", ct),
23727
23818
  textHaloWidth: 1.5,
23728
23819
  textOffset: [0, 0],
23729
23820
  minzoom: 12,
@@ -23740,8 +23831,7 @@ function getLabelConfig(layerName, opts = {}) {
23740
23831
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23741
23832
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23742
23833
  textFont: NAV_AID_LABEL_FONT,
23743
- textColor: DARK_BG,
23744
- textHaloColor: navHalo("WHITE", ct),
23834
+ ...onHalo("NAV_WHITE", ct),
23745
23835
  textHaloWidth: 1.5,
23746
23836
  textOffset: [0, 1.5],
23747
23837
  minzoom: 10,
@@ -23753,8 +23843,7 @@ function getLabelConfig(layerName, opts = {}) {
23753
23843
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23754
23844
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23755
23845
  textFont: NAV_AID_LABEL_FONT,
23756
- textColor: DARK_BG,
23757
- textHaloColor: navHalo("WHITE", ct),
23846
+ ...onHalo("NAV_WHITE", ct),
23758
23847
  textHaloWidth: 1.5,
23759
23848
  textOffset: [0, 1.5],
23760
23849
  minzoom: 10,
@@ -23767,8 +23856,7 @@ function getLabelConfig(layerName, opts = {}) {
23767
23856
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23768
23857
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23769
23858
  textFont: NAV_AID_LABEL_FONT,
23770
- textColor: DARK_BG,
23771
- textHaloColor: navHalo("CREAM", ct),
23859
+ ...onHalo("NAV_CREAM", ct),
23772
23860
  textHaloWidth: 1.5,
23773
23861
  textOffset: [0, 1.5],
23774
23862
  minzoom: 10,
@@ -23781,8 +23869,7 @@ function getLabelConfig(layerName, opts = {}) {
23781
23869
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23782
23870
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23783
23871
  textFont: NAV_AID_LABEL_FONT,
23784
- textColor: DARK_BG,
23785
- textHaloColor: navHalo("YELLOW", ct),
23872
+ ...onHalo("NAV_YELLOW", ct),
23786
23873
  textHaloWidth: 1.5,
23787
23874
  textOffset: [0, 1.5],
23788
23875
  minzoom: 10,
@@ -23795,8 +23882,7 @@ function getLabelConfig(layerName, opts = {}) {
23795
23882
  textField: ["coalesce", ["get", "_navAidLabel"], OBJNAM_TEXT],
23796
23883
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23797
23884
  textFont: NAV_AID_LABEL_FONT,
23798
- textColor: DARK_BG,
23799
- textHaloColor: navHalo("WHITE", ct),
23885
+ ...onHalo("NAV_WHITE", ct),
23800
23886
  textHaloWidth: 1.5,
23801
23887
  textOffset: [0, 1.5],
23802
23888
  minzoom: 10,
@@ -23808,8 +23894,7 @@ function getLabelConfig(layerName, opts = {}) {
23808
23894
  textField: ["get", "_lightLabel"],
23809
23895
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23810
23896
  textFont: NAV_AID_LABEL_FONT,
23811
- textColor: DARK_BG,
23812
- textHaloColor: navHalo("CREAM", ct),
23897
+ ...onHalo("NAV_CREAM", ct),
23813
23898
  textHaloWidth: 1.5,
23814
23899
  textOffset: [2, 0],
23815
23900
  minzoom: 9,
@@ -23833,8 +23918,7 @@ function getLabelConfig(layerName, opts = {}) {
23833
23918
  textField: catfogExpr,
23834
23919
  textSize: NAV_AID_LABEL_TEXT_SIZE,
23835
23920
  textFont: NAV_AID_LABEL_FONT,
23836
- textColor: DARK_BG,
23837
- textHaloColor: navHalo("BLUE", ct),
23921
+ ...onHalo("NAV_BLUE", ct),
23838
23922
  textHaloWidth: 1.5,
23839
23923
  textOffset: [2, 1.2],
23840
23924
  minzoom: 11,
@@ -23909,8 +23993,7 @@ function getLabelConfig(layerName, opts = {}) {
23909
23993
  [13, [0, 0, 13, 10, 11]],
23910
23994
  [16, [0, 0, 12, 11, 10]]
23911
23995
  ]),
23912
- textColor: DARK_BG,
23913
- textHaloColor: COLOR.WATER_DEEP,
23996
+ ...onHalo("WATER_DEEP", ct),
23914
23997
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23915
23998
  textOffset: [0, 0],
23916
23999
  textFont: ["Open Sans Italic"],
@@ -23980,8 +24063,7 @@ function getLabelConfig(layerName, opts = {}) {
23980
24063
  [13, [10, 11]],
23981
24064
  [16, [9, 10]]
23982
24065
  ]),
23983
- textColor: DARK_BG,
23984
- textHaloColor: COLOR.WATER,
24066
+ ...onHalo("WATER", ct),
23985
24067
  textHaloWidth: ORIENTATION_HALO_WIDTH,
23986
24068
  textOffset: [0, 0],
23987
24069
  textFont: ["Open Sans Italic"],
@@ -24001,8 +24083,7 @@ function getLabelConfig(layerName, opts = {}) {
24001
24083
  [13, [10, 10]],
24002
24084
  [16, [9, 10]]
24003
24085
  ]),
24004
- textColor: DARK_BG,
24005
- textHaloColor: COLOR.WATER,
24086
+ ...onHalo("WATER", ct),
24006
24087
  textHaloWidth: ORIENTATION_HALO_WIDTH,
24007
24088
  textOffset: [0, 0],
24008
24089
  textFont: ["Open Sans Italic"],
@@ -24025,8 +24106,7 @@ function getLabelConfig(layerName, opts = {}) {
24025
24106
  16,
24026
24107
  9
24027
24108
  ],
24028
- textColor: DARK_BG,
24029
- textHaloColor: COLOR.WATER,
24109
+ ...onHalo("WATER", ct),
24030
24110
  textHaloWidth: ORIENTATION_HALO_WIDTH,
24031
24111
  textOffset: [0, 0],
24032
24112
  textFont: ["Open Sans Italic"],
@@ -24055,8 +24135,7 @@ function getLabelConfig(layerName, opts = {}) {
24055
24135
  [13, [11.5, 11.5]],
24056
24136
  [16, [10.5, 11.5]]
24057
24137
  ]),
24058
- textColor: DARK_BG,
24059
- textHaloColor: COLOR.LAND_NATURAL,
24138
+ ...onHalo("LAND_NATURAL", ct),
24060
24139
  // Land halo, not the shared taper — see LAND_HALO_WIDTH.
24061
24140
  textHaloWidth: LAND_HALO_WIDTH,
24062
24141
  textOffset: [0, 0],
@@ -24079,8 +24158,7 @@ function getLabelConfig(layerName, opts = {}) {
24079
24158
  [13, [10, 11, 12]],
24080
24159
  [16, [10, 10, 11]]
24081
24160
  ]),
24082
- textColor: DARK_BG,
24083
- textHaloColor: COLOR.CITY,
24161
+ ...onHalo("CITY", ct),
24084
24162
  textHaloWidth: ORIENTATION_HALO_WIDTH,
24085
24163
  textOffset: [0, 0],
24086
24164
  textFont: ["Open Sans Regular"],
@@ -24095,8 +24173,7 @@ function getLabelConfig(layerName, opts = {}) {
24095
24173
  type: "symbol",
24096
24174
  textField: OBJNAM_TEXT,
24097
24175
  textSize: 9,
24098
- textColor: "#bfa88a",
24099
- textHaloColor: DARK_BG,
24176
+ ...onKnockout("STRUCTURE", ct),
24100
24177
  textHaloWidth: 1.5,
24101
24178
  textOffset: [0, 0],
24102
24179
  minzoom: 12,
@@ -24114,8 +24191,7 @@ function getLabelConfig(layerName, opts = {}) {
24114
24191
  type: "symbol",
24115
24192
  textField: OBJNAM_TEXT,
24116
24193
  textSize: 8,
24117
- textColor: "#c8c0b0",
24118
- textHaloColor: DARK_BG,
24194
+ ...onKnockout("STRUCTURE_LIGHT", ct),
24119
24195
  textHaloWidth: 1.2,
24120
24196
  textOffset: [0, 1.2],
24121
24197
  minzoom: 13
@@ -24125,8 +24201,7 @@ function getLabelConfig(layerName, opts = {}) {
24125
24201
  type: "symbol",
24126
24202
  textField: OBJNAM_TEXT,
24127
24203
  textSize: 8,
24128
- textColor: "#c8c0b0",
24129
- textHaloColor: DARK_BG,
24204
+ ...onKnockout("STRUCTURE_LIGHT", ct),
24130
24205
  textHaloWidth: 1.2,
24131
24206
  textOffset: [0, 1.2],
24132
24207
  minzoom: 13
@@ -24136,8 +24211,7 @@ function getLabelConfig(layerName, opts = {}) {
24136
24211
  type: "symbol",
24137
24212
  textField: OBJNAM_TEXT,
24138
24213
  textSize: 8,
24139
- textColor: "#bfa88a",
24140
- textHaloColor: DARK_BG,
24214
+ ...onKnockout("STRUCTURE", ct),
24141
24215
  textHaloWidth: 1.2,
24142
24216
  textOffset: [0, 1],
24143
24217
  minzoom: 13,
@@ -24151,8 +24225,7 @@ function getLabelConfig(layerName, opts = {}) {
24151
24225
  type: "symbol",
24152
24226
  textField: OBJNAM_TEXT,
24153
24227
  textSize: 8,
24154
- textColor: DARK_BG,
24155
- textHaloColor: "#c8c0b0",
24228
+ ...onHalo("STRUCTURE_LIGHT", ct),
24156
24229
  textHaloWidth: 1.2,
24157
24230
  textOffset: [0, 1.2],
24158
24231
  minzoom: 14,
@@ -24173,8 +24246,7 @@ function getLabelConfig(layerName, opts = {}) {
24173
24246
  [13, [10, 10]],
24174
24247
  [16, [9, 9]]
24175
24248
  ]),
24176
- textColor: DARK_BG,
24177
- textHaloColor: COLOR.AIRPORT,
24249
+ ...onHalo("AIRPORT", ct),
24178
24250
  textHaloWidth: ORIENTATION_HALO_WIDTH,
24179
24251
  textOffset: [0, 0],
24180
24252
  textFont: ["Open Sans Regular"],
@@ -24195,8 +24267,7 @@ function getLabelConfig(layerName, opts = {}) {
24195
24267
  16,
24196
24268
  11
24197
24269
  ],
24198
- textColor: DARK_BG,
24199
- textHaloColor: COLOR.SOUNDING,
24270
+ ...onHalo("SOUNDING", ct),
24200
24271
  textHaloWidth: 1,
24201
24272
  textOffset: [0, 0],
24202
24273
  textFont: ["Open Sans Italic"],
@@ -24230,8 +24301,7 @@ function getLabelConfig(layerName, opts = {}) {
24230
24301
  14,
24231
24302
  11
24232
24303
  ],
24233
- textColor: COLOR.SOUNDING,
24234
- textHaloColor: DARK_BG,
24304
+ ...onKnockout("SOUNDING", ct),
24235
24305
  textHaloWidth: 1,
24236
24306
  textOffset: [0, 0],
24237
24307
  textFont: ["Open Sans Italic"],
@@ -24261,8 +24331,7 @@ function getLabelConfig(layerName, opts = {}) {
24261
24331
  16,
24262
24332
  8
24263
24333
  ],
24264
- textColor: "#c545c3",
24265
- textHaloColor: DARK_BG,
24334
+ ...onKnockout("MAGENTA", ct),
24266
24335
  textHaloWidth: ORIENTATION_HALO_WIDTH,
24267
24336
  textOffset: [0, 0],
24268
24337
  textFont: ["Open Sans Italic"],
@@ -24282,8 +24351,7 @@ function getLabelConfig(layerName, opts = {}) {
24282
24351
  16,
24283
24352
  11
24284
24353
  ],
24285
- textColor: DARK_BG,
24286
- textHaloColor: "#3f8a34",
24354
+ ...onHalo("KELP", ct),
24287
24355
  textHaloWidth: 1,
24288
24356
  textOffset: [0, 0],
24289
24357
  textFont: ["Open Sans Italic"],
@@ -24375,8 +24443,7 @@ function getLabelConfig(layerName, opts = {}) {
24375
24443
  17,
24376
24444
  11
24377
24445
  ],
24378
- textColor: isCBL ? "#c545c3" : "#7fbf3f",
24379
- textHaloColor: DARK_BG,
24446
+ ...onKnockout(isCBL ? "MAGENTA" : "PIPELINE", ct),
24380
24447
  textHaloWidth: 1.4,
24381
24448
  textOffset: [0, 0],
24382
24449
  textFont: ["Open Sans Regular"],
@@ -24411,8 +24478,7 @@ function getLabelConfig(layerName, opts = {}) {
24411
24478
  14,
24412
24479
  10
24413
24480
  ],
24414
- textColor: DARK_BG,
24415
- textHaloColor: "#c8c8c8",
24481
+ ...onHalo("SOUNDING", ct),
24416
24482
  textHaloWidth: 1.2,
24417
24483
  textOffset: [0, 0],
24418
24484
  textFont: ["Open Sans Regular"],
@@ -24717,9 +24783,9 @@ var PLACENAME_LAND_SIZE_STOPS = [
24717
24783
  [13, [0, 0, 10, 11, 10, 11, 10, 10, 10, 10]],
24718
24784
  [16, [0, 0, 10, 10, 9, 10, 9, 9, 9, 9]]
24719
24785
  ];
24720
- function buildPlaceNameLayers(sourceId) {
24786
+ function buildPlaceNameLayers(sourceId, ct = "DAY") {
24721
24787
  const sortKey = ["to-number", ["coalesce", ["get", "rank"], 9999999]];
24722
- const make = (idSuffix, classes, font, haloColor, letterSpacing, stops) => ({
24788
+ const make = (idSuffix, classes, font, tint, letterSpacing, stops) => ({
24723
24789
  id: `chrt-placename-${idSuffix}`,
24724
24790
  type: "symbol",
24725
24791
  source: sourceId,
@@ -24747,8 +24813,8 @@ function buildPlaceNameLayers(sourceId) {
24747
24813
  "symbol-sort-key": sortKey
24748
24814
  },
24749
24815
  paint: {
24750
- "text-color": DARK_BG,
24751
- "text-halo-color": haloColor,
24816
+ "text-color": onHalo(tint, ct).textColor,
24817
+ "text-halo-color": onHalo(tint, ct).textHaloColor,
24752
24818
  "text-halo-width": ORIENTATION_HALO_WIDTH,
24753
24819
  "text-opacity": PLACENAME_TEXT_OPACITY
24754
24820
  },
@@ -24758,8 +24824,8 @@ function buildPlaceNameLayers(sourceId) {
24758
24824
  }
24759
24825
  });
24760
24826
  return [
24761
- make("water", PLACENAME_WATER_CLASSES, ["Open Sans Italic"], COLOR.WATER_DEEP, 0.05, PLACENAME_WATER_SIZE_STOPS),
24762
- make("land", PLACENAME_LAND_CLASSES, ["Open Sans Regular"], COLOR.LAND_REGION, 0.02, PLACENAME_LAND_SIZE_STOPS)
24827
+ make("water", PLACENAME_WATER_CLASSES, ["Open Sans Italic"], "WATER_DEEP", 0.05, PLACENAME_WATER_SIZE_STOPS),
24828
+ make("land", PLACENAME_LAND_CLASSES, ["Open Sans Regular"], "LAND_REGION", 0.02, PLACENAME_LAND_SIZE_STOPS)
24763
24829
  ];
24764
24830
  }
24765
24831
  var DRGNOTE_SOURCE_LAYER = "DRGNOTE";
@@ -27483,37 +27549,58 @@ var CHRT_ATON_COLORS = {
27483
27549
  // pink (magenta-ish)
27484
27550
  };
27485
27551
  var CHRT_UNKNOWN_TINT = "#8B9298";
27486
- function chrtAtonTintExpression() {
27552
+ var HOUSE_BLACK = "#101418";
27553
+ function chrtHouseColor(dayHex, palette = "DAY") {
27554
+ if (palette === "DAY") return dayHex;
27555
+ const isBlack = dayHex.toLowerCase() === HOUSE_BLACK.toLowerCase();
27556
+ if (palette === "DUSK") {
27557
+ return isBlack ? dayHex : capLuminance(dayHex, relativeLuminance(resolveColor("CHBLK", "DUSK")));
27558
+ }
27559
+ return isBlack ? NIGHT_INK : capLuminance(dayHex, relativeLuminance(NIGHT_MUTED_INK));
27560
+ }
27561
+ function themeChrtGlyph(svg3, palette = "DAY") {
27562
+ if (palette === "DAY") return svg3;
27563
+ return svg3.replace(
27564
+ /(fill|stroke)="(#[0-9a-fA-F]{3}|#[0-9a-fA-F]{6})"/g,
27565
+ (_m, attr, hex) => {
27566
+ const six = hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex;
27567
+ return `${attr}="${chrtHouseColor(six, palette)}"`;
27568
+ }
27569
+ );
27570
+ }
27571
+ function chrtAtonTintExpression(palette = "DAY") {
27572
+ const c = (code) => chrtHouseColor(CHRT_ATON_COLORS[code], palette);
27487
27573
  return colourCodeCase(
27488
27574
  [
27489
- ["3", CHRT_ATON_COLORS["3"]],
27490
- ["4", CHRT_ATON_COLORS["4"]],
27491
- ["6", CHRT_ATON_COLORS["6"]],
27492
- ["11", CHRT_ATON_COLORS["11"]],
27493
- ["9", CHRT_ATON_COLORS["9"]],
27494
- ["5", CHRT_ATON_COLORS["5"]],
27495
- ["1", CHRT_ATON_COLORS["1"]],
27496
- ["2", CHRT_ATON_COLORS["2"]],
27497
- ["8", CHRT_ATON_COLORS["8"]],
27498
- ["10", CHRT_ATON_COLORS["10"]],
27499
- ["12", CHRT_ATON_COLORS["12"]],
27500
- ["7", CHRT_ATON_COLORS["7"]]
27575
+ ["3", c("3")],
27576
+ ["4", c("4")],
27577
+ ["6", c("6")],
27578
+ ["11", c("11")],
27579
+ ["9", c("9")],
27580
+ ["5", c("5")],
27581
+ ["1", c("1")],
27582
+ ["2", c("2")],
27583
+ ["8", c("8")],
27584
+ ["10", c("10")],
27585
+ ["12", c("12")],
27586
+ ["7", c("7")]
27501
27587
  ],
27502
- CHRT_UNKNOWN_TINT
27588
+ chrtHouseColor(CHRT_UNKNOWN_TINT, palette)
27503
27589
  );
27504
27590
  }
27505
- function chrtLightTintExpression() {
27591
+ function chrtLightTintExpression(palette = "DAY") {
27592
+ const c = (code) => chrtHouseColor(CHRT_ATON_COLORS[code], palette);
27506
27593
  return colourCodeCase(
27507
27594
  [
27508
- ["3", CHRT_ATON_COLORS["3"]],
27509
- ["4", CHRT_ATON_COLORS["4"]],
27510
- ["6", CHRT_ATON_COLORS["6"]],
27511
- ["11", CHRT_ATON_COLORS["11"]],
27512
- ["9", CHRT_ATON_COLORS["9"]],
27513
- ["5", CHRT_ATON_COLORS["5"]],
27514
- ["1", CHRT_ATON_COLORS["1"]]
27595
+ ["3", c("3")],
27596
+ ["4", c("4")],
27597
+ ["6", c("6")],
27598
+ ["11", c("11")],
27599
+ ["9", c("9")],
27600
+ ["5", c("5")],
27601
+ ["1", c("1")]
27515
27602
  ],
27516
- CHRT_ATON_COLORS["1"]
27603
+ c("1")
27517
27604
  );
27518
27605
  }
27519
27606
  function scalar(attr) {
@@ -27615,7 +27702,7 @@ var TINTED_CLASSES = /* @__PURE__ */ new Set([
27615
27702
  "BCNSPP",
27616
27703
  "DAYMAR"
27617
27704
  ]);
27618
- var CHRT_HALO = { color: "#101418", width: 1 };
27705
+ var CHRT_HALO = { color: HOUSE_BLACK, width: 1 };
27619
27706
  var CHRT_LINE_DASH = {
27620
27707
  CBLSUB: { color: "CHMGD", width: 0.8, dash: [6, 3] },
27621
27708
  PIPSOL: { color: "PIPLN", width: 0.8, dash: [6, 3] }
@@ -27643,11 +27730,11 @@ function applyChrtSymbolSet(style, palette = "DAY") {
27643
27730
  layout["icon-image"] = CHRT_ICON_EXPRESSIONS[objectClass]();
27644
27731
  const paint = layer.paint ?? {};
27645
27732
  if (TINTED_CLASSES.has(objectClass)) {
27646
- paint["icon-color"] = chrtAtonTintExpression();
27733
+ paint["icon-color"] = chrtAtonTintExpression(palette);
27647
27734
  paint["icon-halo-color"] = CHRT_HALO.color;
27648
27735
  paint["icon-halo-width"] = CHRT_HALO.width;
27649
27736
  } else if (objectClass === "LIGHTS") {
27650
- paint["icon-color"] = chrtLightTintExpression();
27737
+ paint["icon-color"] = chrtLightTintExpression(palette);
27651
27738
  paint["icon-halo-color"] = CHRT_HALO.color;
27652
27739
  paint["icon-halo-width"] = CHRT_HALO.width;
27653
27740
  }
@@ -30799,7 +30886,7 @@ function generateStyle(palette = "DAY", opts = {}) {
30799
30886
  )
30800
30887
  );
30801
30888
  if (opts.labels === "placename") {
30802
- labelLayers.push(...buildPlaceNameLayers(sourceId));
30889
+ labelLayers.push(...buildPlaceNameLayers(sourceId, palette));
30803
30890
  }
30804
30891
  for (const { label } of chartLabelBundles) {
30805
30892
  if (bandFan === "collapsed") {
@@ -30889,7 +30976,7 @@ function generateStyle(palette = "DAY", opts = {}) {
30889
30976
  }
30890
30977
  }
30891
30978
  if (opts.labels === "placename") {
30892
- labelLayers.push(...buildPlaceNameLayers(sourceId));
30979
+ labelLayers.push(...buildPlaceNameLayers(sourceId, palette));
30893
30980
  } else {
30894
30981
  for (const { objectClass, label } of bundles) {
30895
30982
  if (!label) continue;
@@ -32062,6 +32149,8 @@ var Chrt = class {
32062
32149
  NAUTICAL_SYMBOLS,
32063
32150
  NAV_AID_LAYER_GROUPS,
32064
32151
  NAV_AID_QUERY_LAYERS,
32152
+ NIGHT_INK,
32153
+ NIGHT_MUTED_INK,
32065
32154
  NON_SOLAS_DISCLAIMER,
32066
32155
  NON_SOLAS_DISCLAIMER_SHORT,
32067
32156
  OfflineError,
@@ -32132,13 +32221,16 @@ var Chrt = class {
32132
32221
  buildSectorsFromFeatures,
32133
32222
  buildSources,
32134
32223
  candidateRank,
32224
+ capLuminance,
32135
32225
  cellBandCharacters,
32136
32226
  cellBandMatch,
32137
32227
  chrtAtonTintExpression,
32228
+ chrtHouseColor,
32138
32229
  chrtLightTintExpression,
32139
32230
  collectCandidates,
32140
32231
  collectClickCandidates,
32141
32232
  combineWithBandFilter,
32233
+ contrastRatio,
32142
32234
  daymarkColor,
32143
32235
  decimateFeatures,
32144
32236
  decodeAreaFeatureProps,
@@ -32210,6 +32302,7 @@ var Chrt = class {
32210
32302
  preprocessSoundings,
32211
32303
  preprocessWaterBodies,
32212
32304
  rasterAtonIconExpression,
32305
+ relativeLuminance,
32213
32306
  resolveColor,
32214
32307
  resolveCustomTheme,
32215
32308
  resolveRasterImage,
@@ -32219,11 +32312,13 @@ var Chrt = class {
32219
32312
  rhythmProperties,
32220
32313
  s101ArtworkProvenance,
32221
32314
  sanitizeCustomStyleConfig,
32315
+ scaleLinearLight,
32222
32316
  scaleSizeValue,
32223
32317
  scaminToMinZoom,
32224
32318
  sectorLimitToArcBearing,
32225
32319
  styleModeBand,
32226
32320
  terrainStackCount,
32321
+ themeChrtGlyph,
32227
32322
  tileTemplate,
32228
32323
  uncoveredSectorArcs,
32229
32324
  withinBboxFilter,