immigration.fyiGenogram Generator

Casework

Asylum Interview ReviewerAuditorBundle BuilderCW Form CompletionCase Law FinderCase SummaryChronology DrafterCompilerCountry ScheduleDate ConversionsDocument CompareDocument NotepadEvidence ExhibitorEvidence: MatrixFilerGenogram GeneratorGov.UK Archive CheckImage AnnotatorPassage PickerResearch

Genogram Generator

What this is

Genogram Generator draws a client's family / safeguarding diagram following the social-work genogram convention and exports it for tribunal bundles, Local Authority referrals, statements, or letters. Matter-agnostic, asylum family composition, settlement sponsor chain, child-safeguarding all use the same tool.

Typical workflow

  1. On the Build tab, add People one by one. Mark exactly one Person as Client.
  2. Set each person's Sex (square = M, circle = F, D-shape = NB, ? = unknown), Status (alive, deceased, unborn, abortion, miscarriage, stillborn), and any Key codes (LD, PD, MH…). Trans / gay / lesbian render the nested or inverted-triangle insets automatically.
  3. Add Relationships. Couple covers married / cohabiting / divorced / separated / widowed (pick the kind). Parent Child covers biological / adopted / foster (pick the kind). Overlay draws the abuse / closeness lines on top of the structural diagram, pick the kind (violence / physical / emotional / sexual / hostile / neglect / very-close / close / distant) and the direction (perpetrator victim).
  4. Open Diagram: the genogram renders top-down with the client centred, oldest generation at the top, oldest sibling on the left, male on the left within each couple. Mouse-wheel zooms, click-drag pans, double-click resets.
  5. Open Export for PNG, A4 PDF (with PRIVATE & CONFIDENTIAL header + optional DRAFT watermark), JSON sidecar (drops into ~/Work/00 Open Cases/Case Summaries/ as <ref>.genogram.json), or a plain-prose paragraph for a witness statement.

Conventions reference

The full social-work convention: every shape, line variant, overlay kind, and key code, is embedded below. It is the distilled version of the published Genogram Explanation PDF (07 October 2022) used by Local Authority safeguarding teams. Edit at gmiau-specs/GENOGRAM-GUIDE.md; immigrationfyi-tools update refreshes the embedding.

Show convention reference (GENOGRAM-GUIDE.md)
# Genogram Convention: Reference

Distilled from "Genogram Explanation" (07/10/2022). Source PDF at
`gmiau-specs/source-docs/genogram-guide-07102022.pdf`. This is the
social-work / safeguarding convention; it is what colleagues and the
Local Authority will expect when a genogram is filed with a case.

A **genogram** (a structured family tree) shows current family
relationships across **at least three generations**: it is intended to
make clear who is in the family, who lives with the child, and what the
significant medical, health and emotional dynamics are.

Only **family members** belong on a genogram. Friends, professionals,
and supporters belong on an *ecomap*, not here.

Each person should carry at minimum: **name** and **date of birth (not
age)**. Other dates, marriage, divorce / separation, death: are added
where known. Significant life events may be noted next to the person.

---

## 1. Layout rules

- Orientation: **landscape**.
- Within each couple: **male on the LEFT, female on the RIGHT**, joined
 by a horizontal line.
- Children: drawn **below** the parental line, **oldest on the LEFT,
 youngest on the RIGHT**.
- Generations stack vertically: **oldest generation at the TOP, youngest
 at the BOTTOM**. Typically four tiers, great-grandparents,
 grandparents, parents (and parents' siblings), child(ren).

---

## 2. Person symbols

```
 
 Male Female
 
 
 
 Non-binary Unborn baby
 (D-shape) ____ (triangle; show EDD)
 
 
 Trans FM Trans MF
 
 (square outer, (circle outer,
 circle inner) square inner)
 
 
 Lesbian Gay
 
 (circle with (square with
 inverted triangle) inverted triangle)
```

- **Deceased**: large **X** across the symbol.
- **Abortion**: triangle with an **X** through it.
- **Miscarriage**: triangle with an **X** through it (drawn smaller /
 with a single stroke variation; see PDF p.4).
- **Stillborn**: an X-crossed shape drawn smaller than a live-born
 symbol (square for male, circle for female).
- **Pet**: **diamond** with the pet's name beside it. (Pets are
 included so households are accurately represented.)

---

## 3. Couple-line variants

The horizontal line between two partners encodes the relationship
status. Date labels go **on or just under** the line.

```
 Married. Label: m.MM.YYYY
 (or m.DD.MM.YYYY)

 / Separated, legal procedure for
 divorce has started.

 Γ— Separated, no longer living
 together.

 // Divorced. Label: m.YYYY d.YYYY

 X One partner died during the
 marriage. (Different from the
 "no longer living together" X, this is on the line, the
 deceased's symbol carries the
 across-shape X too.)

 – – – – – – – – Cohabiting / civil partnership.
 Label: start date.

 – – – – / – – – Cohabiting couple separated
 (living apart).

 – – – – / – – – 2018–2021 Civil-partnership couple
 (with dates) or officially separated; both start
 01.02.18 and end dates labelled.
 – 25.06.21
```

