{
  "version": 3,
  "sources": ["route_point_card_core.js"],
  "sourcesContent": ["/*\n * static/js/route_point_card_core.js \u2014 the point card's pure half: the\n * words for one point on a saved route (SNOW-1064; headings since\n * SNOW-1069; the Track and Slope lines since SNOW-1094).\n *\n * The point header (templates/includes/_route_point_card.html) is the\n * route panel's header while a point is placed. It holds the aspect wheel\n * (aspect_wheel_core.js) and two lines of words, labelled Skier's track\n * and Terrain slope in the partial (Track and Slope until 2026-10-19), and this module is where the words come from\n * (docs/decisions/the-point-card-names-the-experience.md).\n *\n * ## The Skier's track line: heading \u00B7 kind \u00B7 band\n *\n * \"NW \u2192 W \u00B7 Descent \u00B7 5\u201315\u00B0\". The heading, the kind and the track's band\n * of degrees, joined by the strings' `join` and `with-band` (templates,\n * because the strings reader trims, so a bare \" \u00B7 \" would lose its\n * spaces):\n *\n *   HEADING    \u2014 the compass point the segment heads in, or the first and\n *                last steps' points joined by an arrow where it turns:\n *                the inner ring's own sectors (`headingSectors`), so the\n *                words name exactly what the ring lights (SNOW-1069).\n *   KIND       \u2014 ascent, descent, traverse or fall line (`kindOf`). Up or\n *                down is the wheel's centre mark, not a word, so the kind\n *                names only how the track lies on the slope. A track with\n *                no kind is level, and reads \"Level\" alone.\n *   BAND       \u2014 the range of the track's step on its own scale\n *                (`trackBand`), never the measured gradient. Level under\n *                5\u00B0, then by direction: descending, 5 / 15 / 25 / 35\u00B0;\n *                climbing, 5 / 10 / 15 / 20\u00B0, because skin tracks live\n *                under 20\u00B0. The bounds are the aspect wheel's\n *                `TRACK_BOUNDS`, so the inner ring's colour, the chevrons\n *                and the band always name the same step.\n *\n * The track carried a word for its step until the usability review\n * (2026-10-19): gentle, moderate, steep, very steep. They were the Slope\n * line's EAWS words on other bounds, so \"Moderate\" over \"Moderate\" named\n * two ranges and \"Steep fall line\" could sit over a \"Moderate\" slope. The\n * band says the step without borrowing a word. `trackWord` still names\n * the steps, for the level test and the wheel's tests.\n *\n * How the track lies on the slope (`headline`) compares its chord with the\n * way the ground falls \u2014 the segment's aspect, its downhill direction. d\n * is the angle between the two, 0\u00B0 straight down the fall line and 180\u00B0\n * straight up it: under 45\u00B0 or over 135\u00B0 is the fall line, anything\n * between a traverse. A gradient that disagrees with the heading \u2014 climbing\n * within 45\u00B0 of downhill \u2014 has turned inside the segment, and reads as the\n * plain ascent or descent.\n *\n * ## Turns: the segment's two ends (SNOW-1069, SNOW-1094)\n *\n * One chord cannot say that a segment turned, and on a skin track the\n * kick turns are 50 m apart: a 25 m segment often holds one. A segment\n * whose first and last steps head into different compass sectors \u2014 the\n * ring lighting two sectors, adjoining or not \u2014 turned. A wobble that\n * stays inside one sector (359\u00B0 to 1\u00B0) did not.\n *\n * A turning segment has no kind of its own (SNOW-1094). The two compass\n * points already say it turned, and the Slope line's \"left, then right\"\n * already says it crossed the fall line, so \"turn\" and \"switchback\"\n * repeated the card. It is the FALL LINE where it descends with either\n * end in the ground's own sector, otherwise an ASCENT or DESCENT by its\n * gradient's sign; a level turn has no kind.\n *\n * Its chord says nothing reliable about the side the ground falls \u2014 a\n * bend's chord can point down the slope while both ends traverse it \u2014 so\n * the Slope line takes the side from the two ends (`turnOf`): one side\n * where they agree, \"left, then right\" where they differ. Reading the\n * chord's side left one bend near Les Tsamos with a side on one route\n * and none on another, because the two routes split it into segments\n * with different chords. The sides need an aspect, which is ground of 5\u00B0\n * or more.\n *\n * THE ASPECT IS A SECTOR. The slope wire sends one of eight sectors per\n * segment (SNOW-976), not a bearing, so the aspect here is the sector's\n * centre and d carries up to 22.5\u00B0 of that rounding. The 45\u00B0 and 135\u00B0\n * edges, and where a turn crosses the fall line, are a reading of a 25 m\n * segment's character, not a survey, and the error is the same one the\n * wheel's outer ring draws.\n *\n * ## The Terrain slope line: the ground, in the EAWS words\n *\n * `groundWord` is the EAWS glossary's slope classes \u2014 moderate under 30\u00B0,\n * steep from 30\u00B0, very steep from 35\u00B0, extremely steep from 40\u00B0 \u2014 with\n * flat under 5\u00B0 added below them, the rule rail two's readout used. The\n * label says \"Slope\", so the words do not: \"Steep\", not \"Steep slope\".\n * The class's band follows it, \"Steep \u00B7 30\u201335\u00B0\" (`groundBand`), as the\n * track's follows its kind, so the two scales read side by side. A\n * traverse adds the side the ground falls away to, and a turning segment\n * its ends' side or sides, except on the fall line itself.\n *\n * ## The accessible name\n *\n * The wheel's label is both lines with their labels, \"Skier's track: \u2026;\n * Terrain slope: \u2026\", read rather than drawn: the heading's arrow is \"to\"\n * (`label-heading-pair`), the parts are joined by `label-join`, and a band\n * is \"30 to 35 degrees\" (`label-band-*`), so a screen reader never says\n * \"right arrow\", \"dot\" or \"en dash\".\n *\n * ## The gradient\n *\n * `segmentGradients` is the signed gradient along the track at each\n * segment: rise over run across the segment's own 25 m (SNOW-1145; one\n * stride either side of its midpoint before), read off the heights rail\n * one's profile draws \u2014 the terrain model's since SNOW-1043. A segment\n * never reaches past its own ends, so the first segment down from a col\n * is not averaged with the climb behind it. It moved here\n * from rail two with SNOW-1064, the gradient's only reader once rail two\n * went (SNOW-1065).\n *\n * No user-facing literal lives here: `reading` takes a strings object\n * read from the partial's `<template>` through `window.pwaStrings`, so\n * i18n-lint has nothing to find. Every function is pure; `reading` reads\n * `self.pwaAspectWheelCore` at call time for the wheel's state, and\n * `boundaryDistances` `self.pwaElevationProfileCore.haversineM` for the\n * profile's own distance.\n *\n * Exports (frozen `self.pwaRoutePointCardCore`):\n *\n *   TRACK_BOUNDS                    \u2014 the track scale's upper bounds, {climb, descent}\n *   FALL_LINE_DEG                   \u2014 within this of the fall line, 45\n *   trackWord(gradient)             \u2014 the track's step, by direction, or null\n *   trackBand(gradient)             \u2014 that step's {low, high} degrees, or null\n *   groundWord(angle)               \u2014 the ground's EAWS class, or null\n *   groundBand(angle)               \u2014 that class's {low, high} degrees, or null\n *   angleBetween(a, b)              \u2014 two bearings' separation, 0 to 180\n *   headingDeg(path)                \u2014 a segment path's bearing, first to last\n *   fallSide(heading, aspect)       \u2014 'left' or 'right', the way the ground falls\n *   headline(heading, aspect, gradient, angle) \u2014 {key, steepness, side}\n *   turnOf(path, aspect)            \u2014 the sides the ground falls at both ends\n *   kindOf(head, gradient, track, fall) \u2014 the Track line's kind, or null\n *   boundaryDistances(slope, coordinates) \u2014 each boundary's distance on the\n *                                     profile, or null\n *   segmentGradients(profile, sampleCount, boundaries?) \u2014 signed, per segment\n *   reading(input, strings)         \u2014 the card's words and the wheel's state\n */\n\n// @ts-check\n\n(function () {\n  'use strict';\n\n  /**\n   * The track scale's exclusive upper bounds, in degrees of absolute\n   * gradient: level, gentle, steady, stiff; very stiff has none. A climb\n   * has its own, because skin tracks live under 20\u00B0. A copy of the aspect\n   * wheel's `TRACK_BOUNDS`, which a test holds equal, so this module's\n   * words need no wheel to read.\n   */\n  const TRACK_BOUNDS = Object.freeze({\n    climb: Object.freeze([5, 10, 15, 20]),\n    descent: Object.freeze([5, 15, 25, 35]),\n  });\n\n  /** The track scale's step names, one more than the bounds. */\n  const TRACK_WORDS = Object.freeze(['level', 'gentle', 'steady', 'stiff', 'very-stiff']);\n\n  /** Within this many degrees of the fall line, the track is on it. */\n  const FALL_LINE_DEG = 45;\n\n  /** Ground under this is flat, and faces nowhere: the server's rule. */\n  const FLAT_GROUND_DEG = 5;\n\n  /** The EAWS slope-class edges above flat: steep, very, extremely. */\n  const GROUND_STEEP_DEG = 30;\n  const VERY_STEEP_DEG = 35;\n  const EXTREMELY_STEEP_DEG = 40;\n\n  /** The ground's class edges, one fewer than `GROUND_WORDS`. */\n  const GROUND_BOUNDS = Object.freeze([FLAT_GROUND_DEG, GROUND_STEEP_DEG, VERY_STEEP_DEG, EXTREMELY_STEEP_DEG]);\n\n  /** The ground's classes, flat first. */\n  const GROUND_WORDS = Object.freeze(['flat', 'moderate', 'steep', 'very-steep', 'extremely-steep']);\n\n  /** Tolerance for comparing distances along the profile. */\n  const EPSILON = 1e-6;\n\n  /**\n   * A headline: which pattern, the track's step to fill it with, and on\n   * a traverse the side the ground falls away to.\n   *\n   * @typedef {{key: string, steepness: ?string, side: ?string}} Headline\n   */\n\n  /**\n   * A finite number, or null.\n   *\n   * @param {*} value A candidate.\n   * @returns {?number} The number, or null.\n   */\n  function finite(value) {\n    return typeof value === 'number' && Number.isFinite(value) ? value : null;\n  }\n\n  /**\n   * Clamp a number into a closed range.\n   *\n   * @param {number} value The number.\n   * @param {number} low The lowest value allowed.\n   * @param {number} high The highest value allowed.\n   * @returns {number} The clamped value.\n   */\n  function clamp(value, low, high) {\n    return Math.min(high, Math.max(low, value));\n  }\n\n  /**\n   * The bounds a signed gradient is read on: the climb's where it rises,\n   * the descent's otherwise.\n   *\n   * @param {number} gradient Degrees, signed.\n   * @returns {ReadonlyArray<number>} The upper bounds.\n   */\n  function trackBounds(gradient) {\n    return gradient > 0 ? TRACK_BOUNDS.climb : TRACK_BOUNDS.descent;\n  }\n\n  /**\n   * A value's step on a scale of exclusive upper bounds.\n   *\n   * @param {number} value The value, already absolute.\n   * @param {ReadonlyArray<number>} bounds The upper bounds.\n   * @returns {number} 0 to `bounds.length`.\n   */\n  function stepOf(value, bounds) {\n    const step = bounds.findIndex((bound) => value < bound);\n    return step === -1 ? bounds.length : step;\n  }\n\n  /**\n   * The track's step on its own scale, read by direction.\n   *\n   * @param {*} gradient Degrees, signed: positive climbs.\n   * @returns {?string} 'level', 'gentle', 'steady', 'stiff' or\n   *   'very-stiff'; null for an unknown gradient.\n   */\n  function trackWord(gradient) {\n    const value = finite(gradient);\n    if (value === null) return null;\n    return TRACK_WORDS[stepOf(Math.abs(value), trackBounds(value))];\n  }\n\n  /**\n   * A step's band of degrees: its lower and upper bounds, either null\n   * where the scale is open at that end.\n   *\n   * @typedef {{low: ?number, high: ?number}} Band\n   */\n\n  /**\n   * The band of degrees the track's step covers (2026-10-19).\n   *\n   * The step's range, not the measured gradient, so the band can never\n   * disagree with the word or the ring's colour.\n   *\n   * @param {*} gradient Degrees, signed: positive climbs.\n   * @returns {?Band} Null for an unknown gradient.\n   */\n  function trackBand(gradient) {\n    const value = finite(gradient);\n    if (value === null) return null;\n    const bounds = trackBounds(value);\n    const step = stepOf(Math.abs(value), bounds);\n    return { low: step > 0 ? bounds[step - 1] : null, high: step < bounds.length ? bounds[step] : null };\n  }\n\n  /**\n   * The band of degrees the ground's EAWS class covers (2026-10-19).\n   *\n   * @param {*} angle The slope angle, degrees.\n   * @returns {?Band} Null for an unknown angle.\n   */\n  function groundBand(angle) {\n    const value = finite(angle);\n    if (value === null) return null;\n    const step = stepOf(value, GROUND_BOUNDS);\n    return {\n      low: step > 0 ? GROUND_BOUNDS[step - 1] : null,\n      high: step < GROUND_BOUNDS.length ? GROUND_BOUNDS[step] : null,\n    };\n  }\n\n  /**\n   * The ground's class, in the EAWS glossary's words.\n   *\n   *   < 5\u00B0 'flat' \u00B7 < 30\u00B0 'moderate' \u00B7 < 35\u00B0 'steep' \u00B7 < 40\u00B0 'very-steep'\n   *   \u00B7 40\u00B0 and more 'extremely-steep'.\n   *\n   * @param {*} angle The slope angle, degrees.\n   * @returns {?string} Null for an unknown angle.\n   */\n  function groundWord(angle) {\n    const value = finite(angle);\n    if (value === null) return null;\n    return GROUND_WORDS[stepOf(value, GROUND_BOUNDS)];\n  }\n\n  /**\n   * The separation of two compass bearings.\n   *\n   * @param {number} a A bearing, degrees.\n   * @param {number} b Another.\n   * @returns {number} 0 to 180.\n   */\n  function angleBetween(a, b) {\n    return Math.abs(((((a - b) % 360) + 540) % 360) - 180);\n  }\n\n  /**\n   * A segment path's bearing, from its first point to its last.\n   *\n   * The chord, not one step: how the track lies on the slope describes the\n   * 25 m segment as a whole. Its two ends are `turnOf`'s.\n   *\n   * @param {*} path The segment's `[lon, lat]` path.\n   * @returns {?number} The bearing, or null with no length.\n   */\n  function headingDeg(path) {\n    const wheel = self.pwaAspectWheelCore;\n    if (!wheel || !Array.isArray(path)) return null;\n    const points = path.filter((p) => Array.isArray(p) && finite(p[0]) !== null && finite(p[1]) !== null);\n    if (points.length < 2) return null;\n    const a = points[0];\n    const b = points[points.length - 1];\n    if (a[0] === b[0] && a[1] === b[1]) return null;\n    return wheel.bearingDeg(a, b);\n  }\n\n  /**\n   * Which side of the skier the ground falls away to.\n   *\n   * The aspect's signed turn from the heading: clockwise (east of a\n   * northward track) is the skier's right.\n   *\n   * @param {number} heading The track's bearing, degrees.\n   * @param {number} aspect The way the ground falls, degrees.\n   * @returns {string} 'right' or 'left'; 'right' straight ahead or behind,\n   *   which a traverse never is.\n   */\n  function fallSide(heading, aspect) {\n    const turn = ((((aspect - heading) % 360) + 540) % 360) - 180;\n    return turn >= 0 ? 'right' : 'left';\n  }\n\n  /**\n   * The headline for one point: the track's step and how it crosses the\n   * slope.\n   *\n   * @param {?number} heading The track's bearing, degrees; null with none.\n   * @param {?number} aspect The way the ground falls, degrees; null where\n   *   it faces nowhere (under 5\u00B0) or is unknown.\n   * @param {?number} gradient The track's signed gradient, degrees.\n   * @param {?number} angle The ground's angle, degrees.\n   * @returns {Headline} `key` names the pattern; `steepness` the track's\n   *   step, null for a pattern that carries none; `side` the way the\n   *   ground falls on a traverse, null otherwise.\n   */\n  function headline(heading, aspect, gradient, angle) {\n    const grade = finite(gradient);\n    if (grade === null) return { key: 'no-height', steepness: null, side: null };\n    const steepness = trackWord(grade);\n    const level = steepness === 'level';\n    const ground = finite(angle);\n    const crossing = finite(heading) !== null && finite(aspect) !== null\n      && ground !== null && ground >= FLAT_GROUND_DEG;\n    if (!crossing) {\n      if (level) return { key: 'level', steepness: null, side: null };\n      return { key: grade > 0 ? 'climb' : 'descent', steepness: steepness, side: null };\n    }\n    const h = /** @type {number} */ (heading);\n    const a = /** @type {number} */ (aspect);\n    if (level) return { key: 'level-traverse', steepness: null, side: fallSide(h, a) };\n    const d = angleBetween(h, a);\n    const down = d < FALL_LINE_DEG;\n    const up = d > 180 - FALL_LINE_DEG;\n    if ((down && grade > 0) || (up && grade < 0)) {\n      return { key: grade > 0 ? 'climb-turning' : 'descent-turning', steepness: steepness, side: null };\n    }\n    if (down) return { key: 'fall-descent', steepness: steepness, side: null };\n    if (up) return { key: 'fall-climb', steepness: steepness, side: null };\n    return {\n      key: grade > 0 ? 'rising-traverse' : 'descending-traverse',\n      steepness: steepness,\n      side: fallSide(h, a),\n    };\n  }\n\n  /**\n   * The side the ground falls at a segment's first step and at its last.\n   *\n   * @typedef {{firstSide: string, lastSide: string}} Turn\n   */\n\n  /**\n   * The bearings of a path's steps, in order, skipping any step with no\n   * length.\n   *\n   * @param {*} path The segment's `[lon, lat]` path, unchecked.\n   * @returns {Array<number>} One bearing per step that has a length.\n   */\n  function stepBearings(path) {\n    const wheel = self.pwaAspectWheelCore;\n    if (!wheel || !Array.isArray(path)) return [];\n    const points = path.filter((p) => Array.isArray(p) && finite(p[0]) !== null && finite(p[1]) !== null);\n    /** @type {Array<number>} */\n    const out = [];\n    for (let i = 0; i < points.length - 1; i += 1) {\n      const a = points[i];\n      const b = points[i + 1];\n      if (a[0] === b[0] && a[1] === b[1]) continue;\n      out.push(wheel.bearingDeg(a, b));\n    }\n    return out;\n  }\n\n  /**\n   * The side the ground falls at each end of a segment (SNOW-1069).\n   *\n   * Where the two differ on a segment that turned, the track crossed the\n   * fall line. On its own a difference proves nothing: a track along the\n   * fall line that wobbles 2\u00B0 either side of it differs too, which is why\n   * the Slope line asks for two heading sectors as well.\n   *\n   * @param {*} path The segment's `[lon, lat]` path.\n   * @param {?number} aspect The way the ground falls, degrees; null where\n   *   it faces nowhere or is unknown.\n   * @returns {?Turn} Null with no aspect or no step with a length.\n   */\n  function turnOf(path, aspect) {\n    const fall = finite(aspect);\n    const bearings = stepBearings(path);\n    if (fall === null || !bearings.length) return null;\n    return {\n      firstSide: fallSide(bearings[0], fall),\n      lastSide: fallSide(bearings[bearings.length - 1], fall),\n    };\n  }\n\n  /**\n   * The headline's kind: how the track lies on the slope.\n   *\n   * A segment that heads into one sector is named by its chord's pattern.\n   * One that heads into two turned, and is named by its gradient rather\n   * than its chord (SNOW-1094): descending with either end in the\n   * ground's own sector it is the fall line, otherwise an ascent or a\n   * descent by the gradient's sign.\n   *\n   * @param {Headline} head `headline`'s reading of the chord.\n   * @param {?number} gradient The track's signed gradient, degrees.\n   * @param {Array<number>} track The heading sectors the ring lights.\n   * @param {?number} fall The sector the ground falls towards; null where\n   *   it faces nowhere or is unknown.\n   * @returns {?string} 'ascent', 'descent', 'traverse' or 'fall-line';\n   *   null for a level track that turned or crosses no slope, or no\n   *   height.\n   */\n  function kindOf(head, gradient, track, fall) {\n    const grade = finite(gradient);\n    if (grade === null || head.key === 'no-height') return null;\n    if (Array.isArray(track) && track.length > 1) {\n      if (trackWord(grade) === 'level') return null;\n      if (grade < 0 && fall !== null && track.includes(fall)) return 'fall-line';\n      return grade > 0 ? 'ascent' : 'descent';\n    }\n    switch (head.key) {\n      case 'fall-descent':\n      case 'fall-climb':\n        return 'fall-line';\n      case 'rising-traverse':\n      case 'descending-traverse':\n      case 'level-traverse':\n        return 'traverse';\n      case 'climb':\n      case 'climb-turning':\n        return 'ascent';\n      case 'descent':\n      case 'descent-turning':\n        return 'descent';\n      default:\n        return null;\n    }\n  }\n\n  /**\n   * The index of the profile run holding a distance, or -1 when the\n   * distance falls in a gap or off either end.\n   *\n   * @param {Array<Array<{d: number, e: number}>>} runs The profile's runs.\n   * @param {number} d A distance along the profile.\n   * @returns {number} The run's index, or -1.\n   */\n  function runAt(runs, d) {\n    for (let r = 0; r < runs.length; r += 1) {\n      const run = runs[r];\n      if (run.length && d >= run[0].d - EPSILON && d <= run[run.length - 1].d + EPSILON) {\n        return r;\n      }\n    }\n    return -1;\n  }\n\n  /**\n   * A profile's height at a distance, linear between its points; null\n   * outside every run.\n   *\n   * @param {Array<Array<{d: number, e: number}>>} runs The profile's runs.\n   * @param {number} d A distance along the profile.\n   * @returns {?number} The height, metres.\n   */\n  function heightAt(runs, d) {\n    const r = runAt(runs, d);\n    if (r < 0) return null;\n    const run = runs[r];\n    if (run.length === 1) return run[0].e;\n    let lo = 0;\n    let hi = run.length - 1;\n    while (hi - lo > 1) {\n      const mid = (lo + hi) >> 1;\n      if (run[mid].d <= d) lo = mid;\n      else hi = mid;\n    }\n    const a = run[lo];\n    const b = run[hi];\n    const gap = b.d - a.d;\n    return gap > 0 ? a.e + (b.e - a.e) * clamp((d - a.d) / gap, 0, 1) : a.e;\n  }\n\n  /**\n   * Where each segment boundary lies on the profile's distance axis.\n   *\n   * The sampler cuts the track every 25 m and folds the remainder into\n   * the last segment, so boundaries are not equal shares of the route: a\n   * 110 m track is cut at 0, 25, 50, 75 and 110 m. Each boundary is\n   * placed by its `seams` entry, the last coordinate at or before it,\n   * plus the step from that coordinate to the boundary point, measured as\n   * `readProfile` measures (haversine, skipping unusable coordinates), so\n   * the distances are on the axis the profile's heights are read from.\n   *\n   * @param {*} slope The route's slope record: `points` and `seams`.\n   * @param {*} coordinates The feature's `geometry.coordinates`.\n   * @returns {?Array<number>} N + 1 non-decreasing distances, metres; null\n   *   without valid `seams`, coordinates, or the profile core.\n   */\n  function boundaryDistances(slope, coordinates) {\n    const profileCore = self.pwaElevationProfileCore;\n    if (!profileCore || typeof profileCore.haversineM !== 'function') return null;\n    const points = slope && slope.points;\n    const seams = slope && slope.seams;\n    if (!Array.isArray(points) || !Array.isArray(seams) || !Array.isArray(coordinates)) return null;\n    if (points.length < 2 || seams.length !== points.length) return null;\n    /** @param {*} p @returns {boolean} */\n    const usable = (p) => Array.isArray(p) && p.length >= 2\n      && typeof p[0] === 'number' && typeof p[1] === 'number';\n    /** @type {Array<?number>} */\n    const along = [];\n    let distance = 0;\n    /** @type {?Array<number>} */\n    let previous = null;\n    for (let c = 0; c < coordinates.length; c += 1) {\n      const p = coordinates[c];\n      if (!usable(p)) {\n        along.push(null);\n        continue;\n      }\n      if (previous) distance += profileCore.haversineM(previous[0], previous[1], p[0], p[1]);\n      previous = [p[0], p[1]];\n      along.push(distance);\n    }\n    /** @type {Array<number>} */\n    const out = [];\n    for (let i = 0; i < seams.length; i += 1) {\n      const seam = seams[i];\n      const point = points[i];\n      if (!Number.isInteger(seam) || seam < 0 || seam >= coordinates.length) return null;\n      const base = along[seam];\n      if (base === null || !usable(point)) return null;\n      const from = coordinates[seam];\n      const d = base + profileCore.haversineM(from[0], from[1], point[0], point[1]);\n      out.push(Math.min(distance, Math.max(i ? out[i - 1] : 0, d)));\n    }\n    return out;\n  }\n\n  /**\n   * The signed gradient along the track at each segment, in degrees:\n   * positive where the track rises in its own direction (SNOW-1044).\n   *\n   * Rise over run across the segment itself (SNOW-1145): between the\n   * heights at its two ends, read off `readProfile`'s runs. The ends are\n   * the sampler's own boundaries where `boundaries` places them\n   * (`boundaryDistances`); without, equal shares of the profile, as rail\n   * one places a segment. Until SNOW-1145 the window was one stride\n   * either side of the middle, 50 m, twice the 25 m the colour, the\n   * heading and the map's cursor describe; now every line of the card\n   * reads the same segment. A window that never leaves its own\n   * segment never leaves its own leg either, so the legs no longer clip\n   * it. A segment spanning an elevation gap is no reading: the gap is\n   * kept as a gap rather than interpolated across.\n   *\n   * @param {?{runs: Array<Array<{d: number, e: number}>>, distanceM: number,\n   *   hasElevation: boolean}} profile A `readProfile` result.\n   * @param {number} sampleCount N, the length of `slope.angles`.\n   * @param {?Array<number>} [boundaries] N + 1 distances on the profile,\n   *   from `boundaryDistances`; ignored unless there are exactly N + 1.\n   * @returns {Array<?number>} N entries, null where a height is missing.\n   */\n  function segmentGradients(profile, sampleCount, boundaries) {\n    const count = sampleCount > 0 ? Math.floor(sampleCount) : 0;\n    /** @type {Array<?number>} */\n    const out = new Array(count).fill(null);\n    if (!profile || !profile.hasElevation || !(profile.distanceM > 0) || !count) return out;\n    const distanceM = profile.distanceM;\n    const placed = Array.isArray(boundaries) && boundaries.length === count + 1\n      && boundaries.every((d) => Number.isFinite(d));\n    for (let i = 0; i < count; i += 1) {\n      const a = placed && boundaries ? boundaries[i] : (i / count) * distanceM;\n      const b = placed && boundaries ? boundaries[i + 1] : ((i + 1) / count) * distanceM;\n      if (!(b - a > EPSILON)) continue;\n      const run = runAt(profile.runs, a);\n      if (run < 0 || run !== runAt(profile.runs, b)) continue;\n      const ea = heightAt(profile.runs, a);\n      const eb = heightAt(profile.runs, b);\n      if (ea === null || eb === null) continue;\n      out[i] = (Math.atan((eb - ea) / (b - a)) * 180) / Math.PI;\n    }\n    return out;\n  }\n\n  /**\n   * A strings value with its placeholders filled.\n   *\n   * @param {Object<string, string>} strings The strings object.\n   * @param {string} key The key.\n   * @param {Object<string, string>} [values] The placeholders.\n   * @returns {string} The text; the key itself when the strings lack it.\n   */\n  function fill(strings, key, values) {\n    const template = strings[key] === undefined ? key : strings[key];\n    const vars = values || {};\n    return String(template).replace(/%\\((\\w+)\\)s/g, (match, name) => (\n      Object.prototype.hasOwnProperty.call(vars, name) ? vars[name] : match\n    ));\n  }\n\n  /**\n   * The heading in words: one compass point, or the first and last\n   * joined.\n   *\n   * @param {*} track The wheel's heading sectors.\n   * @param {Object<string, string>} strings The strings object.\n   * @param {string} pairKey `heading-pair` to draw, `label-heading-pair`\n   *   to read aloud.\n   * @returns {string} The heading; empty with none.\n   */\n  function headingWords(track, strings, pairKey) {\n    if (!Array.isArray(track) || !track.length) return '';\n    const names = track.map((s) => fill(strings, `compass-${s}`));\n    if (names.length === 1) return names[0];\n    return fill(strings, pairKey, { first: names[0], second: names[names.length - 1] });\n  }\n\n  /**\n   * A text with its band of degrees after it, drawn and spoken.\n   *\n   * @param {string} text The word or phrase.\n   * @param {?Band} band The band; none adds nothing.\n   * @param {Object<string, string>} strings The strings object.\n   * @returns {{drawn: string, spoken: string}} \"Steep \u00B7 30\u201335\u00B0\", and\n   *   \"Steep, 30 to 35 degrees\" to read aloud.\n   */\n  function withBand(text, band, strings) {\n    if (!band) return { drawn: text, spoken: text };\n    let shape = 'range';\n    if (band.low === null) shape = 'under';\n    else if (band.high === null) shape = 'over';\n    const values = { low: String(band.low), high: String(band.high) };\n    return {\n      drawn: fill(strings, 'with-band', { text: text, band: fill(strings, `band-${shape}`, values) }),\n      spoken: fill(strings, 'label-with-band', { text: text, band: fill(strings, `label-band-${shape}`, values) }),\n    };\n  }\n\n  /**\n   * The card's words for one point, and the wheel's state for it.\n   *\n   * @param {{index: number, paths: *, gradients: *, angles: *,\n   *   aspects?: *}} input The point's segment and the route's arrays:\n   *   `paths` from `segmentPaths`, `gradients` from `segmentGradients`,\n   *   `angles` and `aspects` from the slope record.\n   * @param {Object<string, string>} strings The strings object, read from\n   *   the partial's `<template>`.\n   * @returns {{headline: string, ground: string, label: string,\n   *   kind: ?string, state: *}} `headline` is the Track line and `ground`\n   *   the Slope line; `label` is the wheel's accessible name, both lines\n   *   with their labels as read aloud; `kind` the Track line's kind, or\n   *   null.\n   */\n  function reading(input, strings) {\n    const wheel = self.pwaAspectWheelCore;\n    const state = wheel ? wheel.wheelState(input) : null;\n    const index = input.index;\n    const paths = Array.isArray(input.paths) ? input.paths : [];\n    const angle = Array.isArray(input.angles) ? finite(input.angles[index]) : null;\n    const terrain = state ? state.terrain : { kind: 'none' };\n    // Flat ground has no sector, so the sides need ground of 5\u00B0 or more.\n    const aspect = terrain && terrain.kind === 'faces' ? terrain.sector * 45 : null;\n    const gradient = Array.isArray(input.gradients) ? finite(input.gradients[index]) : null;\n    const head = headline(headingDeg(paths[index]), aspect, gradient, angle);\n    const turn = turnOf(paths[index], aspect);\n    const track = state ? state.track : [];\n    const kind = kindOf(head, gradient, track, aspect === null ? null : terrain.sector);\n\n    // The kind and the step's band, \"Descent \u00B7 15\u201325\u00B0\"\n    // (2026-10-19: the band replaced the step's word). A track with no\n    // kind is level, and says so in a word: its band adds nothing.\n    let phrase = { drawn: fill(strings, 'headline-no-height'), spoken: fill(strings, 'headline-no-height') };\n    if (gradient !== null) {\n      phrase = kind\n        ? withBand(fill(strings, `kind-${kind}`), trackBand(gradient), strings)\n        : { drawn: fill(strings, 'headline-level'), spoken: fill(strings, 'headline-level') };\n    }\n    const drawn = [headingWords(track, strings, 'heading-pair'), phrase.drawn].filter(Boolean);\n    const spoken = [headingWords(track, strings, 'label-heading-pair'), phrase.spoken].filter(Boolean);\n    const join = (/** @type {Array<string>} */ parts, /** @type {string} */ key) => parts\n      .reduce((before, after) => fill(strings, key, { before: before, after: after }));\n    const headlineText = join(drawn, 'join');\n    const headlineSpoken = join(spoken, 'label-join');\n\n    // A payload cached before SNOW-976 carries no `aspects`, and the wheel\n    // draws it as unknown; the words agree rather than claim flat ground.\n    const groundKey = terrain && (terrain.kind === 'unknown' || terrain.kind === 'none')\n      ? null\n      : groundWord(angle);\n    const slope = groundKey === null\n      ? withBand(fill(strings, 'ground-unknown'), null, strings)\n      : withBand(fill(strings, `ground-${groundKey}`), groundBand(angle), strings);\n    // A side needs ground that faces somewhere; the guard keeps an\n    // unknown reading from claiming one. The fall line names none.\n    let fallKey = null;\n    if (groundKey !== null && groundKey !== 'flat' && kind !== 'fall-line') {\n      if (Array.isArray(track) && track.length > 1) {\n        // A turning segment's side is its two ends', never its chord's.\n        if (turn && turn.firstSide === turn.lastSide) {\n          fallKey = `ground-falling-${turn.firstSide}`;\n        } else if (turn) {\n          fallKey = `ground-falling-${turn.firstSide}-then-${turn.lastSide}`;\n        }\n      } else if (head.side) {\n        fallKey = `ground-falling-${head.side}`;\n      }\n    }\n    const groundText = fallKey ? fill(strings, fallKey, { ground: slope.drawn }) : slope.drawn;\n    const groundSpoken = fallKey ? fill(strings, fallKey, { ground: slope.spoken }) : slope.spoken;\n    return {\n      headline: headlineText,\n      ground: groundText,\n      label: fill(strings, 'label', { headline: headlineSpoken, ground: groundSpoken }),\n      kind: kind,\n      state: state,\n    };\n  }\n\n  self.pwaRoutePointCardCore = Object.freeze({\n    TRACK_BOUNDS: TRACK_BOUNDS,\n    FALL_LINE_DEG: FALL_LINE_DEG,\n    trackWord: trackWord,\n    trackBand: trackBand,\n    groundWord: groundWord,\n    groundBand: groundBand,\n    angleBetween: angleBetween,\n    headingDeg: headingDeg,\n    fallSide: fallSide,\n    headline: headline,\n    turnOf: turnOf,\n    kindOf: kindOf,\n    boundaryDistances: boundaryDistances,\n    segmentGradients: segmentGradients,\n    reading: reading,\n  });\n})();\n"],
  "mappings": "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",
  "names": ["TRACK_BOUNDS", "TRACK_WORDS", "FALL_LINE_DEG", "FLAT_GROUND_DEG", "GROUND_BOUNDS", "GROUND_WORDS", "EPSILON", "finite", "value", "clamp", "low", "high", "trackBounds", "gradient", "stepOf", "bounds", "step", "bound", "trackWord", "trackBand", "groundBand", "angle", "groundWord", "angleBetween", "a", "b", "headingDeg", "path", "wheel", "points", "p", "fallSide", "heading", "aspect", "headline", "grade", "steepness", "level", "ground", "h", "d", "down", "up", "stepBearings", "out", "i", "turnOf", "fall", "bearings", "kindOf", "head", "track", "runAt", "runs", "r", "run", "heightAt", "lo", "hi", "mid", "gap", "boundaryDistances", "slope", "coordinates", "profileCore", "seams", "usable", "along", "distance", "previous", "c", "seam", "point", "base", "from", "segmentGradients", "profile", "sampleCount", "boundaries", "count", "distanceM", "placed", "ea", "eb", "fill", "strings", "key", "values", "template", "vars", "match", "name", "headingWords", "pairKey", "names", "s", "withBand", "text", "band", "shape", "reading", "input", "state", "index", "paths", "terrain", "turn", "kind", "phrase", "drawn", "spoken", "join", "parts", "before", "after", "headlineText", "headlineSpoken", "groundKey", "fallKey", "groundText", "groundSpoken"]
}
