/* finance-stack — styles split (Phase 46 Wave 4)
   Datei: polish.css  •  Lade-Position: 6/6 — Auth-Shell, Modal-Sheet, Modal-Variants, Empty-State
   Lade-Reihenfolge: base → layout-shell → components → pages → charts-hero → polish
*/

/* ============================================================
   Auth-Shell (Move 3, v14.0) — Login + Lock-Pages auf Premium-Niveau.
   Single-Column, große Brand-Mark, ruhiges Layout, viel Whitespace.
   Login extends base.html; Header bleibt leer (kein user_id-Gate).
   ============================================================ */
.auth-shell {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: calc(100dvh - 6rem); /* Header reserviert (auch wenn leer auf Login) */
  padding: var(--space-6) var(--space-4);
}

.auth-card {
  width: 100%;
  max-width: 380px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  text-align: center;
  gap: var(--space-3);
}

.auth-brand {
  width: 64px;
  height: 64px;
  display: block;
  margin: 0 auto var(--space-2);
}

.auth-title {
  font-size: var(--text-2xl);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
  margin: 0;
  letter-spacing: -.01em;
  color: var(--text);
}

.auth-subtitle {
  margin: 0 0 var(--space-4);
  font-size: var(--text-md);
  color: var(--text-muted);
  line-height: var(--leading-snug);
}

.auth-error {
  margin: 0;
  font-size: var(--text-sm);
}

.auth-primary {
  width: 100%;
  padding: .85rem 1rem;
  font-size: var(--text-md);
  font-weight: var(--weight-semi);
  border-radius: var(--r-md);
  margin-top: var(--space-2);
}

.auth-hint {
  margin: var(--space-1) 0 var(--space-4);
  font-size: var(--text-xs);
  color: var(--text-dim);
}

.auth-fallback {
  margin-top: var(--space-3);
  text-align: left;
}
.auth-fallback > summary {
  cursor: pointer;
  color: var(--text-muted);
  font-size: var(--text-sm);
  padding: var(--space-2) 0;
  text-align: center;
  list-style: none;
}
.auth-fallback > summary::-webkit-details-marker { display: none; }
.auth-fallback > summary:hover { color: var(--text); }
.auth-fallback[open] > summary { color: var(--text); margin-bottom: var(--space-2); }

.auth-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: var(--space-2);
}
.auth-form label {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  font-size: var(--text-sm);
  color: var(--text-muted);
  text-align: left;
}
.auth-form input {
  padding: .7rem .85rem;
  border-radius: var(--r-md);
  border: 1px solid var(--border-input);
  background: var(--surface);
  color: var(--text);
  font-size: var(--text-md);
  transition: border-color var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out);
}
.auth-form input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-bg);
}

/* ============================================================
   Modal-Size-Varianten + Sheet-Mode auf Mobile (Move 4, v14.0)
   Desktop: zentriertes Modal, max-width nach data-modal-size.
   Mobile (<621px): Bottom-Sheet mit Handle-Indicator, slide-from-bottom-look.
   ============================================================ */
.modal-card[data-modal-size="sm"] { max-width: 24rem; }
.modal-card[data-modal-size="md"] { max-width: 38rem; }
.modal-card[data-modal-size="lg"] { max-width: 52rem; }

/* 2026-06-09 v2: Card-Opacity NICHT mehr animieren — fade von 0→1 auf der
   Card erzeugte ein „Geist-Ghosting" während der ersten ~200ms, weil der
   page-Hintergrund (Tabbar, Karten, Achsen-Labels) sichtbar DURCH die Card
   schimmerte (Fred-Recording 2026-06-09 23:38). Stattdessen:
   - Backdrop fadet weich opacity 0→1 (var(--duration-base), --ease-out)
   - Mobile: Sheet schiebt sich solid (full opacity) von translateY(100%) →
     translateY(0) rein, also komplett unter dem Viewport-Rand startend →
     dort wo die Card sichtbar wird, ist sie immer voll deckend
   - Desktop: subtiler scale-Pop von 0.96 → 1 bei full opacity; Backdrop
     fadet synchron drüber, daher keine sichtbare Page-Geistspur
   `translateZ(0)` + `will-change` promotet zu eigener Compositor-Layer,
   verhindert iOS-Safari Repaint-Glitches. `prefers-reduced-motion` setzt
   `--duration-base: 1ms` (base.css), Animationen bleiben unmerklich. */
