/* ═══════════════════════════════════════════════════
   NextPercent Hub — Shared Base Styles
   Geladen via <link rel="stylesheet" href="/hub.css?v=3">
   Modulspezifische Styles bleiben inline im jeweiligen HTML.
═══════════════════════════════════════════════════ */

/* Reset — identisch in allen Modulen */
*{margin:0;padding:0;box-sizing:border-box}

/* Font-Baseline — Poppins für alle Module.
   Module können Body-Rule weiter ergänzen (background, height, font-size etc.). */
body{font-family:'Poppins',sans-serif}

/* ─── Page-Load-Fade-In (Sprint 7 — UX-Polish) ───
   Multi-HTML-Setup: jede Page lädt von Scratch. Ohne Animation wirkt jeder
   Modul-Switch hart/abgehackt. Eine 220ms opacity-Fade gibt smoothes Gefühl.

   ACHTUNG: KEIN transform hier! transform mit ANY value != none (auch
   translateY(0)) auf body erstellt einen neuen Stacking-Context UND einen
   neuen Containing-Block für position:fixed-Kinder. Resultat: der
   #np-mobile-sidebar (position:fixed;top:0;bottom:0) bezieht sich dann
   nicht mehr auf den Viewport, sondern auf den (potentiell 3000px hohen)
   Body — Drawer wird riesig + kein Scroll mehr moeglich. Plus animation-
   fill-mode "both" hielt den End-State permanent. NUR opacity, kein fill-mode.
   prefers-reduced-motion respektieren (Accessibility). */
@keyframes np-page-in{
  from{opacity:0}
  to{opacity:1}
}
body{animation:np-page-in 220ms cubic-bezier(.16,1,.3,1)}
@media (prefers-reduced-motion:reduce){
  body{animation:none}
}

/* Design-Tokens — kanonische Namen.
   Module dürfen lokal überschreiben, aber nicht neue Farbwerte erfinden. */
