4bbf6d9728
- Restore src/scrapers/tjing.js with AbortController timeout (8s), error-object returns, and verbatim GraphQL queries - Add getOrCreateLayout() to src/models/course.js - New /api/tjing/search and /api/tjing/import/:tjingId routes; course-table route now includes layoutCount/activeLayoutCount via LEFT JOIN aggregation - Rewrite courses.ejs: action-card with Find/Import tabs, results bar, HTMX course-table-region with body:refresh trigger - Rewrite course-table.ejs: CSS-grid div structure replacing <table>, lazy-load expanded layouts via JS htmx.ajax - Rewrite course-layouts.ejs: layout-card chips with rating tier colouring, collapsible inactive layouts section - Rewrite courses.js: tab switching, live client-side filter, count display, Tjing search/import using DOM API (no innerHTML with untrusted data) - Rewrite courses.css: full new design system using project tokens