# C1 — shared clinical entities: episodes · procedures · follow-up tasks · team referrals · record-scope fields · summary generator · patient record + timeline

Read `_COMMON.md` first. C1 is **three serial WPs**: C1a (BE entities + record scope + registry) → C1b (BE ClinicalSummaryService + PatientRecordService + timeline) → C1c (FE cards). Read the shared parts plus your own section.

**Depends on:** E1e ✅, D2a+D2b ✅ (alerts/conditions/meds/notes, `ShowIfContextBuilder` with `extend()`, `PatientHeaderExtensions`), P3 migration `2026_11_03_160000_create_clinical_templates_table` merged (C1a references `clinical_templates`). C1c needs S1 ✅ and D2c ✅.

## Spec (read before coding)
- `../design-gyn-integration.md` §1 decisions 5 & 6, §2 rows **gyn_episodes → clinical_episodes**, **operations + operation_procedures → clinical_procedures**, **team_referrals**, **follow_up_tasks**, **Summary generator**, **GET /gyn/definitions · /record · PUT values**, **Timeline**, and §4 paragraph «scope `record`».
- `../design.md` §4.7 (rows متابعة/إحالة, Patient record API), §5 (extension contract: `PatientRecordService::extend`), §6 table row `clinic.procedures.mode` (external | center | hospital).
- `../design-data-layers.md` §6 (specialty contract: `ClinicalTypeRegistry` declares packs/intake/workspace/alert_conditions; C1 adds `followup_rules` + `summary_types`).
- `../master-plan.md` C1 row (acceptance: open an episode · record an operation done in an outside hospital · a follow-up task generates itself · team referral with a status · a summary prints).
- `../design-visit-shell.md` §2.1 (timeline + follow-up are shared cards), §3 bullet «مولّد الملخص» + «الخط الزمني».
- GYN source for shapes only: `/home/moonui3/public_html/knowledge-base/plans/gyn-obstetrics-module-src/p3a-schema-core.js` module `team` (referral fields + statuses), `p3d-schema-op.js` modules `operation`/`discharge`/`followup` (procedure header fields, follow-up offsets), `p4b-engine-ui.js` ~line 80–95 (timeline event list) and the prototype `../visit-shell-prototype.html` `GYN_SUM` + `gSummaryText()` (~line 1001, 1075).

## Current code you build on (read)
- `Modules/Clinic/app/Models/{Encounter,ClinicReferral,ClinicalDocument,PatientHistoryAnswer}.php`, `Support/ClinicalDocumentWriter.php`, `Services/PrescriptionPdfService.php` (the DomPDF/RTL pattern to mirror), `Listeners/SnapshotEncounterHistory.php`, `Providers/EventServiceProvider.php`.
- `Modules/Hospital/database/migrations/2026_10_12_100003_create_hospital_surgery_tables.php` (`hospital_operations`: code/name_ar/name_en/specialty…; `hospital_surgeries`: patient_id, admission_id, operation_id, surgeon_id, status, scheduled_at, done_at, diagnosis_pre/post, report json).
- `Modules/Nutrition/app/Services/Visit/VisitRecordService.php` — the `safe()` section pattern `PatientRecordService` must mirror.
- **Name trap:** `Modules/Clinic/app/Services/FollowupResolver.php` is revisit *pricing* (M4 WP3) — unrelated to follow-up tasks; do not touch or reuse it.
- There is **no PHP `ClinicalTypeRegistry` yet** (D0 listed it; only `Enums/ClinicalType` methods exist). C1a creates it.

