{# Plan 49 — apply theme class BEFORE first paint to avoid a dark→light (or light→dark) flash. Reads `cmdop:theme` from localStorage; falls back to 'dark' (the design's native mode). #} {# Plan 48 — brand assets sourced from the marketing app (frontend/apps/web/public/static/logos/). Same icons across cmdop surfaces. #} {# Geist Sans + Geist Mono now self-hosted. @font-face lives in tailwind.input.css; the woff2 files are under /static/fonts. No external CDN dependency, no privacy leak, air-gap friendly. Preload the sans variant so it's ready by FCP. #} {# Plan 50 — Tailwind is built at image-build time into a static CSS bundle instead of fetching the ~100 KB CDN script at runtime. Config lives in tailwind.config.js, customisations in tailwind.input.css. For local dev: run `npm install && npm run build:css` once. #} {# Plan 50 — shared Alpine page helpers (toast / format / auto-refresh). Loaded before alpinejs so page components can mix it in via `Object.assign(pageHelper({...}), {...})` at the top of their factory. See static/admin/shared/page-helper.js. #} {# Plan 60 Phase 1.5 — paginationState() Alpine helper. Loaded eagerly so any page component (machines, fleets, schedules, …) can wire its listing endpoint through one fetch + state mixin instead of hand- rolling pagination. See static/admin/shared/pagination-state.js. #} {# Plan 61/2a — cmd-K quick-search palette. Loaded eagerly so the keyboard shortcut works on the first paint. See static/admin/shared/cmd-k.js. #} {# Plan 61/2b W3 — Jarvis slide-out dock + the deep-chat web component the chat pane mounts. Loaded globally so cmd+\ works on every page, and so machine_detail.html does not need its own deep-chat {% endif %} {% block head %}{% endblock %}
{% if user %} {% endif %} {# Plan 61/2a — flex column so the footer sticks to the bottom even on short pages. min-h-screen guarantees the column fills the viewport. #}