{% load i18n crispy_forms_tags %} {% comment %} The credentials card. Posts to the login view via HTMX so the card can be swapped in-place — either replaced with itself on validation errors (status 422), or replaced with the tenant picker when the authenticated user has access to two or more tenants. The outer wrapper id ``cj-login-card`` is the swap target; the form posts with ``hx-target="#cj-login-card" hx-swap="outerHTML"``. Form rendering is delegated to ``django-crispy-forms`` via the ``|crispy`` filter. The card wrapper, the sign-in button and the surrounding ``
`` tag are owned by *this* template, not the form's ``FormHelper``: helpers must set ``helper.form_tag = False`` and must not render their own ``Card(...)`` (would duplicate the ``card card-md`` wrapper here). {% endcomment %}

{% block login_title %}{% translate "Login to your account" %}{% endblock login_title %}

{% block login_form_top %}{% endblock login_form_top %} {% csrf_token %} {# Non-field errors (e.g. "wrong username or password") are #} {# rendered by crispy as part of ``form|crispy`` below — do #} {# not duplicate them here. The error text itself is owned #} {# by django.contrib.auth and is intentionally kept generic #} {# for security reasons (no user enumeration). #} {{ form|crispy }}
{# Render form.media so HTMX swaps of this partial keep widget JS/CSS #} {# attached for any subclass that brings widgets with Media (e.g. via #} {# a custom AUTH_FORM override). The default ConjuntoAuthenticationForm #} {# emits no media, so this is a no-op out of the box. #} {{ form.media }}