: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); } /* =================================================================== Kopfleiste mit Menü =================================================================== */ .app-bar { display: flex; align-items: center; gap: .75rem; margin-bottom: 1rem; min-height: 2.6rem; } /* Drei Bereiche mit festem Verhalten: links zurück, Mitte der Titel (darf gekürzt werden), rechts das Menü. Vorher standen alle Einträge nebeneinander und brachen unregelmäßig um. */ .bar-back { flex: 0 0 auto; background: none; border: none; padding: .4rem 0; font: inherit; font-size: .95rem; color: var(--accent); cursor: pointer; white-space: nowrap; } .bar-title { flex: 1 1 auto; min-width: 0; font-size: .95rem; font-weight: 600; color: var(--muted); /* Ein langer Listenname darf die Leiste nicht sprengen. */ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: right; } .bar-back + .bar-title { text-align: right; } .app-bar > span.bar-back + .bar-title { text-align: left; } .bar-menu { position: relative; flex: 0 0 auto; } button.burger { display: flex; align-items: center; gap: .4rem; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: .45rem .7rem; font: inherit; font-size: .9rem; color: var(--fg); cursor: pointer; } button.burger[aria-expanded="true"] { background: color-mix(in srgb, var(--accent) 12%, transparent); border-color: var(--accent); } /* Die drei Striche aus einem Element - spart drei weitere Knoten. */ .burger-lines { width: 1.05rem; height: 2px; background: currentColor; position: relative; display: block; } .burger-lines::before, .burger-lines::after { content: ""; position: absolute; left: 0; width: 100%; height: 2px; background: currentColor; } .burger-lines::before { top: -.34rem; } .burger-lines::after { top: .34rem; } /* Auf sehr schmalen Geräten nur das Symbol. */ @media (max-width: 24rem) { .burger-text { display: none; } } .bar-single { flex: 0 0 auto; background: none; border: none; padding: .4rem 0; font: inherit; font-size: .95rem; color: var(--accent); cursor: pointer; white-space: nowrap; text-decoration: underline; text-underline-offset: 2px; } ul.menu-panel { position: absolute; z-index: 30; top: calc(100% + .3rem); right: 0; min-width: 15rem; max-width: min(20rem, calc(100vw - 2rem)); list-style: none; margin: 0; padding: .25rem; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: 0 8px 24px rgba(0, 0, 0, .2); } ul.menu-panel button, ul.menu-panel a { display: block; width: 100%; text-align: left; background: none; border: none; border-radius: calc(var(--radius) - 2px); /* Große Trefferfläche: Das Menü wird am Telefon mit dem Daumen bedient. */ padding: .6rem .7rem; font: inherit; color: inherit; text-decoration: none; cursor: pointer; } ul.menu-panel button:hover, ul.menu-panel a:hover, ul.menu-panel button:focus-visible, ul.menu-panel a:focus-visible { background: color-mix(in srgb, var(--accent) 12%, transparent); } ul.menu-panel .danger { color: var(--error); } .entry-label { display: block; font-weight: 600; } .entry-hint { display: block; font-size: .78rem; color: var(--muted); } .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; } .app-bar, .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 { .app-bar, .bar-actions, .member-actions, .share-list, ul.menu-panel { display: none !important; } } /* =================================================================== Öffentliche Ansicht (/s/) =================================================================== */ .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; } } /* =================================================================== Vorschlagsliste beim Eintippen =================================================================== */ .name-wrap { position: relative; } ul.suggestions { position: absolute; z-index: 20; left: 0; right: 0; top: calc(100% + 2px); list-style: none; margin: 0; padding: 0; max-height: 16rem; overflow-y: auto; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: 0 6px 18px rgba(0, 0, 0, .16); } ul.suggestions > li { border-bottom: 1px solid var(--line); } ul.suggestions > li:last-child { border-bottom: none; } ul.suggestions button { display: block; width: 100%; text-align: left; background: none; border: none; padding: .55rem .8rem; font: inherit; color: inherit; cursor: pointer; } ul.suggestions button:hover, ul.suggestions button:focus-visible { background: color-mix(in srgb, var(--accent) 12%, transparent); } ul.suggestions .name { display: block; overflow-wrap: anywhere; } ul.suggestions .sub { display: block; font-size: .78rem; color: var(--muted); } /* =================================================================== Archiv in der Listenübersicht =================================================================== */ .card.archive { padding-top: .75rem; } button.archive-head { display: flex; justify-content: space-between; align-items: center; width: 100%; background: none; border: none; padding: .4rem 0; font: inherit; font-weight: 600; color: var(--fg); cursor: pointer; } button.archive-head .chev { color: var(--muted); } .card.archive ul.lists { margin-top: .5rem; } .reg-toggle { padding: 0 0 .9rem; border-bottom: 1px solid var(--line); margin-bottom: .3rem; } .reg-toggle .checkline { margin-top: 0; } @media print { ul.suggestions, .card.archive { display: none !important; } } /* =================================================================== Fußzeile mit Impressum und Datenschutz =================================================================== */ .app-footer { max-width: 30rem; margin: 0 auto; padding: 1.5rem 1rem calc(1.5rem + env(safe-area-inset-bottom)); text-align: center; font-size: .82rem; color: var(--muted); } .app-footer a { color: var(--muted); } .app-footer span { margin: 0 .4rem; } /* Über dem Sucher und über Dialogen darf sie nicht durchscheinen. */ body.scanning .app-footer, body.modal-open .app-footer { display: none; } /* =================================================================== Rechtliche Seiten =================================================================== */ .legal-text { line-height: 1.6; } .legal-text h1 { margin-bottom: .2rem; } .legal-text h2 { margin: 2rem 0 .5rem; font-size: 1.05rem; padding-bottom: .3rem; border-bottom: 1px solid var(--line); } .legal-text h3 { margin: 1.4rem 0 .4rem; font-size: .95rem; } .legal-text p { margin: .6rem 0; } .legal-text ul { margin: .6rem 0; padding-left: 1.2rem; } .legal-text li { margin: .25rem 0; } .legal-text table { width: 100%; border-collapse: collapse; margin: .8rem 0; font-size: .9rem; } .legal-text th, .legal-text td { text-align: left; vertical-align: top; padding: .45rem .5rem .45rem 0; border-bottom: 1px solid var(--line); } .legal-text th { font-size: .8rem; text-transform: uppercase; color: var(--muted); } /* Hinweis, dass es sich um einen Entwurf handelt - soll nach dem Ausfüllen entfernt werden. */ .legal-text .draft { background: var(--warn-bg); border: 1px solid var(--warn-line); border-radius: var(--radius); padding: .8rem 1rem; margin: 0 0 1.5rem; font-size: .9rem; } /* Erläuterungen zur Rechtslage - gehören nicht in den fertigen Text. */ .legal-text .hint { font-size: .85rem; color: var(--muted); border-left: 2px solid var(--line); padding-left: .8rem; margin: .5rem 0 1rem; } .legal-text code { background: rgba(127, 127, 127, .18); padding: .1em .35em; border-radius: 3px; font-size: .9em; } @media print { /* Im Ausdruck haben Rechtslinks nichts zu suchen - er soll die Einkaufsliste zeigen, nicht die Fußzeile der Anwendung. */ .app-footer { display: none !important; } }