# Bootstrap Subset Build Proposal KarlDNS currently serves the local Bootstrap 5.3.8 asset at `/bootstrap-5.3.8.min.css`. The local full file is 226.7 KiB raw and 30.1 KiB gzip. ## Current Bootstrap Surface Static templates and asset JavaScript use a small Bootstrap surface: - Layout: `container`, `row`, `col-*`, `d-flex`, `d-grid`, `gap-*`, responsive flex alignment, spacing utilities, `w-100`, `h-100`. - Components: `alert`, `badge`, `btn`, `card`, `form-control`, `form-select`, `form-check`, `input-group`, `nav`, `navbar`, `pagination`, `table`. - Helpers/utilities: `border*`, `rounded*`, `text-*`, `text-bg-*`, `text-truncate`, `visually-hidden`, `opacity-75`, `small`. - JavaScript-created classes in `karldns/web/scripts.py`: `page-item`, `disabled`, `active`, `page-link`, `empty-row`, `empty`. The app CSS in `karldns/web/styles.py` already owns the custom KarlDNS look. Bootstrap is mainly supplying reset, grid, forms, buttons, tables, navigation, pagination, and common utilities. ## Proposed Build Use `scripts/build-bootstrap-subset.py` to compile a Bootstrap Sass subset from transient npm packages: ```sh python3 scripts/build-bootstrap-subset.py python3 scripts/build-bootstrap-subset.py --write ``` The script imports Bootstrap 5.3.8 Sass modules for the components above and filters `$utilities` before `utilities/api` so unused utility families are not emitted. It does not require a committed `package.json`, lockfile, or `node_modules`. Dry-run result on this worktree: - Subset: 113.8 KiB raw, 16.8 KiB gzip. - Full local asset: 226.7 KiB raw, 30.1 KiB gzip. - Reduction: 49.8% raw, 44.2% gzip. ## Rollout Recommendation Keep the current app references unchanged until the subset is visually tested. The safe implementation sequence is: 1. Run `python3 scripts/build-bootstrap-subset.py --write` to create `karldns/assets/bootstrap-karldns.min.css`. 2. Add an isolated asset route for `/bootstrap-karldns.min.css`. 3. Switch `_page()` from `/bootstrap-5.3.8.min.css?v=2` to `/bootstrap-karldns.min.css?v=1`. 4. Run UI tests and browser-check public, dashboard, locked dashboard, admin tables, pagination, dark mode, and copy fields. Do not use a selector-purge pass against rendered HTML yet. The Python templates include dynamic branches and JavaScript-created pagination classes, so Sass module selection plus a curated utility allowlist is simpler and less likely to break rare pages.