Files
familienarchiv/docs/specs/lesereisen-reader-spec.html
Marcel 8e63867ad8
All checks were successful
CI / Unit & Component Tests (push) Successful in 3m23s
CI / OCR Service Tests (push) Successful in 24s
CI / Backend Unit Tests (push) Successful in 4m2s
CI / fail2ban Regex (push) Successful in 46s
CI / Semgrep Security Scan (push) Successful in 21s
CI / Compose Bucket Idempotency (push) Successful in 1m8s
nightly / deploy-staging (push) Successful in 2m44s
docs(specs): UI specs for Lesereisen reader and Journey editor
lesereisen-reader-spec.html — Issue #752
  LR-0 type selector on /geschichten/new
  LR-1 REISE badge on the list
  LR-2 Journey reader (ordered cards, interlude asides, no position numbers)

lesereisen-editor-spec.html — Issue #753
  LE-1 empty JourneyEditor layout
  LE-2 editor with mixed items (documents + interludes, drag handles)
  LE-3 inline note-editing state
  LE-4 mobile layout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 19:07:34 +02:00

728 lines
52 KiB
HTML
Raw Permalink 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="de">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Lesereisen — Reader-Integration · Familienarchiv</title>
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,300;9..144,400;9..144,500&family=DM+Sans:wght@300;400;500;600&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet"/>
<style>
:root{--color-page:#FAFAF7;--color-surface:#F5F4EE;--color-subtle:#EDECEA;--color-border:#D8D7D0;--color-text-muted:#6B6A63;--color-text:#1C1C18;--navy:#012851;--mint:#A1DCD8;--sand:#F0EFE9;--turquoise:#00C7B1;--blue-tint:#E6F1FB;--blue:#2D7DD2;--blue-dark:#185FA5;--green-tint:#E8F5EA;--green:#3D8C4A;--green-dark:#2E6E39;--orange-tint:#FEF0E6;--orange:#E8862A;--orange-dark:#B46820;--font-display:'Fraunces',Georgia,serif;--font-sans:'DM Sans',system-ui,sans-serif;--font-mono:'DM Mono',monospace;--radius-sm:4px;--radius-md:6px;--radius-lg:10px;--radius-xl:16px;--shadow-card:0 1px 3px rgba(28,28,24,.06),0 1px 2px rgba(28,28,24,.04);--shadow-raised:0 4px 12px rgba(28,28,24,.08),0 2px 4px rgba(28,28,24,.04);--shadow-overlay:0 8px 32px rgba(28,28,24,.12),0 2px 8px rgba(28,28,24,.06);}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
body{font-family:var(--font-sans);background:#E8E7E2;color:var(--color-text);font-size:14px;line-height:1.6;}
.doc{max-width:1200px;margin:0 auto;padding:48px 40px 120px;}
.doc-header{display:flex;justify-content:space-between;align-items:flex-end;padding-bottom:28px;border-bottom:1px solid var(--color-border);margin-bottom:48px;background:var(--color-page);margin:-48px -40px 48px;padding:48px 40px 28px;border-radius:var(--radius-xl) var(--radius-xl) 0 0;}
.doc-header h1{font-family:var(--font-display);font-size:28px;font-weight:500;letter-spacing:-.02em;margin-bottom:4px;}
.doc-header p{font-size:13px;color:var(--color-text-muted);max-width:680px;}
.doc-meta{font-family:var(--font-mono);font-size:11px;color:var(--color-text-muted);text-align:right;line-height:1.9;}
.pill{display:inline-block;padding:2px 8px;border-radius:var(--radius-sm);font-size:10px;font-weight:500;letter-spacing:.05em;}
.pill-o{background:var(--orange-tint);color:var(--orange-dark);}
.section{margin-bottom:64px;}
.section-title{font-size:10px;font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--color-text-muted);padding-bottom:10px;border-bottom:1px solid var(--color-border);margin-bottom:24px;}
.prose{font-size:13px;color:var(--color-text-muted);line-height:1.65;max-width:720px;margin-bottom:20px;}
.jh{padding:20px 24px;border-radius:var(--radius-xl);margin-bottom:40px;display:flex;align-items:center;gap:16px;}
.jh .jn{font-family:var(--font-display);font-size:48px;font-weight:300;line-height:1;opacity:.5;}
.jh h2{font-family:var(--font-display);font-size:22px;font-weight:500;letter-spacing:-.02em;margin-bottom:4px;}
.jh p{font-size:13px;line-height:1.5;}.jh .fl{font-family:var(--font-mono);font-size:11px;margin-top:6px;opacity:.7;}
.jh-o{background:var(--orange-tint);border:1px solid #F0C99A;}
.jh-o .jn{color:var(--orange);}
.jh-o p,.jh-o .fl{color:var(--orange-dark);}
.scr{margin-bottom:56px;}
.scr-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;}
.scr-head h3{font-family:var(--font-display);font-size:20px;font-weight:500;letter-spacing:-.02em;}
.scr-id{font-family:var(--font-mono);font-size:11px;color:var(--color-text-muted);padding:2px 8px;border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-page);}
.scr-desc{font-size:12px;color:var(--color-text-muted);line-height:1.6;max-width:720px;margin-bottom:6px;}
.scr-var{font-size:11px;color:var(--color-text-muted);margin-bottom:20px;}.scr-var strong{color:var(--color-text);}
.previews{display:flex;gap:32px;flex-wrap:wrap;justify-content:center;align-items:flex-start;margin-bottom:20px;}
.prev-col{display:flex;flex-direction:column;align-items:center;gap:10px;}
.bp-lbl{font-family:var(--font-mono);font-size:10px;color:var(--color-text-muted);}
.desk{width:100%;max-width:1040px;background:var(--color-page);border-radius:var(--radius-xl);overflow:hidden;box-shadow:var(--shadow-overlay),0 0 0 1px rgba(0,0,0,.06);display:flex;flex-direction:column;}
.phone{width:320px;flex-shrink:0;background:var(--color-page);border-radius:36px;overflow:hidden;box-shadow:var(--shadow-overlay),0 0 0 1px rgba(0,0,0,.07);display:flex;flex-direction:column;border:6px solid #1C1C18;}
.pst{padding:10px 20px 0;display:flex;justify-content:space-between;align-items:center;font-size:12px;background:var(--color-page);}.pst b{font-weight:600;}.pst span{font-size:10px;}
.pb{flex:1;overflow-y:auto;display:flex;flex-direction:column;}
.fa-nav{height:32px;background:var(--navy);display:flex;align-items:center;padding:0 12px;gap:8px;flex-shrink:0;}
.fa-logo{font-size:7px;font-weight:900;color:#fff;letter-spacing:.8px;border-bottom:2px solid var(--mint);padding-bottom:1px;}
.fa-link{font-size:5.5px;color:rgba(255,255,255,.4);font-weight:700;text-transform:uppercase;letter-spacing:.05em;}
.fa-link.active{color:var(--mint);}
.fa-nav-r{margin-left:auto;display:flex;gap:5px;align-items:center;}
.fa-av{width:16px;height:16px;background:rgba(255,255,255,.1);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:5px;font-weight:800;color:rgba(255,255,255,.5);}
.m-nav{height:26px;background:var(--navy);display:flex;align-items:center;padding:0 10px;gap:6px;flex-shrink:0;}
.m-logo{font-size:6px;font-weight:900;color:#fff;letter-spacing:.7px;border-bottom:1.5px solid var(--mint);padding-bottom:1px;}
.m-nav-r{margin-left:auto;display:flex;gap:4px;align-items:center;}
.m-av{width:14px;height:14px;background:rgba(255,255,255,.1);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:4.5px;font-weight:800;color:rgba(255,255,255,.5);}
.m-ham{display:flex;flex-direction:column;gap:2px;width:12px;}
.m-ham span{height:1.5px;background:rgba(255,255,255,.6);border-radius:1px;}
/* ── impl-ref table ── */
.agent{background:var(--color-text);color:#E8E8E2;padding:24px;border-radius:var(--radius-lg);margin-top:20px;}
.agent h4{font-size:9px;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:#5A5A55;margin-bottom:12px;}
.at{width:100%;border-collapse:collapse;font-family:var(--font-mono);font-size:10px;}
.at thead tr{border-bottom:1px solid #2A2A26;}
.at th{text-align:left;padding:6px 10px;font-size:8px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:#5A5A55;font-family:var(--font-sans);}
.at td{padding:5px 10px;border-bottom:1px solid #1E1E1A;vertical-align:top;line-height:1.5;}
.at tr:last-child td{border-bottom:none;}
.at td:first-child{color:#7A7A72;}
.at td:nth-child(2){color:#E8E8E2;font-weight:500;}
.at td:nth-child(3){color:#5A5A55;}
.at .grp td{padding-top:14px;font-family:var(--font-sans);font-size:8px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:#3A3A36;}
/* ── LLM guide ── */
.llm{background:var(--color-page);border:2px solid var(--navy);border-radius:var(--radius-xl);padding:32px 40px;margin-top:64px;}
.llm h2{font-family:var(--font-display);font-size:22px;font-weight:500;letter-spacing:-.02em;margin-bottom:8px;color:var(--navy);}
.llm h3{font-size:14px;font-weight:600;margin:20px 0 8px;}
.llm h4{font-size:12px;font-weight:600;margin:14px 0 6px;color:var(--color-text-muted);}
.llm p,.llm li{font-size:13px;color:var(--color-text-muted);line-height:1.65;}
.llm ul,.llm ol{padding-left:20px;margin-bottom:12px;}
.llm li{margin-bottom:4px;}
.llm code{font-family:var(--font-mono);font-size:11px;background:var(--color-surface);padding:1px 5px;border-radius:3px;}
.llm table{width:100%;border-collapse:collapse;margin:12px 0;font-size:12px;}
.llm th,.llm td{text-align:left;padding:6px 10px;border-bottom:1px solid var(--color-border);}
.llm th{font-weight:500;color:var(--color-text);font-size:11px;text-transform:uppercase;letter-spacing:.05em;}
.llm td{color:var(--color-text-muted);}
/* ── List row (re-used from reader-journey spec) ── */
.g-list-card{background:#fff;border:1px solid #E4E2D7;border-radius:4px;box-shadow:var(--shadow-card);overflow:hidden;}
.g-row{display:flex;gap:0;border-bottom:1px solid #F0EFE9;}
.g-row:last-child{border-bottom:none;}
.g-meta{width:88px;flex-shrink:0;padding:10px 10px 10px 12px;display:flex;flex-direction:column;gap:3px;border-right:1px solid #F0EFE9;}
.g-content{padding:10px 14px 10px 12px;flex:1;min-width:0;}
.g-av{width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:7px;font-weight:800;color:#fff;flex-shrink:0;margin-bottom:3px;}
.av-navy{background:#012851;} .av-purple{background:#534AB7;} .av-teal{background:#0E9488;}
.g-author{font-size:7px;font-weight:700;color:#1C1C18;line-height:1.3;}
.g-date{font-size:6.5px;color:#6B6A63;}
.g-chip{display:inline-flex;align-items:center;gap:2px;padding:1px 5px;background:#F5F4EE;border:1px solid #D8D7D0;border-radius:10px;font-size:6px;font-weight:500;color:#1C1C18;margin-top:2px;max-width:76px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.g-title{font-family:Georgia,serif;font-size:11px;color:#012851;line-height:1.4;margin-bottom:2px;}
.g-excerpt{font-size:7.5px;color:#6B6A63;line-height:1.55;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
.g-filters{display:flex;gap:5px;align-items:center;padding:8px 12px;background:var(--color-page);border-bottom:1px solid #EDECEA;flex-wrap:wrap;}
.g-pill{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:6.5px;font-weight:700;border:1px solid #D8D7D0;color:#6B6A63;background:transparent;}
.g-pill.active{background:#012851;color:#fff;border-color:#012851;}
.g-page-hdr{display:flex;justify-content:space-between;align-items:center;padding:10px 14px 6px;}
.g-page-title{font-family:Georgia,serif;font-size:16px;font-weight:400;color:#012851;}
.g-new-btn{font-size:7px;font-weight:700;padding:4px 10px;border-radius:3px;background:#012851;color:#fff;border:none;display:flex;align-items:center;gap:3px;}
/* ── Journey badge in list ── */
.j-badge{display:inline-flex;align-items:center;padding:1px 5px;border-radius:3px;font-size:5.5px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;background:var(--orange-tint);color:var(--orange-dark);border:1px solid #F0C99A;margin-top:2px;}
/* ── Type selector cards ── */
.type-selector{display:flex;gap:12px;justify-content:center;padding:20px 24px;flex:1;align-items:center;background:#E8E7E2;}
.type-selector-inner{max-width:520px;width:100%;}
.type-selector-q{font-family:Georgia,serif;font-size:12px;font-weight:400;color:#6B6A63;text-align:center;margin-bottom:14px;}
.type-cards{display:flex;gap:10px;}
.type-card{flex:1;border:1px solid #D8D7D0;border-radius:6px;padding:12px 14px;cursor:pointer;background:#fff;display:flex;flex-direction:column;gap:5px;}
.type-card.selected{border-color:var(--orange);background:var(--orange-tint);box-shadow:0 0 0 2px rgba(232,134,42,.15);}
.type-card-icon{font-size:16px;margin-bottom:2px;}
.type-card-title{font-family:Georgia,serif;font-size:11px;font-weight:400;color:var(--navy);}
.type-card-desc{font-size:7.5px;color:#6B6A63;line-height:1.55;}
.type-card-check{width:14px;height:14px;border-radius:50%;background:var(--orange);display:flex;align-items:center;justify-content:center;margin-top:4px;align-self:flex-end;}
.type-card-check svg{width:8px;height:8px;}
.type-next-bar{display:flex;justify-content:flex-end;padding:8px 24px;background:#fff;border-top:1px solid #E4E2D7;}
.type-next-btn{font-size:8px;font-weight:700;padding:5px 14px;border-radius:3px;background:var(--navy);color:#fff;border:none;display:flex;align-items:center;gap:3px;}
/* ── Journey reader ── */
.jr-article{background:var(--color-page);border-radius:6px;padding:16px 20px;max-width:640px;margin:0 auto;}
.jr-back{font-size:7px;color:#6B6A63;margin-bottom:10px;display:flex;align-items:center;gap:2px;}
.jr-badge{display:inline-flex;align-items:center;padding:1px 6px;border-radius:3px;font-size:6px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;background:var(--orange-tint);color:var(--orange-dark);border:1px solid #F0C99A;margin-bottom:5px;}
.jr-title{font-family:Georgia,serif;font-size:18px;font-weight:400;color:#012851;line-height:1.3;margin-bottom:8px;}
.jr-metabar{display:flex;align-items:center;gap:6px;padding-bottom:8px;border-bottom:1px solid #EDECEA;margin-bottom:10px;}
.jr-metabar-r{margin-left:auto;display:flex;align-items:center;gap:6px;}
.jr-edit-btn{font-size:6.5px;font-weight:600;padding:2px 7px;border:1px solid #D8D7D0;border-radius:3px;color:#1C1C18;background:transparent;}
.jr-intro{font-family:Georgia,serif;font-size:8.5px;line-height:1.75;color:#6B6A63;font-style:italic;margin-bottom:12px;padding-bottom:10px;border-bottom:1px dashed #EDECEA;}
/* Journey items in reader */
.jr-item{display:flex;gap:7px;margin-bottom:9px;align-items:flex-start;}
.jr-num{width:18px;height:18px;border-radius:50%;background:#012851;color:#fff;display:flex;align-items:center;justify-content:center;font-size:7px;font-weight:700;flex-shrink:0;margin-top:1px;}
.jr-card{flex:1;background:#fff;border:1px solid #E4E2D7;border-radius:4px;padding:7px 9px;}
.jr-card-title{font-family:Georgia,serif;font-size:9px;color:#012851;line-height:1.3;margin-bottom:2px;font-weight:400;}
.jr-card-meta{font-size:6.5px;color:#6B6A63;margin-bottom:5px;}
.jr-card-link{font-size:7px;font-weight:600;color:#012851;display:flex;align-items:center;gap:2px;}
.jr-annotation{margin-top:6px;padding:5px 7px;border-left:2px solid var(--mint);background:#F5F4EE;border-radius:0 3px 3px 0;}
.jr-annotation-text{font-size:7.5px;font-style:italic;color:#6B6A63;line-height:1.55;}
.jr-interlude{margin:10px 0 10px 25px;padding:7px 9px;border-left:2px solid var(--orange);background:var(--orange-tint);border-radius:0 4px 4px 0;}
.jr-interlude-text{font-size:8px;font-style:italic;color:#1C1C18;line-height:1.65;}
/* Mobile list row */
.m-row{padding:9px 10px;border-bottom:1px solid #F0EFE9;background:#fff;}
.m-row-top{display:flex;align-items:center;gap:5px;margin-bottom:3px;}
.m-author-name{font-size:7px;font-weight:700;color:#1C1C18;}
.m-date{font-size:6.5px;color:#6B6A63;margin-left:auto;}
.m-title{font-family:Georgia,serif;font-size:10px;color:#012851;line-height:1.4;margin-bottom:2px;}
.m-excerpt{font-size:7px;color:#6B6A63;line-height:1.5;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
.m-filters{display:flex;gap:4px;padding:6px 10px;background:var(--color-page);border-bottom:1px solid #EDECEA;overflow-x:auto;flex-wrap:nowrap;}
.m-filters::-webkit-scrollbar{display:none;}
/* Mobile journey reader */
.mjr-article{background:#fff;border-radius:6px;padding:12px 12px 16px;}
.mjr-back{font-size:7px;color:#6B6A63;margin-bottom:7px;display:flex;align-items:center;gap:2px;}
.mjr-badge{display:inline-flex;padding:1px 5px;border-radius:3px;font-size:5.5px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;background:var(--orange-tint);color:var(--orange-dark);border:1px solid #F0C99A;margin-bottom:4px;}
.mjr-title{font-family:Georgia,serif;font-size:14px;font-weight:400;color:#012851;line-height:1.3;margin-bottom:6px;}
.mjr-metabar{display:flex;align-items:center;gap:5px;padding-bottom:6px;border-bottom:1px solid #EDECEA;margin-bottom:8px;}
.mjr-intro{font-family:Georgia,serif;font-size:8px;line-height:1.7;color:#6B6A63;font-style:italic;margin-bottom:9px;padding-bottom:7px;border-bottom:1px dashed #EDECEA;}
.mjr-item{display:flex;gap:5px;margin-bottom:7px;align-items:flex-start;}
.mjr-num{width:14px;height:14px;border-radius:50%;background:#012851;color:#fff;display:flex;align-items:center;justify-content:center;font-size:6px;font-weight:700;flex-shrink:0;margin-top:1px;}
.mjr-card{flex:1;background:#F5F4EE;border:1px solid #E4E2D7;border-radius:4px;padding:5px 7px;}
.mjr-card-title{font-family:Georgia,serif;font-size:8.5px;color:#012851;line-height:1.3;margin-bottom:1px;}
.mjr-card-meta{font-size:6px;color:#6B6A63;margin-bottom:4px;}
.mjr-card-link{font-size:6.5px;font-weight:600;color:#012851;}
.mjr-interlude{margin:7px 0 7px 19px;padding:5px 7px;border-left:2px solid var(--orange);background:var(--orange-tint);border-radius:0 3px 3px 0;}
.mjr-interlude-text{font-size:7.5px;font-style:italic;color:#1C1C18;line-height:1.6;}
/* ── Editor topbar (type selector screen) ── */
.ed-topbar{background:#fff;border-bottom:1px solid #e4e2d7;display:flex;align-items:center;padding:0 14px;gap:8px;height:38px;flex-shrink:0;}
.ed-back{width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:9px;color:var(--color-text-muted);flex-shrink:0;}
.ed-title-label{font-family:var(--font-sans);font-size:10px;font-weight:500;color:var(--color-text);flex:1;}
.ed-status-pill{display:inline-flex;align-items:center;padding:2px 7px;border-radius:20px;font-size:8px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;flex-shrink:0;}
.ed-status-draft{background:#F0EFE9;color:#6B6A63;border:1px solid #D8D7D0;}
@media(max-width:900px){.doc{padding:24px 16px 80px;}}
</style>
</head>
<body>
<div class="doc">
<!-- ═══ DOC HEADER ═══ -->
<div class="doc-header">
<div>
<h1>Lesereisen — Reader-Integration</h1>
<p>Typauswahl bei <code>/geschichten/new</code>, Journey-Badge auf der Übersichtsliste und die neue geordnete Leseansicht auf <code>/geschichten/[id]</code> wenn <code>type === 'JOURNEY'</code>. Bestehende Story-Ansichten bleiben unverändert.</p>
</div>
<div class="doc-meta">
Familienarchiv<br/>
<span class="pill pill-o">Final Spec</span><br/>
2026-06-07 &middot; @leonievoss<br/>
<span style="font-size:10px;margin-top:4px;display:inline-block;">Issue #752</span>
</div>
</div>
<!-- ═══ JOURNEY HEADER ═══ -->
<div class="jh jh-o">
<div class="jn">R</div>
<div>
<h2>Lesereisen — Reader</h2>
<p>Alle angemeldeten Familienmitglieder können Lesereisen entdecken und in Briefsequenzen mit Kuratoren-Notizen eintauchen. BLOG_WRITERs sehen zusätzlich Bearbeiten/Löschen-Aktionen.</p>
<div class="fl">/geschichten &middot; /geschichten/new &middot; /geschichten/[id]</div>
</div>
</div>
<!-- ═══ KONZEPT ═══ -->
<div class="section">
<div class="section-title">Konzept</div>
<p class="prose">Eine <em>Lesereise</em> ist eine <code>Geschichte</code> mit <code>type === 'JOURNEY'</code>. Ihr Kerninhalt ist eine geordnete Sequenz von Briefen (<code>JourneyItem</code>s mit <code>document_id</code>) und Zwischentexten (<code>JourneyItem</code>s ohne <code>document_id</code>). Das optionale Feld <code>body</code> dient als Einleitung/Preface.</p>
<p class="prose">Diese Spec deckt drei Änderungen ab: (1) die Typauswahl auf <code>/geschichten/new</code> als vorgelagerter Schritt, (2) das „REISE"-Badge in der Übersichtsliste, und (3) die neue Journey-Leseansicht auf der Detailseite, die den bestehenden Prosa-Body durch eine nummerierte Briefliste ersetzt.</p>
<p class="prose">Dokument-Items zeigen Titel, Datum, Sender→Empfänger und einen Link zum Brief. Optionale Kuratoren-Notizen erscheinen als Annotation mit Mint-Linker-Rand unter dem Briefeintrag. Interlude-Items (kein Dokument) erscheinen als eingerückte Absätze mit orangenem linken Rand — klar vom Dokumenttyp unterscheidbar, aber harmonisch im Lesefluss.</p>
</div>
<!-- ═══ SCREEN LR-0: TYPE SELECTOR ═══ -->
<div class="section">
<div class="section-title">Screens — Typauswahl</div>
<div class="scr">
<div class="scr-head">
<h3>LR-0 — Typauswahl /geschichten/new</h3>
<span class="scr-id">Issue #752 · LR-0</span>
</div>
<p class="scr-desc">Neuer vorgelagerter Schritt beim Erstellen einer Geschichte. Zwei Karten zur Auswahl: „Geschichte" (Prosa) und „Lesereise" (Briefsequenz). Die ausgewählte Karte wird hervorgehoben. Erst nach Auswahl wird der „Weiter"-Button aktiv. Auswahl bleibt im URL-Param erhalten (<code>?type=JOURNEY</code>).</p>
<p class="scr-var"><strong>Varianten:</strong> Keine Auswahl (Weiter-Button inaktiv) · Lesereise gewählt (hier gezeigt) · Geschichte gewählt</p>
<div class="previews">
<div class="prev-col" style="width:100%;max-width:1040px;">
<span class="bp-lbl">Desktop — 1040px · Lesereise gewählt</span>
<div class="desk" style="min-height:320px;">
<div class="fa-nav">
<span class="fa-logo">ARCHIV</span>
<span style="width:1px;height:14px;background:rgba(255,255,255,.1);margin:0 2px;"></span>
<span class="fa-link">Dokumente</span>
<span class="fa-link">Personen</span>
<span class="fa-link active">Geschichten</span>
<span class="fa-link">Chronik</span>
<div class="fa-nav-r">
<div class="fa-av" style="background:#012851;color:var(--mint);font-size:5px;font-weight:800;">MR</div>
</div>
</div>
<div class="ed-topbar">
<div class="ed-back">&#8592;</div>
<div class="ed-title-label">Neue Geschichte</div>
<div class="ed-status-pill ed-status-draft">ENTWURF</div>
</div>
<div class="type-selector">
<div class="type-selector-inner">
<div class="type-selector-q">Was möchtest du erstellen?</div>
<div class="type-cards">
<!-- Story card -->
<div class="type-card">
<div class="type-card-icon">✍️</div>
<div class="type-card-title">Geschichte</div>
<div class="type-card-desc">Freier Prosatext über Familienerlebnisse, Erinnerungen oder historische Einordnungen — mit verlinkten Personen und Dokumenten.</div>
</div>
<!-- Journey card (selected) -->
<div class="type-card selected">
<div class="type-card-icon">📜</div>
<div class="type-card-title">Lesereise</div>
<div class="type-card-desc">Geordnete Briefsequenz mit optionalen Kuratoren-Notizen zwischen den Briefen — für chronologische Korrespondenz-Sammlungen.</div>
<div class="type-card-check">
<svg viewBox="0 0 10 10" fill="none"><path d="M2 5l2.5 2.5L8 3" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
</div>
</div>
</div>
</div>
<div class="type-next-bar">
<button class="type-next-btn">
Weiter
<svg width="7" height="7" viewBox="0 0 10 10" fill="none"><path d="M4 2l4 3-4 3" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
</button>
</div>
</div>
</div>
</div>
<div class="agent">
<h4>impl-ref — LR-0 Typauswahl</h4>
<table class="at">
<thead><tr><th>Element</th><th>Wert</th><th>Hinweise</th></tr></thead>
<tbody>
<tr class="grp"><td colspan="3">Layout</td></tr>
<tr><td>Selector area</td><td>flex flex-1 items-center justify-center bg-canvas px-6 py-10</td><td>zentriert, füllt restliche Höhe</td></tr>
<tr><td>Frage</td><td>font-serif text-sm text-ink-2 text-center mb-4</td><td></td></tr>
<tr><td>Karten-Grid</td><td>flex gap-4</td><td>2 gleich breite Karten; auf Mobile flex-col</td></tr>
<tr class="grp"><td colspan="3">Type-Karte</td></tr>
<tr><td>Karte (inaktiv)</td><td>border border-line rounded-md p-4 bg-white cursor-pointer hover:border-primary hover:bg-surface</td><td>focus-visible:ring-2 focus-visible:ring-primary</td></tr>
<tr><td>Karte (ausgewählt)</td><td>border-2 border-orange-500 bg-orange-50 shadow-sm</td><td>aria-pressed="true"; kein Tailwind-Kürzel — nutze CSS-var(--orange)</td></tr>
<tr><td>Check-Kreis</td><td>w-5 h-5 rounded-full bg-orange-500 flex items-center justify-center self-end mt-2</td><td>nur sichtbar wenn ausgewählt</td></tr>
<tr><td>Kartentitel</td><td>font-serif text-sm text-ink</td><td></td></tr>
<tr><td>Kartenbeschreibung</td><td>text-xs text-ink-3 leading-relaxed mt-1</td><td></td></tr>
<tr class="grp"><td colspan="3">Navigation</td></tr>
<tr><td>Weiter-Button</td><td>rounded border border-primary bg-primary text-white px-4 py-2 text-sm font-medium disabled:opacity-40</td><td>disabled wenn keine Karte ausgewählt</td></tr>
<tr><td>URL-Param</td><td>?type=STORY | ?type=JOURNEY</td><td>per goto() nach Klick auf Weiter; lesefreundlich bookmarkbar</td></tr>
<tr><td>Mobile</td><td>flex-col Karten; volle Breite</td><td>kein Scrollbedarf auf 320px</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- ═══ SCREEN LR-1: LIST WITH BADGE ═══ -->
<div class="section">
<div class="section-title">Screens — Übersichtsliste</div>
<div class="scr">
<div class="scr-head">
<h3>LR-1 — Reise-Badge in /geschichten</h3>
<span class="scr-id">Issue #752 · LR-1</span>
</div>
<p class="scr-desc">Die Übersichtsliste erhält ein kleines „REISE"-Badge in der Metaspalte einer Journey-Zeile — unterhalb von Datum und Personenchip. Zeilen mit <code>type === 'STORY'</code> bleiben unverändert. Das Badge ist nicht klickbar, dient als reine visuelle Unterscheidung.</p>
<p class="scr-var"><strong>Varianten:</strong> Mischte Liste (hier gezeigt) · Nur-Journey-Filter · Nur-Story-Ansicht (unverändert)</p>
<div class="previews">
<!-- Desktop -->
<div class="prev-col" style="width:100%;max-width:1040px;">
<span class="bp-lbl">Desktop — 1040px · gemischte Liste</span>
<div class="desk">
<div class="fa-nav">
<span class="fa-logo">ARCHIV</span>
<span style="width:1px;height:14px;background:rgba(255,255,255,.1);margin:0 2px;"></span>
<span class="fa-link">Dokumente</span>
<span class="fa-link">Personen</span>
<span class="fa-link active">Geschichten</span>
<span class="fa-link">Chronik</span>
<div class="fa-nav-r">
<div class="fa-av" style="background:#012851;color:var(--mint);font-size:5px;font-weight:800;">MR</div>
</div>
</div>
<div style="background:#E8E7E2;flex:1;padding:14px 16px;">
<div class="g-page-hdr" style="padding:0 0 8px;">
<span class="g-page-title">Geschichten</span>
<button class="g-new-btn">
<svg width="7" height="7" viewBox="0 0 10 10" fill="none"><path d="M5 1v8M1 5h8" stroke="#fff" stroke-width="2" stroke-linecap="round"/></svg>
Neue Geschichte
</button>
</div>
<div class="g-list-card">
<div class="g-filters">
<span class="g-pill active">Alle</span>
<span class="g-pill">Franz Raddatz</span>
<span class="g-pill">Emma Müller</span>
<span class="g-pill" style="border-style:dashed;color:#6B6A63;">+ Person wählen</span>
</div>
<!-- Row 1: Story (no badge) -->
<div class="g-row">
<div class="g-meta">
<div class="g-av av-navy">MR</div>
<div class="g-author">Maria Raddatz</div>
<div class="g-date">14. März 2025</div>
<span class="g-chip">
<span style="width:8px;height:8px;border-radius:50%;background:#012851;display:inline-flex;align-items:center;justify-content:center;font-size:4.5px;font-weight:800;color:var(--mint);flex-shrink:0;">FR</span>
Franz Raddatz
</span>
</div>
<div class="g-content">
<div class="g-title">Der Sommer in Breslau</div>
<div class="g-excerpt">Oma erzählte oft vom letzten Sommer vor dem Krieg, als die Familie noch vollständig zusammen war und niemand ahnte, was kommen würde…</div>
</div>
</div>
<!-- Row 2: Journey (badge!) -->
<div class="g-row">
<div class="g-meta">
<div class="g-av av-purple">KR</div>
<div class="g-author">Klaus Raddatz</div>
<div class="g-date">15. Mai 2025</div>
<span class="g-chip">
<span style="width:8px;height:8px;border-radius:50%;background:#012851;display:inline-flex;align-items:center;justify-content:center;font-size:4.5px;font-weight:800;color:var(--mint);flex-shrink:0;">FR</span>
Franz Raddatz
</span>
<span class="j-badge">REISE</span>
</div>
<div class="g-content">
<div class="g-title">Briefe aus Breslau 19381942</div>
<div class="g-excerpt">Eine Lesereise durch den Briefwechsel zwischen Franz und Emma — von den letzten Friedenssommern bis zum Ende des Krieges.</div>
</div>
</div>
<!-- Row 3: Story -->
<div class="g-row">
<div class="g-meta">
<div class="g-av av-teal">GK</div>
<div class="g-author">Gertrud Koch</div>
<div class="g-date">18. Okt. 2024</div>
<span class="g-chip">
<span style="width:8px;height:8px;border-radius:50%;background:#534AB7;display:inline-flex;align-items:center;justify-content:center;font-size:4.5px;font-weight:800;color:#fff;flex-shrink:0;">EM</span>
Emma Müller
</span>
</div>
<div class="g-content">
<div class="g-title">Die Hochzeit im Krieg</div>
<div class="g-excerpt">1943, mitten im Chaos — Emma bestand darauf, dass das Fest stattfand. Ihr Bruder kam auf Fronturlaub, drei Tage nur, aber es reichte…</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Mobile -->
<div class="prev-col">
<span class="bp-lbl">Mobile — 320px</span>
<div class="phone">
<div class="pst"><b>9:41</b><span>&#9679;&#9679;&#9679;</span></div>
<div class="pb">
<div class="m-nav">
<span class="m-logo">ARCHIV</span>
<div class="m-nav-r">
<div class="m-av">MR</div>
<div class="m-ham"><span></span><span></span><span></span></div>
</div>
</div>
<div style="background:#E8E7E2;flex:1;display:flex;flex-direction:column;">
<div style="padding:8px 10px 4px;">
<span style="font-family:Georgia,serif;font-size:13px;color:#012851;">Geschichten</span>
</div>
<div class="m-filters">
<span class="g-pill active" style="font-size:6px;padding:2px 7px;">Alle</span>
<span class="g-pill" style="font-size:6px;padding:2px 7px;">Franz Raddatz</span>
<span class="g-pill" style="font-size:6px;padding:2px 7px;border-style:dashed;">+ Person…</span>
</div>
<div style="background:#fff;flex:1;">
<!-- Story row -->
<div class="m-row">
<div class="m-row-top">
<div class="g-av av-navy" style="width:16px;height:16px;font-size:5.5px;">MR</div>
<span class="m-author-name">Maria Raddatz</span>
<span class="m-date">14. Mrz. 2025</span>
</div>
<div class="m-title">Der Sommer in Breslau</div>
<div class="m-excerpt">Oma erzählte oft vom letzten Sommer vor dem Krieg…</div>
</div>
<!-- Journey row (badge) -->
<div class="m-row">
<div class="m-row-top">
<div class="g-av av-purple" style="width:16px;height:16px;font-size:5.5px;">KR</div>
<span class="m-author-name">Klaus Raddatz</span>
<span class="m-date">15. Mai 2025</span>
</div>
<div style="display:flex;align-items:center;gap:5px;margin-bottom:3px;">
<div class="m-title" style="margin-bottom:0;">Briefe aus Breslau 19381942</div>
<span class="j-badge" style="flex-shrink:0;">REISE</span>
</div>
<div class="m-excerpt">Eine Lesereise durch den Briefwechsel zwischen Franz und Emma…</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="agent">
<h4>impl-ref — LR-1 Journey-Badge in der Liste</h4>
<table class="at">
<thead><tr><th>Element</th><th>Wert</th><th>Hinweise</th></tr></thead>
<tbody>
<tr class="grp"><td colspan="3">Badge</td></tr>
<tr><td>Journey badge</td><td>inline-flex items-center px-1.5 py-px rounded-sm text-[10px] font-bold uppercase tracking-wide bg-orange-50 text-orange-700 border border-orange-200</td><td>nur wenn type === 'JOURNEY'</td></tr>
<tr><td>Position Desktop</td><td>unterhalb Datum-Text und Personenchip in der Metaspalte (g-meta)</td><td>kein extra Abstand nötig — gap-1 der Flex-Spalte reicht</td></tr>
<tr><td>Position Mobile</td><td>inline flex items-center gap-1.5 neben Titel</td><td>Titel + Badge in einem flex-Wrapper; badge shrink-0</td></tr>
<tr><td>aria-label</td><td>aria-label="Lesereise"</td><td>Badge ist span, kein interaktives Element</td></tr>
<tr class="grp"><td colspan="3">Bedingte Logik</td></tr>
<tr><td>Svelte guard</td><td>{#if geschichte.type === 'JOURNEY'}&lt;span …&gt;REISE&lt;/span&gt;{/if}</td><td>kein Badge für STORY</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- ═══ SCREEN LR-2: JOURNEY READER ═══ -->
<div class="section">
<div class="section-title">Screens — Journey-Leseansicht</div>
<div class="scr">
<div class="scr-head">
<h3>LR-2 — Journey-Detail /geschichten/[id]</h3>
<span class="scr-id">Issue #752 · LR-2</span>
</div>
<p class="scr-desc">Wenn <code>type === 'JOURNEY'</code> ersetzt die geordnete Briefliste den Prosa-Body. Optional zeigt ein Einleitungsabsatz (<code>body</code>) vor den Items. Jedes Item ist entweder ein Briefeintrag (Kartentitel, Datum, Link) oder ein Interlude-Absatz (orangener linker Rand, kursiv). Die Reihenfolge ergibt sich von oben nach unten — keine Nummern. Briefeinträge können eine optionale Kuratoren-Annotation unter dem Link zeigen.</p>
<p class="scr-var"><strong>Varianten:</strong> Leserin ohne Schreibrecht · BLOG_WRITER (Bearbeiten/Löschen sichtbar — hier gezeigt) · Mobile</p>
<div class="previews">
<!-- Desktop -->
<div class="prev-col" style="width:100%;max-width:1040px;">
<span class="bp-lbl">Desktop — 1040px · BLOG_WRITER-Ansicht</span>
<div class="desk" style="min-height:600px;">
<div class="fa-nav">
<span class="fa-logo">ARCHIV</span>
<span style="width:1px;height:14px;background:rgba(255,255,255,.1);margin:0 2px;"></span>
<span class="fa-link">Dokumente</span>
<span class="fa-link">Personen</span>
<span class="fa-link active">Geschichten</span>
<span class="fa-link">Chronik</span>
<div class="fa-nav-r">
<div class="fa-av" style="background:#012851;color:var(--mint);font-size:5px;font-weight:800;">MR</div>
</div>
</div>
<div style="background:#E8E7E2;flex:1;padding:16px 20px;">
<div class="jr-article">
<div class="jr-back">
<svg width="7" height="7" viewBox="0 0 10 10" fill="none"><path d="M6 2L2 5l4 3" stroke="#6B6A63" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
Zurück zu Geschichten
</div>
<div class="jr-badge">LESEREISE</div>
<div class="jr-title">Briefe aus Breslau 19381942</div>
<div class="jr-metabar">
<div class="g-av av-purple" style="width:20px;height:20px;font-size:6.5px;">KR</div>
<div>
<div style="font-size:7.5px;font-weight:700;color:#1C1C18;line-height:1.2;">Klaus Raddatz</div>
<div style="font-size:6.5px;color:#6B6A63;">zusammengestellt am 15. Mai 2025</div>
</div>
<div class="jr-metabar-r">
<button class="jr-edit-btn">Bearbeiten</button>
<span style="font-size:6.5px;font-weight:600;color:#DC4C3E;">Löschen</span>
</div>
</div>
<!-- Intro -->
<div class="jr-intro">Der Briefwechsel zwischen Franz Raddatz und seiner Schwester Emma umspannt vier Jahre — von den letzten unbeschwerten Sommerwochen 1938 bis zum Kriegsende. Diese Lesereise folgt den Briefen in chronologischer Reihenfolge.</div>
<!-- Item 1: Document, no annotation -->
<div class="jr-item">
<div class="jr-card">
<div class="jr-card-title">Brief vom 12. Juli 1938</div>
<div class="jr-card-meta">12. Juli 1938 &middot; von Franz Raddatz an Emma Müller</div>
<div class="jr-card-link">
<svg width="8" height="8" viewBox="0 0 10 12" fill="none"><rect x="1" y="1" width="8" height="10" rx="1" stroke="#012851" stroke-width="1"/><path d="M3 4h4M3 6.5h4M3 9h2" stroke="#012851" stroke-width=".7" stroke-linecap="round"/></svg>
Brief öffnen
<svg width="7" height="7" viewBox="0 0 10 10" fill="none"><path d="M4 2l4 3-4 3" stroke="#012851" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
</div>
</div>
<!-- Interlude -->
<div class="jr-interlude">
<div class="jr-interlude-text">Im Sommer 1938 schrieb Franz voller Zuversicht — er hatte kaum eine Ahnung, wie bald sich die Welt um ihn herum verändern würde. Seine Briefe aus dieser Zeit tragen eine Leichtigkeit, die in den späteren Kriegsjahren vollständig verschwindet.</div>
</div>
<!-- Item 2: Document with annotation -->
<div class="jr-item">
<div class="jr-card">
<div class="jr-card-title">Postkarte aus Breslau, August 1938</div>
<div class="jr-card-meta">22. Aug. 1938 &middot; von Franz Raddatz an Emma Müller</div>
<div class="jr-card-link">
<svg width="8" height="8" viewBox="0 0 10 12" fill="none"><rect x="1" y="1" width="8" height="10" rx="1" stroke="#012851" stroke-width="1"/><path d="M3 4h4M3 6.5h4M3 9h2" stroke="#012851" stroke-width=".7" stroke-linecap="round"/></svg>
Brief öffnen
<svg width="7" height="7" viewBox="0 0 10 10" fill="none"><path d="M4 2l4 3-4 3" stroke="#012851" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<div class="jr-annotation">
<div class="jr-annotation-text">Diese Karte ist ungewöhnlich kurz für Franz — vier Zeilen, fast hastig. Ein Zeichen der aufkommenden Unruhe in den Nachrichten, oder schlicht die Hitze des Augusts?</div>
</div>
</div>
</div>
<!-- Item 3: Document -->
<div class="jr-item">
<div class="jr-card">
<div class="jr-card-title">Brief vom 3. September 1939</div>
<div class="jr-card-meta">3. Sept. 1939 &middot; von Emma Müller an Franz Raddatz</div>
<div class="jr-card-link">
<svg width="8" height="8" viewBox="0 0 10 12" fill="none"><rect x="1" y="1" width="8" height="10" rx="1" stroke="#012851" stroke-width="1"/><path d="M3 4h4M3 6.5h4M3 9h2" stroke="#012851" stroke-width=".7" stroke-linecap="round"/></svg>
Brief öffnen
<svg width="7" height="7" viewBox="0 0 10 10" fill="none"><path d="M4 2l4 3-4 3" stroke="#012851" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Mobile -->
<div class="prev-col">
<span class="bp-lbl">Mobile — 320px · Leserin</span>
<div class="phone" style="min-height:520px;">
<div class="pst"><b>9:41</b><span>&#9679;&#9679;&#9679;</span></div>
<div class="pb">
<div class="m-nav">
<span class="m-logo">ARCHIV</span>
<div class="m-nav-r">
<div class="m-av">MR</div>
<div class="m-ham"><span></span><span></span><span></span></div>
</div>
</div>
<div style="background:#E8E7E2;flex:1;padding:10px;">
<div class="mjr-article">
<div class="mjr-back">
<svg width="6" height="6" viewBox="0 0 10 10" fill="none"><path d="M6 2L2 5l4 3" stroke="#6B6A63" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
Zurück
</div>
<div class="mjr-badge">LESEREISE</div>
<div class="mjr-title">Briefe aus Breslau 19381942</div>
<div class="mjr-metabar">
<div class="g-av av-purple" style="width:16px;height:16px;font-size:5.5px;flex-shrink:0;">KR</div>
<div>
<div style="font-size:7px;font-weight:700;color:#1C1C18;">Klaus Raddatz</div>
<div style="font-size:6px;color:#6B6A63;">15. Mai 2025</div>
</div>
<div style="margin-left:auto;font-size:12px;color:#6B6A63;">···</div>
</div>
<div style="height:1px;background:#EDECEA;margin-bottom:8px;"></div>
<div class="mjr-intro">Der Briefwechsel zwischen Franz und Emma — von 1938 bis Kriegsende.</div>
<!-- Item 1 -->
<div class="mjr-item">
<div class="mjr-card">
<div class="mjr-card-title">Brief vom 12. Juli 1938</div>
<div class="mjr-card-meta">12. Juli 1938 · Franz → Emma</div>
<div class="mjr-card-link">Brief öffnen →</div>
</div>
</div>
<!-- Interlude -->
<div class="mjr-interlude">
<div class="mjr-interlude-text">Im Sommer 1938 schrieb Franz voller Zuversicht — er hatte kaum eine Ahnung, wie bald sich die Welt um ihn herum verändern würde.</div>
</div>
<!-- Item 2 -->
<div class="mjr-item">
<div class="mjr-card">
<div class="mjr-card-title">Postkarte Aug. 1938</div>
<div class="mjr-card-meta">22. Aug. 1938 · Franz → Emma</div>
<div class="mjr-card-link">Brief öffnen →</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="agent">
<h4>impl-ref — LR-2 Journey-Leseansicht</h4>
<table class="at">
<thead><tr><th>Element</th><th>Wert</th><th>Hinweise</th></tr></thead>
<tbody>
<tr class="grp"><td colspan="3">Seitenstruktur</td></tr>
<tr><td>Bedingte Logik</td><td>{#if geschichte.type === 'JOURNEY'} JourneyReader {:else} StoryReader {/if}</td><td>in +page.svelte von /geschichten/[id]</td></tr>
<tr><td>Artikel-Container</td><td>max-w-3xl mx-auto px-4 py-8</td><td>gleich wie StoryReader</td></tr>
<tr><td>Journey-Badge</td><td>inline-flex px-2 py-px rounded-sm text-[10px] font-bold uppercase tracking-widest bg-orange-50 text-orange-700 border border-orange-200 mb-2</td><td>über dem Titel; nicht für STORY</td></tr>
<tr><td>Titel</td><td>font-serif text-3xl text-ink leading-tight mb-4</td><td>gleich wie Story</td></tr>
<tr><td>Metabar</td><td>flex items-center gap-3 pb-4 border-b border-subtle mb-4</td><td>gleich wie Story</td></tr>
<tr><td>Bearbeiten/Löschen</td><td>nur BLOG_WRITE; auf Mobile im ··· BottomSheet</td><td>gleich wie Story</td></tr>
<tr class="grp"><td colspan="3">Intro-Absatz</td></tr>
<tr><td>Intro (body)</td><td>font-serif text-sm text-ink-2 italic leading-relaxed mb-6 pb-4 border-b border-dashed border-subtle</td><td>nur rendern wenn body nicht leer; kein HTML-Rendering — plaintext</td></tr>
<tr class="grp"><td colspan="3">Dokument-Item</td></tr>
<tr><td>Item-Zeile</td><td>mb-3</td><td>kein flex nötig — Karte ist full-width</td></tr>
<tr><td>Dokumentkarte</td><td>bg-white border border-line rounded-sm p-3</td><td></td></tr>
<tr><td>Brieftitel</td><td>font-serif text-sm text-ink leading-snug mb-0.5</td><td>document.title</td></tr>
<tr><td>Briefmeta</td><td>text-xs text-ink-3 mb-2</td><td>formatDate(document.documentDate) · "von X an Y"</td></tr>
<tr><td>Brief öffnen Link</td><td>inline-flex items-center gap-1 text-xs font-semibold text-ink hover:text-primary</td><td>href="/documents/{item.document.id}"</td></tr>
<tr class="grp"><td colspan="3">Kuratoren-Annotation</td></tr>
<tr><td>Annotation</td><td>mt-3 pl-3 border-l-2 border-mint bg-surface rounded-r-sm py-1.5 pr-2</td><td>nur rendern wenn item.note vorhanden</td></tr>
<tr><td>Annotations-Text</td><td>text-xs italic text-ink-2 leading-relaxed</td><td></td></tr>
<tr class="grp"><td colspan="3">Interlude-Item</td></tr>
<tr><td>Interlude-Block</td><td>pl-3 border-l-2 border-orange-400 bg-orange-50 rounded-r-sm py-2 pr-3 my-4</td><td>item.document === null</td></tr>
<tr><td>Interlude-Text</td><td>text-xs italic text-ink leading-relaxed</td><td>item.note; plaintext</td></tr>
<tr class="grp"><td colspan="3">Mobile</td></tr>
<tr><td>··· Menü</td><td>ml-auto text-ink-3; öffnet BottomSheet mit Bearbeiten + Löschen</td><td>BLOG_WRITE; gleich wie Story</td></tr>
<tr><td>Touch Target (Brief öffnen)</td><td>min-h-[44px] durch padding auf der Karte</td><td>WCAG 2.2 AA</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- ═══ LLM IMPLEMENTATION GUIDE ═══ -->
<div class="llm">
<h2>Implementation Guide — Lesereisen Reader</h2>
<h3>Geänderte Views und Routen</h3>
<table>
<thead><tr><th>View</th><th>Route</th><th>Änderung</th></tr></thead>
<tbody>
<tr><td>Neue Geschichte</td><td>/geschichten/new</td><td>Neuer Typauswahl-Schritt als first render; setzt ?type=STORY|JOURNEY</td></tr>
<tr><td>Geschichten-Liste</td><td>/geschichten</td><td>Journey-Badge in GeschichtenCard wenn type === 'JOURNEY'</td></tr>
<tr><td>Geschichte-Detail</td><td>/geschichten/[id]</td><td>Bedingte Verzweigung: JourneyReader | StoryReader</td></tr>
</tbody>
</table>
<h3>Neue Komponenten</h3>
<ul>
<li><code>JourneyReader.svelte</code> — rendert Intro + Items-Liste; Props: <code>geschichte: GeschichteDetail</code></li>
<li><code>JourneyItemCard.svelte</code> — ein Dokument-Item mit optionaler Annotation; Props: <code>item: JourneyItem, position: number</code></li>
<li><code>JourneyInterlude.svelte</code> — ein reiner Text-Interlude; Props: <code>note: string</code></li>
</ul>
<h3>Datenmodell (nach #750)</h3>
<ul>
<li><code>GeschichteType: 'STORY' | 'JOURNEY'</code></li>
<li><code>JourneyItem: { id: UUID, position: number, document: DocumentSummary | null, note: string | null }</code></li>
<li><code>Geschichte.items</code> — geordnete Liste (nach <code>position</code> ASC); für STORY leer</li>
<li><code>Geschichte.body</code> — für JOURNEY der optionale Einleitungstext (plaintext, kein HTML); für STORY der Rich-Text-Body</li>
</ul>
<h3>Typauswahl — Implementierungshinweise</h3>
<ul>
<li>Die Typauswahl ist ein Schritt INNERHALB der <code>/geschichten/new</code>-Route — kein eigener URL, kein <code>goto()</code>. Zustand <code>let selectedType: GeschichteType | null = null</code> in der Komponente.</li>
<li>Erst wenn <code>selectedType !== null</code> ist der „Weiter"-Button aktiviert (<code>disabled={!selectedType}</code>).</li>
<li>Nach Klick auf „Weiter": wenn <code>selectedType === 'JOURNEY'</code><code>goto('/geschichten/new?type=JOURNEY')</code> und zeige den Journey-Editor (aus Issue #753); wenn <code>STORY</code> → bestehender GeschichteEditor (unverändert).</li>
<li>Die Karten verwenden <code>role="radio"</code> und <code>aria-checked</code> für Accessibility. Keyboard: Arrow-Keys wechseln zwischen den Karten, Space/Enter wählt aus.</li>
</ul>
<h3>Journey-Badge — Implementierungshinweise</h3>
<ul>
<li>Badge nur in <code>GeschichtenCard.svelte</code> hinzufügen — keine Änderung an der Listenlogik oder dem API-Aufruf.</li>
<li>Text: „REISE" (Kurzform für die Metaspalte); <code>aria-label="Lesereise"</code> für den Badge-Span.</li>
</ul>
<h3>Journey-Reader — Implementierungshinweise</h3>
<ul>
<li>Items werden bereits geordnet vom Backend geliefert (<code>ORDER BY position ASC</code>). Keine client-seitige Sortierung nötig.</li>
<li>Ein Item ist Interlude wenn <code>item.document === null</code>. In diesem Fall: <code>JourneyInterlude</code>-Komponente rendern.</li>
<li>Der Intro-Absatz (<code>body</code>) wird als Plaintext gerendert — <em>nicht</em> als innerHTML. Im Editor wird es als einfaches Textarea gespeichert, kein HTML.</li>
</ul>
<h3>Berechtigungen</h3>
<ul>
<li>„Bearbeiten" und „Löschen" nur für <code>currentUser.permissions.includes('BLOG_WRITE')</code> — gleich wie Story.</li>
<li>Auf Mobile: Bearbeiten/Löschen im BottomSheet hinter ··· — gleich wie Story.</li>
</ul>
<h3>Barrierefreiheit</h3>
<ul>
<li>Items-Liste: <code>&lt;ol&gt;</code> semantisch für die geordnete Briefliste. Interludes sind <code>&lt;li&gt;</code>-Elemente mit <code>aria-label="Kuratorennotiz"</code>.</li>
<li>„Brief öffnen"-Link: beschreibender Text mit Briefdatum im <code>aria-label</code>, z.B. <code>aria-label="Brief vom 12. Juli 1938 öffnen"</code>.</li>
<li>Touch-Targets: jede Dokumentkarte hat mindestens 44px Höhe durch den Padding der Karte.</li>
<li>Fokusring: <code>focus-visible:ring-2 focus-visible:ring-primary</code> auf allen Links.</li>
</ul>
</div>
</div>
</body>
</html>