@aparte/plugin-cards 0.0.0-stage → 0.29.1

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 (105) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -2
  3. package/dist/carousel-DwgHvriV.js +63 -0
  4. package/dist/carousel-DwgHvriV.js.map +1 -0
  5. package/dist/controls-BYUm4aRV.js +62 -0
  6. package/dist/controls-BYUm4aRV.js.map +1 -0
  7. package/dist/format-BFq79ydr.js +728 -0
  8. package/dist/format-BFq79ydr.js.map +1 -0
  9. package/dist/index.d.ts +30 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +120 -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 +201 -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/fence.d.ts +39 -0
  28. package/dist/kit/fence.d.ts.map +1 -0
  29. package/dist/kit/format.d.ts +49 -0
  30. package/dist/kit/format.d.ts.map +1 -0
  31. package/dist/kit/rating.d.ts +19 -0
  32. package/dist/kit/rating.d.ts.map +1 -0
  33. package/dist/kit/sparkline.d.ts +19 -0
  34. package/dist/kit/sparkline.d.ts.map +1 -0
  35. package/dist/kit/strings.d.ts +139 -0
  36. package/dist/kit/strings.d.ts.map +1 -0
  37. package/dist/link/icons.d.ts +16 -0
  38. package/dist/link/icons.d.ts.map +1 -0
  39. package/dist/link/index.d.ts +98 -0
  40. package/dist/link/index.d.ts.map +1 -0
  41. package/dist/link.js +387 -0
  42. package/dist/link.js.map +1 -0
  43. package/dist/media/icons.d.ts +28 -0
  44. package/dist/media/icons.d.ts.map +1 -0
  45. package/dist/media/index.d.ts +107 -0
  46. package/dist/media/index.d.ts.map +1 -0
  47. package/dist/media.js +610 -0
  48. package/dist/media.js.map +1 -0
  49. package/dist/order/icons.d.ts +49 -0
  50. package/dist/order/icons.d.ts.map +1 -0
  51. package/dist/order/index.d.ts +204 -0
  52. package/dist/order/index.d.ts.map +1 -0
  53. package/dist/order.js +1843 -0
  54. package/dist/order.js.map +1 -0
  55. package/dist/place/icons.d.ts +18 -0
  56. package/dist/place/icons.d.ts.map +1 -0
  57. package/dist/place/index.d.ts +207 -0
  58. package/dist/place/index.d.ts.map +1 -0
  59. package/dist/place.js +1456 -0
  60. package/dist/place.js.map +1 -0
  61. package/dist/plan/icons.d.ts +25 -0
  62. package/dist/plan/icons.d.ts.map +1 -0
  63. package/dist/plan/index.d.ts +153 -0
  64. package/dist/plan/index.d.ts.map +1 -0
  65. package/dist/plan.js +1191 -0
  66. package/dist/plan.js.map +1 -0
  67. package/dist/product/icons.d.ts +16 -0
  68. package/dist/product/icons.d.ts.map +1 -0
  69. package/dist/product/index.d.ts +133 -0
  70. package/dist/product/index.d.ts.map +1 -0
  71. package/dist/product.js +1245 -0
  72. package/dist/product.js.map +1 -0
  73. package/dist/rating-CHVajQ2b.js +35 -0
  74. package/dist/rating-CHVajQ2b.js.map +1 -0
  75. package/dist/score/icons.d.ts +35 -0
  76. package/dist/score/icons.d.ts.map +1 -0
  77. package/dist/score/index.d.ts +185 -0
  78. package/dist/score/index.d.ts.map +1 -0
  79. package/dist/score.js +1843 -0
  80. package/dist/score.js.map +1 -0
  81. package/dist/sparkline-C-cA9obz.js +56 -0
  82. package/dist/sparkline-C-cA9obz.js.map +1 -0
  83. package/dist/stats/icons.d.ts +19 -0
  84. package/dist/stats/icons.d.ts.map +1 -0
  85. package/dist/stats/index.d.ts +137 -0
  86. package/dist/stats/index.d.ts.map +1 -0
  87. package/dist/stats.js +1085 -0
  88. package/dist/stats.js.map +1 -0
  89. package/dist/stock/chart.d.ts +135 -0
  90. package/dist/stock/chart.d.ts.map +1 -0
  91. package/dist/stock/icons.d.ts +15 -0
  92. package/dist/stock/icons.d.ts.map +1 -0
  93. package/dist/stock/index.d.ts +195 -0
  94. package/dist/stock/index.d.ts.map +1 -0
  95. package/dist/stock.js +1013 -0
  96. package/dist/stock.js.map +1 -0
  97. package/dist/weather/conditions.d.ts +25 -0
  98. package/dist/weather/conditions.d.ts.map +1 -0
  99. package/dist/weather/icons.d.ts +12 -0
  100. package/dist/weather/icons.d.ts.map +1 -0
  101. package/dist/weather/index.d.ts +146 -0
  102. package/dist/weather/index.d.ts.map +1 -0
  103. package/dist/weather.js +1162 -0
  104. package/dist/weather.js.map +1 -0
  105. package/package.json +137 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sources":["../src/stats/icons.ts","../src/stats/stats.css?raw","../src/stats/index.ts"],"sourcesContent":["/**\n * The stats card's glyphs: the six a figure may wear beside its label, and the card's own\n * for its one-line states.\n *\n * Drawn on a 24 × 24 grid in `currentColor` strokes, so the sheet colours them through\n * `color` and a theme follows. Constants of this package — the only markup the card parses.\n */\n\nconst svg = (body: string) =>\n `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linecap=\"round\" stroke-linejoin=\"round\" xmlns=\"http://www.w3.org/2000/svg\">${body}</svg>`; // safe-text: this package's own SVG, built from its glyph constants\n\n/** A coin stack: revenue, spend, a price. */\nconst MONEY = svg('<ellipse cx=\"12\" cy=\"6.5\" rx=\"6.5\" ry=\"2.7\"/><path d=\"M5.5 6.5v5c0 1.5 2.9 2.7 6.5 2.7s6.5-1.2 6.5-2.7v-5\"/><path d=\"M5.5 11.5v5c0 1.5 2.9 2.7 6.5 2.7s6.5-1.2 6.5-2.7v-5\"/>');\n\n/** Two people: users, visitors, customers. */\nconst USERS = svg('<circle cx=\"9\" cy=\"8.5\" r=\"3.2\"/><path d=\"M3.2 19.2c.6-3.1 2.9-5 5.8-5s5.2 1.9 5.8 5\"/><path d=\"M15.2 5.6a3.1 3.1 0 0 1 0 5.9\"/><path d=\"M17.4 14.5c1.9.6 3.1 2.3 3.4 4.7\"/>');\n\n/** A trolley: orders, carts, sales. */\nconst CART = svg('<path d=\"M3 4h2.2l2.1 10.4a1.6 1.6 0 0 0 1.6 1.3h8a1.6 1.6 0 0 0 1.6-1.2L20.2 8H6.1\"/><circle cx=\"9.5\" cy=\"19.3\" r=\"1.3\"/><circle cx=\"17\" cy=\"19.3\" r=\"1.3\"/>');\n\n/** A rising line on its axes: growth, a rate, anything charted. */\nconst CHART = svg('<path d=\"M4 4v15.5a.5.5 0 0 0 .5.5H20\"/><path d=\"M7.5 15.5l3.6-4.2 3 2.6 5.1-6.4\"/><path d=\"M16.3 7.5h2.9v2.9\"/>');\n\n/** A clock: a duration, a response time, an uptime. */\nconst CLOCK = svg('<circle cx=\"12\" cy=\"12\" r=\"8.2\"/><path d=\"M12 7.6V12l2.9 1.9\"/>');\n\n/** A star: a rating, a score, a favourite. */\nconst STAR = svg('<path d=\"M12 3.6l2.5 5.2 5.7.8-4.1 4 1 5.6L12 16.5l-5.1 2.7 1-5.6-4.1-4 5.7-.8z\"/>');\n\n/** The glyphs a figure may name in its `icon`. */\nexport const STAT_ICONS = { money: MONEY, users: USERS, cart: CART, chart: CHART, clock: CLOCK, star: STAR } as const;\n\n/** Three bars of rising height: the card's own glyph, for its one-line states. */\nexport const BARS = svg('<path d=\"M5 20V13.5\"/><path d=\"M12 20V8.5\"/><path d=\"M19 20V4.5\"/><path d=\"M3 20h18\"/>');\n","export default \"/* =========================================\\n The stats card — @aparte/plugin-cards/stats\\n =========================================\\n Three variants of one card, chosen by `data-variant` on its root:\\n tiles a tile per figure — label, big number, the change as a pill, a sparkline —\\n in a grid of two or three columns that drops to one on a narrow card.\\n list a fact sheet: the label at the start of each row, the value at its end.\\n hero the first figure large over a wide chart, the others small in a band under it.\\n A change is green when it went the way `good` says, red when not, neutral otherwise —\\n always with its arrow and its sign, so the colour is never the only one saying it.\\n Every colour is a theme token or derived from one, so light and dark follow the chat.\\n */\\n\\n.aparte-stats-card {\\n --aparte-stats-pad: var(--aparte-space-6);\\n --aparte-stats-good: var(--aparte-success);\\n --aparte-stats-good-ink: var(--aparte-success-ink);\\n --aparte-stats-bad: var(--aparte-error);\\n --aparte-stats-bad-ink: var(--aparte-error-ink);\\n --aparte-stats-neutral: var(--aparte-text-muted);\\n --aparte-stats-neutral-ink: var(--aparte-text-muted);\\n /* A figure with no change to judge it by: its line takes the theme's accent. */\\n --aparte-stats-accent: var(--aparte-primary);\\n --aparte-stats-tile-bg: color-mix(in oklab, var(--aparte-text) 3.5%, var(--aparte-surface-1));\\n --aparte-stats-tile-border: color-mix(in oklab, var(--aparte-border) 75%, transparent);\\n --aparte-stats-tile-hover-border: color-mix(in oklab, var(--aparte-text) 18%, var(--aparte-border));\\n --aparte-stats-band-bg: color-mix(in oklab, var(--aparte-text) 3%, var(--aparte-surface-1));\\n --aparte-stats-value-size: calc(1.75rem * var(--aparte-font-scale));\\n --aparte-stats-hero-value-size: calc(2.75rem * var(--aparte-font-scale));\\n}\\n\\n/* ── Widths: each variant asks for its own; the bubble's limit caps them all ── */\\n\\n.aparte-stats-card[data-variant=\\\"tiles\\\"] { --aparte-rich-card-max-inline-size: 28rem; }\\n.aparte-stats-card[data-variant=\\\"tiles\\\"]:has(.aparte-stats__tiles[data-columns=\\\"1\\\"]) { --aparte-rich-card-max-inline-size: 18rem; }\\n.aparte-stats-card[data-variant=\\\"tiles\\\"]:has(.aparte-stats__tiles[data-columns=\\\"3\\\"]) { --aparte-rich-card-max-inline-size: 36rem; }\\n.aparte-stats-card[data-variant=\\\"list\\\"] { --aparte-rich-card-max-inline-size: 26rem; }\\n.aparte-stats-card[data-variant=\\\"hero\\\"] { --aparte-rich-card-max-inline-size: 30rem; }\\n\\n/* ── Heading and footer ──────────────────────────────────────────────── */\\n\\n.aparte-stats__head {\\n display: flex;\\n flex-direction: column;\\n gap: var(--aparte-space-1);\\n padding: var(--aparte-stats-pad) var(--aparte-stats-pad) 0;\\n min-inline-size: 0;\\n}\\n\\n.aparte-stats__title {\\n font-size: var(--aparte-font-size-base);\\n font-weight: var(--aparte-font-weight-semibold);\\n color: var(--aparte-text);\\n overflow-wrap: anywhere;\\n}\\n\\n.aparte-stats__subtitle {\\n font-size: var(--aparte-font-size-sm);\\n color: var(--aparte-text-muted);\\n overflow-wrap: anywhere;\\n}\\n\\n.aparte-stats__body {\\n /* The grid inside reads the body's width, not the window's: a card in a narrow bubble\\n on a wide screen still drops to fewer columns. */\\n container: aparte-stats / inline-size;\\n padding: var(--aparte-space-5) var(--aparte-stats-pad) var(--aparte-stats-pad);\\n min-inline-size: 0;\\n}\\n\\n.aparte-stats__body:first-child { padding-block-start: var(--aparte-stats-pad); }\\n\\n.aparte-stats__foot {\\n display: flex;\\n flex-wrap: wrap;\\n align-items: baseline;\\n justify-content: space-between;\\n gap: var(--aparte-space-1) var(--aparte-space-4);\\n padding: var(--aparte-space-3) var(--aparte-stats-pad);\\n border-block-start: var(--aparte-border-width) solid var(--aparte-border);\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-xs);\\n}\\n\\n.aparte-stats__footnote { overflow-wrap: anywhere; }\\n.aparte-stats__updated { margin-inline-start: auto; white-space: nowrap; }\\n\\n/* ── A figure, whatever its shape ────────────────────────────────────── */\\n\\n.aparte-stats__stat {\\n --aparte-rich-card-spark: var(--aparte-stats-accent);\\n min-inline-size: 0;\\n}\\n\\n.aparte-stats__stat[data-tone=\\\"good\\\"] { --aparte-rich-card-spark: var(--aparte-stats-good); }\\n.aparte-stats__stat[data-tone=\\\"bad\\\"] { --aparte-rich-card-spark: var(--aparte-stats-bad); }\\n.aparte-stats__stat[data-tone=\\\"neutral\\\"] { --aparte-rich-card-spark: var(--aparte-stats-neutral); }\\n\\n.aparte-stats__label {\\n display: flex;\\n align-items: center;\\n gap: var(--aparte-space-2);\\n min-inline-size: 0;\\n margin: 0;\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-sm);\\n font-weight: var(--aparte-font-weight-medium);\\n line-height: 1.3;\\n}\\n\\n.aparte-stats__label-text { min-inline-size: 0; overflow-wrap: anywhere; }\\n\\n/* The glyph sits on a soft chip of the accent, like an app's own KPI icons. */\\n.aparte-stats__icon {\\n --aparte-rich-card-glyph-size: 1.5rem;\\n box-sizing: border-box;\\n padding: 0.3rem;\\n border-radius: var(--aparte-radius-md);\\n background: color-mix(in oklab, var(--aparte-stats-accent) 13%, transparent);\\n color: var(--aparte-stats-accent);\\n}\\n\\n.aparte-stats__value {\\n margin: 0;\\n min-inline-size: 0;\\n color: var(--aparte-text);\\n font-size: var(--aparte-stats-value-size);\\n font-weight: var(--aparte-font-weight-semibold);\\n font-variant-numeric: tabular-nums;\\n letter-spacing: -0.02em;\\n line-height: 1.1;\\n overflow-wrap: anywhere;\\n}\\n\\n/* A word, not a number: a size that does not shout. */\\n.aparte-stats__value[data-format=\\\"text\\\"] { letter-spacing: normal; }\\n\\n.aparte-stats__hint {\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-xs);\\n font-weight: var(--aparte-font-weight-normal);\\n line-height: 1.35;\\n overflow-wrap: anywhere;\\n}\\n\\n/* ── The change: a pill (arrow, signed number), then what it compares with ── */\\n\\n.aparte-stats__change {\\n --aparte-stats-tone: var(--aparte-stats-neutral);\\n --aparte-stats-tone-ink: var(--aparte-stats-neutral-ink);\\n display: flex;\\n flex-wrap: wrap;\\n align-items: center;\\n gap: var(--aparte-space-1) var(--aparte-space-2);\\n min-inline-size: 0;\\n font-size: var(--aparte-font-size-xs);\\n line-height: 1.3;\\n}\\n\\n.aparte-stats__change[data-tone=\\\"good\\\"] {\\n --aparte-stats-tone: var(--aparte-stats-good);\\n --aparte-stats-tone-ink: var(--aparte-stats-good-ink);\\n}\\n\\n.aparte-stats__change[data-tone=\\\"bad\\\"] {\\n --aparte-stats-tone: var(--aparte-stats-bad);\\n --aparte-stats-tone-ink: var(--aparte-stats-bad-ink);\\n}\\n\\n.aparte-stats__pill {\\n display: inline-flex;\\n align-items: center;\\n gap: 0.3em;\\n padding: 0.15em 0.55em;\\n border-radius: var(--aparte-radius-full);\\n background: color-mix(in oklab, var(--aparte-stats-tone) 14%, transparent);\\n color: var(--aparte-stats-tone-ink);\\n font-weight: var(--aparte-font-weight-semibold);\\n font-variant-numeric: tabular-nums;\\n white-space: nowrap;\\n}\\n\\n.aparte-stats__arrow {\\n font-size: 0.72em;\\n line-height: 1;\\n}\\n\\n/* Good or bad, as a shape: a check on a filled dot, an exclamation on a ring — told apart\\n without the colour. */\\n.aparte-stats__verdict {\\n display: inline-grid;\\n place-items: center;\\n inline-size: 1.15em;\\n block-size: 1.15em;\\n border-radius: 50%;\\n font-size: 0.78em;\\n font-weight: var(--aparte-font-weight-bold);\\n line-height: 1;\\n}\\n\\n.aparte-stats__change[data-tone=\\\"good\\\"] .aparte-stats__verdict {\\n background: var(--aparte-stats-tone-ink);\\n color: var(--aparte-surface-1);\\n}\\n\\n.aparte-stats__change[data-tone=\\\"bad\\\"] .aparte-stats__verdict {\\n box-shadow: inset 0 0 0 1.5px var(--aparte-stats-tone-ink);\\n}\\n\\n.aparte-stats__change-label {\\n min-inline-size: 0;\\n color: var(--aparte-text-muted);\\n overflow-wrap: anywhere;\\n}\\n\\n/* ── The sparkline ───────────────────────────────────────────────────── */\\n\\n.aparte-stats__spark { min-inline-size: 0; }\\n\\n/* The line draws itself in once, from where time starts. */\\n.aparte-stats__sparkline {\\n animation: aparte-stats-reveal 0.9s cubic-bezier(0.22, 1, 0.36, 1) both;\\n}\\n\\n@keyframes aparte-stats-reveal {\\n from { clip-path: inset(0 100% 0 0); }\\n to { clip-path: inset(0 0 0 0); }\\n}\\n\\n/* ── tiles ───────────────────────────────────────────────────────────── */\\n\\n.aparte-stats__tiles {\\n --aparte-stats-columns: 2;\\n display: grid;\\n grid-template-columns: repeat(var(--aparte-stats-columns), minmax(0, 1fr));\\n gap: var(--aparte-space-3);\\n margin: 0;\\n padding: 0;\\n list-style: none;\\n}\\n\\n.aparte-stats__tiles[data-columns=\\\"1\\\"] { --aparte-stats-columns: 1; }\\n.aparte-stats__tiles[data-columns=\\\"3\\\"] {\\n --aparte-stats-columns: 3;\\n --aparte-stats-value-size: calc(1.5rem * var(--aparte-font-scale));\\n}\\n\\n.aparte-stats__tile {\\n display: flex;\\n flex-direction: column;\\n gap: var(--aparte-space-2);\\n min-inline-size: 0;\\n padding: var(--aparte-space-4);\\n border: var(--aparte-border-width) solid var(--aparte-stats-tile-border);\\n border-radius: var(--aparte-radius-lg);\\n background: var(--aparte-stats-tile-bg);\\n transition: border-color var(--aparte-duration-fast, 120ms) ease;\\n}\\n\\n.aparte-stats__tile:hover { border-color: var(--aparte-stats-tile-hover-border); }\\n\\n.aparte-stats__tile > .aparte-stats__value { margin-block-start: var(--aparte-space-1); }\\n\\n/* Under the hint, at the tile's foot: a row of tiles keeps its charts on one line. */\\n.aparte-stats__tile > .aparte-stats__spark {\\n block-size: 2.25rem;\\n margin-block-start: auto;\\n padding-block-start: var(--aparte-space-2);\\n}\\n\\n/* One figure alone: the card is its tile, no panel inside the panel. */\\n.aparte-stats__tiles[data-columns=\\\"1\\\"] > .aparte-stats__tile {\\n --aparte-stats-value-size: calc(2.25rem * var(--aparte-font-scale));\\n padding: 0;\\n border: 0;\\n background: none;\\n}\\n\\n.aparte-stats__tiles[data-columns=\\\"1\\\"] > .aparte-stats__tile > .aparte-stats__spark { block-size: 3rem; }\\n\\n@container aparte-stats (max-width: 30rem) {\\n .aparte-stats__tiles[data-columns=\\\"3\\\"] {\\n --aparte-stats-columns: 2;\\n --aparte-stats-value-size: calc(1.75rem * var(--aparte-font-scale));\\n }\\n}\\n\\n/* A phone-wide card: one tile per line, each with the whole width for its number. */\\n@container aparte-stats (max-width: 19.5rem) {\\n .aparte-stats__tiles,\\n .aparte-stats__tiles[data-columns=\\\"3\\\"] { --aparte-stats-columns: 1; }\\n}\\n\\n/* ── list ────────────────────────────────────────────────────────────── */\\n\\n.aparte-stats__list {\\n display: flex;\\n flex-direction: column;\\n margin: 0;\\n}\\n\\n.aparte-stats__row {\\n display: grid;\\n grid-template-columns: minmax(0, 1fr) auto;\\n align-items: center;\\n gap: var(--aparte-space-4);\\n padding: var(--aparte-space-3) var(--aparte-space-2);\\n margin-inline: calc(var(--aparte-space-2) * -1);\\n border-block-end: var(--aparte-border-width) solid var(--aparte-border);\\n border-radius: 0;\\n transition: background-color var(--aparte-duration-fast, 120ms) ease;\\n}\\n\\n.aparte-stats__row:last-child { border-block-end: 0; }\\n.aparte-stats__row:first-child { padding-block-start: 0; }\\n.aparte-stats__row:last-child:not(:first-child) { padding-block-end: 0; }\\n\\n.aparte-stats__list > .aparte-stats__row:hover {\\n background: linear-gradient(to right, transparent, color-mix(in oklab, var(--aparte-text) 3%, transparent) 30%, color-mix(in oklab, var(--aparte-text) 3%, transparent) 70%, transparent);\\n}\\n\\n/* The label and its hint stacked, the glyph beside both. */\\n.aparte-stats__row > .aparte-stats__label {\\n display: grid;\\n grid-template-columns: auto minmax(0, 1fr);\\n align-items: center;\\n column-gap: var(--aparte-space-3);\\n row-gap: 0.1rem;\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-md);\\n font-weight: var(--aparte-font-weight-normal);\\n}\\n\\n.aparte-stats__row > .aparte-stats__label:not(:has(> .aparte-stats__icon)) { grid-template-columns: minmax(0, 1fr); }\\n.aparte-stats__row > .aparte-stats__label > .aparte-stats__icon { grid-row: span 2; }\\n.aparte-stats__row > .aparte-stats__label > .aparte-stats__label-text,\\n.aparte-stats__row > .aparte-stats__label > .aparte-stats__hint { grid-column: -2 / -1; }\\n\\n.aparte-stats__row-value {\\n display: flex;\\n flex-wrap: wrap;\\n align-items: center;\\n justify-content: flex-end;\\n gap: var(--aparte-space-1) var(--aparte-space-3);\\n margin: 0;\\n text-align: end;\\n}\\n\\n.aparte-stats__row-value > .aparte-stats__value {\\n font-size: var(--aparte-font-size-base);\\n letter-spacing: normal;\\n line-height: 1.3;\\n white-space: nowrap;\\n}\\n\\n.aparte-stats__row-value > .aparte-stats__value[data-format=\\\"text\\\"] { white-space: normal; }\\n\\n.aparte-stats__row-value > .aparte-stats__spark {\\n inline-size: 3.5rem;\\n block-size: 1.25rem;\\n}\\n\\n.aparte-stats__row-value > .aparte-stats__change { justify-content: flex-end; }\\n\\n@container aparte-stats (max-width: 19.5rem) {\\n .aparte-stats__row-value > .aparte-stats__spark { display: none; }\\n}\\n\\n/* ── hero ────────────────────────────────────────────────────────────── */\\n\\n.aparte-stats__hero {\\n display: flex;\\n flex-direction: column;\\n gap: var(--aparte-space-2);\\n min-inline-size: 0;\\n}\\n\\n.aparte-stats__hero-figure {\\n display: flex;\\n flex-wrap: wrap;\\n align-items: center;\\n gap: var(--aparte-space-2) var(--aparte-space-4);\\n min-inline-size: 0;\\n}\\n\\n.aparte-stats__hero .aparte-stats__value {\\n font-size: var(--aparte-stats-hero-value-size);\\n font-weight: var(--aparte-font-weight-bold);\\n letter-spacing: -0.03em;\\n line-height: 1;\\n}\\n\\n.aparte-stats__hero .aparte-stats__change { font-size: var(--aparte-font-size-sm); }\\n.aparte-stats__hero .aparte-stats__hint { font-size: var(--aparte-font-size-sm); }\\n\\n/* The chart runs to the card's edges, its area fading into the band below. */\\n.aparte-stats__hero > .aparte-stats__spark {\\n block-size: 5rem;\\n margin-block-start: var(--aparte-space-3);\\n margin-inline: calc(var(--aparte-stats-pad) * -1);\\n}\\n\\n.aparte-stats__hero:last-child > .aparte-stats__spark { margin-block-end: calc(var(--aparte-stats-pad) * -1); }\\n\\n.aparte-stats__hero .aparte-rich-card__sparkline-area { opacity: 0.18; }\\n\\n.aparte-stats__minis {\\n --aparte-stats-columns: 3;\\n display: grid;\\n grid-template-columns: repeat(var(--aparte-stats-columns), minmax(0, 1fr));\\n gap: var(--aparte-space-4) var(--aparte-space-5);\\n margin: 0 calc(var(--aparte-stats-pad) * -1) calc(var(--aparte-stats-pad) * -1);\\n padding: var(--aparte-space-5) var(--aparte-stats-pad);\\n border-block-start: var(--aparte-border-width) solid var(--aparte-border);\\n background: var(--aparte-stats-band-bg);\\n}\\n\\n.aparte-stats__minis[data-count=\\\"1\\\"] { --aparte-stats-columns: 1; }\\n.aparte-stats__minis[data-count=\\\"2\\\"],\\n.aparte-stats__minis[data-count=\\\"4\\\"] { --aparte-stats-columns: 2; }\\n\\n.aparte-stats__mini {\\n display: flex;\\n flex-direction: column;\\n gap: var(--aparte-space-1);\\n min-inline-size: 0;\\n}\\n\\n.aparte-stats__mini > .aparte-stats__label {\\n font-size: var(--aparte-font-size-xs);\\n --aparte-rich-card-glyph-size: 1.25rem;\\n}\\n\\n.aparte-stats__mini > .aparte-stats__label > .aparte-stats__icon { padding: 0.2rem; }\\n\\n.aparte-stats__mini > .aparte-stats__value {\\n font-size: var(--aparte-font-size-lg);\\n letter-spacing: -0.01em;\\n line-height: 1.2;\\n}\\n\\n.aparte-stats__mini-change { margin: 0; }\\n\\n.aparte-stats__mini-change .aparte-stats__pill {\\n padding: 0;\\n background: none;\\n}\\n\\n@container aparte-stats (max-width: 19.5rem) {\\n .aparte-stats__minis,\\n .aparte-stats__minis[data-count] { --aparte-stats-columns: 2; }\\n .aparte-stats__minis[data-count=\\\"1\\\"] { --aparte-stats-columns: 1; }\\n}\\n\\n/* ── Loading ─────────────────────────────────────────────────────────── */\\n\\n.aparte-stats-card[data-state=\\\"loading\\\"] .aparte-stats__sk-title { inline-size: 9rem; }\\n.aparte-stats-card[data-state=\\\"loading\\\"] .aparte-stats__sk-label { inline-size: 5rem; }\\n.aparte-stats-card[data-state=\\\"loading\\\"] .aparte-stats__sk-big {\\n inline-size: 6.5rem;\\n block-size: 2rem;\\n border-radius: var(--aparte-radius-md);\\n}\\n.aparte-stats-card[data-state=\\\"loading\\\"] .aparte-stats__sk-pill {\\n inline-size: 3.5rem;\\n block-size: 1.1rem;\\n border-radius: var(--aparte-radius-full);\\n}\\n.aparte-stats-card[data-state=\\\"loading\\\"] .aparte-stats__sk-value { inline-size: 3.5rem; }\\n.aparte-stats-card[data-state=\\\"loading\\\"] .aparte-stats__row .aparte-stats__sk-label { inline-size: 8rem; }\\n.aparte-stats-card[data-state=\\\"loading\\\"] .aparte-stats__row .aparte-stats__sk-value { justify-self: end; }\\n.aparte-stats-card[data-state=\\\"loading\\\"] .aparte-stats__hero .aparte-stats__sk-big { inline-size: 9rem; block-size: 2.75rem; }\\n.aparte-stats-card[data-state=\\\"loading\\\"] .aparte-stats__sk-chart {\\n inline-size: 100%;\\n block-size: 4rem;\\n margin-block: var(--aparte-space-3) var(--aparte-space-5);\\n border-radius: var(--aparte-radius-md);\\n}\\n.aparte-stats-card[data-state=\\\"loading\\\"] .aparte-stats__minis { margin-block-start: 0; }\\n.aparte-stats-card[data-state=\\\"loading\\\"] .aparte-stats__mini .aparte-stats__sk-label { inline-size: 70%; }\\n.aparte-stats-card[data-state=\\\"loading\\\"] .aparte-skeleton--text + .aparte-skeleton--text { margin-block-start: 0; }\\n\\n@media (prefers-reduced-motion: reduce) {\\n .aparte-stats__sparkline { animation: none; }\\n}\\n\\n@media (max-width: 380px) {\\n .aparte-stats-card { --aparte-stats-pad: var(--aparte-space-5); }\\n}\\n\"","/**\n * @aparte/plugin-cards/stats — a tool's key figures, drawn as a card.\n *\n * import { setupStatsCard } from '@aparte/plugin-cards/stats';\n *\n * setupStatsCard({\n * tool: 'get_sales_summary',\n * map: (result) => ({ title: 'Sales this week', items: result.kpis }),\n * });\n *\n * Three variants of one card: `tiles` (a grid of KPI tiles — label, big number, the change\n * as a pill, a sparkline under it), `list` (a fact sheet: one row per figure, the value\n * at the end, for five to twelve facts) and `hero` (the first figure large over a wide\n * chart, the others as a row of small ones beneath).\n *\n * Your tool keeps its own fields: `readStats` reads a list of figures, one figure, a\n * `{ title, items }` envelope, or a plain record — `{ Revenue: 12000, Orders: 340 }` — as\n * label → value pairs; and the usual spellings of each field (`name` for `label`, `amount`\n * or `count` for `value`, `delta` for `change`, `history` for `trend`). `map` covers the rest.\n * A record's `currency` and `unit` are how its figures are written, never figures: the\n * currency goes to the keys that name money (`revenue`, `avgOrderValue`, `mrr` — not\n * `orders`, nor `refundRate`), the unit to the others, and a figure's own always wins.\n *\n * **How a change is read.** A change is a percentage unless `changeFormat: 'absolute'`\n * says it is in the figure's own unit. A percentage given as a number follows one rule:\n * at most 1 in size it is a ratio (`0.12` → +12 %), above that it is already in percent\n * (`12` → +12 %). So `1` is +100 %; write `\"1%\"` — a string with its sign is never\n * ambiguous — or use `changePercent`, which is always in percent, for one per cent.\n * A `percent` figure's value follows the same rule.\n */\nimport type { AparteConfig } from '@aparte/core';\nimport { defineCard, type CardContext, type CardSetupOptions } from '../kit/define.js';\nimport { el, glyph, num, str } from '../kit/dom.js';\nimport { currencyCode, formatNumber, formatUnit, formatWhen, toDate } from '../kit/format.js';\nimport { sparkline } from '../kit/sparkline.js';\nimport { intlTag, word, type CardWord } from '../kit/strings.js';\nimport { BARS, STAT_ICONS } from './icons.js';\nimport statsStyles from './stats.css?raw';\n\nexport type StatsVariant = 'tiles' | 'list' | 'hero';\n\n/** How a figure's value is written. */\nexport type StatFormat = 'number' | 'percent' | 'currency' | 'compact' | 'duration' | 'text';\n\n/** The glyphs a figure may wear beside its label. */\nexport type StatIcon = keyof typeof STAT_ICONS;\n\n/**\n * One figure as `map` returns it. Only `label` and `value` are needed; every other field\n * adds a line when it is there and nothing when it is not.\n */\nexport interface StatInput {\n label: string;\n /** A number, or a short text (`\"Gold\"`, `\"4.8/5\"`). `\"12%\"` is read as a percentage. */\n value: number | string;\n /**\n * `number` (the default), `percent` (see the rule above), `currency` (with `currency`),\n * `compact` (`12K`, `1.2M`), `duration` (seconds → `1 hr 20 min`) or `text`.\n */\n format?: StatFormat;\n /** An ISO 4217 code (`EUR`) or a usual symbol (`€`); alone, it makes the figure a sum. */\n currency?: string;\n /** An `Intl` unit (`kilometer`, `megabyte`, `kilometer-per-hour`), or any text, appended. */\n unit?: string;\n /** Decimals shown, 0–6. */\n digits?: number;\n /** The change: a percentage (the rule above) or, with `changeFormat: 'absolute'`, in the figure's unit. */\n change?: number | string;\n changeFormat?: 'percent' | 'absolute';\n /** What the change compares with: \"vs last week\". */\n changeLabel?: string;\n /** Which way is good — it colours the change green or red, and says which to a screen reader. Without it the change is neutral. */\n good?: 'up' | 'down';\n /** Past values, oldest first, for the sparkline. */\n trend?: number[];\n /** One short line under the figure. */\n hint?: string;\n icon?: StatIcon;\n}\n\n/** What `map` returns: figures with a heading, a list of them, one figure, or a record of label → value. */\nexport type StatsInput =\n | { title?: string; subtitle?: string; items: StatInput[]; footnote?: string; updatedAt?: string | number | Date }\n | StatInput[]\n | StatInput\n | Record<string, number | string>;\n\n/** One figure as the card draws it, once read. */\nexport interface Stat {\n label: string;\n /** A number in the scale it is drawn in (a `percent` figure's is a ratio), or — for `text` — a text drawn as given. */\n value: number | string;\n /** `text` exactly when `value` is a string; never `currency` without a currency. */\n format: StatFormat;\n /** An ISO 4217 code. */\n currency?: string;\n unit?: string;\n digits?: number;\n /** A ratio for a `percent` change; in the value's own scale for an `absolute` one. */\n change?: number;\n changeFormat: 'percent' | 'absolute';\n changeLabel?: string;\n good?: 'up' | 'down';\n /** Two points at least, finite. */\n trend?: number[];\n hint?: string;\n icon?: StatIcon;\n}\n\n/** The data as the card draws it. */\nexport interface StatsData {\n title?: string;\n subtitle?: string;\n items: Stat[];\n footnote?: string;\n updatedAt?: Date;\n}\n\nconst S = {\n cardsStatsTitle: { en: 'Key figures', fr: 'Chiffres clés', de: 'Kennzahlen', es: 'Cifras clave', it: 'Dati chiave', ja: '主要な数値', ko: '주요 수치', pt: 'Números-chave', ru: 'Ключевые показатели', zh: '关键数据' },\n cardsStatsCount: { en: '{n} figures', fr: '{n} chiffres', de: '{n} Kennzahlen', es: '{n} cifras', it: '{n} dati', ja: '{n}件の数値', ko: '수치 {n}개', pt: '{n} números', ru: 'Показателей: {n}', zh: '{n} 项数据' },\n cardsStatsUpdated: { en: 'Updated {when}', fr: 'Mis à jour {when}', de: 'Aktualisiert {when}', es: 'Actualizado {when}', it: 'Aggiornato {when}', ja: '{when} 更新', ko: '{when} 업데이트', pt: 'Atualizado {when}', ru: 'Обновлено {when}', zh: '更新于 {when}' },\n // Said after the change (\"+12% good\"): the pill's green or red, for a reader who does not see colour.\n cardsStatsGood: { en: 'good', fr: 'favorable', de: 'positiv', es: 'favorable', it: 'positivo', ja: '好調', ko: '좋음', pt: 'favorável', ru: 'хорошо', zh: '向好' },\n cardsStatsBad: { en: 'bad', fr: 'défavorable', de: 'negativ', es: 'desfavorable', it: 'negativo', ja: '不調', ko: '나쁨', pt: 'desfavorável', ru: 'плохо', zh: '变差' },\n} satisfies Record<string, CardWord>;\n\n/** Twelve: past that a card of figures is a report, not an answer. */\nconst STATS_SHOWN = 12;\n/** Points kept in a trend: past this a sparkline is a smudge. */\nconst TREND_POINTS = 60;\n\nconst FORMATS: readonly StatFormat[] = ['number', 'percent', 'currency', 'compact', 'duration', 'text'];\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, keys: readonly string[]): unknown {\n for (const key of keys) if (r[key] !== undefined && r[key] !== null && r[key] !== '') return r[key];\n return undefined;\n}\n\nconst LABEL_KEYS = ['label', 'name', 'title', 'key', 'metric'] as const;\nconst VALUE_KEYS = ['value', 'amount', 'count', 'total'] as const;\nconst LIST_KEYS = ['items', 'stats', 'metrics', 'kpis', 'figures', 'facts'] as const;\n\n/** A number written with its sign and per cent: `\"+12%\"`, `\"−3,5 %\"`, `\"12%\"`. */\nconst PERCENT_TEXT = /^([+\\-−]?)\\s*(\\d+(?:[.,]\\d+)?)\\s*%$/;\n/** A number grouped by commas, as an English tool writes it: `\"12,000\"`, `\"1,234.5\"`. */\nconst GROUPED = /^[+-]?\\d{1,3}(?:,\\d{3})+(?:\\.\\d+)?$/;\n\n/** A number from a value: a finite number, `\"12\"`, or `\"12,000\"`. */\nfunction amount(value: unknown): number | undefined {\n const n = num(value);\n if (n !== undefined) return n;\n if (typeof value === 'string' && GROUPED.test(value.trim())) return Number(value.trim().replace(/,/g, ''));\n return undefined;\n}\n\n/** A percentage written as text, as a ratio: `\"+12%\"` → 0.12. */\nfunction percentText(value: unknown): number | undefined {\n if (typeof value !== 'string') return undefined;\n const match = PERCENT_TEXT.exec(value.trim());\n if (!match) return undefined;\n const n = Number(match[2]!.replace(',', '.')) / 100;\n return match[1] === '-' || match[1] === '−' ? -n : n;\n}\n\n/** The ratio rule: at most 1 in size it is a ratio, above that it is in percent. */\nconst asRatio = (n: number) => (Math.abs(n) <= 1 ? n : n / 100);\n\n/** An `Intl` unit name the runtime knows (`kilometer`, `kilometer-per-hour`). */\nfunction isIntlUnit(unit: string): boolean {\n if (!/^[a-z]+(?:-[a-z]+)*$/.test(unit)) return false;\n try {\n new Intl.NumberFormat('en', { style: 'unit', unit });\n return true;\n } catch {\n return false;\n }\n}\n\n/** `up`/`down` from what a tool writes: `higher`, `lower`, `increase`… */\nfunction readGood(r: Raw): Stat['good'] {\n const value = pick(r, ['good', 'better', 'goodDirection', 'good_direction']);\n if (typeof value === 'string') {\n const v = value.trim().toLowerCase();\n if (['up', 'higher', 'increase', 'high', 'more'].includes(v)) return 'up';\n if (['down', 'lower', 'decrease', 'low', 'less'].includes(v)) return 'down';\n }\n const lower = pick(r, ['lowerIsBetter', 'lower_is_better', 'invert', 'inverted']);\n if (typeof lower === 'boolean') return lower ? 'down' : 'up';\n const higher = pick(r, ['higherIsBetter', 'higher_is_better']);\n if (typeof higher === 'boolean') return higher ? 'up' : 'down';\n return undefined;\n}\n\n/** The trend's points, from numbers, `{ value }` points or `[x, y]` pairs. */\nfunction readTrend(value: unknown): number[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const points = value\n .map((p) => (Array.isArray(p) ? num(p[1]) : isObject(p) ? num(pick(p, ['value', 'y', 'v', 'count', 'amount'])) : num(p)))\n .filter((n): n is number => n !== undefined)\n .slice(-TREND_POINTS);\n return points.length >= 2 ? points : undefined;\n}\n\n/**\n * `key` as a label when a record gave it: `conversionRate` → \"Conversion rate\",\n * `avg_order_value` → \"Avg order value\". A key already written for people — with a space,\n * or a single word in capitals like `MRR` — is kept as it is.\n */\nexport function humanizeKey(key: string): string {\n const k = key.trim();\n if (/\\s/.test(k) || !/[a-z]/.test(k)) return k;\n const words = k.replace(/([a-z\\d])([A-Z])/g, '$1 $2').replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2').split(/[\\s_-]+/).filter(Boolean);\n const text = words.map((w) => (/^[A-Z\\d]{2,}$/.test(w) ? w : w.toLowerCase())).join(' ');\n return text.charAt(0).toUpperCase() + text.slice(1);\n}\n\n/** One figure from whatever a tool wrote, or `null` without a label and a value to show. */\nfunction readStat(raw: unknown, fallbackLabel?: string): Stat | null {\n if (!isObject(raw)) {\n // A record's value given bare: `{ Revenue: 12000 }`.\n return fallbackLabel === undefined ? null : readStat({ value: raw }, fallbackLabel);\n }\n const r = raw;\n const label = str(pick(r, LABEL_KEYS)) ?? (fallbackLabel !== undefined ? humanizeKey(fallbackLabel) : undefined);\n const rawValue = pick(r, VALUE_KEYS);\n if (!label || rawValue === undefined || (typeof rawValue !== 'number' && typeof rawValue !== 'string')) return null;\n\n const asked = typeof r['format'] === 'string' && (FORMATS as readonly string[]).includes(r['format']) ? (r['format'] as StatFormat) : undefined;\n const currency = currencyCode(pick(r, ['currency', 'currency_code', 'currencyCode']));\n const unit = str(pick(r, ['unit', 'units']));\n const digitsRaw = num(pick(r, ['digits', 'decimals', 'precision']));\n const digits = digitsRaw !== undefined ? Math.min(6, Math.max(0, Math.round(digitsRaw))) : undefined;\n\n // The value, and the format it settles: a text that is no number is drawn as given.\n let value: number | string;\n let format: StatFormat;\n let percentScale = false;\n const textPercent = percentText(rawValue);\n const n = amount(rawValue);\n if (textPercent !== undefined && (asked === undefined || asked === 'percent')) {\n // `\"12%\"` is written in percent: an absolute change of 0.5 beside it is half a point.\n percentScale = true;\n value = textPercent;\n format = 'percent';\n } else if (n === undefined || asked === 'text') {\n // A text is drawn as the tool wrote it — `\"12,000\"` asked as text stays `12,000`.\n const text = str(rawValue);\n if (!text) return null;\n value = text;\n format = 'text';\n } else if (asked === 'percent') {\n // The value's scale decides an absolute change's too: 12 (%) moved by 0.5 is half a point.\n percentScale = Math.abs(n) > 1;\n value = asRatio(n);\n format = 'percent';\n } else {\n value = n;\n format = asked === 'currency' ? (currency ? 'currency' : 'number') : asked ?? (currency ? 'currency' : 'number');\n }\n\n // The change: a percentage by the rule, `changePercent` always in percent, or absolute.\n const absolute = r['changeFormat'] === 'absolute' || r['change_format'] === 'absolute';\n let change: number | undefined;\n const percentPoints = amount(pick(r, ['changePercent', 'change_percent', 'percentChange', 'percent_change']));\n const rawChange = pick(r, ['change', 'delta', 'diff', 'variation']);\n const changeText = percentText(rawChange);\n if (!absolute && percentPoints !== undefined) change = percentPoints / 100;\n else if (changeText !== undefined) change = changeText;\n else {\n const c = amount(typeof rawChange === 'string' ? rawChange.replace('−', '-').replace(/^\\+/, '') : rawChange);\n if (c !== undefined) change = absolute ? (format === 'percent' && percentScale ? c / 100 : c) : asRatio(c);\n }\n const changeFormat: Stat['changeFormat'] = absolute && changeText === undefined ? 'absolute' : 'percent';\n\n const icon = typeof r['icon'] === 'string' && Object.hasOwn(STAT_ICONS, r['icon']) ? (r['icon'] as StatIcon) : undefined;\n const changeLabel = str(pick(r, ['changeLabel', 'change_label', 'comparison', 'vs', 'versus']));\n const hint = str(pick(r, ['hint', 'description', 'note', 'caption']));\n const trend = readTrend(pick(r, ['trend', 'history', 'series', 'sparkline', 'values']));\n const good = readGood(r);\n\n return {\n label,\n value,\n format,\n ...((format === 'currency' || format === 'compact') && currency ? { currency } : {}),\n ...(unit && (format === 'number' || format === 'compact') ? { unit } : {}),\n ...(digits !== undefined ? { digits } : {}),\n ...(change !== undefined ? { change } : {}),\n changeFormat,\n ...(change !== undefined && changeLabel ? { changeLabel } : {}),\n ...(good ? { good } : {}),\n ...(trend ? { trend } : {}),\n ...(hint ? { hint } : {}),\n ...(icon ? { icon } : {}),\n };\n}\n\nconst CURRENCY_KEYS = ['currency', 'currency_code', 'currencyCode'] as const;\nconst UNIT_KEYS = ['unit', 'units'] as const;\n\n/**\n * Keys of an envelope that are about the card, not figures of a record. A record's currency\n * and unit say how its figures are written (`{ revenue: 1200, currency: 'EUR' }`).\n */\nconst META_KEYS = new Set([\n 'title', 'heading', 'subtitle', 'period', 'footnote', 'source', 'updatedAt', 'updated_at', 'asOf', 'as_of', 'lastUpdated',\n ...CURRENCY_KEYS, ...UNIT_KEYS,\n]);\n\n/** Every key `readStat` reads, and an `id`: an object made only of these is one figure. */\nconst FIGURE_KEYS = new Set([\n ...LABEL_KEYS, ...VALUE_KEYS, ...CURRENCY_KEYS, ...UNIT_KEYS, 'id', 'format', 'digits', 'decimals', 'precision',\n 'change', 'delta', 'diff', 'variation', 'changePercent', 'change_percent', 'percentChange', 'percent_change', 'changeFormat', 'change_format',\n 'changeLabel', 'change_label', 'comparison', 'vs', 'versus', 'hint', 'description', 'note', 'caption', 'icon',\n 'trend', 'history', 'series', 'sparkline', 'values', 'good', 'better', 'goodDirection', 'good_direction',\n 'lowerIsBetter', 'lower_is_better', 'invert', 'inverted', 'higherIsBetter', 'higher_is_better',\n]);\n\n/**\n * Whether an object with a label and a value is one figure. A `label`, `name`, `key` or\n * `metric` says so. A `title` is also an envelope's heading: `{ title: 'This week', total:\n * 4200, count: 87, refunds: 3 }` is a week of three figures, not \"This week: 87\" — so with a\n * `title` it is one figure only when it holds a single value and nothing a figure does not read.\n */\nfunction isOneFigure(r: Raw): boolean {\n if (pick(r, VALUE_KEYS) === undefined) return false;\n if (pick(r, LABEL_KEYS.filter((k) => k !== 'title')) !== undefined) return true;\n if (pick(r, ['title']) === undefined) return false;\n const values = VALUE_KEYS.filter((k) => r[k] !== undefined && r[k] !== null && r[k] !== '');\n return values.length === 1 && Object.keys(r).every((k) => FIGURE_KEYS.has(k) || META_KEYS.has(k));\n}\n\n/**\n * Words of a key that name a sum of money. A record's `currency` writes only these figures:\n * `{ revenue: 1200, orders: 30, currency: 'EUR' }` is €1,200 and 30 orders, not €30.\n */\nconst MONEY_WORDS = new Set([\n 'revenue', 'revenues', 'sales', 'income', 'profit', 'profits', 'earnings', 'cost', 'costs', 'spend', 'spending', 'price', 'prices',\n 'amount', 'fee', 'fees', 'budget', 'balance', 'payout', 'payouts', 'value', 'gmv', 'mrr', 'arr', 'aov', 'arpu', 'arpa', 'ltv', 'cac',\n]);\n/** …unless another word makes it a count or a share: `salesCount`, `refundRate`, `revenueGrowth`. */\nconst NOT_MONEY_WORDS = new Set(['count', 'number', 'rate', 'ratio', 'percent', 'percentage', 'share', 'margin', 'growth', 'change']);\n\nfunction isMoneyKey(key: string): boolean {\n const words = humanizeKey(key).toLowerCase().split(/\\s+/);\n return words.some((w) => MONEY_WORDS.has(w)) && !words.some((w) => NOT_MONEY_WORDS.has(w));\n}\n\n/**\n * A record's figure with the record's currency or unit, when it has none of its own: the\n * currency for a key that names money, the unit for every other one. A figure that says its\n * own currency, unit or format keeps it.\n */\nfunction withRecordDefaults(value: unknown, key: string, meta: Raw): unknown {\n const currency = currencyCode(pick(meta, CURRENCY_KEYS));\n const unit = str(pick(meta, UNIT_KEYS));\n if (!currency && !unit) return value;\n const figure: Raw = isObject(value) ? value : { value };\n if (pick(figure, [...CURRENCY_KEYS, ...UNIT_KEYS, 'format']) !== undefined) return value;\n if (currency && isMoneyKey(key)) return { ...figure, currency };\n return unit ? { ...figure, unit } : value;\n}\n\n/**\n * The card's data from the loose shape `map` returns — a `{ title, items }` envelope (also\n * `stats`, `metrics`, `kpis`, `figures`), a list of figures, one figure, or a record of\n * label → value pairs (`{ Revenue: 12000 }`, or `{ Revenue: { value: 12000, change: 0.1 } }`)\n * — or `null` when not one figure has a label and a value. At most twelve are kept.\n */\nexport function readStats(raw: unknown): StatsData | null {\n if (!raw || typeof raw !== 'object') return null;\n let stats: Array<Stat | null>;\n let meta: Raw = {};\n if (Array.isArray(raw)) {\n stats = raw.map((item) => readStat(item));\n } else {\n const r = raw as Raw;\n const list = LIST_KEYS.map((key) => r[key]).find((v) => Array.isArray(v) || isObject(v));\n if (Array.isArray(list)) {\n stats = list.map((item) => readStat(item));\n meta = r;\n } else if (isObject(list)) {\n // `{ title, items: { Revenue: 12000 } }`: the envelope around a record.\n stats = Object.entries(list).map(([key, value]) => readStat(withRecordDefaults(value, key, r), key));\n meta = r;\n } else if (isOneFigure(r)) {\n stats = [readStat(r)];\n } else {\n // A record: every key that is not about the card is a figure's label.\n stats = Object.entries(r).filter(([key]) => !META_KEYS.has(key)).map(([key, value]) => readStat(withRecordDefaults(value, key, r), key));\n meta = r;\n }\n }\n const items = stats.filter((s): s is Stat => s !== null).slice(0, STATS_SHOWN);\n if (!items.length) return null;\n const title = str(pick(meta, ['title', 'heading']));\n const subtitle = str(pick(meta, ['subtitle', 'period']));\n const footnote = str(pick(meta, ['footnote', 'source']));\n const updatedAt = toDate(pick(meta, ['updatedAt', 'updated_at', 'asOf', 'as_of', 'lastUpdated']));\n return {\n ...(title ? { title } : {}),\n ...(subtitle ? { subtitle } : {}),\n items,\n ...(footnote ? { footnote } : {}),\n ...(updatedAt ? { updatedAt } : {}),\n };\n}\n\n// ── Writing the numbers ──────────────────────────────────────────────────────\n\n/** `−` as a typographer writes it: `Intl` gives a hyphen-minus. Only on what `Intl` wrote, never on a unit's own text. */\nconst typographic = (text: string) => text.replace(/-/g, '−');\n\n/** A duration in seconds, its two largest units: `1 hr 20 min`, `45 sec`, `2 days 3 hr`. */\nfunction durationText(config: AparteConfig, seconds: number, digits?: number): string {\n const s = Math.abs(seconds);\n if (s < 60) return formatUnit(config, s, 'second', digits ?? (s < 10 && !Number.isInteger(s) ? 1 : 0));\n const units: Array<[string, number]> = [['day', 86_400], ['hour', 3_600], ['minute', 60], ['second', 1]];\n let rest = Math.round(s);\n const parts: string[] = [];\n for (const [unit, size] of units) {\n const count = Math.floor(rest / size);\n rest -= count * size;\n if (count > 0 || parts.length) parts.push(count > 0 ? formatUnit(config, count, unit) : '');\n if (parts.length === 2) break;\n }\n const shown = parts.filter(Boolean);\n try {\n return new Intl.ListFormat(intlTag(config), { type: 'unit', style: 'narrow' }).format(shown);\n } catch {\n return shown.join(' ');\n }\n}\n\n/** The decimals to show: what the figure asks, else the format's habit. */\nfunction fractionDigits(stat: Stat, value: number, fallback: number): Intl.NumberFormatOptions {\n if (stat.digits !== undefined) return { minimumFractionDigits: stat.digits, maximumFractionDigits: stat.digits };\n return { maximumFractionDigits: Number.isInteger(value) ? 0 : fallback };\n}\n\n/**\n * A number of `stat` as the chat's language writes it, in the figure's format —\n * its value, or with `signed`, an absolute change of it.\n */\nfunction writeNumber(config: AparteConfig, stat: Stat, value: number, signed = false): string {\n const sign: Intl.NumberFormatOptions = signed ? { signDisplay: 'exceptZero' } : {};\n const done = (text: string) => (signed ? typographic(text) : text);\n switch (stat.format) {\n case 'percent':\n return done(formatNumber(config, value, { style: 'percent', ...(stat.digits !== undefined ? { minimumFractionDigits: stat.digits, maximumFractionDigits: stat.digits } : { maximumFractionDigits: 1 }), ...sign }));\n case 'duration': {\n const text = durationText(config, value, stat.digits);\n return signed && value !== 0 ? `${value > 0 ? '+' : '−'}${text}` : text;\n }\n case 'currency':\n try {\n // Whole sums without their cents — a KPI reads `$12,000`, not `$12,000.00`.\n const digits = stat.digits !== undefined || Number.isInteger(value) ? fractionDigits(stat, value, 2) : {};\n return done(formatNumber(config, value, { style: 'currency', currency: stat.currency!, ...digits, ...sign }));\n } catch {\n return done(`${formatNumber(config, value, { maximumFractionDigits: 2, ...sign })}\\u00A0${stat.currency}`);\n }\n case 'compact': {\n const compact: Intl.NumberFormatOptions = { notation: 'compact', maximumFractionDigits: stat.digits ?? 1, ...sign };\n if (stat.currency) {\n try {\n return done(formatNumber(config, value, { ...compact, style: 'currency', currency: stat.currency }));\n } catch { /* an unknown code: the number, below */ }\n }\n return withUnit(config, stat, value, compact, done);\n }\n default:\n return withUnit(config, stat, value, { ...fractionDigits(stat, value, 2), ...sign }, done);\n }\n}\n\n/**\n * The number with the figure's unit: `Intl`'s own when it knows it, else the unit's text\n * after it — outside `done`, so a unit like `e-mails` keeps its hyphen.\n */\nfunction withUnit(config: AparteConfig, stat: Stat, value: number, options: Intl.NumberFormatOptions, done: (text: string) => string): string {\n if (stat.unit && isIntlUnit(stat.unit)) {\n return done(formatNumber(config, value, { ...options, style: 'unit', unit: stat.unit, unitDisplay: 'short' }));\n }\n const n = done(formatNumber(config, value, options));\n return stat.unit ? `${n}\\u00A0${stat.unit}` : n;\n}\n\n/** The figure's value as drawn: its number in its format, or its text. */\nexport function statValue(config: AparteConfig, stat: Stat): string {\n return typeof stat.value === 'string' ? stat.value : writeNumber(config, stat, stat.value);\n}\n\n/** The change as drawn, signed: `+12%`, `−3.5%`, or `+€1,200` for an absolute one. */\nexport function statChange(config: AparteConfig, stat: Stat): string | undefined {\n if (stat.change === undefined) return undefined;\n if (stat.changeFormat === 'percent') {\n return typographic(formatNumber(config, stat.change, { style: 'percent', maximumFractionDigits: 1, signDisplay: 'exceptZero' }));\n }\n if (typeof stat.value === 'string') {\n return typographic(formatNumber(config, stat.change, { maximumFractionDigits: 2, signDisplay: 'exceptZero' }));\n }\n return writeNumber(config, stat, stat.change, true);\n}\n\ntype Direction = 'up' | 'down' | 'flat';\ntype Tone = 'good' | 'bad' | 'neutral';\n\nconst directionOf = (change: number): Direction => (change > 0 ? 'up' : change < 0 ? 'down' : 'flat');\n\n/** Green when the figure moved the way it should, red when not, neutral when nobody said. */\nfunction toneOf(stat: Stat): Tone | undefined {\n if (stat.change === undefined) return undefined;\n const direction = directionOf(stat.change);\n if (!stat.good || direction === 'flat') return 'neutral';\n return direction === stat.good ? 'good' : 'bad';\n}\n\n// ── Drawing ──────────────────────────────────────────────────────────────────\n\nconst notNull = <T>(value: T | null | undefined): value is T => value !== null && value !== undefined;\n\n/** The arrow is a shape for the eye; the sign in the number says the same to a screen reader. */\nconst ARROW: Record<Direction, string> = { up: '▲', down: '▼', flat: '' };\n\n/** The change as a pill — arrow and signed number — then what it compares with. */\nfunction changeOf(ctx: CardContext, stat: Stat, { label = true }: { label?: boolean } = {}): HTMLElement | null {\n if (stat.change === undefined) return null;\n const direction = directionOf(stat.change);\n const delta = el('span', { class: 'aparte-stats__delta' });\n ctx.bind(delta, () => statChange(ctx.config, stat)!);\n const tone = toneOf(stat);\n // Green and red are colour alone: a screen reader is told in words which way it went.\n let verdict: HTMLElement | null = null;\n if (tone === 'good' || tone === 'bad') {\n const key = tone === 'good' ? 'cardsStatsGood' : 'cardsStatsBad';\n verdict = el('span', { class: 'aparte-sr-only' });\n ctx.bind(verdict, () => ` ${word(ctx.config, key, S[key])}`);\n }\n // And a mark for the eye that does not tell green from red: the arrow says which way the\n // figure went, the mark whether that is good. Hidden from a screen reader, told the word.\n const mark = tone === 'good' || tone === 'bad'\n ? el('span', { class: 'aparte-stats__verdict', attrs: { 'aria-hidden': 'true' }, text: tone === 'good' ? '✓' : '!' })\n : null;\n const pill = el('span', { class: 'aparte-stats__pill' },\n ARROW[direction] ? el('span', { class: 'aparte-stats__arrow', attrs: { 'aria-hidden': 'true' }, text: ARROW[direction] }) : null,\n delta,\n mark,\n verdict);\n return el('span', { class: 'aparte-stats__change', attrs: { 'data-direction': direction, 'data-tone': tone } },\n pill,\n label && stat.changeLabel ? el('span', { class: 'aparte-stats__change-label', text: stat.changeLabel }) : null);\n}\n\nfunction valueOf(ctx: CardContext, stat: Stat, tag: 'div' | 'dd' | 'span' = 'div'): HTMLElement {\n const node = el(tag, { class: 'aparte-stats__value', attrs: { 'data-format': stat.format } });\n ctx.bind(node, () => statValue(ctx.config, stat));\n return node;\n}\n\nfunction labelOf(stat: Stat, tag: 'div' | 'dt' = 'div'): HTMLElement {\n return el(tag, { class: 'aparte-stats__label' },\n stat.icon ? glyph(STAT_ICONS[stat.icon], 'aparte-rich-card__glyph aparte-stats__icon') : null,\n el('span', { class: 'aparte-stats__label-text', text: stat.label }));\n}\n\nfunction sparkOf(stat: Stat, area = false): HTMLElement | null {\n if (!stat.trend) return null;\n return el('div', { class: 'aparte-stats__spark', attrs: { 'aria-hidden': 'true' } }, sparkline(stat.trend, { area, className: 'aparte-stats__sparkline' }));\n}\n\nconst hintOf = (stat: Stat) => (stat.hint ? el('div', { class: 'aparte-stats__hint', text: stat.hint }) : null);\n\n/** Where a figure stands, on its root: what the sheet colours its pill and its line by. */\nconst statAttrs = (stat: Stat) => ({ 'data-tone': toneOf(stat), 'data-trend': stat.trend !== undefined });\n\n/** The heading over the figures: a title, a line under it. */\nfunction head(data: Pick<StatsData, 'title' | 'subtitle'>): HTMLElement | null {\n if (!data.title && !data.subtitle) return null;\n return el('div', { class: 'aparte-stats__head' },\n data.title ? el('div', { class: 'aparte-stats__title', text: data.title }) : null,\n data.subtitle ? el('div', { class: 'aparte-stats__subtitle', text: data.subtitle }) : null);\n}\n\n/** The line under the figures: where they come from, and when they were read. */\nfunction foot(ctx: CardContext, data: StatsData): HTMLElement | null {\n if (!data.footnote && !data.updatedAt) return null;\n let when: HTMLElement | null = null;\n if (data.updatedAt) {\n const date = data.updatedAt;\n // A day given alone (`2026-10-30`) reads as local midnight: it is drawn as that day,\n // never as \"12:00 AM\", a time no one gave.\n const dayOnly = date.getHours() === 0 && date.getMinutes() === 0 && date.getSeconds() === 0 && date.getMilliseconds() === 0;\n when = el('time', { class: 'aparte-stats__updated', attrs: { datetime: date.toISOString() } });\n ctx.bind(when, () => word(ctx.config, 'cardsStatsUpdated', S.cardsStatsUpdated, {\n when: dayOnly\n ? new Intl.DateTimeFormat(intlTag(ctx.config), { weekday: 'short', month: 'short', day: 'numeric' }).format(date)\n : formatWhen(ctx.config, date),\n }));\n }\n return el('div', { class: 'aparte-stats__foot' },\n data.footnote ? el('span', { class: 'aparte-stats__footnote', text: data.footnote }) : null,\n when);\n}\n\n/** Columns for `n` tiles: never a lone tile on a row of three when two rows of two fit. */\nconst columnsFor = (n: number) => (n === 1 ? 1 : n === 2 || n === 4 ? 2 : 3);\n\n/** The `tiles` variant: a tile per figure, in a grid that narrows with the card. */\nfunction tiles(ctx: CardContext, items: Stat[]): HTMLElement {\n const list = el('ul', { class: 'aparte-stats__tiles', attrs: { role: 'list', 'data-columns': columnsFor(items.length) } });\n for (const stat of items) {\n list.append(el('li', { class: 'aparte-stats__tile aparte-stats__stat', attrs: statAttrs(stat) },\n labelOf(stat),\n valueOf(ctx, stat),\n changeOf(ctx, stat),\n // The hint before the chart: the charts then sit on one line along a row of tiles.\n hintOf(stat),\n sparkOf(stat)));\n }\n return list;\n}\n\n/** The `list` variant: a fact sheet, the label at the start of each row and the value at its end. */\nfunction sheet(ctx: CardContext, items: Stat[]): HTMLElement {\n const list = el('dl', { class: 'aparte-stats__list' });\n for (const stat of items) {\n const term = labelOf(stat, 'dt');\n if (stat.hint) term.append(el('span', { class: 'aparte-stats__hint', text: stat.hint }));\n const value = el('dd', { class: 'aparte-stats__row-value' },\n sparkOf(stat),\n valueOf(ctx, stat, 'span'),\n changeOf(ctx, stat));\n list.append(el('div', { class: 'aparte-stats__row aparte-stats__stat', attrs: statAttrs(stat) }, term, value));\n }\n return list;\n}\n\n/** The `hero` variant: the first figure large over its chart, the others small beneath. */\nfunction hero(ctx: CardContext, items: Stat[]): Node[] {\n const [first, ...rest] = items as [Stat, ...Stat[]];\n const main = el('div', { class: 'aparte-stats__hero aparte-stats__stat', attrs: statAttrs(first) },\n labelOf(first),\n el('div', { class: 'aparte-stats__hero-figure' }, valueOf(ctx, first), changeOf(ctx, first)),\n hintOf(first),\n sparkOf(first, true));\n if (!rest.length) return [main];\n const minis = el('dl', { class: 'aparte-stats__minis', attrs: { 'data-count': Math.min(rest.length, 4) } });\n for (const stat of rest) {\n minis.append(el('div', { class: 'aparte-stats__mini aparte-stats__stat', attrs: statAttrs(stat) },\n labelOf(stat, 'dt'),\n valueOf(ctx, stat, 'dd'),\n stat.change !== undefined ? el('dd', { class: 'aparte-stats__mini-change' }, changeOf(ctx, stat, { label: false })) : null));\n }\n return [main, minis];\n}\n\nfunction render(data: StatsData, ctx: CardContext<StatsVariant>): Node[] {\n const body = ctx.variant === 'list' ? [sheet(ctx, data.items)]\n : ctx.variant === 'hero' ? hero(ctx, data.items)\n : [tiles(ctx, data.items)];\n return [head(data), el('div', { class: 'aparte-stats__body' }, ...body), foot(ctx, data)].filter(notNull);\n}\n\nfunction skeleton(partial: Partial<StatsData> | null, ctx: CardContext<StatsVariant>): Node[] {\n const block = (cls: string, kind: 'text' | 'rect' = 'rect') =>\n el('span', { class: `aparte-skeleton aparte-skeleton--${kind} ${cls}`, attrs: { 'aria-hidden': 'true' } });\n // What the figures are about, before they come: the call's input may already say it.\n const heading = partial?.title\n ? head({ title: partial.title })\n : el('div', { class: 'aparte-stats__head' }, block('aparte-stats__sk-title', 'text'));\n let body: HTMLElement;\n if (ctx.variant === 'list') {\n body = el('div', { class: 'aparte-stats__list' }, ...[0, 1, 2, 3].map(() => el('div', { class: 'aparte-stats__row' },\n block('aparte-stats__sk-label', 'text'), block('aparte-stats__sk-value', 'text'))));\n } else if (ctx.variant === 'hero') {\n body = el('div', { class: 'aparte-stats__sk-hero' },\n el('div', { class: 'aparte-stats__hero' },\n block('aparte-stats__sk-label', 'text'), block('aparte-stats__sk-big'), block('aparte-stats__sk-chart')),\n el('div', { class: 'aparte-stats__minis', attrs: { 'data-count': 3 } }, ...[0, 1, 2].map(() => el('div', { class: 'aparte-stats__mini' },\n block('aparte-stats__sk-label', 'text'), block('aparte-stats__sk-value', 'text')))));\n } else {\n body = el('div', { class: 'aparte-stats__tiles', attrs: { 'data-columns': 2 } }, ...[0, 1, 2, 3].map(() => el('div', { class: 'aparte-stats__tile' },\n block('aparte-stats__sk-label', 'text'), block('aparte-stats__sk-big'), block('aparte-stats__sk-pill'))));\n }\n return [heading, el('div', { class: 'aparte-stats__body' }, body)].filter(notNull);\n}\n\nfunction cardLabel(data: Partial<StatsData> | null, ctx: CardContext): string {\n if (data?.title) return data.title;\n const items = data?.items ?? [];\n if (items.length === 1) return items[0]!.label;\n if (items.length > 1) return word(ctx.config, 'cardsStatsCount', S.cardsStatsCount, { n: formatNumber(ctx.config, items.length) });\n return word(ctx.config, 'cardsStatsTitle', S.cardsStatsTitle);\n}\n\nexport const statsCard = defineCard<StatsData, StatsVariant>({\n name: 'stats',\n variants: ['tiles', 'list', 'hero'],\n styles: statsStyles,\n icon: BARS,\n normalize: readStats,\n render,\n skeleton,\n label: cardLabel,\n // \"Revenue: $12,000 (+12% vs last week); Orders: 340\" — one clause per figure.\n fallback: (data, ctx) => data.items.map((stat) => {\n const change = statChange(ctx.config, stat);\n const said = change ? ` (${[change, stat.changeLabel].filter(notNull).join(' ')})` : '';\n return `${stat.label}: ${statValue(ctx.config, stat)}${said}`;\n }).join('; '),\n partial: (input) => {\n const about = str(input['title'] ?? input['metric'] ?? input['metrics'] ?? input['query'] ?? input['topic'] ?? input['report']);\n return about ? { title: about } : null;\n },\n});\n\n/** Draw a tool's key figures as this card — returns the function that stops it. */\nexport function setupStatsCard(options: CardSetupOptions<StatsData, StatsVariant> = {}): () => void {\n return statsCard.setup(options);\n}\n"],"names":[],"mappings":";;AAQA,MAAM,MAAM,CAAC,SACT,mKAAmK,IAAI;AAG3K,MAAM,QAAQ,IAAI,8KAA8K;AAGhM,MAAM,QAAQ,IAAI,8KAA8K;AAGhM,MAAM,OAAO,IAAI,+JAA+J;AAGhL,MAAM,QAAQ,IAAI,kHAAkH;AAGpI,MAAM,QAAQ,IAAI,iEAAiE;AAGnF,MAAM,OAAO,IAAI,oFAAoF;AAG9F,MAAM,aAAa,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,MAAM,OAAO,OAAO,OAAO,OAAO,MAAM,KAAA;AAG/F,MAAM,OAAO,IAAI,wFAAwF;ACjChH,MAAA,cAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * The stock card's charts: a price line, and candlesticks.