:root{
  /* Dunkle Grün-Palette (Sidebar, dunkle Flächen) */
  --dark:#0a0f0d;
  --g-dark:#0a3526;
  --g-mid:#0F4C35;
  --g-accent:#1a6647;
  --g-bright:#3ddc84;
  --g-dim:rgba(61,220,132,.12);

  /* Flächen */
  --white:#fff;
  --off:#f7f9f8;
  --hv:#fafafa;

  /* Text */
  --text:#111827;
  --text-light:#374151;
  --gray:#6b7280;

  /* Rahmen */
  --border:#e8ebe9;           /* leicht grün-getönt statt kalt-grau — mehr Wärme */
  --border-strong:#d1d5db;    /* für stärkere Abgrenzungen */
  --border-dark:rgba(255,255,255,.08);

  /* Status-Farben (Base) */
  --amber:#f59e0b;
  --blue:#3b82f6;
  --red:#ef4444;
  --purple:#8b5cf6;

  /* ─── Semantic Badge/Chip-Tokens (Sprint 5) ───
     Für alle farbigen UI-Pillen. Jedes Set hat bg/fg/border.
     Damit sehen Badges überall konsistent aus und bleiben subtil —
     keine Pastel-Bastelfarben mehr. */
  --ok-bg:linear-gradient(180deg,rgba(61,220,132,.14),rgba(61,220,132,.08));
  --ok-fg:#0a6640;
  --ok-border:rgba(61,220,132,.3);

  --warn-bg:linear-gradient(180deg,rgba(245,158,11,.14),rgba(245,158,11,.08));
  --warn-fg:#92400e;
  --warn-border:rgba(245,158,11,.3);

  --err-bg:linear-gradient(180deg,rgba(239,68,68,.12),rgba(239,68,68,.07));
  --err-fg:#991b1b;
  --err-border:rgba(239,68,68,.3);

  --info-bg:linear-gradient(180deg,rgba(59,130,246,.12),rgba(59,130,246,.07));
  --info-fg:#1e40af;
  --info-border:rgba(59,130,246,.3);

  --purple-bg:linear-gradient(180deg,rgba(139,92,246,.12),rgba(139,92,246,.07));
  --purple-fg:#5b21b6;
  --purple-border:rgba(139,92,246,.3);

  --neutral-bg:linear-gradient(180deg,rgba(107,114,128,.08),rgba(107,114,128,.04));
  --neutral-fg:#374151;
  --neutral-border:rgba(107,114,128,.22);

  /* ─── Shadow-System (Sprint 5) ───
     Vier Stufen für Tiefe ohne Übertreibung. Stripe/Linear-inspiriert —
     feine Light-Source von oben, nie plakativ. */
  --shadow-xs:0 1px 2px rgba(17,24,39,.04);
  --shadow-sm:0 1px 3px rgba(17,24,39,.06),0 1px 2px rgba(17,24,39,.04);
  --shadow-md:0 4px 12px rgba(17,24,39,.06),0 2px 4px rgba(17,24,39,.04);
  --shadow-lg:0 10px 28px rgba(17,24,39,.08),0 4px 10px rgba(17,24,39,.05);
  --shadow-xl:0 20px 50px rgba(17,24,39,.12),0 8px 20px rgba(17,24,39,.06);

  /* Inner-Glow auf Grün-Accent (für Buttons, Focus-Rings) */
  --glow-g:0 0 0 3px rgba(61,220,132,.22);
  --glow-g-strong:0 4px 16px rgba(61,220,132,.32);

  /* ─── Motion-Tokens (Sprint 5) ───
     Konsistente Timings. Nutze diese Vars statt überall neue Zahlen. */
  --ease-out:cubic-bezier(.16,1,.3,1);        /* sehr sanftes ease-out (quart) */
  --ease-spring:cubic-bezier(.34,1.56,.64,1);  /* leichter Spring-Bounce */
  --ease-in-out:cubic-bezier(.65,0,.35,1);    /* symmetrisch */
  --dur-fast:120ms;
  --dur-med:220ms;
  --dur-slow:420ms;

  /* ─── Glass-Effect-Tokens (Sprint 5) ───
     Für Modals, Sticky-Headers, schwebende Panels. iOS/macOS-Frosted-Feel. */
  --glass-bg:rgba(255,255,255,.72);
  --glass-bg-dark:rgba(10,15,13,.72);
  --glass-blur:saturate(180%) blur(18px);
  --glass-border:rgba(255,255,255,.55);

  /* ─── Alias-Set für Altcode (index.html, freelancer-hub.html) ───
     Wird von applyTheme() in index.html auch per JS gesetzt;
     hier als statischer Fallback damit Seiten ohne applyTheme() funktionieren. */
  --ac:var(--g-bright);
  --at:var(--text);
  --bg:var(--off);
  --bg2:var(--white);
  --bd:var(--border);
  --bs:var(--border);
  --ib:var(--off);
  --hv2:var(--hv);
  --lb:var(--gray);
  --tx:var(--text);
  --ts:var(--text-light);
  --tm:var(--gray);
  --w:var(--amber);
  --d:var(--red);
}

/* ─── Button-Varianten (Sprint 5 — Stripe-inspired) ───
   Basis (.btn) bleibt pro Modul inline, weil Groessen variieren.
   Alle Buttons haben jetzt subtile Shadow + Hover-Lift + Glow auf Focus.
   Transition nutzt die zentralen Motion-Tokens. */
/* ─── Button-Base + Variants (zentralisiert 31.05.2026) ───
   Master-Entscheidungen Jason 31.05.:
   - Primary-Farbe: dunkelgruen (--g-mid = #0F4C35)
   - Klassenname: .btn-primary (Long-Form)
   - Padding-Master: 8px 14px
   .btn-pri ist als Legacy-Alias mit-supported damit alte Aufrufe in
   anfragen.html + recommendations.html nicht direkt brechen — wird
   aber als deprecated markiert. */
.btn{display:inline-flex;align-items:center;gap:6px;font-family:'Poppins',sans-serif;font-size:12px;font-weight:600;padding:8px 14px;border-radius:7px;cursor:pointer;border:none;white-space:nowrap;transition:background var(--dur-fast) var(--ease-out),border-color var(--dur-fast) var(--ease-out),color var(--dur-fast) var(--ease-out),transform var(--dur-fast) var(--ease-out),box-shadow var(--dur-fast) var(--ease-out)}
.btn:disabled{opacity:.45;cursor:not-allowed;pointer-events:none}
.btn:active{transform:translateY(0)!important}

