{# Bullet chart region — v0.61.30 (#880). Stephen Few bullet rows — one row per item. Each row carries: - label (left text) - actual (foreground bar) - target (vertical tick at target/max position) - reference_bands (#883) drawn behind as comparative qualitative zones (red/amber/green or any colour token). Pre-computed MVP: rows come straight off `items` via the `bullet_label` / `bullet_actual` / `bullet_target` column refs in the IR. Per-group_by aggregation is deferred (would need multi-measure support in `_compute_bucketed_aggregates`). Card safety: region emits zero chrome + zero title. The dashboard slot owns both via region_card. v0.62 CSS refactor: inline Tailwind → semantic .dz-bullet-* classes (components/regions.css). Per-band colour stays inline (per-element shape colour driven by reference_bands data). #} {% from 'macros/region_wrapper.html' import region_card %} {% call region_card(title) %}
{% if bullet_rows and bullet_rows | length > 0 and bullet_max_value > 0 %} {% set _band_colours = { 'target': 'hsl(var(--primary))', 'positive': 'hsl(145, 55%, 45%)', 'warning': 'hsl(40, 90%, 55%)', 'destructive': 'hsl(var(--destructive))', 'muted': 'hsl(var(--muted-foreground))', } %}
{% for row in bullet_rows %} {% set actual_pct = (row.actual / bullet_max_value * 100) %} {% set target_pct = (row.target / bullet_max_value * 100) if row.target is not none else 0 %}
{{ row.label }}
{# Comparative bands behind the bar — render before the bar so the bar sits on top. Bands are absolute-positioned by from/to as a percentage of bullet_max_value. #} {% for band in (reference_bands or []) %} {% set band_left_pct = (band['from'] / bullet_max_value * 100) %} {% set band_width_pct = ((band.to - band['from']) / bullet_max_value * 100) %} {% set band_colour = _band_colours.get(band.color, _band_colours['target']) %} {% endfor %} {# Actual bar — primary tint, full opacity so it reads above the muted bands. #} {# Target tick — vertical line at target_pct. Only render when the row has a target value. #} {% if row.target is not none %} {% endif %}
{{ row.actual | round(1) }}{% if row.target is not none %} / {{ row.target | round(1) }}{% endif %}
{% endfor %}

{{ bullet_rows | length }} rows · scale 0–{{ bullet_max_value | round(1) }}

{% else %}

{{ empty_message | default("No data available.") }}

{% endif %}
{% endcall %}