/* 2026-06-10: Vom CSS-Animation-Pattern auf CSS-Transition + Class-Toggle
   umgestellt (analog tx-filter-sheet auf der Buchungsseite, das sauber
   ohne Flackern läuft). Hintergrund: CSS-Animation startet bei DOM-
   Insertion implizit, aber iOS Safari paintet im ersten Frame den
   un-animierten Zustand bevor der Animation-Engine greift — selbst mit
   `animation-fill-mode: both` und expliziten Initial-Werten (Fred v122-
   Recording). Transition + Class-Toggle umgeht das: das Element wird
   im Initial-State eingefügt (opacity:0, translateY(100%)/scale(0.96)),
   ein expliziter Reflow + `is-open`-Klasse triggert dann die Transition
   deterministisch in app-runtime.js (htmx:afterSwap-Hook). */
/* 2026-06-10 Iter-6: ROOT-CAUSE-FIX für „Backdrop wird heller" Mobile-Bug.
   Vorher: `opacity` auf .modal-backdrop transitioniert → propagiert auf ALLE
   Children, inkl. .modal-card. Während der 250ms-Transition war die Card
   semi-transparent → Page-Inhalt schimmerte durch die Card durch. Bei
   opacity:1 wurde die Card plötzlich opak — Eindruck: „Hintergrund wird
   heller". Safari-Timeline (test-modal-background-flicker-recording.json)
   zeigt den Sprung bei t=1.286s genau am Transitions-Ende.
   Fix: nicht opacity transitionieren, sondern background-color direkt am
   Backdrop. Die Card behält dadurch volle Opazität, der Dunkel-Fade läuft
   sauber durch. */
.modal-backdrop {
  background: rgba(0, 0, 0, 0);
  transition: background-color var(--duration-base) var(--ease-out);
  will-change: background-color;
  transform: translateZ(0);
}
.modal-backdrop.is-open { background: rgba(0, 0, 0, 0.55); }

.modal-card {
  transform: translateZ(0) scale(0.96);
  transition: transform var(--duration-base) var(--ease-out);
  transform-origin: center;
  will-change: transform;
}
.modal-backdrop.is-open .modal-card {
  transform: translateZ(0) scale(1);
}

.modal-title {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--weight-semi);
  letter-spacing: -.005em;
  color: var(--text);
}

/* Sheet-Handle — nur sichtbar im Sheet-Mode (Mobile) */
.sheet-handle { display: none; }

@media (max-width: 620px) {
  /* Backdrop bündig nach unten — Sheet wächst vom unteren Rand */
  .modal-backdrop {
    align-items: flex-end;
    padding: 0;
  }

  /* Sheet: full-width, Top-Radius, slide-up via initial transform.
     HTMX rendert das Modal initial sichtbar — wir nutzen eine kurze
     enter-Animation statt einer Toggle-State-Klasse. */
  .modal-card,
  .modal-card[data-modal-size="sm"],
  .modal-card[data-modal-size="md"],
  .modal-card[data-modal-size="lg"] {
    max-width: 100%;
    width: 100%;
    border-radius: var(--r-2xl) var(--r-2xl) 0 0;
    padding: var(--space-3) var(--space-4) calc(var(--space-4) + env(safe-area-inset-bottom));
    max-height: 92dvh;
    box-shadow: 0 -8px 32px rgba(0, 0, 0, .25);
    /* Mobile: slide von unten via Transition + is-open Class-Toggle
       (analog tx-filter-sheet, sauber auf iOS). */
    transform: translateZ(0) translateY(100%);
    transition: transform var(--duration-base) var(--ease-out);
  }
  .modal-backdrop.is-open .modal-card,
  .modal-backdrop.is-open .modal-card[data-modal-size="sm"],
  .modal-backdrop.is-open .modal-card[data-modal-size="md"],
  .modal-backdrop.is-open .modal-card[data-modal-size="lg"] {
    transform: translateZ(0) translateY(0);
  }

  .sheet-handle {
    display: block;
    width: 40px;
    height: 4px;
    border-radius: var(--r-pill);
    background: var(--border);
    margin: 0 auto var(--space-2);
    flex-shrink: 0;
  }

  .modal-head {
    padding-top: var(--space-1);
    margin-bottom: var(--space-2);
  }
}

/* 2026-06-10: sheetSlideUp-Keyframes entfernt — Sheet animiert jetzt via
   CSS-Transition + .is-open-Class (siehe oben), nicht mehr via Animation. */