---

## 4. Parent–child line variants

The vertical line(s) from the parental line down to each child encode
the legal / biological tie.

```
 Biological child, solid line.

 + dashes Adopted child: a solid line and a dashed line
 together (one represents biological origin, one
 represents adoptive parents).

 Foster child, dashed line.
```

Twins / multiples share a single descender that fans out at the bottom:

```
 
 
 
 
 
 non-identical identical triplets
 twins twins (a fan of 3+)
 (horizontal bar
 between the
 twins)
```

---

## 5. Household boundary

A **free-form loop drawn around** a group of people indicates who is
**living in the same household**. The loop may include half-siblings,
step-children, pets, whoever sleeps under the same roof. There is no
formal shape; it just encloses the relevant symbols.

---

## 6. Key information (next to each person)

These abbreviations are drawn **next to the person's symbol** (not
inside it) to flag significant health / risk / status information. The
PDF stresses this list is a **guide only**, not exhaustive.

```
 LD Learning Disability
 PD Physical Disability
 SD Sensory Disability
 MH Mental Health
 AM Alcohol Misuse
 SM Substance Misuse
 D Depression
 P In Prison
 CAR Child At Risk
 SI Severe Illness
 LI Lifelong Illness
 SA Sexual Abuse
 PA Physical Abuse
 A Anxiety (or: experience of being Abused as a Child)
 EA Emotional Abuse
```

Multiple codes are separated by spaces / commas, e.g. `LD MH D`.

---

## 7. Emotional-relationship overlay

These are drawn as **arrows** or as **plain lines** between two
people's symbols, *in addition* to the structural family lines. Arrows
point **from the perpetrator to the victim**.

### Abuse / harm (coloured arrows)

```
 v v v v v v Violence (red, wavy + arrow)
 w w w w w w Physical Abuse (blue, wavy + arrow)
 w w w w w w Emotional Abuse (light green, wavy + arrow)
 w w w w w w Sexual Abuse (purple, DOUBLE wavy + arrow)
 w w w w w w Hostile relationship (light blue, wavy + arrow)
 – – – – – – Neglect (black, DASHED arrow)
```

A **double-headed arrow** ( ) between two people indicates **abuse
in both directions** (mutual).

### Closeness / quality (no arrowheads, plain lines between symbols)

```
 Very close relationship (double line)
 Close relationship (single line)
 – – – – – – – – Distant / poor (dashed line)
```

---

## 8. Examples (from the PDF)

The PDF includes three worked example genograms (PDF pp.10–14). They
illustrate, in combination:

- a four-generation tree with X-crossed deceased grandparents,
 multiple marriages with `m.YYYY d.YYYY` labels, biological + adopted
 + foster children, identical twins, a household boundary loop, plus
 the violence / hostile / sexual-abuse arrows;
- couples shown with cohabiting (dashed) and married (solid) lines,
 including separated-then-cohabiting transitions;
- pets shown as diamonds inside the household loop;
- key-info codes (LD, P, CAR, AM) rendered next to the relevant
 person's symbol.

The genogram is a snapshot, it documents the **current** family as
known to the worker, with as much accuracy as can reasonably be
obtained. Information that is unknown is shown with `?` (e.g. `b.?` or
`m.19??`); it is not fabricated.

Tips & gotchas

  • Mark one Client. Diagram + prose are anchored on the Client. Without a Client the diagram won't render.
  • Relationships drive the diagram, not roles. Setting role = "parent" does not auto-connect to the Client. Add a Parent Child relationship for the line to appear.
  • Siblings. Two people with at least one common Parent edge are siblings automatically. Use the Sibling relationship type only when no common Parent has been entered.
  • Twins / triplets. Use the Multiple-birth group field on each twin / triplet: siblings sharing a group ID get a fan-of-N descender. Pick Identical to add the horizontal bar.
  • Deceased / abortion / miscarriage / stillborn. Set Status: the appropriate X-crossed shape draws automatically. Prose uses "was".
  • Pet. Set role = Pet: renders as a diamond (no body fields needed beyond Name).
  • Storage. Build state autosaves to localStorage; reopening this file restores it. Use Download JSON for a persistent sidecar.
  • Importing a v1 Family Tree sidecar. The tool will accept it and fill missing v2 fields with defaults, revisit Sex / Status / kind on each row afterwards.

Confidentiality: runs entirely in your browser, nothing is uploaded. The sidecar JSON is plaintext; store it under the case's Case Summaries/ folder, same as every other case sidecar.

People

Mark exactly one person as Client. Add everyone the genogram needs.

Relationships

