Version 1.4.0

Designframework

Token, Grundstile und Komponenten für alle Projekte auf jsengenberger.de — CSS ohne Abhängigkeit und eine Kartenkomponente, in Hell und Dunkel geprüft.

Einbinden

<link rel="stylesheet" href="https://static.jsengenberger.de/v1/framework.css">

Grundlagen

Farben

Jede Farbe hat eine Aufgabe. Die Felder folgen dem Thema — schalte oben um und sieh, was sich ändert.

Marke

--color-primary
--color-primary-light
--color-primary-dark
--color-primary-text

Status

--color-success
--color-warning
--color-error
--color-info

Flächen

--bg-primary
--bg-secondary
--bg-tertiary

Text

--text-primary
--text-secondary
--text-tertiary
--text-muted

Linien

--border-color-light
--border-color
--border-color-dark

Karte

--map-land
--map-water
--map-green
--map-building
--map-road

Kartenkategorien

--map-cat-1
--map-cat-2
--map-cat-3
--map-cat-4
--map-cat-5
--map-cat-6

Schrift

Systemschrift, kein Webfont. 9 Größen, keine dazwischen.

  • --font-familySystemschriftPrüfbericht, 148 KB
  • --font-family-monoFestbreiteword/people.xml
  • --font-size-4xl36 pxVerbindlich für alle Projekte
  • --font-size-3xl30 pxVerbindlich für alle Projekte
  • --font-size-2xl24 pxVerbindlich für alle Projekte
  • --font-size-xl20 pxVerbindlich für alle Projekte
  • --font-size-lg18 pxVerbindlich für alle Projekte
  • --font-size-base16 pxVerbindlich für alle Projekte
  • --font-size-sm14 pxVerbindlich für alle Projekte
  • --font-size-xs12 pxVerbindlich für alle Projekte
  • --font-size-2xs10 pxVerbindlich für alle Projekte

Abstände

Jeder Abstand im Framework ist eine dieser Stufen.

  • --spacing-2xs2 px
  • --spacing-xs4 px
  • --spacing-sm8 px
  • --spacing-md16 px
  • --spacing-lg24 px
  • --spacing-xl32 px
  • --spacing-2xl48 px
  • --spacing-3xl64 px

Radien

Von der Haarkante bis zur Pille.

xs
sm
md
lg
xl
full

Alle Token

Die vollständige Liste, 122 Einträge. Maßgeblich ist immer 01-tokens.css.

