Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die README; an keiner Stelle Bedeutung, nur Zeichensetzung.
996 lines
26 KiB
CSS
996 lines
26 KiB
CSS
@import 'tailwindcss';
|
|
@import './fonts.css';
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Design-Tokens. Fachliche Grundlage: docs/10-design-system.md.
|
|
Bezugspunkt ist eine Registratur im Nachtdienst: lackierter Stahl,
|
|
Aktenpapier, Stempelfarbe. Die einzige Farbe kommt von der Klassifizierung.
|
|
--------------------------------------------------------------------------- */
|
|
|
|
@theme {
|
|
/* Grundpalette, dunkel ist der Auslieferungszustand */
|
|
--color-ink-900: #15181a; /* Grundflaeche, kuehles Anthrazit, leicht gruenstichig */
|
|
--color-ink-800: #1d2124; /* Panel */
|
|
--color-ink-700: #262b2f; /* erhoehte Flaeche, Eingabefelder */
|
|
--color-ink-500: #3a4147; /* Linien und Rahmen */
|
|
--color-paper: #e4e7e4; /* Primaertext, papierfarbenes Off-White */
|
|
--color-paper-dim: #939c99; /* Sekundaertext */
|
|
--color-steel: #7a97a6; /* interaktiv: Links, Fokus, aktive Zustaende */
|
|
|
|
/* Klassifizierungsfarben. Das einzige Buntsystem, nirgends sonst benutzt. */
|
|
--color-stamp-0: #8a918d; /* Offen, Grau */
|
|
--color-stamp-1: #6d8a9c; /* Intern, Stahlblau */
|
|
--color-stamp-2: #4e8f72; /* Vertraulich, Gruenspan */
|
|
--color-stamp-3: #b08637; /* Geheim, Messing */
|
|
--color-stamp-4: #b4543c; /* Streng geheim, Oxidrot */
|
|
--color-stamp-5: #7e5e96; /* Leitungssache, Tiefviolett */
|
|
|
|
/* Semantische Ebene. Das helle Thema tauscht nur diese Werte. */
|
|
--color-surface: var(--color-ink-900);
|
|
--color-panel: var(--color-ink-800);
|
|
--color-raised: var(--color-ink-700);
|
|
--color-line: var(--color-ink-500);
|
|
--color-text: var(--color-paper);
|
|
--color-text-dim: var(--color-paper-dim);
|
|
--color-accent: var(--color-steel);
|
|
|
|
/* Schrift. IBM Plex, selbst gehostet, drei Rollen aus einer Familie. */
|
|
--font-sans: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
|
|
--font-condensed: 'IBM Plex Sans Condensed', 'IBM Plex Sans', ui-sans-serif, sans-serif;
|
|
--font-mono: 'IBM Plex Mono', ui-monospace, monospace;
|
|
|
|
/* Skala 12 / 13 / 15 / 18 / 24 px */
|
|
--text-2xs: 0.75rem; /* 12 */
|
|
--text-xs: 0.8125rem; /* 13 */
|
|
--text-sm: 0.9375rem; /* 15 */
|
|
--text-base: 0.9375rem; /* 15, Fliesstext */
|
|
--text-lg: 1.125rem; /* 18 */
|
|
--text-xl: 1.5rem; /* 24 */
|
|
|
|
--text-2xs--line-height: 1.4;
|
|
--text-xs--line-height: 1.45;
|
|
--text-sm--line-height: 1.6;
|
|
--text-base--line-height: 1.6;
|
|
--text-lg--line-height: 1.45;
|
|
--text-xl--line-height: 1.3;
|
|
|
|
/* Struktur: Flaechen bleiben eckig, Bedienelemente sind rund.
|
|
Eine Akte ist ein Blatt und hat scharfe Kanten. Was man druecken oder
|
|
ausfuellen kann, ist rund - daran erkennt man es, bevor man es beruehrt. */
|
|
--radius-none: 0px;
|
|
--radius-sm: 2px;
|
|
--radius-DEFAULT: 2px;
|
|
--radius-md: 2px;
|
|
--radius-lg: 2px;
|
|
--radius-xl: 2px;
|
|
/* Eingabefelder: weich gerundet. Ein mehrzeiliges Feld kann keine Pille sein. */
|
|
--radius-field: 10px;
|
|
/* Knoepfe, Suchbalken, Marken, Profilbild: voll gerundet. */
|
|
--radius-control: 999px;
|
|
|
|
/* Keine Schatten ausser dem Fokusring. */
|
|
--shadow-sm: none;
|
|
--shadow-DEFAULT: none;
|
|
--shadow-md: none;
|
|
--shadow-lg: none;
|
|
|
|
/* Zeilenlaenge hoechstens 72 Zeichen */
|
|
--container-measure: 72ch;
|
|
|
|
/* Die 3 px breite Klassifizierungskante links am Objekt */
|
|
--spacing-edge: 3px;
|
|
}
|
|
|
|
/* Helles Thema.
|
|
*
|
|
* Es tauscht **nur die semantische Ebene**, nie die Grundpalette und nie die
|
|
* Klassifizierungsfarben: eine Stufe muss in beiden Themen dieselbe Farbe
|
|
* haben, sonst lernt man sie zweimal. Siehe docs/10-design-system.md.
|
|
*
|
|
* Kein warmes Cremeweiss, sondern ein leicht kühles Papierweiss - dieselbe
|
|
* Anmutung wie das dunkle Thema, nur andersherum. Die Kontraste sind auf
|
|
* mindestens 4,5:1 für Fliesstext ausgelegt. */
|
|
[data-theme='light'] {
|
|
--color-surface: #eceeea;
|
|
--color-panel: #e2e5e1;
|
|
--color-raised: #f7f8f5;
|
|
--color-line: #b0b6ae;
|
|
--color-text: #1b1f21;
|
|
--color-text-dim: #4d5551;
|
|
--color-accent: #35586a;
|
|
}
|
|
|
|
/* Die Klassifizierungsfarben sind für hellen Grund eine Spur dunkler, damit
|
|
Stempel und Kante lesbar bleiben. Der Farbton bleibt derselbe. */
|
|
[data-theme='light'] {
|
|
--color-stamp-0: #6b716d;
|
|
--color-stamp-1: #4a6577;
|
|
--color-stamp-2: #34694f;
|
|
--color-stamp-3: #856024;
|
|
--color-stamp-4: #8d3c28;
|
|
--color-stamp-5: #5c4270;
|
|
}
|
|
|
|
/* Ohne ausdrückliche Wahl folgt die Anwendung dem System. Der Auslieferungs-
|
|
zustand bleibt dunkel: `prefers-color-scheme: light` muss gesetzt sein. */
|
|
@media (prefers-color-scheme: light) {
|
|
:root:not([data-theme='dark']) {
|
|
--color-surface: #eceeea;
|
|
--color-panel: #e2e5e1;
|
|
--color-raised: #f7f8f5;
|
|
--color-line: #b0b6ae;
|
|
--color-text: #1b1f21;
|
|
--color-text-dim: #4d5551;
|
|
--color-accent: #35586a;
|
|
--color-stamp-0: #6b716d;
|
|
--color-stamp-1: #4a6577;
|
|
--color-stamp-2: #34694f;
|
|
--color-stamp-3: #856024;
|
|
--color-stamp-4: #8d3c28;
|
|
--color-stamp-5: #5c4270;
|
|
}
|
|
}
|
|
|
|
@layer base {
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
border-color: var(--color-line);
|
|
}
|
|
|
|
html {
|
|
color-scheme: dark;
|
|
background-color: var(--color-surface);
|
|
}
|
|
|
|
[data-theme='light'] {
|
|
color-scheme: light;
|
|
}
|
|
|
|
body {
|
|
background-color: var(--color-surface);
|
|
color: var(--color-text);
|
|
font-family: var(--font-sans);
|
|
font-size: var(--text-base);
|
|
line-height: 1.6;
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
|
|
/* Spaltenkoepfe, Stempel und Reiter tragen den schmalen Schnitt.
|
|
Kein Versalsatz: der Stempelcharakter kommt aus Schnitt, Rahmen und Farbe. */
|
|
th,
|
|
legend {
|
|
font-family: var(--font-condensed);
|
|
font-weight: 500;
|
|
text-transform: none;
|
|
}
|
|
|
|
/* Aktenzeichen, Zeitstempel, Hashes und Dienstnummern in Mono. */
|
|
code,
|
|
kbd,
|
|
samp,
|
|
time {
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3 {
|
|
font-weight: 500;
|
|
text-wrap: balance;
|
|
}
|
|
|
|
h1 {
|
|
font-size: var(--text-xl);
|
|
}
|
|
h2 {
|
|
font-size: var(--text-lg);
|
|
}
|
|
h3 {
|
|
font-size: var(--text-base);
|
|
}
|
|
|
|
a {
|
|
color: var(--color-accent);
|
|
text-underline-offset: 2px;
|
|
}
|
|
|
|
/* Auch Kaestchen und Schalter gehoeren zur interaktiven Ebene. */
|
|
input[type='checkbox'],
|
|
input[type='radio'] {
|
|
accent-color: var(--color-accent);
|
|
}
|
|
|
|
/* Sichtbarer Fokusring in --steel, der einzige Schatten im System. */
|
|
:focus-visible {
|
|
outline: 2px solid var(--color-accent);
|
|
outline-offset: 2px;
|
|
border-radius: 2px;
|
|
}
|
|
|
|
::selection {
|
|
background-color: color-mix(in srgb, var(--color-accent) 40%, transparent);
|
|
}
|
|
}
|
|
|
|
@layer components {
|
|
/* ---------------------------------------------------------------------
|
|
Bedienelemente.
|
|
|
|
Zwei Regeln, beide aus dem Betrieb heraus:
|
|
|
|
**Ein Knopf muss vor der Beruehrung als Knopf erkennbar sein.** Deshalb
|
|
traegt jeder einen Rahmen und eine eigene Grundflaeche, auch der
|
|
unscheinbarste. Ein Text, der sich erst beim Ueberfahren als Knopf
|
|
entpuppt, wird nicht gefunden.
|
|
|
|
**Und er muss beim Druecken zurueckmelden, dass er getroffen wurde.**
|
|
Beim Druecken zieht sich der Knopf leicht zusammen und bekommt einen
|
|
inneren Ring - er wirkt kurz dicker, ohne dass sich die Rahmenbreite
|
|
wirklich aendert, sonst wuerde das Umfeld springen. Die Rueckmeldung
|
|
setzt ohne Verzoegerung ein und klingt langsam ab: ein kurzer Klick
|
|
bliebe sonst unsichtbar. Siehe docs/10-design-system.md.
|
|
--------------------------------------------------------------------- */
|
|
.btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 0.4rem;
|
|
border: 1px solid var(--color-line);
|
|
border-radius: var(--radius-control);
|
|
background-color: var(--color-raised);
|
|
color: var(--color-text);
|
|
padding: 0.35rem 0.95rem;
|
|
font-family: var(--font-condensed);
|
|
font-size: var(--text-xs);
|
|
line-height: 1.45;
|
|
text-align: center;
|
|
text-decoration: none;
|
|
white-space: nowrap;
|
|
cursor: pointer;
|
|
/* Abklingen langsam, damit der Druck sichtbar bleibt. */
|
|
transition:
|
|
background-color 240ms ease-out,
|
|
border-color 240ms ease-out,
|
|
color 240ms ease-out,
|
|
transform 240ms ease-out,
|
|
box-shadow 240ms ease-out;
|
|
}
|
|
|
|
.btn:hover:not(:disabled):not([aria-disabled='true']) {
|
|
background-color: var(--color-panel);
|
|
border-color: var(--color-accent);
|
|
color: var(--color-accent);
|
|
transition-duration: 90ms;
|
|
}
|
|
|
|
.btn:active:not(:disabled):not([aria-disabled='true']) {
|
|
transform: scale(0.96);
|
|
border-color: var(--color-accent);
|
|
box-shadow: inset 0 0 0 1.5px var(--color-accent);
|
|
/* Sofort einsetzen, damit auch ein schneller Klick sichtbar wird. */
|
|
transition-duration: 0ms;
|
|
}
|
|
|
|
.btn:disabled,
|
|
.btn[aria-disabled='true'] {
|
|
color: var(--color-text-dim);
|
|
border-style: dashed;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* Der Knopf, der die Sache erledigt. Einer je Formular, nie zwei. */
|
|
.btn-primary {
|
|
color: var(--color-accent);
|
|
border-color: var(--color-accent);
|
|
}
|
|
|
|
.btn-primary:hover:not(:disabled) {
|
|
background-color: color-mix(in srgb, var(--color-accent) 14%, var(--color-raised));
|
|
}
|
|
|
|
/* Fuer dichte Zeilen: Etikettenleisten, Werkzeuge an einem Eintrag. */
|
|
.btn-sm {
|
|
padding: 0.22rem 0.75rem;
|
|
font-size: var(--text-2xs);
|
|
}
|
|
|
|
/* Ein Knopf, dessen Zustand er selbst ist: Etikett an oder aus,
|
|
Reaktion gesetzt oder nicht, Reiter offen oder nicht. */
|
|
.btn[aria-current='page'],
|
|
.btn[aria-pressed='true'] {
|
|
/* Der gefuellte Zustand traegt hellen Text, nicht die Akzentfarbe: auf der
|
|
getoenten Flaeche waere Akzent auf Akzent, und der Kontrast faellt unter
|
|
die Untergrenze aus docs/10-design-system.md. */
|
|
background-color: color-mix(in srgb, var(--color-accent) 26%, var(--color-raised));
|
|
border-color: var(--color-accent);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
.btn[aria-current='page']:hover,
|
|
.btn[aria-pressed='true']:hover {
|
|
color: var(--color-text);
|
|
background-color: color-mix(in srgb, var(--color-accent) 34%, var(--color-raised));
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
Die Zeile einer Liste.
|
|
|
|
Jede Liste in dieser Anwendung zeigt dasselbe Gebilde: eine Kennung, ein
|
|
Titel, etwas Beiwerk, eine Stempelmarke. Bisher bestimmte **jede Zeile
|
|
ihre Spaltenbreiten selbst** - die Kennung war so breit wie ihr Text, und
|
|
damit fing der Titel in jeder Zeile woanders an. Bei „ETHIK" und „WS"
|
|
untereinander sieht man das sofort.
|
|
|
|
Die Breiten stehen deshalb hier und nicht an den Aufrufstellen. Sie sind
|
|
Variablen: eine Liste von Abteilungskuerzeln braucht keine vierzehn
|
|
Zeichen, eine Liste von Aktenzeichen schon. Was gleich bleibt, ist dass
|
|
**innerhalb einer Liste** alles buendig steht.
|
|
--------------------------------------------------------------------- */
|
|
.record-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: baseline;
|
|
column-gap: 1rem;
|
|
row-gap: 0.25rem;
|
|
}
|
|
|
|
/* Die Kennung: Aktenzeichen, Dokumentnummer, Abteilungskuerzel. Mono mit
|
|
Tabellenziffern, damit auch die Ziffern untereinander stehen. */
|
|
.record-key {
|
|
flex: none;
|
|
width: var(--record-key, 14ch);
|
|
overflow: hidden;
|
|
font-family: var(--font-mono);
|
|
font-size: var(--text-xs);
|
|
font-variant-numeric: tabular-nums;
|
|
color: var(--color-text-dim);
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Wie die Kennung, aber fuer eine Bezeichnung aus einer festen Liste:
|
|
die Rolle eines Beteiligten, die Art eines Auftrags. Kein Mono - es ist
|
|
Sprache, keine Nummer. */
|
|
.record-label {
|
|
flex: none;
|
|
width: var(--record-label, 11rem);
|
|
overflow: hidden;
|
|
font-family: var(--font-condensed);
|
|
font-size: var(--text-2xs);
|
|
color: var(--color-text-dim);
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Der Dienstgrad vor einem Namen. In derselben Groesse wie der Name, denn
|
|
er gehoert zu ihm - aber in einer eigenen Spalte, sonst faengt jeder Name
|
|
woanders an. */
|
|
.record-rank {
|
|
flex: none;
|
|
width: var(--record-rank, 6rem);
|
|
overflow: hidden;
|
|
font-size: var(--text-sm);
|
|
color: var(--color-text-dim);
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Der Titel nimmt den Rest. `min-width: 0` ist noetig, damit ein langer
|
|
Titel die Zeile nicht aufblaeht, statt zu kuerzen. */
|
|
.record-title {
|
|
flex: 1 1 10rem;
|
|
min-width: 0;
|
|
}
|
|
|
|
/* Beiwerk am rechten Rand: Status, Datum, Anzahl. Rechtsbuendig, damit die
|
|
Spalte eine Kante hat. */
|
|
.record-meta {
|
|
flex: none;
|
|
width: var(--record-meta, 7rem);
|
|
font-family: var(--font-condensed);
|
|
font-size: var(--text-2xs);
|
|
color: var(--color-text-dim);
|
|
text-align: right;
|
|
}
|
|
|
|
/* Auf schmalen Schirmen gibt es keine Spalten, nur noch Zeilen. Feste
|
|
Breiten wuerden dort ueberlaufen. */
|
|
@media (max-width: 40rem) {
|
|
.record-key,
|
|
.record-label,
|
|
.record-rank,
|
|
.record-meta {
|
|
width: auto;
|
|
text-align: left;
|
|
}
|
|
}
|
|
|
|
/* Die Stempelmarke: ueberall gleich breit, siehe components/StampMark.tsx. */
|
|
.stamp-mark {
|
|
display: inline-flex;
|
|
flex: none;
|
|
align-items: center;
|
|
gap: 0.375rem;
|
|
width: var(--stamp-width, 11.5rem);
|
|
max-width: 100%;
|
|
border: 1px solid;
|
|
border-radius: var(--radius-control);
|
|
padding: 0.1rem 0.6rem;
|
|
font-family: var(--font-condensed);
|
|
font-size: var(--text-2xs);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.stamp-name {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Der Ladepunkt in einem Link, solange der Wechsel laeuft. Kein Kreisel:
|
|
eine ruhig pulsierende Scheibe in der Groesse eines Satzzeichens, die
|
|
nichts verdeckt und nichts aufhaelt. */
|
|
.pending-dot {
|
|
display: inline-block;
|
|
width: 0.45rem;
|
|
height: 0.45rem;
|
|
flex: none;
|
|
border-radius: var(--radius-control);
|
|
background-color: currentColor;
|
|
animation: pending-pulse 900ms ease-in-out infinite;
|
|
}
|
|
|
|
@keyframes pending-pulse {
|
|
0%,
|
|
100% {
|
|
opacity: 0.25;
|
|
transform: scale(0.75);
|
|
}
|
|
50% {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
/* Die Zahl in einem Knopf: eine Angabe, kein Teil der Beschriftung. Sie
|
|
sitzt deshalb ruhiger und in Mono. */
|
|
.btn-count {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.9em;
|
|
color: var(--color-text-dim);
|
|
}
|
|
|
|
.btn[aria-current='page'] .btn-count {
|
|
color: var(--color-text);
|
|
}
|
|
|
|
/* Waehrend eine Aktion laeuft. Kein Spinner, nur ein ruhiger Zustand:
|
|
der Knopf bleibt stehen, wo er ist, und nimmt keine zweite Eingabe an. */
|
|
.btn[aria-busy='true'] {
|
|
color: var(--color-text-dim);
|
|
border-style: dashed;
|
|
cursor: progress;
|
|
}
|
|
|
|
/* Eingabefelder. Weich gerundet statt voll: ein mehrzeiliges Feld als
|
|
Pille waere unlesbar. */
|
|
.field {
|
|
border: 1px solid var(--color-line);
|
|
border-radius: var(--radius-field);
|
|
background-color: var(--color-raised);
|
|
color: var(--color-text);
|
|
padding: 0.4rem 0.7rem;
|
|
font-family: inherit;
|
|
font-size: var(--text-sm);
|
|
line-height: 1.5;
|
|
transition:
|
|
border-color 120ms ease-out,
|
|
background-color 120ms ease-out;
|
|
}
|
|
|
|
.field:hover:not(:disabled) {
|
|
border-color: var(--color-accent);
|
|
}
|
|
|
|
.field:disabled {
|
|
color: var(--color-text-dim);
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------
|
|
Beschriftung und Bedienelement.
|
|
|
|
Der Abstand dazwischen war kleiner als die Polsterung **innerhalb** des
|
|
Feldes, und genau daran erkennt das Auge einen zu engen Satz: das Wort
|
|
steht naeher am Rahmen als der Inhalt des Rahmens an demselben Rahmen,
|
|
also wirkt es angeklebt. Die Regel daraus: **der Abstand nach aussen ist
|
|
groesser als die Polsterung nach innen.**
|
|
|
|
Deshalb stehen beide Werte hier und nicht an den Aufrufstellen. Sie waren
|
|
dort ein Dutzend Mal von Hand gesetzt, mit drei verschiedenen Werten, und
|
|
keiner davon reichte. Siehe docs/10-design-system.md.
|
|
------------------------------------------------------------------- */
|
|
.field-label {
|
|
display: block;
|
|
/* Mehr als die 0.4rem Polsterung des Feldes nach oben und unten. */
|
|
margin-block-end: 0.5rem;
|
|
font-family: var(--font-condensed);
|
|
font-size: var(--text-2xs);
|
|
line-height: 1.4;
|
|
color: var(--color-text-dim);
|
|
}
|
|
|
|
/* Beschriftung daneben statt darueber. Waagerecht braucht es mehr Luft als
|
|
senkrecht: das Feld polstert innen 0.7rem, aussen sind es 0.85rem. */
|
|
.field-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 0.85rem;
|
|
font-family: var(--font-condensed);
|
|
font-size: var(--text-2xs);
|
|
color: var(--color-text-dim);
|
|
}
|
|
|
|
/* Der Hinweis unter einem Feld gehoert naeher an das Feld als an das
|
|
naechste. */
|
|
.field-hint {
|
|
display: block;
|
|
margin-block-start: 0.4rem;
|
|
font-size: var(--text-2xs);
|
|
line-height: 1.45;
|
|
color: var(--color-text-dim);
|
|
}
|
|
|
|
/* Einzeilige Felder, die wie ein Knopf aussehen duerfen: Suchbalken,
|
|
Schnellfilter. */
|
|
.field-pill {
|
|
border-radius: var(--radius-control);
|
|
padding-inline: 0.9rem;
|
|
}
|
|
|
|
select.field {
|
|
padding-block: 0.35rem;
|
|
}
|
|
|
|
/* Steckt das Bild in einem Knopf, traegt der Knopf den Rahmen. Zwei
|
|
ineinander waeren ein Doppelring. */
|
|
.btn > .avatar {
|
|
border: 0;
|
|
}
|
|
|
|
/* Das Profilbild oben rechts und ueberall sonst, wo eine Person auftaucht. */
|
|
.avatar {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex: none;
|
|
border: 1px solid var(--color-line);
|
|
border-radius: var(--radius-control);
|
|
background-color: var(--color-raised);
|
|
color: var(--color-text-dim);
|
|
font-family: var(--font-condensed);
|
|
overflow: hidden;
|
|
object-fit: cover;
|
|
}
|
|
|
|
/* Der eine mutige Moment: die Schwaerzung. Ein massiver Balken mit feiner
|
|
Rahmenlinie, der beim ersten Erscheinen einmal von links nach rechts
|
|
durchwischt. Sonst bewegt sich in der Oberflaeche nichts von selbst. */
|
|
.redaction {
|
|
display: inline-block;
|
|
position: relative;
|
|
overflow: hidden;
|
|
vertical-align: baseline;
|
|
background-color: var(--color-ink-900);
|
|
border: 1px solid var(--color-line);
|
|
border-radius: 2px;
|
|
color: transparent;
|
|
user-select: none;
|
|
}
|
|
|
|
.redaction::after {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
background-color: var(--color-ink-700);
|
|
transform-origin: left center;
|
|
animation: redaction-wipe 150ms ease-out 1 both;
|
|
}
|
|
|
|
@keyframes redaction-wipe {
|
|
from {
|
|
transform: scaleX(1);
|
|
}
|
|
to {
|
|
transform: scaleX(0);
|
|
}
|
|
}
|
|
|
|
/* Zeitachse des Verlaufs: durchgehende senkrechte Linie. Der Chat hat keine.
|
|
Der Unterschied muss ohne Beschriftung erkennbar sein. */
|
|
.timeline {
|
|
position: relative;
|
|
padding-left: 1.5rem;
|
|
}
|
|
|
|
.timeline::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0.4375rem;
|
|
top: 0;
|
|
bottom: 0;
|
|
width: 1px;
|
|
background-color: var(--color-line);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
Das Aktenblatt.
|
|
|
|
Bewusst **ausserhalb** des Design-Systems der Oberflaeche: schwarz auf
|
|
weiss, harte Rahmen, Massangaben in Millimetern. Es ist kein Bildschirm-
|
|
element, sondern ein Formular, das gedruckt und weitergereicht wird und
|
|
auf Papier genauso aussehen muss wie hier. Deshalb steht hier kein
|
|
einziger Farb-Token der Anwendung.
|
|
|
|
Nachgebaut nach dem Formular, das die Personalabteilung bislang von Hand
|
|
ausgefuellt hat. Siehe docs/13-entscheidungen.md.
|
|
--------------------------------------------------------------------- */
|
|
.sheet {
|
|
width: 210mm;
|
|
min-height: 297mm;
|
|
box-sizing: border-box;
|
|
margin: 0 auto;
|
|
padding: 10mm;
|
|
background: #ffffff;
|
|
color: #000000;
|
|
font-family: var(--font-sans, sans-serif);
|
|
}
|
|
|
|
.sheet-frame {
|
|
border: 4px solid #000;
|
|
min-height: calc(297mm - 20mm);
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.sheet-head {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
padding: 15px;
|
|
border-bottom: 4px solid #000;
|
|
}
|
|
|
|
.sheet-head h1 {
|
|
margin: 0 0 5px;
|
|
font-size: 28px;
|
|
font-weight: 900;
|
|
letter-spacing: 1px;
|
|
line-height: 1.1;
|
|
text-transform: uppercase;
|
|
color: #000;
|
|
}
|
|
|
|
.sheet-head h2 {
|
|
margin: 0;
|
|
font-size: 14px;
|
|
font-weight: 900;
|
|
letter-spacing: 2px;
|
|
text-transform: uppercase;
|
|
color: #000;
|
|
}
|
|
|
|
.sheet-mark {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-end;
|
|
gap: 10px;
|
|
}
|
|
|
|
/* Rein dekorativ, deshalb aria-hidden im Markup. */
|
|
.sheet-barcode {
|
|
width: 140px;
|
|
height: 25px;
|
|
background: repeating-linear-gradient(
|
|
90deg,
|
|
#000,
|
|
#000 2px,
|
|
#fff 2px,
|
|
#fff 5px,
|
|
#000 5px,
|
|
#000 8px,
|
|
#fff 8px,
|
|
#fff 10px
|
|
);
|
|
}
|
|
|
|
.sheet-classbar {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
padding: 10px 15px;
|
|
border-bottom: 4px solid #000;
|
|
color: #fff;
|
|
font-size: 14px;
|
|
font-weight: 900;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.sheet-grid {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
table-layout: fixed;
|
|
}
|
|
|
|
.sheet-grid td {
|
|
border: 2px solid #000;
|
|
padding: 10px;
|
|
vertical-align: top;
|
|
word-wrap: break-word;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.sheet-label {
|
|
font-size: 10px;
|
|
font-weight: 900;
|
|
text-transform: uppercase;
|
|
margin-bottom: 4px;
|
|
color: #000;
|
|
}
|
|
|
|
.sheet-value {
|
|
font-size: 14px;
|
|
font-weight: 700;
|
|
min-height: 20px;
|
|
color: #000;
|
|
}
|
|
|
|
.sheet-value-emphasis {
|
|
color: #7f1d1d;
|
|
}
|
|
|
|
.sheet-photo {
|
|
width: 120px;
|
|
height: 160px;
|
|
margin: 0 auto;
|
|
border: 2px solid #000;
|
|
background: #f0f0f0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-align: center;
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
color: #555;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.sheet-photo img {
|
|
position: absolute;
|
|
inset: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.sheet-signature {
|
|
border-bottom: 2px solid #000;
|
|
min-height: 30px;
|
|
display: flex;
|
|
align-items: flex-end;
|
|
font-family: 'Times New Roman', Times, serif;
|
|
font-style: italic;
|
|
font-size: 18px;
|
|
color: #000;
|
|
}
|
|
|
|
.sheet-foot {
|
|
margin-top: auto;
|
|
border-top: 4px solid #000;
|
|
padding: 10px 15px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
font-family: var(--font-mono, monospace);
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
color: #000;
|
|
}
|
|
|
|
/* Schmale Fenster: das Blatt behaelt seine Proportionen und wird als Ganzes
|
|
verkleinert, statt umzubrechen. Ein umgebrochenes Formular waere ein
|
|
anderes Formular. */
|
|
@media (max-width: 230mm) {
|
|
.sheet-scroll {
|
|
overflow-x: auto;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
Die Druckansicht einer Akte.
|
|
|
|
Schwarz auf weiss wie das Aktenblatt, aber im Aufbau eines Berichts:
|
|
Deckblatt, Kopfdaten, Abschnitte, Verlauf, Anhangsverzeichnis. Das
|
|
Wasserzeichen setzt der PDF-Dienst in Kopf- und Fusszeile jeder Seite.
|
|
|
|
Ein Export darf nie sauberer aussehen als die Akte ist: geänderte
|
|
Einträge sind gekennzeichnet, zurückgezogene stehen als Grabstein, und
|
|
gesperrte Felder erscheinen als Balken mit Vermerk statt zu fehlen.
|
|
Siehe docs/08-suche-und-export.md.
|
|
--------------------------------------------------------------------- */
|
|
/* Der Grund unter einer Druckansicht.
|
|
Ohne ihn liegt ein weisses Blatt auf dem dunklen Thema der Anwendung, und
|
|
die Ansicht sieht kaputt aus, obwohl sie stimmt. Beim Drucken faellt er
|
|
weg - Papier bringt seinen eigenen Grund mit. */
|
|
.print-page {
|
|
min-height: 100dvh;
|
|
background: #f2f2f0;
|
|
}
|
|
|
|
.print-sheet {
|
|
max-width: 180mm;
|
|
margin: 0 auto;
|
|
padding: 12mm 0;
|
|
background: #fff;
|
|
color: #000;
|
|
font-size: 10pt;
|
|
line-height: 1.45;
|
|
/* Am Bildschirm auf schmalen Geraeten: die Tabellen darin scrollen in
|
|
sich, statt die Seite breiter zu machen. Auf Papier greift das nicht. */
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.print-meta {
|
|
min-width: 0;
|
|
}
|
|
|
|
.print-sheet h1 {
|
|
font-size: 18pt;
|
|
font-weight: 900;
|
|
margin: 0 0 2mm;
|
|
color: #000;
|
|
}
|
|
|
|
.print-sheet h2 {
|
|
font-size: 12pt;
|
|
font-weight: 900;
|
|
margin: 8mm 0 2mm;
|
|
padding-bottom: 1mm;
|
|
border-bottom: 1.5pt solid #000;
|
|
color: #000;
|
|
break-after: avoid;
|
|
}
|
|
|
|
.print-sheet h3 {
|
|
font-size: 10pt;
|
|
font-weight: 900;
|
|
margin: 4mm 0 1mm;
|
|
color: #000;
|
|
break-after: avoid;
|
|
}
|
|
|
|
.print-cover {
|
|
border: 3pt solid #000;
|
|
padding: 8mm;
|
|
margin-bottom: 8mm;
|
|
}
|
|
|
|
.print-stamp {
|
|
display: inline-block;
|
|
border: 2pt solid #000;
|
|
padding: 1mm 3mm;
|
|
font-weight: 900;
|
|
letter-spacing: 1pt;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.print-meta {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 3mm;
|
|
}
|
|
|
|
.print-meta th,
|
|
.print-meta td {
|
|
border: 0.75pt solid #000;
|
|
padding: 1.5mm 2mm;
|
|
text-align: left;
|
|
vertical-align: top;
|
|
font-size: 9pt;
|
|
}
|
|
|
|
.print-meta th {
|
|
width: 38mm;
|
|
font-weight: 900;
|
|
}
|
|
|
|
/* Ein Eintrag soll nicht über den Seitenrand zerrissen werden. */
|
|
.print-entry {
|
|
break-inside: avoid;
|
|
padding: 2mm 0;
|
|
border-bottom: 0.5pt dotted #666;
|
|
}
|
|
|
|
.print-label {
|
|
font-size: 8pt;
|
|
font-weight: 900;
|
|
text-transform: uppercase;
|
|
color: #000;
|
|
}
|
|
|
|
.print-note {
|
|
font-size: 8pt;
|
|
color: #444;
|
|
}
|
|
|
|
/* Die Schwärzung im Druck: ein voller Balken, kein Weglassen. */
|
|
.print-redacted {
|
|
display: inline-block;
|
|
min-width: 30mm;
|
|
background: #000;
|
|
color: #000;
|
|
user-select: none;
|
|
}
|
|
}
|
|
|
|
/* Drucken: nur das Blatt, ohne Rahmenwerk der Anwendung. Kopf- und Fusszeile
|
|
mit dem Wasserzeichen setzt der PDF-Dienst, siehe docs/08. */
|
|
@media print {
|
|
.no-print {
|
|
display: none !important;
|
|
}
|
|
|
|
body {
|
|
background: #fff !important;
|
|
}
|
|
|
|
.sheet {
|
|
margin: 0;
|
|
padding: 0;
|
|
width: auto;
|
|
}
|
|
|
|
.sheet-frame {
|
|
min-height: auto;
|
|
}
|
|
|
|
.sheet-classbar,
|
|
.print-redacted,
|
|
.print-stamp {
|
|
/* Sonst drucken die Flächen weiss auf weiss. */
|
|
print-color-adjust: exact;
|
|
-webkit-print-color-adjust: exact;
|
|
}
|
|
|
|
.print-sheet {
|
|
max-width: none;
|
|
padding: 0;
|
|
}
|
|
|
|
.print-page {
|
|
min-height: 0;
|
|
background: #fff;
|
|
}
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.redaction::after {
|
|
animation: none;
|
|
transform: scaleX(0);
|
|
}
|
|
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
animation-duration: 0.01ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.01ms !important;
|
|
}
|
|
}
|