All checks were successful
Build & Deploy / deploy (push) Successful in 1m14s
Fehler: claude-haiku-4-5 lehnt output_config.effort mit einem 400 ab, jede Karte lief in einen Lesefehler. effort und der server-seitige Fallback werden jetzt nur an Modelle geschickt, die sie annehmen; ein unbekanntes Modell mit engerem Parametersatz wird einmal ohne Zusatzparameter wiederholt, statt die Karte zu verlieren. Tests decken die Zuordnung ab. Design: Grau kommt als Hierarchiestufe dazu. Drei Ebenen für Fläche (weiß / grau gefüllt / schwarz), Text (schwarz / --ink-2 / --ink-3) und Linie (3px / 1px schwarz / graue Haarlinie). Vorher trug alles dieselbe 3px-Kante und dasselbe Schwarz, dadurch war keine Ordnung erkennbar. Konkret: nicht gewählte Filter treten zurück, Listenzeilen bekommen drei Textstufen und Statuspillen statt einer gleichförmigen Zeile, das Kopfband über Listen ist grau hinterlegt, zweitrangige und zerstörende Aktionen sind leiser als die primäre. iOS: Datumsfelder zentrieren ihren Wert und sacken in der Höhe ein. Die WebKit-Pseudoelemente ziehen sie auf die Form der übrigen Felder. Dazu die Domain in der Dokumentation auf scanner.lucas-orth.de. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
492 lines
11 KiB
CSS
492 lines
11 KiB
CSS
/* Schwarzweiss mit Grau als Hierarchiestufe. Harte Kanten, keine Rundungen.
|
|
Mobile first.
|
|
|
|
Drei Ebenen, konsequent durchgehalten:
|
|
Flaeche weiss -> --fill (gruppiert) -> schwarz (das eine Wichtige)
|
|
Text --ink -> --ink-2 (erlaeuternd) -> --ink-3 (Beiwerk)
|
|
Linie 3px schwarz (traegt) -> 1px schwarz (gliedert) -> --rule (trennt) */
|
|
|
|
:root {
|
|
color-scheme: light;
|
|
|
|
--ink: #000;
|
|
--ink-2: #4a4a4a;
|
|
--ink-3: #8a8a8a;
|
|
|
|
--bg: #fff;
|
|
--fill: #f4f4f4;
|
|
--page: #e4e4e4;
|
|
--rule: #d4d4d4;
|
|
|
|
--sans: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
--pad: 18px;
|
|
}
|
|
|
|
* { box-sizing: border-box; }
|
|
|
|
html, body {
|
|
margin: 0;
|
|
padding: 0;
|
|
background: var(--page);
|
|
color: var(--ink);
|
|
font-family: var(--sans);
|
|
font-size: 15px;
|
|
line-height: 1.45;
|
|
-webkit-text-size-adjust: 100%;
|
|
}
|
|
|
|
body { overflow-x: hidden; }
|
|
|
|
button, input, textarea, select {
|
|
font: inherit;
|
|
color: inherit;
|
|
border-radius: 0;
|
|
-webkit-appearance: none;
|
|
appearance: none;
|
|
}
|
|
|
|
a { color: inherit; }
|
|
|
|
/* ------------------------------------------------------------------ Typografie */
|
|
|
|
.display {
|
|
font-weight: 800;
|
|
font-stretch: 85%;
|
|
letter-spacing: -0.025em;
|
|
text-transform: uppercase;
|
|
line-height: 0.94;
|
|
margin: 0;
|
|
}
|
|
|
|
.d-xl { font-size: 42px; }
|
|
.d-lg { font-size: 30px; }
|
|
.d-md { font-size: 19px; letter-spacing: -0.01em; }
|
|
|
|
.label {
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.18em;
|
|
text-transform: uppercase;
|
|
margin: 0;
|
|
}
|
|
|
|
.muted { color: var(--ink-2); }
|
|
.hint { font-size: 12.5px; line-height: 1.5; color: var(--ink-3); }
|
|
.mono-num { font-variant-numeric: tabular-nums; }
|
|
|
|
/* ---------------------------------------------------------------------- Geruest */
|
|
|
|
.app {
|
|
max-width: 560px;
|
|
margin: 0 auto;
|
|
min-height: 100vh;
|
|
background: var(--bg);
|
|
border-left: 1px solid var(--ink);
|
|
border-right: 1px solid var(--ink);
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.topbar {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 20;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
padding: 13px var(--pad);
|
|
background: var(--bg);
|
|
border-bottom: 3px solid var(--ink);
|
|
}
|
|
|
|
.mark {
|
|
width: 32px;
|
|
height: 32px;
|
|
flex: 0 0 32px;
|
|
background: var(--ink);
|
|
display: grid;
|
|
place-items: center;
|
|
}
|
|
|
|
.mark svg { width: 19px; height: 19px; }
|
|
|
|
.wordmark { line-height: 1; }
|
|
.wordmark .d-md { display: block; }
|
|
.wordmark .label { color: var(--ink-3); margin-top: 4px; }
|
|
|
|
.topbar .spacer { margin-left: auto; }
|
|
|
|
main { flex: 1; display: flex; flex-direction: column; }
|
|
.screen { flex: 1; padding: var(--pad) var(--pad) 30px; }
|
|
.screen[hidden] { display: none; }
|
|
|
|
.stack > * + * { margin-top: 12px; }
|
|
.stack-tight > * + * { margin-top: 8px; }
|
|
|
|
/* ---------------------------------------------------------------------- Bloecke */
|
|
|
|
/* Oberste Ebene: das eine Wichtige pro Ansicht. Nur einmal verwenden. */
|
|
.block-invert {
|
|
background: var(--ink);
|
|
color: var(--bg);
|
|
padding: 20px 18px;
|
|
}
|
|
|
|
.block-invert .muted { color: #a9a9a9; }
|
|
.block-invert .label { color: #a9a9a9; }
|
|
|
|
/* Mittlere Ebene: gruppiert, tritt zurueck. */
|
|
.block {
|
|
background: var(--fill);
|
|
border: 1px solid var(--rule);
|
|
padding: 16px;
|
|
}
|
|
|
|
/* Kopfband ueber einer Liste - ordnet zu, konkurriert aber nicht. */
|
|
.strip {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
padding: 11px 14px;
|
|
background: var(--fill);
|
|
border: 1px solid var(--ink);
|
|
border-bottom: none;
|
|
}
|
|
|
|
.strip .label { color: var(--ink-2); }
|
|
|
|
.section-label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin: 34px 0 12px;
|
|
}
|
|
|
|
.section-label .label { color: var(--ink); }
|
|
|
|
.section-label::after {
|
|
content: "";
|
|
flex: 1;
|
|
height: 1px;
|
|
background: var(--rule);
|
|
}
|
|
|
|
.figures {
|
|
display: flex;
|
|
gap: 32px;
|
|
margin-top: 20px;
|
|
padding-top: 16px;
|
|
border-top: 1px solid rgba(255, 255, 255, 0.28);
|
|
}
|
|
|
|
.figure { display: flex; flex-direction: column; }
|
|
.figure .label { margin-bottom: 6px; }
|
|
|
|
/* --------------------------------------------------------------------- Buttons */
|
|
|
|
.btn {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 10px;
|
|
width: 100%;
|
|
padding: 16px;
|
|
background: var(--bg);
|
|
border: 2px solid var(--ink);
|
|
font-weight: 800;
|
|
font-size: 14px;
|
|
letter-spacing: 0.06em;
|
|
text-transform: uppercase;
|
|
text-decoration: none;
|
|
cursor: pointer;
|
|
text-align: left;
|
|
}
|
|
|
|
/* Was man hier tun soll. */
|
|
.btn-primary { background: var(--ink); color: var(--bg); border-color: var(--ink); }
|
|
|
|
/* Vorhanden, aber leise. */
|
|
.btn-quiet {
|
|
border: 1px solid var(--rule);
|
|
color: var(--ink-2);
|
|
font-weight: 700;
|
|
}
|
|
|
|
.btn:disabled { opacity: 0.35; cursor: not-allowed; }
|
|
.btn .arrow { font-weight: 400; font-size: 17px; }
|
|
.btn-quiet .arrow { color: var(--ink-3); }
|
|
|
|
/* --------------------------------------------------------------------- Formular */
|
|
|
|
.field { display: block; }
|
|
.field .label { color: var(--ink-3); margin-bottom: 6px; }
|
|
|
|
.field input,
|
|
.field textarea {
|
|
width: 100%;
|
|
padding: 11px 12px;
|
|
background: var(--bg);
|
|
border: 1px solid var(--ink);
|
|
}
|
|
|
|
.field input:focus,
|
|
.field textarea:focus { outline: 2px solid var(--ink); outline-offset: 1px; }
|
|
|
|
.field textarea { min-height: 88px; resize: vertical; }
|
|
|
|
/* iOS rendert Datumsfelder eigenwillig: der Wert sitzt zentriert, die Hoehe
|
|
sackt ein, der Innenabstand kommt vom System. Das zieht sie auf die Form
|
|
der uebrigen Felder. */
|
|
.field input[type="datetime-local"] {
|
|
min-height: 46px;
|
|
line-height: 1.2;
|
|
text-align: left;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
.field input[type="datetime-local"]::-webkit-date-and-time-value {
|
|
text-align: left;
|
|
margin: 0;
|
|
min-height: 20px;
|
|
}
|
|
|
|
.field input[type="datetime-local"]::-webkit-calendar-picker-indicator {
|
|
opacity: 0.5;
|
|
filter: grayscale(1);
|
|
}
|
|
|
|
.search { display: flex; border: 2px solid var(--ink); }
|
|
.search input { flex: 1; border: none; padding: 13px 14px; background: var(--bg); }
|
|
.search input:focus { outline: none; }
|
|
|
|
.search button {
|
|
border: none;
|
|
border-left: 1px solid var(--rule);
|
|
background: var(--fill);
|
|
color: var(--ink-2);
|
|
padding: 0 16px;
|
|
cursor: pointer;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.chips { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 10px; }
|
|
|
|
/* Ungewaehlt zurueckgenommen, damit die Auswahl ueberhaupt auffaellt. */
|
|
.chip {
|
|
padding: 7px 11px;
|
|
border: 1px solid var(--rule);
|
|
background: var(--bg);
|
|
color: var(--ink-3);
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.chip[aria-pressed="true"] {
|
|
background: var(--ink);
|
|
border-color: var(--ink);
|
|
color: var(--bg);
|
|
}
|
|
|
|
/* --------------------------------------------------------------------- Listen */
|
|
|
|
.rows { border-top: 1px solid var(--ink); border-bottom: 1px solid var(--ink); }
|
|
|
|
.row {
|
|
display: block;
|
|
width: 100%;
|
|
text-align: left;
|
|
background: var(--bg);
|
|
border: none;
|
|
border-bottom: 1px solid var(--rule);
|
|
padding: 14px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.row:last-child { border-bottom: none; }
|
|
|
|
.row-head {
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
}
|
|
|
|
.row-title { font-weight: 800; font-size: 17px; letter-spacing: -0.01em; }
|
|
.row-sub { color: var(--ink-2); font-size: 13.5px; margin-top: 3px; }
|
|
|
|
.row-meta {
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
color: var(--ink-3);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.row-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 9px; }
|
|
|
|
.pill {
|
|
display: inline-block;
|
|
padding: 3px 7px;
|
|
border: 1px solid var(--rule);
|
|
background: var(--bg);
|
|
color: var(--ink-3);
|
|
font-size: 9px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.pill-solid { background: var(--ink); border-color: var(--ink); color: var(--bg); }
|
|
|
|
.badge {
|
|
display: inline-block;
|
|
padding: 5px 9px;
|
|
border: 1px solid var(--ink);
|
|
background: var(--bg);
|
|
color: var(--ink);
|
|
font-size: 9px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
text-decoration: none;
|
|
cursor: pointer;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------- Tabelle */
|
|
|
|
.data {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
border-top: 1px solid var(--ink);
|
|
border-bottom: 1px solid var(--ink);
|
|
}
|
|
|
|
.data tr:nth-child(even) { background: var(--fill); }
|
|
.data th, .data td { padding: 10px 12px; text-align: left; vertical-align: top; }
|
|
|
|
.data th {
|
|
width: 36%;
|
|
font-weight: 600;
|
|
font-size: 10px;
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
color: var(--ink-3);
|
|
padding-top: 13px;
|
|
}
|
|
|
|
.data td { font-weight: 600; word-break: break-word; }
|
|
|
|
/* ----------------------------------------------------------------------- Bilder */
|
|
|
|
.card-image {
|
|
display: block;
|
|
width: 100%;
|
|
border: 1px solid var(--ink);
|
|
background: var(--fill);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- Navigation */
|
|
|
|
.tabs {
|
|
position: sticky;
|
|
bottom: 0;
|
|
z-index: 20;
|
|
display: flex;
|
|
background: var(--bg);
|
|
border-top: 3px solid var(--ink);
|
|
}
|
|
|
|
.tab {
|
|
flex: 1;
|
|
padding: 12px 4px calc(12px + env(safe-area-inset-bottom));
|
|
background: var(--bg);
|
|
border: none;
|
|
border-left: 1px solid var(--rule);
|
|
color: var(--ink-3);
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.tab:first-child { border-left: none; }
|
|
.tab[aria-selected="true"] { background: var(--ink); color: var(--bg); }
|
|
|
|
.tab .count {
|
|
display: block;
|
|
font-size: 17px;
|
|
font-weight: 800;
|
|
color: var(--ink);
|
|
margin-bottom: 1px;
|
|
}
|
|
|
|
.tab[aria-selected="true"] .count { color: var(--bg); }
|
|
|
|
/* ------------------------------------------------------------------- Zustaende */
|
|
|
|
.empty {
|
|
border: 1px dashed var(--rule);
|
|
background: var(--fill);
|
|
padding: 30px 18px;
|
|
text-align: center;
|
|
}
|
|
|
|
.empty .label { color: var(--ink-2); }
|
|
|
|
.overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 60;
|
|
background: rgba(0, 0, 0, 0.86);
|
|
display: grid;
|
|
place-items: center;
|
|
padding: var(--pad);
|
|
}
|
|
|
|
.overlay[hidden] { display: none; }
|
|
|
|
.overlay .block {
|
|
background: var(--bg);
|
|
border: 3px solid var(--ink);
|
|
width: 100%;
|
|
max-width: 380px;
|
|
}
|
|
|
|
.spinner {
|
|
width: 26px;
|
|
height: 26px;
|
|
border: 3px solid var(--bg);
|
|
border-top-color: transparent;
|
|
animation: spin 0.8s linear infinite;
|
|
}
|
|
|
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
|
|
.toast {
|
|
position: fixed;
|
|
left: 50%;
|
|
bottom: 96px;
|
|
transform: translateX(-50%);
|
|
z-index: 70;
|
|
max-width: 90vw;
|
|
padding: 12px 16px;
|
|
background: var(--ink);
|
|
color: var(--bg);
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.toast[hidden] { display: none; }
|
|
|
|
@media (min-width: 600px) {
|
|
:root { --pad: 26px; }
|
|
.app { border: 1px solid var(--ink); margin: 26px auto; min-height: calc(100vh - 52px); }
|
|
.d-xl { font-size: 52px; }
|
|
}
|