Liste anzeigen
TokenWert (helles Thema)
--color-primary#e75421
--color-primary-light#f16a3e
--color-primary-dark#c64419
--color-primary-rgb231, 84, 33
--color-primary-alphargba(231, 84, 33, 0.1)
--color-primary-ink#ffffff
--color-primary-fillvar(--color-primary-dark)
--color-primary-fill-hover#a8380f
--color-primary-text#b83d16
--color-success#66bb6a
--color-success-light#81c784
--color-success-dark#4caf50
--color-success-alphargba(102, 187, 106, 0.1)
--color-warning#ff9800
--color-warning-light#ffb74d
--color-warning-dark#f57c00
--color-warning-alphargba(255, 152, 0, 0.1)
--color-success-ink#1a1a1a
--color-warning-ink#1a1a1a
--color-error#ef5350
--color-error-light#e57373
--color-error-dark#e53935
--color-error-alphargba(239, 83, 80, 0.1)
--color-error-ink#ffffff
--color-error-fill#c62828
--color-error-fill-hover#b71c1c
--color-info#2196f3
--color-info-light#64b5f6
--color-info-dark#1976d2
--color-info-alphargba(33, 150, 243, 0.1)
--bg-primary#ffffff
--bg-secondary#f8f9fa
--bg-tertiary#e9ecef
--text-primary#2c3e50
--text-secondary#616970
--text-tertiary#808080
--text-muted#adb5bd
--text-inverse#ffffff
--border-color#e0e0e0
--border-color-light#f0f0f0
--border-color-dark#d0d0d0
--hover-bg#f8f9fa
--active-bg#e9ecef
--color-backdroprgba(0, 0, 0, 0.5)
--map-land#f3f4f6
--map-water#cbd8e1
--map-green#e0eadd
--map-building#e4e6e9
--map-road#ffffff
--map-cat-1#7b3fb5
--map-cat-2#00787c
--map-cat-3#b02d7c
--map-cat-4#657315
--map-cat-5#3f4fbf
--map-cat-6#6f6259
--status-success-text#2e7d32
--status-warning-text#8a5300
--status-error-text#c62828
--status-info-text#0d5bb9
--select-arrowurl("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23616970' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")
--shadow-xs0 1px 2px rgba(0, 0, 0, 0.04)
--shadow-sm0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04)
--shadow-md0 4px 6px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.05)
--shadow-lg0 10px 15px rgba(0, 0, 0, 0.08), 0 4px 6px rgba(0, 0, 0, 0.05)
--shadow-xl0 20px 25px rgba(0, 0, 0, 0.1), 0 10px 10px rgba(0, 0, 0, 0.04)
--radius-xs2px
--radius-sm4px
--radius-md8px
--radius-lg12px
--radius-xl16px
--radius-full9999px
--spacing-2xs2px
--spacing-xs4px
--spacing-sm8px
--spacing-md16px
--spacing-lg24px
--spacing-xl32px
--spacing-2xl48px
--spacing-3xl64px
--font-family-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif
--font-family-mono'SF Mono', 'Fira Code', 'Consolas', ui-monospace, monospace
--font-size-2xs0.625rem
--font-size-xs0.75rem
--font-size-sm0.875rem
--font-size-base1rem
--font-size-lg1.125rem
--font-size-xl1.25rem
--font-size-2xl1.5rem
--font-size-3xl1.875rem
--font-size-4xl2.25rem
--font-weight-normal400
--font-weight-medium500
--font-weight-semibold600
--font-weight-bold700
--line-height-tight1.25
--line-height-snug1.375
--line-height-normal1.5
--line-height-relaxed1.625
--letter-spacing-tight-0.025em
--letter-spacing-normal0
--letter-spacing-wide0.025em
--input-height-sm32px
--input-height40px
--input-height-lg48px
--table-field-width14ch
--button-height-sm32px
--button-height40px
--button-height-lg48px
--navbar-height64px
--container-max-width1400px
--container-narrow720px
--focus-ring-colorvar(--color-primary)
--focus-ring-width3px
--focus-ring-offset2px
--transition-fast150ms ease
--transition-normal250ms ease
--transition-slow400ms ease
--z-dropdown100
--z-sticky150
--z-modal-backdrop200
--z-modal250
--z-toast400

Komponenten

Gerüst

Navigationsleiste, Inhaltsbreite und Seitenkopf — der Rahmen, in den jede Ansicht gesetzt wird.

Vier Befunde mit hoher Schwere in zwei Dateien.

Quelltext
<nav class="navbar">
  <div class="navbar__container">
    <a class="navbar__brand" href="/">
      <span class="navbar__mark">A</span>
      <span>Anwendung</span>
    </a>
    <div class="navbar__menu">
      <a class="navbar__link navbar__link--active" href="#">Prüfen</a>
      <a class="navbar__link" href="#">Bereinigen</a>
    </div>
    <div class="navbar__user"><span class="navbar__avatar">J</span> Jens S.</div>
  </div>
</nav>

<main class="container page">
  <header class="page-header">
    <div>
      <h1 class="page-header__title">Prüfbericht</h1>
      <p class="page-header__subtitle">Schriftsatz.docx · 148 KB</p>
    </div>
    <span class="badge badge--danger"><span class="badge__dot"></span>4 hoch</span>
  </header>
  <div class="stack"><p>Vier Befunde mit hoher Schwere in zwei Dateien.</p></div>
</main>

Reiter

Mehrere Ansichten auf einer Seite. Die Leiste haftet unter der Navigation, damit keine Ansicht außer Reichweite rutscht.

Drei Befunde in zwei Dateien.

