Toggle „Regel anlegen“ in der Buchungsmaske (Fix #94); beim Speichern entsteht daraus eine Regel (AbgleichRegel::ausBuchung()), die das Kontoblatt danach in einem modalen Dialog zum Prüfen und Anpassen zeigt. Abbruch (auch per Escape) verwirft die Regel wieder, Speichern übernimmt Änderungen. Die Regelfelder sind aus regeln.php in regelfelder.php ausgelagert, damit beide Formulare dieselbe Bauart teilen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2384 lines
65 KiB
CSS
2384 lines
65 KiB
CSS
/* 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;
|
||
--navi-marke: #6ea8fe;
|
||
--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;
|
||
}
|
||
|
||
/* Die Marke der Seitenleiste hat eine eigene Klasse: ".marke" allein ist
|
||
weiter unten die kleine Statusmarke, deren Regeln hier sonst gewönnen. */
|
||
.seitenleisten-marke {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: .6rem;
|
||
width: 100%;
|
||
background: none;
|
||
border: 0;
|
||
border-bottom: 1px solid rgba(255, 255, 255, .08);
|
||
font-family: inherit;
|
||
font-size: 1.05rem;
|
||
font-weight: 700;
|
||
color: #fff;
|
||
padding: 1.1rem 1.25rem;
|
||
letter-spacing: .01em;
|
||
text-align: left;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.seitenleisten-marke:hover { background: rgba(255, 255, 255, .05); }
|
||
|
||
|
||
.marken-symbol {
|
||
width: 1.6em;
|
||
height: 1.6em;
|
||
flex-shrink: 0;
|
||
object-fit: contain;
|
||
}
|
||
|
||
.marken-text { color: #fff; white-space: nowrap; }
|
||
|
||
/* Wie im Steuerkram: die zweite Worthälfte trägt die Akzentfarbe. */
|
||
.marken-text span { color: var(--navi-marke); }
|
||
|
||
.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;
|
||
}
|
||
|
||
/* ── Eingeklappte Seitenleiste ───────────────────────────────────────────── */
|
||
|
||
/* Ein Klick auf die Marke schiebt die Leiste auf Symbolbreite zusammen. Die
|
||
Beschriftungen verschwinden nur aus dem Bild, nicht aus dem Baum – sonst
|
||
verlören die Verweise ihren Namen für Vorleseprogramme. */
|
||
.rahmen.eingeklappt { grid-template-columns: 64px 1fr; }
|
||
|
||
.rahmen.eingeklappt .seitenleisten-marke,
|
||
.rahmen.eingeklappt .seitenleiste a {
|
||
justify-content: center;
|
||
gap: 0;
|
||
padding-left: 0;
|
||
padding-right: 0;
|
||
}
|
||
|
||
|
||
.rahmen.eingeklappt .marken-text,
|
||
.rahmen.eingeklappt .beschriftung {
|
||
position: absolute;
|
||
width: 1px;
|
||
height: 1px;
|
||
overflow: hidden;
|
||
clip-path: inset(50%);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* ── 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; }
|
||
|
||
/* Der Abrufknopf mit dem Stichtagsfeld davor: Beide gehören zusammen und sollen
|
||
auf einer Zeile bleiben – auch in der rechtsbündigen Aktionsspalte. */
|
||
.abrufform {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: .4rem;
|
||
}
|
||
|
||
.stichtagwahl {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: .35rem;
|
||
font-size: .88rem;
|
||
color: var(--text-gedaempft);
|
||
}
|
||
|
||
.stichtagfeld {
|
||
padding: .25rem .4rem;
|
||
border: 1px solid var(--rand);
|
||
border-radius: 4px;
|
||
background: var(--flaeche);
|
||
color: var(--text);
|
||
font: inherit;
|
||
font-size: .85rem;
|
||
}
|
||
|
||
.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; }
|
||
|
||
/* Kacheln mit unterschiedlich langem Text – etwa in der Verwaltung – lassen ihre
|
||
Knopfleisten sonst auf verschiedenen Höhen enden. Die Kachel wird zur
|
||
Flexspalte, der freie Platz sammelt sich über der Knopfleiste, und die Knöpfe
|
||
stehen in jeder Kachel derselben Zeile auf gleicher Höhe am unteren Rand. */
|
||
.kachelraster.fussbuendig > .kachel {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* Der Abstand nach oben wandert ins Padding: `margin-top: auto` schluckt den
|
||
Außenabstand und ließe die Knöpfe in der höchsten Kachel – die keinen freien
|
||
Platz mehr hat – direkt am Text kleben. */
|
||
.kachelraster.fussbuendig > .kachel > .knopfleiste {
|
||
margin-top: auto;
|
||
padding-top: 1.25rem;
|
||
}
|
||
|
||
.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;
|
||
}
|
||
|
||
/* Legendeneinträge führen in die Buchungen dahinter („Übrige Konten“ eine
|
||
Ebene tiefer): Der Eintrag ist ein Link und sieht auch danach aus – sonst
|
||
probierte ihn niemand aus. */
|
||
a.legendenname {
|
||
color: var(--akzent);
|
||
text-decoration: underline dotted;
|
||
text-underline-offset: 2px;
|
||
}
|
||
|
||
a.legendenname: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; }
|
||
|
||
/* In Listen reicht `.rechts` allein nicht: `table.liste th, table.liste td`
|
||
weiter oben setzt text-align auf links und ist spezifischer. Zahlen- und
|
||
Aktionsspalten stehen deshalb ausdrücklich rechts – die Klasse tut damit
|
||
überall das, was ihr Name sagt. */
|
||
table.liste th.rechts,
|
||
table.liste td.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); }
|
||
|
||
/* Spalte mit dem Ankreuzfeld der Mehrfachauswahl – so schmal wie möglich. */
|
||
table.liste th.wahlspalte,
|
||
table.liste td.wahlspalte {
|
||
width: 1px;
|
||
padding-right: .3rem;
|
||
text-align: center;
|
||
}
|
||
|
||
/* Die Zuordnung Bankkonto → eigenes Konto, kurz im Zugangsformular. */
|
||
ul.kontenzuordnung {
|
||
margin: .25rem 0 .75rem;
|
||
padding-left: 1.1rem;
|
||
}
|
||
|
||
ul.kontenzuordnung li { margin-bottom: .2rem; }
|
||
|
||
/* Zusatzzeile einer Liste – die Felder für ein neu anzulegendes Konto in der
|
||
Kontenzuordnung. Sie hängt optisch an der Zeile darüber. */
|
||
table.liste tr.unterzeile td {
|
||
border-top: 0;
|
||
padding-top: 0;
|
||
}
|
||
|
||
table.liste tr[hidden] { display: none; }
|
||
|
||
td.neues-konto {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
gap: .4rem .6rem;
|
||
}
|
||
|
||
td.neues-konto label {
|
||
margin: 0;
|
||
font-size: .85rem;
|
||
color: var(--text-gedaempft);
|
||
}
|
||
|
||
td.neues-konto input[type="text"] { width: auto; min-width: 12rem; }
|
||
td.neues-konto .nebentext { flex-basis: 100%; }
|
||
|
||
/* Konten mit unkategorisierten Buchungen aus dem laufenden Jahr. Fett wie im
|
||
FinanzManager – kein Farbwechsel, sonst kollidierte er mit der Ampel der
|
||
Salden in derselben Zeile. */
|
||
table.liste.konten tr.unkategorisiert td:first-child a { font-weight: 700; }
|
||
|
||
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); }
|
||
|
||
/* Kombobox: <select> per Typeahead bedienbar, siehe kombobox.js (Fix #41). Das
|
||
Eingabefeld tritt optisch an die Stelle des <select>, darunter klappt die
|
||
gefilterte Liste auf. Größe und Rahmen übernimmt die Kombobox von dem
|
||
Feldtyp, in dem sie steht – Filterleiste und Schnellzuordnung sehen sonst
|
||
unterschiedlich groß aus. */
|
||
.kombobox { position: relative; display: inline-block; }
|
||
|
||
.kombobox-eingabe {
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
border: 1px solid var(--rand);
|
||
border-radius: 4px;
|
||
background: var(--flaeche);
|
||
color: var(--text);
|
||
font: inherit;
|
||
}
|
||
|
||
.kombobox-liste {
|
||
position: absolute;
|
||
z-index: 20;
|
||
top: 100%;
|
||
left: 0;
|
||
right: 0;
|
||
margin: .2rem 0 0;
|
||
padding: .25rem 0;
|
||
max-height: 16rem;
|
||
overflow-y: auto;
|
||
list-style: none;
|
||
border: 1px solid var(--rand-kraeftig);
|
||
border-radius: var(--radius);
|
||
background: var(--flaeche);
|
||
box-shadow: 0 6px 18px rgb(0 0 0 / 20%);
|
||
}
|
||
|
||
.kombobox-gruppe {
|
||
padding: .2rem .6rem;
|
||
color: var(--text-gedaempft);
|
||
font-size: .78rem;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.kombobox-option { padding: .25rem .7rem; cursor: pointer; }
|
||
.kombobox-option.aktiv { background: var(--flaeche-gedaempft); }
|
||
.kombobox-leer { padding: .25rem .7rem; color: var(--text-gedaempft); }
|
||
|
||
.filterleiste .kombobox { max-width: 15rem; }
|
||
.filterleiste .kombobox-eingabe { padding: .3rem .45rem; font-size: .9rem; }
|
||
|
||
.formular .kombobox { width: 100%; }
|
||
.formular .kombobox-eingabe { padding: .5rem .6rem; }
|
||
|
||
.zuordnungsauswahl .kombobox { width: 100%; max-width: 13rem; }
|
||
.zuordnungsauswahl .kombobox-eingabe {
|
||
height: 1.35rem;
|
||
padding: 0 .2rem;
|
||
border-color: var(--akzent);
|
||
font-size: .85rem;
|
||
}
|
||
|
||
table.kontoblatt { font-size: .89rem; }
|
||
table.kontoblatt tr.gegensicht td { background: color-mix(in srgb, var(--akzent) 5%, transparent); }
|
||
|
||
/* Alle Buchungszeilen sind gleich hoch – zwei Textzeilen – und ihr Inhalt steht
|
||
in der Mitte. Eine Zeile, die mit ihrem Text wächst, ließe das Kontoblatt beim
|
||
Blättern hüpfen; eine, die auf eine Zeile schrumpft, machte lange Empfänger
|
||
unlesbar. Was auf zwei Zeilen nicht passt, wird abgeschnitten und steht
|
||
vollständig im Tooltip. */
|
||
table.kontoblatt td {
|
||
padding: .3rem .6rem;
|
||
line-height: 1.35;
|
||
height: calc(2 * 1.35em + .6rem);
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.zellentext {
|
||
display: -webkit-box;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 2;
|
||
line-clamp: 2;
|
||
overflow: hidden;
|
||
overflow-wrap: anywhere;
|
||
}
|
||
|
||
/* Text und Marke nebeneinander: Abgeschnitten wird nur der Text, die Marke
|
||
bleibt vollständig stehen. */
|
||
.zellenreihe {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: .4rem;
|
||
}
|
||
|
||
.zellenreihe .zellentext { min-width: 0; }
|
||
|
||
/* Im abgeschnittenen Kasten wird die Marke zum Blockelement – ohne diese Breite
|
||
liefe ihr Rahmen bis zum Rand der Spalte. */
|
||
a.zuordnungsfeld .marke { width: fit-content; }
|
||
|
||
.buchungstext { max-width: 26rem; }
|
||
|
||
.blaettern {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: .75rem;
|
||
margin-top: .8rem;
|
||
}
|
||
|
||
/* Schnellzuordnung: Die Kategoriespalte ist anklickbar wie ein Eingabefeld,
|
||
sieht aber nicht danach aus – sonst flimmerte die ganze Spalte. Der
|
||
gestrichelte Unterstrich erscheint erst beim Überfahren.
|
||
|
||
Feld und Auswahlliste sind gleich breit und gleich hoch. Sonst rückte beim
|
||
Anklicken die halbe Zeile: Die Spalte wüchse auf die Breite der längsten
|
||
Kategorie, und der Empfänger daneben bräche um. */
|
||
td.zuordnungszelle { width: 13rem; }
|
||
td.klassenzelle { width: 9rem; }
|
||
|
||
a.zuordnungsfeld,
|
||
a.klassenfeld {
|
||
display: -webkit-box;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 2;
|
||
line-clamp: 2;
|
||
max-width: 13rem;
|
||
min-height: 1.35rem;
|
||
overflow: hidden;
|
||
overflow-wrap: anywhere;
|
||
color: inherit;
|
||
text-decoration: none;
|
||
border-bottom: 1px dashed transparent;
|
||
}
|
||
|
||
a.klassenfeld { max-width: 9rem; }
|
||
|
||
a.zuordnungsfeld:hover,
|
||
a.zuordnungsfeld:focus-visible,
|
||
a.klassenfeld:hover,
|
||
a.klassenfeld:focus-visible { border-bottom-color: var(--rand-kraeftig); }
|
||
|
||
.zuordnungsauswahl { display: flex; gap: .3rem; }
|
||
.zuordnungsauswahl[hidden] { display: none; }
|
||
|
||
.zuordnungsauswahl select {
|
||
width: 100%;
|
||
max-width: 13rem;
|
||
height: 1.35rem;
|
||
padding: 0 .2rem;
|
||
border: 1px solid var(--akzent);
|
||
border-radius: 4px;
|
||
background: var(--flaeche);
|
||
color: var(--text);
|
||
font: inherit;
|
||
font-family: var(--schrift);
|
||
font-size: .85rem;
|
||
}
|
||
|
||
/* 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; }
|
||
|
||
/* Überschrift der Splittabelle mit dem Knopf „Splitbuchungen löschen“ rechts. */
|
||
.buchungsmaske .splitkopf { display: flex; align-items: center; gap: .6rem; }
|
||
.buchungsmaske .splitkopf h3 { margin: 0; }
|
||
.buchungsmaske .splitkopf .knopf { margin-left: auto; }
|
||
|
||
/* Der Splitdialog des Kontoblatts. Als <dialog> und nicht als eigene Seite:
|
||
Die Aufteilung gehört zur Zeile, aus der sie geöffnet wurde. */
|
||
.splitdialog {
|
||
width: min(46rem, 92vw);
|
||
padding: 1.1rem 1.25rem 1.25rem;
|
||
border: 1px solid var(--rand-kraeftig);
|
||
border-radius: var(--radius);
|
||
background: var(--flaeche);
|
||
color: var(--text);
|
||
box-shadow: 0 10px 30px rgb(0 0 0 / 25%);
|
||
}
|
||
|
||
.splitdialog::backdrop { background: rgb(0 0 0 / 35%); }
|
||
|
||
.splitdialog h2 { margin: 0 0 .3rem; font-size: 1.05rem; }
|
||
.splitdialog .knopfleiste { margin-top: .9rem; }
|
||
.splitdialog .splittabelle { margin-top: .6rem; }
|
||
|
||
/* Das Löschen der ganzen Aufteilung steht rechts außen – weit weg von
|
||
„Speichern“ und „Abbrechen“, damit es nicht im Vorbeigehen getroffen wird. */
|
||
.splitdialog .knopfleiste .knopf.gefahr { margin-left: auto; }
|
||
|
||
/* Die Formatwahl vor Import und Export – als Dialog auf der Verwaltungsseite
|
||
und als Kachelinhalt auf der Ausweichseite, deshalb zwei Ebenen: der Dialog
|
||
trägt den Rahmen, .formatwahl die Karten. */
|
||
.formatdialog {
|
||
width: min(34rem, 92vw);
|
||
padding: 1.1rem 1.25rem 1.25rem;
|
||
border: 1px solid var(--rand-kraeftig);
|
||
border-radius: var(--radius);
|
||
background: var(--flaeche);
|
||
color: var(--text);
|
||
box-shadow: 0 10px 30px rgb(0 0 0 / 25%);
|
||
}
|
||
|
||
.formatdialog::backdrop { background: rgb(0 0 0 / 35%); }
|
||
.formatdialog h2 { margin: 0 0 .3rem; font-size: 1.05rem; }
|
||
.formatdialog .knopfleiste { margin-top: .9rem; }
|
||
|
||
.formatwahl {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
|
||
gap: .7rem;
|
||
margin-top: .8rem;
|
||
}
|
||
|
||
.formatkarte {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: .25rem;
|
||
padding: .8rem .9rem;
|
||
border: 1px solid var(--rand-kraeftig);
|
||
border-radius: var(--radius);
|
||
background: var(--flaeche-gedaempft);
|
||
color: inherit;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.formatkarte:hover,
|
||
.formatkarte:focus-visible {
|
||
border-color: var(--akzent);
|
||
background: color-mix(in srgb, var(--akzent) 8%, transparent);
|
||
}
|
||
|
||
.formatname { font-weight: 600; font-size: 1.05rem; }
|
||
|
||
/* Der Wertpapierdialog trägt ein Formular und wird dadurch länger als der
|
||
Splitdialog; bei kleinen Fenstern scrollt er. Der Regeldialog übernimmt
|
||
dieselben Regelfelder wie die Regelliste – aus demselben Grund dieselbe
|
||
Bauart. */
|
||
.wertpapierdialog { max-height: 88vh; overflow-y: auto; }
|
||
.wertpapierdialog .formular { max-width: none; }
|
||
.wertpapierdialog h2 { margin: 0 0 .3rem; font-size: 1.05rem; }
|
||
|
||
.regeldialog { max-height: 88vh; overflow-y: auto; }
|
||
.regeldialog .formular { max-width: none; }
|
||
|
||
/* Die Kostentabelle: Betrag rechts, Kategorie als stiller Hinweis daneben. */
|
||
table.kostentabelle { margin-top: .6rem; }
|
||
table.kostentabelle td { padding: .25rem .4rem; }
|
||
table.kostentabelle input.rechts { text-align: right; width: 7.5rem; }
|
||
table.kostentabelle select { max-width: 16rem; width: 100%; }
|
||
table.kostentabelle th[scope="row"] { font-weight: 400; text-align: left; }
|
||
table.kostentabelle .gruppenzeile th { padding-top: .7rem; font-weight: 600; }
|
||
|
||
/* Die Abgleichspalte zwischen Klasse und Betrag: so schmal wie ihr Zeichen.
|
||
Sie erscheint nur, wenn ein Bargeld-Tool eingerichtet ist. */
|
||
table.liste th.bargeldspalte,
|
||
table.liste td.bargeldspalte {
|
||
width: 1.8rem;
|
||
padding-left: .2rem;
|
||
padding-right: .2rem;
|
||
text-align: center;
|
||
}
|
||
|
||
table.liste th.bargeldspalte {
|
||
font-size: .78rem;
|
||
color: var(--text-gedaempft);
|
||
}
|
||
|
||
.bargeldmarke {
|
||
font-size: .95rem;
|
||
line-height: 1;
|
||
cursor: help;
|
||
}
|
||
|
||
.bargeld-gefunden { color: var(--positiv); }
|
||
.bargeld-fehlt { color: var(--negativ); }
|
||
|
||
/* Der graue Kreis ist eine Aussage über nichts und tritt entsprechend zurück. */
|
||
.bargeld-neutral { color: var(--text-gedaempft); font-size: .6rem; }
|
||
|
||
/* Das Ausrufezeichen behält ausdrücklich die Textfarbe des Farbschemas: Der
|
||
Fehler liegt beim Abruf, nicht bei der Buchung – rot oder grün wäre eine
|
||
Aussage über die Buchung, die niemand treffen kann. */
|
||
.bargeld-fehler { color: inherit; font-weight: 700; }
|
||
|
||
/* ── 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;
|
||
}
|
||
|
||
/* Erklärungen zu einem Feld stehen im Tooltip seiner Beschriftung statt als
|
||
eigene Zeile darunter – das spart in langen Masken sichtbar Höhe. Die
|
||
gepunktete Linie zeigt, dass dort etwas zu holen ist. */
|
||
.formular label[title],
|
||
.formular h3 span[title] {
|
||
text-decoration: underline dotted;
|
||
text-underline-offset: .25em;
|
||
cursor: help;
|
||
}
|
||
|
||
/* Zweispaltiges Formular: je Feld ein .feld mit Beschriftung, Eingabe und
|
||
Hinweis, zwei davon nebeneinander. Lange Formulare – das Kontoformular etwa –
|
||
bleiben so ohne vertikales Scrollen einsehbar. */
|
||
.formular.zweispaltig {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
align-items: start;
|
||
gap: 1rem 1.5rem;
|
||
}
|
||
|
||
.formular.breit.zweispaltig { max-width: 900px; }
|
||
|
||
.formular.zweispaltig .feld {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: .3rem;
|
||
}
|
||
|
||
.formular.zweispaltig .feld label { margin-top: 0; }
|
||
|
||
.formular.zweispaltig .feld .feldhinweis { margin-top: 0; }
|
||
|
||
.formular.zweispaltig .feld .feldwert { margin: 0; }
|
||
|
||
.formular.zweispaltig .feld label.ankreuzfeld { margin-top: 0; }
|
||
|
||
/* Über beide Spalten: verstecktes CSRF-Feld, Überschriften, Knopfleiste,
|
||
Tabellen – die Splitzeilen der Buchungsmaske etwa – und Felder, die für eine
|
||
halbe Zeile zu breit sind. */
|
||
.formular.zweispaltig > input[type="hidden"],
|
||
.formular.zweispaltig > h3,
|
||
.formular.zweispaltig > .splitkopf,
|
||
.formular.zweispaltig > p,
|
||
.formular.zweispaltig > table,
|
||
.formular.zweispaltig > .knopfleiste,
|
||
.formular.zweispaltig .feld.ganz { grid-column: 1 / -1; }
|
||
|
||
/* Die Abstände kommen im Grid aus dem gap – eigene Ränder addierten sich dazu. */
|
||
.formular.zweispaltig > h3 { margin: 0; }
|
||
.formular.zweispaltig > p { margin: 0; }
|
||
.formular.zweispaltig > table { margin: 0; }
|
||
.formular.zweispaltig > .knopfleiste { margin-top: .5rem; }
|
||
|
||
@media (max-width: 720px) {
|
||
.formular.zweispaltig { grid-template-columns: 1fr; }
|
||
}
|
||
|
||
/* Beschriftung links neben der Eingabe statt darüber. Das halbiert die Höhe je
|
||
Feld – die Buchungsmaske passt damit samt Splitzeilen auf einen Bildschirm.
|
||
Hinweise stehen unter der Eingabe, also in derselben Spalte wie diese. */
|
||
.formular.beschriftung-links .feld {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 10rem) minmax(0, 1fr);
|
||
align-items: center;
|
||
gap: .25rem .7rem;
|
||
}
|
||
|
||
.formular.beschriftung-links .feld > label { grid-column: 1; }
|
||
.formular.beschriftung-links .feld > :not(label) { grid-column: 2; }
|
||
|
||
/* Das Ankreuzfeld trägt seine Beschriftung selbst und braucht keine Spalte.
|
||
Hinweise laufen über beide Spalten: in der schmalen Eingabespalte allein
|
||
würden sie zu einem hohen Textblock, der die Zeile auseinanderzieht. */
|
||
.formular.beschriftung-links .feld > label.ankreuzfeld,
|
||
.formular.beschriftung-links .feld > .feldhinweis { grid-column: 1 / -1; }
|
||
|
||
@media (max-width: 560px) {
|
||
.formular.beschriftung-links .feld { grid-template-columns: 1fr; }
|
||
.formular.beschriftung-links .feld > label,
|
||
.formular.beschriftung-links .feld > :not(label) { grid-column: 1; }
|
||
}
|
||
|
||
.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; }
|
||
|
||
/* Kategorien in der Auswahlliste stehen als Baum. Eingerückt wird über
|
||
data-ebene wie in der Kategorienverwaltung – ein style-Attribut verwirft die
|
||
Content-Security-Policy (style-src 'self'). */
|
||
.auswahlliste .baumwahl[data-ebene="1"] { padding-left: 1.2rem; }
|
||
.auswahlliste .baumwahl[data-ebene="2"] { padding-left: 2.4rem; }
|
||
.auswahlliste .baumwahl[data-ebene="3"] { padding-left: 3.6rem; }
|
||
.auswahlliste .baumwahl[data-ebene="4"] { padding-left: 4.8rem; }
|
||
.auswahlliste .baumwahl[data-ebene="5"] { padding-left: 6rem; }
|
||
.auswahlliste .baumwahl[data-ebene="6"] { padding-left: 7.2rem; }
|
||
|
||
.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.warnend { color: var(--warnung); }
|
||
|
||
.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); }
|
||
|
||
/* Umbruch statt Überlauf: Knopfleisten mit mehreren Wegen – etwa in den Kacheln
|
||
der Verwaltung – ragten sonst über den rechten Kachelrand hinaus. */
|
||
.knopfleiste {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
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)); }
|
||
|
||
/* Gesperrt, solange nichts ausgewählt ist – sichtbar, aber ohne Aufforderung. */
|
||
.knopf:disabled,
|
||
.knopf:disabled:hover {
|
||
opacity: .5;
|
||
cursor: default;
|
||
background: var(--flaeche);
|
||
}
|
||
|
||
.feldwert { margin: .1rem 0 .3rem; }
|
||
|
||
/* ── Meldungen ───────────────────────────────────────────────────────────── */
|
||
|
||
/* Die Meldungen liegen über der Ansicht, nicht in ihr: Sie schieben sich von
|
||
ganz oben ins Bild und wieder hinaus, ohne den Inhalt zu verschieben – sonst
|
||
rückt die halbe Seite auf und beim Ausblenden wieder zurück. */
|
||
.meldungen {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 100;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: .4rem;
|
||
max-width: 80vw;
|
||
padding-top: .5rem;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.meldung {
|
||
padding: .55rem .9rem;
|
||
border-radius: var(--radius);
|
||
border: 1px solid var(--rand);
|
||
background: var(--flaeche);
|
||
box-shadow: var(--schatten);
|
||
font-size: .92rem;
|
||
/* So schmal wie die Meldung lang ist; erst an der 80-%-Grenze des
|
||
Elternelements wird umgebrochen. */
|
||
max-width: 100%;
|
||
overflow-wrap: anywhere;
|
||
/* Anklicken blendet aus (app.js) – sonst verdeckte eine stehenbleibende
|
||
Fehlermeldung die Werkzeugleiste bis zum nächsten Seitenwechsel. */
|
||
pointer-events: auto;
|
||
cursor: pointer;
|
||
animation: meldung-herein .3s ease-out;
|
||
}
|
||
|
||
@keyframes meldung-herein {
|
||
from { transform: translateY(-150%); opacity: 0; }
|
||
to { transform: translateY(0); opacity: 1; }
|
||
}
|
||
|
||
.meldung-erfolg { background: var(--akzent-schwach); border-color: var(--akzent); }
|
||
|
||
/* Erfolgsmeldungen schieben sich nach einigen Sekunden wieder hinaus (app.js). */
|
||
.meldung.verblasst {
|
||
opacity: 0;
|
||
transform: translateY(-150%);
|
||
transition: opacity .4s, transform .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); }
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.meldung { animation: none; }
|
||
.meldung.verblasst { transform: none; transition: opacity .4s; }
|
||
}
|
||
|
||
.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: <details> 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; }
|
||
|
||
/* Ein Bericht mit wenigen Spalten soll nicht über die ganze Breite gezogen
|
||
werden: Die Tabelle nimmt nur den Platz, den ihre Spalten brauchen, und
|
||
steht dabei mittig unter der Überschrift. Die Zahlenspalten bleiben in sich
|
||
rechtsbündig (.rechts), die letzte schließt bündig mit dem Tabellenrand ab. */
|
||
table.liste.bericht {
|
||
width: auto;
|
||
max-width: 100%;
|
||
margin-inline: auto;
|
||
}
|
||
|
||
/* Im Scrollrahmen darf die Tabelle über die sichtbare Breite hinausgehen –
|
||
sonst quetschte max-width die zwölf Monatsspalten in Umbrüche. */
|
||
.breittabelle table.liste.bericht { max-width: none; }
|
||
|
||
/* 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;
|
||
}
|
||
|
||
/* Das Ankreuzfeld der Mehrfachauswahl steht vor dem Text und richtet sich an
|
||
der ersten Zeile aus, nicht an der Mitte der Karte. */
|
||
.umsatzwahl {
|
||
flex: none;
|
||
margin-top: .25rem;
|
||
}
|
||
|
||
/* Titelleiste einer Kartenliste: Sie vertritt die Kopfzeile, die eine Tabelle
|
||
von selbst hätte – hier steht das Ankreuzfeld „alle wählen“. */
|
||
.listenkopf {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 1rem;
|
||
padding: .35rem .9rem;
|
||
margin-bottom: .4rem;
|
||
border-bottom: 1px solid var(--rand);
|
||
font-size: .85rem;
|
||
color: var(--text-gedaempft);
|
||
}
|
||
|
||
.listenkopf .ankreuzfeld {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: .5rem;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.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-offen { color: var(--warnung); border-color: var(--warnung); }
|
||
.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; }
|
||
|
||
/* Die Splitzeilen einer Regel hängen unter ihrer Regel und sind zugeklappt,
|
||
solange keine da sind – sonst stünde unter jeder Regel eine leere Tabelle. */
|
||
.regelsplitzeile > td {
|
||
padding: 0 .4rem .6rem;
|
||
border-top: 0;
|
||
}
|
||
|
||
.regelsplitzeile summary {
|
||
cursor: pointer;
|
||
font-size: .85rem;
|
||
color: var(--text-gedaempft);
|
||
}
|
||
|
||
.regelsplitzeile .splittabelle { margin-top: .5rem; }
|
||
.regelsplitzeile .feldhinweis { margin-bottom: 0; }
|
||
|
||
/* Die Aufteilung, die eine Regel vorschlägt: reine Anzeige, die Felder daneben
|
||
sind versteckt. */
|
||
.vorschlagssplits {
|
||
flex: 1 1 100%;
|
||
margin: 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
font-size: .85rem;
|
||
}
|
||
|
||
.vorschlagssplits li {
|
||
display: flex;
|
||
gap: .5rem;
|
||
justify-content: space-between;
|
||
max-width: 28rem;
|
||
padding: .1rem 0;
|
||
}
|
||
|
||
/* ── 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;
|
||
}
|
||
|
||
/* Stammdaten einer Detailseite: Merkmal links, Wert rechts. Kein Formular,
|
||
also auch keine Feldpaare – nur zwei Spalten, die untereinander bündig
|
||
bleiben, und ein Umbruch auf eine Spalte, wenn es eng wird. */
|
||
.merkmale {
|
||
display: grid;
|
||
grid-template-columns: minmax(6rem, auto) 1fr;
|
||
gap: .3rem .9rem;
|
||
margin: 0;
|
||
}
|
||
|
||
.merkmale dt {
|
||
color: var(--text-gedaempft);
|
||
font-size: .85rem;
|
||
align-self: center;
|
||
}
|
||
|
||
.merkmale dd { 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);
|
||
}
|
||
|
||
/* <progress> 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,
|
||
.rahmen.eingeklappt { grid-template-columns: 1fr; }
|
||
|
||
/* Waagerecht gibt es nichts zu sparen: Beschriftungen bleiben sichtbar. */
|
||
.rahmen.eingeklappt .marken-text,
|
||
.rahmen.eingeklappt .beschriftung {
|
||
position: static;
|
||
width: auto;
|
||
height: auto;
|
||
clip-path: none;
|
||
}
|
||
|
||
.rahmen.eingeklappt .seitenleisten-marke,
|
||
.rahmen.eingeklappt .seitenleiste a {
|
||
justify-content: flex-start;
|
||
gap: .6rem;
|
||
padding-left: 1.25rem;
|
||
padding-right: 1.25rem;
|
||
}
|
||
|
||
.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;
|
||
}
|
||
}
|
||
|
||
/* Übermittlungsprotokoll: ein Block je Durchlauf, die Meldungen im Wortlaut
|
||
klappen darunter auf. */
|
||
.protokolldialog { width: min(60rem, 94vw); }
|
||
|
||
.protokolleintrag {
|
||
margin: 0 0 .8rem;
|
||
padding: .6rem .75rem;
|
||
border: 1px solid var(--rand);
|
||
border-radius: var(--radius);
|
||
}
|
||
|
||
.protokolleintrag header { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
|
||
.protokolleintrag p { margin: .4rem 0; }
|
||
.protokolleintrag summary { cursor: pointer; font-size: .88rem; color: var(--text-gedaempft); }
|
||
.protokolleintrag .protokolltext { max-height: 22rem; overflow: auto; word-break: break-all; }
|
||
|
||
/* Kippschalter statt Ankreuzfeld. Gilt für jedes Ankreuzfeld; ausgenommen ist nur die
|
||
Zeilenauswahl in den Listen (Kopf-Ankreuzfeld „alle wählen“ und die Auswahl je Buchung
|
||
bzw. Umsatz), wo ein Schalter je Zeile die Tabelle aufblähen würde. Das Element bleibt
|
||
ein echtes Ankreuzfeld: Tastatur, Formularversand und Skripte ändern sich nicht. */
|
||
input[type="checkbox"]:not(.alle-waehlen):not([name="buchungen[]"]):not([name="umsaetze[]"]) {
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
position: relative;
|
||
flex: none;
|
||
width: 2.6rem;
|
||
height: 1.4rem;
|
||
margin: 0;
|
||
border-radius: 999px;
|
||
background-color: var(--rand-kraeftig);
|
||
background-repeat: no-repeat;
|
||
background-position: right .5rem center;
|
||
background-size: .6rem;
|
||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M1.5 1.5l7 7m0-7l-7 7' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' fill='none'/%3E%3C/svg%3E");
|
||
box-shadow: inset 0 1px 2px rgba(16, 24, 40, .18);
|
||
cursor: pointer;
|
||
vertical-align: middle;
|
||
transition: background-color .15s ease;
|
||
}
|
||
|
||
input[type="checkbox"]:not(.alle-waehlen):not([name="buchungen[]"]):not([name="umsaetze[]"])::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: .15rem;
|
||
left: .15rem;
|
||
width: 1.1rem;
|
||
height: 1.1rem;
|
||
border-radius: 50%;
|
||
background: linear-gradient(#ffffff, #eceff3);
|
||
box-shadow: 0 1px 3px rgba(16, 24, 40, .35);
|
||
transition: transform .15s ease;
|
||
}
|
||
|
||
input[type="checkbox"]:not(.alle-waehlen):not([name="buchungen[]"]):not([name="umsaetze[]"]):checked {
|
||
background-color: var(--akzent);
|
||
background-position: left .5rem center;
|
||
background-size: .7rem;
|
||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M1.3 5.4l2.5 2.5 5-5.6' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C/svg%3E");
|
||
}
|
||
|
||
input[type="checkbox"]:not(.alle-waehlen):not([name="buchungen[]"]):not([name="umsaetze[]"]):checked::before {
|
||
transform: translateX(1.2rem);
|
||
}
|
||
|
||
input[type="checkbox"]:not(.alle-waehlen):not([name="buchungen[]"]):not([name="umsaetze[]"]):focus-visible {
|
||
outline: 2px solid var(--akzent);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
input[type="checkbox"]:not(.alle-waehlen):not([name="buchungen[]"]):not([name="umsaetze[]"]):disabled {
|
||
opacity: .5;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
input[type="checkbox"],
|
||
input[type="checkbox"]::before { transition: none; }
|
||
}
|