3
+ *
4
+ * **The line**: an area under the series, split at a baseline into the part above it (the
5
+ * "up" colour) and the part below (the "down" colour), the last point marked, the high and
6
+ * the low written where they happen. Why two clip paths rather than two areas: an area cut
7
+ * at the baseline needs the exact crossing points of every segment that crosses it, which
8
+ * is arithmetic per segment and a polygon per run. Clipping the SAME path twice, once to
9
+ * the band above the baseline and once to the band below, splits it exactly where the line
10
+ * crosses, for any series, with two rectangles. The strokes are split the same way, so the
11
+ * line changes colour at the crossing too.
12
+ *
13
+ * **The candles**: a body from the open to the close, a wick from the low to the high, the
14
+ * volume as faint bars along the bottom. A rising candle is HOLLOW and a falling one FILLED
15
+ * (the classic convention), and that is a choice for the reader, not for the look: a filled
16
+ * body alone does not say which end is the open, so its colour would be the only telling.
17
+ * Hollow-or-filled says it without colour. Every body of a kind is one path, every wick of
18
+ * a kind another: eighty candles are a handful of nodes, not four hundred.
19
+ *
20
+ * Both are SVG built with `createElementNS` from numbers only, so a tool's values never
21
+ * reach a parser, stretched to the card's width (`preserveAspectRatio="none"`, the strokes
22
+ * kept at their width by `vector-effect`). That would squash anything round, so the dot,
23
+ * the dashed baseline, the cursor and the labels are HTML laid over the SVG, placed in
24
+ * percent of the same box.
25
+ *
26
+ * Time runs left to right in every script, as it does on the market's own charts: the
27
+ * plot is `dir="ltr"`, the text around it follows the page.
28
+ */
29
+ import type { CardContext } from '../kit/define.js';
30
+ /** One point of a series: its value, and when it was, when the tool said. */
31
+ export interface ChartPoint {
32
+ value: number;
33
+ time?: Date;
34
+ }
35
+ /** One candle: a stretch of time's first, highest, lowest and last price. */
36
+ export interface Candle {
37
+ time?: Date;
38
+ open: number;
39
+ high: number;
40
+ low: number;
41
+ close: number;
42
+ volume?: number;
43
+ }
44
+ export interface ChartGeometry {
45
+ /** The line, in a 100 × 100 box. */
46
+ line: string;
47
+ /** The area between the line and the baseline. */
48
+ area: string;
49
+ points: Array<[number, number]>;
50
+ /** The baseline's height in the box. */
51
+ baseY: number;
52
+ /** Where the highest and the lowest values are (their first occurrence). */
53
+ hi: number;
54
+ lo: number;
55
+ }
56
+ /**
57
+ * The chart's shape for `values` against `baseline`, or `null` under two points. The
58
+ * baseline is inside the scale, so it is always on the chart; a series that does not
59
+ * move is a flat line through the middle.
60
+ */
61
+ export declare function chartGeometry(values: number[], baseline: number): ChartGeometry | null;
62
+ /**
63
+ * At most `max` points, keeping each stretch's lowest and highest: a day of minutes
64
+ * (390 points) or a year of hours is more than a card's width can show, and a plain
65
+ * stride would drop the very high and low the labels name. The first and the last
66
+ * point always stay.
67
+ */
68
+ export declare function thin<T extends ChartPoint>(points: T[], max?: number): T[];
69
+ /**
70
+ * At most `max` candles, by merging neighbours into wider ones — the way a chart moves
71
+ * from hourly to daily candles — rather than dropping any: a merged candle opens with the
72
+ * first, closes with the last, and keeps the highest high, the lowest low and the summed
73
+ * volume, so nothing that happened leaves the chart. Its time is the first one's.
74
+ */
75
+ export declare function groupCandles(candles: Candle[], max?: number): Candle[];
76
+ /** One candle's place in the 100 × 100 box. */
77
+ export interface CandleShape {
78
+ /** The centre of its slot, and its body's width. */
79
+ x: number;
80
+ width: number;
81
+ /** The body's top and bottom, the wick's ends, the close. */
82
+ top: number;
83
+ bottom: number;
84
+ high: number;
85
+ low: number;
86
+ close: number;
87
+ direction: 'up' | 'down' | 'flat';
88
+ /** Its volume bar's height, from the bottom of the box. */
89
+ volume: number;
90
+ }
91
+ export interface CandleGeometry {
92
+ shapes: CandleShape[];
93
+ /** The candles with the highest high and the lowest low. */
94
+ hi: number;
95
+ lo: number;
96
+ /** Whether a volume band is drawn along the bottom. */
97
+ volume: boolean;
98
+ }
99
+ /**
100
+ * The candles' shapes, or `null` with none. The prices take the box above the volume
101
+ * band, with the same room above and below as the line for the labels.
102
+ */
103
+ export declare function candleGeometry(candles: Candle[]): CandleGeometry | null;
104
+ export interface PriceChartOptions {
105
+ points: ChartPoint[];
106
+ /** The value the chart is split at: the previous close, or where the series started. */
107
+ baseline: number;
108
+ /** A value as text, in the quote's currency and precision. */
109
+ value(v: number): string;
110
+ /** A point's time as text. */
111
+ time(d: Date): string;
112
+ /** The plot's accessible name: what the chart shows, in a sentence. */
113
+ label(): string;
114
+ /** The market is open: the last point pulses. */
115
+ live?: boolean;
116
+ /** What sits under the plot (the range, the baseline's legend); the readout takes its place while the chart is explored. */
117
+ info?: Node[];
118
+ }
119
+ /** The line chart, or `null` under two points. */
120
+ export declare function priceChart(ctx: CardContext, options: PriceChartOptions): HTMLElement | null;
121
+ export interface CandleChartOptions {
122
+ candles: Candle[];
123
+ value(v: number): string;
124
+ time(d: Date): string;
125
+ /** A candle under the cursor: the short line shown ("O 1 H 2 L 0 C 1"), and the sentence said. */
126
+ ohlc(c: Candle): {
127
+ shown: string;
128
+ spoken: string;
129
+ };
130
+ label(): string;
131
+ info?: Node[];
132
+ }
133
+ /** The candlestick chart, or `null` without a candle. */
134
+ export declare function candleChart(ctx: CardContext, options: CandleChartOptions): HTMLElement | null;
135
+ //# sourceMappingURL=chart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart.d.ts","sourceRoot":"","sources":["../../src/stock/chart.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The stock card's glyphs: the arrows beside a change, and the card's own glyph for its
3
+ * one-line states.
4
+ *
5
+ * Constants of this package — the only markup the card parses. The arrows are filled in
6
+ * `currentColor`, so the change's colour reaches them through `color`; the sign written
7
+ * beside them says the same thing in text, so neither the colour nor the arrow is alone.
8
+ */
9
+ /** A small filled triangle, pointing up. */
10
+ export declare 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>";
11
+ /** The same, pointing down. */
12
+ export declare 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>";
13
+ /** A rising line over an axis: the card's glyph when it has nothing to draw. */
14
+ export declare 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>";
15
+ //# sourceMappingURL=icons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/stock/icons.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,4CAA4C;AAC5C,eAAO,MAAM,EAAE,kIAA0H,CAAC;AAE1I,+BAA+B;AAC/B,eAAO,MAAM,IAAI,kIAA0H,CAAC;AAE5I,gFAAgF;AAChF,eAAO,MAAM,KAAK,6RAAyQ,CAAC"}
@@ -0,0 +1,195 @@
1
+ /**
2
+ * @aparte/plugin-cards/stock — a market quote, drawn with its chart.
3
+ *
4
+ * import { setupStockCard } from '@aparte/plugin-cards/stock';
5
+ *
6
+ * setupStockCard({ tool: 'get_quote' });
7
+ *
8
+ * A stock, an index, a crypto-currency or a currency pair: whatever has a symbol and a
9
+ * price. Four variants of one card: `chart` (the quote at length — the price, the change,
10
+ * the chart against the previous close, the day's figures), `compact` (a row per quote,
11
+ * its sparkline in the change's colour), `ticker` (a strip of quotes that scrolls
12
+ * sideways, like a market ticker — static, nothing moves on its own) and `candles` (the
13
+ * `chart` card with a candlestick chart in place of the line).
14
+ *
15
+ * Several quotes in `chart` or `candles` are drawn as `compact` rows: a watchlist is read
16
+ * by comparing its lines, and a carousel of charts would show one quote at a time — the
17
+ * opposite of a watchlist — at a width (a slide) the chart cannot use. A quote asked for
18
+ * in `candles` that has no candles is drawn with the line chart, from its series: the
19
+ * card shows what it has rather than an empty frame.
20
+ *
21
+ * Your tool keeps its own fields: `readQuotes` already reads Yahoo Finance's quote and
22
+ * chart, Alpha Vantage's `GLOBAL_QUOTE`, Finnhub's quote (when a `symbol` is given beside
23
+ * it), CoinGecko's markets and OHLC, Binance's klines — and `map` covers the rest.
24
+ *
25
+ * **Range buttons.** Give a quote the `ranges` your app can serve and an `onChange` that
26
+ * serves them: the card draws a row of buttons over its chart, and a press asks your app
27
+ * for the quote over that range, drawn in place — the same element, the focus kept on the
28
+ * pressed button. Without an `onChange` no button is drawn: one that does nothing would be
29
+ * a promise the card cannot keep.
30
+ *
31
+ * setupStockCard({
32
+ * tool: 'get_quote',
33
+ * map: (result) => ({ ...result, ranges: ['1D', '5D', '1M', '6M', '1Y', '5Y'] }),
34
+ * onChange: async ({ name, value }, data) => {
35
+ * const [quote] = data.quotes;
36
+ * if (name !== 'range' || !quote) return;
37
+ * const chart = await fetch(`/api/chart?symbol=${quote.symbol}&range=${value}`).then((r) => r.json());
38
+ * // The quote as it was, over the new range: say the range, and send its series
39
+ * // (and its candles, for the `candles` variant) — the old ones would be kept.
40
+ * return { ...quote, range: value, series: chart.series, candles: chart.candles };
41
+ * },
42
+ * });
43
+ *
44
+ * The baseline follows the range: the previous close for a day, where the series starts
45
+ * for anything longer.
46
+ */
47
+ import type { AparteConfig } from '@aparte/core';
48
+ import { type CardSetupOptions } from '../kit/define.js';
49
+ import { type Candle, type ChartPoint } from './chart.js';
50
+ export type StockVariant = 'chart' | 'compact' | 'ticker' | 'candles';
51
+ export type { Candle, ChartPoint } from './chart.js';
52
+ /** Where the market stands for this quote. */
53
+ export type MarketState = 'open' | 'closed' | 'pre' | 'post';
54
+ /** A range the chart covers: one of the usual, or a label of your own ("YTD"). */
55
+ export type StockRange = '1D' | '5D' | '1M' | '6M' | '1Y' | '5Y' | (string & {});
56
+ /**
57
+ * One quote as `map` returns it. `symbol` and `price` are needed — a quote given only
58
+ * candles or a series takes its last close as its price — and every other field adds a
59
+ * line when it is there and nothing when it is not.
60
+ *
61
+ * The change is derived from what is given, and only what is missing is derived — a value
62
+ * the tool gives is never recomputed, so its own rounding stands: `change` from
63
+ * `previousClose`, then `previousClose` from `change` (or, failing that, from
64
+ * `changePercent`), then `changePercent` from the two. When `changePercent` and
65
+ * `previousClose` are both given, both are shown as given and the chart's baseline is the
66
+ * given `previousClose`.
67
+ */
68
+ export interface QuoteInput {
69
+ symbol: string;
70
+ name?: string;
71
+ exchange?: string;
72
+ price?: number | string;
73
+ /** An ISO 4217 code (`USD`) or a usual symbol (`$`). */
74
+ currency?: string;
75
+ /** The change since the previous close, in the currency. */
76
+ change?: number | string;
77
+ /** The change in percent: `0.85` is +0.85 %. `"0.85%"` reads too. */
78
+ changePercent?: number | string;
79
+ previousClose?: number | string;
80
+ open?: number | string;
81
+ high?: number | string;
82
+ low?: number | string;
83
+ volume?: number | string;
84
+ marketCap?: number | string;
85
+ yearHigh?: number | string;
86
+ yearLow?: number | string;
87
+ /** The chart: values in time order, or `{ time, value }` points (also `[time, value]` pairs). */
88
+ series?: number[] | Array<{
89
+ time: string | number | Date;
90
+ value: number;
91
+ }>;
92
+ /**
93
+ * The `candles` variant's chart, in time order. Also read: Yahoo's chart result
94
+ * (`timestamp` + `indicators.quote[0]`), Binance's klines and CoinGecko's OHLC
95
+ * (`[time, open, high, low, close, volume?]` arrays, numbers or strings), and
96
+ * `{ t, o, h, l, c, v }` objects. A quote with candles and no series draws its line
97
+ * from the closes.
98
+ */
99
+ candles?: Array<{
100
+ time: string | number | Date;
101
+ open: number | string;
102
+ high: number | string;
103
+ low: number | string;
104
+ close: number | string;
105
+ volume?: number | string;
106
+ }>;
107
+ /** The range the series (or the candles) covers. */
108
+ range?: StockRange;
109
+ /** The ranges your app can serve: drawn as buttons over the chart when the card has an `onChange`. */
110
+ ranges?: StockRange[];
111
+ marketState?: MarketState;
112
+ /** When the price was: an ISO string, an epoch (seconds or milliseconds) or a Date. */
113
+ time?: string | number | Date;
114
+ /** Where the symbol links to; `http(s)` only. */
115
+ url?: string;
116
+ }
117
+ /** What `map` returns: one quote, a list (a watchlist), or a list with a heading. */
118
+ export type QuotesInput = QuoteInput | QuoteInput[] | {
119
+ title?: string;
120
+ quotes: QuoteInput[];
121
+ };
122
+ /** One quote as the card draws it, once read. */
123
+ export interface Quote {
124
+ symbol: string;
125
+ name?: string;
126
+ exchange?: string;
127
+ price: number;
128
+ /** An ISO 4217 code. */
129
+ currency?: string;
130
+ change?: number;
131
+ /** In percent: `0.85` is +0.85 %. */
132
+ changePercent?: number;
133
+ previousClose?: number;
134
+ open?: number;
135
+ high?: number;
136
+ low?: number;
137
+ volume?: number;
138
+ marketCap?: number;
139
+ yearHigh?: number;
140
+ yearLow?: number;
141
+ /** In time order, at most 2000 points; the candles' closes when only candles were given. */
142
+ series: ChartPoint[];
143
+ /** In time order, at most 2000. */
144
+ candles: Candle[];
145
+ range?: string;
146
+ ranges?: string[];
147
+ marketState?: MarketState;
148
+ time?: Date;
149
+ url?: string;
150
+ }
151
+ /** The data as the card draws it. */
152
+ export interface StockData {
153
+ /** The heading over several quotes ("Tech watchlist"). */
154
+ title?: string;
155
+ quotes: Quote[];
156
+ }
157
+ /**
158
+ * The card's data from the loose shape `map` returns — one quote, a list, or
159
+ * `{ title, quotes }` (also `results`, `items`, `data`, Yahoo's `quoteResponse.result`,
160
+ * Alpha Vantage's `Global Quote`) — or `null` when not one quote has a symbol and a price.
161
+ * At most twelve are kept.
162
+ */
163
+ export declare function readQuotes(raw: unknown): StockData | null;
164
+ /** Which way a quote moved; `undefined` when the tool said nothing of it. */
165
+ export declare function directionOf(quote: Pick<Quote, 'change' | 'changePercent'>): 'up' | 'down' | 'flat' | undefined;
166
+ /**
167
+ * What the chart is split at. The previous close, for a day's chart (a range of one day,
168
+ * or none said): that is what the day's change is measured against. For a longer range,
169
+ * where the series started — yesterday's close in the middle of a year is a line nothing
170
+ * on the chart relates to.
171
+ */
172
+ export declare function baselineOf(quote: Quote): {
173
+ value: number;
174
+ kind: 'close' | 'start';
175
+ } | undefined;
176
+ /**
177
+ * How many decimals a quote's prices are written with. The currency's own (2, 0 for the
178
+ * yen) at least; more where the price needs them — a currency pair is read to four
179
+ * (`1.0832`), a coin under one to four significant digits (`0.00001234`). A float's noise
180
+ * (`182.52999877929688`) is not precision: past four decimals the price is rounded.
181
+ */
182
+ export declare function digitsOf(quote: Pick<Quote, 'price' | 'currency'>): number;
183
+ export declare const stockCard: {
184
+ name: string;
185
+ variants: readonly StockVariant[];
186
+ setup: (options?: CardSetupOptions<StockData, StockVariant>) => () => void;
187
+ segment: (raw: unknown, options?: {
188
+ id?: string;
189
+ variant?: StockVariant | undefined;
190
+ config?: AparteConfig;
191
+ }) => import("../index.js").AparteCardSegment;
192
+ };
193
+ /** Draw a tool's quotes as this card — returns the function that stops it. */
194
+ export declare function setupStockCard(options?: CardSetupOptions<StockData, StockVariant>): () => void;
195
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stock/index.ts"],"names":[],"mappings":"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"}