Quelltext
<div class="stack">
  <div class="tabs" role="tablist" aria-label="Ansichten" id="reiter-beispiel">
    <button class="tabs__tab tabs__tab--active" role="tab" id="tab-uebersicht" aria-selected="true" aria-controls="panel-uebersicht" tabindex="0">Übersicht</button>
    <button class="tabs__tab" role="tab" id="tab-kommentare" aria-selected="false" aria-controls="panel-kommentare" tabindex="-1">Kommentare <span class="badge badge--sm">5</span></button>
  </div>
  <section class="tab-panel" role="tabpanel" id="panel-uebersicht" aria-labelledby="tab-uebersicht"><p>Drei Befunde in zwei Dateien.</p></section>
  <section class="tab-panel" role="tabpanel" id="panel-kommentare" aria-labelledby="tab-kommentare" hidden><p>Fünf Kommentare von zwei Verfassern.</p></section>
</div>
<script type="module">
  import { connectTabs } from "https://static.jsengenberger.de/v1/tabs/tabs.js";
  connectTabs(document.getElementById("reiter-beispiel"));
</script>

Knöpfe

Eine Hauptaktion je Ansicht, alles andere tritt zurück. Feste Höhen halten eine Reihe Knöpfe auf einer Linie.

Quelltext
<div class="row">
<button class="btn btn-primary">Dokument öffnen</button>
<button class="btn btn-secondary">Ansehen</button>
<button class="btn btn-danger">Alles entfernen</button>
<button class="btn btn-ghost">Zurücksetzen</button>
<button class="btn btn-secondary btn-sm">klein</button>
<button class="btn btn-primary btn-lg">groß</button>
<button class="btn btn-primary" disabled>gesperrt</button>
</div>

Badges

Kurze Zustände und Zahlen. Die Farbe trägt die Bedeutung, der Text sagt sie aus.

Hoch Mittel Gering Sauber 70 Befunde
Quelltext
<div class="row">
<span class="badge badge--danger"><span class="badge__dot"></span>Hoch</span>
<span class="badge badge--warning"><span class="badge__dot"></span>Mittel</span>
<span class="badge badge--info"><span class="badge__dot"></span>Gering</span>
<span class="badge badge--success"><span class="badge__dot"></span>Sauber</span>
<span class="badge">70 Befunde</span>
</div>

Karten

Inhalt in einem Rahmen, mit Kopf und Fuß für Titel und Aktionen. Kacheln fassen eine Kennzahl zusammen.

Was gefunden wurde

4 hoch

Autor, Firma und zwei Kommentare mit Namen.

Quelltext
<section class="card">
  <header class="card__header">
    <h2 class="card__header-title">Was gefunden wurde</h2>
    <span class="badge badge--danger">4 hoch</span>
  </header>
  <div class="card__body"><p>Autor, Firma und zwei Kommentare mit Namen.</p></div>
  <footer class="card__footer">
    <button class="btn btn-secondary">Verwerfen</button>
    <button class="btn btn-primary">Auswahl entfernen</button>
  </footer>
</section>
H
4
Hohes Risiko
M
7
Mittleres Risiko
G
12
Geringes Risiko
S
3
Dateien sauber
Quelltext
<div class="grid grid--4">
<div class="stat-card">
  <div class="stat-card__tile stat-card__tile--danger">H</div>
  <div>
    <div class="stat-card__value">4</div>
    <div class="stat-card__label">Hohes Risiko</div>
  </div>
</div>
<div class="stat-card"><div class="stat-card__tile stat-card__tile--warning">M</div><div><div class="stat-card__value">7</div><div class="stat-card__label">Mittleres Risiko</div></div></div>
<div class="stat-card"><div class="stat-card__tile stat-card__tile--info">G</div><div><div class="stat-card__value">12</div><div class="stat-card__label">Geringes Risiko</div></div></div>
<div class="stat-card"><div class="stat-card__tile stat-card__tile--success">S</div><div><div class="stat-card__value">3</div><div class="stat-card__label">Dateien sauber</div></div></div>
</div>
Seite 1
Seite 2
Seite 3
Seite 4
Quelltext
<div class="grid grid--4">
<div class="card is-dragging"><div class="card__body">Seite 1</div></div>
<div class="card is-drop-target" data-side="before"><div class="card__body">Seite 2</div></div>
<div class="card"><div class="card__body">Seite 3</div></div>
<div class="card is-drop-target" data-side="after"><div class="card__body">Seite 4</div></div>
</div>

Formular

Beschriftung über dem Feld, Hinweis oder Fehler darunter — jedes Feld in seiner eigenen Gruppe.

