kairix
{% if step is defined %}
{% for i in range(1, total_steps + 1) %}
{% if i < step %}✓
{% elif i == step %}{{ i }}
{% else %}{{ i }}
{% endif %}
{% if not loop.last %}{% endif %}
{% endfor %}
{% endif %}
{% block content %}{% endblock %}
{# Shared layout primitive (#488): card → content → banner slot →
action row, on every screen. Async results (validation, scan,
handshake, search, progress) render INTO this always-present
fixed-size slot, which always sits ABOVE the action row — so no
interactive element ever moves when a result arrives. #}
{%- block actions -%}{%- endblock -%}