{% if not violations %}
{# W1b: affirmative empty state. #}
✓ No wash-sale violations detected for {{ selected_year }} across all accounts.
net-alpha checks both directions and across accounts.
{% else %}
{# Build the lag-sort URL preserving current filters. The wash-sales tab
reads `selected_accounts` (list) and `selected_period`; legacy
`filter_account` is singular and no longer populated by the tax route, so
we iterate the list and url-encode each entry. Target /tax directly so we
don't bounce through the /wash-sales → /tax 301 redirect. #}
{% set lag_qs = ['view=' ~ view] %}
{% if filter_ticker %}{% set _ = lag_qs.append('ticker=' ~ (filter_ticker|urlencode)) %}{% endif %}
{% for a in selected_accounts %}{% set _ = lag_qs.append('account=' ~ (a|urlencode)) %}{% endfor %}
{% if selected_period %}{% set _ = lag_qs.append('period=' ~ (selected_period|urlencode)) %}{% endif %}
{% if filter_year %}{% set _ = lag_qs.append('year=' ~ filter_year) %}{% endif %}
{% if filter_confidence %}{% set _ = lag_qs.append('confidence=' ~ (filter_confidence|urlencode)) %}{% endif %}
{% set _ = lag_qs.append('sort=lag') %}
{% set _ = lag_qs.append('order=' ~ next_lag_order) %}
{% set lag_url = '/tax?' ~ lag_qs|join('&') %}
{% for v in g.violations %}
{% set lag = lag_days(v) %}
{% set src = source_label(v) %}
{# Each violation gets its own so Alpine x-data scopes
correctly over both the data row and the explain row. #}
{{ v.loss_sale_date or "—" }}
{{ v.loss_account or "—" }} → {{ v.buy_account or "—" }}
{{ v.triggering_buy_date or "—" }}
{% if lag is not none %}{{ lag }}d{% else %}—{% endif %}
, so HTMX innerHTML swap inserts
valid table content (a
inside a
is hoisted by browsers). #}
{% endfor %}
{% endfor %}
{% endif %}
{# C4: Exempt matches — §1256 contracts that were skipped by the wash-sale detector.
Shown as a sibling section below the violations table. Gray + line-through styling
signals "detected but not penalised". #}
{% if exempt_matches %}
§1256 Exempt Matches
These pairs were detected within the 30-day window but are exempt from wash-sale rules under IRC §1256(c).
Loss date
Loss → Buy
Trigger date
Ticker
Notional disallowed
Matched qty
Confidence
Exempt reason
{% for em in exempt_matches %}
{{ em.loss_sale_date or "—" }}
{{ em.loss_account or "—" }} → {{ em.buy_account or "—" }}