/* Finanzmanager – Grundgestaltung * * Layout wie im Lexware FinanzManager: feste Navigation links, Werkzeugleiste * oben, darunter Tab-Leiste und dichte Datentabellen. Optik moderner: ruhigere * Farben, mehr Weißraum, klare Typografie. * * Farben ausschließlich über Custom Properties. Die helle Palette steht auf * blankem :root, die dunkle wird an zwei Stellen nachgezogen – einmal für die * Systemvorgabe, einmal für die ausdrückliche Wahl im Einstellungsdialog. */ :root { --grund: #f4f6f8; --flaeche: #ffffff; --flaeche-gedaempft: #eef1f5; --rand: #d6dce4; --rand-kraeftig: #b8c2cf; --text: #1c2530; --text-gedaempft: #5b6875; --akzent: #1f6feb; --akzent-text: #ffffff; --akzent-schwach: #e5efff; --navi-grund: #24313f; --navi-text: #cdd7e2; --navi-text-aktiv: #ffffff; --navi-aktiv: #1f6feb; --positiv: #1a7f4b; --negativ: #c0392b; --warnung: #9a6700; --schatten: 0 1px 2px rgba(16, 24, 40, .06), 0 1px 3px rgba(16, 24, 40, .1); --radius: 6px; --schrift: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; --schrift-zahl: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace; } @media (prefers-color-scheme: dark) { :root:not([data-thema="hell"]) { --grund: #161b22; --flaeche: #1c2330; --flaeche-gedaempft: #232b39; --rand: #303a49; --rand-kraeftig: #44506180; --text: #e5eaf1; --text-gedaempft: #9aa7b6; --akzent: #4d8ef7; --akzent-text: #0d1117; --akzent-schwach: #1d2b45; --navi-grund: #10151c; --navi-text: #9aa7b6; --navi-text-aktiv: #ffffff; --navi-aktiv: #2f6fd0; --positiv: #46b877; --negativ: #f0705f; --warnung: #d9a441; --schatten: 0 1px 2px rgba(0, 0, 0, .4); } } :root[data-thema="dunkel"] { --grund: #161b22; --flaeche: #1c2330; --flaeche-gedaempft: #232b39; --rand: #303a49; --rand-kraeftig: #445061; --text: #e5eaf1; --text-gedaempft: #9aa7b6; --akzent: #4d8ef7; --akzent-text: #0d1117; --akzent-schwach: #1d2b45; --navi-grund: #10151c; --navi-text: #9aa7b6; --navi-text-aktiv: #ffffff; --navi-aktiv: #2f6fd0; --positiv: #46b877; --negativ: #f0705f; --warnung: #d9a441; --schatten: 0 1px 2px rgba(0, 0, 0, .4); } * { box-sizing: border-box; } body { margin: 0; background: var(--grund); color: var(--text); font: 15px/1.5 var(--schrift); -webkit-font-smoothing: antialiased; } a { color: var(--akzent); text-decoration: none; } a:hover { text-decoration: underline; } code { font-family: var(--schrift-zahl); font-size: .9em; background: var(--flaeche-gedaempft); padding: .1em .35em; border-radius: 4px; } /* ── Grundraster ─────────────────────────────────────────────────────────── */ .rahmen { display: grid; grid-template-columns: 232px 1fr; min-height: 100vh; } .seitenleiste { background: var(--navi-grund); color: var(--navi-text); padding: 0 0 2rem; position: sticky; top: 0; height: 100vh; overflow-y: auto; } .marke { font-size: 1.05rem; font-weight: 600; color: #fff; padding: 1.25rem 1.25rem 1rem; letter-spacing: .01em; } .seitenleiste ul { list-style: none; margin: 0; padding: 0; } .seitenleiste a { display: flex; align-items: center; gap: .7rem; padding: .6rem 1.25rem; color: var(--navi-text); border-left: 3px solid transparent; font-size: .95rem; } .seitenleiste a:hover { background: rgba(255, 255, 255, .05); color: var(--navi-text-aktiv); text-decoration: none; } .seitenleiste a.aktiv { background: var(--navi-aktiv); border-left-color: #fff; color: var(--navi-text-aktiv); font-weight: 500; } .seitenleiste .icon { width: 1.1em; text-align: center; opacity: .85; } .hauptbereich { display: flex; flex-direction: column; min-width: 0; } /* ── Werkzeugleiste ──────────────────────────────────────────────────────── */ .werkzeugleiste { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .85rem 1.5rem; background: var(--flaeche); border-bottom: 1px solid var(--rand); position: sticky; top: 0; z-index: 10; } .werkzeugleiste h1 { margin: 0; font-size: 1.35rem; font-weight: 600; color: var(--akzent); } .werkzeuge { display: flex; align-items: center; gap: .75rem; } .werkzeug { background: none; border: 1px solid transparent; color: var(--text-gedaempft); font: inherit; font-size: .9rem; padding: .35rem .6rem; border-radius: var(--radius); cursor: pointer; } .werkzeug:hover { background: var(--flaeche-gedaempft); border-color: var(--rand); color: var(--text); text-decoration: none; } .benutzer { font-size: .9rem; color: var(--text-gedaempft); } form.inline { display: inline; margin: 0; } .inhalt { padding: 1.25rem 1.5rem 3rem; flex: 1; min-width: 0; } /* ── Tab-Leiste ──────────────────────────────────────────────────────────── */ .tableiste { display: flex; gap: .25rem; border-bottom: 1px solid var(--rand); margin-bottom: 1.25rem; overflow-x: auto; } .tab { padding: .5rem .9rem; border: 1px solid transparent; border-bottom: none; border-radius: var(--radius) var(--radius) 0 0; color: var(--text-gedaempft); font-size: .93rem; white-space: nowrap; } .tab:hover { background: var(--flaeche-gedaempft); text-decoration: none; } /* Schiebt einen Eintrag ans andere Ende der Leiste – etwa „Kacheln wählen“, das kein Register ist, sondern ein Weg hinaus. */ .tab.rechtsbuendig { margin-left: auto; } .tab.aktiv { background: var(--flaeche); border-color: var(--rand); color: var(--text); font-weight: 500; margin-bottom: -1px; padding-bottom: calc(.5rem + 1px); } /* ── Kacheln ─────────────────────────────────────────────────────────────── */ .kachelraster { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 1rem; } .kachel { background: var(--flaeche); border: 1px solid var(--rand); border-radius: var(--radius); box-shadow: var(--schatten); padding: 1rem 1.15rem 1.25rem; } .kachel.einzeln { max-width: 640px; } .kachel header { margin-bottom: .6rem; } .kachel header.mitschalter { display: flex; align-items: center; justify-content: space-between; gap: .5rem 1rem; flex-wrap: wrap; } /* Der Schalter teilt sich die Zeile mit der Überschrift und bleibt oben rechts; der erklärende Satz nimmt die ganze nächste Zeile. Stünde er in derselben Zeile, drückte er den Schalter in einer schmalen Kachel nach unten. */ .kachel header.mitschalter > h2 { min-width: 0; } .kachel header.mitschalter > .kachelhinweis { flex: 1 0 100%; margin: 0; } .kachelhinweis { margin: .25rem 0 0; color: var(--text-gedaempft); font-size: .85rem; } .kachel h2 { margin: 0; font-size: 1rem; font-weight: 600; } /* Kleine Marke: Zustand (Monatsabschluss), Dateiname (Import) oder der Schritt eines mehrteiligen Dialogs (Einrichtung einer Bankverbindung). */ .phasenmarke, .schrittmarke { display: inline-block; background: var(--akzent-schwach); color: var(--akzent); font-size: .8rem; font-weight: 600; padding: .15rem .5rem; border-radius: 999px; margin: 0 0 .75rem; } .platzhalter { color: var(--text-gedaempft); font-size: .92rem; margin: .5rem 0 0; } .checkliste { list-style: none; margin: 0; padding: 0; font-size: .92rem; } .checkliste li { padding: .3rem 0 .3rem 1.5rem; position: relative; color: var(--text-gedaempft); } .checkliste li::before { content: "○"; position: absolute; left: 0; } .checkliste li.erledigt { color: var(--text); } .checkliste li.erledigt::before { content: "●"; color: var(--positiv); } /* ── Diagramme ─────────────────────────────────────────────────────────────── Selbst erzeugtes SVG, keine Diagrammbibliothek. Die Farbe eines Kontos steht als Klasse am Element: Ein fill-Attribut ginge zwar an der CSP vorbei, könnte aber nicht auf das dunkle Thema reagieren. Jede Serie setzt --farbe, davon leben Balken (fill) und Legendenpunkt (background) gleichermaßen. */ .serie-1 { --farbe: #4c78a8; } .serie-2 { --farbe: #f58518; } .serie-3 { --farbe: #54a24b; } .serie-4 { --farbe: #e45756; } .serie-5 { --farbe: #72b7b2; } .serie-6 { --farbe: #b279a2; } .serie-7 { --farbe: #d8b02c; } .serie-8 { --farbe: #9d755d; } .serie-9 { --farbe: #2f8f8a; } .serie-10 { --farbe: #8f8ad4; } .serie-11 { --farbe: #e07b91; } .serie-12 { --farbe: #7b8a99; } .diagrammbereich { display: flex; flex-direction: column; gap: .6rem; } /* Achsenbeschriftung und Zeichenfläche sind zwei SVGs nebeneinander. Die Achse ist fest, die Fläche nimmt den Rest – und weil deren Balken waagerecht in Prozent sitzen, rücken sie in einer breiten Kachel auseinander, statt breiter zu werden. Ein einziges SVG könnte das nicht: Prozentangaben rechnen immer auf die volle Breite, die feste Achse ließe sich nicht abziehen. */ .diagrammflaeche { display: flex; align-items: flex-start; width: 100%; } .diagrammachse { flex: none; } .diagramm { flex: 1 1 0; min-width: 0; display: block; overflow: visible; } .diagramm rect { fill: var(--farbe); } .diagramm-gitter { stroke: var(--rand); stroke-width: 1; } .diagramm-nulllinie { stroke: var(--rand-kraeftig); stroke-width: 1.5; } .diagramm-achse, .diagramm-beschriftung { fill: var(--text-gedaempft); font-family: var(--schrift); font-size: 10px; } /* Ziffernschrift für die Achse, aber schmal genug für 21 Punkte Spaltenabstand bleiben die Monatskürzel darunter. */ .diagramm-achse { font-family: var(--schrift-zahl); font-size: 11px; } .diagramm-beschriftung.schwach { opacity: .7; } /* Unter der Zeichnung und in kleiner Schrift: So bleibt die Kachel so breit wie ihre Nachbarn, und zwölf Kontonamen passen in zwei Spalten darunter. */ .diagrammlegende { list-style: none; margin: 0; padding: 0; align-self: stretch; display: grid; grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr)); gap: 0 1rem; font-size: .74rem; align-content: start; } .diagrammlegende li { display: flex; align-items: center; gap: .4rem; padding: .1rem 0; } .legendenfarbe { width: .65rem; height: .65rem; border-radius: 2px; background: var(--farbe); flex: none; } .legendenname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* „Übrige Konten“ führt eine Ebene tiefer: Der Eintrag ist ein Link und sieht auch danach aus – sonst probierte ihn niemand aus. */ .legendenname.tiefer { color: var(--akzent); text-decoration: underline dotted; text-underline-offset: 2px; } .legendenname.tiefer:hover { text-decoration: underline; } .diagrammpfad { margin: 0; font-size: .74rem; color: var(--text-gedaempft); } .kachelfuss { margin-top: 1rem; } /* Einnahmen und Ausgaben tragen keine Seriennummer, sondern die Bedeutungsfarben der Anwendung – grün und rot lesen sich hier ohne Legende. */ .balken-einnahme { --farbe: var(--positiv); } .balken-ausgabe { --farbe: var(--negativ); } .saldofarbe { --farbe: var(--akzent); } .diagramm-saldo { stroke: var(--akzent); stroke-width: 1.5; fill: none; } .diagramm circle.diagramm-saldo-punkt { fill: var(--akzent); } /* ── Ringdiagramm ──────────────────────────────────────────────────────────── */ .ringbereich { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; } .ringdiagramm { flex: 0 0 auto; width: 160px; height: 160px; } /* Der schmale Rand in Flächenfarbe trennt benachbarte Segmente, ohne dass es nach Umrandung aussieht. */ .ringdiagramm path { fill: var(--farbe); stroke: var(--flaeche); stroke-width: 1.5; } .ringsumme { fill: var(--text); font-family: var(--schrift-zahl); font-size: 13px; font-weight: 600; text-anchor: middle; } .ringtext { fill: var(--text-gedaempft); font-family: var(--schrift); font-size: 10px; } .ringlegende { list-style: none; margin: 0; padding: 0; flex: 1 1 12rem; min-width: 0; font-size: .78rem; } .ringlegende li { display: grid; grid-template-columns: .65rem 1fr auto auto; align-items: center; gap: .45rem; padding: .15rem 0; } .ringlegende .legendenbetrag { font-family: var(--schrift-zahl); font-size: .74rem; } .ringlegende .legendenanteil { color: var(--text-gedaempft); font-size: .72rem; min-width: 2.4rem; text-align: right; } /* ── Offene Vorgänge ───────────────────────────────────────────────────────── */ .vorgangsliste { list-style: none; margin: 0; padding: 0; font-size: .92rem; } .vorgangsliste li { padding: .3rem 0; border-bottom: 1px solid var(--rand); } .vorgangsliste li:last-child { border-bottom: none; } .vorgangszahl { display: inline-block; min-width: 1.6rem; padding: .05rem .4rem; margin-right: .4rem; border-radius: 999px; background: var(--akzent-schwach); color: var(--akzent); font-family: var(--schrift-zahl); font-size: .8rem; text-align: center; } /* ── Ein/Aus-Schalter ──────────────────────────────────────────────────────── Die Bahn mit dem laufenden Knopf, wie man ihn von Mobilgeräten kennt. Ein abschickender Knopf statt eines Ankreuzfelds: Ohne Inline-Skript könnte ein Ankreuzfeld sein Formular nicht selbst abschicken, und Inline-Skripte verbietet die Content-Security-Policy. */ .schalterform { margin: 0; } .schalter { display: inline-flex; align-items: center; gap: .5rem; padding: .15rem; border: none; border-radius: var(--radius); background: none; color: var(--text-gedaempft); font: inherit; font-size: .85rem; cursor: pointer; } .schalter[aria-checked="true"] { color: var(--text); } .schalter:focus-visible { outline: 2px solid var(--akzent); outline-offset: 1px; } .schalterbahn { position: relative; flex: none; width: 2.3rem; height: 1.25rem; border-radius: 999px; background: var(--rand-kraeftig); transition: background .15s ease; } .schalterknopf { position: absolute; top: .15rem; left: .15rem; width: .95rem; height: .95rem; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgb(0 0 0 / 35%); transition: transform .15s ease; } .schalter[aria-checked="true"] .schalterbahn { background: var(--akzent); } .schalter[aria-checked="true"] .schalterknopf { transform: translateX(1.05rem); } /* ── Tabellen ────────────────────────────────────────────────────────────── */ table.liste { width: 100%; border-collapse: collapse; background: var(--flaeche); border: 1px solid var(--rand); border-radius: var(--radius); overflow: hidden; font-size: .92rem; } table.liste th, table.liste td { padding: .45rem .7rem; text-align: left; border-bottom: 1px solid var(--rand); } table.liste thead th { background: var(--flaeche-gedaempft); font-weight: 600; color: var(--text-gedaempft); white-space: nowrap; } table.liste tbody tr:last-child td { border-bottom: none; } table.liste tbody tr:hover { background: var(--flaeche-gedaempft); } .rechts { text-align: right; } .betrag { font-family: var(--schrift-zahl); font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; } .betrag.negativ { color: var(--negativ); } .nowrap { white-space: nowrap; } /* Gliederung der Kontenübersicht: Gruppenkopf, Gruppensumme, Gesamtsumme. */ table.liste tr.gruppenzeile th { background: var(--flaeche-gedaempft); border-top: 1px solid var(--rand); font-size: .85rem; letter-spacing: .03em; text-transform: uppercase; color: var(--text-gedaempft); } table.liste tr.gruppensumme td { font-weight: 600; background: color-mix(in srgb, var(--flaeche-gedaempft) 55%, var(--flaeche)); } table.liste tfoot tr.summenzeile td { font-weight: 700; border-top: 2px solid var(--rand-kraeftig); background: var(--flaeche-gedaempft); } table.liste tr.inaktiv td { color: var(--text-gedaempft); } table.liste input[type="text"], table.liste input[type="number"] { width: 100%; padding: .25rem .4rem; border: 1px solid var(--rand); border-radius: 4px; background: var(--flaeche); color: var(--text); font: inherit; } table.liste input.schmal { width: 5rem; } /* ── Budgetplaner ──────────────────────────────────────────────────────────── Zwölf Monatsspalten passen auf keinen Bildschirm: Die Tabelle scrollt in ihrem eigenen Rahmen, die Kategoriespalte bleibt dabei stehen. */ .breittabelle { overflow-x: auto; margin-bottom: 1rem; } table.budgetplaner { min-width: 100%; } table.budgetplaner th, table.budgetplaner td { padding: .3rem .5rem; white-space: nowrap; } table.budgetplaner .spalte-kategorie { position: sticky; left: 0; z-index: 1; background: var(--flaeche); min-width: 16rem; } table.budgetplaner thead .spalte-kategorie, table.budgetplaner tfoot .spalte-kategorie { background: var(--flaeche-gedaempft); } table.budgetplaner tbody tr:hover .spalte-kategorie { background: var(--flaeche-gedaempft); } table.budgetplaner th.gruppenkopf { text-align: center; border-left: 1px solid var(--rand); } /* Der laufende Monat ist die Spalte, auf die man zuerst schaut. */ table.budgetplaner .laufend { background: color-mix(in srgb, var(--akzent) 8%, transparent); } table.budgetplaner tr.summenzeile-kategorie td { font-weight: 600; } /* Breit genug für „123.456,78“ – eine Stelle mehr, als der Haushalt braucht. */ table.budgetplaner input.betragsfeld { width: 7rem; text-align: right; font-family: var(--schrift-zahl); font-variant-numeric: tabular-nums; } table.budgetplaner td.rechts { font-family: var(--schrift-zahl); font-variant-numeric: tabular-nums; } /* Zahnrad vor jedem Eingabefeld: verteilt den Wert über die Zeile. Das Menü dazu gibt es nur einmal; app.js hängt es in die angeklickte Zelle, die es deshalb verankern muss. Positioniert wird über CSS, nicht über ein per JavaScript gesetztes style-Attribut – das verwürfe die Content-Security-Policy (style-src 'self'). */ table.budgetplaner td.budgetzelle { position: relative; } .zahnrad { border: none; background: none; color: var(--text-gedaempft); cursor: pointer; font-size: .85rem; line-height: 1; /* Ein Drittel des früheren Abstands: Der kam aus diesem Padding plus dem Leerzeichen im Markup, das die Zelle in Ziffernschrift breit setzte. */ padding: 0 .27rem 0 0; } .zahnrad:hover, .zahnrad[aria-expanded="true"] { color: var(--akzent); } .zahnradmenue { position: absolute; top: 100%; right: .3rem; z-index: 3; display: flex; flex-direction: column; min-width: 10rem; padding: .2rem; border: 1px solid var(--rand-kraeftig); border-radius: var(--radius); background: var(--flaeche); box-shadow: 0 4px 12px rgb(0 0 0 / 18%); } /* Fließtext, nicht Zahlensatz: Die Zelle vererbt sonst ihre Ziffernschrift. */ .menueeintrag { border: none; background: none; color: var(--text); cursor: pointer; font: inherit; font-family: var(--schrift); font-size: .88rem; text-align: left; padding: .35rem .5rem; border-radius: var(--radius); white-space: nowrap; } .menueeintrag:hover { background: var(--flaeche-gedaempft); } /* Aufklappen des Kategoriebaums; ohne JavaScript bleibt alles sichtbar. */ .klappknopf { border: none; background: none; color: var(--text-gedaempft); cursor: pointer; font: inherit; padding: 0 .3rem 0 0; } .klappknopf[aria-expanded="false"] { transform: rotate(-90deg); display: inline-block; } tr.zugeklappt { display: none; } /* Einrückung des Kategoriebaums. Die Ebene steht als data-Attribut an der Zeile – so bleibt die Tabelle frei von verschachtelten Elementen. Kein style-Attribut: Die Content-Security-Policy (style-src 'self') verwirft Inline-Styles, die Einrückung fiele stillschweigend aus. */ .baumname { display: inline-block; padding-left: 0; } .baumname[data-ebene="1"] { padding-left: 1.4rem; } .baumname[data-ebene="2"] { padding-left: 2.8rem; } .baumname[data-ebene="3"] { padding-left: 4.2rem; } .baumname[data-ebene="4"] { padding-left: 5.6rem; } .baumname[data-ebene="5"] { padding-left: 7rem; } .baumname[data-ebene="6"] { padding-left: 8.4rem; } .nebentext { color: var(--text-gedaempft); font-size: .88rem; } .marke { display: inline-block; padding: .05rem .4rem; border: 1px solid var(--rand-kraeftig); border-radius: 999px; font-size: .75rem; color: var(--text-gedaempft); white-space: nowrap; } .kennzahl { font-family: var(--schrift-zahl); font-size: 2rem; font-weight: 600; margin: .2rem 0; } .protokoll { margin: .4rem 0 0; padding-left: 1.1rem; font-size: .9rem; } .protokoll li.fehler { color: var(--negativ); } /* ── Aktionsleiste über den Listen ───────────────────────────────────────── */ .seitenaktionen { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-bottom: 1rem; } .seitenaktionen .fuellung { flex: 1; } .saldoanzeige { font-size: .9rem; color: var(--text-gedaempft); } .saldoanzeige strong { margin-left: .35rem; font-family: var(--schrift-zahl); font-size: 1.05rem; color: var(--text); } .saldoanzeige strong.negativ { color: var(--negativ); } /* ── Kontoblatt ──────────────────────────────────────────────────────────── */ .filterleiste { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-bottom: 1rem; padding: .6rem .75rem; background: var(--flaeche); border: 1px solid var(--rand); border-radius: var(--radius); } .filterleiste input[type="search"], .filterleiste input[type="date"], .filterleiste select { padding: .3rem .45rem; border: 1px solid var(--rand); border-radius: 4px; background: var(--flaeche); color: var(--text); font: inherit; font-size: .9rem; } .filterleiste input[type="search"] { min-width: 16rem; } .filterleiste select { max-width: 15rem; } .filterleiste label { font-size: .88rem; color: var(--text-gedaempft); } table.kontoblatt { font-size: .89rem; } table.kontoblatt td { padding: .3rem .6rem; } table.kontoblatt tr.gegensicht td { background: color-mix(in srgb, var(--akzent) 5%, transparent); } .gekuerzt { max-width: 26rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .blaettern { display: flex; align-items: center; gap: .75rem; margin-top: .8rem; } /* Die Splittabelle sitzt im Formular und braucht schmalere Zellen. */ table.splittabelle td { padding: .3rem .4rem; } table.splittabelle select { max-width: 14rem; width: 100%; } table.splittabelle input.rechts { text-align: right; } .buchungsmaske [hidden] { display: none; } /* ── Formulare ───────────────────────────────────────────────────────────── */ .formular { display: flex; flex-direction: column; gap: .35rem; max-width: 380px; } .formular.breit { max-width: 620px; background: var(--flaeche); border: 1px solid var(--rand); border-radius: var(--radius); padding: 1.25rem; box-shadow: var(--schatten); } .formular label { font-size: .9rem; font-weight: 500; margin-top: .6rem; } .formular label.ankreuzfeld { display: flex; align-items: center; gap: .5rem; font-weight: 500; } /* Mehrfachauswahl im Formular – etwa die Konten einer Kontengruppe. Bei vielen Einträgen scrollt die Liste, statt das Formular auseinanderzuziehen. */ .auswahlliste { display: flex; flex-direction: column; gap: .35rem; max-height: 22rem; overflow-y: auto; padding: .6rem .7rem; border: 1px solid var(--rand); border-radius: var(--radius); background: var(--flaeche-gedaempft); } .auswahlliste .ankreuzfeld { margin: 0; } .auswahlliste .nebentext { margin-left: .35rem; } .formular input[type="text"], .formular input[type="password"], .formular input[type="number"], .formular select { font: inherit; padding: .5rem .6rem; border: 1px solid var(--rand-kraeftig); border-radius: var(--radius); background: var(--flaeche); color: var(--text); width: 100%; } .formular input:focus-visible, .formular select:focus-visible, .knopf:focus-visible { outline: 2px solid var(--akzent); outline-offset: 1px; } .formular h3 { margin: 1.5rem 0 .5rem; font-size: .95rem; } .feldhinweis { font-size: .85rem; color: var(--text-gedaempft); margin: .15rem 0 0; } /* Der Hinweis hinter einem Ankreuzfeld statt darunter – bei einer Liste gleichartiger Schalter hielte eine eigene Zeile je Hinweis sie zu weit auseinander. */ .feldhinweis.inline { margin: 0; font-weight: 400; } .optional { font-weight: 400; color: var(--text-gedaempft); } .knopfleiste { display: flex; gap: .6rem; margin-top: 1.25rem; } .knopf { display: inline-block; font: inherit; font-size: .93rem; padding: .5rem 1rem; border: 1px solid var(--rand-kraeftig); border-radius: var(--radius); background: var(--flaeche); color: var(--text); cursor: pointer; } .knopf:hover { background: var(--flaeche-gedaempft); text-decoration: none; } /* Kein eigener Außenabstand: der primäre Knopf steht sonst in jeder Knopfleiste um genau diesen Betrag tiefer als seine Nachbarn. Den Abstand nach oben setzt allein die .knopfleiste. */ .knopf.primaer { background: var(--akzent); border-color: var(--akzent); color: var(--akzent-text); font-weight: 500; } .knopf.primaer:hover { filter: brightness(1.08); } .knopf.klein { padding: .25rem .6rem; font-size: .85rem; } /* Ein Knopf, der die gerade gewählte Ansicht markiert – etwa die drei Spaltenbilder des Budgetplaners. */ .knopf.aktiv { background: var(--akzent-schwach); border-color: var(--akzent); font-weight: 500; } .knopf.gefahr { border-color: var(--negativ); color: var(--negativ); background: var(--flaeche); } .knopf.gefahr:hover { background: color-mix(in srgb, var(--negativ) 12%, var(--flaeche)); } .feldwert { margin: .1rem 0 .3rem; } /* ── Meldungen ───────────────────────────────────────────────────────────── */ .meldung { padding: .65rem .9rem; border-radius: var(--radius); border: 1px solid var(--rand); margin-bottom: 1rem; font-size: .92rem; } .meldung-erfolg { background: var(--akzent-schwach); border-color: var(--akzent); } /* Erfolgsmeldungen blenden sich nach einigen Sekunden aus (app.js). */ .meldung.verblasst { opacity: 0; transition: opacity .4s; } .meldung-fehler { background: color-mix(in srgb, var(--negativ) 12%, var(--flaeche)); border-color: var(--negativ); } .meldung-warnung { background: color-mix(in srgb, var(--warnung) 15%, var(--flaeche)); border-color: var(--warnung); } .hinweis { color: var(--text-gedaempft); font-size: .93rem; } /* ── Schlichter Rahmen (Anmeldung, Fehlerseiten) ─────────────────────────── */ body.schlicht { display: grid; place-items: center; min-height: 100vh; padding: 1.5rem; } .karte-mitte { background: var(--flaeche); border: 1px solid var(--rand); border-radius: 10px; box-shadow: var(--schatten); padding: 2rem; width: 100%; max-width: 400px; } .marke.gross { padding: 0 0 1.25rem; font-size: 1.3rem; color: var(--text); } /* ── Auswertungen ────────────────────────────────────────────────────────── */ /* Aufklappmenü ohne JavaScript:
in der Aktionsleiste. Ein eigenes Menü mit Skript wäre mehr Code für dasselbe Verhalten – und die Content-Security-Policy verbietet Inline-Handler ohnehin. */ .menue { position: relative; display: inline-block; } .menue > summary { list-style: none; user-select: none; } .menue > summary::-webkit-details-marker { display: none; } .menueliste { position: absolute; z-index: 20; top: calc(100% + .3rem); left: 0; min-width: 14rem; padding: .35rem; background: var(--flaeche); border: 1px solid var(--rand-kraeftig); border-radius: var(--radius); box-shadow: var(--schatten); } .menueliste.breit { min-width: 22rem; padding: .9rem; } .menueliste > a { display: block; padding: .4rem .55rem; border-radius: 4px; color: var(--text); font-size: .92rem; } .menueliste > a:hover { background: var(--flaeche-gedaempft); text-decoration: none; } .speichernform { display: flex; flex-direction: column; gap: .2rem; } .speichernform label { font-size: .88rem; font-weight: 500; margin-top: .5rem; } .speichernform input[type="text"], .speichernform select { font: inherit; font-size: .92rem; padding: .4rem .5rem; border: 1px solid var(--rand-kraeftig); border-radius: 4px; background: var(--flaeche); color: var(--text); width: 100%; } .speichernform .knopfleiste { margin-top: .9rem; } /* Die Berichtsliste einer Gruppenkachel. */ .berichtsliste { list-style: none; margin: .3rem 0 0; padding: 0; } .berichtsliste li { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem; padding: .25rem 0; border-bottom: 1px solid var(--rand); } .berichtsliste li:last-child { border-bottom: none; } .berichtssymbol { color: var(--text-gedaempft); margin-right: .35rem; } .berichtstyp { color: var(--text-gedaempft); font-size: .82rem; white-space: nowrap; } /* Die Filterleiste des Berichts steht mehrzeilig – anders als die einzeilige des Kontoblatts, von der sie das Aussehen erbt. */ .berichtsfilter { flex-direction: column; align-items: stretch; gap: .6rem; } .filterzeile { display: flex; flex-wrap: wrap; align-items: end; gap: .5rem .9rem; } .filterzeile > label { display: flex; flex-direction: column; gap: .15rem; font-size: .82rem; color: var(--text-gedaempft); } .filterzeile label.ankreuz { flex-direction: row; align-items: center; gap: .35rem; padding-bottom: .35rem; } .filterzeile select[multiple] { min-width: 13rem; max-width: 18rem; font-size: .88rem; /* Vorformatierter Text: Nur so bleibt die Einrückung des Kategoriebaums in den Optionen stehen – der Browser faltet Leerzeichen sonst zusammen. */ white-space: pre; } .einschraenkung > summary { cursor: pointer; font-size: .85rem; color: var(--text-gedaempft); padding: .2rem 0; } .einschraenkung[open] > summary { margin-bottom: .5rem; } .hinweis.klein { font-size: .82rem; margin-top: .6rem; } .berichtskopf { text-align: center; margin: 1.4rem 0 .8rem; } .berichtskopf h2 { margin: 0; font-size: 1.15rem; } .berichtskopf p { margin: .15rem 0 0; color: var(--text-gedaempft); font-size: .88rem; } table.bericht { font-size: .9rem; } table.bericht td { padding: .28rem .7rem; } /* Abschnittsüberschrift „Einnahmen“ / „Ausgaben“. */ table.bericht tr.abschnittszeile th { text-align: left; padding-top: .8rem; background: var(--flaeche-gedaempft); font-size: .95rem; } /* „Gesamt 400 - Leben“ – die Summe eines Kategorieastes. */ table.bericht tr.astsumme td { font-weight: 600; background: color-mix(in srgb, var(--akzent) 6%, transparent); } table.bericht tr.ohnezuordnung td { color: var(--text-gedaempft); font-style: italic; } /* Zeilen- und Wertlinks führen in den Drilldown. Sie sollen die Tabelle nicht blau einfärben – erst beim Überfahren zeigt sich, dass es weitergeht. */ table.bericht .zeilenlink, table.bericht .wertlink { color: inherit; } table.bericht .zeilenlink:hover, table.bericht .wertlink:hover { color: var(--akzent); text-decoration: underline; } /* Zeilenweise Formulare: Name, Sortierung und Knopf nebeneinander. */ .zeilenform { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin: 0; } .zeilenform label { display: flex; align-items: center; gap: .35rem; font-size: .88rem; } .zeilenform input[type="text"], .zeilenform input[type="number"] { font: inherit; font-size: .92rem; padding: .35rem .5rem; border: 1px solid var(--rand-kraeftig); border-radius: 4px; background: var(--flaeche); color: var(--text); } .zeilenform input.schmal { width: 5rem; } /* ── Online-Banking ────────────────────────────────────────────────────────── Die Abgleichliste ist keine Tabelle: Zu jedem Umsatz gehören mehrere Wege (verbinden, neu buchen, verwerfen), jeder mit eigenem Formular. In Zellen gepresst wäre das unlesbar; hier bekommt jeder Umsatz eine eigene Karte. */ .umsatz { background: var(--flaeche); border: 1px solid var(--rand); border-radius: var(--radius); padding: .75rem .9rem; margin-bottom: .6rem; } .umsatzkopf { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; } .umsatztext { min-width: 0; } .umsatztext .nebentext { display: block; font-size: .8rem; } .verwendungszweck { margin: .3rem 0 0; font-size: .88rem; color: var(--text-gedaempft); overflow-wrap: anywhere; } .umsatzbetrag { font-family: var(--schrift-zahl); font-size: 1.05rem; font-weight: 600; white-space: nowrap; } .umsatzaktion { display: flex; align-items: center; flex-wrap: wrap; gap: .4rem .6rem; margin-top: .5rem; padding-top: .5rem; border-top: 1px dashed var(--rand); } .umsatzaktion select { max-width: 16rem; } .vorschlagsmarke { background: var(--akzent-schwach); color: var(--akzent); font-size: .75rem; font-weight: 600; padding: .1rem .5rem; border-radius: 999px; white-space: nowrap; } /* Statusmarken der Abrufliste. Sie erben von .marke und färben nur den Rand – ein voll gefüllter Punkt zöge in einer Tabelle zu viel Aufmerksamkeit. */ .marke-erfolg { color: var(--positiv); border-color: var(--positiv); } .marke-fehler { color: var(--negativ); border-color: var(--negativ); } .marke-tan_offen { color: var(--warnung); border-color: var(--warnung); } .marke-abgebrochen { color: var(--text-gedaempft); } .tanhinweis { background: var(--flaeche-gedaempft); border-left: 3px solid var(--akzent); padding: .5rem .7rem; margin: .5rem 0; font-size: .93rem; } /* photoTAN-Grafiken liefern die Banken klein; unskaliert wären sie kaum zu scannen, größer als die Kachel dürfen sie aber auch nicht werden. */ .tanbild { display: block; max-width: 100%; width: 240px; height: auto; margin: .75rem 0; image-rendering: pixelated; background: #fff; padding: .5rem; border-radius: var(--radius); } .protokolltext { margin: 0; padding: .6rem .7rem; background: var(--flaeche-gedaempft); border-radius: var(--radius); font-family: var(--schrift-zahl); font-size: .78rem; white-space: pre-wrap; overflow-x: auto; } .feldpaar { display: flex; gap: .5rem; } .regeltabelle select, .regeltabelle input[type="text"] { max-width: 12rem; } /* ── Wertpapiere ─────────────────────────────────────────────────────────── */ /* Die Kennzahlen über der Depotübersicht: Wert, Einstand, Gewinn, Erträge – nebeneinander, aber umbrechend, damit sie auch auf schmalen Fenstern lesbar bleiben. */ .kennzahlenleiste { display: flex; flex-wrap: wrap; gap: .75rem; margin-bottom: 1.25rem; } .kennzahlkachel { flex: 1 1 9rem; background: var(--flaeche); border: 1px solid var(--rand); border-radius: var(--radius); padding: .6rem .8rem; display: flex; flex-direction: column; gap: .1rem; } .kennzahltitel { font-size: .78rem; color: var(--text-gedaempft); } .kennzahlkachel .kennzahl { font-size: 1.25rem; margin: 0; } /* Zahlenlastige Tabellen bekommen Ziffernschrift in den rechtsbündigen Spalten – so stehen Kommastellen untereinander. */ table.liste.zahlen td.rechts { font-family: var(--schrift-zahl); } .wertflaeche { fill: var(--akzent); opacity: .18; stroke: none; } .wertlinie { fill: none; stroke: var(--akzent); stroke-width: 2; } /* Der Einstand als gestrichelte Linie: Er ist die Vergleichsgröße, nicht der Hauptverlauf. */ .einstandslinie { fill: none; stroke: var(--text-gedaempft); stroke-width: 1.5; stroke-dasharray: 4 3; } .diagramm circle.wertpunkt { fill: var(--akzent); } .wertfarbe { --farbe: var(--akzent); } .einstandsfarbe { --farbe: var(--text-gedaempft); } /* ── Termine, Verträge, Sparziele ────────────────────────────────────────── */ /* Was überfällig ist, wird nicht rot eingefärbt, sondern bekommt eine Kante: Eine ganze Zeile in Signalfarbe liest sich schlechter, nicht dringender. */ table.liste tr.ueberfaellig td:first-child { border-left: 3px solid var(--negativ); padding-left: calc(.6rem - 3px); } .kalendermonat { margin-bottom: 1.5rem; } .kalendermonat h3 { margin: 0 0 .4rem; font-size: .95rem; color: var(--text-gedaempft); } .kalendertag { width: 3.5rem; white-space: nowrap; } .tagzahl { font-family: var(--schrift-zahl); font-size: 1.1rem; font-weight: 600; margin-right: .3rem; } table.liste tr.luecke td { text-align: center; font-style: italic; background: var(--flaeche-gedaempft); } /* statt eines eigenen Balkens: Die Breite käme sonst nur über ein style-Attribut zustande, und das verbietet die Content-Security-Policy. */ .fortschritt { display: block; width: 100%; height: .75rem; margin: .5rem 0 .3rem; border: none; border-radius: 999px; background: var(--flaeche-gedaempft); appearance: none; } .fortschritt::-webkit-progress-bar { background: var(--flaeche-gedaempft); border-radius: 999px; } .fortschritt::-webkit-progress-value { background: var(--positiv); border-radius: 999px; } .fortschritt::-moz-progress-bar { background: var(--positiv); border-radius: 999px; } .fortschrittstext { margin: 0 0 .5rem; font-size: .95rem; } .marke-entwurf { color: var(--warnung); border-color: var(--warnung); } .marke-gesendet { color: var(--positiv); border-color: var(--positiv); } .marke-storniert { color: var(--text-gedaempft); } .kennzahl.klein { font-size: 1rem; } /* ── Schmale Fenster ─────────────────────────────────────────────────────── */ @media (max-width: 820px) { .rahmen { grid-template-columns: 1fr; } .seitenleiste { position: static; height: auto; padding-bottom: .5rem; } .seitenleiste ul { display: flex; overflow-x: auto; } .seitenleiste a { border-left: none; border-bottom: 3px solid transparent; white-space: nowrap; } .seitenleiste a.aktiv { border-left: none; border-bottom-color: #fff; } }