Beim Abrufen und beim Bearbeiten sprang die halbe Seite. Ursache war der CSS-Spaltenfluss: Aendert eine Karte ihre Hoehe, verteilt der Browser ALLE Karten neu auf die Spalten. Ich hatte das zweimal am Symptom kuriert (Formular in den Dialog verschoben), aber die naechste wachsende Karte brachte es zurueck. Jetzt bekommt jede Karte fest ihre Spalte. Waechst eine, verschiebt sich nur, was in derselben Spalte darunter steht. Die Spaltenzahl kommt aus der tatsaechlichen Containerbreite (ResizeObserver), nicht aus der Fensterbreite – in der schmalen Seitenleisten-Ansicht stimmte das sonst nicht. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1100 lines
22 KiB
CSS
1100 lines
22 KiB
CSS
/* Eigene Stil-Ergänzungen für Certain Finance – bewusst getrennt von der aus
|
||
der Vorlage übernommenen styles.css, damit Basis und Ergänzung sauber bleiben. */
|
||
|
||
.brand-mark {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
}
|
||
.brand-logo {
|
||
display: block;
|
||
flex: 0 0 auto;
|
||
}
|
||
.brand-name {
|
||
font-weight: 650;
|
||
font-size: 1rem;
|
||
letter-spacing: -0.01em;
|
||
color: var(--text);
|
||
}
|
||
|
||
/* Beträge: Vorzeichenfarbe. Grün = Einnahme/im Budget, Rot = Ausgabe/über Budget. */
|
||
.amount.pos { color: var(--ok); }
|
||
.amount.neg { color: var(--danger); }
|
||
.amount.muted { color: var(--muted); }
|
||
|
||
/* Umgerechneter Zweitbetrag (Originalwährung -> Hauptwährung) klein und gedämpft. */
|
||
.amount-converted {
|
||
color: var(--muted);
|
||
font-size: 0.82em;
|
||
margin-left: 4px;
|
||
}
|
||
|
||
/* Schlichtes zentriertes Layout für Login / Passwort ändern. */
|
||
.auth-screen {
|
||
min-height: 100vh;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: var(--sp-5);
|
||
background: var(--bg);
|
||
}
|
||
.auth-card {
|
||
width: 100%;
|
||
max-width: 380px;
|
||
}
|
||
.auth-card .brand-mark {
|
||
justify-content: center;
|
||
margin-bottom: var(--sp-4);
|
||
}
|
||
|
||
/* Eingabefeld mit angehängtem Icon-Knopf (z. B. Passwort ein-/ausblenden). */
|
||
.input-with-button {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
}
|
||
.input-with-button > input {
|
||
flex: 1 1 auto;
|
||
min-width: 0;
|
||
}
|
||
|
||
/* Flex-Kinder dürfen schrumpfen – sonst drängt ein 100%-breites select/input
|
||
ein danebenliegendes Feld auf 0 (das war der Grund für das winzige IBAN-Feld). */
|
||
.row > * {
|
||
min-width: 0;
|
||
}
|
||
|
||
/* Leerer Zustand (z. B. Dashboard ohne Karten). */
|
||
.empty-state {
|
||
text-align: center;
|
||
color: var(--muted);
|
||
padding: var(--sp-6) var(--sp-4);
|
||
}
|
||
.empty-state .icon {
|
||
opacity: 0.5;
|
||
margin-bottom: var(--sp-3);
|
||
}
|
||
|
||
/* Farbiges Icon-Plättchen (Konten/Kategorien). */
|
||
.icon-chip {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: var(--radius-sm);
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
/* Betrag + umgerechneter Wert (rechtsbündig gestapelt). */
|
||
.money {
|
||
display: inline-flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
line-height: 1.3;
|
||
}
|
||
.money .amount {
|
||
font-variant-numeric: tabular-nums;
|
||
font-weight: 560;
|
||
}
|
||
|
||
/* Icon-Auswahlgitter. */
|
||
.icon-picker {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: var(--sp-2);
|
||
margin-top: 5px;
|
||
}
|
||
.icon-picker-item {
|
||
width: 38px;
|
||
height: 38px;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border: 1px solid var(--border-strong);
|
||
border-radius: var(--radius-sm);
|
||
background: var(--surface);
|
||
color: var(--muted);
|
||
cursor: pointer;
|
||
transition: border-color .12s, color .12s, background .12s;
|
||
}
|
||
.icon-picker-item:hover {
|
||
color: var(--text);
|
||
background: var(--surface-2);
|
||
}
|
||
.icon-picker-item.selected {
|
||
background: var(--accent-soft);
|
||
}
|
||
|
||
/* Farbwähler-Zeile. */
|
||
.color-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
margin-top: 5px;
|
||
}
|
||
.color-row input[type="color"] {
|
||
width: 44px;
|
||
height: 34px;
|
||
padding: 2px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* Name + Icon nebeneinander (Listen). */
|
||
.named {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-3);
|
||
min-width: 0;
|
||
}
|
||
.named .named-text {
|
||
min-width: 0;
|
||
}
|
||
.named .named-sub {
|
||
color: var(--muted);
|
||
font-size: 0.8rem;
|
||
}
|
||
|
||
/* Kategorien-Verwaltung: durchgehende Liste in EINER Karte, die Gruppen nur als
|
||
dezente Zwischenüberschrift dazwischen (keine abgesetzten Gruppen-Karten). */
|
||
.cat-section + .cat-section {
|
||
margin-top: var(--sp-5);
|
||
}
|
||
.cat-section-head {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
padding-bottom: var(--sp-2);
|
||
margin-bottom: 2px;
|
||
border-bottom: 2px solid var(--border-strong);
|
||
}
|
||
.cat-section-name {
|
||
flex: 1;
|
||
min-width: 0;
|
||
font-size: 1.05rem;
|
||
font-weight: 650;
|
||
}
|
||
.cat-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-3);
|
||
padding: 9px 4px;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.cat-section .cat-row:last-child {
|
||
border-bottom: none;
|
||
}
|
||
.cat-row:hover {
|
||
background: var(--surface-2);
|
||
}
|
||
.cat-row .grow {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
/* Seitenkopf mit Titel + Aktion rechts. */
|
||
.page-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: var(--sp-3);
|
||
margin-bottom: var(--sp-4);
|
||
}
|
||
.page-head h1 {
|
||
margin: 0;
|
||
}
|
||
|
||
/* Konten. */
|
||
.account-total {
|
||
display: flex;
|
||
align-items: baseline;
|
||
justify-content: space-between;
|
||
padding-bottom: var(--sp-3);
|
||
margin-bottom: var(--sp-2);
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.account-total strong {
|
||
font-size: 1.2rem;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
.account-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.account-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-3);
|
||
padding: var(--sp-3) 0;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.account-row:last-child {
|
||
border-bottom: none;
|
||
}
|
||
.row-actions {
|
||
display: flex;
|
||
gap: 4px;
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
/* Filterleiste. */
|
||
.filter-bar {
|
||
display: flex;
|
||
gap: var(--sp-3);
|
||
flex-wrap: wrap;
|
||
margin-bottom: var(--sp-4);
|
||
}
|
||
.filter-bar select {
|
||
width: auto;
|
||
min-width: 160px;
|
||
margin-top: 0;
|
||
}
|
||
|
||
/* Segmentierte Umschaltung (Ausgabe/Einnahme/Transfer). */
|
||
.seg {
|
||
display: flex;
|
||
border: 1px solid var(--border-strong);
|
||
border-radius: var(--radius-sm);
|
||
overflow: hidden;
|
||
margin-bottom: var(--sp-4);
|
||
}
|
||
.seg-btn {
|
||
flex: 1;
|
||
padding: 8px 10px;
|
||
border: none;
|
||
background: var(--surface);
|
||
color: var(--muted);
|
||
font-weight: 560;
|
||
cursor: pointer;
|
||
border-right: 1px solid var(--border);
|
||
}
|
||
.seg-btn:last-child {
|
||
border-right: none;
|
||
}
|
||
.seg-btn.active {
|
||
background: var(--accent);
|
||
color: #fff;
|
||
}
|
||
|
||
.nowrap {
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* Nimmt den freien Platz in einer Flex-Zeile und darf schrumpfen (Ellipsis). */
|
||
.grow {
|
||
flex: 1 1 auto;
|
||
min-width: 0;
|
||
}
|
||
|
||
/* Nutzer-Chip in der Seitenleisten-Fußzeile ist ein Link auf „Mein Konto". */
|
||
a.sidebar-user {
|
||
text-decoration: none;
|
||
border-radius: var(--radius-sm);
|
||
padding: 2px 4px;
|
||
margin: -2px -4px;
|
||
transition: background .12s;
|
||
}
|
||
a.sidebar-user:hover {
|
||
background: var(--surface-2);
|
||
}
|
||
a.sidebar-user:hover .name {
|
||
color: var(--accent);
|
||
}
|
||
|
||
/* Budget: mehrere Monate nebeneinander. */
|
||
.budget-months {
|
||
display: grid;
|
||
gap: var(--sp-4);
|
||
grid-template-columns: repeat(var(--cols, 1), minmax(0, 1fr));
|
||
align-items: start;
|
||
}
|
||
@media (max-width: 820px) {
|
||
.budget-months {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
.budget-col {
|
||
min-width: 0;
|
||
}
|
||
.budget-col-head {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding-bottom: var(--sp-2);
|
||
margin-bottom: var(--sp-2);
|
||
border-bottom: 2px solid var(--border-strong);
|
||
}
|
||
.budget-col-head strong {
|
||
font-size: 1.05rem;
|
||
}
|
||
.budget-col-income {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
padding: 4px 0 var(--sp-2);
|
||
margin-bottom: var(--sp-2);
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.budget-crow {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
padding: 6px 0;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.budget-crow:last-child {
|
||
border-bottom: none;
|
||
}
|
||
.budget-crow .amount.small {
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
/* Budget. */
|
||
.budget-navbar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-3);
|
||
}
|
||
.budget-month {
|
||
font-size: 1.05rem;
|
||
min-width: 170px;
|
||
text-align: center;
|
||
}
|
||
.flip {
|
||
transform: rotate(180deg);
|
||
}
|
||
.budget-group + .budget-group {
|
||
margin-top: var(--sp-4);
|
||
}
|
||
.budget-group-head {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
padding: var(--sp-2) 0;
|
||
margin-bottom: 4px;
|
||
border-bottom: 2px solid var(--border-strong);
|
||
}
|
||
.budget-cat {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-3);
|
||
padding: 7px 0;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.budget-cat:last-child {
|
||
border-bottom: none;
|
||
}
|
||
.budget-cat-name {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
min-width: 0;
|
||
}
|
||
.budget-cat-bar {
|
||
flex: 1;
|
||
}
|
||
.amount-input {
|
||
width: 96px;
|
||
text-align: right;
|
||
margin-top: 0;
|
||
padding: 5px 8px;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
.budget-actual {
|
||
width: 96px;
|
||
text-align: right;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
.budget-slash {
|
||
margin: 0 -4px;
|
||
}
|
||
.budget-bar {
|
||
height: 7px;
|
||
background: var(--surface-2);
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
.budget-bar-fill {
|
||
height: 100%;
|
||
background: var(--ok);
|
||
border-radius: 4px;
|
||
transition: width 0.2s;
|
||
}
|
||
.budget-bar-fill.over {
|
||
background: var(--danger);
|
||
}
|
||
.budget-total-row.card-total {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
padding-top: var(--sp-3);
|
||
margin-top: var(--sp-2);
|
||
border-top: 2px solid var(--border-strong);
|
||
}
|
||
tr.budget-total-row td {
|
||
border-top: 2px solid var(--border-strong);
|
||
padding-top: var(--sp-2);
|
||
}
|
||
|
||
/* Sparen-Option im Transfer-Formular. */
|
||
.savings-opt {
|
||
padding: var(--sp-3);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-sm);
|
||
background: var(--surface-2);
|
||
margin-bottom: var(--sp-4);
|
||
}
|
||
.checkline {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
margin-bottom: var(--sp-2);
|
||
}
|
||
.checkline span {
|
||
color: var(--text);
|
||
font-weight: 560;
|
||
}
|
||
|
||
/* ---------- Dashboard-Grid ---------- */
|
||
.dash-toolbar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
position: relative;
|
||
}
|
||
.dash-add {
|
||
position: relative;
|
||
}
|
||
.dash-add-menu {
|
||
position: absolute;
|
||
right: 0;
|
||
top: calc(100% + 4px);
|
||
z-index: 20;
|
||
background: var(--surface);
|
||
border: 1px solid var(--border-strong);
|
||
border-radius: var(--radius-sm);
|
||
box-shadow: var(--shadow);
|
||
min-width: 200px;
|
||
overflow: hidden;
|
||
}
|
||
.dash-add-item {
|
||
display: block;
|
||
width: 100%;
|
||
text-align: left;
|
||
padding: 8px 12px;
|
||
border: none;
|
||
background: none;
|
||
color: var(--text);
|
||
cursor: pointer;
|
||
}
|
||
.dash-add-item:hover {
|
||
background: var(--surface-2);
|
||
}
|
||
|
||
/* Karten-Optionen im Anordnen-Modus (z. B. Gruppen vs. Kategorien). */
|
||
.dash-config-bar {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: var(--sp-3);
|
||
padding-bottom: var(--sp-2);
|
||
margin-bottom: var(--sp-2);
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.dash-config-opt {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
gap: 4px;
|
||
min-width: 0;
|
||
flex: 1 1 140px;
|
||
}
|
||
.seg.sm {
|
||
margin-bottom: 0;
|
||
width: 100%;
|
||
}
|
||
.seg.sm .seg-btn {
|
||
padding: 4px 9px;
|
||
font-size: 0.78rem;
|
||
}
|
||
|
||
.dash-grid {
|
||
position: relative;
|
||
}
|
||
.dash-card {
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
box-shadow: var(--shadow);
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
.dash-card-head {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
padding: 8px 12px;
|
||
border-bottom: 1px solid var(--border);
|
||
flex: 0 0 auto;
|
||
}
|
||
.dash-card-title {
|
||
font-size: 0.7rem;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.05em;
|
||
color: var(--muted);
|
||
font-weight: 650;
|
||
flex: 1;
|
||
}
|
||
.dash-grid.editing .dash-card-head {
|
||
cursor: move;
|
||
background: var(--surface-2);
|
||
}
|
||
.dash-remove {
|
||
color: var(--danger);
|
||
}
|
||
.dash-card-body {
|
||
flex: 1;
|
||
min-height: 0;
|
||
overflow: auto;
|
||
padding: var(--sp-3);
|
||
}
|
||
|
||
.dash-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
}
|
||
.dash-line {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
padding: 6px 0;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.dash-line:last-child {
|
||
border-bottom: none;
|
||
}
|
||
.dash-total {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: var(--sp-2);
|
||
padding-top: var(--sp-2);
|
||
margin-top: 2px;
|
||
border-top: 2px solid var(--border-strong);
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
.ellipsis {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.dash-loading, .dash-empty {
|
||
padding: var(--sp-4);
|
||
text-align: center;
|
||
}
|
||
.dash-progress {
|
||
padding: 6px 0;
|
||
}
|
||
.dash-progress-top {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
margin-bottom: 4px;
|
||
}
|
||
.dash-kpis {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
gap: var(--sp-2);
|
||
height: 100%;
|
||
}
|
||
.dash-kpi {
|
||
display: flex;
|
||
align-items: baseline;
|
||
justify-content: space-between;
|
||
}
|
||
.dash-kpi strong {
|
||
font-size: 1.1rem;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
/* react-grid-layout: Platzhalter + Resize-Griff an das Theme angleichen. */
|
||
.react-grid-item.react-grid-placeholder {
|
||
background: var(--accent);
|
||
opacity: 0.15;
|
||
border-radius: var(--radius);
|
||
}
|
||
.react-grid-item > .react-resizable-handle::after {
|
||
border-right-color: var(--border-strong);
|
||
border-bottom-color: var(--border-strong);
|
||
}
|
||
|
||
/* ---------- CSV-Import ---------- */
|
||
.table-scroll {
|
||
overflow-x: auto;
|
||
}
|
||
.raw-table {
|
||
font-size: 0.8rem;
|
||
}
|
||
.raw-table th,
|
||
.raw-table td {
|
||
white-space: nowrap;
|
||
max-width: 220px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
.raw-table th {
|
||
color: var(--muted);
|
||
font-weight: 600;
|
||
}
|
||
.map-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
|
||
gap: var(--sp-3);
|
||
margin-top: var(--sp-3);
|
||
}
|
||
.map-grid label {
|
||
margin-bottom: 0;
|
||
}
|
||
tr.row-invalid {
|
||
opacity: 0.45;
|
||
}
|
||
tr.row-dup {
|
||
opacity: 0.55;
|
||
}
|
||
.doc-text {
|
||
max-height: 240px;
|
||
overflow: auto;
|
||
font-size: 0.78rem;
|
||
white-space: pre-wrap;
|
||
color: var(--muted);
|
||
background: var(--surface-2);
|
||
padding: var(--sp-3);
|
||
border-radius: var(--radius-sm);
|
||
margin-top: var(--sp-2);
|
||
}
|
||
/* Beleg-Seiten als Bildstreifen (horizontal scrollbar). */
|
||
.doc-pages {
|
||
display: flex;
|
||
gap: var(--sp-3);
|
||
overflow-x: auto;
|
||
padding-bottom: var(--sp-2);
|
||
}
|
||
.doc-page {
|
||
height: 440px;
|
||
width: auto;
|
||
flex: 0 0 auto;
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-sm);
|
||
background: #fff;
|
||
}
|
||
.import-more {
|
||
margin-top: var(--sp-3);
|
||
}
|
||
.import-more > summary {
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* DataTable-Zellen einzeilig halten, damit „…" greift (Excel-artig). */
|
||
.datatable td { white-space: nowrap; vertical-align: middle; }
|
||
.datatable td .named-text { min-width: 0; }
|
||
/* Interaktive Zellen (Import-Prüfansicht) füllen ihre Spalte, statt auf 60% zu
|
||
schrumpfen (globale .table td select/input-Regel überschreiben). */
|
||
.datatable td select,
|
||
.datatable td input[inputmode],
|
||
.datatable td input[type="text"] { max-width: none; width: 100%; }
|
||
.datatable td .catsel { width: 100%; }
|
||
|
||
/* ---------- Kategorie-Auswahl (auf-/zuklappbarer Baum, Ersatz für <select>) ---------- */
|
||
.catsel {
|
||
width: 100%;
|
||
}
|
||
.catsel-btn {
|
||
width: 100%;
|
||
margin-top: 5px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
padding: 7px 10px;
|
||
border: 1px solid var(--border-strong);
|
||
border-radius: var(--radius-sm);
|
||
background: var(--surface);
|
||
color: var(--text);
|
||
font: inherit;
|
||
text-align: left;
|
||
cursor: pointer;
|
||
transition: border-color .12s, box-shadow .12s;
|
||
}
|
||
.catsel-btn:hover:not(:disabled) {
|
||
border-color: var(--accent);
|
||
}
|
||
.catsel-btn:disabled {
|
||
opacity: 0.6;
|
||
cursor: default;
|
||
}
|
||
.catsel-btn.open {
|
||
border-color: var(--accent);
|
||
box-shadow: 0 0 0 3px var(--accent-soft);
|
||
}
|
||
.catsel-value {
|
||
flex: 1 1 auto;
|
||
min-width: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
}
|
||
.catsel-caret {
|
||
flex: 0 0 auto;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.catsel-panel {
|
||
position: fixed;
|
||
z-index: 1000;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: var(--surface);
|
||
border: 1px solid var(--border-strong);
|
||
border-radius: var(--radius);
|
||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
|
||
overflow: hidden;
|
||
}
|
||
.catsel-search {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
padding: 8px 10px;
|
||
border-bottom: 1px solid var(--border);
|
||
color: var(--muted);
|
||
flex: 0 0 auto;
|
||
}
|
||
.catsel-search input {
|
||
width: 100%;
|
||
border: none;
|
||
background: none;
|
||
outline: none;
|
||
margin: 0;
|
||
padding: 0;
|
||
color: var(--text);
|
||
font: inherit;
|
||
}
|
||
.catsel-list {
|
||
overflow-y: auto;
|
||
padding: 5px;
|
||
}
|
||
.catsel-group + .catsel-group {
|
||
margin-top: 2px;
|
||
}
|
||
.catsel-group-head {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
width: 100%;
|
||
padding: 6px;
|
||
border: none;
|
||
background: none;
|
||
cursor: pointer;
|
||
color: var(--muted);
|
||
font-weight: 650;
|
||
font-size: 0.72rem;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.03em;
|
||
}
|
||
.catsel-group-head:hover {
|
||
color: var(--text);
|
||
}
|
||
.catsel-gchev {
|
||
flex: 0 0 auto;
|
||
transition: transform .12s ease;
|
||
}
|
||
.catsel-gchev.collapsed {
|
||
transform: rotate(-90deg);
|
||
}
|
||
.catsel-opt {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
width: 100%;
|
||
padding: 6px 8px 6px 22px;
|
||
border: none;
|
||
border-radius: var(--radius-sm);
|
||
background: none;
|
||
color: var(--text);
|
||
font: inherit;
|
||
text-align: left;
|
||
cursor: pointer;
|
||
}
|
||
.catsel-opt:hover {
|
||
background: var(--surface-2);
|
||
}
|
||
.catsel-opt.selected {
|
||
background: var(--accent-soft);
|
||
color: var(--accent);
|
||
font-weight: 600;
|
||
}
|
||
.catsel-check {
|
||
margin-left: auto;
|
||
flex: 0 0 auto;
|
||
color: var(--accent);
|
||
}
|
||
.catsel-empty {
|
||
padding: 10px;
|
||
}
|
||
|
||
/* ---------- Schlagwörter (Kategorie-Popup + Prüfmeldungen) ---------- */
|
||
.kw-add {
|
||
display: flex;
|
||
gap: var(--sp-2);
|
||
margin-bottom: var(--sp-3);
|
||
}
|
||
.kw-add input {
|
||
flex: 1 1 auto;
|
||
min-width: 0;
|
||
margin-top: 0;
|
||
}
|
||
.kw-chips {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: var(--sp-2);
|
||
}
|
||
.kw-chip {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 4px 6px 4px 11px;
|
||
border-radius: 20px;
|
||
background: var(--surface-2);
|
||
border: 1px solid var(--border);
|
||
font-size: 0.85rem;
|
||
}
|
||
.kw-amount {
|
||
color: var(--muted);
|
||
font-variant-numeric: tabular-nums;
|
||
font-size: 0.8em;
|
||
}
|
||
.kw-chip button {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 18px;
|
||
height: 18px;
|
||
padding: 0;
|
||
margin: 0;
|
||
border: none;
|
||
border-radius: 50%;
|
||
background: none;
|
||
color: var(--muted);
|
||
cursor: pointer;
|
||
}
|
||
.kw-chip button:hover {
|
||
background: var(--danger);
|
||
color: #fff;
|
||
}
|
||
/* Schlagwort-Knopf in der Kategorienliste. Belegte Kategorien tragen die
|
||
Akzentfarbe und die Anzahl – so sieht man der Liste an, wo schon etwas
|
||
hinterlegt ist, ohne jede Kategorie einzeln zu öffnen. */
|
||
.kw-btn {
|
||
gap: 5px;
|
||
}
|
||
.kw-btn.belegt {
|
||
color: var(--accent);
|
||
border-color: var(--accent-soft);
|
||
background: var(--accent-soft);
|
||
}
|
||
.kw-btn-zahl {
|
||
font-size: 0.72rem;
|
||
font-weight: 640;
|
||
font-variant-numeric: tabular-nums;
|
||
line-height: 1;
|
||
}
|
||
|
||
/* Das Schlagwort, das gerade oben in der Zeile liegt. Bearbeitet wird dort,
|
||
nicht im Chip – im Chip war für den Betrag kein Platz. */
|
||
.kw-chip.aktiv {
|
||
border-color: var(--accent);
|
||
box-shadow: 0 0 0 2px var(--accent-soft);
|
||
}
|
||
/* Passend dazu die Eingabezeile hervorheben, damit klar ist, dass dort gerade
|
||
ein vorhandenes Wort liegt und nicht ein neues entsteht. */
|
||
.kw-add.bearbeitet input {
|
||
border-color: var(--accent);
|
||
}
|
||
|
||
.kw-flag {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-3);
|
||
padding: var(--sp-3) 0;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.kw-flag:last-child {
|
||
border-bottom: none;
|
||
}
|
||
.kw-flag-main {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
.kw-flag-word {
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* ---------- Passwort: Anforderungsliste, Zwei-Faktor ---------- */
|
||
|
||
/* Nur für Screenreader – optisch weg, aber vorlesbar. */
|
||
.sr-only {
|
||
position: absolute;
|
||
width: 1px;
|
||
height: 1px;
|
||
padding: 0;
|
||
margin: -1px;
|
||
overflow: hidden;
|
||
clip: rect(0 0 0 0);
|
||
white-space: nowrap;
|
||
border: 0;
|
||
}
|
||
|
||
/* Hakt sich beim Tippen ab. Farben ausschliesslich aus Tokens, sonst bricht
|
||
das dunkle Thema. */
|
||
.pw-rules {
|
||
list-style: none;
|
||
margin: var(--sp-2) 0 0;
|
||
padding: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 3px;
|
||
font-size: 0.82rem;
|
||
}
|
||
.pw-rule {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-2);
|
||
color: var(--muted);
|
||
transition: color 0.16s ease;
|
||
}
|
||
.pw-rule.erfuellt {
|
||
color: var(--ok);
|
||
}
|
||
.pw-rule-mark {
|
||
flex: 0 0 auto;
|
||
width: 16px;
|
||
height: 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
/* Offener Punkt, solange die Regel nicht erfüllt ist. */
|
||
.pw-rule-dot {
|
||
width: 7px;
|
||
height: 7px;
|
||
border-radius: 50%;
|
||
border: 1.5px solid currentColor;
|
||
opacity: 0.55;
|
||
}
|
||
/* Kurzer Impuls, wenn das Häkchen erscheint. */
|
||
.pw-rule.erfuellt .pw-rule-mark {
|
||
animation: pw-rule-pop 0.18s ease-out;
|
||
}
|
||
|
||
@keyframes pw-rule-pop {
|
||
from { transform: scale(0.4); opacity: 0; }
|
||
60% { transform: scale(1.18); opacity: 1; }
|
||
to { transform: scale(1); opacity: 1; }
|
||
}
|
||
|
||
/* styles.css hat keinen globalen Bewegungs-Reset, nur eine Aufzählung –
|
||
deshalb hier noch einmal ausdrücklich für die neuen Bewegungen. */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.pw-rule { transition: none; }
|
||
.pw-rule.erfuellt .pw-rule-mark { animation: none; }
|
||
}
|
||
|
||
/* Zwei-Faktor: QR-Code, Secret und Wiederherstellungscodes. */
|
||
.tfa-qr {
|
||
display: block;
|
||
width: 190px;
|
||
height: 190px;
|
||
/* Der QR-Code braucht weissen Grund, damit er auch im dunklen Thema
|
||
zuverlässig gescannt wird. */
|
||
background: #fff;
|
||
padding: var(--sp-2);
|
||
border-radius: var(--radius-sm);
|
||
border: 1px solid var(--border);
|
||
}
|
||
.tfa-secret {
|
||
display: inline-block;
|
||
padding: 6px var(--sp-2);
|
||
border-radius: var(--radius-sm);
|
||
background: var(--surface-2);
|
||
border: 1px solid var(--border);
|
||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||
font-size: 0.9rem;
|
||
letter-spacing: 0.06em;
|
||
/* styles.css setzt body { user-select: none } – ohne das hier liesse sich
|
||
das Secret nicht markieren und kopieren. */
|
||
user-select: text;
|
||
}
|
||
.tfa-codes {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
||
gap: var(--sp-2);
|
||
margin: var(--sp-3) 0;
|
||
padding: var(--sp-3);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-sm);
|
||
background: var(--surface-2);
|
||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||
font-size: 0.9rem;
|
||
user-select: text;
|
||
}
|
||
.tfa-codes .verbraucht {
|
||
color: var(--muted);
|
||
text-decoration: line-through;
|
||
}
|
||
|
||
/* Zusammenfassung der Prüfansicht beim Wiederherstellen. */
|
||
.restore-summary {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin-top: var(--sp-2);
|
||
font-size: 0.88rem;
|
||
}
|
||
.restore-summary td {
|
||
padding: 3px 0;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.restore-summary td:last-child {
|
||
text-align: right;
|
||
font-variant-numeric: tabular-nums;
|
||
color: var(--muted);
|
||
}
|
||
.restore-summary tr:last-child td {
|
||
border-bottom: none;
|
||
}
|
||
|
||
/* Zweiter Buchen-Knopf unter der Prüfliste – bei vielen Zeilen ist der obere
|
||
längst aus dem Bild gescrollt. */
|
||
.commit-footer {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
padding-top: var(--sp-3);
|
||
margin-top: var(--sp-2);
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
|
||
/* Ausgaben-Anteile: der Prozentwert ist die Kernaussage der Karte und steht
|
||
deshalb vor dem Betrag, mit gleichbleibender Ziffernbreite. */
|
||
.share-pct {
|
||
font-variant-numeric: tabular-nums;
|
||
white-space: nowrap;
|
||
}
|
||
/* Wird die Karte schmal, gibt zuerst der Betrag nach – ohne den Kategorienamen
|
||
sagt die Zeile nichts mehr aus, ohne den Betrag bleibt der Anteil lesbar. */
|
||
.share-row .share-name {
|
||
min-width: 4.5rem;
|
||
}
|
||
.share-row .share-amount {
|
||
flex: 0 1 auto;
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|