Charts
Three deterministic, pure-SVG charts — no chart library, no canvas. Color comes only from currentColor and the --ch-viz-* scale, every chart shares the loading / empty / ready state machine, and the crosshair is a prop, never a hover.
Sparkline
The inline trend line for asset rows — 24 hourly points, gradient fill under the line, sized to sit beside an AmountDisplay.
<Sparkline data={[]} state="loading" />--ch-bg-raised
Skeleton at exact chart size — no layout shift when data lands.
<Sparkline data={[]} state="empty" />--ch-border-faint--ch-fg-faint
No history yet — dashed bounds with the mono NO DATA mark.
<Sparkline data={btc.sparkline} label="BTC 24-hour trend" />--ch-viz-1
BTC, last 24 hours, on viz-1 with the gradient fill.
<Sparkline data={dbl.sparkline} fill={false} className="text-viz-4" />--ch-viz-4
DBL on viz-4, fill off — for dense tables where stacked gradients muddy.
PriceChart
The full line + area chart with y-grid and x-ticks — here the BTC → XMR rate over 24 hours at 30-minute resolution. The crosshair prop pins a static marker with its value; there is no hover dependency to lose on touch.
<PriceChart data={[]} state="loading" />--ch-bg-raised
Full-size skeleton block.
<PriceChart data={[]} state="empty" />--ch-border-faint--ch-fg-faint
Pair has no rate history on this node yet.
<PriceChart data={rates} xLabels={["14:30","20:30","02:30","08:00","14:00"]} formatY={(v) => v.toFixed(1)} />--ch-viz-1--ch-viz-grid--ch-fg-faint
48 points, four y-grid lines, five time ticks.
<PriceChart data={rates} xLabels={labels} crosshair={36} />--ch-viz-1--ch-border-strong--ch-bg
Marker pinned at point 36 — dashed rule, ring dot, and the value read out above the plot.
AllocationDonut
Portfolio share as ring segments cycling viz-1 through viz-5 with hairline gaps, and a free center slot — here the fiat total.
<AllocationDonut data={[]} state="loading" />--ch-bg-raised--ch-radius-pill
Circle skeleton at ring size.
<AllocationDonut data={[]} state="empty" />--ch-border-faint--ch-fg-faint
Fresh install — nothing funded yet.
<AllocationDonut data={allocation}>
<span>{totalFiat}</span>
</AllocationDonut>--ch-viz-1--ch-viz-2--ch-viz-3--ch-viz-4--ch-viz-5--ch-viz-grid
Six assets by fiat value, total in the center slot.
<AllocationDonut data={[{ label: "BTC", value: 164741 }]} />--ch-viz-1--ch-viz-grid
One holding — a full ring with no segment gap.
Across themes
The allocation ring under dark, light, and Harbor Mode — the viz scale is tuned per layer, so series stay distinguishable on every background.
<AllocationDonut data={allocation} size={140}>
<span>{totalFiat}</span>
</AllocationDonut>--ch-viz-1--ch-viz-2--ch-viz-3--ch-viz-4--ch-viz-5