{# `data-base` is what makes a custom theme inherit: tokens.css matches `[data-base="shire"]` as well as `[data-theme="shire"]`, so a custom light theme gets the whole parchment palette underneath its own handful of colours. Without it, four light colours would sit on Moria's near-black surfaces. `data-themes` is the list of `id:base` pairs, which is what the browser needs in order to set both attributes when somebody switches -- one attribute to split rather than a JSON island to parse. #} {% block title %}{{ brand.name }}{% endblock %} {# An uploaded favicon wins; then the icon derived from an uploaded logo; then the shipped leaf. Three rungs rather than two because somebody who uploads a logo and no favicon still expects the tab to change. #} {% if brand.favicon_path %} {% elif brand.icon_paths.favicon %} {% else %} {% endif %} {# Installing as an app. The manifest is a route, not a file, because it carries the instance name; the icons are PNG because a launcher will not take an SVG. theme-color is rewritten by app.js when the theme changes -- the value here is only what the browser paints with before the stylesheet has resolved. #} {% if brand.icon_paths['apple-touch'] %} {% else %} {% endif %} {# Last, so an administrator's rules win, and before {% block head %} so a page's own stylesheet still comes after it. The query string is a hash of everything the route builds, so the URL changes exactly when the stylesheet does -- with a fixed URL the browser's cache would be what decided when a rebrand took effect. Deliberately NOT in the service worker's precache list for the same reason: that cache is versioned by the release, and branding changes between releases. #} {% block head %}{% endblock %} {# Applied before first paint so a reload never flashes the wrong theme. The server already rendered data-theme from the signed-in user's preference; this only corrects it for a visitor whose local choice differs (or who is signed out, where the server has nothing to go on). #} {% include "partials/icons.html" %} {% block body %}{% endblock %} {# commands.js before composer.js: the second reads the first's table to draw the `/` menu, and both are deferred so the order here is the run order. #} {# The version in the query string is what versions the worker's cache, so a release invalidates it without anyone remembering to bump a constant. serviceWorker is absent over plain http, which is why a LAN install without TLS silently offers no install prompt -- that is the browser's rule, not ours. #} {% block scripts %}{% endblock %}