.btn-primary,.btn-pri{background:var(--g-mid);color:#fff;box-shadow:var(--shadow-xs)}
.btn-primary:hover:not(:disabled),.btn-pri:hover:not(:disabled){background:var(--g-accent);transform:translateY(-1px);box-shadow:var(--shadow-sm)}
.btn-primary:focus-visible,.btn-pri:focus-visible{outline:none;box-shadow:var(--glow-g)}

.btn-ghost{background:#fff;border:1px solid var(--border);color:var(--text-light);box-shadow:var(--shadow-xs)}
.btn-ghost:hover:not(:disabled){border-color:var(--border-strong);color:var(--text);background:#fff;transform:translateY(-1px);box-shadow:var(--shadow-sm)}
.btn-ghost:focus-visible{outline:none;border-color:var(--g-bright);box-shadow:var(--glow-g)}

.btn-danger{background:var(--err-bg);color:var(--err-fg);border:1px solid var(--err-border);box-shadow:var(--shadow-xs)}
.btn-danger:hover:not(:disabled){transform:translateY(-1px);box-shadow:var(--shadow-sm),0 4px 12px rgba(239,68,68,.15)}

.btn-dark{background:var(--dark);color:#fff;box-shadow:var(--shadow-xs)}
.btn-dark:hover:not(:disabled){background:var(--g-mid);transform:translateY(-1px);box-shadow:var(--shadow-md)}

/* ─── Badge-Standards (Sprint 5) ───
   Alle farbigen Pillen/Chips sollten diese Klassen nutzen statt
   Inline-Style. Subtile Gradient + Border + feiner Shadow = premium,
   nicht mehr flach-pastellig. Base-Class (.badge) kann pro Modul
   inline erweitert werden (Padding, Font-Size), wichtig sind die
   Farb-Varianten. */
.badge{display:inline-flex;align-items:center;gap:4px;padding:3px 9px;font-size:10px;font-weight:600;letter-spacing:.02em;border-radius:100px;white-space:nowrap;line-height:1.4;border:1px solid transparent;transition:transform var(--dur-fast) var(--ease-out),box-shadow var(--dur-fast) var(--ease-out)}
.badge-ok{background:var(--ok-bg);color:var(--ok-fg);border-color:var(--ok-border);box-shadow:var(--shadow-xs)}
.badge-warn{background:var(--warn-bg);color:var(--warn-fg);border-color:var(--warn-border);box-shadow:var(--shadow-xs)}
.badge-err{background:var(--err-bg);color:var(--err-fg);border-color:var(--err-border);box-shadow:var(--shadow-xs)}
.badge-info{background:var(--info-bg);color:var(--info-fg);border-color:var(--info-border);box-shadow:var(--shadow-xs)}
.badge-purple{background:var(--purple-bg);color:var(--purple-fg);border-color:var(--purple-border);box-shadow:var(--shadow-xs)}
.badge-neutral{background:var(--neutral-bg);color:var(--neutral-fg);border-color:var(--neutral-border);box-shadow:var(--shadow-xs)}

/* ─── Glass-Backdrop (Sprint 5) ───
   Modal-Overlays bekommen ein frosted-glass Gefühl statt plattem grauen
   Layer. iOS/macOS-Standard. */
.glass{background:var(--glass-bg);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);border:1px solid var(--glass-border)}

/* Overlay-Klassen die durch hub.css bekannt sind bekommen automatisch
   den Backdrop-Blur-Effekt. Modul-spezifische Overlay-Farben (rgba black)
   werden subtiler — Blur übernimmt die visuelle Trennung. */
.cm-overlay,.modal-overlay,.create-overlay,.project-overlay,.del-ov,.mo-overlay{
  background:rgba(10,15,13,.28)!important;
  backdrop-filter:saturate(140%) blur(6px);
  -webkit-backdrop-filter:saturate(140%) blur(6px);
}

/* ─── Card-Basis mit Elevation (Sprint 5) ───
   Jedes Modul kann .card-elev einsetzen für einheitliche Kachel-Optik.
   Bestehende module-specific Styles bleiben unberührt. */
.card-elev{background:#fff;border:1px solid var(--border);border-radius:12px;box-shadow:var(--shadow-sm);transition:transform var(--dur-med) var(--ease-out),box-shadow var(--dur-med) var(--ease-out)}
.card-elev:hover{transform:translateY(-2px);box-shadow:var(--shadow-md)}

/* Page-Load-Fade-In wurde Sprint 5c wieder entfernt — auf Modulen mit
   zweiphasigem Render (Cache-Hydrate → Cloud-Refresh) gab's ein
   sichtbares Doppel-Animation-Wackeln. Der erste Fade lief, dann kam
   innerHTML-Replace → zweiter Fade. Nicht mehr schön. */

/* ─── Skeleton-Loading-States (Sprint 6a) ───
   Statt "Laden..."-Text bekommen Module beim Initial-Load ein
   Skeleton-Gerüst — hebt gefühlte Performance, verhindert Layout-Shift.
   Usage: <div class="sk sk-card"></div> / <div class="sk sk-line"></div>
   Shimmer-Animation wandert smooth von links nach rechts. */
.sk{
  position:relative;
  background:linear-gradient(90deg,#eef1ef 0%,#f7f9f8 40%,#eef1ef 100%);
  background-size:200% 100%;
  border-radius:6px;
  animation:sk-shimmer 1.6s ease-in-out infinite;
}
.sk-line{height:12px;margin-bottom:8px}
.sk-line-sm{height:9px;width:60%}
.sk-line-lg{height:18px;width:40%;margin-bottom:12px}
.sk-card{height:90px;border-radius:12px;margin-bottom:10px}
.sk-card-sm{height:60px;border-radius:10px;margin-bottom:8px}
.sk-card-lg{height:140px;border-radius:14px;margin-bottom:14px}
.sk-circle{border-radius:50%}
.sk-row{display:flex;align-items:center;gap:12px;padding:10px 0}
.sk-row .sk-circle{width:32px;height:32px;flex-shrink:0}
.sk-row .sk-content{flex:1;display:flex;flex-direction:column;gap:6px}
@keyframes sk-shimmer{
  0%{background-position:200% 50%}
  100%{background-position:-200% 50%}
}

/* Reduziere Motion für User die es so eingestellt haben */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms!important;
    transition-duration:.01ms!important;
  }
}

/* ─── Globale Mobile-Guards ───
   Greift überall — verhindert dass Form-Inputs und Überschriften aus
   dem Viewport schießen. In Modals spielt iOS/Safari sonst verrückt
   wenn der Zoom reinzoomt wegen font-size<16px.
*/
html{-webkit-text-size-adjust:100%}
input,select,textarea{box-sizing:border-box;max-width:100%;min-width:0}
/* iOS: font-size <16px triggert Autozoom beim Fokus — auf 16px
   aufrunden bei kleineren Screens. */
@media (max-width:768px){
  input[type=text],input[type=email],input[type=url],input[type=number],
  input[type=date],input[type=datetime-local],input[type=tel],input[type=search],
  input[type=password],select,textarea{font-size:16px!important}
}

/* Body-Scroll-Lock Helfer: wenn ein Overlay offen ist, setzt das JS
   body.np-lock — dann ist Scroll im Hintergrund blockiert und der
   Dialog kann selbst scrollen. Module können sich darauf verlassen. */
body.np-lock{overflow:hidden!important;touch-action:none;position:fixed;inset:0;width:100%}
body.np-lock .main,body.np-lock .content,body.np-lock .home{overflow:hidden!important}

/* Automatisches Body-Scroll-Lock via :has() — greift wenn eines der
   bekannten Overlay-Elemente sichtbar im DOM ist. Modul-Code muss
   dann nicht mehr manuell lock/unlock aufrufen. iOS 15.4+ / Chrome
   105+ (sehr breit verbreitet). */
body:has(.cm-overlay.open),
body:has(.create-overlay),
body:has(.project-overlay),
body:has(.modal-overlay.active),
body:has(.del-ov),
body:has(.fn-targets-modal),
body:has(.mo-overlay.open),
body:has(#overlay.active),
body:has(.ov),
body:has(#edit-overlay.open){
  overflow:hidden!important;touch-action:none
}

/* Standard-Overlays werden selbst scrollbar gemacht (damit der Content
   nicht aus dem Viewport fällt). Greift für alle bekannten Overlay-
   Klassen im Hub — wenn ein Modul einen eigenen Namen nutzt, inline
   überschreiben. */
.modal-overlay,.cm-overlay,.ov,.create-overlay,.pm-overlay,.del-ov,.fn-targets-modal,.mo-overlay{
  overflow-y:auto;-webkit-overflow-scrolling:touch;
}
/* Modal-Content hat max-height und eigenen Scroll-Kontext, damit der
   Button-Footer sichtbar bleibt auch wenn der Body lang ist. */
.cm-modal,.create-modal,.pm-panel,.del-box,.sp,.fn-targets-box{
  max-height:calc(100dvh - 40px);max-height:calc(100vh - 40px);
}
@media (max-width:768px){
  .cm-modal,.create-modal,.pm-panel,.fn-targets-box{
    max-height:100dvh;max-height:100vh;border-radius:0!important
  }
}

/* ═══════════════════════════════════════════════════
   Mobile-Loading-Flash & Sidebar — Global Layout-Fix
   ───────────────────────────────────────────────────
   Diese Regeln müssen VOR First-Paint greifen, sonst sieht
   der User kurz die fixed-Sidebar (#0a0f0d, schwarz) plus
   weißen Content — der hässliche „Split-Screen-Flash"-Effekt
   beim Page-Switch auf Mobile. Vorher per JS injiziert
   (_nav.js), aber das passiert nach Initial-Paint. Hier in
   hub.css ist es garantiert vor First-Paint da.
═══════════════════════════════════════════════════ */
@media (max-width:768px){
  /* Desktop-Sidebar komplett versteckt — wird durch Mobile-Header
     ersetzt der via _nav.js gebaut wird. */
  .sidebar,
  #global-sidebar,
  .app-layout > aside.sidebar{display:none!important}
  .main,
  main,
  .app-layout > main{margin-left:0!important;width:100%!important}
  /* Initial-Body-Background passend zu Content-Hintergrund —
     verhindert dass kurz die dunkle Sidebar-Farbe durchschimmert. */
  body{background:#f7f9f8}

  /* Mobile-Drawer (np-mobile-sidebar) — robustes Scroll-Setup für iOS.
     overscroll-behavior:contain verhindert dass Touch-Scroll vom Drawer
     zur darunter liegenden Page propagiert. touch-action:pan-y erlaubt
     nur vertikales Wischen (kein horizontales "Drawer-mit-Daumen-wider-
     aufschiebbar"). overflow-y:auto + -webkit-overflow-scrolling:touch
     fuer smoothes vertikales Scrollen. */
  #np-mobile-sidebar{
    overflow-x:hidden!important;
    overflow-y:auto!important;
    overscroll-behavior:contain;
    touch-action:pan-y;
    -webkit-overflow-scrolling:touch;
    /* Width MIT !important — verhindert dass modul-spezifisches CSS
       die Drawer-Breite veraendert. Tasks/Anfragen/Uebersicht hatten
       teils ihre eigenen .sidebar-Regeln die durch erhoehte Specificity
       oder !important den Drawer mit aufgeblasen haben. */
    max-width:280px!important;
    width:280px!important;
    /* Harte rechte Kante: Module haben unterschiedliche Page-Hintergruende
       (Tasks/Freelancer-Hub haben dunkle Cards, Client-Onboarding helle).
       1px Inset-Border + schmaler shadow = klare visuelle Kante, OHNE den
       Eindruck zu erwecken der Drawer sei breiter (24px-Blur tat genau das). */
    box-shadow:inset -1px 0 0 rgba(255,255,255,.08), 2px 0 6px rgba(0,0,0,.35);
  }
  #np-sidebar-backdrop{
    overscroll-behavior:contain;
    touch-action:none;
    /* Einheitlich dunkler Backdrop (vorher .4) damit Drawer-Kante immer
       optisch gleich aussieht, egal was im Hintergrund liegt. */
    background:rgba(0,0,0,.55)!important;
  }
  /* Nav-Items: white-space:nowrap im _nav.js-Default sprengt den Drawer
     wenn Labels zu lang sind. Wir koennen dort nicht editieren (alle
     Module benutzen dasselbe _nav.js), aber hier per !important + ID-
     Specificity ueberschreiben. Items selber bekommen overflow:hidden
     + min-width:0, das Label bekommt nowrap+ellipsis. */
  body #np-mobile-sidebar .nav-item{
    white-space:normal!important;
    overflow:hidden!important;
    min-width:0!important;
    max-width:calc(280px - 16px)!important;
    box-sizing:border-box!important;
    /* Touch-Target-Hoehe: _nav.js setzt padding:10px 14px. Auf Mobile
       sind 10px vertikal zu wenig — Items sehen "zusammengequetscht"
       aus und sind unter dem 44px Apple-HIG-Touch-Target. Wir erhoehen
       NUR vertikal (top/bottom), horizontal bleibt damit der Drawer
       nicht breiter wird. */
    /* User-Feedback: 15px war zu hoch (Drawer ueberlief), 13px war zu eng.
       14px = Sweet Spot, knapp ueber Apple-44px-Touch-Standard. */
    padding-top:14px!important;
    padding-bottom:14px!important;
    margin-top:3px!important;
    margin-bottom:3px!important;
  }
  body #np-mobile-sidebar .nav-label{
    flex:1!important;
    overflow:hidden!important;
    text-overflow:ellipsis!important;
    white-space:nowrap!important;
    min-width:0!important;
  }
  /* Width-Cap auf alle Drawer-Kinder — verhindert dass z.B. lange Section-
     Header, Avatar-Bars oder Logout-Buttons den Drawer aufblasen.
     ACHTUNG: HIER KEIN overflow-x:hidden! CSS-Spec: wenn eine overflow-
     Achse non-visible ist, wird die andere implizit auto. Auf <nav> als
     direktem Drawer-Kind hat das frueher dazu gefuehrt dass <nav> selbst
     zum scroll-Container fuer Vertikal wird — User scrollt dann INNERHALB
     der Tools-Liste statt im Drawer. Width-Cap reicht: das Parent
     #np-mobile-sidebar hat schon overflow-x:hidden (siehe oben), das
     schneidet jede Ueberlaenge ab. */
  body #np-mobile-sidebar > *,
  body #np-mobile-sidebar nav > *,
  body #np-mobile-sidebar nav > * > *{
    max-width:100%!important;
    box-sizing:border-box!important;
  }
  body #np-mobile-sidebar .nav-profile{max-width:100%!important;overflow:hidden!important}

  /* Scrollbar-Indikatoren komplett unsichtbar — sowohl auf dem Drawer-
     Root als auch auf jedem Kind. Falls trotz neuer Layout-Regeln noch
     ein internes Element zum scroll-Container wird, soll der User
     wenigstens KEINEN Scrollbar-Strich sehen. _nav.js setzt das schon
     auf #np-mobile-sidebar selbst, aber hier zusaetzlich per !important
     vererbt auf alle Descendants. */
  body #np-mobile-sidebar,
  body #np-mobile-sidebar *{
    scrollbar-width:none!important;
    -ms-overflow-style:none!important;
  }
  body #np-mobile-sidebar::-webkit-scrollbar,
  body #np-mobile-sidebar *::-webkit-scrollbar{
    width:0!important;
    height:0!important;
    display:none!important;
  }

  /* touch-action: NUR auf dem Drawer-Root, NICHT auf den Kindern.
     Lesson learned: pan-y auf einem nicht-scrollenden Kind fangt den
     Touch ab und propagiert ihn nicht ans scrollende Parent — vertikales
     Scrollen wird unmoeglich. Auf dem Root reicht pan-y vollkommen:
     - Vertikales Wischen scrollt den Drawer (overflow-y:auto).
     - Horizontales Wischen wird blockiert (pan-y verbietet pan-x).
     Kinder behalten touch-action:auto Default — der Browser handhabt
     Klicks/Taps darauf normal, und Wisch-Gesten propagieren zum Parent. */
  body #np-mobile-sidebar{
    touch-action:pan-y!important;
  }
}

/* ─── Toast (zentralisiert 29.05.2026, vorher in 8 Files dupliziert) ───
   Lazy-erzeugt durch _helpers.js toast()-Helper. Markup-Konvention:
     <div id="np-toast" class="toast"></div>
   wird in body angehaengt wenn nicht vorhanden. Legacy id="toast"
   wird ebenfalls erkannt (Backwards-compat).
   Kind-Klassen: '' (Standard), 'err' (rot), 'warn' (gelb).
   pointer-events:none damit Klicks unter dem Toast durchgehen
   (kritisch fuer Modals — Bug-Lesson 14.05.). */
.toast{position:fixed;bottom:20px;right:20px;background:#0a0f0d;color:#fff;padding:10px 16px;border-radius:8px;font-size:12px;font-weight:500;z-index:300;opacity:0;transform:translateY(10px);transition:opacity .25s,transform .25s;display:flex;align-items:center;gap:6px;pointer-events:none;max-width:calc(100vw - 40px);white-space:pre-line;line-height:1.4;font-family:'Poppins',sans-serif}
.toast.show{opacity:1;transform:translateY(0)}
.toast.err{background:#7f1d1d}
.toast.warn{background:#92400e}
