{# Pre-paint theme resolver (#94). MUST stay before every stylesheet AND the blocking htmx script below: a slow script fetch must not delay theme resolution, or the first painted frame flashes the wrong theme. Guarded: unreadable storage or an unknown value falls back to System (no attribute). All other theme wiring lives at the end of . #} {% block title %}Voxint review{% endblock %} {# Island stylesheet (issue #48). Placed BEFORE the inline
{# Ops Console app shell (#205, V2 #207). The icon rail and command bar are overridable blocks: the setup wizard overrides both empty so the flex shell collapses to a plain column. Focus order: skip-link, rail nav, command bar, main. #} {% block sidebar %} {% endblock %}
{% block topbar %}
{% block command_bar %} {% block cb_breadcrumb %}{{ active_nav or 'home' }}{% endblock %} {% block cb_summary %}{% endblock %}
{# #162: the decorative search affordance is removed until search exists — a visible "Search everything ⌘K" that does nothing is a broken promise. The block stays as the seam the real command palette will fill; the .cb-search CSS is kept for it too. #} {% block cb_search %}{% endblock %} {% block cb_actions %} {% endblock %} {% endblock %}
{% endblock %}
{% block nav %}{% endblock %}
{# Guided-tutorial banner: present only when the API layer resolved a real tutorial-run/step for this page. Injected here (outside every page's body block, and outside the workbench htmx swap target) so fragment swaps never remove it. #} {% if tutorial %}{% include "fragments/tutorial_banner.html" %}{% endif %} {% block body %}{% endblock %}
{# Activity indicator + toasts (Console 2.0 P7, #162). The whole feature lives in this one flag-gated block, so a dark-shipped install (the default) ships zero extra bytes. shell.activity_enabled already implies Jobs discovery is on, so the badge target (/jobs) and toast links are honest. The poller is a plain progressive-enhancement IIFE (the theme/sidebar convention), NOT an island: a JSON poll + a toast queue needs no React. #} {% if shell.activity_enabled %}
{% endif %} {# Theme wiring (#94). The resolver owns first paint; this owns the rest. Split on purpose (multi-model plan review): applyDom never persists and the storage handler never writes back, so cross-tab events cannot echo; persistence failures degrade to a working same-page toggle. The Settings radios are wired by document-level delegation (inert on pages without them, survives htmx swaps — no script lives in the partial); pageshow re-reads for bfcache restores. OS flips in System mode need no JS: the guarded @media block re-themes chrome, and WaveformStrip has its own matchMedia listener. #} {# Icon-rail toggle (#207). The icon rail is always visible on desktop. On narrow viewports (<=50rem) it hides behind a hamburger button in the command bar. The hamburger is CSS-hidden on wide screens and shown on narrow. Crossing the breakpoint closes any open mobile disclosure. Inert on shellless pages (no #sidebar-toggle in the DOM). #} {# Shared island loader (issue #48): the ONLY script every page pulls in. It no-ops when a page has no [data-island] nodes and dynamically imports only the island bundles present, so adding an island never touches base.html. The guard keeps dev/source-run (no build) working — no broken script tag. #} {% if asset_url('main') %}{% endif %}