Each row connects two people. Couple = horizontal line; Parent Child = vertical line; Overlay = on-top abuse / closeness arrow.

Wheel = zoom Β· Drag = pan Β· Double-click = reset
No genogram yet. On the Build tab, add at least one person and mark them as Client.

Image & PDF

PNG renders the current genogram at print resolution; PDF wraps it on A4 with the canonical PRIVATE & CONFIDENTIAL header, a footer band (case ref Β· date Β· page), and an optional DRAFT watermark (toggle in Config).

PNG:
PDF: (same filename for either orientation)

Sidecar JSON

Downloads <ref>.genogram.json for the case's Case Summaries/ folder. The case-summary file itself is never touched. v1 Family Tree sidecars (<ref>.family-tree.json) can be imported.

Filename:

Plain-prose paragraph

A single paragraph walking the family outwards from the client. Drop into a witness statement or covering letter; edit as needed. Overlay edges (abuse / closeness) are deliberately NOT emitted, they're safeguarding metadata, not biographical fact.

Backlog (per GENOGRAM-SPEC Β§11)

Household-boundary freeform loop Β· distinct step-parent dashed-double line Β· EB Garamond inline Β· qpdf-wasm AES-256 encryption Β· auto-import from gmiau-case-summary/1. The PDF here is unencrypted; encrypt downstream via pdf-encrypt.html if needed.

Render mode

Simple: rounded rectangles for everyone, plain solid couple / parent lines, deceased shown with a single diagonal slash, no key codes, no abuse / closeness overlay. Filenames say Family Tree. Genogram: the published social-work convention: shapes by sex / trans / orientation, X-across deceased, key codes, abuse / closeness overlay arrows. Filenames say Genogram. The data model is the same in both modes: switching never loses what you've entered.

Diagram options

PDF export

Orientation is chosen at export time via the two PDF buttons on the Export tab. Filenames follow EXPORT-SPEC.md Β§1: YYMMDD CLIENTREF SEQ Genogram.{pdf,png}. The sidecar JSON uses <ref>.genogram.json. Both formats are unencrypted: pipe through pdf-encrypt.html if AES-256 is needed.

App font

App appearance

Tab visibility

Syncs across every GMIAU Shell tool via ifyi_hide_guide_tab + ifyi_hide_config_tab.

Tool spec (reference)

The current GENOGRAM-SPEC.md is inlined at build time. Edit the spec at gmiau-specs/GENOGRAM-SPEC.md and run immigrationfyi-tools update to refresh.

Show GENOGRAM-SPEC.md
# Genogram Generator: Tool Spec

**Version 2.0 Β· 2026-05-15**

`genogram-generator.html` is a GMIAU Shell tool for drawing a client's
**genogram**, a family / relationship diagram following the
social-work convention summarised in `GENOGRAM-GUIDE.md`. The output is
intended to drop into a tribunal bundle exhibit, into a safeguarding
referral, or into a witness statement (as a paragraph of plain prose).

This tool **supersedes the Family Tree tool** that shipped on
2026-05-14. The Family Tree tool used rectangles for every person and
collapsed all couple relationships into one line type; Genogram
Generator follows the published social-work convention (different
shapes by sex, distinct couple-line variants, parent-child line types,
key-info codes, abuse / closeness overlay).

Cross-referenced specs:

- `gmiau-specs/GENOGRAM-GUIDE.md`, the social-work convention itself
 (distilled from the published Genogram Explanation PDF). Embedded
 verbatim in the Guide tab via `@@SPEC:GENOGRAM-GUIDE@@`.
- `gmiau-specs/GMIAU-STYLE-GUIDE.md`, shell scaffold, tabs, settings,
 themed scrollbars, panel width (Β§4A), Guide-tab visibility (Β§2C).
- `gmiau-specs/PDF-OUTPUT-SPEC.md`, A4 margins, fonts, page setup.
- `gmiau-specs/GMIAU-ICONS-SPEC.md`, icon design.
- `gmiau-specs/EXPORT-SPEC.md`: export filename convention.

Source PDF: `gmiau-specs/source-docs/genogram-guide-07102022.pdf`.

---

## 1. Purpose

One tool, one diagram. The caseworker enters every relevant person
plus each pairwise relationship; the tool lays them out generationally
(top-down) and exports:

1. **A4 PDF** (landscape default) for a bundle exhibit, with the
 canonical PDF protection pattern (PRIVATE & CONFIDENTIAL header,
 optional DRAFT watermark), see Β§5.
2. **PNG** at 2Γ— device pixels, white background, see Β§5.1.
3. **Interactive HTML SVG** in the Diagram tab (pan / zoom).
4. **Sidecar JSON** at
 `<open_cases>/Case Summaries/<ref>.genogram.json`, see Β§6.
5. **Plain-prose paragraph** for pasting into a witness statement or
 letter, see Β§7.

