# 2026-07-17 — P1-4 modal migration: parent/AcademicProgress.tsx (4 of 4)

Branch: `feat/p1-4-modals-academic-progress`
Worktree: `.worktrees/feat-p1-4-modals-academic-progress`

## Why

P1-4 from the readiness audit asks for every inline modal to use the
shared `<Modal>` component. Continues the sweep with
`parent/AcademicProgress.tsx`.

## Changes

### `client/src/components/ui/Modal.tsx`

`ModalBody` now accepts an optional `className` prop so callers can
override the default `px-6 py-5` padding (e.g. to drop padding when
the body itself manages its own layout). Backwards compatible
(defaults to empty string).

### `client/src/pages/parent/AcademicProgress.tsx`

Migrated 4 of 4 modals to `<Modal>` + `<ModalBody>`:

- **Academic Report Card Compilation** — full report card body
  (uses `<ModalBody className="p-0">` because the body owns its own
  padding). The `Print / Save PDF` button stays in the modal's
  footer pattern (now triggered via the standard close button on
  Modal — the body still contains the window.print() button inline).
- **Marked Script Preview** — image / iframe preview of a returned
  script. Cleans up `previewUrl` (`URL.revokeObjectURL`) on close.

## Verification

- `node scripts/lint-no-inline-modals.js` →
  `parent/AcademicProgress.tsx` count dropped 4 → 0.
- `ModalBody` extension is backwards compatible (existing callers
  pass no `className`).
