@cfasim-ui/charts 0.4.16 → 0.5.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.
@@ -1,5 +1,5 @@
1
1
  import { NumberFormat } from '@cfasim-ui/shared';
2
- import { ChartData, DateFormat, ChartCommonProps, ChartHoverPayload, ChartTooltipBaseProps, BlendMode, LineMarkStyle } from '../_shared/index.js';
2
+ import { ChartData, DateFormat, ChartCommonProps, ChartHoverPayload, ChartTooltipBaseProps, BlendMode, LineMarkStyle, LabelStyle } from '../_shared/index.js';
3
3
  export type BarChartData = ChartData;
4
4
  export interface BarSeries {
5
5
  /** Bar values; one entry per category. `y` is accepted as an alias. */
@@ -57,6 +57,64 @@ export interface BarSummaryLine extends LineMarkStyle {
57
57
  /** Override the line's value-axis ceiling. Defaults to the line's own max. */
58
58
  valueMax?: number;
59
59
  }
60
+ /** Context passed to a `barLabels.format` function. */
61
+ export interface BarLabelContext {
62
+ value: number;
63
+ categoryIndex: number;
64
+ seriesIndex: number;
65
+ /** The resolved category label string. */
66
+ category: string;
67
+ }
68
+ /**
69
+ * Styling and behavior for value labels drawn directly on the bars (an
70
+ * alternative to reading values off the value axis — see `valueAxis`).
71
+ * Most useful with `layout="stacked"`, where each segment carries its own
72
+ * value. Extends `LabelStyle` (`fontSize` / `fontWeight`).
73
+ */
74
+ export interface BarLabelStyle extends LabelStyle {
75
+ /**
76
+ * How to turn a bar's numeric value into label text. A `NumberFormat`
77
+ * (preset/printf/function), or a function receiving `(value, context)`
78
+ * for fully custom strings (e.g. `">99%"`). Return `""` to omit a
79
+ * label. When unset, falls back to `valueTickFormat`, then a default.
80
+ */
81
+ format?: NumberFormat | ((value: number, ctx: BarLabelContext) => string);
82
+ /**
83
+ * Label text color. `"auto"` (default) picks white or near-black per
84
+ * segment by the fill's luminance for readable contrast; outside-placed
85
+ * labels use the chart's text color. Any other CSS color is used as-is
86
+ * for every label.
87
+ */
88
+ color?: string;
89
+ /**
90
+ * Where to draw each label. `"auto"` (default) centers it inside the
91
+ * segment when the text fits, otherwise just past the segment's
92
+ * high-value edge. `"inside"` / `"outside"` force one placement.
93
+ */
94
+ placement?: "auto" | "inside" | "outside";
95
+ /**
96
+ * Alignment of an *inside* label along the value axis. `"center"`
97
+ * (default) centers it in its segment; `"start"` pins it to the
98
+ * segment's low-value edge (left edge for horizontal bars); `"end"`
99
+ * pins it to the high-value edge. Outside/overflow labels ignore this
100
+ * and always sit just past the high-value edge.
101
+ */
102
+ align?: "start" | "center" | "end";
103
+ /**
104
+ * How to handle labels that would collide along the value axis (common
105
+ * with many small adjacent segments). `"shift"` (default) nudges them
106
+ * apart toward higher values; `"hide"` drops the colliding label. Either
107
+ * way, a label pushed past the chart edge is hidden.
108
+ */
109
+ overlap?: "shift" | "hide";
110
+ /**
111
+ * Segments smaller than this many pixels (along the value axis) never
112
+ * get an *inside* label — they fall back to outside placement (or hide,
113
+ * per `overlap`). Use to suppress labels crammed into thin slivers.
114
+ * Default 0 (size alone never forces a label out; text fit still does).
115
+ */
116
+ minSize?: number;
117
+ }
60
118
  interface BarChartProps extends ChartCommonProps {
61
119
  /** Single-series values. Equivalent to `y`. */
62
120
  data?: BarChartData;
@@ -112,6 +170,15 @@ interface BarChartProps extends ChartCommonProps {
112
170
  valueTickFormat?: NumberFormat;
113
171
  /** Formatter for category-axis labels. Receives the resolved category string. */
114
172
  categoryFormat?: (label: string, index: number) => string;
173
+ /**
174
+ * Alignment of the category labels in horizontal orientation. `"end"`
175
+ * (default) right-aligns them against the plot's left edge; `"start"`
176
+ * left-aligns them at the chart's left margin; `"center"` centers them
177
+ * in the margin. The `categoryHeader`, if set, follows the same
178
+ * alignment. Ignored in vertical orientation (labels stay centered
179
+ * under each column).
180
+ */
181
+ categoryAlign?: "start" | "center" | "end";
115
182
  /**
116
183
  * Date-tick formatter for date-mode category labels (auto-detected
117
184
  * when every entry of `categories` parses as a date). Ignored unless
@@ -133,6 +200,33 @@ interface BarChartProps extends ChartCommonProps {
133
200
  */
134
201
  groupGap?: number;
135
202
  valueGrid?: boolean;
203
+ /**
204
+ * Draw the value axis (its line and tick labels). Default true. Set
205
+ * false for a clean "value-on-bar" look where each segment is labeled
206
+ * via `barLabels` and there's no axis to read against.
207
+ */
208
+ valueAxis?: boolean;
209
+ /**
210
+ * Draw the numeric value directly on each bar instead of (or alongside)
211
+ * reading it off the value axis. `true` uses defaults; pass a
212
+ * `BarLabelStyle` to customize formatting, color, placement, and
213
+ * overlap handling. Most useful with `layout="stacked"`.
214
+ */
215
+ barLabels?: boolean | BarLabelStyle;
216
+ /**
217
+ * Header drawn above the category labels (e.g. "Scenario"). Aligned to
218
+ * match the category labels — right-edge-aligned in horizontal
219
+ * orientation, centered under each column in vertical. Reserves a row
220
+ * of space above the plot.
221
+ */
222
+ categoryHeader?: string;
223
+ /**
224
+ * Header drawn above the bars / value area (e.g. "Proportion of
225
+ * simulations"), left-aligned to where the bars start. Pairs with
226
+ * `categoryHeader` to label both columns of a value-on-bar chart.
227
+ * Reserves a row of space above the plot.
228
+ */
229
+ valueHeader?: string;
136
230
  }
137
231
  declare function __VLS_template(): {
138
232
  attrs: Partial<{}>;
@@ -167,6 +261,7 @@ declare const __VLS_component: import('vue').DefineComponent<BarChartProps, {},
167
261
  barPadding: number;
168
262
  groupGap: number;
169
263
  valueGrid: boolean;
264
+ valueAxis: boolean;
170
265
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
171
266
  containerRef: HTMLDivElement;
172
267
  svgRef: SVGSVGElement;
@@ -198,10 +198,10 @@ declare function __VLS_template(): {
198
198
  $forceUpdate: () => void;
199
199
  $nextTick: typeof import('vue').nextTick;
200
200
  $watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (...args: [R, R, import('@vue/reactivity').OnCleanup]) => any : (...args: [any, any, import('@vue/reactivity').OnCleanup]) => any, options?: import('vue').WatchOptions): import('vue').WatchStopHandle;
201
- } & Readonly<{}> & Omit<Readonly<{}> & Readonly<{}>, "setData" | "getEl"> & import('vue').ShallowUnwrapRef<{
202
- setData(next: import('./ChoroplethTooltip').ChoroplethTooltipData | null): void;
203
- getEl(): HTMLDivElement | null;
204
- }> & {} & import('vue').ComponentCustomProperties & {} & {
201
+ } & Readonly<{}> & Omit<Readonly<{}> & Readonly<{}>, "setData" | "getEl"> & {
202
+ setData: (next: import('./ChoroplethTooltip').ChoroplethTooltipData | null) => void;
203
+ getEl: () => HTMLDivElement | null;
204
+ } & {} & import('vue').ComponentCustomProperties & {} & {
205
205
  $slots: Readonly<{
206
206
  default?(props: import('./ChoroplethTooltip').ChoroplethTooltipData): unknown;
207
207
  }> & {
@@ -294,10 +294,10 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {}, {}
294
294
  $forceUpdate: () => void;
295
295
  $nextTick: typeof import('vue').nextTick;
296
296
  $watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (...args: [R, R, import('@vue/reactivity').OnCleanup]) => any : (...args: [any, any, import('@vue/reactivity').OnCleanup]) => any, options?: import('vue').WatchOptions): import('vue').WatchStopHandle;
297
- } & Readonly<{}> & Omit<Readonly<{}> & Readonly<{}>, "setData" | "getEl"> & import('vue').ShallowUnwrapRef<{
298
- setData(next: import('./ChoroplethTooltip').ChoroplethTooltipData | null): void;
299
- getEl(): HTMLDivElement | null;
300
- }> & {} & import('vue').ComponentCustomProperties & {} & {
297
+ } & Readonly<{}> & Omit<Readonly<{}> & Readonly<{}>, "setData" | "getEl"> & {
298
+ setData: (next: import('./ChoroplethTooltip').ChoroplethTooltipData | null) => void;
299
+ getEl: () => HTMLDivElement | null;
300
+ } & {} & import('vue').ComponentCustomProperties & {} & {
301
301
  $slots: Readonly<{
302
302
  default?(props: import('./ChoroplethTooltip').ChoroplethTooltipData): unknown;
303
303
  }> & {
@@ -9,7 +9,22 @@ export interface ColumnConfig {
9
9
  label?: string;
10
10
  width?: ColumnWidth | number;
11
11
  align?: ColumnAlign;
12
+ /** Class applied to every body `<td>` in this column. */
12
13
  cellClass?: string;
14
+ /**
15
+ * Class applied to both the header `<th>` and every body `<td>` in
16
+ * this column. Use for styling that should span the whole column
17
+ * (borders, backgrounds, fonts). For body-only styling, use
18
+ * `cellClass`.
19
+ */
20
+ columnClass?: string;
21
+ /**
22
+ * Allow cell contents to wrap to multiple lines when wider than the
23
+ * column. Default `false` — cells stay on one line and truncate with
24
+ * an ellipsis. Set to `true` for text-heavy columns where the full
25
+ * value should remain visible.
26
+ */
27
+ wrap?: boolean;
13
28
  /**
14
29
  * Custom formatter for cell values in this column. Accepts a
15
30
  * {@link NumberFormat} (preset name, printf-style string, or
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Color helpers for picking a readable text color against a bar fill.
3
+ * The luminance math is pure and unit-testable; resolving CSS values
4
+ * that aren't plain hex/rgb (named colors, `var(--x)`) needs the DOM and
5
+ * is handled separately by {@link resolveColorToRgb}.
6
+ */
7
+ export type Rgb = [number, number, number];
8
+ /**
9
+ * Parse a hex (`#rgb`, `#rrggbb`, `#rrggbbaa`) or `rgb()/rgba()` string to
10
+ * `[r, g, b]` in 0..255. Returns null for anything else (named colors,
11
+ * `var(...)`, `hsl(...)`) — resolve those via {@link resolveColorToRgb}.
12
+ */
13
+ export declare function parseRgb(color: string): Rgb | null;
14
+ /** WCAG relative luminance (0 = black, 1 = white) for an RGB triple. */
15
+ export declare function relativeLuminance([r, g, b]: Rgb): number;
16
+ /**
17
+ * Resolve any CSS color string (including named colors and `var(--x)`) to
18
+ * an RGB triple by letting the browser compute it on a hidden probe
19
+ * element. Cached per input. Returns null in non-DOM environments or when
20
+ * the value can't be resolved. Plain hex/rgb shortcut through
21
+ * {@link parseRgb} without touching the DOM.
22
+ */
23
+ export declare function resolveColorToRgb(color: string): Rgb | null;
24
+ /**
25
+ * Pick the more readable of `light`/`dark` text colors for a given fill.
26
+ * Uses the WCAG luminance threshold (0.179) that maximizes contrast
27
+ * against black-or-white text. When the fill can't be resolved (e.g. an
28
+ * unresolvable CSS var in a non-DOM context), falls back to `light`.
29
+ */
30
+ export declare function pickContrastColor(fill: string, light?: string, dark?: string): string;
@@ -0,0 +1 @@
1
+ export {};
@@ -11,4 +11,5 @@ export { default as ChartAnnotations } from './ChartAnnotations';
11
11
  export type { ChartAnnotation } from './annotations.js';
12
12
  export { useChartFoundation, makeTooltipValueFormatter, type ChartFoundationOptions, } from './useChartFoundation.js';
13
13
  export type { ChartCommonProps, ChartHoverPayload, ChartTooltipValue, ChartTooltipBaseProps, TitleStyle, LabelStyle, BlendMode, LineMarkStyle, } from './chartProps.js';
14
+ export { parseRgb, relativeLuminance, resolveColorToRgb, pickContrastColor, type Rgb, } from './contrast.js';
14
15
  export { parseDate, isDateLike, isAllDates, pickDateTicks, formatDate, DATE_FORMAT_PRESETS, type DateFormat, type DateFormatPreset, type DateTickUnit, type DateTimezone, } from './dateAxis.js';
@@ -1,2 +1,2 @@
1
- import { r as e, t } from "./hsaMapping-Devrp7Rk.js";
1
+ import { r as e, t } from "./hsaMapping-BahYDmea.js";
2
2
  export { t as fipsToHsa, e as hsaNames };
package/dist/index.css CHANGED
@@ -1,2 +1,2 @@
1
- .line-chart-wrapper:hover .chart-menu-button,.bar-chart-wrapper:hover .chart-menu-button,.choropleth-wrapper:hover .chart-menu-button,.line-chart-wrapper:focus-within .chart-menu-button,.bar-chart-wrapper:focus-within .chart-menu-button,.choropleth-wrapper:focus-within .chart-menu-button,.line-chart-wrapper.is-fullscreen .chart-menu-button,.bar-chart-wrapper.is-fullscreen .chart-menu-button,.choropleth-wrapper.is-fullscreen .chart-menu-button{opacity:1}.line-chart-wrapper.is-fullscreen,.bar-chart-wrapper.is-fullscreen,.choropleth-wrapper.is-fullscreen{z-index:var(--cfasim-z-fullscreen,1000);background:var(--color-bg-0,#fff);color:var(--color-text,inherit);box-sizing:border-box;flex-direction:column;justify-content:center;padding:2em;display:flex;position:fixed;inset:0}.choropleth-wrapper.is-fullscreen svg{flex:auto;width:100%;height:100%;min-height:0}.chart-sr-only{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.chart-menu-trigger-area[data-v-c74e2889]{z-index:1;position:absolute;top:0;right:0}.chart-menu-button[data-v-c74e2889]{border:1px solid var(--color-border);background:var(--color-bg-0,#fff);width:28px;height:28px;color:var(--color-text-secondary);cursor:pointer;opacity:0;border-radius:.25em;justify-content:center;align-items:center;transition:opacity .15s;display:flex}.chart-menu-button[data-state=open][data-v-c74e2889]{opacity:1}.chart-menu-button[data-v-c74e2889]:hover{background:var(--color-bg-1,#0000000d);color:var(--color-text)}.chart-menu-content{z-index:100;background:var(--color-bg-0);border:1px solid var(--color-border);border-radius:.25em;min-width:140px;padding:.25em;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.chart-menu-item{font-size:var(--font-size-sm);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap;border-radius:.25em;outline:none;align-items:center;padding:.375em .5em;display:flex}.chart-menu-item[data-highlighted]{background:var(--color-primary);color:#fff}.line-chart-wrapper[data-v-0d24242d]{width:100%;position:relative}.line-chart-tooltip-label[data-v-0d24242d]{margin-bottom:.25em;font-weight:600}.line-chart-tooltip-row[data-v-0d24242d]{align-items:center;gap:.375em;display:flex}.line-chart-download-link[data-v-0d24242d]{text-align:right;font-size:var(--font-size-sm);margin-top:.25em;display:block}.line-chart-tooltip-swatch[data-v-0d24242d]{border-radius:50%;flex-shrink:0;width:.625em;height:.625em;display:inline-block}.line-chart-download-button{border:1px solid var(--color-border);background:var(--color-bg-0,#fff);color:var(--color-text);font-size:var(--font-size-sm);cursor:pointer;border-radius:.25em;align-items:center;margin-top:.5em;padding:.5em 1em;display:inline-flex}.line-chart-download-button:hover{background:var(--color-bg-1,#0000000d)}.line-chart-download-button:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.bar-chart-wrapper[data-v-bce03a52]{width:100%;position:relative}.bar-chart-tooltip-label[data-v-bce03a52]{margin-bottom:.25em;font-weight:600}.bar-chart-tooltip-row[data-v-bce03a52]{align-items:center;gap:.375em;display:flex}.bar-chart-download-link[data-v-bce03a52]{text-align:right;font-size:var(--font-size-sm);margin-top:.25em;display:block}.bar-chart-tooltip-swatch[data-v-bce03a52]{border-radius:50%;flex-shrink:0;width:.625em;height:.625em;display:inline-block}.bar-chart-download-button{border:1px solid var(--color-border);background:var(--color-bg-0,#fff);color:var(--color-text);font-size:var(--font-size-sm);cursor:pointer;border-radius:.25em;align-items:center;margin-top:.5em;padding:.5em 1em;display:inline-flex}.bar-chart-download-button:hover{background:var(--color-bg-1,#0000000d)}.bar-chart-download-button:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.choropleth-wrapper[data-v-b11a80ed]{--choropleth-legend-bg:var(--color-bg-0,#fff);width:100%;position:relative}.choropleth-wrapper svg[data-v-b11a80ed]{width:100%;height:auto;display:block}.choropleth-wrapper.pannable svg[data-v-b11a80ed]{cursor:grab}.choropleth-wrapper.pannable svg[data-v-b11a80ed]:active{cursor:grabbing}.state-path[data-v-b11a80ed]{cursor:pointer}.choropleth-reset[data-v-b11a80ed]{font:inherit;color:var(--color-text-secondary,#555);background:var(--color-bg-0,#fff);border:1px solid var(--color-border,#e5e7eb);cursor:pointer;border-radius:4px;padding:4px 10px;font-size:12px;position:absolute;bottom:8px;left:8px;box-shadow:0 1px 2px #0000000d}.choropleth-reset[data-v-b11a80ed]:hover{background:var(--color-bg-1,#f8f9fa);color:var(--color-text,#212529)}.choropleth-header[data-v-b11a80ed]{background:var(--choropleth-legend-bg);color:currentColor;border-radius:4px;flex-direction:column;align-items:center;gap:10px;width:fit-content;margin:0 auto;padding:8px 14px;display:flex}.choropleth-title[data-v-b11a80ed]{white-space:pre-line;font-size:14px;font-weight:600;line-height:1.2}.choropleth-legend[data-v-b11a80ed]{align-items:center;gap:14px;font-size:13px;line-height:1.2;display:flex}.choropleth-legend-title[data-v-b11a80ed]{font-weight:600}.choropleth-legend-item[data-v-b11a80ed]{align-items:center;gap:6px;display:inline-flex}.choropleth-legend-swatch[data-v-b11a80ed]{border-radius:3px;width:12px;height:12px;display:inline-block}.choropleth-legend-continuous[data-v-b11a80ed]{flex-direction:column;width:160px;display:flex}.choropleth-legend-gradient[data-v-b11a80ed]{border-radius:2px;height:12px}.choropleth-legend-ticks[data-v-b11a80ed]{opacity:.7;height:14px;margin-top:4px;font-size:11px;position:relative}.choropleth-legend-ticks>span[data-v-b11a80ed]{position:absolute;transform:translate(-50%)}.chart-tooltip-anchor[data-v-44377f70]{pointer-events:none;width:1px;height:1px;position:absolute}.chart-tooltip-content{z-index:100;background:var(--color-bg-0,#fff);border:1px solid var(--color-border,#e5e7eb);font-size:var(--font-size-sm,.875rem);pointer-events:none;border-radius:.375em;padding:.5em .75em;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.TableOuter[data-v-20a55780]{display:inline-block;position:relative}.TableOuter.full-width[data-v-20a55780]{display:block}.TableWrapper[data-v-20a55780]{font-size:var(--font-size-sm);overflow-x:auto}.Table[data-v-20a55780]{border-collapse:collapse;font-variant-numeric:tabular-nums;border:1px solid var(--color-border);table-layout:fixed;margin:0;display:table}.Table.full-width[data-v-20a55780]{width:100%}.Table tr[data-v-20a55780],.Table th[data-v-20a55780],.Table td[data-v-20a55780]{background:0 0;border:none}.Table th[data-v-20a55780],.Table td[data-v-20a55780]{white-space:nowrap;text-align:left;padding:.75em 1.25em}.Table th[data-v-20a55780]{border-bottom:1px solid var(--color-border-header);font-weight:600;position:sticky;top:0}.Table tbody td[data-v-20a55780]{border-bottom:1px solid var(--color-border)}.Table tbody tr:last-child td[data-v-20a55780]{border-bottom:none}.TableOuter[data-v-20a55780] .chart-menu-trigger-area{top:4px;right:4px}.TableOuter[data-v-20a55780] .chart-menu-button{opacity:1}.TableOuter.has-menu .Table thead th[data-v-20a55780]:last-child{padding-right:2.5em}.data-table-download-button{border:1px solid var(--color-border);background:var(--color-bg-0,#fff);color:var(--color-text);font-size:var(--font-size-sm);cursor:pointer;border-radius:.25em;align-items:center;margin-top:.75em;padding:.5em 1em;display:inline-flex}.data-table-download-button:hover{background:var(--color-bg-1,#0000000d)}.data-table-download-button:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.data-table-download-link{text-align:right;font-size:var(--font-size-sm);margin-top:.25em;display:block}
1
+ .line-chart-wrapper:hover .chart-menu-button,.bar-chart-wrapper:hover .chart-menu-button,.choropleth-wrapper:hover .chart-menu-button,.line-chart-wrapper:focus-within .chart-menu-button,.bar-chart-wrapper:focus-within .chart-menu-button,.choropleth-wrapper:focus-within .chart-menu-button,.line-chart-wrapper.is-fullscreen .chart-menu-button,.bar-chart-wrapper.is-fullscreen .chart-menu-button,.choropleth-wrapper.is-fullscreen .chart-menu-button{opacity:1}.line-chart-wrapper.is-fullscreen,.bar-chart-wrapper.is-fullscreen,.choropleth-wrapper.is-fullscreen{z-index:var(--cfasim-z-fullscreen,1000);background:var(--color-bg-0,#fff);color:var(--color-text,inherit);box-sizing:border-box;flex-direction:column;justify-content:center;padding:2em;display:flex;position:fixed;inset:0}.choropleth-wrapper.is-fullscreen svg{flex:auto;width:100%;height:100%;min-height:0}.chart-sr-only{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.chart-menu-trigger-area[data-v-c74e2889]{z-index:1;position:absolute;top:0;right:0}.chart-menu-button[data-v-c74e2889]{border:1px solid var(--color-border);background:var(--color-bg-0,#fff);width:28px;height:28px;color:var(--color-text-secondary);cursor:pointer;opacity:0;border-radius:.25em;justify-content:center;align-items:center;transition:opacity .15s;display:flex}.chart-menu-button[data-state=open][data-v-c74e2889]{opacity:1}.chart-menu-button[data-v-c74e2889]:hover{background:var(--color-bg-1,#0000000d);color:var(--color-text)}.chart-menu-content{z-index:100;background:var(--color-bg-0);border:1px solid var(--color-border);border-radius:.25em;min-width:140px;padding:.25em;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.chart-menu-item{font-size:var(--font-size-sm);cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap;border-radius:.25em;outline:none;align-items:center;padding:.375em .5em;display:flex}.chart-menu-item[data-highlighted]{background:var(--color-primary);color:#fff}.line-chart-wrapper[data-v-0d24242d]{width:100%;position:relative}.line-chart-tooltip-label[data-v-0d24242d]{margin-bottom:.25em;font-weight:600}.line-chart-tooltip-row[data-v-0d24242d]{align-items:center;gap:.375em;display:flex}.line-chart-download-link[data-v-0d24242d]{text-align:right;font-size:var(--font-size-sm);margin-top:.25em;display:block}.line-chart-tooltip-swatch[data-v-0d24242d]{border-radius:50%;flex-shrink:0;width:.625em;height:.625em;display:inline-block}.line-chart-download-button{border:1px solid var(--color-border);background:var(--color-bg-0,#fff);color:var(--color-text);font-size:var(--font-size-sm);cursor:pointer;border-radius:.25em;align-items:center;margin-top:.5em;padding:.5em 1em;display:inline-flex}.line-chart-download-button:hover{background:var(--color-bg-1,#0000000d)}.line-chart-download-button:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.bar-chart-wrapper[data-v-59c746d2]{width:100%;position:relative}.bar-chart-tooltip-label[data-v-59c746d2]{margin-bottom:.25em;font-weight:600}.bar-chart-tooltip-row[data-v-59c746d2]{align-items:center;gap:.375em;display:flex}.bar-chart-download-link[data-v-59c746d2]{text-align:right;font-size:var(--font-size-sm);margin-top:.25em;display:block}.bar-chart-tooltip-swatch[data-v-59c746d2]{border-radius:50%;flex-shrink:0;width:.625em;height:.625em;display:inline-block}.bar-chart-download-button{border:1px solid var(--color-border);background:var(--color-bg-0,#fff);color:var(--color-text);font-size:var(--font-size-sm);cursor:pointer;border-radius:.25em;align-items:center;margin-top:.5em;padding:.5em 1em;display:inline-flex}.bar-chart-download-button:hover{background:var(--color-bg-1,#0000000d)}.bar-chart-download-button:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.choropleth-wrapper[data-v-b11a80ed]{--choropleth-legend-bg:var(--color-bg-0,#fff);width:100%;position:relative}.choropleth-wrapper svg[data-v-b11a80ed]{width:100%;height:auto;display:block}.choropleth-wrapper.pannable svg[data-v-b11a80ed]{cursor:grab}.choropleth-wrapper.pannable svg[data-v-b11a80ed]:active{cursor:grabbing}.state-path[data-v-b11a80ed]{cursor:pointer}.choropleth-reset[data-v-b11a80ed]{font:inherit;color:var(--color-text-secondary,#555);background:var(--color-bg-0,#fff);border:1px solid var(--color-border,#e5e7eb);cursor:pointer;border-radius:4px;padding:4px 10px;font-size:12px;position:absolute;bottom:8px;left:8px;box-shadow:0 1px 2px #0000000d}.choropleth-reset[data-v-b11a80ed]:hover{background:var(--color-bg-1,#f8f9fa);color:var(--color-text,#212529)}.choropleth-header[data-v-b11a80ed]{background:var(--choropleth-legend-bg);color:currentColor;border-radius:4px;flex-direction:column;align-items:center;gap:10px;width:fit-content;margin:0 auto;padding:8px 14px;display:flex}.choropleth-title[data-v-b11a80ed]{white-space:pre-line;font-size:14px;font-weight:600;line-height:1.2}.choropleth-legend[data-v-b11a80ed]{align-items:center;gap:14px;font-size:13px;line-height:1.2;display:flex}.choropleth-legend-title[data-v-b11a80ed]{font-weight:600}.choropleth-legend-item[data-v-b11a80ed]{align-items:center;gap:6px;display:inline-flex}.choropleth-legend-swatch[data-v-b11a80ed]{border-radius:3px;width:12px;height:12px;display:inline-block}.choropleth-legend-continuous[data-v-b11a80ed]{flex-direction:column;width:160px;display:flex}.choropleth-legend-gradient[data-v-b11a80ed]{border-radius:2px;height:12px}.choropleth-legend-ticks[data-v-b11a80ed]{opacity:.7;height:14px;margin-top:4px;font-size:11px;position:relative}.choropleth-legend-ticks>span[data-v-b11a80ed]{position:absolute;transform:translate(-50%)}.chart-tooltip-anchor[data-v-44377f70]{pointer-events:none;width:1px;height:1px;position:absolute}.chart-tooltip-content{z-index:100;background:var(--color-bg-0,#fff);border:1px solid var(--color-border,#e5e7eb);font-size:var(--font-size-sm,.875rem);pointer-events:none;border-radius:.375em;padding:.5em .75em;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.TableOuter[data-v-21721f41]{display:inline-block;position:relative}.TableOuter.full-width[data-v-21721f41]{display:block}.TableWrapper[data-v-21721f41]{font-size:var(--font-size-sm);overflow-x:auto}.Table[data-v-21721f41]{border-collapse:collapse;font-variant-numeric:tabular-nums;border:1px solid var(--color-border);table-layout:fixed;margin:0;display:table}.Table.full-width[data-v-21721f41]{width:100%}.Table tr[data-v-21721f41],.Table th[data-v-21721f41],.Table td[data-v-21721f41]{background:0 0;border:none}.Table th[data-v-21721f41],.Table td[data-v-21721f41]{white-space:nowrap;text-overflow:ellipsis;text-align:left;padding:.75em 1.25em;overflow:hidden}.Table th.cell-wrap[data-v-21721f41],.Table td.cell-wrap[data-v-21721f41]{white-space:normal;text-overflow:clip;overflow:visible}.Table th[data-v-21721f41]{border-bottom:1px solid var(--color-border-header);font-weight:600;position:sticky;top:0}.Table tbody td[data-v-21721f41]{border-bottom:1px solid var(--color-border)}.Table tbody tr:last-child td[data-v-21721f41]{border-bottom:none}.TableOuter[data-v-21721f41] .chart-menu-trigger-area{top:4px;right:4px}.TableOuter[data-v-21721f41] .chart-menu-button{opacity:1}.TableOuter.has-menu .Table thead th[data-v-21721f41]:last-child{padding-right:2.5em}.data-table-download-button{border:1px solid var(--color-border);background:var(--color-bg-0,#fff);color:var(--color-text);font-size:var(--font-size-sm);cursor:pointer;border-radius:.25em;align-items:center;margin-top:.75em;padding:.5em 1em;display:inline-flex}.data-table-download-button:hover{background:var(--color-bg-1,#0000000d)}.data-table-download-button:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.data-table-download-link{text-align:right;font-size:var(--font-size-sm);margin-top:.25em;display:block}
2
2
  /*$vite$:1*/