/* ============================================================
   Empty-State-Komponente (Move 4, v14.0)
   Zentrale Klasse für „Noch keine X"-Zustände. Ersetzt 5+ Ad-hoc-Varianten.
   ============================================================ */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--space-2);
  padding: var(--space-6) var(--space-4);
  max-width: 380px;
  margin: 0 auto;
  color: var(--text-muted);
}

.empty__icon {
  width: 56px;
  height: 56px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--space-1);
}
.empty__icon svg { width: 28px; height: 28px; }

.empty__title {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--weight-semi);
  color: var(--text);
  line-height: var(--leading-snug);
}

.empty__subtext {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text-muted);
  line-height: var(--leading-snug);
  max-width: 32ch;
}

.empty__action {
  margin-top: var(--space-3);
  display: inline-flex;
  gap: var(--space-2);
}

.empty--compact {
  padding: var(--space-4) var(--space-3);
  gap: var(--space-1);
}
.empty--compact .empty__icon { width: 40px; height: 40px; }
.empty--compact .empty__icon svg { width: 20px; height: 20px; }
.empty--compact .empty__title { font-size: var(--text-md); }

/* ============================================================
   A11y-Polish (Phase 1.2 Welle A) — Skip-Link + TopBar-Touch-Targets.
   - Skip-Link: keyboard-only, visuell sichtbar nur bei :focus, springt
     direkt in #main-content. Auf JEDER Page nutzbar (in base.html).
   - TopBar-Buttons (nav-burger/theme-toggle/privacy-toggle/Abmelden):
     Effective click area >= 44x44 (Apple-iOS-Guideline). Padding der
     vorhandenen Rules in layout-shell.css bleibt fuer optische Groesse
     unberuehrt — min-* erweitert nur die Hit-Area, nicht den Icon-Look.
   ============================================================ */
.skip-link {
  position: absolute;
  top: -100px;
  left: var(--space-2, .5rem);
  z-index: 9999;
  background: var(--surface, #fff);
  color: var(--text, #111);
  padding: var(--space-3, .75rem) var(--space-4, 1rem);
  border: 2px solid var(--accent, currentColor);
  border-radius: 0 0 8px 8px;
  font-weight: 600;
  text-decoration: none;
  transition: top .12s ease-out;
}
.skip-link:focus,
.skip-link:focus-visible {
  top: 0;
  outline: 2px solid var(--accent, currentColor);
  outline-offset: 2px;
}

.app-header .nav-burger,
.app-header .theme-toggle,
.app-header .privacy-toggle {
  min-width: 44px;
  min-height: 44px;
}
.app-header form.inline button.link {
  min-height: 44px;
  padding-block: var(--space-2, .5rem);
  padding-inline: var(--space-3, .75rem);
  display: inline-flex;
  align-items: center;
}
/* Desktop-Bottom: Sidebar-Abmelden ebenfalls auf Touch-Min anheben. */
.nav-sidebar-bottom form.inline button.link {
  min-height: 44px;
  padding-block: var(--space-2, .5rem);
  display: inline-flex;
  align-items: center;
}

/* Hero-Info-Buttons (i)-Tooltips: optisch klein lassen (16-22px Icon), aber
   Hit-Area auf 44x44 erweitern via ::before-Pseudo. So bleiben Legend +
   Chip-Layout unveraendert, der Klick funktioniert aber zuverlaessig auf
   Mobile (Memory project_finances_visual_qa_patterns + audit H-2).
   2026-06-06 M-2-Follow-Up: KEIN `position: relative`-Reset hier — chip-info
   ist in charts-hero.css absolut positioniert (top:.5rem;right:.5rem;) und
   ein relative-Reset wuerde die Buttons in den Normalfluss (links unten)
   kippen. ::before braucht nur einen positionierten Containing Block —
   absolute genuegt genauso wie relative. */
.hero-v3-cylinder-legend__info::before,
.hero-v3__chip-info::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
  /* Keine background — unsichtbare Hit-Area. */
}

/* Lazy-Load Button-Spinner (POLISH-AUDIT B-1): waehrend hx-request swappen
   wir Label gegen "Laedt…". Wird auch von intersect-Trigger ausgeloest, nicht
   nur Click. */
.tx-load-more__spinner { display: none; }
.tx-load-more.htmx-request .tx-load-more__label { display: none; }
.tx-load-more.htmx-request .tx-load-more__spinner { display: inline; }
