@aparte/plugin-cards 0.0.0-stage → 0.29.0

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.
Files changed (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -2
  3. package/dist/carousel-CPy-0JGN.js +63 -0
  4. package/dist/carousel-CPy-0JGN.js.map +1 -0
  5. package/dist/controls-BVX2u7sK.js +62 -0
  6. package/dist/controls-BVX2u7sK.js.map +1 -0
  7. package/dist/format-CchcJRum.js +720 -0
  8. package/dist/format-CchcJRum.js.map +1 -0
  9. package/dist/index.d.ts +28 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +35 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/items/icons.d.ts +12 -0
  14. package/dist/items/icons.d.ts.map +1 -0
  15. package/dist/items/index.d.ts +100 -0
  16. package/dist/items/index.d.ts.map +1 -0
  17. package/dist/items.js +698 -0
  18. package/dist/items.js.map +1 -0
  19. package/dist/kit/carousel.d.ts +17 -0
  20. package/dist/kit/carousel.d.ts.map +1 -0
  21. package/dist/kit/controls.d.ts +51 -0
  22. package/dist/kit/controls.d.ts.map +1 -0
  23. package/dist/kit/define.d.ts +194 -0
  24. package/dist/kit/define.d.ts.map +1 -0
  25. package/dist/kit/dom.d.ts +40 -0
  26. package/dist/kit/dom.d.ts.map +1 -0
  27. package/dist/kit/format.d.ts +49 -0
  28. package/dist/kit/format.d.ts.map +1 -0
  29. package/dist/kit/rating.d.ts +19 -0
  30. package/dist/kit/rating.d.ts.map +1 -0
  31. package/dist/kit/sparkline.d.ts +19 -0
  32. package/dist/kit/sparkline.d.ts.map +1 -0
  33. package/dist/kit/strings.d.ts +139 -0
  34. package/dist/kit/strings.d.ts.map +1 -0
  35. package/dist/link/icons.d.ts +16 -0
  36. package/dist/link/icons.d.ts.map +1 -0
  37. package/dist/link/index.d.ts +98 -0
  38. package/dist/link/index.d.ts.map +1 -0
  39. package/dist/link.js +387 -0
  40. package/dist/link.js.map +1 -0
  41. package/dist/media/icons.d.ts +28 -0
  42. package/dist/media/icons.d.ts.map +1 -0
  43. package/dist/media/index.d.ts +107 -0
  44. package/dist/media/index.d.ts.map +1 -0
  45. package/dist/media.js +610 -0
  46. package/dist/media.js.map +1 -0
  47. package/dist/order/icons.d.ts +49 -0
  48. package/dist/order/icons.d.ts.map +1 -0
  49. package/dist/order/index.d.ts +204 -0
  50. package/dist/order/index.d.ts.map +1 -0
  51. package/dist/order.js +1843 -0
  52. package/dist/order.js.map +1 -0
  53. package/dist/place/icons.d.ts +18 -0
  54. package/dist/place/icons.d.ts.map +1 -0
  55. package/dist/place/index.d.ts +207 -0
  56. package/dist/place/index.d.ts.map +1 -0
  57. package/dist/place.js +1456 -0
  58. package/dist/place.js.map +1 -0
  59. package/dist/plan/icons.d.ts +25 -0
  60. package/dist/plan/icons.d.ts.map +1 -0
  61. package/dist/plan/index.d.ts +153 -0
  62. package/dist/plan/index.d.ts.map +1 -0
  63. package/dist/plan.js +1191 -0
  64. package/dist/plan.js.map +1 -0
  65. package/dist/product/icons.d.ts +16 -0
  66. package/dist/product/icons.d.ts.map +1 -0
  67. package/dist/product/index.d.ts +133 -0
  68. package/dist/product/index.d.ts.map +1 -0
  69. package/dist/product.js +1245 -0
  70. package/dist/product.js.map +1 -0
  71. package/dist/rating-B8Mdx_b_.js +35 -0
  72. package/dist/rating-B8Mdx_b_.js.map +1 -0
  73. package/dist/score/icons.d.ts +35 -0
  74. package/dist/score/icons.d.ts.map +1 -0
  75. package/dist/score/index.d.ts +185 -0
  76. package/dist/score/index.d.ts.map +1 -0
  77. package/dist/score.js +1843 -0
  78. package/dist/score.js.map +1 -0
  79. package/dist/sparkline-C-cA9obz.js +56 -0
  80. package/dist/sparkline-C-cA9obz.js.map +1 -0
  81. package/dist/stats/icons.d.ts +19 -0
  82. package/dist/stats/icons.d.ts.map +1 -0
  83. package/dist/stats/index.d.ts +137 -0
  84. package/dist/stats/index.d.ts.map +1 -0
  85. package/dist/stats.js +1085 -0
  86. package/dist/stats.js.map +1 -0
  87. package/dist/stock/chart.d.ts +135 -0
  88. package/dist/stock/chart.d.ts.map +1 -0
  89. package/dist/stock/icons.d.ts +15 -0
  90. package/dist/stock/icons.d.ts.map +1 -0
  91. package/dist/stock/index.d.ts +195 -0
  92. package/dist/stock/index.d.ts.map +1 -0
  93. package/dist/stock.js +1013 -0
  94. package/dist/stock.js.map +1 -0
  95. package/dist/weather/conditions.d.ts +25 -0
  96. package/dist/weather/conditions.d.ts.map +1 -0
  97. package/dist/weather/icons.d.ts +12 -0
  98. package/dist/weather/icons.d.ts.map +1 -0
  99. package/dist/weather/index.d.ts +146 -0
  100. package/dist/weather/index.d.ts.map +1 -0
  101. package/dist/weather.js +1162 -0
  102. package/dist/weather.js.map +1 -0
  103. package/package.json +137 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stock.js","sources":["../src/stock/chart.ts","../src/stock/icons.ts","../src/stock/stock.css?raw","../src/stock/index.ts"],"sourcesContent":["/**\n * The stock card's charts: a price line, and candlesticks.\n *\n * **The line**: an area under the series, split at a baseline into the part above it (the\n * \"up\" colour) and the part below (the \"down\" colour), the last point marked, the high and\n * the low written where they happen. Why two clip paths rather than two areas: an area cut\n * at the baseline needs the exact crossing points of every segment that crosses it, which\n * is arithmetic per segment and a polygon per run. Clipping the SAME path twice, once to\n * the band above the baseline and once to the band below, splits it exactly where the line\n * crosses, for any series, with two rectangles. The strokes are split the same way, so the\n * line changes colour at the crossing too.\n *\n * **The candles**: a body from the open to the close, a wick from the low to the high, the\n * volume as faint bars along the bottom. A rising candle is HOLLOW and a falling one FILLED\n * (the classic convention), and that is a choice for the reader, not for the look: a filled\n * body alone does not say which end is the open, so its colour would be the only telling.\n * Hollow-or-filled says it without colour. Every body of a kind is one path, every wick of\n * a kind another: eighty candles are a handful of nodes, not four hundred.\n *\n * Both are SVG built with `createElementNS` from numbers only, so a tool's values never\n * reach a parser, stretched to the card's width (`preserveAspectRatio=\"none\"`, the strokes\n * kept at their width by `vector-effect`). That would squash anything round, so the dot,\n * the dashed baseline, the cursor and the labels are HTML laid over the SVG, placed in\n * percent of the same box.\n *\n * Time runs left to right in every script, as it does on the market's own charts: the\n * plot is `dir=\"ltr\"`, the text around it follows the page.\n */\nimport type { CardContext } from '../kit/define.js';\nimport { el } from '../kit/dom.js';\nimport { word, type CardWord } from '../kit/strings.js';\n\n/** What the plot is called where a screen reader would say \"application\". */\nconst CHART_ROLE: CardWord = { en: 'chart', fr: 'graphique', de: 'Diagramm', es: 'gráfico', it: 'grafico', ja: 'チャート', ko: '차트', pt: 'gráfico', ru: 'график', zh: '图表' };\n\nconst SVG = 'http://www.w3.org/2000/svg';\n\n/** One point of a series: its value, and when it was, when the tool said. */\nexport interface ChartPoint {\n value: number;\n time?: Date;\n}\n\n/** One candle: a stretch of time's first, highest, lowest and last price. */\nexport interface Candle {\n time?: Date;\n open: number;\n high: number;\n low: number;\n close: number;\n volume?: number;\n}\n\nexport interface ChartGeometry {\n /** The line, in a 100 × 100 box. */\n line: string;\n /** The area between the line and the baseline. */\n area: string;\n points: Array<[number, number]>;\n /** The baseline's height in the box. */\n baseY: number;\n /** Where the highest and the lowest values are (their first occurrence). */\n hi: number;\n lo: number;\n}\n\n/** Room above the highest point and under the lowest, as a share of the height: the labels sit there. */\nconst PAD = 0.2;\n\n/**\n * The chart's shape for `values` against `baseline`, or `null` under two points. The\n * baseline is inside the scale, so it is always on the chart; a series that does not\n * move is a flat line through the middle.\n */\nexport function chartGeometry(values: number[], baseline: number): ChartGeometry | null {\n if (values.length < 2) return null;\n let hi = 0;\n let lo = 0;\n values.forEach((v, i) => {\n if (v > values[hi]!) hi = i;\n if (v < values[lo]!) lo = i;\n });\n const top = Math.max(values[hi]!, baseline);\n const bottom = Math.min(values[lo]!, baseline);\n const span = top - bottom;\n const y = (v: number) => (span === 0 ? 50 : 100 - (PAD * 100 + ((v - bottom) / span) * (100 - 2 * PAD * 100)));\n const step = 100 / (values.length - 1);\n const points = values.map((v, i): [number, number] => [i * step, y(v)]);\n const at = (p: [number, number]) => `${p[0].toFixed(2)} ${p[1].toFixed(2)}`;\n const line = `M${points.map(at).join(' L')}`;\n const baseY = y(baseline);\n const area = `${line} L100 ${baseY.toFixed(2)} L0 ${baseY.toFixed(2)} Z`;\n return { line, area, points, baseY, hi, lo };\n}\n\n/**\n * At most `max` points, keeping each stretch's lowest and highest: a day of minutes\n * (390 points) or a year of hours is more than a card's width can show, and a plain\n * stride would drop the very high and low the labels name. The first and the last\n * point always stay.\n */\nexport function thin<T extends ChartPoint>(points: T[], max = 240): T[] {\n if (points.length <= max) return points;\n const buckets = Math.max(1, Math.floor(max / 2) - 1);\n const size = points.length / buckets;\n const out: T[] = [points[0]!];\n for (let b = 0; b < buckets; b++) {\n const slice = points.slice(Math.floor(b * size), Math.floor((b + 1) * size));\n if (!slice.length) continue;\n let low = slice[0]!;\n let high = slice[0]!;\n for (const p of slice) {\n if (p.value < low.value) low = p;\n if (p.value > high.value) high = p;\n }\n for (const p of slice.indexOf(low) <= slice.indexOf(high) ? [low, high] : [high, low]) {\n if (out[out.length - 1] !== p) out.push(p);\n }\n }\n const last = points[points.length - 1]!;\n if (out[out.length - 1] !== last) out.push(last);\n return out;\n}\n\n/**\n * At most `max` candles, by merging neighbours into wider ones — the way a chart moves\n * from hourly to daily candles — rather than dropping any: a merged candle opens with the\n * first, closes with the last, and keeps the highest high, the lowest low and the summed\n * volume, so nothing that happened leaves the chart. Its time is the first one's.\n */\nexport function groupCandles(candles: Candle[], max = 80): Candle[] {\n if (candles.length <= max) return candles;\n const size = Math.ceil(candles.length / max);\n const out: Candle[] = [];\n for (let i = 0; i < candles.length; i += size) {\n const group = candles.slice(i, i + size);\n const first = group[0]!;\n const volumes = group.map((c) => c.volume).filter((v): v is number => v !== undefined);\n out.push({\n ...(first.time ? { time: first.time } : {}),\n open: first.open,\n close: group[group.length - 1]!.close,\n high: Math.max(...group.map((c) => c.high)),\n low: Math.min(...group.map((c) => c.low)),\n ...(volumes.length ? { volume: volumes.reduce((a, b) => a + b, 0) } : {}),\n });\n }\n return out;\n}\n\n/** One candle's place in the 100 × 100 box. */\nexport interface CandleShape {\n /** The centre of its slot, and its body's width. */\n x: number;\n width: number;\n /** The body's top and bottom, the wick's ends, the close. */\n top: number;\n bottom: number;\n high: number;\n low: number;\n close: number;\n direction: 'up' | 'down' | 'flat';\n /** Its volume bar's height, from the bottom of the box. */\n volume: number;\n}\n\nexport interface CandleGeometry {\n shapes: CandleShape[];\n /** The candles with the highest high and the lowest low. */\n hi: number;\n lo: number;\n /** Whether a volume band is drawn along the bottom. */\n volume: boolean;\n}\n\n/** The band the volume bars take at the bottom, when there are any. */\nconst VOLUME_BAND = 16;\n\n/**\n * The candles' shapes, or `null` with none. The prices take the box above the volume\n * band, with the same room above and below as the line for the labels.\n */\nexport function candleGeometry(candles: Candle[]): CandleGeometry | null {\n if (candles.length === 0) return null;\n let hi = 0;\n let lo = 0;\n candles.forEach((c, i) => {\n if (c.high > candles[hi]!.high) hi = i;\n if (c.low < candles[lo]!.low) lo = i;\n });\n const maxVolume = Math.max(0, ...candles.map((c) => c.volume ?? 0));\n const floor = maxVolume > 0 ? 100 - VOLUME_BAND : 100;\n const pad = PAD * 80;\n const top = candles[hi]!.high;\n const bottom = candles[lo]!.low;\n const span = top - bottom;\n const y = (v: number) => (span === 0 ? floor / 2 : floor - pad - ((v - bottom) / span) * (floor - 2 * pad));\n const slot = 100 / candles.length;\n const shapes = candles.map((c, i): CandleShape => {\n const open = y(c.open);\n const close = y(c.close);\n return {\n x: (i + 0.5) * slot,\n width: slot * 0.62,\n top: Math.min(open, close),\n bottom: Math.max(open, close),\n high: y(c.high),\n low: y(c.low),\n close,\n direction: c.close > c.open ? 'up' : c.close < c.open ? 'down' : 'flat',\n volume: maxVolume > 0 ? ((c.volume ?? 0) / maxVolume) * (VOLUME_BAND - 2) : 0,\n };\n });\n return { shapes, hi, lo, volume: maxVolume > 0 };\n}\n\nlet serial = 0;\n\nfunction svgNode<K extends keyof SVGElementTagNameMap>(tag: K, attrs: Record<string, string | number>): SVGElementTagNameMap[K] {\n const node = document.createElementNS(SVG, tag);\n for (const [name, value] of Object.entries(attrs)) node.setAttribute(name, String(value));\n return node;\n}\n\nfunction stretchedSvg(): SVGSVGElement {\n const svg = svgNode('svg', { viewBox: '0 0 100 100', preserveAspectRatio: 'none', 'aria-hidden': 'true', focusable: 'false' });\n svg.setAttribute('class', 'aparte-stock__svg');\n return svg;\n}\n\n/** A spot laid over the plot at a point, in percent of its box. */\nfunction place(node: HTMLElement, x: number, y: number): void {\n node.style.setProperty('--aparte-stock-x', `${x.toFixed(2)}%`);\n node.style.setProperty('--aparte-stock-y', `${y.toFixed(2)}%`);\n}\n\n/** Where a label sits against its point, so one at an edge stays inside the card. */\nconst alignOf = (x: number) => (x < 14 ? 'start' : x > 86 ? 'end' : 'center');\n\n/** The high or the low, written where it happened. */\nfunction extreme(ctx: CardContext, kind: 'hi' | 'lo', x: number, y: number, text: () => string): HTMLElement {\n const label = el('span', { class: `aparte-stock__extreme aparte-stock__extreme--${kind}`, attrs: { 'aria-hidden': 'true', 'data-align': alignOf(x) } });\n place(label, x, y);\n ctx.bind(label, text);\n return label;\n}\n\n/** What a chart's frame needs from its drawing. */\ninterface FrameOptions {\n kind: 'line' | 'candles';\n svg: SVGSVGElement;\n /** Laid over the SVG, under the cursor. */\n under: Array<HTMLElement | null>;\n /** Laid over the cursor (the last point's dot). */\n over?: HTMLElement[];\n count: number;\n /** The point a share of the width falls on. */\n indexAt(ratio: number): number;\n /** Where the cursor sits on point `i`. */\n at(i: number): [number, number];\n /** What point `i` reads as: shown in the line, and said in full. */\n readout(i: number): { shown: string; spoken: string };\n label(): string;\n info?: Node[];\n}\n\n/**\n * A chart's frame: the plot, then a line under it with the range and the legend. Hovering,\n * touching or arrowing through the focused plot puts a cursor on a point and writes it in\n * that line, which is a polite live region — the short form shown, the full one said.\n */\nfunction frame(ctx: CardContext, options: FrameOptions): HTMLElement {\n const cursor = el('span', { class: 'aparte-stock__cursor', attrs: { 'aria-hidden': 'true' } });\n const cursorDot = el('span', { class: 'aparte-stock__cursor-dot', attrs: { 'aria-hidden': 'true' } });\n // Not `img`: an image takes no keys, so a screen reader in browse mode keeps the arrows\n // for itself and the cursor never moves. Not `slider` either: its value would be a point's\n // index, and the readout below already says each point. `application` is the role whose\n // contract is \"the keys are this element's\" — safe here because everything inside is\n // `aria-hidden` (there is nothing to browse), and named a \"chart\" so that is what is said.\n const plot = el('div', { class: 'aparte-stock__plot', attrs: { tabindex: 0, role: 'application', dir: 'ltr', 'data-kind': options.kind } },\n options.svg, ...options.under, cursor, cursorDot, ...(options.over ?? []));\n ctx.bind(plot, options.label, 'aria-label');\n ctx.bind(plot, () => word(ctx.config, 'cardsStockChartRole', CHART_ROLE), 'aria-roledescription');\n\n const shown = el('span', { class: 'aparte-stock__readout-shown', attrs: { 'aria-hidden': 'true' } });\n const spoken = el('span', { class: 'aparte-sr-only' });\n const readout = el('span', { class: 'aparte-stock__readout', attrs: { 'aria-live': 'polite', 'aria-atomic': 'true' } }, shown, spoken);\n const info = el('div', { class: 'aparte-stock__chart-info' }, ...(options.info ?? []));\n const root = el('div', { class: 'aparte-stock__chart' }, plot, el('div', { class: 'aparte-stock__chart-foot' }, readout, info));\n\n const last = options.count - 1;\n let current = -1;\n // A cursor put there by the keyboard stays when the mouse wanders off; one put there\n // by the mouse goes with it, even though the click focused the plot.\n let byKeyboard = false;\n function show(index: number): void {\n current = Math.max(0, Math.min(last, index));\n const [x, y] = options.at(current);\n place(cursor, x, y);\n place(cursorDot, x, y);\n root.setAttribute('data-scrub', '');\n const text = options.readout(current);\n shown.textContent = text.shown;\n spoken.textContent = text.spoken;\n }\n function hide(): void {\n current = -1;\n root.removeAttribute('data-scrub');\n shown.textContent = '';\n spoken.textContent = '';\n }\n const fromPointer = (event: PointerEvent) => {\n const box = plot.getBoundingClientRect();\n if (!box.width) return;\n show(options.indexAt(Math.max(0, Math.min(1, (event.clientX - box.left) / box.width))));\n };\n plot.addEventListener('pointermove', fromPointer);\n plot.addEventListener('pointerdown', (event) => {\n byKeyboard = false;\n fromPointer(event);\n });\n // A touch the browser takes over to scroll the page (`touch-action: pan-y`) is cancelled.\n plot.addEventListener('pointerleave', () => { if (!byKeyboard || document.activeElement !== plot) hide(); });\n plot.addEventListener('pointercancel', hide);\n plot.addEventListener('focus', () => {\n if (current >= 0) return;\n byKeyboard = true;\n show(last);\n });\n plot.addEventListener('blur', hide);\n plot.addEventListener('keydown', (event) => {\n const page = Math.max(1, Math.round(options.count / 10));\n const from = current < 0 ? last : current;\n const moves: Record<string, number> = {\n ArrowLeft: from - (event.shiftKey ? page : 1),\n ArrowRight: from + (event.shiftKey ? page : 1),\n PageUp: from - page,\n PageDown: from + page,\n Home: 0,\n End: last,\n };\n if (event.key === 'Escape') {\n hide();\n return;\n }\n const to = moves[event.key];\n if (to === undefined) return;\n event.preventDefault();\n byKeyboard = true;\n show(to);\n });\n return root;\n}\n\nexport interface PriceChartOptions {\n points: ChartPoint[];\n /** The value the chart is split at: the previous close, or where the series started. */\n baseline: number;\n /** A value as text, in the quote's currency and precision. */\n value(v: number): string;\n /** A point's time as text. */\n time(d: Date): string;\n /** The plot's accessible name: what the chart shows, in a sentence. */\n label(): string;\n /** The market is open: the last point pulses. */\n live?: boolean;\n /** What sits under the plot (the range, the baseline's legend); the readout takes its place while the chart is explored. */\n info?: Node[];\n}\n\n/** The line chart, or `null` under two points. */\nexport function priceChart(ctx: CardContext, options: PriceChartOptions): HTMLElement | null {\n const shown = thin(options.points);\n const geometry = chartGeometry(shown.map((p) => p.value), options.baseline);\n if (!geometry) return null;\n const { points, baseY } = geometry;\n\n const id = `aparte-stock-${++serial}`;\n const svg = stretchedSvg();\n const band = (name: string, y: number, height: number) => {\n const clip = svgNode('clipPath', { id: `${id}-${name}`, clipPathUnits: 'userSpaceOnUse' });\n clip.append(svgNode('rect', { x: -5, y: y.toFixed(2), width: 110, height: Math.max(0, height).toFixed(2) }));\n return clip;\n };\n // The fill fades towards the baseline in both directions: strongest at the line.\n const gradient = (name: 'up' | 'down', from: number, to: number) => {\n const g = svgNode('linearGradient', { id: `${id}-fill-${name}`, gradientUnits: 'userSpaceOnUse', x1: 0, x2: 0, y1: from.toFixed(2), y2: to.toFixed(2) });\n const stop = (offset: number, opacity: number) => {\n const s = svgNode('stop', { offset, 'stop-opacity': opacity });\n s.setAttribute('class', name === 'up' ? 'aparte-stock__stop aparte-stock__stop--up' : 'aparte-stock__stop aparte-stock__stop--down');\n return s;\n };\n g.append(stop(0, name === 'up' ? 0.3 : 0.02), stop(1, name === 'up' ? 0.02 : 0.3));\n return g;\n };\n const defs = svgNode('defs', {});\n defs.append(\n band('up', -10, baseY + 10),\n band('down', baseY, 110 - baseY),\n gradient('up', Math.min(...points.map((p) => p[1])), baseY),\n gradient('down', baseY, Math.max(...points.map((p) => p[1]))),\n );\n const area = (name: 'up' | 'down') => {\n const path = svgNode('path', { d: geometry.area, fill: `url(#${id}-fill-${name})`, 'clip-path': `url(#${id}-${name})` });\n path.setAttribute('class', name === 'up' ? 'aparte-stock__area aparte-stock__area--up' : 'aparte-stock__area aparte-stock__area--down');\n return path;\n };\n const stroke = (name: 'up' | 'down') => {\n const path = svgNode('path', { d: geometry.line, 'clip-path': `url(#${id}-${name})`, 'vector-effect': 'non-scaling-stroke' });\n path.setAttribute('class', name === 'up' ? 'aparte-stock__line aparte-stock__line--up' : 'aparte-stock__line aparte-stock__line--down');\n return path;\n };\n svg.append(defs, area('up'), area('down'), stroke('up'), stroke('down'));\n\n const baseline = el('span', { class: 'aparte-stock__baseline', attrs: { 'aria-hidden': 'true' } });\n place(baseline, 0, baseY);\n // The dot takes the colour of the side of the baseline it ends on — over a year that\n // can be the other way from the day's change, which the pill above says.\n const end = shown[shown.length - 1]!.value;\n const side = end > options.baseline ? 'up' : end < options.baseline ? 'down' : 'flat';\n const dot = el('span', { class: 'aparte-stock__dot', attrs: { 'aria-hidden': 'true', 'data-live': options.live === true, 'data-direction': side } });\n const lastPoint = points[points.length - 1]!;\n place(dot, lastPoint[0], lastPoint[1]);\n // The high and the low are not both written when the series does not move.\n const flat = shown[geometry.hi]!.value === shown[geometry.lo]!.value;\n const mark = (kind: 'hi' | 'lo', i: number) => extreme(ctx, kind, points[i]![0], points[i]![1], () => options.value(shown[i]!.value));\n\n return frame(ctx, {\n kind: 'line',\n svg,\n under: [baseline, flat ? null : mark('hi', geometry.hi), flat ? null : mark('lo', geometry.lo)],\n over: [dot],\n count: points.length,\n indexAt: (ratio) => Math.round(ratio * (points.length - 1)),\n at: (i) => points[i]!,\n readout: (i) => {\n const p = shown[i]!;\n const text = p.time ? `${options.value(p.value)} · ${options.time(p.time)}` : options.value(p.value);\n return { shown: text, spoken: text };\n },\n label: options.label,\n info: options.info ?? [],\n });\n}\n\nexport interface CandleChartOptions {\n candles: Candle[];\n value(v: number): string;\n time(d: Date): string;\n /** A candle under the cursor: the short line shown (\"O 1 H 2 L 0 C 1\"), and the sentence said. */\n ohlc(c: Candle): { shown: string; spoken: string };\n label(): string;\n info?: Node[];\n}\n\n/** The candlestick chart, or `null` without a candle. */\nexport function candleChart(ctx: CardContext, options: CandleChartOptions): HTMLElement | null {\n const candles = groupCandles(options.candles);\n const geometry = candleGeometry(candles);\n if (!geometry) return null;\n const { shapes } = geometry;\n\n const svg = stretchedSvg();\n const paths: Record<string, string> = {};\n const add = (key: string, d: string) => { paths[key] = (paths[key] ?? '') + d; };\n const n = (v: number) => v.toFixed(2);\n for (const s of shapes) {\n const x0 = s.x - s.width / 2;\n const x1 = s.x + s.width / 2;\n // A body that did not move still shows, as a line about a pixel high.\n const bottom = Math.max(s.bottom, s.top + 0.8);\n add(`body-${s.direction}`, `M${n(x0)} ${n(s.top)}H${n(x1)}V${n(bottom)}H${n(x0)}Z`);\n // The wick stops at the body: a hollow candle stays hollow.\n add(`wick-${s.direction}`, `M${n(s.x)} ${n(s.high)}V${n(s.top)}M${n(s.x)} ${n(bottom)}V${n(s.low)}`);\n if (s.volume > 0) add(`volume-${s.direction}`, `M${n(x0)} 100H${n(x1)}V${n(100 - s.volume)}H${n(x0)}Z`);\n }\n for (const kind of ['volume', 'wick', 'body'] as const) {\n for (const direction of ['up', 'down', 'flat'] as const) {\n const d = paths[`${kind}-${direction}`];\n if (!d) continue;\n const path = svgNode('path', { d, 'vector-effect': 'non-scaling-stroke' });\n const name = `aparte-stock__${kind}`;\n path.setAttribute('class', [name, `${name}--${direction}`].join(' '));\n svg.append(path);\n }\n }\n const flat = candles[geometry.hi]!.high === candles[geometry.lo]!.low;\n const hi = shapes[geometry.hi]!;\n const lo = shapes[geometry.lo]!;\n return frame(ctx, {\n kind: 'candles',\n svg,\n under: [\n flat ? null : extreme(ctx, 'hi', hi.x, hi.high, () => options.value(candles[geometry.hi]!.high)),\n flat ? null : extreme(ctx, 'lo', lo.x, lo.low, () => options.value(candles[geometry.lo]!.low)),\n ],\n count: shapes.length,\n indexAt: (ratio) => Math.min(shapes.length - 1, Math.floor(ratio * shapes.length)),\n at: (i) => [shapes[i]!.x, shapes[i]!.close],\n readout: (i) => {\n const c = candles[i]!;\n const text = options.ohlc(c);\n const when = c.time ? ` · ${options.time(c.time)}` : '';\n return { shown: `${text.shown}${when}`, spoken: `${text.spoken}${when}` };\n },\n label: options.label,\n info: options.info ?? [],\n });\n}\n","/**\n * The stock card's glyphs: the arrows beside a change, and the card's own glyph for its\n * one-line states.\n *\n * Constants of this package — the only markup the card parses. The arrows are filled in\n * `currentColor`, so the change's colour reaches them through `color`; the sign written\n * beside them says the same thing in text, so neither the colour nor the arrow is alone.\n */\n\n/** A small filled triangle, pointing up. */\nexport const UP = '<svg viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"currentColor\" d=\"M6 2.2l4.3 6.6H1.7z\"/></svg>';\n\n/** The same, pointing down. */\nexport const DOWN = '<svg viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"currentColor\" d=\"M6 9.8L1.7 3.2h8.6z\"/></svg>';\n\n/** A rising line over an axis: the card's glyph when it has nothing to draw. */\nexport const CHART = '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M3.5 4v15.5h17\"/><path d=\"M6.5 15l4-4.5 3 2.5 5.5-6.5\"/><path d=\"M15.8 6.5h3.2v3.2\"/></svg>';\n","export default \"/* =========================================\\n The stock card — @aparte/plugin-cards/stock\\n =========================================\\n Four variants of one card, chosen by `data-variant` on its root:\\n chart one quote at length: the symbol, the price and its change, the chart\\n against the previous close, the day's figures and the 52-week range.\\n Several quotes in `chart` are rows, as in `compact`.\\n compact a row per quote — symbol and name, sparkline, price, change.\\n ticker a strip of quotes that scrolls sideways, by hand: nothing moves on its own.\\n candles the chart card with candlesticks in place of the line (the line when the\\n quote has no candles).\\n Up and down are `--aparte-stock-up` / `--aparte-stock-down` (the theme's success and\\n error by default): a market that writes a rise in red swaps the two. A change always\\n carries its sign and an arrow too, so the colour is never the only telling.\\n */\\n\\n.aparte-stock-card {\\n --aparte-stock-up: var(--aparte-success);\\n --aparte-stock-down: var(--aparte-error);\\n --aparte-stock-flat: var(--aparte-text-muted);\\n /* The colours as text on the card: mixed toward the ink, like the theme's own `-ink`\\n tokens, and derived from the two above so a swap carries over to the text. */\\n --aparte-stock-up-ink: color-mix(in oklab, var(--aparte-stock-up) 40%, var(--aparte-text));\\n --aparte-stock-down-ink: color-mix(in oklab, var(--aparte-stock-down) 40%, var(--aparte-text));\\n --aparte-stock-chart-height: 8.5rem;\\n --aparte-stock-price-size: calc(var(--aparte-font-size-2xl) * 1.3);\\n --aparte-stock-tone: var(--aparte-stock-flat);\\n --aparte-stock-tone-ink: var(--aparte-text-muted);\\n}\\n\\n.aparte-stock-card [data-direction=\\\"up\\\"] {\\n --aparte-stock-tone: var(--aparte-stock-up);\\n --aparte-stock-tone-ink: var(--aparte-stock-up-ink);\\n}\\n\\n.aparte-stock-card [data-direction=\\\"down\\\"] {\\n --aparte-stock-tone: var(--aparte-stock-down);\\n --aparte-stock-tone-ink: var(--aparte-stock-down-ink);\\n}\\n\\n.aparte-stock-card [data-direction=\\\"flat\\\"] {\\n --aparte-stock-tone: var(--aparte-stock-flat);\\n --aparte-stock-tone-ink: var(--aparte-text-muted);\\n}\\n\\n/* ── Widths: each variant asks for its own; the bubble's limit caps them all ── */\\n\\n.aparte-stock-card[data-variant=\\\"chart\\\"],\\n.aparte-stock-card[data-variant=\\\"candles\\\"] { --aparte-rich-card-max-inline-size: 27rem; }\\n.aparte-stock-card[data-variant=\\\"compact\\\"],\\n.aparte-stock-card:has(> .aparte-stock__list) { --aparte-rich-card-max-inline-size: 26rem; }\\n.aparte-stock-card[data-variant=\\\"ticker\\\"] { --aparte-rich-card-max-inline-size: 36rem; }\\n\\n/* ── A quote, whatever its shape ─────────────────────────────────────── */\\n\\n.aparte-stock {\\n position: relative;\\n min-inline-size: 0;\\n color: var(--aparte-text);\\n}\\n\\n.aparte-stock__heading {\\n padding: var(--aparte-space-5) var(--aparte-rich-card-padding) var(--aparte-space-2);\\n font-size: var(--aparte-font-size-md);\\n font-weight: var(--aparte-font-weight-semibold);\\n overflow-wrap: anywhere;\\n}\\n\\n.aparte-stock__id {\\n display: flex;\\n align-items: baseline;\\n gap: var(--aparte-space-3);\\n min-inline-size: 0;\\n}\\n\\n.aparte-stock__symbol {\\n flex: none;\\n font-weight: var(--aparte-font-weight-bold);\\n letter-spacing: 0.01em;\\n color: inherit;\\n text-decoration: none;\\n}\\n\\na.aparte-stock__symbol:hover {\\n text-decoration: underline;\\n text-decoration-thickness: 1px;\\n text-underline-offset: 0.18em;\\n}\\n\\na.aparte-stock__symbol:focus-visible {\\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\\n outline-offset: var(--aparte-focus-outline-offset);\\n border-radius: var(--aparte-radius-xs);\\n}\\n\\n.aparte-stock__name {\\n min-inline-size: 0;\\n overflow: hidden;\\n color: var(--aparte-text-muted);\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n/* The change: arrow and signed figures on a wash of its own colour. */\\n.aparte-stock__change {\\n display: inline-flex;\\n align-items: center;\\n gap: var(--aparte-space-1);\\n padding: var(--aparte-space-1) var(--aparte-space-3);\\n border-radius: var(--aparte-radius-full);\\n background: color-mix(in oklab, var(--aparte-stock-tone) 14%, transparent);\\n color: var(--aparte-stock-tone-ink);\\n font-size: var(--aparte-font-size-sm);\\n font-weight: var(--aparte-font-weight-semibold);\\n line-height: 1.2;\\n white-space: nowrap;\\n --aparte-rich-card-glyph-size: 0.75em;\\n}\\n\\n.aparte-stock__arrow { color: var(--aparte-stock-tone); }\\n\\n/* ── chart: the quote at length ──────────────────────────────────────── */\\n\\n.aparte-stock--chart {\\n display: flex;\\n flex-direction: column;\\n gap: var(--aparte-space-5);\\n padding: var(--aparte-space-7) var(--aparte-rich-card-padding) var(--aparte-space-6);\\n /* A wash of the day's colour at the top, gone by the chart: the card says which way\\n before a figure is read, and stays the card's surface where the figures are. */\\n background: linear-gradient(\\n to bottom,\\n color-mix(in oklab, var(--aparte-stock-tone) 8%, var(--aparte-surface-1)),\\n var(--aparte-surface-1) 55%\\n );\\n}\\n\\n.aparte-stock--chart .aparte-stock__head {\\n display: flex;\\n flex-direction: column;\\n gap: var(--aparte-space-1);\\n}\\n\\n.aparte-stock--chart .aparte-stock__id { font-size: var(--aparte-font-size-base); }\\n\\n.aparte-stock__meta {\\n display: flex;\\n flex-wrap: wrap;\\n align-items: center;\\n column-gap: var(--aparte-space-3);\\n row-gap: var(--aparte-space-1);\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-sm);\\n}\\n\\n.aparte-stock__meta > * + *::before {\\n content: \\\"·\\\";\\n margin-inline-end: var(--aparte-space-3);\\n}\\n\\n.aparte-stock__market {\\n display: inline-flex;\\n align-items: center;\\n gap: var(--aparte-space-2);\\n}\\n\\n/* The dot is a colour AND a word: open, closed, before or after the session. */\\n.aparte-stock__market-dot {\\n display: inline-block;\\n inline-size: 0.45rem;\\n block-size: 0.45rem;\\n border-radius: var(--aparte-radius-full);\\n background: var(--aparte-stock-flat);\\n}\\n\\n.aparte-stock__market[data-market=\\\"open\\\"] .aparte-stock__market-dot {\\n background: var(--aparte-success);\\n box-shadow: 0 0 0 3px color-mix(in oklab, var(--aparte-success) 22%, transparent);\\n}\\n\\n.aparte-stock__market[data-market=\\\"pre\\\"] .aparte-stock__market-dot,\\n.aparte-stock__market[data-market=\\\"post\\\"] .aparte-stock__market-dot {\\n background: var(--aparte-warning);\\n}\\n\\n.aparte-stock__quote {\\n display: flex;\\n flex-wrap: wrap;\\n align-items: baseline;\\n column-gap: var(--aparte-space-5);\\n row-gap: var(--aparte-space-2);\\n}\\n\\n.aparte-stock__amount {\\n display: inline-flex;\\n align-items: baseline;\\n gap: var(--aparte-space-2);\\n min-inline-size: 0;\\n}\\n\\n.aparte-stock__price {\\n font-size: var(--aparte-stock-price-size);\\n font-weight: var(--aparte-font-weight-semibold);\\n letter-spacing: -0.02em;\\n line-height: 1;\\n overflow-wrap: anywhere;\\n}\\n\\n.aparte-stock__currency {\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-sm);\\n font-weight: var(--aparte-font-weight-medium);\\n}\\n\\n.aparte-stock__quote .aparte-stock__change {\\n align-self: center;\\n font-size: var(--aparte-font-size-md);\\n}\\n\\n/* ── The chart ───────────────────────────────────────────────────────── */\\n\\n.aparte-stock__chart {\\n display: flex;\\n flex-direction: column;\\n gap: var(--aparte-space-3);\\n}\\n\\n/* Time runs left to right (the element is `dir=\\\"ltr\\\"`), so the spots laid over the\\n plot are placed from its left edge, which is its start. */\\n.aparte-stock__plot {\\n position: relative;\\n block-size: var(--aparte-stock-chart-height);\\n border-radius: var(--aparte-radius-sm);\\n cursor: crosshair;\\n /* A finger sliding sideways explores the chart; up and down still scroll the chat. */\\n touch-action: pan-y;\\n -webkit-tap-highlight-color: transparent;\\n}\\n\\n.aparte-stock__plot:focus-visible {\\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\\n outline-offset: var(--aparte-focus-outline-offset);\\n}\\n\\n.aparte-stock__svg {\\n position: absolute;\\n inset: 0;\\n display: block;\\n inline-size: 100%;\\n block-size: 100%;\\n overflow: visible;\\n}\\n\\n.aparte-stock__stop--up { stop-color: var(--aparte-stock-up); }\\n.aparte-stock__stop--down { stop-color: var(--aparte-stock-down); }\\n\\n.aparte-stock__line {\\n fill: none;\\n stroke-width: 2;\\n stroke-linecap: round;\\n stroke-linejoin: round;\\n}\\n\\n.aparte-stock__line--up { stroke: var(--aparte-stock-up); }\\n.aparte-stock__line--down { stroke: var(--aparte-stock-down); }\\n\\n/* Everything laid over the plot is placed at `--aparte-stock-x/y`, in percent of it. */\\n.aparte-stock__baseline,\\n.aparte-stock__extreme,\\n.aparte-stock__dot,\\n.aparte-stock__cursor,\\n.aparte-stock__cursor-dot {\\n position: absolute;\\n inset-inline-start: var(--aparte-stock-x, 0%);\\n inset-block-start: var(--aparte-stock-y, 0%);\\n pointer-events: none;\\n}\\n\\n.aparte-stock__baseline {\\n inset-inline: 0;\\n border-block-start: 1px dashed color-mix(in oklab, var(--aparte-text) 32%, transparent);\\n}\\n\\n.aparte-stock__extreme {\\n --aparte-stock-shift: -50%;\\n translate: var(--aparte-stock-shift) calc(-100% - var(--aparte-space-2));\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-2xs);\\n font-weight: var(--aparte-font-weight-medium);\\n line-height: 1;\\n white-space: nowrap;\\n}\\n\\n.aparte-stock__extreme--lo { translate: var(--aparte-stock-shift) var(--aparte-space-2); }\\n.aparte-stock__extreme[data-align=\\\"start\\\"] { --aparte-stock-shift: 0%; }\\n.aparte-stock__extreme[data-align=\\\"end\\\"] { --aparte-stock-shift: -100%; }\\n\\n/* The last point: the line's colour on a ring of the card's surface. */\\n.aparte-stock__dot,\\n.aparte-stock__cursor-dot {\\n inline-size: 0.6rem;\\n block-size: 0.6rem;\\n translate: -50% -50%;\\n border: 2px solid var(--aparte-surface-1);\\n border-radius: var(--aparte-radius-full);\\n background: var(--aparte-stock-tone);\\n box-sizing: border-box;\\n}\\n\\n/* Open market: the last point breathes. Under reduced motion the kit stops it. */\\n.aparte-stock__dot[data-live]::after {\\n content: \\\"\\\";\\n position: absolute;\\n inset: -2px;\\n border-radius: inherit;\\n background: var(--aparte-stock-tone);\\n opacity: 0.45;\\n animation: aparte-stock-pulse 1.8s ease-out infinite;\\n}\\n\\n@keyframes aparte-stock-pulse {\\n from { scale: 1; opacity: 0.45; }\\n to { scale: 3; opacity: 0; }\\n}\\n\\n.aparte-stock__cursor {\\n inset-block: 0;\\n inline-size: 0;\\n translate: -50% 0;\\n border-inline-start: 1px solid color-mix(in oklab, var(--aparte-text) 45%, transparent);\\n visibility: hidden;\\n}\\n\\n.aparte-stock__cursor-dot {\\n visibility: hidden;\\n background: var(--aparte-text);\\n}\\n\\n.aparte-stock__chart[data-scrub] .aparte-stock__cursor,\\n.aparte-stock__chart[data-scrub] .aparte-stock__cursor-dot { visibility: visible; }\\n\\n.aparte-stock__chart[data-scrub] .aparte-stock__dot { opacity: 0.35; }\\n\\n/* Under the plot: the range and the legend, or — while the chart is explored — the\\n value and time under the cursor, in the same place. */\\n.aparte-stock__chart-foot {\\n display: grid;\\n min-block-size: 1.5rem;\\n font-size: var(--aparte-font-size-sm);\\n}\\n\\n.aparte-stock__chart-foot > * { grid-area: 1 / 1; }\\n\\n.aparte-stock__chart-info {\\n display: flex;\\n flex-wrap: wrap;\\n align-items: center;\\n justify-content: space-between;\\n gap: var(--aparte-space-3);\\n color: var(--aparte-text-muted);\\n}\\n\\n.aparte-stock__readout {\\n align-self: center;\\n font-weight: var(--aparte-font-weight-semibold);\\n white-space: nowrap;\\n}\\n\\n.aparte-stock__chart[data-scrub] .aparte-stock__chart-info { visibility: hidden; }\\n\\n.aparte-stock__range {\\n padding: var(--aparte-space-1) var(--aparte-space-3);\\n border: var(--aparte-border-width) solid var(--aparte-border);\\n border-radius: var(--aparte-radius-full);\\n color: var(--aparte-text);\\n font-size: var(--aparte-font-size-xs);\\n font-weight: var(--aparte-font-weight-medium);\\n}\\n\\n.aparte-stock__legend {\\n display: inline-flex;\\n align-items: center;\\n gap: var(--aparte-space-2);\\n margin-inline-start: auto;\\n}\\n\\n.aparte-stock__legend-line {\\n inline-size: 1rem;\\n border-block-start: 1px dashed color-mix(in oklab, var(--aparte-text) 45%, transparent);\\n}\\n\\n.aparte-stock__change--range {\\n margin-inline-start: auto;\\n font-size: var(--aparte-font-size-xs);\\n}\\n\\n/* ── The range buttons, across the top of the chart ──────────────────── */\\n\\n.aparte-stock__ranges .aparte-rich-card__segmented {\\n display: flex;\\n inline-size: 100%;\\n box-sizing: border-box;\\n}\\n\\n.aparte-stock__ranges .aparte-rich-card__segment {\\n flex: 1 1 0;\\n min-inline-size: 0;\\n padding-inline: var(--aparte-space-1);\\n white-space: nowrap;\\n font-variant-numeric: tabular-nums;\\n}\\n\\n/* While the app answers a range, the chart it will replace steps back; the buttons stay\\n as they are, so another range can be chosen without waiting. */\\n.aparte-stock__chart {\\n transition: opacity var(--aparte-duration-base) ease;\\n}\\n\\n.aparte-stock-card[data-busy] .aparte-stock__chart { opacity: 0.45; }\\n\\n/* ── Candles: hollow when they rose, filled when they fell ───────────── */\\n\\n.aparte-stock__body,\\n.aparte-stock__wick {\\n stroke-width: 1;\\n stroke-linejoin: miter;\\n}\\n\\n.aparte-stock__body--up {\\n fill: none;\\n stroke: var(--aparte-stock-up);\\n}\\n\\n.aparte-stock__body--down {\\n fill: var(--aparte-stock-down);\\n stroke: var(--aparte-stock-down);\\n}\\n\\n.aparte-stock__body--flat {\\n fill: var(--aparte-stock-flat);\\n stroke: var(--aparte-stock-flat);\\n}\\n\\n.aparte-stock__wick { fill: none; }\\n.aparte-stock__wick--up { stroke: var(--aparte-stock-up); }\\n.aparte-stock__wick--down { stroke: var(--aparte-stock-down); }\\n.aparte-stock__wick--flat { stroke: var(--aparte-stock-flat); }\\n\\n/* The volume: faint, so it is read after the prices and never instead of them. */\\n.aparte-stock__volume {\\n stroke: none;\\n opacity: 0.22;\\n}\\n\\n.aparte-stock__volume--up { fill: var(--aparte-stock-up); }\\n.aparte-stock__volume--down { fill: var(--aparte-stock-down); }\\n.aparte-stock__volume--flat { fill: var(--aparte-stock-flat); }\\n\\n.aparte-stock__plot[data-kind=\\\"candles\\\"] .aparte-stock__cursor-dot {\\n inline-size: 0.45rem;\\n block-size: 0.45rem;\\n}\\n\\n/* ── The figures ─────────────────────────────────────────────────────── */\\n\\n.aparte-stock__stats {\\n display: grid;\\n grid-template-columns: repeat(auto-fill, minmax(6.75rem, 1fr));\\n gap: var(--aparte-space-4) var(--aparte-space-5);\\n margin: 0;\\n padding-block-start: var(--aparte-space-5);\\n border-block-start: var(--aparte-border-width) solid var(--aparte-border);\\n}\\n\\n.aparte-stock__stat {\\n display: flex;\\n flex-direction: column;\\n gap: var(--aparte-space-1);\\n min-inline-size: 0;\\n}\\n\\n.aparte-stock__stat--wide { grid-column: 1 / -1; }\\n\\n.aparte-stock__stat-term {\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-xs);\\n}\\n\\n.aparte-stock__stat-value {\\n margin: 0;\\n font-size: var(--aparte-font-size-md);\\n font-weight: var(--aparte-font-weight-medium);\\n overflow-wrap: anywhere;\\n}\\n\\n/* The 52-week range: its two ends, the bar between, the price as a mark on it. */\\n.aparte-stock__year {\\n display: flex;\\n align-items: center;\\n gap: var(--aparte-space-4);\\n}\\n\\n.aparte-stock__year-bar {\\n position: relative;\\n flex: 1;\\n block-size: 0.3rem;\\n border-radius: var(--aparte-radius-full);\\n background: linear-gradient(\\n to var(--aparte-stock-year-toward, right),\\n color-mix(in oklab, var(--aparte-stock-down) 40%, var(--aparte-surface-2)),\\n var(--aparte-surface-2) 50%,\\n color-mix(in oklab, var(--aparte-stock-up) 40%, var(--aparte-surface-2))\\n );\\n}\\n\\n.aparte-stock__year-bar:dir(rtl) { --aparte-stock-year-toward: left; }\\n\\n.aparte-stock__year-mark {\\n position: absolute;\\n inset-block-start: 50%;\\n inset-inline-start: var(--aparte-stock-position, 50%);\\n inline-size: 0.2rem;\\n block-size: 0.85rem;\\n translate: -50% -50%;\\n border-radius: var(--aparte-radius-full);\\n background: var(--aparte-text);\\n box-shadow: 0 0 0 2px var(--aparte-surface-1);\\n}\\n\\n.aparte-stock__year-mark:dir(rtl) { translate: 50% -50%; }\\n\\n/* ── compact: a row per quote ────────────────────────────────────────── */\\n\\n.aparte-stock__list {\\n margin: 0;\\n padding: 0;\\n list-style: none;\\n}\\n\\n.aparte-stock__item + .aparte-stock__item {\\n border-block-start: var(--aparte-border-width) solid var(--aparte-border);\\n}\\n\\n.aparte-stock--row {\\n display: grid;\\n grid-template-columns: minmax(0, 1fr) minmax(3rem, 4.5rem) auto;\\n align-items: center;\\n gap: var(--aparte-space-5);\\n padding: var(--aparte-space-5) var(--aparte-rich-card-padding);\\n transition: background-color var(--aparte-duration-fast) ease;\\n}\\n\\n.aparte-stock--row .aparte-stock__id {\\n flex-direction: column;\\n align-items: flex-start;\\n gap: 0;\\n}\\n\\n.aparte-stock--row .aparte-stock__name {\\n max-inline-size: 100%;\\n font-size: var(--aparte-font-size-sm);\\n}\\n\\n.aparte-stock--row[data-linked]:hover { background: var(--aparte-surface-2); }\\n\\n/* The symbol's link covers the row or the tick: one link per quote, read once. */\\n.aparte-stock__link--stretched { outline: none; }\\n\\n.aparte-stock__link--stretched::after {\\n content: \\\"\\\";\\n position: absolute;\\n inset: 0;\\n border-radius: inherit;\\n}\\n\\n.aparte-stock--row:has(.aparte-stock__link--stretched:focus-visible),\\n.aparte-stock__tick:has(.aparte-stock__link--stretched:focus-visible) {\\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\\n outline-offset: calc(var(--aparte-focus-outline-width) * -1);\\n}\\n\\n.aparte-stock__spark {\\n block-size: 2rem;\\n --aparte-rich-card-spark: var(--aparte-stock-tone);\\n}\\n\\n.aparte-stock__spark-base {\\n stroke: color-mix(in oklab, var(--aparte-text) 28%, transparent);\\n stroke-width: 1;\\n stroke-dasharray: 2 3;\\n}\\n\\n.aparte-stock__sparkline .aparte-rich-card__sparkline-line { stroke-width: 1.6; }\\n\\n.aparte-stock__figures {\\n display: flex;\\n flex-direction: column;\\n align-items: flex-end;\\n gap: var(--aparte-space-2);\\n}\\n\\n.aparte-stock__row-price {\\n font-weight: var(--aparte-font-weight-semibold);\\n white-space: nowrap;\\n}\\n\\n.aparte-stock__figures .aparte-stock__change {\\n min-inline-size: 4.75rem;\\n justify-content: flex-end;\\n}\\n\\n/* ── ticker: a strip of quotes ───────────────────────────────────────── */\\n\\n.aparte-stock-card[data-variant=\\\"ticker\\\"] > .aparte-stock__heading {\\n padding-block-end: 0;\\n}\\n\\n.aparte-stock__tape {\\n display: flex;\\n gap: var(--aparte-space-2);\\n margin: 0;\\n padding: var(--aparte-space-3);\\n list-style: none;\\n overflow-x: auto;\\n overscroll-behavior-x: contain;\\n scroll-snap-type: x proximity;\\n scroll-padding-inline: var(--aparte-space-3);\\n scrollbar-width: thin;\\n /* Both ends fade, so a strip that runs on says so — the same at the start and the end,\\n whichever way the page reads. */\\n -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--aparte-space-4), #000 calc(100% - var(--aparte-space-4)), transparent);\\n mask-image: linear-gradient(to right, transparent, #000 var(--aparte-space-4), #000 calc(100% - var(--aparte-space-4)), transparent);\\n}\\n\\n.aparte-stock__tape:focus-visible {\\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\\n outline-offset: calc(var(--aparte-focus-outline-width) * -1);\\n border-radius: inherit;\\n}\\n\\n.aparte-stock__tick {\\n position: relative;\\n display: inline-flex;\\n flex: none;\\n align-items: center;\\n gap: var(--aparte-space-3);\\n padding: var(--aparte-space-3) var(--aparte-space-4);\\n border-radius: var(--aparte-radius-md);\\n font-size: var(--aparte-font-size-md);\\n white-space: nowrap;\\n scroll-snap-align: start;\\n transition: background-color var(--aparte-duration-fast) ease;\\n}\\n\\n.aparte-stock__tick + .aparte-stock__tick::before {\\n content: \\\"\\\";\\n position: absolute;\\n inset-block: 25%;\\n inset-inline-start: calc(var(--aparte-space-1) * -1);\\n border-inline-start: var(--aparte-border-width) solid var(--aparte-border);\\n}\\n\\n.aparte-stock__tick[data-linked]:hover { background: var(--aparte-surface-2); }\\n\\n.aparte-stock__tick-price { color: var(--aparte-text); }\\n\\n.aparte-stock__tick .aparte-stock__change {\\n padding: 0;\\n background: none;\\n}\\n\\n/* ── Skeletons ───────────────────────────────────────────────────────── */\\n\\n.aparte-stock--skeleton { pointer-events: none; }\\n.aparte-stock-card .aparte-stock__sk-symbol { inline-size: 3.5rem; }\\n.aparte-stock-card .aparte-stock__sk-name { inline-size: 7rem; margin: 0; }\\n.aparte-stock-card .aparte-stock__sk-price { inline-size: 8rem; block-size: 2rem; }\\n.aparte-stock-card .aparte-stock__sk-pill { inline-size: 5rem; block-size: 1.25rem; margin: 0; border-radius: var(--aparte-radius-full); }\\n.aparte-stock-card .aparte-stock__sk-chart { block-size: var(--aparte-stock-chart-height); }\\n.aparte-stock-card .aparte-stock__sk-term { inline-size: 3.5rem; }\\n.aparte-stock-card .aparte-stock__sk-figure { inline-size: 4.5rem; margin: 0; }\\n.aparte-stock-card .aparte-stock__sk-spark { block-size: 1.5rem; }\\n.aparte-stock--skeleton .aparte-stock__quote { align-items: center; }\\n.aparte-stock__tick--skeleton { gap: var(--aparte-space-4); }\\n\\n/* ── Narrow: a phone's width ─────────────────────────────────────────── */\\n\\n@media (max-width: 380px) {\\n .aparte-stock-card {\\n --aparte-stock-chart-height: 7rem;\\n --aparte-stock-price-size: var(--aparte-font-size-2xl);\\n }\\n\\n .aparte-stock--row {\\n grid-template-columns: minmax(0, 1fr) 2.75rem auto;\\n gap: var(--aparte-space-4);\\n }\\n\\n .aparte-stock__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }\\n}\\n\\n@media (prefers-reduced-motion: reduce) {\\n .aparte-stock__dot[data-live]::after { animation: none; opacity: 0; }\\n}\\n\"","/**\n * @aparte/plugin-cards/stock — a market quote, drawn with its chart.\n *\n * import { setupStockCard } from '@aparte/plugin-cards/stock';\n *\n * setupStockCard({ tool: 'get_quote' });\n *\n * A stock, an index, a crypto-currency or a currency pair: whatever has a symbol and a\n * price. Four variants of one card: `chart` (the quote at length — the price, the change,\n * the chart against the previous close, the day's figures), `compact` (a row per quote,\n * its sparkline in the change's colour), `ticker` (a strip of quotes that scrolls\n * sideways, like a market ticker — static, nothing moves on its own) and `candles` (the\n * `chart` card with a candlestick chart in place of the line).\n *\n * Several quotes in `chart` or `candles` are drawn as `compact` rows: a watchlist is read\n * by comparing its lines, and a carousel of charts would show one quote at a time — the\n * opposite of a watchlist — at a width (a slide) the chart cannot use. A quote asked for\n * in `candles` that has no candles is drawn with the line chart, from its series: the\n * card shows what it has rather than an empty frame.\n *\n * Your tool keeps its own fields: `readQuotes` already reads Yahoo Finance's quote and\n * chart, Alpha Vantage's `GLOBAL_QUOTE`, Finnhub's quote (when a `symbol` is given beside\n * it), CoinGecko's markets and OHLC, Binance's klines — and `map` covers the rest.\n *\n * **Range buttons.** Give a quote the `ranges` your app can serve and an `onChange` that\n * serves them: the card draws a row of buttons over its chart, and a press asks your app\n * for the quote over that range, drawn in place — the same element, the focus kept on the\n * pressed button. Without an `onChange` no button is drawn: one that does nothing would be\n * a promise the card cannot keep.\n *\n * setupStockCard({\n * tool: 'get_quote',\n * map: (result) => ({ ...result, ranges: ['1D', '5D', '1M', '6M', '1Y', '5Y'] }),\n * onChange: async ({ name, value }, data) => {\n * const [quote] = data.quotes;\n * if (name !== 'range' || !quote) return;\n * const chart = await fetch(`/api/chart?symbol=${quote.symbol}&range=${value}`).then((r) => r.json());\n * // The quote as it was, over the new range: say the range, and send its series\n * // (and its candles, for the `candles` variant) — the old ones would be kept.\n * return { ...quote, range: value, series: chart.series, candles: chart.candles };\n * },\n * });\n *\n * The baseline follows the range: the previous close for a day, where the series starts\n * for anything longer.\n */\nimport type { AparteConfig } from '@aparte/core';\nimport { defineCard, type CardContext, type CardSetupOptions } from '../kit/define.js';\nimport { el, glyph, num, str, webUrl } from '../kit/dom.js';\nimport { currencyCode, formatHour, formatNumber, formatWhen, toDate } from '../kit/format.js';\nimport { sparkline } from '../kit/sparkline.js';\nimport { intlTag, word, type CardWord } from '../kit/strings.js';\nimport { segmented } from '../kit/controls.js';\nimport { candleChart, priceChart, thin, type Candle, type ChartPoint } from './chart.js';\nimport { CHART, DOWN, UP } from './icons.js';\nimport stockStyles from './stock.css?raw';\n\nexport type StockVariant = 'chart' | 'compact' | 'ticker' | 'candles';\n\nexport type { Candle, ChartPoint } from './chart.js';\n\n/** Where the market stands for this quote. */\nexport type MarketState = 'open' | 'closed' | 'pre' | 'post';\n\n/** A range the chart covers: one of the usual, or a label of your own (\"YTD\"). */\nexport type StockRange = '1D' | '5D' | '1M' | '6M' | '1Y' | '5Y' | (string & {});\n\n/**\n * One quote as `map` returns it. `symbol` and `price` are needed — a quote given only\n * candles or a series takes its last close as its price — and every other field adds a\n * line when it is there and nothing when it is not.\n *\n * The change is derived from what is given, and only what is missing is derived — a value\n * the tool gives is never recomputed, so its own rounding stands: `change` from\n * `previousClose`, then `previousClose` from `change` (or, failing that, from\n * `changePercent`), then `changePercent` from the two. When `changePercent` and\n * `previousClose` are both given, both are shown as given and the chart's baseline is the\n * given `previousClose`.\n */\nexport interface QuoteInput {\n symbol: string;\n name?: string;\n exchange?: string;\n price?: number | string;\n /** An ISO 4217 code (`USD`) or a usual symbol (`$`). */\n currency?: string;\n /** The change since the previous close, in the currency. */\n change?: number | string;\n /** The change in percent: `0.85` is +0.85 %. `\"0.85%\"` reads too. */\n changePercent?: number | string;\n previousClose?: number | string;\n open?: number | string;\n high?: number | string;\n low?: number | string;\n volume?: number | string;\n marketCap?: number | string;\n yearHigh?: number | string;\n yearLow?: number | string;\n /** The chart: values in time order, or `{ time, value }` points (also `[time, value]` pairs). */\n series?: number[] | Array<{ time: string | number | Date; value: number }>;\n /**\n * The `candles` variant's chart, in time order. Also read: Yahoo's chart result\n * (`timestamp` + `indicators.quote[0]`), Binance's klines and CoinGecko's OHLC\n * (`[time, open, high, low, close, volume?]` arrays, numbers or strings), and\n * `{ t, o, h, l, c, v }` objects. A quote with candles and no series draws its line\n * from the closes.\n */\n candles?: Array<{ time: string | number | Date; open: number | string; high: number | string; low: number | string; close: number | string; volume?: number | string }>;\n /** The range the series (or the candles) covers. */\n range?: StockRange;\n /** The ranges your app can serve: drawn as buttons over the chart when the card has an `onChange`. */\n ranges?: StockRange[];\n marketState?: MarketState;\n /** When the price was: an ISO string, an epoch (seconds or milliseconds) or a Date. */\n time?: string | number | Date;\n /** Where the symbol links to; `http(s)` only. */\n url?: string;\n}\n\n/** What `map` returns: one quote, a list (a watchlist), or a list with a heading. */\nexport type QuotesInput = QuoteInput | QuoteInput[] | { title?: string; quotes: QuoteInput[] };\n\n/** One quote as the card draws it, once read. */\nexport interface Quote {\n symbol: string;\n name?: string;\n exchange?: string;\n price: number;\n /** An ISO 4217 code. */\n currency?: string;\n change?: number;\n /** In percent: `0.85` is +0.85 %. */\n changePercent?: number;\n previousClose?: number;\n open?: number;\n high?: number;\n low?: number;\n volume?: number;\n marketCap?: number;\n yearHigh?: number;\n yearLow?: number;\n /** In time order, at most 2000 points; the candles' closes when only candles were given. */\n series: ChartPoint[];\n /** In time order, at most 2000. */\n candles: Candle[];\n range?: string;\n ranges?: string[];\n marketState?: MarketState;\n time?: Date;\n url?: string;\n}\n\n/** The data as the card draws it. */\nexport interface StockData {\n /** The heading over several quotes (\"Tech watchlist\"). */\n title?: string;\n quotes: Quote[];\n}\n\nconst S = {\n cardsStockTitle: { en: 'Market quote', fr: 'Cours de bourse', de: 'Börsenkurs', es: 'Cotización', it: 'Quotazione', ja: '株価', ko: '시세', pt: 'Cotação', ru: 'Котировка', zh: '行情' },\n cardsStockCount: { en: '{n} quotes', fr: '{n} cours', de: '{n} Kurse', es: '{n} cotizaciones', it: '{n} quotazioni', ja: '{n}件の銘柄', ko: '종목 {n}개', pt: '{n} cotações', ru: 'Котировок: {n}', zh: '{n} 个行情' },\n cardsStockMarketOpen: { en: 'Market open', fr: 'Marché ouvert', de: 'Markt geöffnet', es: 'Mercado abierto', it: 'Mercato aperto', ja: '取引時間中', ko: '장 운영 중', pt: 'Mercado aberto', ru: 'Рынок открыт', zh: '交易中' },\n cardsStockMarketClosed: { en: 'Market closed', fr: 'Marché fermé', de: 'Markt geschlossen', es: 'Mercado cerrado', it: 'Mercato chiuso', ja: '取引終了', ko: '장 마감', pt: 'Mercado fechado', ru: 'Рынок закрыт', zh: '已收盘' },\n cardsStockPreMarket: { en: 'Pre-market', fr: 'Pré-ouverture', de: 'Vorbörslich', es: 'Preapertura', it: 'Pre-mercato', ja: 'プレマーケット', ko: '장전 거래', pt: 'Pré-mercado', ru: 'Премаркет', zh: '盘前' },\n cardsStockAfterHours: { en: 'After hours', fr: 'Après-clôture', de: 'Nachbörslich', es: 'Poscierre', it: 'After hours', ja: 'アフターマーケット', ko: '시간외 거래', pt: 'After-market', ru: 'Постмаркет', zh: '盘后' },\n cardsStockAsOf: { en: 'As of {time}', fr: 'À {time}', de: 'Stand: {time}', es: 'A las {time}', it: 'Alle {time}', ja: '{time}時点', ko: '{time} 기준', pt: 'Às {time}', ru: 'На {time}', zh: '截至 {time}' },\n cardsStockOpen: { en: 'Open', fr: 'Ouverture', de: 'Eröffnung', es: 'Apertura', it: 'Apertura', ja: '始値', ko: '시가', pt: 'Abertura', ru: 'Открытие', zh: '开盘' },\n cardsStockHigh: { en: 'High', fr: 'Plus haut', de: 'Hoch', es: 'Máximo', it: 'Massimo', ja: '高値', ko: '고가', pt: 'Máxima', ru: 'Максимум', zh: '最高' },\n cardsStockLow: { en: 'Low', fr: 'Plus bas', de: 'Tief', es: 'Mínimo', it: 'Minimo', ja: '安値', ko: '저가', pt: 'Mínima', ru: 'Минимум', zh: '最低' },\n cardsStockPrevClose: { en: 'Prev. close', fr: 'Clôture veille', de: 'Vortag', es: 'Cierre anterior', it: 'Chiusura prec.', ja: '前日終値', ko: '전일 종가', pt: 'Fech. anterior', ru: 'Пред. закрытие', zh: '昨收' },\n cardsStockVolume: { en: 'Volume', fr: 'Volume', de: 'Volumen', es: 'Volumen', it: 'Volume', ja: '出来高', ko: '거래량', pt: 'Volume', ru: 'Объём', zh: '成交量' },\n cardsStockMarketCap: { en: 'Market cap', fr: 'Capitalisation', de: 'Marktkap.', es: 'Cap. bursátil', it: 'Capitalizzazione', ja: '時価総額', ko: '시가총액', pt: 'Valor de mercado', ru: 'Капитализация', zh: '市值' },\n cardsStockYearRange: { en: '52-week range', fr: 'Sur 52 semaines', de: '52-Wochen-Spanne', es: 'Rango de 52 semanas', it: 'Intervallo 52 settimane', ja: '52週レンジ', ko: '52주 범위', pt: 'Intervalo de 52 semanas', ru: 'Диапазон за 52 недели', zh: '52周范围' },\n cardsStockChart: {\n en: 'Price chart: low {low}, high {high}, last {last}', fr: 'Graphique du cours : plus bas {low}, plus haut {high}, dernier {last}',\n de: 'Kursverlauf: Tief {low}, Hoch {high}, zuletzt {last}', es: 'Gráfico de precio: mínimo {low}, máximo {high}, último {last}',\n it: 'Grafico del prezzo: minimo {low}, massimo {high}, ultimo {last}', ja: '価格チャート:安値 {low}、高値 {high}、現在 {last}',\n ko: '가격 차트: 저가 {low}, 고가 {high}, 현재 {last}', pt: 'Gráfico de preço: mínima {low}, máxima {high}, último {last}',\n ru: 'График цены: минимум {low}, максимум {high}, последняя {last}', zh: '价格走势:最低 {low},最高 {high},最新 {last}',\n },\n cardsStockRange: { en: 'Range', fr: 'Période', de: 'Zeitraum', es: 'Periodo', it: 'Periodo', ja: '期間', ko: '기간', pt: 'Período', ru: 'Период', zh: '时间范围' },\n cardsStockOhlc: {\n en: 'O {open} H {high} L {low} C {close}', fr: 'O {open} H {high} B {low} C {close}', de: 'E {open} H {high} T {low} S {close}',\n es: 'A {open} Máx {high} Mín {low} C {close}', it: 'A {open} Max {high} Min {low} C {close}', ja: '始 {open} 高 {high} 安 {low} 終 {close}',\n ko: '시 {open} 고 {high} 저 {low} 종 {close}', pt: 'A {open} Máx {high} Mín {low} F {close}', ru: 'О {open} Макс {high} Мин {low} З {close}',\n zh: '开 {open} 高 {high} 低 {low} 收 {close}',\n },\n cardsStockOhlcSaid: {\n en: 'Open {open}, high {high}, low {low}, close {close}', fr: 'Ouverture {open}, plus haut {high}, plus bas {low}, clôture {close}',\n de: 'Eröffnung {open}, Hoch {high}, Tief {low}, Schluss {close}', es: 'Apertura {open}, máximo {high}, mínimo {low}, cierre {close}',\n it: 'Apertura {open}, massimo {high}, minimo {low}, chiusura {close}', ja: '始値 {open}、高値 {high}、安値 {low}、終値 {close}',\n ko: '시가 {open}, 고가 {high}, 저가 {low}, 종가 {close}', pt: 'Abertura {open}, máxima {high}, mínima {low}, fechamento {close}',\n ru: 'Открытие {open}, максимум {high}, минимум {low}, закрытие {close}', zh: '开盘 {open},最高 {high},最低 {low},收盘 {close}',\n },\n cardsStockChartRange: {\n en: 'Price chart, {range}: low {low}, high {high}, last {last}', fr: 'Graphique du cours, {range} : plus bas {low}, plus haut {high}, dernier {last}',\n de: 'Kursverlauf, {range}: Tief {low}, Hoch {high}, zuletzt {last}', es: 'Gráfico de precio, {range}: mínimo {low}, máximo {high}, último {last}',\n it: 'Grafico del prezzo, {range}: minimo {low}, massimo {high}, ultimo {last}', ja: '価格チャート({range}):安値 {low}、高値 {high}、現在 {last}',\n ko: '가격 차트({range}): 저가 {low}, 고가 {high}, 현재 {last}', pt: 'Gráfico de preço, {range}: mínima {low}, máxima {high}, último {last}',\n ru: 'График цены, {range}: минимум {low}, максимум {high}, последняя {last}', zh: '价格走势({range}):最低 {low},最高 {high},最新 {last}',\n },\n} satisfies Record<string, CardWord>;\n\nconst MARKET_WORD: Record<MarketState, keyof typeof S> = {\n open: 'cardsStockMarketOpen',\n closed: 'cardsStockMarketClosed',\n pre: 'cardsStockPreMarket',\n post: 'cardsStockAfterHours',\n};\n\n/** Twelve: a watchlist past that is a screener, not an answer. */\nconst QUOTES_SHOWN = 12;\n/** Points kept per series: a year of hours. The chart thins them to its width. */\nconst POINTS_KEPT = 2000;\n\n// ── Reading ──────────────────────────────────────────────────────────────────\n\ntype Raw = Record<string, unknown>;\n\nconst isObject = (value: unknown): value is Raw => !!value && typeof value === 'object' && !Array.isArray(value);\n\n/** The first of `keys` that `r` has a value for. */\nfunction pick(r: Raw | undefined, keys: readonly string[]): unknown {\n if (!r) return undefined;\n for (const key of keys) if (r[key] !== undefined && r[key] !== null) return r[key];\n return undefined;\n}\n\n/** A percentage as a number of percent: `0.85`, `\"0.85\"`, Alpha Vantage's `\"0.8500%\"`. */\nfunction percentOf(value: unknown): number | undefined {\n return typeof value === 'string' ? num(value.replace(/[%\\s]/g, '')) : num(value);\n}\n\n/** A date written as a day only (`2024-01-05`, Alpha Vantage's trading day) is that day, here — not midnight in London. */\nfunction readTime(value: unknown): Date | undefined {\n // An epoch of 0 is a field left empty (Finnhub's `t` for an unknown symbol), not 1970.\n if (value === 0) return undefined;\n if (typeof value === 'string') {\n const day = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value.trim());\n if (day) return new Date(Number(day[1]), Number(day[2]) - 1, Number(day[3]));\n }\n return toDate(value) ?? undefined;\n}\n\n/**\n * The times of one series, read in ONE unit. Alone, an epoch under 10^12 is seconds\n * (`toDate`'s rule); in a series in milliseconds that starts before 2001-09-09, that rule\n * read the early points as seconds, dated them thirty thousand years ahead, and the sort put\n * them last. So the series decides: it is in milliseconds when any of its epochs passes\n * 10^11 — the year 5138 as seconds, which no market has traded in; 1973 as milliseconds.\n */\nfunction readTimes(values: unknown[]): Array<Date | undefined> {\n const ms = values.some((v) => typeof v === 'number' && v >= 1e11);\n return values.map((v) => readTime(ms && typeof v === 'number' && v !== 0 ? new Date(v) : v));\n}\n\n/** Yahoo's `REGULAR`, `PREPRE`, `POSTPOST`; the plain words; a boolean \"is open\". */\nfunction readMarketState(r: Raw): MarketState | undefined {\n const value = pick(r, ['marketState', 'market_state', 'marketStatus', 'market_status', 'session']);\n if (typeof value === 'string') {\n const key = value.toLowerCase().replace(/[^a-z]/g, '');\n if (['open', 'regular', 'trading', 'live'].includes(key)) return 'open';\n // Yahoo's `PREPRE` and `POSTPOST` are the hours AROUND the extended sessions: before the\n // pre-market opens, after the after-hours have closed. Nothing trades then.\n if (['closed', 'close', 'prepre', 'postpost'].includes(key)) return 'closed';\n if (key.startsWith('pre')) return 'pre';\n if (key.startsWith('post') || key.startsWith('after') || key === 'extended') return 'post';\n return undefined;\n }\n const open = pick(r, ['isOpen', 'is_open', 'marketOpen', 'market_open']);\n return typeof open === 'boolean' ? (open ? 'open' : 'closed') : undefined;\n}\n\nconst VALUE_KEYS = ['value', 'price', 'close', 'c', 'y', 'adjClose', 'adj_close'];\nconst TIME_KEYS = ['time', 't', 'date', 'timestamp', 'datetime', 'x'];\n\n/** The chart's points: numbers, `[time, value]` pairs (CoinGecko's `prices`), or objects. */\nfunction readSeries(value: unknown): ChartPoint[] {\n if (!Array.isArray(value)) return [];\n const points: ChartPoint[] = [];\n const times = readTimes(value.map((item) => (Array.isArray(item) ? item[0] : isObject(item) ? pick(item, TIME_KEYS) : undefined)));\n value.forEach((item, i) => {\n const v = num(Array.isArray(item) ? item[1] : isObject(item) ? pick(item, VALUE_KEYS) : item);\n const time = times[i];\n if (v !== undefined) points.push(time ? { value: v, time } : { value: v });\n });\n // A series that names every point's time is put in time order: some APIs list the newest first.\n if (points.length > 1 && points.every((p) => p.time)) points.sort((a, b) => a.time!.getTime() - b.time!.getTime());\n return points.slice(-POINTS_KEPT);\n}\n\n/**\n * The candles from what a tool wrote: Yahoo's chart (the whole answer or one result),\n * `[time, open, high, low, close, volume?]` arrays (Binance's klines, CoinGecko's OHLC),\n * or objects. A candle missing a price is dropped; a high and a low the wrong way round are\n * swapped, then a high under the body or a low over it is widened to the body, so a candle\n * is never drawn inside out.\n */\nfunction readCandles(value: unknown): Candle[] {\n let list = value;\n if (isObject(value)) {\n const chart = isObject(value['chart']) && Array.isArray(value['chart']['result']) ? value['chart']['result'][0] : value;\n const indicators = isObject(chart) && isObject(chart['indicators']) && Array.isArray(chart['indicators']['quote']) ? chart['indicators']['quote'][0] : undefined;\n const times = isObject(chart) ? chart['timestamp'] : undefined;\n if (!Array.isArray(times) || !isObject(indicators)) return [];\n const at = (key: string, i: number) => (Array.isArray(indicators[key]) ? (indicators[key] as unknown[])[i] : undefined);\n list = times.map((t, i) => ({ t, o: at('open', i), h: at('high', i), l: at('low', i), c: at('close', i), v: at('volume', i) }));\n }\n if (!Array.isArray(list)) return [];\n const rows: unknown[][] = list.map((item) => (Array.isArray(item)\n ? item\n : isObject(item)\n ? [pick(item, ['time', 't', 'date', 'timestamp', 'openTime']), pick(item, ['open', 'o']), pick(item, ['high', 'h']), pick(item, ['low', 'l']), pick(item, ['close', 'c']), pick(item, ['volume', 'v'])]\n : []));\n const times = readTimes(rows.map((row) => row[0]));\n const candles: Candle[] = [];\n rows.forEach(([, o, h, l, c, v], i) => {\n const open = num(o);\n const close = num(c);\n let high = num(h);\n let low = num(l);\n if (open === undefined || close === undefined || high === undefined || low === undefined) return;\n // A high under the low is the two fields swapped, not two wrong values: widening the\n // body alone would drop the true extreme (a low of 6 kept as a high of 5).\n if (high < low) [high, low] = [low, high];\n const time = times[i];\n const volume = num(v);\n candles.push({\n ...(time ? { time } : {}),\n open,\n high: Math.max(high, open, close),\n low: Math.min(low, open, close),\n close,\n ...(volume !== undefined && volume >= 0 ? { volume } : {}),\n });\n });\n if (candles.length > 1 && candles.every((c) => c.time)) candles.sort((a, b) => a.time!.getTime() - b.time!.getTime());\n return candles.slice(-POINTS_KEPT);\n}\n\n/**\n * Marks a quote whose previous close was worked back from a rounded percentage: good\n * enough for a baseline, not for a figure. A symbol key, so it survives the spread an\n * app's `onChange` makes of the quote it was handed (`{ ...quote, range }`).\n */\nconst ESTIMATED = Symbol('aparte-stock-estimated');\nconst isEstimated = (quote: Quote) => (quote as unknown as Record<symbol, unknown>)[ESTIMATED] === true;\n\n/** One quote from whatever a tool wrote, or `null` without a symbol and a price. */\nfunction readQuote(raw: unknown): Quote | null {\n if (!isObject(raw)) return null;\n // Yahoo's chart: the quote is its `meta`, the candles are beside it.\n const r: Raw = isObject(raw['meta']) && isObject(raw['indicators']) ? { ...raw['meta'], candles: raw } : raw;\n const given = str(pick(r, ['symbol', 'ticker', '01. symbol', 'code']));\n if (!given) return null;\n // CoinGecko writes `btc`; a ticker is read in capitals.\n const symbol = /[A-Z]/.test(given) ? given : given.toUpperCase();\n // Finnhub's one-letter fields (`c`, `d`, `pc`…) come last in each list, and are only\n // ever read here, past the symbol: on their own they are no quote at all.\n const sparkline7d = isObject(r['sparkline_in_7d']) ? r['sparkline_in_7d']['price'] : undefined;\n const candles = readCandles(pick(r, ['candles', 'ohlc', 'klines', 'bars']) ?? (isObject(r['chart']) ? r['chart'] : undefined));\n let series = readSeries(pick(r, ['series', 'prices', 'history', 'chart', 'points', 'sparkline']) ?? sparkline7d);\n if (!series.length && candles.length) series = candles.map((c) => (c.time ? { value: c.close, time: c.time } : { value: c.close }));\n const price = num(pick(r, ['price', 'regularMarketPrice', '05. price', 'current_price', 'lastPrice', 'last', 'c'])) ?? series[series.length - 1]?.value;\n if (price === undefined) return null;\n\n let change = num(pick(r, ['change', 'regularMarketChange', '09. change', 'price_change_24h', 'd']));\n let changePercent = percentOf(pick(r, [\n 'changePercent', 'change_percent', 'percentChange', 'percent_change', 'changesPercentage',\n 'regularMarketChangePercent', '10. change percent', 'price_change_percentage_24h', 'dp',\n ]));\n let previousClose = num(pick(r, ['previousClose', 'previous_close', 'prevClose', 'regularMarketPreviousClose', '08. previous close', 'pc']));\n // Yahoo's chart names the close before its FIRST point `chartPreviousClose`: yesterday's\n // over a day, the close of a year ago over a year. Read as the previous close past a day,\n // it made the change the year's (+73.23) beside the day's percent (-1.23 %). Past a day\n // there is no day's close in that answer, and none is invented.\n if (previousClose === undefined && str(r['range'])?.toLowerCase() === '1d') previousClose = num(r['chartPreviousClose']);\n // Finnhub answers an unknown symbol with zeros: no price and no close is no quote.\n if (price === 0 && !previousClose) return null;\n if (previousClose === 0) previousClose = undefined;\n\n let guessed = false;\n if (change === undefined && previousClose !== undefined) change = price - previousClose;\n if (previousClose === undefined && change !== undefined && price - change !== 0) previousClose = price - change;\n if (previousClose === undefined && changePercent !== undefined && changePercent !== -100) {\n previousClose = price / (1 + changePercent / 100);\n guessed = true;\n }\n if (changePercent === undefined && change !== undefined && previousClose) changePercent = (change / previousClose) * 100;\n\n const range = str(pick(r, ['range', 'period', 'timeframe'])) ?? (sparkline7d && series.length ? '7D' : undefined);\n const positive = (value: unknown) => {\n const n = num(value);\n return n !== undefined && n >= 0 ? n : undefined;\n };\n const fields = {\n name: str(pick(r, ['name', 'shortName', 'longName', 'displayName', 'companyName', 'company_name'])),\n exchange: str(pick(r, ['exchange', 'fullExchangeName', 'exchangeName', 'exchange_name'])),\n currency: currencyCode(pick(r, ['currency', 'currency_code', 'currencyCode', 'financialCurrency'])),\n change,\n changePercent,\n previousClose,\n open: num(pick(r, ['open', 'regularMarketOpen', '02. open', 'o'])),\n high: num(pick(r, ['high', 'dayHigh', 'regularMarketDayHigh', '03. high', 'high_24h', 'h'])),\n low: num(pick(r, ['low', 'dayLow', 'regularMarketDayLow', '04. low', 'low_24h', 'l'])),\n volume: positive(pick(r, ['volume', 'regularMarketVolume', '06. volume', 'total_volume'])),\n marketCap: positive(pick(r, ['marketCap', 'market_cap', 'marketCapitalization', 'MarketCapitalization'])),\n yearHigh: num(pick(r, ['yearHigh', 'fiftyTwoWeekHigh', '52WeekHigh', 'week52High', 'high52', 'year_high'])),\n yearLow: num(pick(r, ['yearLow', 'fiftyTwoWeekLow', '52WeekLow', 'week52Low', 'low52', 'year_low'])),\n range,\n ranges: Array.isArray(r['ranges']) ? [...new Set(r['ranges'].map(str).filter((x): x is string => x !== undefined))].slice(0, 8) : undefined,\n marketState: readMarketState(r),\n time: readTime(pick(r, ['time', 'asOf', 'as_of', 'timestamp', 'updatedAt', 'updated_at', 'lastUpdated', 'last_updated', 'regularMarketTime', '07. latest trading day', 't'])),\n url: webUrl(pick(r, ['url', 'link', 'href'])) ?? undefined,\n };\n const quote: Quote = { symbol, price, series, candles };\n for (const [key, value] of Object.entries(fields)) {\n if (value !== undefined && !(Array.isArray(value) && value.length === 0)) (quote as unknown as Raw)[key] = value;\n }\n // A 52-week range the wrong way round, or flat, is no range.\n if (quote.yearHigh === undefined || quote.yearLow === undefined || quote.yearHigh <= quote.yearLow) {\n delete quote.yearHigh;\n delete quote.yearLow;\n }\n if (guessed || (r as Record<symbol, unknown>)[ESTIMATED] === true) (quote as unknown as Record<symbol, unknown>)[ESTIMATED] = true;\n return quote;\n}\n\n/**\n * The card's data from the loose shape `map` returns — one quote, a list, or\n * `{ title, quotes }` (also `results`, `items`, `data`, Yahoo's `quoteResponse.result`,\n * Alpha Vantage's `Global Quote`) — or `null` when not one quote has a symbol and a price.\n * At most twelve are kept.\n */\nexport function readQuotes(raw: unknown): StockData | null {\n if (!raw || typeof raw !== 'object') return null;\n let list: unknown[];\n let title: string | undefined;\n if (Array.isArray(raw)) {\n list = raw;\n } else {\n const r = raw as Raw;\n const single = readQuote(r);\n if (single) return { quotes: [single] };\n const yahoo = isObject(r['quoteResponse']) ? r['quoteResponse']['result'] : undefined;\n const yahooChart = isObject(r['chart']) ? r['chart']['result'] : undefined;\n const many = [r['quotes'], r['results'], r['items'], r['watchlist'], r['data'], yahoo, yahooChart].find(Array.isArray);\n if (many) {\n list = many;\n title = str(pick(r, ['title', 'heading', 'name']));\n } else {\n list = [r['Global Quote']];\n }\n }\n const quotes = list.map(readQuote).filter((q): q is Quote => q !== null).slice(0, QUOTES_SHOWN);\n return quotes.length ? { ...(title ? { title } : {}), quotes } : null;\n}\n\n/** Which way a quote moved; `undefined` when the tool said nothing of it. */\nexport function directionOf(quote: Pick<Quote, 'change' | 'changePercent'>): 'up' | 'down' | 'flat' | undefined {\n const moved = quote.change ?? quote.changePercent;\n if (moved === undefined) return undefined;\n return moved > 0 ? 'up' : moved < 0 ? 'down' : 'flat';\n}\n\n/**\n * What the chart is split at. The previous close, for a day's chart (a range of one day,\n * or none said): that is what the day's change is measured against. For a longer range,\n * where the series started — yesterday's close in the middle of a year is a line nothing\n * on the chart relates to.\n */\nexport function baselineOf(quote: Quote): { value: number; kind: 'close' | 'start' } | undefined {\n const intraday = !quote.range || /^(1\\s*d(ay)?|today|intraday)$/i.test(quote.range.trim());\n if (intraday && quote.previousClose !== undefined) return { value: quote.previousClose, kind: 'close' };\n const first = quote.series[0];\n return first ? { value: first.value, kind: 'start' } : undefined;\n}\n\n// ── Formatting ───────────────────────────────────────────────────────────────\n\nconst minorCache = new Map<string, number>();\n\n/** The currency's own decimals: 2 for the dollar, 0 for the yen. */\nfunction minorDigits(currency?: string): number {\n if (!currency) return 2;\n let digits = minorCache.get(currency);\n if (digits === undefined) {\n try {\n digits = new Intl.NumberFormat('en', { style: 'currency', currency }).resolvedOptions().maximumFractionDigits ?? 2;\n } catch {\n digits = 2;\n }\n minorCache.set(currency, digits);\n }\n return digits;\n}\n\nfunction decimalsOf(n: number): number {\n const [mantissa, exponent] = String(Math.abs(n)).split('e');\n const decimals = (mantissa!.split('.')[1] ?? '').length;\n return Math.max(0, decimals - Number(exponent ?? 0));\n}\n\n/**\n * How many decimals a quote's prices are written with. The currency's own (2, 0 for the\n * yen) at least; more where the price needs them — a currency pair is read to four\n * (`1.0832`), a coin under one to four significant digits (`0.00001234`). A float's noise\n * (`182.52999877929688`) is not precision: past four decimals the price is rounded.\n */\nexport function digitsOf(quote: Pick<Quote, 'price' | 'currency'>): number {\n const base = minorDigits(quote.currency);\n const abs = Math.abs(quote.price);\n const given = decimalsOf(quote.price);\n if (abs > 0 && abs < 1) return Math.min(Math.max(base, given), Math.floor(-Math.log10(abs)) + 4, 8);\n if (abs >= 10) return Math.max(base, Math.min(given, 2));\n if (given <= base) return base;\n return Math.min(given, 4);\n}\n\n/** A price in the quote's precision, without its currency: the big number, the figures. */\nfunction plain(config: AparteConfig, quote: Quote, value: number): string {\n const d = digitsOf(quote);\n return formatNumber(config, value, { minimumFractionDigits: d, maximumFractionDigits: d });\n}\n\n/** A price with its currency's symbol, for a row or a tick: `$182.52`, `€45.13`. */\nfunction money(config: AparteConfig, quote: Quote, value: number): string {\n if (!quote.currency) return plain(config, quote, value);\n const d = digitsOf(quote);\n try {\n return formatNumber(config, value, { style: 'currency', currency: quote.currency, currencyDisplay: 'narrowSymbol', minimumFractionDigits: d, maximumFractionDigits: d });\n } catch {\n return `${plain(config, quote, value)} ${quote.currency}`;\n }\n}\n\n/** `+0.68%`, with its sign whichever way it went. */\nfunction percentText(config: AparteConfig, percent: number): string {\n return formatNumber(config, percent / 100, { style: 'percent', minimumFractionDigits: 2, maximumFractionDigits: 2, signDisplay: 'exceptZero' });\n}\n\nfunction changeText(config: AparteConfig, quote: Quote, short: boolean): string {\n const absolute = quote.change !== undefined\n ? formatNumber(config, quote.change, { minimumFractionDigits: digitsOf(quote), maximumFractionDigits: digitsOf(quote), signDisplay: 'exceptZero' })\n : undefined;\n const percent = quote.changePercent !== undefined ? percentText(config, quote.changePercent) : undefined;\n if (short) return (percent ?? absolute)!;\n return absolute && percent ? `${absolute} (${percent})` : (absolute ?? percent)!;\n}\n\n/** Large numbers the way a market page writes them: `52.3M`, `2.85 Bio. $`. */\nfunction compact(config: AparteConfig, value: number, currency?: string): string {\n const options: Intl.NumberFormatOptions = { notation: 'compact', maximumFractionDigits: 2 };\n if (currency) {\n try {\n return formatNumber(config, value, { ...options, style: 'currency', currency, currencyDisplay: 'narrowSymbol' });\n } catch {\n // A currency `Intl` does not know: the number alone.\n }\n }\n return formatNumber(config, value, options);\n}\n\nconst UNITS: Record<string, string> = { d: 'day', w: 'week', m: 'month', y: 'year' };\n\n/** `1D` → \"1 day\", `6M` → \"6 months\", in the chat's language; a label of the tool's own as it wrote it. */\nfunction rangeText(config: AparteConfig, range: string): string {\n const match = /^(\\d+)\\s*(d|days?|w|wks?|weeks?|m|mo|mos|mons?|months?|y|yrs?|years?)$/i.exec(range.trim());\n if (!match) return range;\n try {\n return formatNumber(config, Number(match[1]), { style: 'unit', unit: UNITS[match[2]!.charAt(0).toLowerCase()]!, unitDisplay: 'long' });\n } catch {\n return range;\n }\n}\n\n/**\n * A range on its button: the language's narrow unit (`5d`, `1 mese`, `1年`), and a one- or\n * two-letter abbreviation tightened into capitals the way a market's own buttons write it\n * (`5D`, `1M`, `5J`, `1Г`). The full words are the button's accessible name.\n */\nfunction rangeShort(config: AparteConfig, range: string): string {\n const match = /^(\\d+)\\s*(d|days?|w|wks?|weeks?|m|mo|mos|mons?|months?|y|yrs?|years?)$/i.exec(range.trim());\n if (!match) return range;\n let text: string;\n try {\n text = formatNumber(config, Number(match[1]), { style: 'unit', unit: UNITS[match[2]!.charAt(0).toLowerCase()]!, unitDisplay: 'narrow' }).replace(/\\.$/, '');\n } catch {\n return range;\n }\n return /^\\d+\\s?\\p{L}{1,2}$/u.test(text) ? text.replace(/\\s/g, '').toLocaleUpperCase(intlTag(config)) : text;\n}\n\n/** \"As of\" time: the hour today, the day for a close written as a date, the day and hour otherwise. */\nfunction whenText(config: AparteConfig, date: Date, now = new Date()): string {\n const tag = intlTag(config);\n const dayOnly = !date.getHours() && !date.getMinutes() && !date.getSeconds();\n const sameYear = date.getFullYear() === now.getFullYear();\n if (dayOnly) return new Intl.DateTimeFormat(tag, { month: 'short', day: 'numeric', year: sameYear ? undefined : 'numeric' }).format(date);\n if (date.toDateString() === now.toDateString()) return formatHour(config, date);\n return new Intl.DateTimeFormat(tag, { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }).format(date);\n}\n\n/** A point's time under the cursor, as fine as the series is long. */\nfunction pointTime(config: AparteConfig, date: Date, span: number): string {\n const tag = intlTag(config);\n if (span <= 36 * 3_600_000) return formatHour(config, date);\n if (span <= 8 * 86_400_000) return formatWhen(config, date);\n if (span <= 400 * 86_400_000) return new Intl.DateTimeFormat(tag, { month: 'short', day: 'numeric' }).format(date);\n return new Intl.DateTimeFormat(tag, { month: 'short', year: 'numeric' }).format(date);\n}\n\n// ── Drawing ──────────────────────────────────────────────────────────────────\n\nconst notNull = <T>(value: T | null | undefined | false): value is T => value !== null && value !== undefined && value !== false;\n\n/** The symbol, a link out when the quote has a URL. */\nfunction symbolOf(quote: Quote, stretched = false): HTMLElement {\n if (!quote.url) return el('span', { class: 'aparte-stock__symbol', text: quote.symbol });\n return el('a', {\n class: `aparte-stock__symbol aparte-stock__link${stretched ? ' aparte-stock__link--stretched' : ''}`,\n attrs: { href: quote.url, target: '_blank', rel: 'noopener noreferrer' },\n text: quote.symbol,\n });\n}\n\n/** The change: an arrow and a signed number, in the change's colour — the sign says it without the colour. */\nfunction changePill(ctx: CardContext, quote: Quote, short = false): HTMLElement | null {\n const direction = directionOf(quote);\n if (!direction) return null;\n const pill = el('span', { class: 'aparte-stock__change', attrs: { 'data-direction': direction } });\n if (direction !== 'flat') pill.append(glyph(direction === 'up' ? UP : DOWN, 'aparte-rich-card__glyph aparte-stock__arrow'));\n const text = el('span', { class: 'aparte-stock__change-text' });\n ctx.bind(text, () => changeText(ctx.config, quote, short));\n pill.append(text);\n return pill;\n}\n\nfunction marketOf(ctx: CardContext, quote: Quote): HTMLElement | null {\n if (!quote.marketState) return null;\n const text = el('span', { class: 'aparte-stock__market-text' });\n ctx.word(text, MARKET_WORD[quote.marketState], S[MARKET_WORD[quote.marketState]]);\n return el('span', { class: 'aparte-stock__market', attrs: { 'data-market': quote.marketState } },\n el('span', { class: 'aparte-stock__market-dot', attrs: { 'aria-hidden': 'true' } }),\n text);\n}\n\nfunction asOf(ctx: CardContext, quote: Quote): HTMLElement | null {\n if (!quote.time) return null;\n const time = quote.time;\n const node = el('time', { class: 'aparte-stock__time', attrs: { datetime: time.toISOString() } });\n ctx.bind(node, () => word(ctx.config, 'cardsStockAsOf', S.cardsStockAsOf, { time: whenText(ctx.config, time) }));\n return node;\n}\n\nfunction head(ctx: CardContext, quote: Quote): HTMLElement {\n const meta = [\n quote.exchange ? el('span', { class: 'aparte-stock__exchange', text: quote.exchange }) : null,\n marketOf(ctx, quote),\n asOf(ctx, quote),\n ].filter(notNull);\n return el('div', { class: 'aparte-stock__head' },\n el('div', { class: 'aparte-stock__id' },\n symbolOf(quote),\n quote.name ? el('span', { class: 'aparte-stock__name', text: quote.name }) : null),\n meta.length ? el('div', { class: 'aparte-stock__meta' }, ...meta) : null);\n}\n\nfunction chartLabel(ctx: CardContext, quote: Quote, low: number, high: number, last: number): string {\n const vars = {\n low: plain(ctx.config, quote, low),\n high: plain(ctx.config, quote, high),\n last: plain(ctx.config, quote, last),\n range: quote.range ? rangeText(ctx.config, quote.range) : '',\n };\n return quote.range ? word(ctx.config, 'cardsStockChartRange', S.cardsStockChartRange, vars) : word(ctx.config, 'cardsStockChart', S.cardsStockChart, vars);\n}\n\n/** How long the points cover, for how finely their times are written. */\nfunction spanOf(times: Array<Date | undefined>): number {\n const known = times.filter(notNull);\n return known.length > 1 ? known[known.length - 1]!.getTime() - known[0]!.getTime() : 0;\n}\n\n/** The range under the chart, unless the buttons over it already say which is pressed. */\nfunction rangeChip(ctx: CardContext, quote: Quote): HTMLElement | null {\n if (!quote.range || (ctx.live && quote.ranges?.length)) return null;\n const range = el('span', { class: 'aparte-stock__range' });\n const value = quote.range;\n ctx.bind(range, () => rangeText(ctx.config, value));\n return range;\n}\n\n/** The candlestick chart, with its range under it. */\nfunction candlesOf(ctx: CardContext, quote: Quote): HTMLElement | null {\n const { candles } = quote;\n const value = (v: number) => plain(ctx.config, quote, v);\n const span = spanOf(candles.map((c) => c.time));\n const low = Math.min(...candles.map((c) => c.low));\n const high = Math.max(...candles.map((c) => c.high));\n return candleChart(ctx, {\n candles,\n value,\n time: (d) => pointTime(ctx.config, d, span),\n ohlc: (c) => {\n const vars = { open: value(c.open), high: value(c.high), low: value(c.low), close: value(c.close) };\n return { shown: word(ctx.config, 'cardsStockOhlc', S.cardsStockOhlc, vars), spoken: word(ctx.config, 'cardsStockOhlcSaid', S.cardsStockOhlcSaid, vars) };\n },\n label: () => chartLabel(ctx, quote, low, high, candles[candles.length - 1]!.close),\n info: [rangeChip(ctx, quote)].filter(notNull),\n });\n}\n\n/** The chart, with its range and its baseline's legend under it — or, past a day, the range's own change. */\nfunction chartOf(ctx: CardContext, quote: Quote): HTMLElement | null {\n // Candles when they were asked for and given; the line otherwise, from the series or the closes.\n if (ctx.variant === 'candles' && quote.candles.length) return candlesOf(ctx, quote);\n const base = baselineOf(quote);\n if (!base || quote.series.length < 2) return null;\n const info: Node[] = [];\n const chip = rangeChip(ctx, quote);\n if (chip) info.push(chip);\n if (base.kind === 'close') {\n const text = el('span', { class: 'aparte-stock__legend-text' });\n ctx.bind(text, () => `${word(ctx.config, 'cardsStockPrevClose', S.cardsStockPrevClose)} ${plain(ctx.config, quote, base.value)}`);\n info.push(el('span', { class: 'aparte-stock__legend' }, el('span', { class: 'aparte-stock__legend-line', attrs: { 'aria-hidden': 'true' } }), text));\n } else if (base.value !== 0) {\n const last = quote.series[quote.series.length - 1]!.value;\n const moved = ((last - base.value) / Math.abs(base.value)) * 100;\n const over = changePill(ctx, { ...quote, change: undefined, changePercent: moved }, true);\n if (over) {\n over.classList.add('aparte-stock__change--range');\n info.push(over);\n }\n }\n const span = spanOf(quote.series.map((p) => p.time));\n const values = quote.series.map((p) => p.value);\n return priceChart(ctx, {\n points: quote.series,\n baseline: base.value,\n value: (v) => plain(ctx.config, quote, v),\n time: (d) => pointTime(ctx.config, d, span),\n label: () => chartLabel(ctx, quote, Math.min(...values), Math.max(...values), values[values.length - 1]!),\n live: quote.marketState === 'open',\n info,\n });\n}\n\n/** The day's figures, then the 52-week range as a bar with the price on it. */\nfunction stats(ctx: CardContext, quote: Quote): HTMLElement | null {\n const list = el('dl', { class: 'aparte-stock__stats' });\n const stat = (key: keyof typeof S, compute: () => string, extra?: HTMLElement) => {\n const term = el('dt', { class: 'aparte-stock__stat-term' });\n ctx.word(term, key, S[key]);\n const value = el('dd', { class: 'aparte-stock__stat-value' });\n if (extra) value.append(extra);\n else ctx.bind(value, compute);\n list.append(el('div', { class: `aparte-stock__stat${extra ? ' aparte-stock__stat--wide' : ''}` }, term, value));\n };\n const figure = (value: number | undefined) => (value === undefined ? undefined : () => plain(ctx.config, quote, value));\n const rows: Array<[keyof typeof S, (() => string) | undefined]> = [\n ['cardsStockOpen', figure(quote.open)],\n ['cardsStockHigh', figure(quote.high)],\n ['cardsStockLow', figure(quote.low)],\n ['cardsStockPrevClose', isEstimated(quote) ? undefined : figure(quote.previousClose)],\n ['cardsStockVolume', quote.volume === undefined ? undefined : () => compact(ctx.config, quote.volume!)],\n ['cardsStockMarketCap', quote.marketCap === undefined ? undefined : () => compact(ctx.config, quote.marketCap!, quote.currency)],\n ];\n for (const [key, compute] of rows) if (compute) stat(key, compute);\n if (quote.yearLow !== undefined && quote.yearHigh !== undefined) {\n const { yearLow: low, yearHigh: high } = quote;\n const position = Math.max(0, Math.min(1, (quote.price - low) / (high - low)));\n const bar = el('span', { class: 'aparte-stock__year-bar', attrs: { 'aria-hidden': 'true' } },\n el('span', { class: 'aparte-stock__year-mark' }));\n bar.style.setProperty('--aparte-stock-position', `${(position * 100).toFixed(1)}%`);\n const lowText = el('span', { class: 'aparte-stock__year-low' });\n ctx.bind(lowText, () => plain(ctx.config, quote, low));\n const highText = el('span', { class: 'aparte-stock__year-high' });\n ctx.bind(highText, () => plain(ctx.config, quote, high));\n // The two ends are text; the bar between them only places the price, which is written above.\n stat('cardsStockYearRange', () => '', el('span', { class: 'aparte-stock__year' }, lowText, bar, highText));\n }\n return list.childNodes.length ? list : null;\n}\n\n/**\n * The range buttons, when the app serves ranges (`ctx.live` and `quote.ranges`). They sit\n * over the chart, across its width: they change the chart, so they are on its edge — where\n * a market's own app puts them — and stretched, every range is a fair target for a thumb\n * and the row reads as the chart's own tabs. Over it rather than under it, because the\n * line under the plot is the readout's while the chart is explored. They are drawn even\n * when the new range came back without a chart, so another can be chosen.\n */\nfunction rangesOf(ctx: CardContext, quote: Quote): HTMLElement | null {\n const ranges = quote.ranges ?? [];\n const pressed = ranges.find((r) => r.toLowerCase() === quote.range?.toLowerCase()) ?? quote.range;\n const group = segmented(ctx, {\n name: 'range',\n value: pressed,\n options: ranges.map((r) => ({ value: r, label: () => rangeShort(ctx.config, r) })),\n label: () => word(ctx.config, 'cardsStockRange', S.cardsStockRange),\n });\n if (!group) return null;\n // \"1M\" on the button, \"1 month\" to a screen reader.\n group.querySelectorAll('button').forEach((button, i) => ctx.bind(button, () => rangeText(ctx.config, ranges[i]!), 'aria-label'));\n return el('div', { class: 'aparte-stock__ranges' }, group);\n}\n\n/** The `chart` and `candles` variants: one quote at length. */\nfunction chartCard(ctx: CardContext, quote: Quote): HTMLElement {\n const price = el('span', { class: 'aparte-stock__price' });\n ctx.bind(price, () => plain(ctx.config, quote, quote.price));\n const amount = el('span', { class: 'aparte-stock__amount' },\n price,\n quote.currency ? el('span', { class: 'aparte-stock__currency', text: quote.currency }) : null);\n return el('div', { class: 'aparte-stock aparte-stock--chart', attrs: { 'data-direction': directionOf(quote) } },\n head(ctx, quote),\n el('div', { class: 'aparte-stock__quote' }, amount, changePill(ctx, quote)),\n rangesOf(ctx, quote),\n chartOf(ctx, quote),\n stats(ctx, quote));\n}\n\n/** A sparkline in the change's colour, over the dashed baseline the chart would use. */\nfunction sparkOf(quote: Quote): SVGSVGElement | null {\n const base = baselineOf(quote);\n if (!base || quote.series.length < 2) return null;\n const values = thin(quote.series, 64).map((p) => p.value);\n const lo = Math.min(...values, base.value);\n const hi = Math.max(...values, base.value);\n const pad = 0.12;\n const svg = sparkline(values, { className: 'aparte-stock__sparkline', range: [lo, hi], pad });\n // The kit draws in a 100 × 40 box; the baseline is placed by the same rule.\n const y = hi === lo ? 20 : 40 - (pad * 40 + ((base.value - lo) / (hi - lo)) * (40 - 2 * pad * 40));\n const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n for (const [name, value] of Object.entries({ x1: 0, x2: 100, y1: y.toFixed(2), y2: y.toFixed(2), 'vector-effect': 'non-scaling-stroke' })) line.setAttribute(name, String(value));\n line.setAttribute('class', 'aparte-stock__spark-base');\n svg.prepend(line);\n return svg;\n}\n\n/** The `compact` variant's row: symbol and name, sparkline, price and change. */\nfunction row(ctx: CardContext, quote: Quote): HTMLElement {\n const price = el('span', { class: 'aparte-stock__row-price' });\n ctx.bind(price, () => money(ctx.config, quote, quote.price));\n const spark = sparkOf(quote);\n return el('div', { class: 'aparte-stock aparte-stock--row', attrs: { 'data-direction': directionOf(quote), 'data-linked': quote.url !== undefined } },\n el('div', { class: 'aparte-stock__id' },\n symbolOf(quote, true),\n quote.name ? el('span', { class: 'aparte-stock__name', text: quote.name }) : null),\n el('div', { class: 'aparte-stock__spark', attrs: { 'data-empty': !spark } }, spark),\n el('div', { class: 'aparte-stock__figures' }, price, changePill(ctx, quote, true)));\n}\n\n/** The `ticker` variant: a strip of symbol, price and change, scrolled by hand. */\nfunction ticker(ctx: CardContext, data: StockData): HTMLElement {\n const tape = el('ul', { class: 'aparte-stock__tape', attrs: { role: 'list', tabindex: 0 } });\n ctx.bind(tape, () => labelOf(data, ctx), 'aria-label');\n for (const quote of data.quotes) {\n const price = el('span', { class: 'aparte-stock__tick-price' });\n ctx.bind(price, () => money(ctx.config, quote, quote.price));\n tape.append(el('li', { class: 'aparte-stock__tick', attrs: { 'data-direction': directionOf(quote), 'data-linked': quote.url !== undefined } },\n symbolOf(quote, true), price, changePill(ctx, quote, true)));\n }\n return el('div', { class: 'aparte-stock__ticker' }, tape);\n}\n\nfunction heading(data: StockData): HTMLElement | null {\n return data.title ? el('div', { class: 'aparte-stock__heading', text: data.title }) : null;\n}\n\nfunction labelOf(data: Partial<StockData> | null, ctx: CardContext): string {\n const quotes = data?.quotes ?? [];\n if (quotes.length === 1) return quotes[0]!.name ? `${quotes[0]!.symbol} ${quotes[0]!.name}` : quotes[0]!.symbol;\n if (data?.title) return data.title;\n if (quotes.length > 1) return word(ctx.config, 'cardsStockCount', S.cardsStockCount, { n: formatNumber(ctx.config, quotes.length) });\n return word(ctx.config, 'cardsStockTitle', S.cardsStockTitle);\n}\n\nfunction render(data: StockData, ctx: CardContext<StockVariant>): Node[] {\n const { quotes } = data;\n if (ctx.variant === 'ticker') return [heading(data), ticker(ctx, data)].filter(notNull);\n if (quotes.length === 1) return [ctx.variant === 'compact' ? row(ctx, quotes[0]!) : chartCard(ctx, quotes[0]!)];\n const list = el('ul', { class: 'aparte-stock__list', attrs: { role: 'list' } },\n ...quotes.map((q) => el('li', { class: 'aparte-stock__item' }, row(ctx, q))));\n return [heading(data), list].filter(notNull);\n}\n\nfunction skeleton(partial: Partial<StockData> | null, ctx: CardContext<StockVariant>): Node[] {\n const block = (cls: string, kind: 'text' | 'rect' = 'text') =>\n el('span', { class: `aparte-skeleton aparte-skeleton--${kind} ${cls}`, attrs: { 'aria-hidden': 'true' } });\n // The symbols the call asked for, before their prices are in.\n const symbols = partial?.title ? partial.title.split(/,\\s*/).filter(Boolean) : [];\n const symbol = (text?: string) => (text ? el('span', { class: 'aparte-stock__symbol', text }) : block('aparte-stock__sk-symbol'));\n\n if (ctx.variant === 'ticker') {\n const ticks = Array.from({ length: Math.max(4, symbols.length) }, (_, i) =>\n el('li', { class: 'aparte-stock__tick aparte-stock__tick--skeleton' }, symbol(symbols[i]), block('aparte-stock__sk-figure')));\n return [el('div', { class: 'aparte-stock__ticker' }, el('ul', { class: 'aparte-stock__tape', attrs: { role: 'list' } }, ...ticks))];\n }\n if (ctx.variant === 'compact' || symbols.length > 1) {\n const rows = Array.from({ length: Math.max(3, Math.min(symbols.length, QUOTES_SHOWN)) }, (_, i) =>\n el('li', { class: 'aparte-stock__item' },\n el('div', { class: 'aparte-stock aparte-stock--row aparte-stock--skeleton' },\n el('div', { class: 'aparte-stock__id' }, symbol(symbols[i]), block('aparte-stock__sk-name')),\n block('aparte-stock__spark aparte-stock__sk-spark', 'rect'),\n el('div', { class: 'aparte-stock__figures' }, block('aparte-stock__sk-figure'), block('aparte-stock__sk-pill')))));\n return [el('ul', { class: 'aparte-stock__list', attrs: { role: 'list' } }, ...rows)];\n }\n return [el('div', { class: 'aparte-stock aparte-stock--chart aparte-stock--skeleton' },\n el('div', { class: 'aparte-stock__head' }, el('div', { class: 'aparte-stock__id' }, symbol(symbols[0]), block('aparte-stock__sk-name'))),\n el('div', { class: 'aparte-stock__quote' }, block('aparte-stock__sk-price'), block('aparte-stock__sk-pill')),\n block('aparte-stock__sk-chart', 'rect'),\n el('div', { class: 'aparte-stock__stats' }, ...Array.from({ length: 6 }, () => el('div', { class: 'aparte-stock__stat' }, block('aparte-stock__sk-term'), block('aparte-stock__sk-figure')))))];\n}\n\nexport const stockCard = defineCard<StockData, StockVariant>({\n name: 'stock',\n variants: ['chart', 'compact', 'ticker', 'candles'],\n styles: stockStyles,\n icon: CHART,\n normalize: readQuotes,\n render,\n skeleton,\n label: labelOf,\n fallback: (data, ctx) => {\n // \"AAPL 182.52 USD, +1.23 (+0.68%)\": a line per quote, as a model would list them.\n const lines = data.quotes.map((q) => {\n const price = `${plain(ctx.config, q, q.price)}${q.currency ? ` ${q.currency}` : ''}`;\n return directionOf(q) ? `${q.symbol} ${price}, ${changeText(ctx.config, q, false)}` : `${q.symbol} ${price}`;\n });\n return [data.quotes.length > 1 ? data.title : undefined, ...lines].filter(notNull).join('\\n');\n },\n partial: (input) => {\n const raw = input['symbols'] ?? input['tickers'] ?? input['symbol'] ?? input['ticker'] ?? input['pair'];\n const list = (Array.isArray(raw) ? raw : typeof raw === 'string' ? raw.split(',') : [])\n .map((s) => str(s))\n .filter((s): s is string => s !== undefined)\n .map((s) => (/[A-Z]/.test(s) ? s : s.toUpperCase()));\n return list.length ? { title: list.slice(0, QUOTES_SHOWN).join(', ') } : null;\n },\n});\n\n/** Draw a tool's quotes as this card — returns the function that stops it. */\nexport function setupStockCard(options: CardSetupOptions<StockData, StockVariant> = {}): () => void {\n return stockCard.setup(options);\n}\n"],"names":["times","row"],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The weather a card knows how to draw, and the doors to it from the APIs a tool calls.
3
+ *
4
+ * A tool returns its own codes — WMO numbers from Open-Meteo, ids from OpenWeather, a
5
+ * sentence from elsewhere. The card draws eleven conditions; these functions turn a code
6
+ * into one of them, so an app's `map` is one call instead of a table.
7
+ */
8
+ import type { CardWord } from '../kit/strings.js';
9
+ export type WeatherCondition = 'clear' | 'partly-cloudy' | 'cloudy' | 'fog' | 'drizzle' | 'rain' | 'heavy-rain' | 'sleet' | 'snow' | 'thunder' | 'wind';
10
+ export declare const WEATHER_CONDITIONS: readonly WeatherCondition[];
11
+ /**
12
+ * A WMO weather code (Open-Meteo's `weather_code`) as a condition.
13
+ * https://open-meteo.com/en/docs — "WMO Weather interpretation codes".
14
+ */
15
+ export declare function conditionFromWmo(code: unknown): WeatherCondition | undefined;
16
+ /**
17
+ * An OpenWeather condition id (`weather[0].id`) as a condition.
18
+ * https://openweathermap.org/weather-conditions
19
+ */
20
+ export declare function conditionFromOpenWeather(id: unknown): WeatherCondition | undefined;
21
+ /** A description ("Light rain", "Partiellement nuageux") as a condition — English and French. */
22
+ export declare function conditionFromText(text: unknown): WeatherCondition | undefined;
23
+ /** What each condition is called, when the tool gives no description of its own. */
24
+ export declare const CONDITION_WORDS: Record<WeatherCondition, CardWord>;
25
+ //# sourceMappingURL=conditions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conditions.d.ts","sourceRoot":"","sources":["../../src/weather/conditions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,MAAM,gBAAgB,GACtB,OAAO,GACP,eAAe,GACf,QAAQ,GACR,KAAK,GACL,SAAS,GACT,MAAM,GACN,YAAY,GACZ,OAAO,GACP,MAAM,GACN,SAAS,GACT,MAAM,CAAC;AAEb,eAAO,MAAM,kBAAkB,EAAE,SAAS,gBAAgB,EAEzD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAc5E;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAgBlF;AAiBD,iGAAiG;AACjG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAM7E;AAED,oFAAoF;AACpF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,gBAAgB,EAAE,QAAQ,CAY9D,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The weather glyphs: one 64 × 64 drawing per condition, day and night, built from a few
3
+ * parts (sun, moon, cloud, drops, flakes, bolt). Coloured and animated by the sheet
4
+ * through their classes — `--aparte-weather-*` tokens, so a theme recolours the sky.
5
+ *
6
+ * They live here and not in core's `icons/`: core's set is what core draws, and core
7
+ * draws no weather. These are constants of the package, the only markup a card parses.
8
+ */
9
+ import type { WeatherCondition } from './conditions.js';
10
+ /** The glyph for a condition, by day or by night, as markup for `glyph()`. */
11
+ export declare function weatherIcon(condition: WeatherCondition, night?: boolean): string;
12
+ //# sourceMappingURL=icons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/weather/icons.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AA+BxD,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,SAAS,EAAE,gBAAgB,EAAE,KAAK,UAAQ,GAAG,MAAM,CAuC9E"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * @aparte/plugin-cards/weather — a tool's weather, drawn as a card.
3
+ *
4
+ * import { setupWeatherCard, fromOpenMeteo } from '@aparte/plugin-cards/weather';
5
+ *
6
+ * setupWeatherCard({
7
+ * tool: 'get_weather',
8
+ * map: (result) => fromOpenMeteo(result.forecast, { location: result.city }),
9
+ * });
10
+ *
11
+ * Three variants of one card: `hero` (the sky, the temperature, the next hours), `compact`
12
+ * (one line) and `forecast` (the days ahead, each with its range). Your tool keeps its
13
+ * own fields — `map` says which is which — and three readers turn the codes of the usual
14
+ * APIs into the card's conditions: `conditionFromWmo` (Open-Meteo), `conditionFromOpenWeather`
15
+ * and `conditionFromText`.
16
+ */
17
+ import type { AparteConfig } from '@aparte/core';
18
+ import { type CardSetupOptions } from '../kit/define.js';
19
+ import { type WeatherCondition } from './conditions.js';
20
+ export type WeatherVariant = 'hero' | 'compact' | 'forecast';
21
+ export type WindUnit = 'km/h' | 'mph' | 'm/s' | 'kn';
22
+ /** One hour ahead. */
23
+ export interface WeatherHour {
24
+ time: string | number | Date;
25
+ temperature: number;
26
+ condition?: WeatherCondition | string;
27
+ /** Chance of precipitation, 0–100. */
28
+ precipitation?: number;
29
+ /** OpenWeather's `pop`: the same chance as a share, 0–1, where `1` is certain rain. */
30
+ pop?: number;
31
+ night?: boolean;
32
+ }
33
+ /** One day ahead. */
34
+ export interface WeatherDay {
35
+ date: string | number | Date;
36
+ condition?: WeatherCondition | string;
37
+ high: number;
38
+ low: number;
39
+ /** Chance of precipitation, 0–100. */
40
+ precipitation?: number;
41
+ /** OpenWeather's `pop`: the same chance as a share, 0–1, where `1` is certain rain. */
42
+ pop?: number;
43
+ }
44
+ /**
45
+ * The weather card's fields — what `map` returns. Only `temperature` (or `daily`) is
46
+ * needed; every other field adds a line when it is there and nothing when it is not.
47
+ */
48
+ export interface WeatherInput {
49
+ location?: string;
50
+ /** One of the eleven conditions, or a description `conditionFromText` reads. */
51
+ condition?: WeatherCondition | string;
52
+ /** The tool's own description, in its own language; else the condition's name. */
53
+ summary?: string;
54
+ temperature?: number;
55
+ /** `C` (default) or `F` — `fahrenheit` and OpenWeather's `imperial` read as `F` too. */
56
+ unit?: 'C' | 'F' | 'fahrenheit' | 'imperial' | 'metric';
57
+ feelsLike?: number;
58
+ high?: number;
59
+ low?: number;
60
+ /** 0–100. */
61
+ humidity?: number;
62
+ /** A speed in `km/h`, or `{ speed, unit, direction }` — direction in degrees, where it blows from. */
63
+ wind?: number | {
64
+ speed: number;
65
+ unit?: WindUnit;
66
+ direction?: number;
67
+ };
68
+ /** Chance of precipitation, 0–100. */
69
+ precipitation?: number;
70
+ /** OpenWeather's `pop`: the same chance as a share, 0–1, where `1` is certain rain. */
71
+ pop?: number;
72
+ /** Draw the night sky and the moon. */
73
+ night?: boolean;
74
+ /** When this was measured. */
75
+ time?: string | number | Date;
76
+ hourly?: WeatherHour[];
77
+ daily?: WeatherDay[];
78
+ }
79
+ /** The data as the card draws it, once read. */
80
+ export interface WeatherData {
81
+ location?: string;
82
+ condition: WeatherCondition;
83
+ summary?: string;
84
+ temperature?: number;
85
+ unit: 'C' | 'F';
86
+ feelsLike?: number;
87
+ high?: number;
88
+ low?: number;
89
+ humidity?: number;
90
+ wind?: {
91
+ speed: number;
92
+ unit: WindUnit;
93
+ direction?: number;
94
+ };
95
+ precipitation?: number;
96
+ night: boolean;
97
+ time?: Date;
98
+ hourly: Array<{
99
+ time: Date;
100
+ temperature: number;
101
+ condition?: WeatherCondition;
102
+ precipitation?: number;
103
+ night: boolean;
104
+ }>;
105
+ daily: Array<{
106
+ date: Date;
107
+ condition: WeatherCondition;
108
+ high: number;
109
+ low: number;
110
+ precipitation?: number;
111
+ }>;
112
+ }
113
+ /** The card's data from the loose shape `map` returns, or `null` when there is no temperature to show. */
114
+ export declare function readWeather(raw: unknown): WeatherData | null;
115
+ /**
116
+ * Open-Meteo's forecast response (https://open-meteo.com/en/docs) as the card's fields.
117
+ * Ask it for `current=temperature_2m,apparent_temperature,relative_humidity_2m,is_day,
118
+ * weather_code,wind_speed_10m,wind_direction_10m`, `hourly=temperature_2m,weather_code,
119
+ * precipitation_probability` and `daily=weather_code,temperature_2m_max,temperature_2m_min,
120
+ * precipitation_probability_max`; whatever it lacks is left out. Open-Meteo returns no
121
+ * place name, so pass it.
122
+ *
123
+ * Its times carry no offset (`2026-10-31T14:00`): they are on the clock of the `timezone`
124
+ * you asked for, GMT by default, and the response says how far that is from UTC
125
+ * (`utc_offset_seconds`). They are read as the instants they are, so the hours show on the
126
+ * reader's own clock whatever the `timezone`; ask `timezone=auto` so the DAYS are the
127
+ * place's own (its "today", and each day's high and low).
128
+ */
129
+ export declare function fromOpenMeteo(response: unknown, options?: {
130
+ location?: string;
131
+ }): WeatherInput;
132
+ export declare const weatherCard: {
133
+ name: string;
134
+ variants: readonly WeatherVariant[];
135
+ setup: (options?: CardSetupOptions<WeatherData, WeatherVariant>) => () => void;
136
+ segment: (raw: unknown, options?: {
137
+ id?: string;
138
+ variant?: WeatherVariant | undefined;
139
+ config?: AparteConfig;
140
+ }) => import("../index.js").AparteCardSegment;
141
+ };
142
+ /** Draw a tool's weather as this card — returns the function that stops it. */
143
+ export declare function setupWeatherCard(options?: CardSetupOptions<WeatherData, WeatherVariant>): () => void;
144
+ export { conditionFromWmo, conditionFromOpenWeather, conditionFromText, WEATHER_CONDITIONS } from './conditions.js';
145
+ export type { WeatherCondition } from './conditions.js';
146
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/weather/index.ts"],"names":[],"mappings":"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"}