Manual data entry only in v2.0. No GEDCOM, no auto-import from
case summary, no household boundary, no radial layout (the v1.2
radial-layout stub is removed, top-down is the only laid-out form
and matches the convention).

Anything in `GENOGRAM-GUIDE.md` that is **not** implemented here is
listed in Β§11 as backlog.

---

## 2. Tabs

Per `GMIAU-STYLE-GUIDE.md` Β§2A (tab-btn style), Β§2C (Guide / Config
hideable toggles). Minimum-5 ordering. Primary tool tab
(`build`) is default-active per the 2026-05-13 reversal
(`feedback_guide_default_flip`).

| Order | Tab | id | Default-active | Hideable |
|-------|---------------|--------------|----------------|----------|
| 1 | Guide | `guide` | no | yes |
| 2 | Build | `build` | **yes** | no |
| 3 | Diagram | `diagram` | no | no |
| 4 | Export | `export` | no | no |
| 5 | Config | `config` | no | yes |
| 6 | Settings | `settings` | no | no |
| 7 | Index | (link) | n/a | no |

`window.IFYI_PRIMARY_TAB = 'build'`.

The **Guide tab** holds: a hand-written intro to using the tool, then a
`<details>`-wrapped `@@SPEC:GENOGRAM-GUIDE@@` block holding the
inlined social-work convention.

The **Settings tab** holds the canonical 6 toggles (Mode, Theme,
App-font Family, App-font Size, Hide Guide, Hide Config) plus a
`<details>`-wrapped `@@SPEC:GENOGRAM-SPEC@@` block holding this
spec.

---

## 3. Data model

### 3.1 Person

```ts
type Person = {
 id: string; // 'p1', 'p2', … (stable across a session)
 role: 'client' // exactly one Person should have role='client'
 | 'spouse'
 | 'parent'
 | 'child'
 | 'sibling'
 | 'grandparent'
 | 'maternal-aunt' | 'paternal-aunt'
 | 'maternal-uncle' | 'paternal-uncle'
 | 'cousin'
 | 'in-law'
 | 'pet'
 | 'other';
 name: string;

 // Symbol attributes
 sex: 'M' | 'F' | 'NB' | '?'; // displayed shape (square/circle/D/?)
 trans?: 'F-to-M' | 'M-to-F'; // renders nested inner shape
 orientation?: 'gay' | 'lesbian'; // renders inverted-triangle inset

 // Life status
 status: 'alive' | 'deceased' | 'unborn' | 'abortion' | 'miscarriage'
 | 'stillborn' | 'unknown';
 dob?: string; // 'YYYY-MM-DD' | 'YYYY' | '', never required
 dod?: string; // date of death (only if status='deceased')
 edd?: string; // expected delivery date (only if status='unborn')

 // Optional context
 location?: string; // 'Kabul, Afghanistan' / 'UK' / etc.
 keyCodes?: string; // free-text, space-or-comma separated: 'LD MH D'
 // rendered next to (not inside) the symbol. See Β§3.4.
 notes?: string; // free text, risk profile, witness availability, etc.

 // Multiple births
 multipleId?: string; // shared group id ('m1', 'm2', …), siblings with
 // the same multipleId render as a fan-of-N descender
 multipleKind?: 'identical' | 'fraternal'; // identical adds a horizontal bar
};
```

The `role` field is **descriptive labelling only**. Graph structure
comes from the Relationships list. Pets render as a small diamond per
the convention; everything else uses the Β§3.3 shape table.

### 3.2 Relationship

```ts
type Relationship =
 | { type: 'couple'; a: PersonId; b: PersonId;
 kind: 'married' | 'separated-legal' | 'separated-living-apart'
 | 'divorced' | 'widowed' | 'cohabiting'
 | 'cohabiting-separated' | 'civil-separated';
 startDate?: string; // m.YYYY or m.DD.MM.YYYY for married/cohabiting
 endDate?: string; // d.YYYY for divorced/widowed
 }
 | { type: 'parent'; parent: PersonId; child: PersonId;
 kind: 'biological' | 'adopted' | 'foster';
 }
 | { type: 'sibling'; a: PersonId; b: PersonId; } // shorthand, see Β§3.5
 | { type: 'overlay'; a: PersonId; b: PersonId;
 kind: 'violence' | 'physical-abuse' | 'emotional-abuse'
 | 'sexual-abuse' | 'hostile' | 'neglect'
 | 'very-close' | 'close' | 'distant';
 direction: 'a-to-b' | 'b-to-a' | 'both' | 'none';
 // direction='none' is the only valid choice for very-close / close /
 // distant (plain lines, no arrowhead). For the abuse + neglect
 // kinds, direction must be 'a-to-b', 'b-to-a', or 'both'.
 };
```

Note the v1.2 v2.0 changes:

- `spouse` + `partner` a single `couple` with a `kind` field.
- `adoptive-parent` / `step-parent` a single `parent` with a `kind`
 field (`biological` / `adopted` / `foster`). "Step-parent" is not in
 the social-work convention as a distinct line type; render a
 step-parent as a `couple` edge plus a `parent` edge of kind
 `adopted` where the step-relationship is legally formalised, else
 leave the parent edge absent. (Backlog item: explicit step-parent
 dashed-double-line.)
- New `overlay` edge type carries the abuse / closeness lines that
 sit on top of the structural diagram.

### 3.3 Shape table (rendered)

| sex | trans | orientation | Renders |
|-----|------------|-------------|--------------------------------------------------|
| M |, |: | Square |
| F |: |: | Circle (oval) |
| NB |: |: | D-shape (Word's "Flowchart: Delay") |
| ? |: |: | A question mark inside a dashed square |
| M |, | gay | Square with inverted-triangle () inset |
| F |, | lesbian | Circle with inverted-triangle () inset |
| M | `F-to-M` |, | Square outer, circle inner (born-female) |
| F | `M-to-F` |, | Circle outer, square inner (born-male) |

A `status='unborn'` symbol is **always** a triangle regardless of sex.
A `status='deceased'` symbol carries a large `X` across whatever shape
the Β§3.3 table would otherwise draw. `status='abortion'` and
`status='miscarriage'` render an X-through small triangle.
`status='stillborn'` renders an X-through small square (M) or oval (F).

### 3.4 keyCodes

A free-text field. The tool does not validate against the
GUIDE Β§6 list, caseworkers should follow it but the convention is
self-documenting and stable extensions (e.g. `ASD`) are routine.
Rendered as a short line of text **above** the person's symbol, in the
shell's muted text colour. Comma-separated codes are accepted but
displayed verbatim.

### 3.5 Sibling shorthand

`{ type: 'sibling', a, b }` is shorthand for "share at least one
parent" when the user hasn't entered grandparent rows. The diagram
engine treats two people with at least one common `parent` edge as
siblings automatically, sibling rows are only needed when no common
parent has been entered.

### 3.6 Sidecar JSON shape

```json
{
 "_v": 2,
 "_tool": "genogram-generator",
 "_exportedAt": "2026-05-15T14:21:00.000Z",
 "case_ref": "RB12345",
 "people": [ { "id": "p1", "role": "client", "name": "…", … } ],
 "relationships": [ { "type": "couple", "a": "p1", "b": "p2", … }, … ],
 "options": {
 "show_dob": true,
 "show_location": true,
 "show_status": true,
 "show_keycodes": true,
 "show_overlay": true
 }
}
```

The `_v: 2` bump distinguishes Genogram sidecars from v1 Family Tree
sidecars (which had `_tool: "family-tree"`). v1 sidecars are not
auto-migrated in v2.0, the import will accept them but warn that
fields are missing.

---

## 4. Diagram engine

Top-down only. The v1.2 radial layout is removed.

### 4.1 Tier assignment

BFS from the client (tier 0). Each `parent` edge moves +1 toward the
parent (older), each `parent` edge from the other side moves βˆ’1
(younger). Couple partners share a tier.

### 4.2 Within-tier ordering

1. **Couples sit adjacent**: the male symbol is on the LEFT, the
 female symbol on the RIGHT, joined by a horizontal couple-line.
 Non-binary partners take the position dictated by the partner's sex
 (NB M NB on the right; NB F NB on the left; NB NB 
 insertion order).
2. **Siblings cluster** and are sorted **DOB-ascending, left-to-right**
 (oldest on the LEFT). Siblings without a DOB hold their insertion
 order at the right end of the cluster.
3. **Stable order** otherwise, preserve insertion order when
 underdetermined.

### 4.2a Sub-row wrapping (large families)

A tier only ever grows sideways, so a wide generation is fitted
width-first on A4 and most of the page height goes unused, which is
what made names in a large family unreadable. A tier is therefore
allowed to wrap into **stacked sub-rows**, spending that height to buy
back scale.

Wrapping is automatic and conservative:

- It is attempted **only** when the whole diagram would otherwise print
 below **9 pt** on a single A4 sheet. At or above that, the strict
 one-row-per-generation layout of Β§4.1 is kept untouched.
- Candidate sub-row widths are tried widest-first, and a narrower split
 must beat the incumbent by **more than 3%** (and the unwrapped layout
 by more than 5%) to be adopted. The layout closest to the convention
 therefore wins ties.
- A **couple is never split** across sub-rows: partners travel as one
 unit.
- A sibling group too wide for one sub-row is given **exclusive**
 sub-rows, which keeps the margin to its left clear.
- The parent bus (Β§4.3) then draws **one bus per sub-row**, the lower
 ones fed by a vertical drop-line running down that clear left margin.

Worked example: 14 siblings on a 92-unit pitch is 1260 units wide and
prints names at 5.6 pt. Wrapped to 2 sub-rows of 7 it is 616 Γ— 369 and
prints at 10.8 pt.

### 4.3 Edges

- **Couple line**: horizontal, between the two symbols. The Β§4.6 table
 governs stroke style (solid / dashed) and stroke decorations
 (single slash, X, double slash, etc.).
- **Parent–child line**: vertical line down from the midpoint of the
 couple-line (or from a single parent's symbol) to a horizontal
 *sibling bus*; from the bus, one vertical descender per child. The
 Β§4.7 table governs stroke style (solid / dashed / solid+dashed).
- **Twins**: a single descender that fans out into N legs at the
 bottom. `multipleKind='identical'` adds a horizontal bar joining
 the legs.
- **Overlay edges**: drawn ON TOP of the structural diagram, after all
 structural lines, with their own per-kind colour and dash pattern.
 Overlay edges may bend around symbols (route via simple orthogonal
 segments), straight lines are acceptable if no symbol is on the
 direct path.

### 4.4 Symbol sizing and label fitting

Each symbol is 64 Γ— 44 SVG units, on a column pitch of 92 (`BOX_W +
H_GAP`). Labels:

- **Name** on line 1 (under the symbol).
- **`b.YYYY-MM-DD`** on line 2 (replaces line 2 with `b.?` if absent),
 with `d.YYYY-MM-DD` appended when deceased.
- **Location** on line 3 (hidden when `options.show_location=false`).
- **keyCodes** is rendered ABOVE the symbol, line 0, when present.

Every label is **measured and wrapped to 86 units** (the column pitch
less a 6-unit gutter), never cut at a fixed character count, a
character count cannot know how wide the text is, so it both truncated
readable names and let long ones overlap the next column. Widths are
measured against the export font (Helvetica / Arial) so screen and PDF
agree.

- Name wraps to at most **2 lines**, breaking on spaces.
- The `b.` / `d.` pair sits on one line when it fits, otherwise one
 date per line. A date is never truncated.
- Location wraps to at most 2 lines; keyCodes stay on one.
- Only a single unbreakable word longer than the column is ellipsized.
- Row height is derived from the tallest label block in that row, so
 rows are exactly as tall as their content needs.

Couple-line labels sit in the 28-unit gap between the two symbols, so
they are stacked one part per line and shrunk (8 px down to a 6 px
floor) to fit that gap rather than run across both symbols. They are
year-level (`m.YYYY`, `m.YYYY d.YYYY`), a full ISO date cannot be set
legibly in that gap, and the exact day is carried by the Prose tab.

### 4.5 Deceased / abortion / miscarriage / stillborn

X is stroked at 1.5Γ— the regular symbol stroke weight, across the
full extent of whatever shape the symbol uses, corner to corner.

### 4.6 Couple-line variants

| `kind` | Stroke | Decoration | Label format |
|--------------------------|----------|-------------------------------------|---------------------|
| `married` | solid | none | `m.MM.YYYY` |
| `separated-legal` | solid | single `/` slash through the line | (start date if any) |
| `separated-living-apart` | solid | `Γ—` cross through the line | (start date if any) |
| `divorced` | solid | double `//` slashes | `m.YYYY d.YYYY` |
| `widowed` | solid | `X` on the line | `m.YYYY d.YYYY` |
| `cohabiting` | dashed | none | start date |
| `cohabiting-separated` | dashed | single `/` slash | start date |
| `civil-separated` | dashed | `/` slash | `YYYY-YYYY` range |

### 4.7 Parent-child variants

| `kind` | Stroke |
|---------------|------------------------------------------------|
| `biological` | solid |
| `adopted` | one solid descender + one dashed descender |
| `foster` | dashed |

### 4.8 Overlay variants

| `kind` | Colour | Stroke | Arrow |
|------------------|--------------|---------------------|---------------|
| `violence` | red | wavy + solid base | yes |
| `physical-abuse` | blue | wavy + solid base | yes |
| `emotional-abuse`| light green | wavy + solid base | yes |
| `sexual-abuse` | purple | DOUBLE wavy | yes |
| `hostile` | light blue | wavy + solid base | yes |
| `neglect` | black | dashed | yes |
| `very-close` | black | DOUBLE solid | no |
| `close` | black | solid | no |
| `distant` | black | dashed | no |

`direction='both'` renders a double-headed arrow.

### 4.9 Pan / zoom

Native SVG via `viewBox` mutation. Mouse-wheel zooms, click-drag pans,
double-click resets. Touch support is not required in v2.0.

---

## 5. PDF export

Per `ref_ifyi_pdf_protection` and `feedback_private_and_confidential_glyph`:

- **Page**: A4 (297 Γ— 210 mm). Orientation is chosen at export time, the Export tab has two buttons, ** Landscape PDF** and ** Portrait
 PDF**. No Config toggle (removed in v2.0.1).
- **Fit to page**: the exporter always uses the FULL content bbox
 (via `SVGSVGElement.getBBox()`), independent of whatever pan / zoom
 the user has left in the Diagram tab. Aspect-preserving fit centres
 the diagram between the header and footer with 12 mm horizontal
 margins.
- **Readability floor and multi-sheet spill**: names are held at a
 minimum of **6 pt**. If the diagram cannot fit one sheet at that
 size, it is **tiled across up to 9 A4 sheets** rather than shrunk
 further. Tiles are spread evenly over the content, so neighbouring
 sheets overlap slightly and the far edge is covered exactly. Past 9
 sheets the exporter falls back to a single fitted sheet. Each sheet
 repeats the header and is titled `… (sheet N of M)`; the footer
 numbers them `Page N of M`.
- **Orientation hint**: because Β§4.2a optimises the layout for
 whichever orientation suits the diagram, the Export tab shows the
 sheet count and resulting name size for BOTH orientations, marking
 the better one as recommended.
- **Header**: `PRIVATE & CONFIDENTIAL` (ampersand, never "AND") centred
 at the top, ~12 pt Helvetica bold (EB Garamond when inlined, see
 Β§11).
- **Watermark**: `DRAFT` diagonal stamp, light grey, 25% opacity
 (Config toggle, off by default).
- **Footer band**: case ref, date generated, page number. No GMIAU
 logo on the genogram page itself.
- **Encryption**: deferred. v2.0 ships an unencrypted PDF; pipe
 through `pdf-encrypt.html` (qpdf-wasm AES-256) if the bundle
 requires it.
- **Filename**: `YYMMDD CLIENTREF SEQ Genogram.pdf` per
 `EXPORT-SPEC.md Β§1` (single-space separator), built via the
 canonical `_exportName()` helper inlined in the tool.

### 5.1 PNG export

- **Resolution**: 2Γ— CSS-px scale of the current SVG viewBox.
- **Inline CSS**: the tool clones the live SVG and injects a fixed
 light palette before serialising (`_EXPORT_SVG_CSS` constant) so
 the export is independent of the in-app theme.
- **Filename**: `YYMMDD CLIENTREF SEQ Genogram.png`.
- **Library**: none, pure DOM (`new Image(); canvas.toBlob`).

---

## 6. Sidecar JSON I/O

Write-back target:

```
<open_cases>/Case Summaries/<ref>.genogram.json
```

`<open_cases>` resolves from the One File config (`paths.openCases`)
when loaded, else falls back to `~/Work/00 Open Cases/`. The
case-summary JSON itself is **untouched**.

Import in the Build tab's ` Import sidecar` button reads that path
(via `<input type=file>` since FSA is disabled on `file://`). On
save, the tool offers a download with the canonical filename.

**v1 Family Tree sidecars** (`<ref>.family-tree.json`, `_v: 1`) are
accepted on import; missing v2 fields are filled with defaults
(`sex: '?'`, `status: 'alive'`, `couple.kind: 'married'`,
`parent.kind: 'biological'`). The tool surfaces a one-time banner
when a v1 sidecar is imported so the caseworker knows to revisit the
new fields.

---

## 7. Plain-prose generator

Generates a single paragraph by walking the graph from the client
outwards. Sentence templates:

| Edge type from client | Sentence |
|------------------------------------------------|---------------------------------------------------------------------------|
| Couple, married, alive | "{X} is the {client}'s {wife\|husband}, born {dob} in {location}." |
| Couple, divorced | "{X} is the {client}'s ex-{wife\|husband}, married {m} and divorced {d}." |
| Couple, cohabiting | "{X} is the {client}'s partner, in a relationship since {start}." |
| Parent (mother / father by sex) | "{X} is the {client}'s {mother\|father}, born {dob} in {location}." |
| Parent, deceased | "{X} was the {client}'s {mother\|father}, born {dob} and died {dod}." |
| Parent, adopted | "{X} adopted the {client}, …" |
| Parent, foster | "{X} is the {client}'s foster {mother\|father}, …" |
| Child (biological) | "{X} is the {client}'s {daughter\|son\|child}, born {dob}." |
| Sibling | "{X} is the {client}'s {sister\|brother\|sibling}, born {dob}." |
| Aunt/uncle (derived: sibling of a parent) | "{X} is the {client}'s {maternal\|paternal} {aunt\|uncle}, …" |

Order: couple parents children siblings aunts/uncles 
grandparents others. Punctuation uses commas + ` and ` (no Oxford
comma, UK style). Each person is emitted at most once.

Overlay edges are NOT emitted in prose (they're confidential
safeguarding metadata, not biographical fact).

### 7.1 Placeholder convention (form inputs)

Per `REFERENCES-SPEC.md Β§104-105`, form placeholders use the canonical
example strings directly (no `e.g.` prefix). Seeded placeholders:
person name **`David Pountney`**, location **`Manchester, UK`**, case
ref **`RB12345`**.

---

## 8. Settings (canonical 6)

The tool inherits the canonical 6 toggles unchanged (Mode, Theme,
App-font Family, App-font Size, Hide Guide, Hide Config). No tool-local
matter-toggles in the Settings tab.

The Settings tab also includes a `<details>` block with the inlined
`@@SPEC:GENOGRAM-SPEC@@` (this file) for in-tool reference.

---

## 9. Config (per-tool)

| Field | Default | Notes |
|--------------------------------|--------------|------------------------------------------------------------------------|
| Show DOB | on | matter-toggle |
| Show location | on | " |
| Show status | on | controls whether status markers (`X`, triangle for unborn) render |
| Show keyCodes | on | " |
| Show overlay | on | hide the abuse / closeness overlay for non-safeguarding exhibits |
| DRAFT watermark | off | matter-toggle: On / Off (`ifyi_gg_pdf_draft`). Orientation lives on the Export tab, no Config toggle. |

All persist to `localStorage` under namespaced keys `ifyi_gg_<setting>`.

---

## 10. File layout

```
immigrationfyi-tools/source/genogram-generator.html edit here
immigrationfyi-tools/offline/genogram-generator-offline.html regen by build-all-offline.py
gmiau-specs/GENOGRAM-SPEC.md this file
gmiau-specs/GENOGRAM-GUIDE.md social-work convention, inlined in Guide tab
gmiau-specs/source-docs/genogram-guide-07102022.pdf original PDF
gmiau-specs/icons/genogram-generator.{svg,png} icon (frame + glyph)
```

Vault docs:

```
~/Notes/Resources/Cheatsheets/Genogram Generator Cheatsheet.md
~/Notes/Resources/Reference/Genogram Generator Reference.md
```

GitHub Pages mirror (Filer / Bundle Builder / Evidence Exhibitor /
Auditor companion): `ryanbestford.github.io/tools/genogram-generator.html`,
encrypted via `~/Projects/rjb/tools/publish.fish`.

---

## 11. Backlog (deferred from v2.0)

- **Household boundary**, freeform loop drawn around co-resident
 symbols (GUIDE Β§5). Postponed because freeform-path UX in SVG is
 awkward; a rectangular bounding-box approximation may land in v2.1.
- **Step-parent line**, distinct dashed-double-line style.
- **EB Garamond** inline for PDF body text (currently Helvetica).
- **qpdf-wasm AES-256** PDF encryption (pipe through `pdf-encrypt.html`
 in the meantime).
- **Auto-import from `gmiau-case-summary/1`**, read parents, spouse,
 children from the case-summary JSON to pre-fill the Build tab.
- **GEDCOM import / export**, unsupported; would need its own spec.

---

## 12. Versioning

- **2.1 Β· 2026-05-15**, Render-mode toggle added to the Config tab: **Simple (family tree)** vs **Genogram (procedure)**, persisted to `localStorage.ifyi_gg_render_mode` (default: `genogram`). Simple mode renders rounded rectangles for every person regardless of sex / trans / orientation, draws plain solid couple / parent lines (no per-kind decorations or dashing), uses the original diagonal-slash for deceased (no X-across-shape), and skips key-codes + overlay edges entirely. Couple labels condense to `m.YYYY Β· div.YYYY`. Export filenames + PDF title switch to `Family Tree`. Data model is unchanged, switching modes never loses entered data; sidecar JSON does not store the mode (Settings-level preference per [[ref_ifyi_one_file_config]]-style stickiness, not per-case).
- **2.0.1 Β· 2026-05-15**, Export-tab PDF buttons split into ** Landscape PDF** + ** Portrait PDF** (orientation chosen at export, not via Config). Export now uses `SVGSVGElement.getBBox()` to fit the FULL content (the previous version inherited the user's pan / zoom, which clipped the leftmost column in `RB12345.genogram.json`). Diagram-tab **Fit** button and `dblclick` now call `fitToContent()` directly (no full re-render).
- **2.0 Β· 2026-05-15**, Genogram Generator. Renamed from Family Tree;
 conventions adopted from `gmiau-specs/source-docs/genogram-guide-07102022.pdf`.
 Visual core (shapes by sex, deceased X, twins/triplets, trans
 nesting, gay/lesbian inverted-triangle) + couple-line variants
 (married/separated/divorced/widowed/cohabiting/civil-separated) +
 parent-child line types (biological/adopted/foster) + male-left /
 oldest-left layout + keyCodes field + emotional-relationship
 overlay (7 kinds Γ— 4 directions). Sidecar `_v` bumps to 2; v1
 sidecars are accepted on import with defaults filled.

Prior versions of the predecessor tool (Family Tree v1.0 / v1.1 / v1.2,
2026-05-13 2026-05-14) are archived in
`gmiau-backup/genogram-rename-2026-05-15/` for reference.