Leer entfernt den Namen vollständig.
Ein Pfad ist als Autorname nicht zulässig.
Quelltext
<div class="form-group">
  <label class="form-label" for="autor">Neuer Autorname</label>
  <input class="form-control" id="autor" placeholder="leer lassen">
  <span class="form-hint">Leer entfernt den Namen vollständig.</span>
</div>

<div class="form-group">
  <label class="form-label" for="pfad">Vorlagenpfad</label>
  <input class="form-control form-control--mono is-invalid" id="pfad" value="C:\Vorlagen\">
  <span class="form-error">Ein Pfad ist als Autorname nicht zulässig.</span>
</div>

<div class="form-group">
  <label class="form-label" for="tiefe">Prüftiefe</label>
  <select class="form-control form-select" id="tiefe"><option>Gründlich</option><option>Schnell</option></select>
</div>

<div class="form-group">
  <label class="form-label" for="notiz">Anmerkung</label>
  <textarea class="form-control form-textarea" id="notiz"></textarea>
</div>
Quelltext
<div class="stack stack--sm">
  <div class="form-check">
    <input class="form-check-input" type="checkbox" id="a" checked>
    <label class="form-check-label" for="a">Autor und Firma entfernen</label>
  </div>
  <div class="form-switch">
    <input class="form-switch-input" type="checkbox" id="roh" checked>
    <label for="roh">Rohansicht</label>
  </div>
</div>
Quelltext
<div class="form-group">
  <label class="form-label" for="wert">Wert in der Datei</label>
  <div class="input-group">
    <input class="form-control form-control--mono" id="wert" value="Dr. Katharina Vogelsang">
    <button class="btn btn-secondary">Leeren</button>
  </div>
</div>

<div class="form-group">
  <label class="form-label" for="anschrift">Anschrift</label>
  <textarea class="form-control form-control--sm form-textarea--grow" id="anschrift" rows="1"></textarea>
</div>

Word-Dokument hierher ziehenWord-Dokument auswählen

oder

Quelltext
<div class="dropzone">
  <p class="empty-state__title"><span class="pointer-only">Word-Dokument hierher ziehen</span><span class="touch-only">Word-Dokument auswählen</span></p>
  <p class="empty-state__text"><span class="pointer-only">oder </span><button class="btn btn-secondary btn-sm">Datei auswählen</button></p>
</div>

Tabelle

Zahlen und Werte in Zeilen. Breite Tabellen scrollen in ihrem eigenen Kasten, nie die Seite.

FundortWertAnzahl
word/people.xmlKatharina Vogelsang218
Quelltext
<div class="table-scroll">
  <table class="table">
    <thead><tr><th>Fundort</th><th>Wert</th><th class="table__num">Anzahl</th></tr></thead>
    <tbody>
      <tr><td class="table__mono">word/people.xml</td><td class="table__mono">Katharina Vogelsang</td><td class="table__num">218</td></tr>
    </tbody>
  </table>
</div>
AutorDr. Katharina Vogelsang
Quelltext
<table class="table">
  <tbody>
    <tr><th class="table__key" scope="row">Autor</th><td class="table__mono">Dr. Katharina Vogelsang</td></tr>
  </tbody>
</table>
Nr.NameZeile entfernen
1
2
Quelltext
<div class="table-scroll">
  <table class="table table--nowrap table--edit">
    <thead><tr><th class="table__num">Nr.</th><th>Name</th><th class="table__actions"><span class="visually-hidden">Zeile entfernen</span></th></tr></thead>
    <tbody>
      <tr><td class="table__num">1</td><td><input class="form-control form-control--sm" aria-label="Name, Zeile 1" value="Vogelsang"></td><td class="table__actions"><button class="btn btn-ghost btn-sm">Entfernen</button></td></tr>
      <tr><td class="table__num">2</td><td><input class="form-control form-control--sm" aria-label="Name, Zeile 2" value="Schulz"></td><td class="table__actions"><button class="btn btn-ghost btn-sm">Entfernen</button></td></tr>
    </tbody>
  </table>
</div>

Vorher/Nachher

Ein geänderter Wert an seinem Platz: der alte durchgestrichen, der neue hervorgehoben, beide mit Wort.

