{% load static %} {% block title %}DemandTrail Messaging{% endblock %} {% comment %} **Leg 1 of the anti-flash contract.** The sidebar can start a page at either of two widths, and the stored one has to be known before first paint — so this runs synchronously, ahead of the stylesheet's effect and long before Alpine. Legs 2 and 3 are the {% block extra_head %}{% endblock %} {% csrf_token %} {% include "partials/_toast_host.html" %} {% if show_app_shell %} {% comment %} Two pieces of shell state. `sidebarCollapsed` is desktop-only and persisted — x-effect writes it back on every change through the head script's guarded helper, and the pre-paint script beside that helper reads it before Alpine exists. `mobileMenuOpen` is the drawer and is deliberately NOT persisted: a drawer that reopens itself on the next page is a drawer covering the page you asked for. `wsOpen` used to be here because two controls opened one panel. There is one trigger now, so it lives on the switcher — see partials/_app_sidebar.html. {% endcomment %}
{% comment %} `lg:hidden`, never a bare `hidden`: Alpine shows an element by clearing its inline display, after which an unconditional display:none utility reasserts itself and the element stays invisible forever. A responsive variant is fine, and test_no_element_combines_x_show_with_a_display_none_utility splits on tokens for exactly that reason. {% endcomment %} {% comment %} The one sidebar, on every page of the product. The block is not a seam for replacing it — a second
{% else %}
{% comment %} Issue #31 owns the auth templates. They extend this file and fill this block; .auth-card and .auth-bg are already in the design system, so a login page is `{% extends "base.html" %}` plus a card. {% endcomment %} {% block auth_content %}{% endblock %}
{% endif %} {% comment %} Vendored JS (deviation 6). Studio pulls flatpickr, Chart.js and Sortable off a public CDN, which forces that origin into script-src and style-src. Every library here is served from 'self'; see scripts/vendor-js.mjs. A Django comment rather than an HTML one on purpose: an HTML comment ships to the browser, so a page documenting the removal of a CDN origin would still contain that origin's hostname — and the test asserting no CDN reference survives in any rendered template would fail on its own explanation. Order is load-bearing: htmx synchronously first, then any inline script that DEFINES an Alpine component, then Alpine itself deferred so those definitions exist by the time it boots. {% endcomment %} {% include "partials/_modal_behaviours.html" %} {% block alpine_components %}{% endblock %} {% block extra_js %}{% endblock %}