Files
desfoto/site/gtin/css/app.css
2026-09-25 19:01:51 +02:00

775 lines
13 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* GTIN Generator – bewusst klein, hell und scanfreundlich. */
:root {
--schwarz: #111111;
--text: #111111;
--text-leise: #4b5563;
--linie: #d1d5db;
--flaeche: #ffffff;
--hintergrund: #f4f5f7;
--fokus: #1d4ed8;
--radius: 12px;
--abstand: 16px;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
min-height: 100vh;
background: var(--hintergrund);
color: var(--text);
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 1rem;
line-height: 1.5;
}
body.scan-offen {
overflow: hidden;
}
body.liste-offen {
overflow: hidden;
}
[hidden] {
display: none !important;
}
:focus-visible {
outline: 3px solid var(--fokus);
outline-offset: 2px;
}
.app {
width: 100%;
max-width: 44rem;
margin: 0 auto;
padding: calc(12px + env(safe-area-inset-top)) var(--abstand)
calc(var(--abstand) + env(safe-area-inset-bottom));
display: flex;
flex-direction: column;
gap: 12px;
}
/* Fuer Hilfstechnik vorhanden, ohne Platz auf dem Bildschirm zu kosten. */
.nur-vorlesen {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0 0 0 0);
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.hinweis-badge {
display: block;
margin: 0;
padding: 6px 10px;
border-radius: var(--radius);
background: #fef3c7;
color: #92400e;
font-size: 0.85rem;
text-align: center;
}
.karte {
background: var(--flaeche);
border: 1px solid var(--linie);
border-radius: var(--radius);
padding: var(--abstand);
}
.feld-titel {
margin: 0 0 8px;
font-size: 1rem;
font-weight: 600;
}
.feld {
width: 100%;
min-height: 3.5rem;
padding: 12px 14px;
border: 2px solid var(--linie);
border-radius: var(--radius);
background: var(--flaeche);
color: var(--text);
font-size: 1.5rem;
font-variant-numeric: tabular-nums;
letter-spacing: 0.08em;
text-align: center;
}
.feld:focus {
border-color: var(--schwarz);
}
.feld-hinweis {
margin: 8px 0 0;
color: var(--text-leise);
font-size: 0.9rem;
text-align: center;
}
.fehler {
margin: 10px 0 0;
padding: 10px 12px;
border-radius: var(--radius);
background: #fee2e2;
color: #991b1b;
font-weight: 600;
text-align: center;
}
.ergebnis {
text-align: center;
}
.gtin-typ {
margin: 0;
color: var(--text-leise);
font-size: 0.85rem;
letter-spacing: 0.18em;
text-transform: uppercase;
}
.gtin {
margin: 6px 0 14px;
padding: 6px 10px;
border: 0;
border-radius: var(--radius);
background: none;
color: var(--text);
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: clamp(1.9rem, 9vw, 2.75rem);
font-weight: 700;
letter-spacing: 0.06em;
font-variant-numeric: tabular-nums;
cursor: pointer;
}
.barcode {
display: flex;
justify-content: center;
padding: 10px 4px;
background: var(--flaeche);
border-radius: var(--radius);
}
.barcode svg {
display: block;
max-width: 100%;
height: auto;
}
.aktionen {
margin-top: var(--abstand);
display: flex;
flex-direction: column;
gap: 10px;
}
.aktionen-reihe {
display: flex;
gap: 10px;
}
.aktionen-reihe .knopf {
flex: 1 1 0;
min-width: 0;
}
.knopf {
min-height: 3rem;
padding: 12px 16px;
border: 2px solid var(--schwarz);
border-radius: var(--radius);
background: var(--flaeche);
color: var(--text);
font-size: 1rem;
font-weight: 600;
cursor: pointer;
}
.knopf-stark {
background: var(--schwarz);
color: #ffffff;
}
.knopf-leise {
border-color: transparent;
background: none;
color: var(--text-leise);
text-decoration: underline;
font-weight: 500;
}
.knopf:hover {
opacity: 0.9;
}
.verlauf-titel {
margin: 0 0 10px;
font-size: 1rem;
font-weight: 600;
}
.verlauf-liste {
margin: 0 0 10px;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
}
.verlauf-liste li + li {
border-top: 1px solid var(--linie);
}
.verlauf-eintrag {
width: 100%;
min-height: 3rem;
display: flex;
align-items: center;
gap: 10px;
padding: 10px 8px;
border: 0;
border-radius: 8px;
background: none;
color: var(--text);
font-size: 1rem;
font-variant-numeric: tabular-nums;
text-align: left;
cursor: pointer;
touch-action: manipulation;
}
.verlauf-eintrag:hover,
.verlauf-eintrag:focus-visible {
background: #eef2ff;
}
.verlauf-artikel {
min-width: 5.5rem;
font-weight: 600;
}
.verlauf-pfeil {
color: var(--text-leise);
}
.verlauf-gtin {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
letter-spacing: 0.04em;
}
.fuss {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding-bottom: 8px;
}
.fuss-hinweis {
margin: 0;
color: var(--text-leise);
font-size: 0.9rem;
text-align: center;
}
.toast {
position: fixed;
left: 50%;
bottom: calc(20px + env(safe-area-inset-bottom));
transform: translateX(-50%);
margin: 0;
padding: 10px 18px;
border-radius: 999px;
background: var(--schwarz);
color: #ffffff;
font-weight: 600;
z-index: 60;
}
.kopier-hilfe {
position: fixed;
top: -1000px;
left: -1000px;
opacity: 0;
}
/* ------------------------------------------------------------ Scanmodus -- */
.scan {
position: fixed;
inset: 0;
z-index: 50;
background: #ffffff;
display: flex;
align-items: center;
justify-content: center;
padding: calc(12px + env(safe-area-inset-top)) 12px
calc(12px + env(safe-area-inset-bottom));
}
.scan-innen {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 14px;
outline: none;
}
.scan-seite {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
}
.scan-barcode {
width: 100%;
/* Nimmt im Hochformat die verbleibende Hoehe ein, damit der Barcode so
gross wie moeglich wird. Die Groesse wird in app.js gemessen. */
flex: 1 1 auto;
min-height: 0;
display: flex;
align-items: center;
justify-content: center;
}
.scan-barcode svg {
display: block;
max-width: 100%;
max-height: 100%;
height: auto;
}
.scan-gtin {
margin: 0;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: clamp(1.5rem, 7vw, 2.5rem);
font-weight: 700;
letter-spacing: 0.08em;
font-variant-numeric: tabular-nums;
}
.scan-hinweis {
margin: 0;
color: var(--text-leise);
font-size: 0.9rem;
text-align: center;
}
.scan-zurueck {
min-width: 12rem;
}
/*
* Querformat: Der Barcode bekommt die volle Breite des Bildschirms, GTIN und
* Zurueck-Schaltflaeche stehen daneben. Dadurch wird der grosse Code deutlich
* groesser als im Hochformat, wo die Beschriftung darunter liegt.
*/
@media (orientation: landscape) {
.scan-innen {
flex-direction: row;
gap: 18px;
}
.scan-barcode {
width: auto;
align-self: stretch;
}
.scan-seite {
flex: 0 1 auto;
min-width: 0;
max-width: 34%;
align-self: center;
gap: 10px;
}
.scan-gtin {
font-size: clamp(1rem, 4.4vh, 1.9rem);
}
.scan-hinweis {
font-size: 0.8rem;
}
.scan-zurueck {
width: 100%;
min-width: 0;
}
}
/* ---------------------------------------------------------- Listenmodus -- */
/* Der Einstieg ist bewusst ein kleiner Link unter dem Werkzeug: Die
Einzelansicht bleibt die Hauptansicht. */
.fuss-liste {
margin: 0;
}
.fuss-datenschutz {
margin: 0;
color: var(--text-leise);
font-size: 0.78rem;
text-align: center;
}
.fuss-datenschutz a,
.fuss-rechtliches a {
color: inherit;
text-underline-offset: 0.18em;
}
.fuss-rechtliches {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 0.35rem 0.9rem;
font-size: 0.78rem;
}
.link-klein {
min-height: 2.75rem;
padding: 6px 10px;
border: 0;
border-radius: 8px;
background: none;
color: var(--text-leise);
font-size: 0.9rem;
font-weight: 500;
text-decoration: underline;
cursor: pointer;
}
.link-klein:hover {
color: var(--text);
}
.liste {
position: fixed;
inset: 0;
z-index: 50;
background: var(--flaeche);
padding: calc(12px + env(safe-area-inset-top)) var(--abstand)
calc(12px + env(safe-area-inset-bottom));
}
.liste-innen {
width: 100%;
max-width: 44rem;
height: 100%;
margin: 0 auto;
display: flex;
flex-direction: column;
gap: 10px;
outline: none;
}
.liste-erfassen,
.liste-anzeige {
flex: 1 1 auto;
min-height: 0;
display: flex;
flex-direction: column;
gap: 10px;
}
/* Schritt 1: Nummern erfassen. */
.liste-form {
display: flex;
flex-direction: column;
gap: 8px;
}
/* Die Abstaende liegen am Formular, nicht an den einzelnen Elementen. */
.liste-form .feld-titel,
.liste-form .feld-hinweis,
.liste-form .fehler {
margin: 0;
}
/*
* Feld und Bestaetigung bilden eine Zeile: Der Knopf sitzt unmittelbar neben
* der Eingabe, damit das Bestaetigen auf dem Telefon nicht von der
* Bildschirmtastatur abhaengt. Auf sehr schmalen Anzeigen bricht er unter das
* Feld und bleibt dort ein volles Touchziel.
*/
.liste-eingabezeile {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.liste-eingabezeile .feld {
flex: 1 1 9rem;
width: auto;
min-width: 0;
}
.liste-hinzufuegen {
flex: 1 1 auto;
}
.liste-titel {
margin: 0;
font-size: 1rem;
font-weight: 600;
}
.liste-anzahl {
display: inline-block;
min-width: 1.6rem;
margin-left: 6px;
padding: 1px 7px;
border-radius: 999px;
background: var(--schwarz);
color: #ffffff;
font-size: 0.8rem;
font-variant-numeric: tabular-nums;
text-align: center;
}
.liste-eintraege {
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
margin: 0;
padding: 0;
list-style: none;
}
.liste-eintrag {
display: flex;
align-items: center;
gap: 10px;
border-top: 1px solid var(--linie);
}
.liste-eintrag:first-child {
border-top: 0;
}
.liste-nr {
min-width: 5.5rem;
font-weight: 600;
font-variant-numeric: tabular-nums;
}
.liste-eintrag .liste-gtin {
font-size: 1rem;
font-weight: 400;
letter-spacing: 0.04em;
}
.liste-weg {
margin-left: auto;
min-width: 2.75rem;
min-height: 2.75rem;
border: 0;
border-radius: 8px;
background: none;
color: var(--text-leise);
font-size: 1.1rem;
cursor: pointer;
}
.liste-weg:hover,
.liste-weg:focus-visible {
background: var(--hintergrund);
color: var(--text);
}
.liste-leer {
margin: 0;
padding: 14px 0;
color: var(--text-leise);
text-align: center;
}
.liste-aktionen,
.liste-links {
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
}
/* Schritt 2: GTIN und Barcode nacheinander anzeigen. */
.liste-zaehler {
margin: 0;
color: var(--text-leise);
font-size: 0.9rem;
font-variant-numeric: tabular-nums;
text-align: center;
}
.liste-buehne {
flex: 1 1 auto;
min-height: 0;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: minmax(0, 1fr) auto;
grid-template-areas:
"mitte mitte"
"zurueck vor";
gap: 10px;
touch-action: pan-y;
}
.liste-mitte {
grid-area: mitte;
min-height: 0;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
outline: none;
}
.liste-barcode {
flex: 1 1 auto;
min-height: 0;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.liste-barcode svg {
display: block;
max-width: 100%;
max-height: 100%;
height: auto;
}
.liste-gtin {
margin: 0;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: clamp(1.4rem, 6.5vw, 2.2rem);
font-weight: 700;
letter-spacing: 0.07em;
font-variant-numeric: tabular-nums;
}
.liste-pfeil {
min-height: 3rem;
border: 2px solid var(--schwarz);
border-radius: var(--radius);
background: var(--flaeche);
color: var(--text);
font-size: 1.25rem;
cursor: pointer;
}
#liste-zurueck {
grid-area: zurueck;
}
#liste-vor {
grid-area: vor;
}
.liste-artikel {
margin: 0;
color: var(--text-leise);
font-variant-numeric: tabular-nums;
text-align: center;
}
/*
* Der Schritt zur naechsten Nummer zeigt die Richtung: Der neue Barcode kommt
* von der Seite, in die der Nutzer geblättert hat. 160 ms, einmalig, und unter
* "prefers-reduced-motion: reduce" abgeschaltet.
*/
@keyframes liste-schritt-vor {
from {
transform: translateX(14px);
opacity: 0.35;
}
to {
transform: none;
opacity: 1;
}
}
@keyframes liste-schritt-zurueck {
from {
transform: translateX(-14px);
opacity: 0.35;
}
to {
transform: none;
opacity: 1;
}
}
.liste-schritt-vor {
animation: liste-schritt-vor 160ms ease-out;
}
.liste-schritt-zurueck {
animation: liste-schritt-zurueck 160ms ease-out;
}
/*
* Querformat: Die Pfeile stehen als Leisten neben dem Barcode, der dadurch die
* volle Hoehe bekommt.
*/
@media (orientation: landscape) {
.liste-buehne {
grid-template-columns: auto minmax(0, 1fr) auto;
grid-template-rows: minmax(0, 1fr);
grid-template-areas: "zurueck mitte vor";
}
.liste-pfeil {
width: 4rem;
height: 100%;
}
}
@media (min-width: 40rem) {
.aktionen {
flex-direction: row-reverse;
}
.aktionen .knopf-stark {
flex: 1 1 0;
}
.aktionen-reihe {
flex: 1 1 0;
}
}
@media (prefers-reduced-motion: reduce) {
* {
transition: none !important;
animation: none !important;
}
}