Files
familienarchiv/docs/specs/persons-concept-a-enriched-directory.html
Marcel ae47af52b9
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
docs: add persons section Concept A spec (Enriched Directory)
Wireframe spec for the Persons section redesign (issue #157):
- Enriched person cards with alias, life dates, document count
- 2-column detail layout (person info sidebar + activity area)
- Dedicated /persons/[id]/edit route with sticky save bar
- Danger Zone accordion for merge (collapsed by default)
- All fields on new person form (birth year, death year, notes)
- Full coverage: list, detail, edit, new, edge cases, implementation notes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 16:55:24 +02:00

1646 lines
103 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Persons Section — Concept A Specification · Familienarchiv</title>
<style>
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
body{font-family:'Helvetica Neue',Arial,sans-serif;background:#ECEAE4;color:#1A1A1A;line-height:1.5}
.doc{max-width:1560px;margin:0 auto;padding:48px 32px}
.doc-masthead{margin-bottom:56px;border-bottom:2px solid #C8C4BE;padding-bottom:28px}
.doc-masthead h1{font-size:26px;font-weight:800;color:#002850;letter-spacing:-.5px}
.doc-masthead p{margin-top:6px;color:#666;font-size:14px;max-width:680px;line-height:1.6}
.doc-masthead .meta{margin-top:10px;font-size:11px;color:#AAA;font-weight:600;letter-spacing:1px;text-transform:uppercase}
.section{margin-bottom:72px}
.section+.section{border-top:2px dashed #C8C4BE;padding-top:64px}
.sec-intro{display:flex;align-items:flex-start;gap:20px;margin-bottom:28px}
.sec-num{font-size:52px;font-weight:900;color:#DDD;line-height:1;flex-shrink:0;width:64px}
.sec-meta{}
.sec-badge{display:inline-block;font-size:10px;font-weight:800;padding:3px 10px;border-radius:20px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px}
.badge-arch{background:#F0F0F0;color:#555}
.badge-users{background:#E3EEFF;color:#1D4ED8}
.badge-persons{background:#E3EEFF;color:#1D4ED8}
.badge-groups{background:#E5F5EC;color:#15803D}
.badge-tags{background:#FEF3C7;color:#B45309}
.badge-system{background:#FEE2E2;color:#B91C1C}
.badge-edge{background:#F3E8FF;color:#7C3AED}
.sec-title{font-size:20px;font-weight:800;color:#002850;margin-bottom:4px}
.sec-tagline{font-size:13px;color:#666;max-width:620px;line-height:1.6}
.screens{display:flex;gap:20px;align-items:flex-start;margin-bottom:16px;flex-wrap:wrap}
.screens.cols2{display:grid;grid-template-columns:1fr 1fr;gap:20px}
.screens.cols3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px}
.screens.cols4{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:14px}
.screen-block{display:flex;flex-direction:column;min-width:0}
.screen-label{font-size:10px;font-weight:800;color:#888;text-transform:uppercase;letter-spacing:1.5px;margin-bottom:8px;display:flex;align-items:center;gap:8px}
.sz{background:#E8E4DF;color:#666;padding:1px 6px;border-radius:3px;font-size:9px}
.state-tag{padding:1px 7px;border-radius:3px;font-size:9px;font-weight:700;background:#DBEAFE;color:#1E40AF}
.state-tag.new{background:#DCFCE7;color:#166534}
.state-tag.edit{background:#FEF3C7;color:#92400E}
.state-tag.del{background:#FEE2E2;color:#991B1B}
.state-tag.empty{background:#F3F4F6;color:#374151}
.state-tag.err{background:#FEE2E2;color:#991B1B}
.state-tag.warn{background:#FEF3C7;color:#92400E}
.screen-cap{font-size:9px;color:#888;margin-top:6px;text-align:center;font-style:italic;line-height:1.5}
.wf{background:#fff;border:2px solid #B8B4AE;border-radius:10px;overflow:hidden;box-shadow:0 4px 20px rgba(0,0,0,.08);position:relative}
.wf-bar{height:26px;background:#E8E4DF;border-bottom:1px solid #C8C4BE;display:flex;align-items:center;padding:0 10px;gap:5px}
.dot{width:8px;height:8px;border-radius:50%;background:#C8C4BE}
.urlbar{flex:1;height:13px;background:#D8D4CE;border-radius:3px;margin-left:8px}
.NAV{height:44px;background:#0D2240;display:flex;align-items:center;padding:0 18px;gap:14px}
.NAV-m{height:46px;background:#0D2240;display:flex;align-items:center;padding:0 14px;justify-content:space-between}
.logo{font-size:10px;font-weight:900;color:#fff;letter-spacing:1px}
.nl{font-size:8px;color:rgba(255,255,255,.55);font-weight:700;text-transform:uppercase;letter-spacing:.5px}
.nl.on{color:#fff;border-bottom:2px solid #A6DAD8;padding-bottom:2px}
.nr{margin-left:auto;display:flex;gap:8px;align-items:center}
.nico{width:22px;height:22px;background:rgba(255,255,255,.12);border-radius:5px}
.nlang{font-size:8px;color:rgba(255,255,255,.5);font-weight:700;display:flex;gap:4px}
.nlang .on{color:#fff}
.EN{width:120px;background:#0D2240;flex-shrink:0;display:flex;flex-direction:column}
.EN-head{padding:10px 12px 6px;font-size:7.5px;font-weight:800;color:rgba(255,255,255,.3);text-transform:uppercase;letter-spacing:1px}
.EN-item{padding:11px 14px;display:flex;flex-direction:column;gap:3px;cursor:pointer;border-left:3px solid transparent;flex-shrink:0}
.EN-item.on{background:rgba(255,255,255,.1);border-left-color:#A6DAD8}
.EN-lbl{font-size:9px;font-weight:800;color:rgba(255,255,255,.55);text-transform:uppercase;letter-spacing:.5px}
.EN-item.on .EN-lbl{color:#fff}
.EN-cnt{font-size:13px;font-weight:900;color:rgba(255,255,255,.2)}
.EN-item.on .EN-cnt{color:rgba(255,255,255,.65)}
.EN-spacer{flex:1}
.EN-item.sys{border-top:1px solid rgba(255,255,255,.1);margin-top:auto}
.LP{width:240px;flex-shrink:0;border-right:1px solid #E0DDD6;display:flex;flex-direction:column;background:#F7F5F2}
.LP-head{padding:10px 14px;border-bottom:1px solid #E0DDD6;background:#F0EDE8;display:flex;align-items:center;justify-content:space-between}
.LP-title{font-size:10px;font-weight:800;color:#0D2240;text-transform:uppercase;letter-spacing:.5px}
.LP-search{margin:8px 10px 4px;height:28px;border:1.5px solid #D1D5DB;border-radius:5px;background:#fff;display:flex;align-items:center;padding:0 8px;font-size:9px;color:#AAA;font-style:italic;gap:4px}
.LP-item{padding:9px 14px;border-bottom:1px solid #EAE7E2;cursor:pointer;display:flex;align-items:center;justify-content:space-between}
.LP-item:hover{background:#EEEAE5}
.LP-item.on{background:#EEF2FF;border-right:3px solid #002850}
.LP-name{font-size:10px;font-weight:700;color:#1A1A1A}
.LP-item.on .LP-name{color:#002850}
.LP-sub{font-size:8px;color:#999;margin-top:1px}
.LP-item.on .LP-sub{color:#7B9FD4}
.LP-chev{font-size:11px;color:#CCC}
.LP-item.on .LP-chev{color:#002850}
.LP-empty{padding:24px 14px;text-align:center;font-size:9px;color:#BBB;font-style:italic}
.DP{flex:1;display:flex;flex-direction:column;min-width:0;background:#fff}
.DP-head{padding:14px 20px;border-bottom:1px solid #E8E4DF;background:#F7F5F2;display:flex;align-items:flex-start;justify-content:space-between;flex-shrink:0}
.DP-title{font-size:14px;font-weight:800;color:#0D2240}
.DP-sub{font-size:9px;color:#888;margin-top:2px}
.DP-body{padding:16px 20px;flex:1;display:flex;flex-direction:column;gap:0;overflow:hidden}
.DP-empty{flex:1;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:8px;padding:32px}
.DP-empty-icon{font-size:32px;opacity:.2}
.DP-empty-msg{font-size:11px;color:#AAA;text-align:center;line-height:1.6}
.DP-footer{background:#fff;border-top:1.5px solid #E8E4DF;padding:10px 20px;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;box-shadow:0 -2px 8px rgba(0,0,0,.05)}
.BODY{display:flex;min-height:0;flex:1}
.BTN{display:inline-flex;align-items:center;gap:4px;font-size:8px;font-weight:800;padding:5px 10px;border-radius:4px;text-transform:uppercase;letter-spacing:.5px;cursor:pointer;white-space:nowrap}
.BTN-sm{font-size:7.5px;padding:3px 8px}
.BTN-xs{font-size:7px;padding:2px 6px}
.BTN-primary{background:#002850;color:#fff}
.BTN-outline{border:1.5px solid #002850;color:#002850;background:transparent}
.BTN-ghost{color:#777;background:transparent}
.BTN-danger{border:1.5px solid #DC2626;color:#DC2626;background:#FEF2F2}
.BTN-danger-fill{background:#DC2626;color:#fff}
.BTN-warn{background:#D97706;color:#fff}
.BTN-green{background:#15803D;color:#fff}
.BTN-amber{border:1.5px solid #D97706;color:#D97706;background:#FFFBEB}
.FG{margin-bottom:10px}
.FG-row{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:10px}
.FG-row3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:10px}
.FL{display:block;font-size:8px;font-weight:800;color:#888;text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}
.FL .req{color:#DC2626}
.FI{width:100%;height:26px;border:1.5px solid #D1D5DB;border-radius:4px;background:#F9FAFB}
.FI.focus{border-color:#002850;background:#fff;box-shadow:0 0 0 3px rgba(0,40,80,.07)}
.FI.filled{display:flex;align-items:center;padding:0 8px;font-size:9px;color:#333}
.FTA{width:100%;height:52px;border:1.5px solid #D1D5DB;border-radius:4px;background:#F9FAFB}
.FTA.filled{padding:6px 8px;font-size:9px;color:#333;line-height:1.4}
.FI.err{border-color:#DC2626;background:#FFF5F5}
.ferr{font-size:8px;color:#DC2626;margin-top:2px}
.SH{font-size:8px;font-weight:800;color:#AAA;text-transform:uppercase;letter-spacing:1.5px;padding:10px 0 6px;border-top:1px solid #F0EDE6;margin-top:4px}
.SH:first-child{border-top:none;margin-top:0;padding-top:0}
.CH{display:inline-flex;align-items:center;font-size:7.5px;font-weight:800;padding:2px 6px;border-radius:10px;text-transform:uppercase;letter-spacing:.3px}
.CH+.CH{margin-left:3px}
.CH-blue{background:#DBEAFE;color:#1E40AF;border:1px solid #BFDBFE}
.CH-red{background:#FEE2E2;color:#991B1B;border:1px solid #FCA5A5}
.CH-green{background:#DCFCE7;color:#166534;border:1px solid #BBF7D0}
.CH-grey{background:#F3F4F6;color:#374151;border:1px solid #E5E7EB}
.CH-warn{background:#FEF3C7;color:#92400E;border:1px solid #FDE68A}
.CH-amber{background:#FEF9C3;color:#854D0E;border:1px solid #FEF08A}
.CH-navy{background:#EEF2FF;color:#002850;border:1px solid #C7D2FE}
.CH-mint{background:#D6F0EE;color:#0F5B58;border:1px solid #A6DAD8}
.AL{padding:8px 10px;border-radius:5px;font-size:9px;line-height:1.5}
.AL-warn{background:#FFFBEB;border:1px solid #FDE68A;color:#92400E}
.AL-info{background:#EFF6FF;border:1px solid #BFDBFE;color:#1E40AF}
.AL-err{background:#FEF2F2;border:1px solid #FCA5A5;color:#991B1B}
.AL-ok{background:#F0FDF4;border:1px solid #BBF7D0;color:#166534}
.DZ{border:1.5px solid #FCA5A5;border-radius:6px;padding:12px 14px;margin-top:4px;background:#FFF5F5}
.DZ-title{font-size:10px;font-weight:800;color:#991B1B;margin-bottom:4px;display:flex;align-items:center;gap:5px}
.DZ-desc{font-size:8.5px;color:#777;line-height:1.5;margin-bottom:8px}
.DZ-confirm{background:#FEE2E2;border:1.5px solid #FCA5A5;border-radius:4px;padding:8px 10px;margin-top:6px}
.DZ-confirm-msg{font-size:9px;color:#7F1D1D;font-weight:600;margin-bottom:6px}
.SC{border:1.5px solid #E8E4DF;border-radius:6px;padding:12px 14px;margin-bottom:10px}
.SC.warn{border-color:#FDE68A;background:#FFFBEB}
.SC.danger{border-color:#FCA5A5;background:#FFF5F5}
.SC-title{font-size:11px;font-weight:800;color:#1A1A1A;margin-bottom:3px;display:flex;align-items:center;gap:6px}
.SC-badge{font-size:7.5px;padding:1px 5px;border-radius:3px;font-weight:800;text-transform:uppercase}
.SC.warn .SC-badge{background:#FDE68A;color:#92400E}
.SC.danger .SC-badge{background:#FCA5A5;color:#7F1D1D}
.SC-desc{font-size:8.5px;color:#777;line-height:1.5;margin-bottom:10px}
.IB{width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:5px;font-size:13px;border:1px solid #E8E4DF;background:#fff;color:#666;cursor:pointer}
.IB.edit{color:#2563EB;border-color:#BFDBFE;background:#EFF6FF}
.IB.del{color:#DC2626;border-color:#FCA5A5;background:#FEF2F2}
.DECISION{background:#F0F7FF;border:1.5px solid #BFDBFE;border-radius:8px;padding:14px 16px;margin:16px 0}
.DECISION-title{font-size:10px;font-weight:800;color:#1E40AF;text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px;display:flex;align-items:center;gap:6px}
.DECISION ul{display:flex;flex-direction:column;gap:4px;padding-left:0}
.DECISION li{font-size:11px;color:#1E3A5F;line-height:1.5;list-style:none;padding-left:14px;position:relative}
.DECISION li::before{content:'→';position:absolute;left:0;color:#60A5FA}
.SPEC{background:#fff;border:1px solid #E8E4DF;border-radius:8px;padding:16px;margin-top:16px}
.SPEC-title{font-size:10px;font-weight:800;color:#555;text-transform:uppercase;letter-spacing:1px;margin-bottom:10px}
.SPEC-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.SPEC-col{}
.SPEC-rule{margin-bottom:8px}
.SPEC-rule-num{font-size:9px;font-weight:800;color:#002850;margin-bottom:2px}
.SPEC-rule-text{font-size:11px;color:#444;line-height:1.5}
.SPEC-rule-code{font-size:10px;font-family:monospace;background:#F3F4F6;padding:1px 4px;border-radius:2px;color:#1A1A1A}
.BP-table{width:100%;border-collapse:collapse;font-size:11px;margin-top:8px}
.BP-table th{text-align:left;padding:8px 12px;font-size:10px;font-weight:800;color:#888;text-transform:uppercase;letter-spacing:.5px;border-bottom:2px solid #E8E4DF;background:#F7F5F2}
.BP-table td{padding:8px 12px;border-bottom:1px solid #F0EDE6;color:#444;vertical-align:top}
.BP-table tr:last-child td{border-bottom:none}
.BP-table code{font-size:10px;font-family:monospace;background:#F3F4F6;padding:1px 4px;border-radius:2px}
.SUM-table{width:100%;border-collapse:collapse;font-size:11px}
.SUM-table th{text-align:left;padding:9px 14px;font-size:10px;font-weight:800;color:#888;text-transform:uppercase;letter-spacing:.5px;border-bottom:2px solid #E8E4DF;background:#F7F5F2}
.SUM-table td{padding:8px 14px;border-bottom:1px solid #F0EDE6;color:#444;vertical-align:middle}
.SUM-table tr:nth-child(even) td{background:#FAFAF7}
.PH{height:8px;background:#E8E4DF;border-radius:3px;margin-bottom:5px}
.PH.w30{width:30%}.PH.w50{width:50%}.PH.w70{width:70%}.PH.w40{width:40%}.PH.w60{width:60%}
.URL-LINE{background:#F0EDE8;border:1px solid #DDD8D0;border-radius:4px;padding:4px 10px;font-size:9px;font-family:monospace;color:#555;margin-bottom:8px}
.URL-LINE span.qs{color:#1D4ED8}
.DECISION{background:#F0F7FF;border:1.5px solid #BFDBFE;border-radius:8px;padding:14px 16px;margin:16px 0}
.mobile-flow{display:flex;gap:12px;align-items:flex-start;flex-wrap:wrap}
.mobile-step{display:flex;flex-direction:column;align-items:center;gap:4px}
.mobile-step-label{font-size:8px;color:#888;font-style:italic;text-align:center}
.mobile-arrow{font-size:20px;color:#CCC;align-self:center;margin-top:36px}
.wf-m{background:#fff;border:2px solid #B8B4AE;border-radius:10px;overflow:hidden;box-shadow:0 4px 16px rgba(0,0,0,.08);position:relative;width:155px}
code{font-size:10px;font-family:monospace;background:#F3F4F6;padding:1px 4px;border-radius:2px;color:#1A1A1A}
/* ── Persons-specific ── */
.MAIN{flex:1;padding:16px 20px;overflow:hidden;display:flex;flex-direction:column;gap:12px;min-width:0}
.MAIN-wide{flex:1;padding:20px 28px;overflow:hidden;display:flex;flex-direction:column;gap:14px;min-width:0}
/* Stats bar */
.STATS-BAR{display:flex;align-items:center;gap:16px;padding:8px 0 4px}
.STATS-BAR-item{display:flex;align-items:baseline;gap:5px}
.STATS-BAR-val{font-size:15px;font-weight:900;color:#002850;line-height:1}
.STATS-BAR-label{font-size:8px;color:#AAA;text-transform:uppercase;letter-spacing:.5px}
.STATS-BAR-sep{font-size:12px;color:#D1D5DB;font-weight:300}
/* Person grid */
.PERSON-GRID{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
.PERSON-GRID-2{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
/* Person card in grid */
.PG-card{background:#fff;border:1.5px solid #E8E4DF;border-radius:8px;padding:14px 12px;display:flex;flex-direction:column;align-items:center;gap:7px;cursor:pointer;position:relative;transition:box-shadow .15s}
.PG-card:hover{box-shadow:0 2px 12px rgba(0,0,0,.09);border-color:#A6DAD8;border-left:3px solid #A6DAD8}
.PG-initials{width:48px;height:48px;background:#002850;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:800;color:#fff;flex-shrink:0;font-family:Georgia,serif}
.PG-name{font-size:10px;font-weight:700;color:#1A1A1A;text-align:center;font-family:Georgia,serif}
.PG-alias{font-size:8.5px;color:#888;font-style:italic;text-align:center}
.PG-dates{font-size:8px;color:#AAA;text-align:center}
.PG-doccount{font-size:7.5px;background:#F3F4F6;border:1px solid #E5E7EB;border-radius:10px;padding:2px 7px;color:#666}
/* Detail layout */
.DETAIL-LAYOUT{display:grid;grid-template-columns:35fr 65fr;gap:20px;align-items:start}
.DETAIL-LAYOUT-stacked{display:flex;flex-direction:column;gap:16px}
/* Person card (detail sidebar) */
.PERSON-CARD{background:#fff;border:1.5px solid #E8E4DF;border-radius:8px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,.05)}
.PERSON-CARD-topbar{height:4px;background:#002850}
.PERSON-CARD-body{padding:20px 16px}
.PC-avatar{width:64px;height:64px;background:#002850;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:20px;font-weight:800;color:#fff;font-family:Georgia,serif;margin:0 auto 12px}
.PC-avatar-lg{width:80px;height:80px;font-size:26px}
.PC-name{font-size:15px;font-weight:800;color:#0D2240;text-align:center;font-family:Georgia,serif;line-height:1.3;margin-bottom:3px}
.PC-alias{font-size:10px;color:#888;font-style:italic;text-align:center;margin-bottom:6px}
.PC-dates{font-size:9px;color:#666;text-align:center;margin-bottom:10px}
.PC-notes-label{font-size:7.5px;font-weight:800;color:#AAA;text-transform:uppercase;letter-spacing:1px;margin-bottom:3px}
.PC-notes{font-size:9px;color:#555;line-height:1.5;background:#F9FAFB;border-radius:4px;padding:8px;border:1px solid #F0EDE6;margin-bottom:12px}
/* Activity area */
.ACTIVITY{display:flex;flex-direction:column;gap:14px}
.ACT-section{background:#fff;border:1.5px solid #E8E4DF;border-radius:8px;padding:14px 16px}
.ACT-section-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}
.ACT-title{font-size:8px;font-weight:800;color:#AAA;text-transform:uppercase;letter-spacing:1.5px}
.ACT-badge{font-size:8px;font-weight:800;background:#EEF2FF;color:#002850;border-radius:10px;padding:1px 7px}
/* Document row */
.DOC-ROW{display:flex;align-items:center;gap:8px;padding:7px 0;border-bottom:1px solid #F0EDE6}
.DOC-ROW:last-child{border-bottom:none}
.DOC-ROW-icon{width:22px;height:26px;background:#E8E4DF;border-radius:3px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:9px;color:#888}
.DOC-ROW-icon.sent{background:#EEF2FF;color:#002850}
.DOC-ROW-icon.recv{background:#D6F0EE;color:#0F5B58}
.DOC-ROW-title{font-size:9px;font-weight:600;color:#1A1A1A;flex:1;line-height:1.3}
.DOC-ROW-meta{font-size:8px;color:#AAA;flex-shrink:0}
.DOC-ROW-status{}
/* Correspondent chip */
.CORR-chip{display:inline-flex;align-items:center;gap:5px;background:#F7F5F2;border:1px solid #E0DDD6;border-radius:20px;padding:4px 10px;font-size:8.5px;font-weight:700;color:#333;cursor:pointer}
.CORR-chip:hover{background:#EEF2FF;border-color:#A6DAD8}
.CORR-av{width:16px;height:16px;background:#002850;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:5.5px;color:#fff;font-weight:800;font-family:Georgia,serif;flex-shrink:0}
.CORR-count{font-size:7.5px;color:#999}
/* Sticky save bar */
.SAVE-BAR{background:#fff;border-top:1.5px solid #E8E4DF;padding:10px 20px;display:flex;align-items:center;justify-content:space-between;box-shadow:0 -2px 8px rgba(0,0,0,.06);flex-shrink:0}
/* Back link */
.BACK-LINK{font-size:8px;font-weight:800;color:#888;text-transform:uppercase;letter-spacing:.5px;display:inline-flex;align-items:center;gap:5px;margin-bottom:10px;cursor:pointer}
.BACK-LINK:hover{color:#002850}
.BACK-ARROW{font-size:11px}
/* Empty dashed box */
.EMPTY-BOX{border:2px dashed #D1D5DB;border-radius:8px;padding:28px 16px;text-align:center;display:flex;flex-direction:column;align-items:center;gap:8px}
.EMPTY-ICON{font-size:28px;opacity:.2}
.EMPTY-MSG{font-size:10px;color:#AAA;line-height:1.5}
.EMPTY-CTA{font-size:8px;font-weight:800;background:#002850;color:#fff;padding:5px 12px;border-radius:4px;text-transform:uppercase;letter-spacing:.5px;cursor:pointer;margin-top:4px}
/* Danger zone accordion */
.DZ-ACCORD{border:1.5px solid #FCA5A5;border-radius:6px;overflow:hidden;margin-top:16px}
.DZ-ACCORD-head{padding:10px 14px;background:#FFF5F5;display:flex;align-items:center;justify-content:space-between;cursor:pointer}
.DZ-ACCORD-label{font-size:9px;font-weight:800;color:#991B1B;text-transform:uppercase;letter-spacing:.5px;display:flex;align-items:center;gap:6px}
.DZ-ACCORD-chev{font-size:11px;color:#FCA5A5}
.DZ-ACCORD-body{border-top:1px solid #FCA5A5;padding:12px 14px;background:#fff}
.DZ-ACCORD-desc{font-size:8.5px;color:#777;line-height:1.5;margin-bottom:10px}
/* Search result count */
.RESULT-COUNT{font-size:9px;color:#888;font-style:italic}
/* Page heading area */
.PAGE-HDR{display:flex;align-items:flex-start;justify-content:space-between;flex-wrap:wrap;gap:8px}
.PAGE-TITLE{font-size:14px;font-weight:800;color:#0D2240}
.PAGE-SUB{font-size:9px;color:#999;margin-top:2px}
.FORM-CARD{background:#fff;border:1.5px solid #E8E4DF;border-radius:8px;padding:16px 18px;margin-bottom:14px}
.FORM-CARD-title{font-size:8px;font-weight:800;color:#AAA;text-transform:uppercase;letter-spacing:1.5px;margin-bottom:12px}
/* Section divider */
.SEC-DIV{border:none;border-top:1px solid #F0EDE6;margin:10px 0}
/* Show more link */
.SHOW-MORE{font-size:8.5px;color:#002850;font-weight:700;text-align:center;padding:6px 0;cursor:pointer;display:block;border-top:1px solid #F0EDE6;margin-top:2px}
.SHOW-MORE:hover{color:#1D4ED8}
/* Sort toggle */
.SORT-TOGGLE{font-size:7.5px;color:#888;font-weight:700;background:#F3F4F6;border:1px solid #E5E7EB;border-radius:3px;padding:1px 5px;cursor:pointer}
/* Unsaved banner */
.UNSAVED-BANNER{background:#FFFBEB;border:1.5px solid #FDE68A;border-radius:6px;padding:8px 12px;display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px}
.UNSAVED-MSG{font-size:9px;color:#92400E;font-weight:600}
/* Save error banner */
.ERR-BANNER{background:#FEF2F2;border:1.5px solid #FCA5A5;border-radius:6px;padding:8px 12px;margin-bottom:10px}
.ERR-BANNER-msg{font-size:9px;color:#991B1B;font-weight:600}
/* Typeahead field */
.TYPEAHEAD{position:relative}
.TYPEAHEAD-INPUT{width:100%;height:26px;border:1.5px solid #D1D5DB;border-radius:4px;background:#F9FAFB;display:flex;align-items:center;padding:0 8px;font-size:9px;color:#AAA;font-style:italic}
.TYPEAHEAD-INPUT.focus{border-color:#002850}
</style>
</head>
<body>
<div class="doc">
<!-- HEADER -->
<div class="doc-masthead">
<h1>Persons Section — Concept A: Enriched Directory</h1>
<p>Complete developer-ready screen spec for the Persons section redesign. Covers the person list, detail view (2-column layout), edit form (dedicated route), new person form, and all edge cases. Every screen, state, and entity is specified. A developer should be able to implement the full feature from this spec alone.</p>
<div class="meta">Familienarchiv · Persons Spec · Concept A · v1.0 · 2026-03</div>
</div>
<!-- S0 ARCHITECTURE -->
<div class="section">
<div class="sec-intro">
<div class="sec-num">0</div>
<div class="sec-meta">
<span class="sec-badge badge-arch">Architecture</span>
<div class="sec-title">Routes, Layout Model & Breakpoints</div>
<div class="sec-tagline">Four routes. 2-column detail layout on desktop. Dedicated edit route with sticky save bar. Merge panel hidden in Danger Zone accordion.</div>
</div>
</div>
<div class="screens cols2" style="margin-bottom:24px">
<div class="screen-block">
<div class="screen-label">Route map</div>
<div style="background:#fff;border:1px solid #E8E4DF;border-radius:8px;overflow:hidden">
<table class="SUM-table">
<thead><tr><th>Route</th><th>Purpose</th><th>Key state</th></tr></thead>
<tbody>
<tr><td><code>/persons</code></td><td>Person directory — 4-column grid, search, stats bar</td><td>search query param</td></tr>
<tr><td><code>/persons/new</code></td><td>Create new person — all 6 fields</td><td>form validation</td></tr>
<tr><td><code>/persons/[id]</code></td><td>Person detail — 2-col layout, activity area</td><td>person id in path</td></tr>
<tr><td><code>/persons/[id]/edit</code></td><td>Edit form — sticky save bar, Danger Zone accordion</td><td>dirty state, merge</td></tr>
</tbody>
</table>
</div>
</div>
<div class="screen-block">
<div class="screen-label">Breakpoint behaviour</div>
<div style="background:#fff;border:1px solid #E8E4DF;border-radius:8px;overflow:hidden">
<table class="BP-table">
<thead><tr><th>Viewport</th><th>List layout</th><th>Detail layout</th><th>Edit layout</th></tr></thead>
<tbody>
<tr><td><code>&lt;640px</code> Mobile</td><td>1-col list</td><td>Stacked single col</td><td>Full-page form</td></tr>
<tr><td><code>6401023px</code> Tablet</td><td>2-col grid</td><td>Stacked single col</td><td>Full-page form</td></tr>
<tr><td><code>≥1024px</code> Desktop</td><td>4-col grid</td><td>2-col sidebar+main</td><td>Full-page form</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Layout diagram -->
<div class="screens" style="margin-bottom:24px">
<div class="screen-block" style="flex:1">
<div class="screen-label">2-column detail layout anatomy <span class="sz">≥1024px</span></div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV">
<div class="logo">FAMILIENARCHIV</div>
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
</div>
<div class="MAIN-wide" style="height:300px">
<div class="BACK-LINK"><span class="BACK-ARROW"></span> Back to overview</div>
<div style="display:grid;grid-template-columns:35fr 65fr;gap:20px;align-items:start">
<!-- Sidebar annotation -->
<div style="position:relative">
<div style="position:absolute;top:-20px;left:0;right:0;text-align:center;font-size:8px;font-weight:800;color:#1D4ED8;background:#E3EEFF;border-radius:3px;padding:2px 4px">PERSON CARD · 35%</div>
<div class="PERSON-CARD">
<div class="PERSON-CARD-topbar"></div>
<div class="PERSON-CARD-body">
<div class="PC-avatar">OF</div>
<div class="PC-name">Otto Fischer</div>
<div class="PC-alias">„Großvater Otto"</div>
<div class="PC-dates">✦ 1882 &nbsp;&nbsp; 1944</div>
<div style="margin-top:8px">
<div class="PC-notes-label">Notes</div>
<div class="PC-notes">Patriarchal figure of the Fischer family…</div>
</div>
<div style="text-align:center"><div class="BTN BTN-outline BTN-sm" style="width:100%;justify-content:center">Edit person</div></div>
</div>
</div>
</div>
<!-- Activity annotation -->
<div style="position:relative">
<div style="position:absolute;top:-20px;left:0;right:0;text-align:center;font-size:8px;font-weight:800;color:#B45309;background:#FEF3C7;border-radius:3px;padding:2px 4px">ACTIVITY AREA · 65%</div>
<div class="ACTIVITY">
<div class="ACT-section">
<div class="ACT-section-head"><div class="ACT-title">Frequent Correspondents</div></div>
<div style="display:flex;gap:6px;flex-wrap:wrap">
<div class="CORR-chip"><div class="CORR-av">HM</div>Hans Müller <span class="CORR-count">×4</span></div>
<div class="CORR-chip"><div class="CORR-av">AS</div>Anna Schmidt <span class="CORR-count">×2</span></div>
</div>
</div>
<div class="ACT-section" style="padding-bottom:6px">
<div class="ACT-section-head"><div class="ACT-title">Sent Documents</div><div class="ACT-badge">5</div></div>
<div class="DOC-ROW"><div class="DOC-ROW-icon sent"></div><div class="DOC-ROW-title">Brief an den König</div><div class="DOC-ROW-meta">12 Nov 1938</div><div class="CH CH-navy" style="font-size:7px;margin-left:5px">Uploaded</div></div>
<div class="DOC-ROW"><div class="DOC-ROW-icon sent"></div><div class="DOC-ROW-title">Grundbucheintrag Hof Fischer</div><div class="DOC-ROW-meta">3 Mar 1922</div><div class="CH CH-green" style="font-size:7px;margin-left:5px">Archived</div></div>
<div class="SHOW-MORE">Show 3 more…</div>
</div>
<div class="ACT-section">
<div class="ACT-section-head"><div class="ACT-title">Received Documents</div><div class="ACT-badge">3</div></div>
<div class="DOC-ROW"><div class="DOC-ROW-icon recv"></div><div class="DOC-ROW-title">Scan ohne Titel</div><div class="DOC-ROW-meta">25 Nov 1938</div><div class="CH CH-warn" style="font-size:7px;margin-left:5px">Scan pending</div></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="DECISION">
<div class="DECISION-title">📐 Key design decisions</div>
<ul>
<li>Edit moved to <code>/persons/[id]/edit</code> — removes in-place toggle; PersonCard is view-only; edit state no longer lives in $state on the detail page.</li>
<li>Merge panel moved inside a collapsible Danger Zone accordion at the bottom of the edit page — reduces cognitive load on the detail view.</li>
<li>"Full Name" label removed from view mode — the &lt;h1&gt; / PC-name already shows the name; duplicate removed per audit finding.</li>
<li>Stats bar on list page: <code>persons.length</code> + <code>totalDocs</code> — requires <code>documentCount</code> field on PersonDTO (or computed client-side from separate query).</li>
<li>New person form gains birth year, death year, notes — brings parity with edit form.</li>
</ul>
</div>
</div>
<!-- S1 PERSON LIST -->
<div class="section">
<div class="sec-intro">
<div class="sec-num">1</div>
<div class="sec-meta">
<span class="sec-badge badge-persons">List</span>
<div class="sec-title">Person Directory <code style="font-size:14px">/persons</code></div>
<div class="sec-tagline">4-column card grid on desktop. Stats bar. Search. Each card shows initials circle, full name, alias, life dates, doc count chip. Hover: mint left-border + shadow.</div>
</div>
</div>
<!-- 1A Desktop full list -->
<div class="screens" style="margin-bottom:24px">
<div class="screen-block" style="flex:1">
<div class="screen-label">1-A · Desktop full list <span class="sz">1440px</span> <span class="state-tag">default</span></div>
<div class="URL-LINE">/persons</div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV">
<div class="logo">FAMILIENARCHIV</div>
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
</div>
<div class="MAIN-wide">
<!-- Header row -->
<div class="PAGE-HDR">
<div>
<div class="PAGE-TITLE">Persons</div>
<div class="STATS-BAR">
<div class="STATS-BAR-item"><div class="STATS-BAR-val">4</div><div class="STATS-BAR-label">Persons</div></div>
<div class="STATS-BAR-sep">·</div>
<div class="STATS-BAR-item"><div class="STATS-BAR-val">14</div><div class="STATS-BAR-label">Documents</div></div>
</div>
</div>
<div style="display:flex;align-items:center;gap:10px">
<div style="width:180px;height:28px;border:1.5px solid #D1D5DB;border-radius:4px;background:#F9FAFB;display:flex;align-items:center;padding:0 8px;font-size:9px;color:#AAA;font-style:italic;gap:4px">🔍 Search persons…</div>
<div class="BTN BTN-primary">+ New person</div>
</div>
</div>
<!-- Grid -->
<div class="PERSON-GRID" style="padding-bottom:16px">
<!-- Card 1 - Otto Fischer -->
<div class="PG-card" style="border-left:3px solid #A6DAD8;box-shadow:0 2px 12px rgba(0,0,0,.09)">
<div class="PG-initials">OF</div>
<div class="PG-name">Otto Fischer</div>
<div class="PG-alias">„Großvater Otto"</div>
<div class="PG-dates">✦ 1882 · † 1944</div>
<div class="PG-doccount">8 docs</div>
</div>
<!-- Card 2 - Hans Müller -->
<div class="PG-card">
<div class="PG-initials">HM</div>
<div class="PG-name">Hans Müller</div>
<div class="PG-dates">✦ 1890 · † 1962</div>
<div class="PG-doccount">2 docs</div>
</div>
<!-- Card 3 - Anna Schmidt -->
<div class="PG-card">
<div class="PG-initials">AS</div>
<div class="PG-name">Anna Schmidt</div>
<div class="PG-alias">„Oma Anna"</div>
<div class="PG-dates">✦ 1905</div>
<div class="PG-doccount">8 docs</div>
</div>
<!-- Card 4 - Maria Weber -->
<div class="PG-card">
<div class="PG-initials">MW</div>
<div class="PG-name">Maria Weber</div>
<div class="PG-dates" style="color:#D1D5DB;font-style:italic">no dates</div>
<div class="PG-doccount">1 doc</div>
</div>
</div>
</div>
</div>
<div class="screen-cap">Card 1 shown in hover state (mint left border + shadow). No alias shown for Hans Müller and Maria Weber — those fields are simply omitted when empty. "no dates" placeholder shown in muted italic when both fields absent.</div>
</div>
</div>
<!-- 1B Tablet + Mobile side by side -->
<div class="screens cols2" style="margin-bottom:24px">
<div class="screen-block">
<div class="screen-label">1-B · Tablet <span class="sz">768px</span></div>
<div class="URL-LINE">/persons</div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV-m">
<div class="logo">FAMILIENARCHIV</div>
<div class="nr"><div class="nico"></div><div class="nico"></div></div>
</div>
<div class="MAIN">
<div class="PAGE-HDR">
<div>
<div class="PAGE-TITLE" style="font-size:12px">Persons</div>
<div class="STATS-BAR" style="gap:10px">
<div class="STATS-BAR-item"><div class="STATS-BAR-val" style="font-size:13px">4</div><div class="STATS-BAR-label">Persons</div></div>
<div class="STATS-BAR-sep">·</div>
<div class="STATS-BAR-item"><div class="STATS-BAR-val" style="font-size:13px">14</div><div class="STATS-BAR-label">Docs</div></div>
</div>
</div>
<div class="BTN BTN-primary BTN-sm">+ New</div>
</div>
<div style="height:26px;border:1.5px solid #D1D5DB;border-radius:4px;background:#F9FAFB;display:flex;align-items:center;padding:0 8px;font-size:9px;color:#AAA;font-style:italic;gap:4px;margin-bottom:10px">🔍 Search persons…</div>
<div class="PERSON-GRID-2">
<div class="PG-card">
<div class="PG-initials">OF</div>
<div class="PG-name">Otto Fischer</div>
<div class="PG-alias">„Großvater Otto"</div>
<div class="PG-dates">✦ 1882 · † 1944</div>
<div class="PG-doccount">8 docs</div>
</div>
<div class="PG-card">
<div class="PG-initials">HM</div>
<div class="PG-name">Hans Müller</div>
<div class="PG-dates">✦ 1890 · † 1962</div>
<div class="PG-doccount">2 docs</div>
</div>
<div class="PG-card">
<div class="PG-initials">AS</div>
<div class="PG-name">Anna Schmidt</div>
<div class="PG-alias">„Oma Anna"</div>
<div class="PG-dates">✦ 1905</div>
<div class="PG-doccount">8 docs</div>
</div>
<div class="PG-card">
<div class="PG-initials">MW</div>
<div class="PG-name">Maria Weber</div>
<div class="PG-dates" style="color:#D1D5DB;font-style:italic">no dates</div>
<div class="PG-doccount">1 doc</div>
</div>
</div>
</div>
</div>
</div>
<div class="screen-block">
<div class="screen-label">1-C · Mobile <span class="sz">375px</span></div>
<div class="URL-LINE">/persons</div>
<div class="wf" style="max-width:260px">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV-m">
<div class="logo" style="font-size:8px">FAMILIENARCHIV</div>
<div class="nico"></div>
</div>
<div class="MAIN" style="padding:12px">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px">
<div>
<div class="PAGE-TITLE" style="font-size:11px">Persons</div>
<div style="font-size:8px;color:#AAA;margin-top:1px">4 persons · 14 docs</div>
</div>
<div class="BTN BTN-primary BTN-xs">+ New</div>
</div>
<div style="height:24px;border:1.5px solid #D1D5DB;border-radius:4px;background:#F9FAFB;display:flex;align-items:center;padding:0 8px;font-size:8px;color:#AAA;font-style:italic;gap:4px;margin-bottom:8px">🔍 Search…</div>
<!-- Mobile: 1-col list style cards -->
<div style="display:flex;flex-direction:column;gap:6px">
<div style="background:#fff;border:1.5px solid #E8E4DF;border-radius:6px;padding:10px 12px;display:flex;align-items:center;gap:10px;cursor:pointer">
<div class="PG-initials" style="width:36px;height:36px;font-size:11px;flex-shrink:0">OF</div>
<div style="flex:1;min-width:0">
<div class="PG-name" style="text-align:left">Otto Fischer</div>
<div class="PG-alias" style="text-align:left;margin-top:1px">„Großvater Otto"</div>
<div style="display:flex;gap:8px;margin-top:2px">
<div class="PG-dates" style="text-align:left">✦ 1882 · † 1944</div>
<div class="PG-doccount">8 docs</div>
</div>
</div>
<div style="font-size:12px;color:#CCC"></div>
</div>
<div style="background:#fff;border:1.5px solid #E8E4DF;border-radius:6px;padding:10px 12px;display:flex;align-items:center;gap:10px;cursor:pointer">
<div class="PG-initials" style="width:36px;height:36px;font-size:11px;flex-shrink:0">HM</div>
<div style="flex:1;min-width:0">
<div class="PG-name" style="text-align:left">Hans Müller</div>
<div style="display:flex;gap:8px;margin-top:2px">
<div class="PG-dates" style="text-align:left">✦ 1890 · † 1962</div>
<div class="PG-doccount">2 docs</div>
</div>
</div>
<div style="font-size:12px;color:#CCC"></div>
</div>
<div style="background:#fff;border:1.5px solid #E8E4DF;border-radius:6px;padding:10px 12px;display:flex;align-items:center;gap:10px;cursor:pointer">
<div class="PG-initials" style="width:36px;height:36px;font-size:11px;flex-shrink:0">AS</div>
<div style="flex:1;min-width:0">
<div class="PG-name" style="text-align:left">Anna Schmidt</div>
<div class="PG-alias" style="text-align:left;margin-top:1px">„Oma Anna"</div>
<div style="display:flex;gap:8px;margin-top:2px">
<div class="PG-dates" style="text-align:left">✦ 1905</div>
<div class="PG-doccount">8 docs</div>
</div>
</div>
<div style="font-size:12px;color:#CCC"></div>
</div>
<div style="background:#fff;border:1.5px solid #E8E4DF;border-radius:6px;padding:10px 12px;display:flex;align-items:center;gap:10px;cursor:pointer">
<div class="PG-initials" style="width:36px;height:36px;font-size:11px;flex-shrink:0">MW</div>
<div style="flex:1;min-width:0">
<div class="PG-name" style="text-align:left">Maria Weber</div>
<div style="display:flex;gap:8px;margin-top:2px">
<div class="PG-doccount">1 doc</div>
</div>
</div>
<div style="font-size:12px;color:#CCC"></div>
</div>
</div>
</div>
</div>
<div class="screen-cap">Mobile: cards switch to horizontal row layout (initials left, text right, chevron right). Touch-friendly min-height. No centered text.</div>
</div>
</div>
<!-- 1D Empty state + 1E Search -->
<div class="screens cols2" style="margin-bottom:16px">
<div class="screen-block">
<div class="screen-label">1-D · Empty state <span class="sz">desktop</span> <span class="state-tag empty">empty</span></div>
<div class="URL-LINE">/persons</div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV">
<div class="logo">FAMILIENARCHIV</div>
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
</div>
<div class="MAIN-wide">
<div class="PAGE-HDR" style="margin-bottom:20px">
<div>
<div class="PAGE-TITLE">Persons</div>
<div style="font-size:9px;color:#AAA;margin-top:2px">0 persons · 0 documents</div>
</div>
<div class="BTN BTN-primary">+ New person</div>
</div>
<div class="EMPTY-BOX" style="padding:48px 24px">
<div class="EMPTY-ICON">👤</div>
<div style="font-size:13px;font-weight:700;color:#CCC">No persons yet</div>
<div class="EMPTY-MSG">Add the first family member to begin building the archive's person directory.</div>
<div class="EMPTY-CTA">Add the first family member</div>
</div>
</div>
</div>
</div>
<div class="screen-block">
<div class="screen-label">1-E · Search results <span class="sz">desktop</span> <span class="state-tag">filtered</span></div>
<div class="URL-LINE">/persons<span class="qs">?q=Fischer</span></div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV">
<div class="logo">FAMILIENARCHIV</div>
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
</div>
<div class="MAIN-wide">
<div class="PAGE-HDR" style="margin-bottom:8px">
<div>
<div class="PAGE-TITLE">Persons</div>
</div>
<div style="display:flex;align-items:center;gap:10px">
<div style="width:180px;height:28px;border:1.5px solid #002850;border-radius:4px;background:#fff;box-shadow:0 0 0 3px rgba(0,40,80,.07);display:flex;align-items:center;padding:0 8px;font-size:9px;color:#333;gap:4px">🔍 Fischer</div>
<div class="BTN BTN-primary">+ New person</div>
</div>
</div>
<div style="font-size:9px;color:#888;margin-bottom:12px;font-style:italic">1 result for "Fischer" <span style="font-size:8px;color:#AAA;margin-left:8px;cursor:pointer">Clear ×</span></div>
<div class="PERSON-GRID">
<div class="PG-card">
<div class="PG-initials">OF</div>
<div class="PG-name">Otto Fischer</div>
<div class="PG-alias">„Großvater Otto"</div>
<div class="PG-dates">✦ 1882 · † 1944</div>
<div class="PG-doccount">8 docs</div>
</div>
</div>
</div>
</div>
<div class="screen-cap">Search filters by first name, last name, or alias. Result count shown below header. "Clear ×" resets query param. Search box has focus ring when active.</div>
</div>
</div>
</div>
<!-- S2 PERSON DETAIL -->
<div class="section">
<div class="sec-intro">
<div class="sec-num">2</div>
<div class="sec-meta">
<span class="sec-badge badge-persons">Detail</span>
<div class="sec-title">Person Detail <code style="font-size:14px">/persons/[id]</code></div>
<div class="sec-tagline">2-column layout on desktop. Left sidebar: Person Card (35%). Right: Activity Area — Frequent Correspondents, Sent Documents, Received Documents (65%). Stacked on tablet/mobile.</div>
</div>
</div>
<!-- 2A Desktop full detail -->
<div class="screens" style="margin-bottom:24px">
<div class="screen-block" style="flex:1">
<div class="screen-label">2-A · Desktop detail — Otto Fischer <span class="sz">1440px</span> <span class="state-tag">view</span></div>
<div class="URL-LINE">/persons/a1b2c3d4</div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV">
<div class="logo">FAMILIENARCHIV</div>
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
</div>
<div class="MAIN-wide">
<div class="BACK-LINK"><span class="BACK-ARROW"></span> Back to overview</div>
<!-- 2-col layout -->
<div class="DETAIL-LAYOUT">
<!-- Left: Person Card -->
<div>
<div class="PERSON-CARD">
<div class="PERSON-CARD-topbar"></div>
<div class="PERSON-CARD-body">
<div class="PC-avatar PC-avatar-lg">OF</div>
<div class="PC-name">Otto Fischer</div>
<div class="PC-alias">„Großvater Otto"</div>
<div class="PC-dates">✦ 1882 &nbsp;·&nbsp; † 1944</div>
<hr class="SEC-DIV">
<div class="PC-notes-label">Notes</div>
<div class="PC-notes">Patriarchal figure of the Fischer family. Farmer from Baden-Württemberg. Married to Helene Fischer (née Braun).</div>
<div class="BTN BTN-outline BTN-sm" style="width:100%;justify-content:center;margin-top:4px">✏ Edit person</div>
</div>
</div>
</div>
<!-- Right: Activity -->
<div class="ACTIVITY">
<!-- Frequent Correspondents -->
<div class="ACT-section">
<div class="ACT-section-head">
<div class="ACT-title">Frequent Correspondents</div>
<div style="font-size:8px;color:#AAA;font-style:italic">(click to view conversation)</div>
</div>
<div style="display:flex;gap:6px;flex-wrap:wrap">
<div class="CORR-chip" title="Click to view conversation">
<div class="CORR-av">HM</div>
Hans Müller
<span class="CORR-count">×4</span>
<span style="font-size:9px;margin-left:2px">💬</span>
</div>
<div class="CORR-chip" title="Click to view conversation">
<div class="CORR-av">AS</div>
Anna Schmidt
<span class="CORR-count">×2</span>
<span style="font-size:9px;margin-left:2px">💬</span>
</div>
</div>
</div>
<!-- Sent Documents -->
<div class="ACT-section" style="padding-bottom:0">
<div class="ACT-section-head">
<div class="ACT-title">Sent Documents</div>
<div style="display:flex;align-items:center;gap:6px">
<div class="ACT-badge">5</div>
<div class="SORT-TOGGLE">Date ▾</div>
</div>
</div>
<div class="DOC-ROW">
<div class="DOC-ROW-icon sent"></div>
<div>
<div class="DOC-ROW-title">Brief an den König</div>
<div style="font-size:8px;color:#AAA;margin-top:1px">Berlin · 12 Nov 1938</div>
</div>
<div style="margin-left:auto"><div class="CH CH-navy" style="font-size:7px">Uploaded</div></div>
</div>
<div class="DOC-ROW">
<div class="DOC-ROW-icon sent"></div>
<div>
<div class="DOC-ROW-title">Grundbucheintrag Hof Fischer</div>
<div style="font-size:8px;color:#AAA;margin-top:1px">Freiburg · 3 Mar 1922</div>
</div>
<div style="margin-left:auto"><div class="CH CH-green" style="font-size:7px">Archived</div></div>
</div>
<div class="DOC-ROW">
<div class="DOC-ROW-icon sent"></div>
<div>
<div class="DOC-ROW-title">Pachtvertrag Südfeld</div>
<div style="font-size:8px;color:#AAA;margin-top:1px">Karlsruhe · 14 Jul 1910</div>
</div>
<div style="margin-left:auto"><div class="CH CH-green" style="font-size:7px">Archived</div></div>
</div>
<div class="SHOW-MORE">Show 2 more…</div>
</div>
<!-- Received Documents -->
<div class="ACT-section" style="padding-bottom:0">
<div class="ACT-section-head">
<div class="ACT-title">Received Documents</div>
<div style="display:flex;align-items:center;gap:6px">
<div class="ACT-badge">3</div>
<div class="SORT-TOGGLE">Date ▾</div>
</div>
</div>
<div class="DOC-ROW">
<div class="DOC-ROW-icon recv"></div>
<div>
<div class="DOC-ROW-title">Scan ohne Titel</div>
<div style="font-size:8px;color:#AAA;margin-top:1px">Hamburg · 25 Nov 1938</div>
</div>
<div style="margin-left:auto"><div class="CH CH-warn" style="font-size:7px">Scan pending</div></div>
</div>
<div class="DOC-ROW">
<div class="DOC-ROW-icon recv"></div>
<div>
<div class="DOC-ROW-title">Scan ohne Titel</div>
<div style="font-size:8px;color:#AAA;margin-top:1px">Hamburg · 25 Nov 1938</div>
</div>
<div style="margin-left:auto"><div class="CH CH-warn" style="font-size:7px">Scan pending</div></div>
</div>
<div class="DOC-ROW">
<div class="DOC-ROW-icon recv"></div>
<div>
<div class="DOC-ROW-title">Scan ohne Titel</div>
<div style="font-size:8px;color:#AAA;margin-top:1px">Hamburg · 25 Nov 1938</div>
</div>
<div style="margin-left:auto"><div class="CH CH-warn" style="font-size:7px">Scan pending</div></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="screen-cap">Left sidebar has 2px navy top accent bar. Avatar 80px. No "Full Name" label — name shown directly as PC-name h1. Notes section only rendered when notes field is non-empty. Edit button navigates to /persons/[id]/edit.</div>
</div>
</div>
<!-- 2B Tablet + 2C Mobile -->
<div class="screens cols2" style="margin-bottom:24px">
<div class="screen-block">
<div class="screen-label">2-B · Tablet stacked <span class="sz">768px</span></div>
<div class="URL-LINE">/persons/a1b2c3d4</div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV-m">
<div class="logo">FAMILIENARCHIV</div>
<div class="nr"><div class="nico"></div><div class="nico"></div></div>
</div>
<div class="MAIN">
<div class="BACK-LINK" style="margin-bottom:8px"><span class="BACK-ARROW"></span> Back</div>
<!-- Stacked: person card full width -->
<div class="PERSON-CARD">
<div class="PERSON-CARD-topbar"></div>
<div class="PERSON-CARD-body" style="display:flex;align-items:center;gap:14px;padding:14px 16px">
<div class="PC-avatar" style="margin:0;flex-shrink:0">OF</div>
<div>
<div class="PC-name" style="text-align:left;font-size:13px">Otto Fischer</div>
<div class="PC-alias" style="text-align:left">„Großvater Otto"</div>
<div class="PC-dates" style="text-align:left">✦ 1882 · † 1944</div>
</div>
<div style="margin-left:auto"><div class="BTN BTN-outline BTN-sm">✏ Edit</div></div>
</div>
</div>
<!-- Activity below -->
<div class="ACT-section">
<div class="ACT-section-head"><div class="ACT-title">Frequent Correspondents</div></div>
<div style="display:flex;gap:6px;flex-wrap:wrap">
<div class="CORR-chip"><div class="CORR-av">HM</div>Hans Müller <span class="CORR-count">×4</span></div>
<div class="CORR-chip"><div class="CORR-av">AS</div>Anna Schmidt <span class="CORR-count">×2</span></div>
</div>
</div>
<div class="ACT-section" style="padding-bottom:0">
<div class="ACT-section-head"><div class="ACT-title">Sent Documents</div><div class="ACT-badge">5</div></div>
<div class="DOC-ROW"><div class="DOC-ROW-icon sent"></div><div class="DOC-ROW-title">Brief an den König</div><div style="margin-left:auto"><div class="CH CH-navy" style="font-size:7px">Uploaded</div></div></div>
<div class="DOC-ROW"><div class="DOC-ROW-icon sent"></div><div class="DOC-ROW-title">Grundbucheintrag Hof Fischer</div><div style="margin-left:auto"><div class="CH CH-green" style="font-size:7px">Archived</div></div></div>
<div class="SHOW-MORE">Show 3 more…</div>
</div>
<div class="ACT-section">
<div class="ACT-section-head"><div class="ACT-title">Received Documents</div><div class="ACT-badge">3</div></div>
<div class="DOC-ROW"><div class="DOC-ROW-icon recv"></div><div class="DOC-ROW-title">Scan ohne Titel</div><div style="margin-left:auto"><div class="CH CH-warn" style="font-size:7px">Scan pending</div></div></div>
<div class="DOC-ROW"><div class="DOC-ROW-icon recv"></div><div class="DOC-ROW-title">Scan ohne Titel</div><div style="margin-left:auto"><div class="CH CH-warn" style="font-size:7px">Scan pending</div></div></div>
</div>
</div>
</div>
</div>
<div class="screen-block">
<div class="screen-label">2-C · Mobile <span class="sz">375px</span></div>
<div class="URL-LINE">/persons/a1b2c3d4</div>
<div class="wf" style="max-width:260px">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV-m">
<div class="logo" style="font-size:8px">FAMILIENARCHIV</div>
<div class="nico"></div>
</div>
<div class="MAIN" style="padding:12px;gap:10px">
<div class="BACK-LINK" style="margin-bottom:4px"><span class="BACK-ARROW"></span> Back</div>
<div class="PERSON-CARD">
<div class="PERSON-CARD-topbar"></div>
<div class="PERSON-CARD-body" style="padding:12px 14px;text-align:center">
<div class="PC-avatar" style="width:52px;height:52px;font-size:16px">OF</div>
<div class="PC-name" style="font-size:13px;margin-top:8px">Otto Fischer</div>
<div class="PC-alias">„Großvater Otto"</div>
<div class="PC-dates">✦ 1882 · † 1944</div>
<div class="BTN BTN-outline BTN-sm" style="width:100%;justify-content:center;margin-top:10px">✏ Edit person</div>
</div>
</div>
<div class="ACT-section" style="padding:10px 12px">
<div class="ACT-section-head"><div class="ACT-title">Correspondents</div></div>
<div style="display:flex;gap:4px;flex-wrap:wrap">
<div class="CORR-chip" style="font-size:8px"><div class="CORR-av">HM</div>Hans M. <span class="CORR-count">×4</span></div>
<div class="CORR-chip" style="font-size:8px"><div class="CORR-av">AS</div>Anna S. <span class="CORR-count">×2</span></div>
</div>
</div>
<div class="ACT-section" style="padding:10px 12px;padding-bottom:0">
<div class="ACT-section-head"><div class="ACT-title">Sent</div><div class="ACT-badge">5</div></div>
<div class="DOC-ROW" style="padding:5px 0"><div class="DOC-ROW-icon sent" style="width:18px;height:22px"></div><div class="DOC-ROW-title" style="font-size:8.5px">Brief an den König</div></div>
<div class="DOC-ROW" style="padding:5px 0"><div class="DOC-ROW-icon sent" style="width:18px;height:22px"></div><div class="DOC-ROW-title" style="font-size:8.5px">Grundbucheintrag…</div></div>
<div class="SHOW-MORE" style="font-size:8px">Show 3 more…</div>
</div>
<div class="ACT-section" style="padding:10px 12px">
<div class="ACT-section-head"><div class="ACT-title">Received</div><div class="ACT-badge">3</div></div>
<div class="DOC-ROW" style="padding:5px 0"><div class="DOC-ROW-icon recv" style="width:18px;height:22px"></div><div class="DOC-ROW-title" style="font-size:8.5px">Scan ohne Titel ×3</div></div>
</div>
</div>
</div>
</div>
</div>
<!-- 2D Minimal data person -->
<div class="screens" style="margin-bottom:16px">
<div class="screen-block" style="max-width:700px">
<div class="screen-label">2-D · Minimal data person — Hans Müller <span class="sz">desktop</span> <span class="state-tag">no alias · no notes · no death year</span></div>
<div class="URL-LINE">/persons/b2c3d4e5</div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV">
<div class="logo">FAMILIENARCHIV</div>
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
</div>
<div class="MAIN-wide">
<div class="BACK-LINK"><span class="BACK-ARROW"></span> Back to overview</div>
<div class="DETAIL-LAYOUT">
<div>
<div class="PERSON-CARD">
<div class="PERSON-CARD-topbar"></div>
<div class="PERSON-CARD-body">
<div class="PC-avatar PC-avatar-lg">HM</div>
<div class="PC-name">Hans Müller</div>
<!-- No alias — section omitted -->
<div class="PC-dates">✦ 1890</div>
<!-- No notes — section omitted entirely -->
<div style="margin-top:10px">
<div style="font-size:8px;color:#D1D5DB;font-style:italic;text-align:center;padding:4px 0">No notes added</div>
</div>
<div class="BTN BTN-outline BTN-sm" style="width:100%;justify-content:center;margin-top:8px">✏ Edit person</div>
</div>
</div>
</div>
<div class="ACTIVITY">
<!-- No correspondents — section omitted -->
<div class="ACT-section" style="padding-bottom:0">
<div class="ACT-section-head"><div class="ACT-title">Sent Documents</div><div class="ACT-badge">1</div></div>
<div class="DOC-ROW">
<div class="DOC-ROW-icon sent"></div>
<div><div class="DOC-ROW-title">Brief an den König</div><div style="font-size:8px;color:#AAA;margin-top:1px">Berlin · 12 Nov 1938</div></div>
<div style="margin-left:auto"><div class="CH CH-navy" style="font-size:7px">Uploaded</div></div>
</div>
</div>
<div class="ACT-section">
<div class="ACT-section-head"><div class="ACT-title">Received Documents</div><div class="ACT-badge">1</div></div>
<div class="DOC-ROW">
<div class="DOC-ROW-icon recv"></div>
<div><div class="DOC-ROW-title">Scan ohne Titel</div><div style="font-size:8px;color:#AAA;margin-top:1px">Hamburg · 25 Nov 1938</div></div>
<div style="margin-left:auto"><div class="CH CH-warn" style="font-size:7px">Scan pending</div></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="screen-cap">Optional sections (alias, notes, Frequent Correspondents) collapse gracefully when empty. Death year omitted — only birth year shown. "No notes added" placeholder in muted italic; entire Notes card section still renders but with placeholder text. Correspondents section not shown when no co-correspondents exist.</div>
</div>
</div>
</div>
<!-- S3 EDIT PERSON -->
<div class="section">
<div class="sec-intro">
<div class="sec-num">3</div>
<div class="sec-meta">
<span class="sec-badge badge-persons">Edit</span>
<div class="sec-title">Edit Person <code style="font-size:14px">/persons/[id]/edit</code></div>
<div class="sec-tagline">Dedicated route. Full-bleed sticky save bar at bottom. 2-column field grid. Danger Zone accordion at the very bottom. Merge panel lives here, not on detail view.</div>
</div>
</div>
<!-- 3A Desktop edit -->
<div class="screens" style="margin-bottom:24px">
<div class="screen-block" style="flex:1">
<div class="screen-label">3-A · Desktop edit form <span class="sz">1440px</span> <span class="state-tag edit">edit</span></div>
<div class="URL-LINE">/persons/a1b2c3d4/edit</div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV">
<div class="logo">FAMILIENARCHIV</div>
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
</div>
<div style="display:flex;flex-direction:column;height:480px">
<div class="MAIN-wide" style="flex:1;overflow:hidden">
<div class="BACK-LINK"><span class="BACK-ARROW"></span> Back to Otto Fischer</div>
<div class="PAGE-TITLE" style="margin-bottom:16px">Edit person: Otto Fischer</div>
<div class="FORM-CARD">
<div class="FORM-CARD-title">Personal Details</div>
<!-- Row 1: First + Last name -->
<div class="FG-row">
<div class="FG">
<div class="FL">First name <span class="req">*</span></div>
<div class="FI filled">Otto</div>
</div>
<div class="FG">
<div class="FL">Last name <span class="req">*</span></div>
<div class="FI filled">Fischer</div>
</div>
</div>
<!-- Row 2: Alias -->
<div class="FG">
<div class="FL">Nickname / Alias <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
<div class="FI filled">Großvater Otto</div>
</div>
<!-- Row 3: Birth + Death year -->
<div class="FG-row">
<div class="FG">
<div class="FL">Birth year <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
<div class="FI filled">1882</div>
</div>
<div class="FG">
<div class="FL">Death year <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
<div class="FI filled">1944</div>
</div>
</div>
<!-- Notes -->
<div class="FG">
<div class="FL">Notes <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
<div class="FTA filled" style="height:60px">Patriarchal figure of the Fischer family. Farmer from Baden-Württemberg. Married to Helene Fischer (née Braun).</div>
</div>
</div>
<!-- Danger Zone accordion (collapsed) -->
<div class="DZ-ACCORD">
<div class="DZ-ACCORD-head">
<div class="DZ-ACCORD-label">⚠ Danger Zone <span class="CH CH-red" style="margin-left:4px">Destructive actions</span></div>
<div class="DZ-ACCORD-chev"></div>
</div>
<!-- Collapsed: only header visible -->
<div style="padding:8px 14px;background:#FFF5F5;border-top:1px solid #FCA5A5">
<div style="font-size:8.5px;color:#888;display:flex;align-items:center;gap:6px;cursor:pointer">
<span>Merge with another person…</span>
<span style="color:#CCC"></span>
</div>
</div>
</div>
</div>
<!-- Sticky save bar -->
<div class="SAVE-BAR">
<div class="BTN BTN-ghost">Discard changes</div>
<div class="BTN BTN-primary">Save changes</div>
</div>
</div>
</div>
<div class="screen-cap">Back link says "← Back to Otto Fischer" — links to /persons/[id]. Page heading uses person full name. Danger Zone accordion collapsed by default; only the "Merge with another person…" affordance is visible. Sticky save bar uses full-bleed pattern from CLAUDE.md.</div>
</div>
</div>
<!-- 3B Validation error -->
<div class="screens cols2" style="margin-bottom:24px">
<div class="screen-block">
<div class="screen-label">3-B · Validation error <span class="sz">desktop</span> <span class="state-tag err">error</span></div>
<div class="URL-LINE">/persons/a1b2c3d4/edit</div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV">
<div class="logo">FAMILIENARCHIV</div>
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
<div class="nr"><div class="nico"></div></div>
</div>
<div style="display:flex;flex-direction:column;height:320px">
<div class="MAIN-wide" style="flex:1;overflow:hidden">
<div class="BACK-LINK"><span class="BACK-ARROW"></span> Back to Otto Fischer</div>
<div class="PAGE-TITLE" style="margin-bottom:12px">Edit person: Otto Fischer</div>
<div class="FORM-CARD">
<div class="FORM-CARD-title">Personal Details</div>
<div class="FG-row">
<div class="FG">
<div class="FL">First name <span class="req">*</span></div>
<div class="FI err" style="border-color:#DC2626;background:#FFF5F5"></div>
<div class="ferr">First name is required</div>
</div>
<div class="FG">
<div class="FL">Last name <span class="req">*</span></div>
<div class="FI filled">Fischer</div>
</div>
</div>
<div class="FG">
<div class="FL">Nickname / Alias</div>
<div class="FI filled">Großvater Otto</div>
</div>
<div class="FG-row">
<div class="FG">
<div class="FL">Birth year</div>
<div class="FI filled">1882</div>
</div>
<div class="FG">
<div class="FL">Death year</div>
<div class="FI filled">1944</div>
</div>
</div>
</div>
</div>
<div class="SAVE-BAR">
<div class="BTN BTN-ghost">Discard changes</div>
<div class="BTN BTN-primary">Save changes</div>
</div>
</div>
</div>
<div class="screen-cap">Errors shown on submit — not live. Affected field gets red border + error message below. Save button remains enabled (not disabled). Multiple fields can show errors simultaneously.</div>
</div>
<!-- 3C Danger Zone expanded -->
<div class="screen-block">
<div class="screen-label">3-C · Danger Zone expanded — Merge panel <span class="sz">desktop</span></div>
<div class="URL-LINE">/persons/a1b2c3d4/edit</div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV">
<div class="logo">FAMILIENARCHIV</div>
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
<div class="nr"><div class="nico"></div></div>
</div>
<div style="display:flex;flex-direction:column;height:400px">
<div class="MAIN-wide" style="flex:1;overflow:hidden">
<div class="BACK-LINK"><span class="BACK-ARROW"></span> Back to Otto Fischer</div>
<div class="PAGE-TITLE" style="margin-bottom:12px">Edit person: Otto Fischer</div>
<!-- Form card (abbreviated) -->
<div class="FORM-CARD" style="padding:10px 14px">
<div class="FORM-CARD-title" style="margin-bottom:8px">Personal Details</div>
<div class="FG-row">
<div class="FG"><div class="FL">First name <span class="req">*</span></div><div class="FI filled">Otto</div></div>
<div class="FG"><div class="FL">Last name <span class="req">*</span></div><div class="FI filled">Fischer</div></div>
</div>
<div style="font-size:8px;color:#AAA;font-style:italic">… more fields above …</div>
</div>
<!-- Danger Zone — EXPANDED -->
<div class="DZ-ACCORD">
<div class="DZ-ACCORD-head" style="background:#FFF5F5">
<div class="DZ-ACCORD-label">⚠ Danger Zone <span class="CH CH-red" style="margin-left:4px">Destructive actions</span></div>
<div class="DZ-ACCORD-chev" style="transform:rotate(90deg)"></div>
</div>
<div class="DZ-ACCORD-body">
<div style="font-size:10px;font-weight:800;color:#991B1B;margin-bottom:6px">Merge with another person</div>
<div class="DZ-ACCORD-desc">Select a target person. All documents and links from <strong>Otto Fischer</strong> will be transferred to the target, and this person will be permanently deleted. This action cannot be undone.</div>
<div class="FG" style="margin-bottom:10px">
<div class="FL">Search for person to merge into…</div>
<div class="TYPEAHEAD-INPUT focus">Search persons…</div>
</div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
<div class="BTN BTN-danger-fill BTN-sm">Merge Otto Fischer →</div>
<div class="BTN BTN-ghost BTN-sm">Cancel</div>
</div>
<div class="AL AL-warn" style="font-size:8px">⚠ This action cannot be undone. All documents linked to Otto Fischer will be reassigned.</div>
</div>
</div>
</div>
<div class="SAVE-BAR">
<div class="BTN BTN-ghost">Discard changes</div>
<div class="BTN BTN-primary">Save changes</div>
</div>
</div>
</div>
<div class="screen-cap">Danger Zone expanded by clicking the header row (Svelte $state boolean toggle). Merge typeahead uses PersonTypeahead component. Red "Merge" button disabled until a target person is selected. Warning banner always visible inside expanded panel.</div>
</div>
</div>
<!-- 3D Mobile edit -->
<div class="screens" style="margin-bottom:16px">
<div class="screen-block" style="max-width:300px">
<div class="screen-label">3-D · Mobile edit <span class="sz">375px</span> <span class="state-tag edit">edit</span></div>
<div class="URL-LINE">/persons/a1b2c3d4/edit</div>
<div class="wf" style="max-width:260px">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV-m">
<div class="logo" style="font-size:8px">FAMILIENARCHIV</div>
<div class="nico"></div>
</div>
<div style="display:flex;flex-direction:column;height:500px">
<div class="MAIN" style="padding:12px;flex:1;overflow:hidden;gap:8px">
<div class="BACK-LINK"><span class="BACK-ARROW"></span> Back to Otto Fischer</div>
<div class="PAGE-TITLE" style="font-size:11px;margin-bottom:8px">Edit: Otto Fischer</div>
<div class="FORM-CARD" style="padding:10px 12px">
<div class="FORM-CARD-title" style="margin-bottom:8px">Personal Details</div>
<!-- Single-column on mobile -->
<div class="FG">
<div class="FL">First name <span class="req">*</span></div>
<div class="FI filled">Otto</div>
</div>
<div class="FG">
<div class="FL">Last name <span class="req">*</span></div>
<div class="FI filled">Fischer</div>
</div>
<div class="FG">
<div class="FL">Nickname / Alias</div>
<div class="FI filled">Großvater Otto</div>
</div>
<div class="FG">
<div class="FL">Birth year</div>
<div class="FI filled">1882</div>
</div>
<div class="FG">
<div class="FL">Death year</div>
<div class="FI filled">1944</div>
</div>
<div class="FG">
<div class="FL">Notes</div>
<div class="FTA filled" style="height:50px;font-size:8px">Patriarchal figure of the Fischer family…</div>
</div>
</div>
<!-- Danger Zone collapsed -->
<div class="DZ-ACCORD">
<div class="DZ-ACCORD-head">
<div class="DZ-ACCORD-label" style="font-size:8px">⚠ Danger Zone</div>
<div class="DZ-ACCORD-chev"></div>
</div>
</div>
</div>
<div class="SAVE-BAR" style="padding:8px 12px">
<div class="BTN BTN-ghost BTN-sm">Discard</div>
<div class="BTN BTN-primary BTN-sm">Save changes</div>
</div>
</div>
</div>
<div class="screen-cap">Mobile: 2-column field grid collapses to 1-column. All fields stack vertically. Sticky save bar remains full-bleed. Danger Zone always at very bottom, collapsed by default.</div>
</div>
</div>
</div>
<!-- S4 NEW PERSON -->
<div class="section">
<div class="sec-intro">
<div class="sec-num">4</div>
<div class="sec-meta">
<span class="sec-badge badge-persons">New</span>
<div class="sec-title">New Person <code style="font-size:14px">/persons/new</code></div>
<div class="sec-tagline">Centered max-w-2xl form. All 6 fields (fixes the 3-field inconsistency). Card-style save bar (not sticky). "Create person" green primary button.</div>
</div>
</div>
<div class="screens cols2" style="margin-bottom:24px">
<!-- 4A Desktop new person -->
<div class="screen-block">
<div class="screen-label">4-A · Desktop new person <span class="sz">1440px</span> <span class="state-tag new">new</span></div>
<div class="URL-LINE">/persons/new</div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV">
<div class="logo">FAMILIENARCHIV</div>
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
</div>
<div class="MAIN-wide">
<div class="BACK-LINK"><span class="BACK-ARROW"></span> Back to overview</div>
<div class="PAGE-TITLE" style="margin-bottom:16px">New person</div>
<!-- Centered max-w-2xl container -->
<div style="max-width:560px">
<div class="FORM-CARD">
<div class="FORM-CARD-title">Person details</div>
<div class="FG-row">
<div class="FG">
<div class="FL">First name <span class="req">*</span></div>
<div class="FI"></div>
</div>
<div class="FG">
<div class="FL">Last name <span class="req">*</span></div>
<div class="FI"></div>
</div>
</div>
<div class="FG">
<div class="FL">Nickname / Alias <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
<div class="FI"></div>
</div>
<div class="FG-row">
<div class="FG">
<div class="FL">Birth year <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
<div class="FI"></div>
</div>
<div class="FG">
<div class="FL">Death year <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
<div class="FI"></div>
</div>
</div>
<div class="FG">
<div class="FL">Notes <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
<div class="FTA" style="height:60px"></div>
</div>
</div>
<!-- Card-style save bar (not sticky — short form) -->
<div style="display:flex;align-items:center;justify-content:space-between;background:#fff;border:1.5px solid #E8E4DF;border-radius:8px;padding:10px 16px;box-shadow:0 1px 4px rgba(0,0,0,.04)">
<div class="BTN BTN-ghost">Cancel</div>
<div class="BTN BTN-green">Create person</div>
</div>
</div>
</div>
</div>
<div class="screen-cap">Save bar uses card-style (not sticky full-bleed) — form is short enough to always be visible. "Cancel" navigates back to /persons. "Create person" green primary. All empty fields shown — no pre-fill.</div>
</div>
<!-- 4B Mobile new person -->
<div class="screen-block">
<div class="screen-label">4-B · Mobile new person <span class="sz">375px</span> <span class="state-tag new">new</span></div>
<div class="URL-LINE">/persons/new</div>
<div class="wf" style="max-width:260px">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV-m">
<div class="logo" style="font-size:8px">FAMILIENARCHIV</div>
<div class="nico"></div>
</div>
<div class="MAIN" style="padding:12px;gap:8px">
<div class="BACK-LINK"><span class="BACK-ARROW"></span> Back</div>
<div class="PAGE-TITLE" style="font-size:11px;margin-bottom:8px">New person</div>
<div class="FORM-CARD" style="padding:10px 12px">
<div class="FORM-CARD-title" style="margin-bottom:8px">Person details</div>
<div class="FG">
<div class="FL">First name <span class="req">*</span></div>
<div class="FI"></div>
</div>
<div class="FG">
<div class="FL">Last name <span class="req">*</span></div>
<div class="FI"></div>
</div>
<div class="FG">
<div class="FL">Nickname / Alias</div>
<div class="FI"></div>
</div>
<div class="FG">
<div class="FL">Birth year</div>
<div class="FI"></div>
</div>
<div class="FG">
<div class="FL">Death year</div>
<div class="FI"></div>
</div>
<div class="FG">
<div class="FL">Notes</div>
<div class="FTA" style="height:52px"></div>
</div>
</div>
<div style="display:flex;align-items:center;justify-content:space-between;background:#fff;border:1.5px solid #E8E4DF;border-radius:6px;padding:8px 12px">
<div class="BTN BTN-ghost BTN-sm">Cancel</div>
<div class="BTN BTN-green BTN-sm">Create person</div>
</div>
</div>
</div>
<div class="screen-cap">Mobile: all fields in single column. Save bar card-style (not sticky). Same 6 fields as desktop.</div>
</div>
</div>
</div>
<!-- S5 EDGE CASES -->
<div class="section">
<div class="sec-intro">
<div class="sec-num">5</div>
<div class="sec-meta">
<span class="sec-badge badge-edge">Edge Cases</span>
<div class="sec-title">Edge Cases & Error States</div>
<div class="sec-tagline">Person with no documents. Unsaved changes guard. Save API error.</div>
</div>
</div>
<!-- 5A Person with no documents -->
<div class="screens" style="margin-bottom:24px">
<div class="screen-block" style="flex:1">
<div class="screen-label">5-A · Person with no documents — Maria Weber <span class="sz">desktop</span> <span class="state-tag empty">no documents</span></div>
<div class="URL-LINE">/persons/d4e5f6g7</div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV">
<div class="logo">FAMILIENARCHIV</div>
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
</div>
<div class="MAIN-wide">
<div class="BACK-LINK"><span class="BACK-ARROW"></span> Back to overview</div>
<div class="DETAIL-LAYOUT">
<div>
<div class="PERSON-CARD">
<div class="PERSON-CARD-topbar"></div>
<div class="PERSON-CARD-body">
<div class="PC-avatar PC-avatar-lg">MW</div>
<div class="PC-name">Maria Weber</div>
<div style="font-size:8.5px;color:#D1D5DB;font-style:italic;text-align:center;margin-top:4px;margin-bottom:4px">No alias · No dates</div>
<div class="BTN BTN-outline BTN-sm" style="width:100%;justify-content:center;margin-top:10px">✏ Edit person</div>
</div>
</div>
</div>
<div class="ACTIVITY">
<!-- No correspondents — section omitted entirely -->
<!-- Sent: empty state -->
<div class="ACT-section">
<div class="ACT-section-head">
<div class="ACT-title">Sent Documents</div>
<div class="ACT-badge" style="background:#F3F4F6;color:#AAA">0</div>
</div>
<div class="EMPTY-BOX" style="padding:20px;border-color:#E8E4DF">
<div class="EMPTY-ICON" style="font-size:20px">📄</div>
<div class="EMPTY-MSG">No sent documents yet</div>
</div>
</div>
<!-- Received: empty state -->
<div class="ACT-section">
<div class="ACT-section-head">
<div class="ACT-title">Received Documents</div>
<div class="ACT-badge" style="background:#F3F4F6;color:#AAA">0</div>
</div>
<div class="EMPTY-BOX" style="padding:20px;border-color:#E8E4DF">
<div class="EMPTY-ICON" style="font-size:20px">📄</div>
<div class="EMPTY-MSG">No received documents yet</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="screen-cap">When both sent and received document counts are 0, empty-state dashed boxes are shown. Correspondent section is entirely absent (not rendered). Count badge shows 0 in grey, not navy.</div>
</div>
</div>
<!-- 5B Unsaved changes guard + 5C Save error -->
<div class="screens cols2" style="margin-bottom:16px">
<div class="screen-block">
<div class="screen-label">5-B · Unsaved changes guard <span class="sz">edit page</span> <span class="state-tag warn">dirty form</span></div>
<div class="URL-LINE">/persons/a1b2c3d4/edit</div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV">
<div class="logo">FAMILIENARCHIV</div>
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
<div class="nr"><div class="nico"></div></div>
</div>
<div style="display:flex;flex-direction:column;height:320px">
<div class="MAIN-wide" style="flex:1;overflow:hidden;gap:10px">
<div class="BACK-LINK"><span class="BACK-ARROW"></span> Back to Otto Fischer</div>
<!-- Unsaved changes banner -->
<div class="UNSAVED-BANNER">
<div class="UNSAVED-MSG">⚠ You have unsaved changes. Save or discard before leaving.</div>
<div style="display:flex;gap:6px">
<div class="BTN BTN-primary BTN-sm">Save</div>
<div class="BTN BTN-ghost BTN-sm">Discard</div>
</div>
</div>
<div class="PAGE-TITLE" style="font-size:11px;margin-bottom:8px">Edit person: Otto Fischer</div>
<div class="FORM-CARD" style="padding:10px 12px">
<div class="FORM-CARD-title" style="margin-bottom:8px">Personal Details</div>
<div class="FG-row">
<div class="FG">
<div class="FL">First name <span class="req">*</span></div>
<div class="FI filled focus">Ott<span style="border-right:2px solid #002850">&nbsp;</span></div>
</div>
<div class="FG">
<div class="FL">Last name <span class="req">*</span></div>
<div class="FI filled">Fischer</div>
</div>
</div>
<div style="font-size:8px;color:#AAA;font-style:italic;margin-top:4px">Form is dirty — first name partially edited</div>
</div>
</div>
<div class="SAVE-BAR">
<div class="BTN BTN-ghost">Discard changes</div>
<div class="BTN BTN-primary">Save changes</div>
</div>
</div>
</div>
<div class="screen-cap">Banner triggers when user clicks the back link or uses browser navigation while form isDirty (track with Svelte $derived). [Save] in banner = same action as save bar. [Discard] resets form and navigates away. SvelteKit beforeNavigate() hook handles browser back/forward.</div>
</div>
<div class="screen-block">
<div class="screen-label">5-C · Save error — API failure <span class="sz">edit page</span> <span class="state-tag err">error</span></div>
<div class="URL-LINE">/persons/a1b2c3d4/edit</div>
<div class="wf">
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
<div class="NAV">
<div class="logo">FAMILIENARCHIV</div>
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
<div class="nr"><div class="nico"></div></div>
</div>
<div style="display:flex;flex-direction:column;height:320px">
<div class="MAIN-wide" style="flex:1;overflow:hidden;gap:10px">
<div class="BACK-LINK"><span class="BACK-ARROW"></span> Back to Otto Fischer</div>
<!-- Error banner -->
<div class="ERR-BANNER">
<div class="ERR-BANNER-msg">✕ Save failed — First name is required.</div>
</div>
<div class="PAGE-TITLE" style="font-size:11px;margin-bottom:8px">Edit person: Otto Fischer</div>
<div class="FORM-CARD" style="padding:10px 12px">
<div class="FORM-CARD-title" style="margin-bottom:8px">Personal Details</div>
<div class="FG-row">
<div class="FG">
<div class="FL">First name <span class="req">*</span></div>
<div class="FI err"></div>
<div class="ferr">First name is required</div>
</div>
<div class="FG">
<div class="FL">Last name <span class="req">*</span></div>
<div class="FI filled">Fischer</div>
</div>
</div>
<div class="FG-row">
<div class="FG">
<div class="FL">Birth year</div>
<div class="FI filled">1882</div>
</div>
<div class="FG">
<div class="FL">Death year</div>
<div class="FI filled">1944</div>
</div>
</div>
</div>
</div>
<div class="SAVE-BAR">
<div class="BTN BTN-ghost">Discard changes</div>
<div class="BTN BTN-primary">Save changes</div>
</div>
</div>
</div>
<div class="screen-cap">API error shown in red banner below the back link. Specific field also highlighted with inline error. Error message uses backend ErrorCode translation via getErrorMessage(). Page stays on edit route — user can correct and retry.</div>
</div>
</div>
</div>
<!-- S6 IMPLEMENTATION NOTES -->
<div class="section">
<div class="sec-intro">
<div class="sec-num">6</div>
<div class="sec-meta">
<span class="sec-badge badge-arch">Implementation</span>
<div class="sec-title">Implementation Notes</div>
<div class="sec-tagline">Numbered rules covering every required code change. Follow these in order to implement the full Concept A redesign.</div>
</div>
</div>
<div class="SPEC">
<div class="SPEC-title">Implementation rules — Concept A: Enriched Directory</div>
<div class="SPEC-grid">
<div class="SPEC-col">
<div class="SPEC-rule">
<div class="SPEC-rule-num">Rule 1 — Route change</div>
<div class="SPEC-rule-text">Add <span class="SPEC-rule-code">/persons/[id]/edit</span> as a new SvelteKit route (<span class="SPEC-rule-code">+page.svelte</span> + <span class="SPEC-rule-code">+page.server.ts</span>). Move the <span class="SPEC-rule-code">update</span> form action from <span class="SPEC-rule-code">/persons/[id]/+page.server.ts</span> to the edit route's server file. <span class="SPEC-rule-code">PersonCard.svelte</span> edit-mode <span class="SPEC-rule-code">$state</span> can be removed — the card is now view-only. The [Edit person] button navigates to <span class="SPEC-rule-code">/persons/{id}/edit</span>.</div>
</div>
<div class="SPEC-rule">
<div class="SPEC-rule-num">Rule 2 — New person form fields</div>
<div class="SPEC-rule-text">Add <span class="SPEC-rule-code">birthYear</span>, <span class="SPEC-rule-code">deathYear</span>, and <span class="SPEC-rule-code">notes</span> fields to <span class="SPEC-rule-code">/persons/new/+page.svelte</span> and the corresponding <span class="SPEC-rule-code">create</span> server action. These fields are already on the PersonDTO and the backend <span class="SPEC-rule-code">PersonService</span>; only the frontend form was missing them. Use <span class="SPEC-rule-code">parseInt(formData.get('birthYear'))</span> — handle empty string as <span class="SPEC-rule-code">undefined</span>.</div>
</div>
<div class="SPEC-rule">
<div class="SPEC-rule-num">Rule 3 — Card enrichment on list page</div>
<div class="SPEC-rule-text">The list <span class="SPEC-rule-code">+page.server.ts</span> already returns <span class="SPEC-rule-code">persons[]</span>. No backend change needed — <span class="SPEC-rule-code">alias</span>, <span class="SPEC-rule-code">birthYear</span>, <span class="SPEC-rule-code">deathYear</span> are already on the PersonDTO. Update the card template in <span class="SPEC-rule-code">+page.svelte</span> to render these fields. Render alias only <span class="SPEC-rule-code">{#if person.alias}</span>. Life dates: <span class="SPEC-rule-code">✦ {birthYear}</span> and <span class="SPEC-rule-code">† {deathYear}</span> joined with <span class="SPEC-rule-code"> · </span>; omit when null.</div>
</div>
<div class="SPEC-rule">
<div class="SPEC-rule-num">Rule 4 — Stats bar</div>
<div class="SPEC-rule-text">Compute <span class="SPEC-rule-code">persons.length</span> (person count) and <span class="SPEC-rule-code">totalDocs = persons.reduce((acc, p) => acc + (p.documentCount ?? 0), 0)</span> (total documents). This requires backend to return <span class="SPEC-rule-code">documentCount: number</span> on PersonDTO — add this field to the Java <span class="SPEC-rule-code">Person</span> entity response (computed via <span class="SPEC-rule-code">@Formula</span> or a JPQL query in <span class="SPEC-rule-code">PersonService.findAll()</span>). Mark it <span class="SPEC-rule-code">@Schema(requiredMode = REQUIRED)</span> and run <span class="SPEC-rule-code">npm run generate:api</span>.</div>
</div>
<div class="SPEC-rule">
<div class="SPEC-rule-num">Rule 5 — 2-column detail layout</div>
<div class="SPEC-rule-text">Replace the current vertical stack in <span class="SPEC-rule-code">/persons/[id]/+page.svelte</span> with a CSS grid: <span class="SPEC-rule-code">class="grid md:grid-cols-[35fr_65fr] gap-5 items-start"</span>. Left child = PersonCard. Right child = Activity wrapper containing the three ACT sections. On mobile/tablet (<span class="SPEC-rule-code">&lt;md:</span>) the grid collapses to single column (PersonCard above, Activity below).</div>
</div>
<div class="SPEC-rule">
<div class="SPEC-rule-num">Rule 6 — Merge panel relocation</div>
<div class="SPEC-rule-text"><span class="SPEC-rule-code">PersonMergePanel.svelte</span> must be moved from <span class="SPEC-rule-code">/persons/[id]/+page.svelte</span> to <span class="SPEC-rule-code">/persons/[id]/edit/+page.svelte</span>. Wrap it in a collapsible accordion: <span class="SPEC-rule-code">let dangerOpen = $state(false)</span>; the accordion header toggles <span class="SPEC-rule-code">dangerOpen</span>; the body uses a CSS <span class="SPEC-rule-code">transition</span> on max-height or a simple <span class="SPEC-rule-code">{#if dangerOpen}</span> block.</div>
</div>
</div>
<div class="SPEC-col">
<div class="SPEC-rule">
<div class="SPEC-rule-num">Rule 7 — "Full Name" duplication fix</div>
<div class="SPEC-rule-text">Remove the <span class="SPEC-rule-code">&lt;div class="FL"&gt;Full Name&lt;/div&gt;</span> label and associated value row from <span class="SPEC-rule-code">PersonCard.svelte</span> view mode. The <span class="SPEC-rule-code">&lt;h1&gt;</span> (PC-name class) already displays the full name. This was flagged in the audit as a direct duplication.</div>
</div>
<div class="SPEC-rule">
<div class="SPEC-rule-num">Rule 8 — Sticky save bar</div>
<div class="SPEC-rule-text">The edit route uses the full-bleed sticky pattern from <span class="SPEC-rule-code">CLAUDE.md</span>: <span class="SPEC-rule-code">class="sticky bottom-0 z-10 -mx-4 px-6 py-4 bg-white border-t border-brand-sand shadow-[0_-2px_8px_rgba(0,0,0,0.06)] flex items-center justify-between"</span>. The new person form uses the card-style save bar (not sticky): <span class="SPEC-rule-code">class="mt-4 flex items-center justify-between rounded-sm border border-brand-sand bg-white px-6 py-4 shadow-sm"</span>.</div>
</div>
<div class="SPEC-rule">
<div class="SPEC-rule-num">Rule 9 — Co-correspondents tooltip</div>
<div class="SPEC-rule-text">Add <span class="SPEC-rule-code">title="Click to view conversation"</span> to each correspondent chip element. Optionally add a small 💬 chat icon inside the chip (Unicode or a 12px SVG). The chip's <span class="SPEC-rule-code">href</span> should navigate to <span class="SPEC-rule-code">/conversations?person1={currentId}&amp;person2={corrId}</span>. This clarifies the navigation target which was previously ambiguous.</div>
</div>
<div class="SPEC-rule">
<div class="SPEC-rule-num">Rule 10 — Document status labels</div>
<div class="SPEC-rule-text">Map raw status enums to human-readable i18n labels using the existing Paraglide system: <span class="SPEC-rule-code">PLACEHOLDER → m.status_scan_pending()</span>, <span class="SPEC-rule-code">UPLOADED → m.status_uploaded()</span>, <span class="SPEC-rule-code">TRANSCRIBED → m.status_transcribed()</span>, <span class="SPEC-rule-code">REVIEWED → m.status_reviewed()</span>, <span class="SPEC-rule-code">ARCHIVED → m.status_archived()</span>. Add keys to <span class="SPEC-rule-code">messages/de.json</span>, <span class="SPEC-rule-code">en.json</span>, <span class="SPEC-rule-code">es.json</span>. Add <span class="SPEC-rule-code">DOCUMENT_STATUS_INVALID</span> to <span class="SPEC-rule-code">ErrorCode.java</span> and <span class="SPEC-rule-code">errors.ts</span> for unknown values.</div>
</div>
<div class="SPEC-rule">
<div class="SPEC-rule-num">Rule 11 — Unsaved changes guard</div>
<div class="SPEC-rule-text">In <span class="SPEC-rule-code">/persons/[id]/edit/+page.svelte</span>, track a <span class="SPEC-rule-code">isDirty = $derived(...)</span> boolean by comparing current field values to the loaded person. Use SvelteKit's <span class="SPEC-rule-code">beforeNavigate(({ cancel }) => { if (isDirty) cancel() })</span> to block browser navigation. Show the inline warning banner (yellow, above the form) when isDirty and user attempts to leave. The banner [Save] button submits the form; [Discard] resets fields and calls <span class="SPEC-rule-code">invalidate()</span>.</div>
</div>
<div class="SPEC-rule">
<div class="SPEC-rule-num">Rule 12 — Mobile card layout</div>
<div class="SPEC-rule-text">On mobile (<span class="SPEC-rule-code">&lt;640px</span>) the person grid cards switch from centered column layout to horizontal row layout: initials circle on the left (36×36px), text block in the middle (name + alias + dates + doc count), chevron on the right. Use <span class="SPEC-rule-code">sm:flex-col sm:items-center</span> vs base <span class="SPEC-rule-code">flex-row items-center</span> in Tailwind. This improves scannability on narrow screens.</div>
</div>
</div>
</div>
</div>
<!-- Status label reference -->
<div class="DECISION" style="margin-top:24px">
<div class="DECISION-title">📋 Document status label map (Rule 10)</div>
<ul>
<li><code>PLACEHOLDER</code> → "Scan pending" — <span class="CH CH-warn">Scan pending</span> (amber chip)</li>
<li><code>UPLOADED</code> → "Uploaded" — <span class="CH CH-navy">Uploaded</span> (navy chip)</li>
<li><code>TRANSCRIBED</code> → "Transcribed" — <span class="CH CH-blue">Transcribed</span> (blue chip)</li>
<li><code>REVIEWED</code> → "Reviewed" — <span class="CH CH-mint">Reviewed</span> (mint chip)</li>
<li><code>ARCHIVED</code> → "Archived" — <span class="CH CH-green">Archived</span> (green chip)</li>
</ul>
</div>
<!-- Files to touch summary -->
<div style="background:#fff;border:1px solid #E8E4DF;border-radius:8px;overflow:hidden;margin-top:24px">
<div style="padding:12px 16px;background:#F7F5F2;border-bottom:1px solid #E8E4DF;font-size:10px;font-weight:800;color:#555;text-transform:uppercase;letter-spacing:1px">Files to create / modify</div>
<table class="SUM-table">
<thead><tr><th>File</th><th>Action</th><th>Related rule(s)</th></tr></thead>
<tbody>
<tr><td><code>frontend/src/routes/persons/+page.svelte</code></td><td>Add alias, dates, doc count to card template; add stats bar; switch to 4-col grid; mobile row layout</td><td>3, 4, 12</td></tr>
<tr><td><code>frontend/src/routes/persons/new/+page.svelte</code></td><td>Add birth year, death year, notes fields</td><td>2</td></tr>
<tr><td><code>frontend/src/routes/persons/new/+page.server.ts</code></td><td>Handle new fields in create action</td><td>2</td></tr>
<tr><td><code>frontend/src/routes/persons/[id]/+page.svelte</code></td><td>2-col grid layout; view-only PersonCard; remove edit toggle state; remove merge panel</td><td>1, 5, 6, 7</td></tr>
<tr><td><code>frontend/src/routes/persons/[id]/+page.server.ts</code></td><td>Remove update action (moved to edit route)</td><td>1</td></tr>
<tr><td><code>frontend/src/routes/persons/[id]/edit/+page.svelte</code></td><td>CREATE: edit form, sticky save bar, danger zone accordion, unsaved guard</td><td>1, 6, 8, 11</td></tr>
<tr><td><code>frontend/src/routes/persons/[id]/edit/+page.server.ts</code></td><td>CREATE: load person, update action</td><td>1</td></tr>
<tr><td><code>frontend/src/lib/components/PersonCard.svelte</code></td><td>Remove edit mode toggle; remove "Full Name" label row; make view-only</td><td>1, 7</td></tr>
<tr><td><code>frontend/src/lib/components/PersonMergePanel.svelte</code></td><td>Move to edit route; add tooltip to chips</td><td>6, 9</td></tr>
<tr><td><code>backend/src/main/java/…/model/Person.java</code></td><td>Add <code>documentCount</code> computed field or handle in service</td><td>4</td></tr>
<tr><td><code>frontend/src/lib/errors.ts</code></td><td>Add DOCUMENT_STATUS_INVALID error code</td><td>10</td></tr>
<tr><td><code>frontend/src/lib/messages/de.json</code> + <code>en.json</code> + <code>es.json</code></td><td>Add status label keys</td><td>10</td></tr>
</tbody>
</table>
</div>
</div>
</div><!-- end .doc -->
</body>
</html>