{# Wash-sales tab content — inner body for the /tax wash-sales tab. Context variables expected: view, filter_ticker, filter_account, filter_year, filter_confidence, tickers, accounts, years, selected_year, selected_accounts, accounts_available, account_filter_active, plus table-view keys: violations, summary, groups, expand_default, lag_days, source_label, sort, order, next_lag_order or calendar-view keys: markers #} {% import "_account_multi_select.html" as macros_acc %} {# Unified filter bar — fields used by both views #} {% set _has_filters = filter_ticker or selected_accounts or filter_confidence or filter_year_explicit %}
Filter {% if _has_filters %}— {% if filter_ticker %}{{ filter_ticker }} · {% endif %}{% if selected_accounts %}{{ selected_accounts|join(', ') }} · {% endif %}{% if filter_year %}{{ filter_year }} · {% endif %}{% if filter_confidence %}{{ filter_confidence }}{% endif %}{% endif %}
{% for t in tickers %}
{{ macros_acc.account_multi_select(accounts_available, selected_accounts) }}
{% if view == 'calendar' %} {% else %} {% endif %}
{% if sort %}{% endif %} {% if order %}{% endif %} Reset
{# W2: active-filter chip summary row with ⌫ reset link. Always rendered so the reset anchor (data-testid="filter-reset") is always in the DOM. #}
Filters: {% if filter_ticker %} ticker: {{ filter_ticker }} {% endif %} {% if selected_accounts %} account: {{ selected_accounts|join(', ') }} {% endif %} {% if filter_confidence %} confidence: {{ filter_confidence }} {% endif %} ✗ reset
{# W3: compact calendar strip — always rendered so the testid is always in the DOM. On the table view this renders as a minimal month-header strip. The full ribbon (portfolio equity-curve page) keeps its own rich chart. #}
{% for label in ["J","F","M","A","M","J","J","A","S","O","N","D"] %} {{ label }} {% endfor %}
{# T5: realized-P/L stacked mini-bar — losses left of midpoint, gains right. Uses realized_kpis (OffsetBudget) from the wash-sales context. #} {% if realized_kpis is defined %} {% set _losses = realized_kpis.realized_losses_ytd|abs %} {% set _gains = realized_kpis.realized_gains_ytd|abs %} {% set _max = (_losses if _losses > _gains else _gains) %} {% if _max > 0 %}
{{ fmt_currency(realized_kpis.realized_losses_ytd) }} / {{ fmt_currency(realized_kpis.realized_gains_ytd) }}
{% else %}
No realized P/L this period.
{% endif %} {% endif %} {# View toggle — segmented control. Preserve filters when toggling. #} {% set _year_qs = 0 if all_years else (filter_year or selected_year) %} {% set qs_no_view %}ticker={{ filter_ticker|urlencode }}{% for a in selected_accounts %}&account={{ a|urlencode }}{% endfor %}&year={{ _year_qs }}&confidence={{ filter_confidence|urlencode }}{% endset %}
Table Calendar
{# Wash-sale watch — recent loss closes you shouldn't buy back yet. Lives at the top of both views so it's always visible while reviewing wash sales. #}

Watch — open positions where you closed a loss recently and a re-buy here would still trigger a wash sale. Violations — realized wash sales below.

{% include "_portfolio_wash_watch.html" %}
{% if view == 'calendar' %} {% include "_calendar_ribbon.html" %}
{% else %} {# W1: violations panel is explicitly labeled backward-looking. #}

Violations · backward-looking detected

{% if summary and summary.violation_count > 0 %}
{{ summary.violation_count }} violations
${{ "%.2f"|format(summary.disallowed_total|float) }} disallowed
{{ summary.confirmed_count }} confirmed
{{ summary.probable_count }} probable
{{ summary.unclear_count }} unclear
{% endif %} {% include "_detail_table.html" %} {% endif %}