## Decisions already made (do not re-litigate)
1. **Episodes are generic** (`clinical_episodes`): pregnancy, treatment cycle, ortho case, nutrition programme, admission, GYN case are all `kind`s. An encounter belongs to at most one episode (`encounters.episode_id` nullable). Episode `categories` (json list of category codes) feed `show_if {cat:…}` via `ShowIfContextBuilder::extend('categories', …)`.
2. **Procedures are core** (`clinical_procedures`), never a GYN table; the procedure catalog is `hospital_operations` (one catalog, `specialty` filter); procedure template fields are answers with **scope `record`** (`record_type='clinical_procedure'`, `record_id`). No `operation_procedures` table — `procedure_codes` json holds the picked catalog rows.
3. **`clinic.procedures.mode`**: `external` (default — record what was done elsewhere; no Hospital link) | `center` (procedure done in-house, optional link) | `hospital` (must link a `hospital_surgeries` row for in-house procedures). Read with a default; report the setting definition row.
4. **Scope `record`** on answers (design-gyn §4): `record_type varchar(24) NOT NULL default ''` + `record_id` nullable; `scope_key = record_id ?? encounter_id ?? 0` (in the existing `saving()` hook); unique becomes `(patient_id, history_question_id, record_type, scope_key, repeat_index)` — replace the unique **as it exists after E1e** (read E1e's migration `2026_11_03_1300xx` for its real name). Allowed record types live in a constant allow-list (`clinical_procedure`, `clinical_episode`; G3/G5 append `treatment_cycle`, `pregnancy`).
5. **Follow-up tasks** (`follow_up_tasks`) are generated by rules declared per clinical type in `ClinicalTypeRegistry::followupRules()`; C1 ships the mechanism + a `general` default + the `procedure.signed` trigger with the GYN default offsets (1 w / 1 m / 3 m / 6 m, design-gyn §7 G4 — tunable later). It does **not** migrate `dental_recalls` or `hospital_admissions.follow_up_on` yet (design.md §4.7 says later) — leave both untouched.
6. **Team referral = `clinic_referrals` extended** (`kind external|team|mdt`, `episode_id`, `team` (catalog code), `member_user_id`, `status requested|seen|opinion|joint|back`, `plan`) — no new table. A team member's caseload = referrals where `member_user_id = me` ∪ episodes whose `team` json contains me.
7. **One summary engine** `ClinicalSummaryService` in Clinic: summary *types* come from the registry; per-`module_key` *templates* are PHP classes registered in a `SummaryTemplateRegistry` (G1/G2… register theirs). A generic fallback renders any module's answers as «Label: value» lines (the prototype `gSummaryText` behaviour). Private fields/modules and private notes are excluded unless `include_private=true` AND the user has `clinic.fields.private`; the `couple` type ignores `include_private` entirely. Saving = a `clinical_documents` row `doc_type='summary'` with the rendered snapshot (immutable), PDF via the PrescriptionPdfService pattern.
8. **One record API** `GET clinic/patients/{p}/record?encounter_id=&sections=` (`PatientRecordService` with `extend(string $section, callable)` + `safe()`), promoted from P4. The timeline is one of its sections and also its own endpoint for paging.

## Shared-file rules (all C1 WPs)
- `Modules/Clinic/routes/api.php`, `Modules/Hospital/routes/api.php`, `Modules/Core/database/seeders/RolePermissionSeeder.php`, `ClinicSettingDefinitionSeeder.php`: **orchestrator-owned — REPORT** route lines (verbatim, with middleware/permission and names), permission names, setting definitions. Ship permissions through your own `Grant…PermissionsSeeder` + bridge migration (pattern: `2026_10_09_130003_clinic_device_permission_bridge.php` + `Database/Seeders/GrantClinicDevicePermissionsSeeder.php`) and report the installer-list line.
- **Hot files you own during C1 (no other agent touches them while C1 runs):** `Models/Encounter.php` (C1a only: `episode_id` fillable + `episode()` relation — nothing else), `Providers/EventServiceProvider.php` (C1a: add listeners only), `Services/HistoryService.php` (C1a: record scope only), `Models/PatientHistoryAnswer.php` (C1a: saving hook + fillable). Keep edits minimal and additive.
- FE i18n: targeted edits in `ar.json`/`en.json` under `CLINICAL_ENTITIES.*`, `TIMELINE.*`, `SUMMARY.*`; **do NOT bump `I18N_VERSION`**.
- Pick-don't-type everywhere (S1 `clinical-picker`); multi-values are rows or JSON arrays of codes, never CSV.

---

## C1a — BE entities, record scope, registry (migrations `2026_11_03_182000`–`182099`)

### Do
1. **`182000_create_clinical_episodes_table`**: `clinical_episodes` (id, company_id, patient_id, clinical_type string(24), kind string(24) (pregnancy | treatment_cycle | ortho_case | nutrition_program | admission | gyn_case | general), title string(191) nullable, categories json nullable, status string(12) default 'open' (open | closed | cancelled), opened_at datetime, closed_at nullable, close_reason string(191) nullable, primary_doctor_id nullable, team json nullable (`[{user_id, role}]`), ref_type string(32) nullable, ref_id nullable, created_by, timestamps, softDeletes; idx (company_id, patient_id, status), (ref_type, ref_id)). **`182001_add_episode_id_to_encounters`**: `encounters.episode_id` nullable + index (guarded).
2. **`182002_create_clinical_procedures_table`**: `clinical_procedures` (id, company_id, patient_id, episode_id nullable, encounter_id nullable, clinical_type string(24) nullable, status string(12) default 'planned' (planned | scheduled | done | cancelled), place string(12) (external | clinic | center | hospital), place_name string(191) nullable, scheduled_at datetime nullable, performed_at datetime nullable, procedure_codes json (`[{operation_id, code, name_ar, name_en}]`), approach string(32) nullable, anesthesia string(16) nullable, side string(12) nullable, surgeon_id nullable, surgeon_name string(191) nullable, assistants json nullable, hospital_surgery_id nullable, template_id nullable (→ clinical_templates), indication text nullable, findings text nullable, complications json nullable, specimens json nullable, notes text nullable, signed_at/signed_by nullable, created_by, timestamps, softDeletes; idx (company_id, patient_id), (episode_id), (hospital_surgery_id)).
3. **Hospital migration** `Modules/Hospital/database/migrations/2026_11_03_182010_add_clinical_template_to_hospital_operations.php`: `hospital_operations.clinical_template_id` nullable (no FK). This is the only Hospital file you touch.
4. **`182003_create_follow_up_tasks_table`**: `follow_up_tasks` (id, company_id, patient_id, source_type string(32), source_id, clinical_type string(24) nullable, rule_key string(48) nullable, title_ar string(191), title_en string(191) nullable, due_on date, window_days smallint nullable, template json nullable (what to check: card ids / field codes / note), status string(12) default 'open' (open | done | cancelled | missed), done_encounter_id nullable, done_at nullable, assigned_to nullable, created_by nullable, timestamps, softDeletes; idx (company_id, patient_id, status, due_on), (source_type, source_id)). Unique (source_type, source_id, rule_key, due_on) to keep generation idempotent.
5. **`182004_extend_clinic_referrals`**: + `kind` string(12) default 'external', `episode_id` nullable, `team` string(64) nullable (lookup code, `lookup_key='team'`), `member_user_id` nullable, `status` string(12) default 'requested', `plan` text nullable, `status_changed_at` nullable, `responded_at` nullable; `referred_to_name` → nullable (`->change()`; team referrals have no outside name). Guarded. Seed (same file, idempotent, per company with clinic data) `clinical_lookups` `lookup_key='team'` with codes/labels from the GYN `team` module list (gyn, endometriosis_team, fertility_ivf, mfm, urology, urogynecology, oncology, radiology, pathology, colorectal_gi, general_surgery, anesthesia, andrology, sexual_medicine, pelvic_floor_physio, psychology, endocrinology, hematology, other) — Arabic labels yours, English from the list; `specialty` NULL (teams are shared).
6. **`182005_add_record_scope_to_patient_history_answers`**: decision 4 (guarded, MySQL-safe index swap: add new unique first, then drop old). Backfill `record_type=''`.
7. **Models + enums**: `ClinicalEpisode`, `ClinicalProcedure`, `FollowUpTask` (BaseModel/TenantAware, casts, relations, `LogsActivity` like D2a), enums `EpisodeKind`, `EpisodeStatus`, `ProcedureStatus`, `ProcedurePlace`, `FollowUpStatus`, `ReferralKind`, `ReferralStatus`; `ClinicReferral` fillable/casts + `episode()`, `member()`; `Encounter::episode()`; `PatientHistoryAnswer` fillable + hook (decision 4).
8. **`Modules/Clinic/app/Clinical/ClinicalTypeRegistry.php`** (new): static per-type declaration, code-defined, read by BE services: `followupRules(string $type): array` (rule_key → `{trigger: 'procedure.signed'|'encounter.signed'|'episode.closed', offsets: ['7d','1m','3m','6m'], title_ar, title_en, template}`), `summaryTypes(string $type): array` (key → `{label_ar, label_en, modules: list|null}`), `register(string $type, array $declaration)` (G-phases call it from their service providers), `forType()`. Seed `general` (summary type `clinic` only; follow-up rule `encounter.signed` → none by default) and `gyn_ob` placeholders (summary types `clinic, fertility, operative, antenatal, delivery, discharge, followup, uds, urogyn, couple` with module lists copied from the prototype `GYN_SUM`; follow-up `procedure.signed` → 7d/1m/3m/6m). No FE coupling.
9. **Services** (`Modules/Clinic/app/Services/Clinical/`):
   - `EpisodeService`: `open(patientId, clinicalType, kind, data, userId)`, `close(episodeId, reason, userId)`, `attachEncounter(encounterId, ?episodeId)` (same patient + company, encounter editable), `openFor(patientId, ?clinicalType)`, `setCategories(episodeId, codes[])`, team add/remove. On `EncounterStarted` (new listener `AttachEncounterToOpenEpisode`, registered in EventServiceProvider): if the patient has exactly ONE open episode whose `clinical_type` = the encounter's department clinical type → set `episode_id`; never guess when 0 or >1.
   - `ProcedureService`: `record(patientId, data, userId)` (mode rules, decision 3: in `external` mode `place` must be external and `hospital_surgery_id` is rejected 422; in `hospital` mode an in-house place requires `hospital_surgery_id` of the same patient), `update` (422 after `signed_at`), `sign(procedureId, userId)` (sets signed_*; fires new event `ClinicalProcedureSigned`), `linkSurgery(procedureId, surgeryId)` (same patient/company; copies performed_at=done_at, procedure_codes from operation, surgeon), `cancel`. `procedure_codes` items validated against active `hospital_operations` of the company (or free-text `{name_ar}` when the catalog has no match — allowed only in external mode).
   - `FollowUpService`: `generate(string $trigger, Model $source, string $clinicalType, Carbon $anchor)` → creates tasks from the registry rules (idempotent via the unique key); listeners `GenerateFollowUpsOnProcedureSigned`, `GenerateFollowUpsOnEncounterSigned` (registry-driven, no-op when the type has no rule); `complete(taskId, encounterId)`, `cancel`, `listFor(patientId, status)`, `dueList(companyId, from, to, ?doctorId)`; nightly-safe `markMissed()` (status open + due_on + window_days < today → missed) exposed as an artisan command `clinic:followups:mark-missed` (register in the Clinic service provider's commands list if there is one — else report).
   - `ReferralService` additions (or extend the existing referral controller's logic — read `ClinicReferralController` first; keep its validation for kind=external unchanged): create team/mdt referrals, `setStatus(referralId, status, plan?, userId)` (only the member, the author, or `clinic.referrals.manage`), `caseload(userId)`.
   - `Support/ShowIfContextBuilder::extend('categories', …)` registration (from the Clinic service provider): categories ∪= open episodes' `categories` for the encounter's episode (or the patient's open episodes of the same clinical type).
   - **Record-scope fields:** `HistoryService::saveRecordAnswers(string $recordType, int $recordId, array $items, User)` (record must exist, same company/patient, type in the allow-list, procedure not signed) + `recordAnswers(recordType, recordId, ?moduleKey)`; reuse the existing per-item validation/encoding; private-field rule from E1e applies.
10. **Controllers/Requests/Resources** (new): `ClinicalEpisodeController` (index by patient, store, show, close, attach encounter, categories, team), `ClinicalProcedureController` (index by patient/episode, store, show, update, sign, link-surgery, cancel), `FollowUpTaskController` (index by patient, due list, complete, cancel, store manual), `RecordFieldController` (`GET/PUT records/{record_type}/{record_id}/fields?module_key=`), referral status + caseload endpoints (new methods on a new `TeamReferralController` — do not rewrite `ClinicReferralController`). Every endpoint: company check, signed-encounter rules via `assertEditable()` where an encounter is written.
11. **Permissions (REPORT + Grant seeder `GrantClinicEntitiesPermissionsSeeder` + bridge `182020_clinic_entities_permission_bridge`)**: `clinic.episodes.view`, `clinic.episodes.manage`, `clinic.procedures.view`, `clinic.procedures.edit`, `clinic.procedures.sign`, `clinic.followups.view`, `clinic.followups.manage`, `clinic.referrals.manage` (status for others), `clinic.summary.generate` (used by C1b). Grants: owner/admin all; roles holding `clinic.encounters.update` (doctors) all except `referrals.manage`; nurses (`clinic.vitals.record`) followups.view.
12. **Proposed routes (REPORT):** `GET/POST patients/{patient}/episodes`, `GET episodes/{episode}`, `POST episodes/{episode}/close`, `PUT episodes/{episode}/categories`, `PUT episodes/{episode}/team`, `PUT encounters/{encounter}/episode`; `GET/POST patients/{patient}/procedures`, `GET/PUT procedures/{procedure}`, `POST procedures/{procedure}/sign|link-surgery|cancel`; `GET patients/{patient}/follow-ups`, `GET follow-ups/due`, `POST patients/{patient}/follow-ups`, `POST follow-ups/{task}/complete|cancel`; `GET/PUT records/{recordType}/{recordId}/fields`; `PATCH referrals/{referral}/status`, `POST encounters/{encounter}/team-referrals`, `GET referrals/caseload`. Also report the settings rows: `clinic.procedures.mode` (select external|center|hospital, default external), and nothing else.
13. Lang keys for enums + 422s (`Modules/Clinic/lang/{ar,en}`). CHANGELOG lines EN/AR in the report.

### Tests — `Modules/Clinic/tests/Feature/C1aEntitiesTest.php` (prefix `c1a_`)
open/close episode; encounter auto-attaches to the single open episode of its type and not when two are open; episode categories satisfy `{cat:'aub'}` through `ShowIfContextBuilder`; external-mode procedure with `hospital_surgery_id` → 422; hospital-mode in-house procedure without link → 422, with a same-patient surgery ok, other patient's → 422; signed procedure update → 422; `procedure.signed` for gyn_ob generates 4 tasks at 7d/1m/3m/6m and re-firing creates none; `markMissed` flips an overdue task; team referral status by member ok, by stranger 403; caseload lists it; record-scope answers for two procedures of the same patient persist side by side with the same question, and a non-allow-listed record type → 422. Run also `E1eAnswersTest`, `HistoryEngineTest`, `PlatformE1HistoryEngineTest`, `D2aFactsTest`, any `*Referral*Test.php` and `*Encounter*Test.php` in Modules/Clinic/tests, and `Modules/Hospital/tests` files that cover operations/surgeries — keep green.

### Out of scope (C1a)
Summary/record/timeline (C1b), FE (C1c), GYN operation templates & Clavien (G4), dental recalls / admission follow-up migration, pregnancies/cycles tables (G5/G3).

---

## C1b — BE summary generator + patient record + timeline (migrations `2026_11_03_183000`–`183099`, only if needed)

### Do
1. **`Modules/Clinic/app/Services/Clinical/Summary/`**: `SummaryTemplate` interface (`moduleKey(): string`, `render(SummaryInput $in): ?string` — English medical text per design-gyn decision G6, plain text, one paragraph), `SummaryTemplateRegistry` (register/get/has), `SummaryInput` (readonly: module values map local-key → value incl. repeat rows as list of maps, labels map, patient facts, encounter, include_private), `GenericModuleTemplate` (fallback: «<b>Label</b>: value» parts for non-empty values, max 6, labels from definitions, lookup codes resolved to `value_en` ?? `value_ar`).
2. **`ClinicalSummaryService`**: `build(Encounter $e, string $type, User $u, bool $includePrivate=false): array{type, title, sections: list<{module_key, title, text}>, shared_cards: list<string>, generated_at}`:
   - module list = `ClinicalTypeRegistry::summaryTypes($type)[type].modules` ?? (core modules + every module whose fields have answers in this encounter / record and whose module `show_if` passes — use `ShowIfContextBuilder` and, for module-level rules, the optional `ModuleRegistry` contract `Modules\Clinic\Clinical\Contracts\ModuleCatalog` (interface: `modulesFor(string $clinicalType): list<array{key, group, show_if, priv, title_ar, title_en}>`) that a specialty binds in its service provider; when unbound, modules are derived from distinct `module_key`s with no module rule).
   - values per module: encounter-scope answers of this encounter + patient-scope answers (L1/L2), decoded like `ShowIfContextBuilder` does, repeat rows grouped by `repeat_group`/`repeat_index`.
   - shared facts lines always available to templates: alerts, conditions, meds, diagnoses (`encounter_diagnoses`), complaints, latest observations (D1 `ObservationService::latestFor`).
   - exclusions: questions `is_private` and modules `priv` unless allowed (decision 7); `ClinicalNote` private never.
   - `save(...)`: writes `clinical_documents` (`doc_type='summary'`, body = rendered sections json + plain text, `encounter_id`, `patient_id`, `document_number` via the existing number writer if present — read `ClinicalDocumentWriter`) → immutable; `pdf(document)` via a new `SummaryPdfService` mirroring `PrescriptionPdfService` (bilingual RTL header from `clinic.print.*`, English body).
   - A TS mirror is NOT needed for C1 (the FE previews by calling the BE); G1/G2 decide live summary.
3. **`PatientRecordService`** (`Services/Clinical/PatientRecordService.php`): `build(Patient, ?Encounter, array $sections, User)` with built-in sections `header` (D2b summary), `alerts`, `conditions`, `meds`, `encounters` (last N with dept/doctor/status/diagnoses), `episodes`, `procedures`, `documents`, `referrals`, `follow_ups`, `observations` (latest per code), `answers` (`?module_key=`), `timeline`; `static extend(string $section, callable(Patient, ?Encounter, User): mixed)`; every section through a `safe()` like Nutrition's. Private filtering applies.
4. **`TimelineService`**: `for(Patient, ?from, ?to, ?types, User, page)` → items `{at, type: encounter|episode_open|episode_close|procedure|document|referral|follow_up|prescription, title_ar, title_en, subtitle, tone, ref: {type, id}, clinical_type}` sorted desc; sources: encounters (not cancelled), episodes, procedures (performed_at ?? scheduled_at), clinical_documents (summary/report/certificate), referrals, follow_up_tasks (due/done), prescriptions kind discharge/home (optional). Specialty sources via `TimelineService::extend(type, fn)` (G3/G5 add cycles/pregnancies).
5. **Controllers** (new): `ClinicalSummaryController` (`GET encounters/{encounter}/summary?type=&include_private=`, `POST encounters/{encounter}/summary` → saved document, `GET summaries/{document}/pdf`), `PatientRecordController` (`GET patients/{patient}/record?encounter_id=&sections=`), `PatientTimelineController` (`GET patients/{patient}/timeline?from=&to=&types=&page=`). Permissions: summary → `clinic.summary.generate`; record/timeline → `clinic.patients.view` + `clinic.history.view`. REPORT the route lines.
6. Register the generic template + the `general` type's `clinic` summary (core lines: complaint, vitals, history, exam, diagnosis, plan/rx, follow-up).

### Tests — `Modules/Clinic/tests/Feature/C1bSummaryRecordTest.php` (prefix `c1b_`)
generic summary renders labelled values and resolves lookup codes; a private field is absent by default, present with include_private + permission, absent in `couple` type even with include_private; a registered template overrides the generic one for its module; saved summary is a `clinical_documents` row doc_type summary and is immutable (second save = new row); PDF endpoint 200 + `application/pdf`; record endpoint returns requested sections and a throwing extension section yields its empty value (logged) without failing the request; timeline merges an encounter, a procedure, a referral and a follow-up in date order. Run `C1aEntitiesTest`, `D2bHeaderSnapshotTest` too.

### Out of scope (C1b)
GYN templates (G1/G2), P5 document templates (sick leave/report), TS summary mirror, FE.

---

## C1c — FE cards (no migrations)

**Fable design consult is MANDATORY** for the timeline card and the summary card (they are visual, used by every specialty): give Fable the prototype (`../visit-shell-prototype.html` — cards `gyn_timeline`, `gyn_summary`; screenshot helper in `S1-visit-shell-fe.md` §Spec 4) and ask for the generic (non-GYN) version: event tones per type, density on mobile, summary-type segmented control, preview → «حفظ وطباعة» flow, the private-exclusion note. 1–2 rounds; record decisions in your report.

### Do (FE repo; folder `src/app/features/clinic/clinical/` (new) + the S1 card registry)
1. `clinical-entities.service.ts` (episodes, procedures, follow-ups, team referrals, record fields), `clinical-summary.service.ts`, `patient-timeline.service.ts`, typed models.
2. Cards (standalone, inputs `[patientId] [encounterId] [locked] [clinicalType]`, output `changed`):
   - `timeline-card.component.ts` (shared card `timeline`): filter chips by type, infinite page, click → opens the source (encounter route / procedure dialog / document PDF).
   - `episode-bar.component.ts`: the encounter's episode chip («حلقة: عقم ثانوي · مفتوحة منذ …»), attach/detach/open new, close with reason; categories shown as chips (read-only here — GYN edits them in G1). Rendered by the shell in its start rail (add ONE slot in the shell start rail template: `visit-shell/visit-start-rail.component.ts`) — that is your only S1 chrome edit.
   - `procedure-dialog.component.ts`: record/edit a procedure (catalog picker on hospital operations filtered by specialty; free-text name allowed in external mode; place segmented by `clinic.procedures.mode` from the layout payload/settings; date; surgeon pick or name; findings; sign button with confirm; link-surgery picker in hospital mode).
   - `procedures-card.component.ts` (shared card `procedures`): list + «＋ عملية» → dialog.
   - Upgrade S1's `visit-shell/cards/visit-followup-card.component.ts` (it already anticipates C1): list open/done tasks for the patient, generated ones tagged «تلقائي», complete-on-this-visit, manual add (date + title), keep its existing «احجز متابعة» action.
   - `team-referral-card.component.ts` (shared card `team`): team picker (`lookup_key=team`), member pick, reason, status stepper requested → seen → opinion → joint → back, plan; external referrals keep using the existing `encounter/referral` dialog unchanged.
   - `summary-card.component.ts` (shared card `summary_gen`): type segmented control from `GET …/summary` types (registry per clinical type, exposed in the summary response as `available_types`), preview, include-private toggle only when permitted, «حفظ وطباعة» (POST then open the PDF), «نسخ».
3. Register the new card ids in `visit-shell/card-catalog.ts` (`timeline`, `procedures`, `team`, `summary_gen`; kind shared) and their bodies in the shell's card `@switch`; add `timeline` + `summary_gen` to the general default layout at the end of the flow ONLY if the Fable consult agrees (else leave them addable from the catalog). No other S1 file edits.
4. i18n targeted keys (no version bump). `npx ng build --base-href /app/` green. No deploy.

### Out of scope (C1c)
GYN category editing, GYN module host, GYN summary types' bespoke text (G1/G2), nutrition/dental layouts.

---

## Report back (each WP)
Files created/edited; test output with pass counts; route lines + permissions + settings rows + installer-list line to paste; CHANGELOG EN/AR; files needed but not touched; Fable decisions (C1c).
