Replace all 676 inline sexp() string calls across 7 services with
render(component_name, **kwargs) calls backed by 46 external .sexpr
component definition files (587 defcomps total).
- Add render() function to shared/sexp/jinja_bridge.py
- Add load_service_components() helper and update load_sexp_dir() for *.sexpr
- Update parser keyword regex to support HTMX hx-on::event syntax
- Convert remaining inline HTML in route files to render() calls
- Add shared/sexp/templates/misc.sexp for cross-service utility components
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The sexp parser doesn't handle "(" and ")" as string literals
inside expressions. Use raw! with pre-formatted strings instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Eliminates all f-string HTML from the remaining three services,
completing the migration of all sexp_components.py files to the
s-expression rendering system.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>