Files
einkaufsapp/web/html/app.css
2026-08-08 20:31:58 +02:00

1246 lines
26 KiB
CSS

:root {
--bg: #f6f6f4;
--fg: #1c1c1a;
--muted: #6b6b66;
--card: #ffffff;
--line: #dedcd6;
--accent: #2f6f4e;
--accent-fg: #ffffff;
--error: #a32a1f;
--warn-bg: #fdf3e0;
--warn-line: #e4c98a;
--radius: 10px;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #16161a;
--fg: #e8e8e4;
--muted: #9a9a94;
--card: #202027;
--line: #34343c;
--accent: #58a37a;
--accent-fg: #10130f;
--error: #e88a80;
--warn-bg: #2e2718;
--warn-line: #6b5a2e;
}
}
* { box-sizing: border-box; }
body {
margin: 0;
padding: 0;
background: var(--bg);
color: var(--fg);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.55;
font-size: 16px;
}
#app {
max-width: 30rem;
margin: 0 auto;
padding: 1.5rem 1rem calc(2rem + env(safe-area-inset-bottom));
}
.loading { color: var(--muted); text-align: center; padding: 3rem 0; }
.card {
background: var(--card);
border: 1px solid var(--line);
border-radius: var(--radius);
padding: 1.5rem 1.25rem;
margin-bottom: 1rem;
}
h1 { font-size: 1.35rem; margin: 0 0 .5rem; }
.lead { color: var(--muted); margin: 0 0 1.25rem; }
.lead.warn {
color: var(--fg);
background: var(--warn-bg);
border: 1px solid var(--warn-line);
border-radius: var(--radius);
padding: .75rem .9rem;
}
label {
display: block;
font-weight: 600;
font-size: .9rem;
margin: 1rem 0 .3rem;
}
.hint { font-weight: 400; color: var(--muted); }
input[type="email"],
input[type="password"],
input[type="text"] {
width: 100%;
padding: .7rem .8rem;
font-size: 1rem;
font-family: inherit;
color: var(--fg);
background: var(--bg);
border: 1px solid var(--line);
border-radius: var(--radius);
}
input:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 1px;
}
button {
font: inherit;
cursor: pointer;
border-radius: var(--radius);
border: 1px solid transparent;
padding: .7rem 1.1rem;
}
button.primary {
width: 100%;
margin-top: 1.25rem;
background: var(--accent);
color: var(--accent-fg);
font-weight: 600;
}
button.primary:disabled { opacity: .55; cursor: progress; }
.row { display: flex; gap: .5rem; }
.row input { flex: 1; }
.row button.primary { width: auto; margin-top: 0; flex-shrink: 0; }
.error, .notice {
margin: .9rem 0 0;
padding: .6rem .8rem;
border-radius: var(--radius);
font-size: .92rem;
}
.error { color: var(--error); border: 1px solid currentColor; }
.notice { color: var(--accent); border: 1px solid currentColor; }
.switch { margin: 1rem 0 0; text-align: center; font-size: .92rem; }
a { color: var(--accent); }
.bar {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: 1rem;
margin-bottom: 1rem;
font-size: .92rem;
}
.who { color: var(--muted); overflow-wrap: anywhere; }
.lists { list-style: none; margin: 0 0 1rem; padding: 0; }
.lists li {
display: flex;
justify-content: space-between;
gap: .75rem;
padding: .65rem 0;
border-bottom: 1px solid var(--line);
}
.lists li:last-child { border-bottom: none; }
.lists .meta { color: var(--muted); font-size: .85rem; white-space: nowrap; }
.empty { color: var(--muted); }
.footnote {
color: var(--muted);
font-size: .85rem;
text-align: center;
margin-top: 1.5rem;
}
/* ===================================================================
Phase 3: Listenansicht
=================================================================== */
a.linklike,
button.linklike {
background: none;
border: none;
padding: 0;
color: var(--accent);
font: inherit;
text-align: left;
cursor: pointer;
text-decoration: underline;
text-underline-offset: 2px;
}
button.secondary {
background: var(--card);
border: 1px solid var(--line);
color: var(--fg);
font-weight: 600;
}
button.danger {
background: none;
border: 1px solid var(--line);
color: var(--error);
padding: .4rem .7rem;
}
.offline-hint {
background: var(--warn-bg);
border: 1px solid var(--warn-line);
border-radius: var(--radius);
padding: .6rem .8rem;
margin: 0 0 1rem;
font-size: .9rem;
}
/* --- Artikel hinzufügen --- */
.add-row { margin-top: .5rem; }
.add-row > input { margin-bottom: .5rem; }
.add-row .qty { flex: 0 0 5.5rem; }
.add-row .unit { flex: 0 0 6rem; }
/* --- Markt- und Gruppenabschnitte --- */
.market {
background: var(--card);
border: 1px solid var(--line);
border-radius: var(--radius);
margin-bottom: 1rem;
overflow: hidden;
}
.market > h2 {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: .75rem;
margin: 0;
padding: .8rem 1rem;
font-size: 1.05rem;
background: color-mix(in srgb, var(--accent) 12%, transparent);
border-bottom: 1px solid var(--line);
}
.market-meta {
font-size: .82rem;
font-weight: 400;
color: var(--muted);
white-space: nowrap;
}
.category { padding: 0 0 .25rem; }
.category > h3 {
margin: .75rem 1rem .25rem;
font-size: .8rem;
font-weight: 700;
letter-spacing: .04em;
text-transform: uppercase;
color: var(--muted);
}
ul.items { list-style: none; margin: 0; padding: 0; }
li.item { border-top: 1px solid var(--line); }
.category > ul.items > li.item:first-child { border-top: none; }
.item-main {
display: flex;
align-items: center;
gap: .6rem;
padding: .55rem 1rem;
}
/* Große Trefferfläche: die App wird einhändig im Laden bedient.
padding: 0 ist entscheidend - die allgemeine button-Regel setzt
1,1rem waagerecht, und das ist mehr als die vorgesehenen 2rem
Breite. Der Knopf wurde dadurch auseinandergezogen und wirkte oval.
aspect-ratio hält ihn auch dann kreisrund, wenn eine Schrift die
Zeilenhöhe verändert. */
button.check {
flex: 0 0 2.1rem;
width: 2.1rem;
height: 2.1rem;
aspect-ratio: 1;
padding: 0;
border: 2px solid var(--line);
border-radius: 50%;
background: var(--bg);
color: var(--accent-fg);
font-size: 1.05rem;
font-weight: 700;
line-height: 1;
display: grid;
place-items: center;
}
button.check[aria-pressed="true"] {
background: var(--accent);
border-color: var(--accent);
}
.item-text { flex: 1; min-width: 0; }
.item-text .name { display: block; overflow-wrap: anywhere; }
.item-text .sub { display: block; font-size: .82rem; color: var(--muted); }
li.item.bought .item-text .name {
text-decoration: line-through;
color: var(--muted);
}
li.item.deferred { opacity: .6; }
li.item.deferred .item-text .name { font-style: italic; }
.price-cell {
flex: 0 0 auto;
display: flex;
flex-direction: column;
align-items: flex-end;
gap: .1rem;
}
input.price {
width: 4.5rem;
padding: .4rem .5rem;
text-align: right;
font-size: .9rem;
}
/* Zeilensumme bei mehreren Stück: macht sichtbar, dass der eingetragene
Preis je Gebinde gilt. */
.line-total {
font-size: .75rem;
color: var(--muted);
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
button.menu-toggle {
flex: 0 0 auto;
background: none;
border: none;
color: var(--muted);
font-size: 1.2rem;
line-height: 1;
padding: .3rem .4rem;
}
.item-menu {
padding: .25rem 1rem 1rem 3.6rem;
background: color-mix(in srgb, var(--fg) 4%, transparent);
}
.item-menu label {
margin: .6rem 0 .2rem;
font-size: .8rem;
}
.item-menu select {
width: 100%;
padding: .5rem;
font: inherit;
color: var(--fg);
background: var(--bg);
border: 1px solid var(--line);
border-radius: var(--radius);
}
.menu-actions {
display: flex;
gap: .5rem;
margin-top: .9rem;
}
.menu-actions button {
flex: 1;
background: var(--card);
border: 1px solid var(--line);
color: var(--fg);
font-size: .9rem;
}
.menu-actions button.danger { color: var(--error); }
/* --- Fußzeile mit Summe --- */
.summary {
background: var(--card);
border: 1px solid var(--line);
border-radius: var(--radius);
padding: 1rem;
}
.summary .total {
display: flex;
justify-content: space-between;
align-items: baseline;
font-size: 1.1rem;
}
.summary button { width: 100%; margin-top: .9rem; }
/* --- Verwaltung von Märkten und Warengruppen --- */
ul.sortable {
list-style: none;
margin: 0 0 1.25rem;
padding: 0;
}
li.sortable-row {
display: flex;
align-items: center;
gap: .4rem;
padding: .3rem 0;
background: var(--card);
/* Beim Ziehen wird transform gesetzt - ohne relative Positionierung
würde die Zeile hinter ihren Nachbarn verschwinden. */
position: relative;
border-radius: var(--radius);
}
/* Anfasser: feste Breite, der Rest teilt sich den Platz. */
button.grip {
flex: 0 0 2rem;
height: 2.4rem;
padding: 0;
background: none;
border: 1px solid transparent;
color: var(--muted);
font-size: 1.1rem;
line-height: 1;
cursor: grab;
/* Ohne das scrollt die Seite, statt die Zeile zu ziehen. */
touch-action: none;
user-select: none;
}
button.grip:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 1px;
border-radius: var(--radius);
}
li.sortable-row input.entry-name {
flex: 1 1 auto;
min-width: 0;
}
button.remove {
flex: 0 0 2.2rem;
padding: .45rem 0;
text-align: center;
font-size: 1.1rem;
line-height: 1;
}
/* Während des Ziehens */
ul.sortable.sorting { cursor: grabbing; }
ul.sortable.sorting button.grip { cursor: grabbing; }
ul.sortable.sorting li.sortable-row:not(.dragging) { transition: transform .12s ease; }
li.sortable-row.dragging {
z-index: 2;
box-shadow: 0 4px 14px rgba(0, 0, 0, .18);
opacity: .95;
}
li.sortable-row.dragging button.grip { color: var(--accent); }
/* --- Druck: A4, gruppiert, mit Kästchen zum Abhaken --- */
@media print {
@page { size: A4; margin: 15mm; }
body { background: #fff; color: #000; font-size: 11pt; }
#app { max-width: none; padding: 0; }
.bar, .add-row, .summary button, button.menu-toggle,
.item-menu, .offline-hint, .footnote, label, .row { display: none !important; }
.card, .market, .summary {
border: none;
background: none;
padding: 0;
margin: 0 0 6mm;
}
.market { break-inside: avoid; }
.market > h2 { background: none; border-bottom: 1pt solid #000; padding: 0 0 1mm; }
.category > h3 { margin: 3mm 0 1mm; color: #000; }
li.item { border-top: none; }
.item-main { padding: .5mm 0; }
/* Leeres Kästchen statt der Schaltfläche */
button.check {
width: 4mm; height: 4mm;
border: .5pt solid #000; border-radius: 0;
background: none; color: #000; font-size: 8pt;
}
input.price {
border: none; background: none; width: 18mm;
border-bottom: .5pt dotted #666;
}
}
/* ===================================================================
Phase 5: Teilen
=================================================================== */
.bar-actions { display: flex; gap: 1rem; }
select {
width: 100%;
padding: .6rem .5rem;
font: inherit;
color: var(--fg);
background: var(--bg);
border: 1px solid var(--line);
border-radius: var(--radius);
}
ul.share-list { list-style: none; margin: 0; padding: 0; }
ul.share-list > li {
padding: .8rem 0;
border-bottom: 1px solid var(--line);
}
ul.share-list > li:last-child { border-bottom: none; }
.who-block .name { display: block; font-weight: 600; overflow-wrap: anywhere; }
.who-block .sub { display: block; font-size: .82rem; color: var(--muted); }
select.role { margin-top: .5rem; }
.member-actions {
display: flex;
flex-wrap: wrap;
gap: .5rem;
margin-top: .6rem;
}
.member-actions button {
flex: 1 1 auto;
background: var(--card);
border: 1px solid var(--line);
color: var(--fg);
font-size: .85rem;
padding: .45rem .7rem;
}
.member-actions button.danger { color: var(--error); }
button.danger.wide {
width: 100%;
margin-top: .5rem;
padding: .7rem;
font-weight: 600;
}
li.invite.revoked .who-block .name,
li.invite.expired .who-block .name {
color: var(--muted);
text-decoration: line-through;
}
li.invite.accepted .who-block .name { color: var(--muted); }
@media print {
.bar-actions, .member-actions, .share-list { display: none !important; }
}
/* ===================================================================
Öffentliche Ansicht (/s/<token>)
=================================================================== */
.public-head { margin-bottom: 1rem; }
.public-head h1 { margin-bottom: .2rem; }
.public-head .sub { margin: 0; color: var(--muted); font-size: .88rem; }
span.check.readonly {
flex: 0 0 2.1rem;
width: 2.1rem;
height: 2.1rem;
aspect-ratio: 1;
border: 2px solid var(--line);
border-radius: 50%;
display: grid;
place-items: center;
color: var(--accent);
font-size: 1.05rem;
font-weight: 700;
}
.price-static {
flex: 0 0 auto;
font-variant-numeric: tabular-nums;
color: var(--muted);
font-size: .9rem;
}
label.checkline {
display: flex;
align-items: center;
gap: .5rem;
font-weight: 400;
margin: .7rem 0 0;
}
label.checkline input[type="checkbox"] {
width: 1.1rem;
height: 1.1rem;
accent-color: var(--accent);
flex: 0 0 auto;
}
.fresh-link {
background: var(--warn-bg);
border: 1px solid var(--warn-line);
border-radius: var(--radius);
padding: .9rem;
margin-bottom: 1rem;
}
.fresh-link p { margin: 0 0 .5rem; }
.fresh-link .sub { font-size: .82rem; color: var(--muted); margin: .7rem 0 0; }
input.linkfield {
width: 100%;
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: .82rem;
padding: .55rem;
}
input[type="date"] {
width: 100%;
padding: .65rem .5rem;
font: inherit;
color: var(--fg);
background: var(--bg);
border: 1px solid var(--line);
border-radius: var(--radius);
}
@media print {
.public-head .sub, .no-print { display: none !important; }
span.check.readonly {
width: 4mm; height: 4mm;
border: .5pt solid #000; border-radius: 0;
font-size: 8pt;
}
.price-static { color: #000; }
}
/* ===================================================================
Phase 4: Synchronisationszustand
=================================================================== */
.sync-hint {
margin: 0 0 1rem;
padding: .55rem .8rem;
border-radius: var(--radius);
font-size: .88rem;
border: 1px solid;
}
.sync-hint.offline {
background: var(--warn-bg);
border-color: var(--warn-line);
color: var(--fg);
}
.sync-hint.pending {
border-color: var(--line);
color: var(--muted);
}
.sync-hint.problem {
border-color: var(--error);
color: var(--error);
}
/* Noch nicht bestätigte Änderungen kennzeichnen - ohne sie zu verstecken.
Der Nutzer soll sehen, dass die Änderung da ist, aber auch, dass sie
noch unterwegs ist. */
li.item.pending .item-text .name::after {
content: " ·";
color: var(--accent);
font-weight: 700;
}
li.item.pending { background: color-mix(in srgb, var(--accent) 5%, transparent); }
button.check:disabled { opacity: .4; cursor: default; }
@media print {
.sync-hint { display: none !important; }
li.item.pending { background: none; }
li.item.pending .item-text .name::after { content: ""; }
}
/* ===================================================================
Listenübersicht mit Aktionen
=================================================================== */
ul.lists > li.list-row {
display: block;
padding: 0;
border-bottom: 1px solid var(--line);
}
ul.lists > li.list-row:last-child { border-bottom: none; }
.list-main {
display: flex;
align-items: center;
gap: .5rem;
}
button.list-open {
flex: 1;
min-width: 0;
display: block;
text-align: left;
background: none;
border: none;
padding: .7rem 0;
font: inherit;
color: inherit;
cursor: pointer;
}
button.list-open .name {
display: block;
font-weight: 600;
color: var(--accent);
overflow-wrap: anywhere;
}
button.list-open .meta {
display: block;
font-size: .82rem;
color: var(--muted);
white-space: normal;
}
.list-menu { padding: 0 0 .8rem; }
li.list-row.renaming { padding: .6rem 0; }
li.list-row.renaming .row { gap: .4rem; }
li.list-row.renaming input { flex: 1; min-width: 0; }
button.cancel {
background: var(--card);
border: 1px solid var(--line);
color: var(--fg);
flex-shrink: 0;
}
/* ===================================================================
Phase 6: Strichcode-Sucher und Artikelstamm
=================================================================== */
body.scanning { overflow: hidden; }
.scan-overlay {
position: fixed;
inset: 0;
z-index: 100;
background: #101012;
color: #f2f2f0;
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem calc(1rem + env(safe-area-inset-right))
calc(1rem + env(safe-area-inset-bottom))
calc(1rem + env(safe-area-inset-left));
overflow-y: auto;
}
.scan-stage {
position: relative;
flex: 1 1 auto;
min-height: 40vh;
border-radius: var(--radius);
overflow: hidden;
background: #000;
}
.scan-video {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
/* Sucherrahmen über dem Bereich, den der Decoder auswertet. */
.scan-frame {
position: absolute;
left: 6%;
right: 6%;
top: 32.5%;
height: 35%;
border: 2px solid rgba(255, 255, 255, .85);
border-radius: 6px;
box-shadow: 0 0 0 100vmax rgba(0, 0, 0, .45);
pointer-events: none;
}
.scan-hint {
margin: 0;
text-align: center;
font-size: .92rem;
color: #cfcfc9;
}
.scan-manual label {
color: #cfcfc9;
font-size: .85rem;
margin-bottom: .3rem;
}
.scan-manual input {
background: #1c1c20;
border-color: #34343c;
color: #f2f2f0;
}
.scan-overlay .scan-close {
background: #1c1c20;
border-color: #34343c;
color: #f2f2f0;
width: 100%;
}
button.secondary.scan { flex-shrink: 0; }
/* --- Artikelstamm --- */
ul.articles { list-style: none; margin: 1rem 0 0; padding: 0; }
li.article-row {
border-bottom: 1px solid var(--line);
}
li.article-row:last-child { border-bottom: none; }
button.article-open {
display: block;
width: 100%;
text-align: left;
background: none;
border: none;
padding: .7rem 0;
font: inherit;
color: inherit;
cursor: pointer;
}
button.article-open .name {
display: block;
font-weight: 600;
color: var(--accent);
overflow-wrap: anywhere;
}
button.article-open .sub {
display: block;
font-size: .82rem;
color: var(--muted);
}
li.article-row.editing > .name {
display: block;
font-weight: 600;
padding: .7rem 0 0;
}
.article-editor { padding-bottom: 1rem; }
.availability { margin-top: 1rem; }
.attr-rows { margin-top: .3rem; }
.attr-row {
display: flex;
gap: .4rem;
margin-bottom: .4rem;
}
.attr-row .attr-key { flex: 0 0 40%; min-width: 0; }
.attr-row .attr-value { flex: 1; min-width: 0; }
button.linklike.add-attr { margin-top: .2rem; font-size: .9rem; }
input[type="search"] {
width: 100%;
padding: .7rem .8rem;
font-size: 1rem;
font-family: inherit;
color: var(--fg);
background: var(--bg);
border: 1px solid var(--line);
border-radius: var(--radius);
}
@media print {
.scan-overlay { display: none !important; }
}
/* --- Eingabezeile: Name, Detailfelder, Schaltflächen untereinander --- */
.add-row > input#add-name { margin-bottom: .5rem; }
.add-fields {
display: flex;
flex-wrap: wrap;
gap: .5rem;
margin-bottom: .5rem;
}
/* Menge schmal, Einheit schmal, Eigenschaft nimmt den Rest. Bei sehr
schmalen Geräten bricht die Eigenschaft in die nächste Zeile. */
.add-fields .count { flex: 0 1 4rem; min-width: 3.2rem; text-align: center; }
.add-fields .qty { flex: 0 1 5rem; min-width: 4rem; }
.add-fields .unit { flex: 0 1 5.5rem; min-width: 4rem; }
.add-fields .variant { flex: 1 1 8rem; min-width: 0; }
.add-actions {
display: flex;
gap: .5rem;
}
/* Vorher liefen die Schaltflächen aus der Box, weil sie sich die Zeile
mit den Eingabefeldern teilten. Jetzt eigene Zeile, gleichmäßig
verteilt. */
.add-actions button {
flex: 1;
margin-top: 0;
}
/* ===================================================================
Bestätigungsdialog nach dem Scan
=================================================================== */
body.modal-open { overflow: hidden; }
.modal {
position: fixed;
inset: 0;
z-index: 90;
background: rgba(0, 0, 0, .5);
display: flex;
align-items: flex-end;
justify-content: center;
padding: 1rem;
padding-bottom: calc(1rem + env(safe-area-inset-bottom));
overflow-y: auto;
}
@media (min-width: 30rem) {
.modal { align-items: center; }
}
.modal-card {
background: var(--card);
border: 1px solid var(--line);
border-radius: var(--radius);
padding: 1.25rem;
width: 100%;
max-width: 28rem;
}
.modal-card h2 { margin: 0 0 .2rem; font-size: 1.15rem; }
.modal-card .sub { margin: 0 0 1rem; color: var(--muted); font-size: .85rem; }
/* Herkunftshinweis: Wenn Angaben aus einer fremden Quelle vorbelegt
werden, soll das sichtbar sein - nicht als Kleingedrucktes. */
.source-note {
background: var(--warn-bg);
border: 1px solid var(--warn-line);
border-radius: var(--radius);
padding: .6rem .8rem;
margin: 0 0 1rem;
font-size: .88rem;
}
.modal-card .add-fields { margin-top: .6rem; }
.modal-card .menu-actions { margin-top: 1.2rem; }
.modal-card .menu-actions button.primary { margin-top: 0; }
/* ===================================================================
Phase 7: Preisvergleich
=================================================================== */
.price-card { padding: 0; overflow: hidden; }
button.price-head {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: .75rem;
width: 100%;
background: color-mix(in srgb, var(--accent) 10%, transparent);
border: none;
border-bottom: 1px solid var(--line);
padding: .75rem 1rem;
font: inherit;
color: inherit;
text-align: left;
cursor: pointer;
}
button.price-head .name { font-weight: 600; overflow-wrap: anywhere; }
button.price-head .spread {
font-size: .8rem;
color: var(--muted);
white-space: nowrap;
}
.price-rows { padding: .25rem 1rem .75rem; }
.price-row {
display: flex;
align-items: baseline;
gap: .6rem;
padding: .4rem 0;
border-bottom: 1px solid var(--line);
}
.price-row:last-child { border-bottom: none; }
.price-row .market { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.price-row .amount {
font-variant-numeric: tabular-nums;
font-weight: 600;
white-space: nowrap;
}
.price-row.best .amount { color: var(--accent); }
.price-row .badge {
flex: 0 0 auto;
font-size: .72rem;
font-weight: 700;
letter-spacing: .03em;
text-transform: uppercase;
color: var(--accent);
border: 1px solid currentColor;
border-radius: 999px;
padding: .05rem .45rem;
}
.price-row .diff {
flex: 0 0 auto;
font-size: .78rem;
color: var(--muted);
font-variant-numeric: tabular-nums;
min-width: 3.5rem;
text-align: right;
}
.price-detail {
padding: .5rem 1rem 1rem;
border-top: 1px solid var(--line);
background: color-mix(in srgb, var(--fg) 3%, transparent);
}
.price-detail h4 {
margin: .6rem 0 .4rem;
font-size: .8rem;
letter-spacing: .04em;
text-transform: uppercase;
color: var(--muted);
}
ul.price-markets { list-style: none; margin: 0; padding: 0; }
ul.price-markets > li {
display: grid;
grid-template-columns: 1fr auto;
gap: 0 .6rem;
padding: .45rem 0;
border-bottom: 1px solid var(--line);
}
ul.price-markets > li:last-child { border-bottom: none; }
ul.price-markets .market { font-weight: 600; }
ul.price-markets .sub {
grid-column: 1 / 2;
font-size: .78rem;
color: var(--muted);
}
ul.price-markets .amount {
grid-row: 1 / 3;
grid-column: 2 / 3;
align-self: center;
font-variant-numeric: tabular-nums;
font-weight: 600;
}
.price-history { margin-top: .8rem; font-size: .85rem; }
.price-history summary { cursor: pointer; color: var(--accent); }
.price-history ul { list-style: none; margin: .5rem 0 0; padding: 0; }
.price-history li { padding: .2rem 0; color: var(--muted); }
/* Hinweis im Eintragsmenü */
.price-tip {
margin: 0 0 .3rem;
padding: .5rem .7rem;
background: color-mix(in srgb, var(--accent) 10%, transparent);
border-radius: var(--radius);
font-size: .85rem;
}
@media print {
.price-tip, .price-detail { display: none !important; }
}
/* --- Stückzahl direkt am Artikel --- */
.item-count {
flex: 0 0 auto;
min-width: 1.9rem;
text-align: right;
font-variant-numeric: tabular-nums;
font-size: .95rem;
color: var(--muted);
white-space: nowrap;
}
/* Mehr als ein Stück wird hervorgehoben: Beim Einkaufen ist das die
Angabe, die man leicht übersieht und dann zu wenig einpackt. */
.item-count.many {
font-weight: 700;
color: var(--fg);
}
li.item.bought .item-count { color: var(--muted); font-weight: 400; }
@media print {
.item-count { color: #000; }
.item-count.many { font-weight: 700; }
}
/* --- Einstellungen --- */
h3.device-heading {
margin: 1.5rem 0 .3rem;
font-size: .8rem;
letter-spacing: .04em;
text-transform: uppercase;
color: var(--muted);
}
.card > .menu-actions { margin-top: 1rem; }
/* ===================================================================
Benutzerverwaltung
=================================================================== */
.stats {
display: flex;
flex-wrap: wrap;
gap: .5rem;
margin: 1rem 0;
}
.stat {
flex: 1 1 5rem;
min-width: 4.5rem;
padding: .6rem .5rem;
border: 1px solid var(--line);
border-radius: var(--radius);
text-align: center;
}
.stat .value {
display: block;
font-size: 1.35rem;
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.stat .label { display: block; font-size: .75rem; color: var(--muted); }
.stat.warn {
background: var(--warn-bg);
border-color: var(--warn-line);
}
ul.admin-users { list-style: none; margin: 0; padding: 0; }
li.admin-user { border-bottom: 1px solid var(--line); }
li.admin-user:last-child { border-bottom: none; }
/* Deaktivierte Konten erkennbar, aber nicht versteckt: Man muss sie
finden, um sie zu reaktivieren. */
li.admin-user.inactive .user-open .name {
color: var(--muted);
text-decoration: line-through;
}
button.user-open {
display: block;
width: 100%;
text-align: left;
background: none;
border: none;
padding: .7rem 0;
font: inherit;
color: inherit;
cursor: pointer;
}
button.user-open .name {
display: block;
font-weight: 600;
color: var(--accent);
overflow-wrap: anywhere;
}
button.user-open .sub {
display: block;
font-size: .82rem;
color: var(--muted);
}
li.admin-user .item-menu { padding-left: 0; padding-right: 0; }
.item-menu .sub {
display: block;
font-size: .82rem;
color: var(--muted);
margin: .2rem 0 0;
}
hr.thin {
border: none;
border-top: 1px solid var(--line);
margin: 1.2rem 0 .8rem;
}
input.months {
width: 6rem;
padding: .6rem .5rem;
font: inherit;
text-align: right;
color: var(--fg);
background: var(--bg);
border: 1px solid var(--line);
border-radius: var(--radius);
}
@media print { .stats, ul.admin-users { display: none !important; } }