FeldÄnderung
Fristendevorher 12.03.2026 nachher 15.03.2026
Zuständigvorher Amtsgericht Bonn nachher Landgericht Köln, 3. Zivilkammer
Quelltext
<div class="table-scroll">
  <table class="table">
    <thead><tr><th>Feld</th><th>Änderung</th></tr></thead>
    <tbody>
      <tr><th class="table__key" scope="row">Fristende</th><td><span class="diff"><span class="diff__part"><span class="diff__label">vorher</span> <del>12.03.2026</del></span> <span class="diff__part"><span class="diff__label">nachher</span> <ins>15.03.2026</ins></span></span></td></tr>
      <tr><th class="table__key" scope="row">Zuständig</th><td><span class="diff"><span class="diff__part"><span class="diff__label">vorher</span> <del>Amtsgericht Bonn</del></span> <span class="diff__part"><span class="diff__label">nachher</span> <ins>Landgericht Köln, 3. Zivilkammer</ins></span></span></td></tr>
    </tbody>
  </table>
</div>

Hinweisboxen

Eine Meldung, die stehen bleibt, bis man sie gelesen hat — in den vier Statusfarben.

Änderungen annehmen verändert den Inhalt

Das Original bleibt unangetastet.

Bereinigt — keine Metadaten mehr gefunden.

Die Datei ist beschädigt und lässt sich nicht öffnen.

Die Prüfung läuft vollständig im Browser.

Quelltext
<div class="stack stack--sm">
  <div class="alert alert--warning">
    <span class="alert__mark" aria-hidden="true">!</span>
    <div class="alert__content">
      <p class="alert__title">Änderungen annehmen verändert den Inhalt</p>
      <p class="alert__message">Das Original bleibt unangetastet.</p>
    </div>
  </div>
  <div class="alert alert--success">
    <span class="alert__mark" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8.5l3 3 7-7"/></svg></span>
    <div class="alert__content"><p class="alert__title">Bereinigt — keine Metadaten mehr gefunden.</p></div>
  </div>
  <div class="alert alert--danger">
    <span class="alert__mark" aria-hidden="true">!</span>
    <div class="alert__content"><p class="alert__title">Die Datei ist beschädigt und lässt sich nicht öffnen.</p></div>
  </div>
  <div class="alert alert--info">
    <span class="alert__mark" aria-hidden="true">i</span>
    <div class="alert__content"><p class="alert__title">Die Prüfung läuft vollständig im Browser.</p></div>
  </div>
</div>

Aufklappbereich

Einzelheiten, die nicht jeder lesen muss — zu, bis man sie aufklappt.

Einzelheiten zu den Links ansehen (3)
https://example.org/rechnung
https://example.org/konto
https://example.org/hilfe
Quelltext
<details class="disclosure">
  <summary>Einzelheiten zu den Links ansehen (3)</summary>
  <div class="stack stack--sm">
    <div class="list-item">https://example.org/rechnung</div>
    <div class="list-item">https://example.org/konto</div>
    <div class="list-item">https://example.org/hilfe</div>
  </div>
</details>

Erläuterung

Ein „i" neben einem Feld oder Ergebnis öffnet einen kurzen Text — ein Begriff und die Norm, aus der er stammt.

Ein schriftlicher Verwaltungsakt gilt am vierten Tag nach der Aufgabe zur Post als bekannt gegeben (§ 41 Abs. 2 Satz 1 VwVfG).
Quelltext
<div class="form-group">
  <label class="form-label" for="zugang">Bekanntgabe des Bescheids</label>
  <button class="info-btn" type="button" popovertarget="info-zugang" aria-controls="info-zugang" aria-label="Erläuterung: Bekanntgabe">
    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><circle cx="8" cy="8" r="6.25"/><path d="M8 7.25v3.75"/><circle cx="8" cy="5" r="0.5" fill="currentColor"/></svg>
  </button>
  <span class="info-pop" id="info-zugang" popover>Ein schriftlicher Verwaltungsakt gilt am vierten Tag nach der Aufgabe zur Post als bekannt gegeben (§ 41 Abs. 2 Satz 1 VwVfG).</span>
  <input class="form-control" id="zugang" type="date">
</div>

Fortschritt

Wie weit ein Vorgang ist. Die Breite ist der einzige Inline-Stil, den das Framework erlaubt.

