Screenshotting the pages under dark mode and compact density (rather than
trusting that design tokens were enough) turned up two mistakes repeated across
every page this feature set added:
- `.card` carries only the surface, border and radius — padding comes from the
separate `.card-pad`. Fifteen cards were rendering with their content flush
against the edges.
- `.field` *is* the input box, a 40px-tall flex row. Wrapping a label plus a
control in it produced a joined addon rather than a label above its field.
`.field-block` is the label-above layout, and thirty-seven wrappers now use it.
Both were invisible to type-checking and to the tests, which is exactly why the
visual pass was worth running. Numbers in the new UI now go through
formatNumber so they render as Persian digits, and the utilization page's
header no longer repeats the sentence that appears under its filters verbatim.
The QA driver gained a `--ui` flag: theme and density live in
localStorage['clinicpro-ui'], so without seeding them dark mode and compact
density cannot be screenshotted at all.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Laser is six to eight sessions; the previous design only knew single
appointments, which is the exception rather than the rule.
- CourseProtocol per service: session count and three distinct spacings —
min is the earliest that is clinically allowed, ideal is best, max is where
the course starts losing its effect
- Starting a course creates every session up front as `planned` and copies the
protocol's numbers and per-session params, so changing the protocol tomorrow
leaves a running course alone
- Suggestions anchor on the last *completed* session, not the course start:
when session 2 slips, session 3 moves with it
- Slots are ranked by distance from ideal, not by earliest available — day 21
is worse than day 27 when 28 is the target
- book-all is all-or-nothing inside one transaction, with a moving anchor and a
90-day horizon; sessions past the horizon stay planned and are reported, not
treated as failures
- The effective minimum is the stricter of the protocol and the task-09 spacing
policy, so a clinic rule never fights the protocol
- Cancelling one session returns only that session to planned; abandoning a
course does not cancel its appointments, which stays an explicit decision
One active course per (patient, service) via active_course_key, the same
partial-uniqueness trick as Appointment::activeSlotKey.
Admin: CourseProtocolsPage, TreatmentCoursePage and a courses tab on the
patient record.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>