Quelltext
<div class="stack stack--sm">
  <div class="progress progress--sm"><div class="progress__fill" style="width: 30%"></div></div>
  <div class="progress"><div class="progress__fill" style="width: 60%"></div></div>
  <div class="progress progress--lg"><div class="progress__fill progress__fill--success" style="width: 100%"></div></div>
</div>

Leerzustand

Was eine Ansicht zeigt, solange es noch nichts zu zeigen gibt — mit dem einen Schritt, der das ändert.

Noch kein Dokument geöffnet

Ziehen Sie eine Word-Datei hierher.

Quelltext
<div class="empty-state">
  <div class="empty-state__mark" aria-hidden="true">∅</div>
  <h2 class="empty-state__title">Noch kein Dokument geöffnet</h2>
  <p class="empty-state__text">Ziehen Sie eine Word-Datei hierher.</p>
  <button class="btn btn-primary">Datei auswählen</button>
</div>

Dialog

Eine Rückfrage, die die Seite anhält. Abbrechen steht zuerst und bekommt den Fokus.

Quelltext
<div class="modal-overlay">
  <div class="modal" role="dialog" aria-modal="true" aria-labelledby="t">
    <header class="modal__header">
      <div>
        <h2 class="modal__title" id="t">Änderungen annehmen?</h2>
        <p class="modal__subtitle">16 Revisionen von drei Personen</p>
      </div>
      <button class="btn btn-ghost btn-sm" aria-label="Schließen">×</button>
    </header>
    <div class="modal__body"><p>Die Revisionen werden übernommen und aus dem Dokument entfernt. Das lässt sich nicht rückgängig machen.</p></div>
    <footer class="modal__footer">
      <button class="btn btn-secondary">Abbrechen</button>
      <button class="btn btn-primary">Annehmen</button>
    </footer>
  </div>
</div>

Code und Werte

Werte aus fremden Dateien in Festbreitenschrift, Fundstellen in den Statusfarben.

Der Wert steht in word/people.xml.

m.schulz@kanzlei.example
Quelltext
<p>Der Wert steht in <code>word/people.xml</code>.</p>

<pre><span class="code-mark--high">m.schulz@kanzlei.example</span></pre>

Landkarte

Eine schlichte Karte in unseren Farben: Straßen einfärben, Marker und Werte setzen, mit Legende und Werkzeugen — ein Modul, kein Markup.

Quelltext
<div id="karte-beispiel"></div>
<script type="module">
  import { createMap } from "https://static.jsengenberger.de/v1/map/map.js";

  const map = await createMap(document.getElementById("karte-beispiel"), {
    label: "Bonn, Innenstadt",
    center: [7.0995, 50.734],
    zoom: 15,
  });
  const innenstadt = [7.09, 50.728, 7.11, 50.74];
  await map.highlightStreet("Poststraße", { area: innenstadt, category: 1, fit: false,
    info: "Vom Hauptbahnhof zum Münsterplatz" });
  await map.highlightStreet("Sternstraße", { area: innenstadt, category: 2, fit: false,
    info: "Fußgängerzone zwischen Friedensplatz und Markt" });
  map.addMarker([7.1029, 50.7351], { label: "Altes Rathaus", info: "Markt 2" });
  map.addMarker([7.0968, 50.732], { label: "Bonn Hauptbahnhof", text: "Hbf", category: 5 });
  map.setLegend({
    title: "Legende",
    toggle: true,
    items: [
      { label: "Poststraße", category: 1 },
      { label: "Sternstraße", category: 2 },
      { label: "Sehenswürdigkeit", kind: "marker" },
      { label: "Bahnhof", kind: "marker", category: 5 },
    ],
  });
</script>

Druck

Ergebnisseiten drucken sauber auf A4: ohne Bedienelemente, in Hell, mit einem Kopf, den es nur auf Papier gibt.

Quelltext
<header class="print-header">
  <p class="print-header__title">Fristenberechnung — Ergebnis</p>
  <dl class="print-header__meta">
    <div><dt>Version</dt><dd>2.1.0</dd></div>
    <div><dt>Stand</dt><dd>01.11.2026</dd></div>
    <div><dt>Erstellt</dt><dd><time datetime="2026-11-01T14:32">01.11.2026, 14:32 Uhr</time></dd></div>
  </dl>
</header>