/* 03-rahmen.css — Seitenkopf (alle Seiten), Essen-Wochenraster, Navigation unten. Teil der geordneten Kaskade: in index.html in Nummern-Reihenfolge geladen; Regeln NICHT zwischen Dateien verschieben, ohne die Reihenfolge zu bedenken. */
/* ─── PREMIUM LIQUID-GLASS HEADER (für alle Pages) ──────────────────────── */
/* Alle Header (Kalender, Einkauf, Profil, Statistik) als schwebende Glass-Cards. */
.header,
.shop-header,
.profile-header,
.stats-header,
.monthcal-header {
  margin: max(10px, env(safe-area-inset-top)) 12px 8px;
  padding: 16px 18px 18px;
  border-radius: 26px;
  /* Glas-Tint + driftender Glow liegen jetzt auf ::before (siehe unten) — ENTKOPPELT
     vom backdrop-filter dieses Elements. So animiert background-position NICHT mehr die
     Blur-Ebene → kein Dauer-Flackern auf High-DPR (OnePlus 15, dpr 3.5); Optik identisch. */
  border: 1px solid rgba(255,255,255,0.10);
  backdrop-filter: blur(calc(15px * var(--glass-mult) * var(--glass-scroll, 1))) saturate(180%);
  -webkit-backdrop-filter: blur(calc(15px * var(--glass-mult) * var(--glass-scroll, 1))) saturate(180%);
  box-shadow:
    0 24px 48px -20px rgba(0,0,0,0.45),
    0 4px 12px -4px rgba(0,0,0,0.25),
    inset 0 1px 0 rgba(255,255,255,0.12),
    inset 0 -1px 0 rgba(0,0,0,0.12);
  position: sticky;
  top: max(10px, env(safe-area-inset-top));
  z-index: 100;
  isolation: isolate;
}
/* Unregelmäßiger „Wander"-Pfad (nicht-lineare Zeiten + 2D-Richtungswechsel) →
   wirkt organisch statt statisch; Weg bewusst kürzer gehalten (weniger weit rein/raus). */
@keyframes headerGlowFloat {
  0%   { background-position: 12% 20%; }
  18%  { background-position: 88% 30%; }
  36%  { background-position: 60% 85%; }
  54%  { background-position: 90% 58%; }
  72%  { background-position: 22% 78%; }
  88%  { background-position: 35% 16%; }
  100% { background-position: 12% 20%; }
}
/* Glas-Tint + driftender Glow als Pseudo-Element OHNE backdrop-filter → die teure
   Blur-Ebene des Headers bleibt STATISCH, nur dieser leichte Gradient repaintet beim
   Driften (kein Re-Raster der Blur-Ebene = kein Flackern auf High-DPR). Optik identisch. */
.header::before,
.shop-header::before,
.profile-header::before,
.stats-header::before,
.monthcal-header::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(circle at 12% -10%, rgba(var(--cell-glow-rgb), 0.32) 0%, transparent 60%),
    radial-gradient(circle at 100% 110%, rgba(255,255,255,0.05) 0%, transparent 55%),
    linear-gradient(135deg, rgba(255,255,255,0.09) 0%, rgba(255,255,255,0.02) 100%);
  background-size: 146% 146%;
  background-position: 50% 50%;
  animation: headerGlowFloat 14s ease-in-out infinite;
}
/* Reduced-Motion / Animationen aus: Glow WIRKLICH stoppen (nicht nur 0.001s) — sonst
   bleibt der Repaint-Druck. Statischer Verlauf bleibt sichtbar. */
@media (prefers-reduced-motion: reduce) {
  .header::before, .shop-header::before, .profile-header::before,
  .stats-header::before, .monthcal-header::before { animation: none; background-position: 50% 50%; }
}
html.anims-off .header::before, html.anims-off .shop-header::before,
html.anims-off .profile-header::before, html.anims-off .stats-header::before,
html.anims-off .monthcal-header::before { animation: none !important; background-position: 50% 50%; }
/* Glas-aus (html.no-glass): die Header haben nur halbtransparente Verläufe + den
   (dann entfernten) backdrop-filter → ohne deckenden Grund scrollt der Inhalt sichtbar
   durch. Eine opake --card-Basis UNTER die bestehenden Verläufe legen (Look bleibt,
   jetzt deckend). position/z-index/sticky bleiben aus der Basisregel. */
html.no-glass .header,
html.no-glass .shop-header,
html.no-glass .profile-header,
html.no-glass .stats-header,
html.no-glass .monthcal-header {
  background-color: var(--card);
}
/* FPS: Beim Scrollen den Milchglas-Blur kurz flacher rechnen (–65%) → die teure
   Blur-Ebene ist pro Scroll-Frame deutlich billiger; nach Scroll-Ende (uiFx entfernt
   .scrolling) sofort wieder voll. EIGENE Variable, damit der Stärke-Regler
   (--glass-mult, inline gesetzt) NICHT überschrieben wird (sie multiplizieren sich). */
html.scrolling { --glass-scroll: 0.35; }
/* ANDROID/Adreno (html.andr): den Scroll-Blur-Dip NEUTRALISIEREN. Der Wert-Sprung
   (15px↔5.25px an ~35 Flächen gleichzeitig, hart ohne Übergang, bei jedem Scroll-
   Start UND -Ende) zwingt Adreno zum kompletten Neu-Rastern aller Backdrops →
   der sichtbare 1-Frame-Blitz („Momente, in denen die App rumflackert"). Konstanter
   Blur flackert nicht; iPhone/WebKit behält den FPS-Dip (dort kein Re-Raster-Blitz). */
html.andr.scrolling { --glass-scroll: 1; }

/* Gradient-Text-Helper für alle Hero-Titles in den Glass-Cards */
.hero-gradient-text {
  background: linear-gradient(180deg,
    var(--text) 0%,
    color-mix(in srgb, var(--text) 78%, transparent) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  letter-spacing: -0.03em;
}

/* Shared Hero-Layout (Caption + Title + Stat). Wird in shop-/profile-/stats-header
   verwendet — analog zum Calendar-Header. */
.hero-caption {
  font-size: 10px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text);
  opacity: 0.5;
  white-space: nowrap;
}
.hero-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-3);
}
.hero-block {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.hero-title {
  font-size: 26px;
  font-weight: var(--fw-heavy);
  letter-spacing: -0.025em;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hero-stat {
  font-size: 12px;
  font-weight: var(--fw-bold);
  color: var(--text);
  opacity: 0.55;
  letter-spacing: 0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
}

/* Generischer Header-Action-Button (Pill mit Icon + Label).
   Wie .header-today-btn, aber neutral (kein Akzent-Tint) — für Aktionen
   wie "Zurück" auf der Stats-Page. */
.header-action-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 32px;
  padding: 0 11px 0 9px;
  border-radius: var(--r-pill);
  background: linear-gradient(135deg, rgba(255,255,255,0.14), rgba(255,255,255,0.06));
  border: 1px solid rgba(255,255,255,0.14);
  color: var(--text);
  font-family: inherit;
  font-size: 11px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.12);
  transition:
    background 0.22s cubic-bezier(0.32, 0.72, 0, 1),
    border-color 0.22s ease,
    transform 0.30s cubic-bezier(0.34, 1.56, 0.64, 1),
    box-shadow 0.28s ease;
}
.header-action-btn:active {
  background: rgba(var(--cell-glow-rgb), 0.32);
  border-color: rgba(var(--cell-glow-rgb), 0.55);
  transform: scale(0.93);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.12),
    0 0 0 1px rgba(var(--cell-glow-rgb), 0.30),
    0 0 14px rgba(var(--cell-glow-rgb), 0.30);
}
.header-action-btn svg { opacity: 0.85; transition: transform 0.30s cubic-bezier(0.34, 1.56, 0.64, 1); }
.header-action-btn:active svg { transform: translateX(-2px); }
.header-action-btn.flash { animation: flashPulse 0.35s ease; }
/* Stats-Refresh-Button: Icon dreht sich während Daten geladen werden */
#statsRefreshBtn.is-spinning svg {
  animation: statsRefreshSpin 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes statsRefreshSpin {
  0%   { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

/* Top-Row: Dynamische Context-Caption links, Date-Picker rechts */
.header-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: 10px;
  min-height: 22px;
}
.header-user,
.user-avatar,
.user-name,
.user-sub { display: none; }

/* Dynamic Context-Caption — wechselt je nach Wochen-Position (current/past/future).
   Wird über JS gesetzt: 'Diese Woche' / 'Letzte Woche' / 'In 2 Wochen' / etc. */
.week-context {
  font-size: 10px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text);
  opacity: 0.5;
  transition: color 0.25s ease, opacity 0.25s ease;
  white-space: nowrap;
}
.week-context.current {
  color: var(--text-accent);
  opacity: 0.95;
}
.week-context.past {
  color: var(--text);
  opacity: 0.32;
}
.week-context.future {
  color: var(--text);
  opacity: 0.65;
}

.header-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
  align-items: center;
}
.icon-btn {
  height: 32px;
  min-width: 32px;
  padding: 0 var(--sp-2);
  border-radius: var(--r-pill);
  background: linear-gradient(135deg, rgba(255,255,255,0.14), rgba(255,255,255,0.06));
  border: 1px solid rgba(255,255,255,0.14);
  color: var(--text);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.12);
  transition: background 0.15s, transform 0.15s;
}
.icon-btn:active {
  background: rgba(var(--cell-glow-rgb), 0.20);
  transform: scale(0.94);
}

/* Today als sekundäre Header-Action (rechts neben Date-Picker).
   Selbe Maße wie .icon-btn, aber mit Akzent-Tint damit sie sich klar als
   „aktive Rückkehr-Action" abhebt. */
.header-today-btn {
  display: none;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  padding: 0;
  border-radius: var(--r-pill);
  /* Bewusst sehr transparent — der Header-Glow soll durch den Button
     durchscheinen, die Action bleibt über Border + Akzent-Icon erkennbar. */
  background: rgba(var(--cell-glow-rgb), 0.08);
  border: 1px solid rgba(var(--cell-glow-rgb), 0.22);
  color: var(--text-accent);
  font-family: inherit;
  cursor: pointer;
  flex-shrink: 0;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
  transition: background 0.15s, transform 0.15s, border-color 0.15s;
}
.header-today-btn[style*="flex"],
.header-today-btn[data-visible="true"] { display: inline-flex; }
.header-today-btn:active {
  background: rgba(var(--cell-glow-rgb), 0.20);
  border-color: rgba(var(--cell-glow-rgb), 0.38);
  transform: scale(0.94);
}
.header-today-btn svg { opacity: 0.90; }
.icon-btn.flash { animation: flashPulse 0.35s ease; }
@keyframes flashPulse {
  0%   { background: linear-gradient(135deg, rgba(255,255,255,0.14), rgba(255,255,255,0.06)); }
  35%  { background: rgba(var(--cell-glow-rgb), 0.55); box-shadow: 0 0 18px rgba(var(--cell-glow-rgb), 0.55); }
  100% { background: linear-gradient(135deg, rgba(255,255,255,0.14), rgba(255,255,255,0.06)); }
}

/* Hero-Row: Title-Block (Title + Stat) links, Joined-Stepper (mit optionalem
   Today-Button in der Mitte) rechts. CSS-`order` arrangiert HTML zu:
   title-block | ‹ | [Heute] | › */
.month-nav {
  display: flex;
  align-items: center;
  gap: 0;
}
.month-title-block {
  order: 1;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  margin-right: var(--sp-3);
}
.month-title {
  font-size: 28px;
  font-weight: var(--fw-heavy);
  letter-spacing: -0.03em;
  line-height: 1.05;
  text-align: left;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* Subtle gradient-text für Premium-Wirkung */
  background: linear-gradient(180deg,
    var(--text) 0%,
    color-mix(in srgb, var(--text) 78%, transparent) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  /* Title-Crossfade beim Wochenwechsel: kurzes Fade-Out, Text-Tausch, Fade-In */
  transition: opacity 0.17s cubic-bezier(0.32, 0.72, 0, 1);
}
.month-title.title-fading-out { opacity: 0; }
.month-title.title-fading-in  {
  opacity: 1;
  animation: title-fade-in 0.18s cubic-bezier(0.32, 0.72, 0, 1) both;
}
@keyframes title-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.month-stat {
  font-size: 11px;
  font-weight: var(--fw-med);
  color: var(--text);
  opacity: 0.50;
  letter-spacing: 0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
}

/* Joined-Glass-Stepper — Wochen-Pfeile als zusammenhängende Pill.
   Stärker: 40×38px (statt 36×32), SVG-Chevrons mit stroke-width 2.6,
   stärkere Border-Glow-Akzentfarbe für klares Touch-Feedback. */
.month-btn {
  width: 40px;
  height: 38px;
  background: linear-gradient(135deg, rgba(255,255,255,0.16), rgba(255,255,255,0.07));
  border: 1px solid rgba(255,255,255,0.16);
  color: var(--text);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s, transform 0.12s, border-color 0.15s, box-shadow 0.15s;
  flex-shrink: 0;
  border-radius: 0;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.14);
}
.month-btn svg {
  width: 17px;
  height: 17px;
  stroke: currentColor;
  fill: none;
  opacity: 0.92;
  transition: transform 0.15s;
}
.month-btn:first-of-type {
  order: 2;
  border-radius: var(--r-pill) 0 0 var(--r-pill);
  border-right: none;
}
.month-btn:last-of-type {
  order: 3;
  border-radius: 0 var(--r-pill) var(--r-pill) 0;
}
.month-btn:active {
  background: rgba(var(--cell-glow-rgb), 0.30);
  border-color: rgba(var(--cell-glow-rgb), 0.45);
  transform: scale(0.93);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.14),
    inset 0 0 12px rgba(var(--cell-glow-rgb), 0.20);
}
.month-btn:first-of-type:active svg { transform: translateX(-1px); }
.month-btn:last-of-type:active  svg { transform: translateX(1px); }
.month-btn.flash { animation: flashPulse 0.35s ease; }

/* Mini-Day-Indicator-Strip — 7 Dots, einer pro Tag der Woche.
   Gefüllt = Mahlzeit eingetragen, Akzent + Halo = heute, leer = noch nichts. */
.week-dots {
  display: flex;
  justify-content: space-between;
  gap: 4px;
  margin-top: 14px;
  padding: 0 2px;
}
.week-dots .dot {
  flex: 1;
  max-width: 28px;
  height: 4px;
  border-radius: 2px;
  background: rgba(255,255,255,0.10);
  transition: background 0.2s, box-shadow 0.2s;
}
.week-dots .dot.filled {
  background: rgba(255,255,255,0.55);
}
/* Heute → in Ruhe EXAKT wie die anderen Wochentage (User-Wunsch). Die
   „Anpassung an die Hintergrund-Animation" ist eine eigene Akzent-Tönung
   (::after), die im selben 14s-Takt wie headerGlowFloat über den Strich
   zieht: ein paar Sekunden Theme-Farbe, dann wieder neutral weiß — wirkt,
   als würde der driftende Header-Glow ihn beim Vorbeiziehen einfärben. */
.week-dots .dot.today {
  position: relative;
  overflow: hidden;
}
/* ECHTE Kopplung an den Header-Glow (uiFx.initTodayDotGlow): JS liest die
   tatsächlich animierte background-position des Headers aus, berechnet daraus
   die Live-Positionen BEIDER Glows (Akzent oben-links, Weiß unten-rechts) und
   setzt die Deckkräfte aus der realen Distanz zum Heute-Strich. Akzent-Nähe
   tönt in Theme-Farbe (::after), Weiß-Nähe hellt auf (::before). Keine
   geratene Zeitachse mehr — die Färbung folgt dem Glow selbst. */
.week-dots .dot.today::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(90deg,
    rgba(var(--cell-glow-rgb), 0.95),
    rgba(var(--cell-glow-rgb), 0.55));
  opacity: var(--tint-a, 0);
  transition: opacity 0.25s linear;
}
.week-dots .dot.today::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: rgba(255, 255, 255, 0.95);
  opacity: var(--tint-w, 0);
  transition: opacity 0.25s linear;
}

/* ─── CALENDAR / WEEK GRID ──────────────────────────────────────────────── */
/* .calendar-wrap, .calendar-grid und .week-row Layout-Properties siehe oben
   (im Scroll-Fix-Block). Hier nur Card-Styling für die Tag-Cards: */

.week-row {
  display: flex; align-items: stretch;
  background: var(--cell-bg);
  border-radius: var(--r-md);
  border: 1px solid var(--cell-border);
  overflow: hidden;
  cursor: pointer;
  position: relative;
  transition: transform 0.18s, background 0.18s;
  /* Kein Text-Markieren/iOS-Callout beim Halten & Ziehen (nervt am Handy). */
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
}
.week-row:active { transform: scale(0.985); }
/* Während Wochen-Wechsel-Animation: pointer-events deaktiviert + :active aus,
   damit Klicks während des Slides nicht stören. */
.calendar-track .week-row { pointer-events: none; }
.calendar-track .week-row:active { transform: none; }
.week-row.today {
  background: rgba(var(--cell-glow-rgb), 0.10);
  border-color: rgba(var(--cell-glow-rgb), 0.40);
}
.week-row.weekend .week-day-info { background: rgba(255,255,255,0.03); }

.week-day-info {
  width: 56px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; flex-shrink: 0;
  border-right: 1px solid var(--cell-border);
  padding: var(--sp-2) 0;
}
.week-day-name {
  font-size: 10px;
  font-weight: var(--fw-bold);
  color: var(--text);
  opacity: 0.6;
  text-transform: uppercase;
  letter-spacing: var(--ls-wide);
}
.week-day-num {
  font-size: var(--fs-t3);
  font-weight: var(--fw-heavy);
  color: var(--text);
  line-height: 1;
  letter-spacing: var(--ls-tight);
}
.week-day-num.is-today {
  width: 32px; height: 32px;
  border-radius: var(--r-pill);
  background: var(--btn-grad);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-callout);
  box-shadow: 0 4px 12px rgba(var(--cell-glow-rgb), 0.35);
}

.week-content {
  flex: 1;
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3);
  min-width: 0;
  position: relative;
}
.week-color-strip {
  width: 3px;
  align-self: stretch;
  border-radius: 2px;
  flex-shrink: 0;
}
.week-content.has-img { padding: 0; }
.week-meal-img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  z-index: 1;
}
.week-content.has-img::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(95deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.45) 50%, rgba(0,0,0,0.05) 100%);
  z-index: 2;
}
.week-text { flex: 1; min-width: 0; z-index: 3; position: relative; }
.week-content.has-img .week-text { padding: var(--sp-3); }
.week-meal-name {
  font-size: var(--fs-body);
  font-weight: var(--fw-bold);
  color: var(--text);
  letter-spacing: var(--ls-snug);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.week-content.has-img .week-meal-name {
  color: #fff;
  text-shadow: 0 1px 8px rgba(0,0,0,0.6);
}
.week-meal-notes {
  font-size: var(--fs-foot);
  font-weight: var(--fw-med);
  color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  margin-top: 2px;
}
.week-content.has-img .week-meal-notes {
  color: rgba(255,255,255,0.78);
  text-shadow: 0 1px 6px rgba(0,0,0,0.55);
}
.week-add-icon {
  flex: 1;
  display: flex; align-items: center; justify-content: center;
  font-size: 22px;
  color: var(--text); opacity: 0.22;
  font-weight: 300;
}

/* Zieh-Griff auf der Wochen-Tageskarte: Tag per Drag & Drop verschieben
   (iOS-Homescreen-Stil — halten + ziehen, die anderen Tage weichen aus).
   Kompakt + dezent, mit zartem dunklem Pill auch über Bildern lesbar. */
.week-grip {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  z-index: 5;
  width: 22px; height: 26px; padding: 0;   /* HITBOX bleibt — gut greifbar */
  display: flex; align-items: center; justify-content: center;
  border: none;
  background: transparent;                  /* sichtbares Pill steckt im ::before (kleiner) */
  color: rgba(255,255,255,0.85);
  cursor: grab; touch-action: none;
  opacity: 0.6;
  transition: opacity 0.15s, transform 0.12s;
}
/* Sichtbarer Teil (Pill) — kleiner als die Hitbox, zentriert hinter den Punkten. */
.week-grip::before {
  content: '';
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 16px; height: 19px;
  border-radius: 6px;
  background: rgba(0,0,0,0.22);
  -webkit-backdrop-filter: blur(calc(2px * var(--glass-mult) * var(--glass-scroll, 1))); backdrop-filter: blur(calc(2px * var(--glass-mult) * var(--glass-scroll, 1)));
  transition: background 0.15s;
}
.week-grip svg { fill: currentColor; pointer-events: none; position: relative; z-index: 1; width: 9px; height: 14px; }
.week-grip:hover { opacity: 0.9; }
.week-grip:active { cursor: grabbing; opacity: 1; transform: translateY(-50%) scale(0.9); }
.week-grip:active::before { background: rgba(0,0,0,0.42); }

/* Angehobene Karte beim Ziehen: schwebt mit Schatten + Akzent-Rahmen über den
   anderen. (transform/translate steuert JS inline — hier nur der „Lift"-Look.) */
.week-row--dragging {
  box-shadow: 0 18px 40px -8px rgba(0,0,0,0.55), 0 6px 14px -6px rgba(0,0,0,0.5);
  cursor: grabbing;
}
.week-row--dragging::after {
  content: ''; position: absolute; inset: 0;
  border-radius: var(--r-md);
  box-shadow: inset 0 0 0 1px rgba(var(--cell-glow-rgb), 0.55);
  pointer-events: none; z-index: 6;
}
/* Während neu angeordnet wird: kein :active-Zucken der (nicht gezogenen) Karten. */
.calendar-grid.is-reordering .week-row { cursor: grab; }
.calendar-grid.is-reordering .week-row:active { transform: none; }

/* ─── BOTTOM NAV – Floating Liquid-Glass Pill ───────────────────────────── */
/* Konzept: Bottom-Nav schwebt als Glass-Pill am unteren Rand — dieselbe
   Materialität wie die Header-Cards (Radial-Glow von unten, Backdrop-Blur,
   Inner-Highlight, Drop-Shadow). Edge-to-edge wird durch Margins ersetzt. */
.bottom-nav {
  margin: 6px 12px max(10px, env(safe-area-inset-bottom));
  padding: 6px;
  display: flex;
  gap: 4px;
  border-radius: 26px;
  background:
    radial-gradient(circle at 50% 120%, rgba(var(--cell-glow-rgb), 0.18) 0%, transparent 60%),
    linear-gradient(135deg, rgba(255,255,255,0.10) 0%, rgba(255,255,255,0.03) 100%);
  border: 1px solid rgba(255,255,255,0.10);
  backdrop-filter: blur(calc(15px * var(--glass-mult) * var(--glass-scroll, 1))) saturate(180%);
  -webkit-backdrop-filter: blur(calc(15px * var(--glass-mult) * var(--glass-scroll, 1))) saturate(180%);
  box-shadow:
    0 -8px 32px -16px rgba(0,0,0,0.45),
    0 24px 48px -20px rgba(0,0,0,0.30),
    inset 0 1px 0 rgba(255,255,255,0.12),
    inset 0 -1px 0 rgba(0,0,0,0.12);
  position: sticky;
  /* MUSS zum margin-bottom (10px) passen: auf nicht-scrollenden Seiten steht
     die Leiste im Fluss (Abstand = margin), auf scrollenden pinnt sticky sie
     bei diesem bottom-Wert. Waren die Werte verschieden (8 vs 10), HÜPFTE die
     Leiste beim Seitenwechsel sichtbar um 2px (wirkte wie Breitenänderung). */
  bottom: max(10px, env(safe-area-inset-bottom));
  z-index: var(--z-nav);
  /* Layout-Änderungen der Tabs (flex-grow/padding) bleiben in der Leiste —
     kein Reflow der Seite darunter während der Tab-Wechsel-Animation. */
  contain: layout;
}
/* Tab-Items als horizontale Capsules. Inaktive: nur Icon (Label collapsed).
   Aktiv: Tab expandiert (flex grows), Label morpht von max-width 0 zu sichtbar,
   Akzent-Background fadet ein. Alles mit Spring-Easing für iOS-typisches Feel. */
.nav-item {
  flex: 1;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 0;
  padding: 10px 6px;
  border-radius: var(--r-pill);
  cursor: pointer;
  border: none;
  background: transparent;
  color: var(--text);
  font-family: inherit;
  font-size: 12px;
  font-weight: var(--fw-heavy);
  letter-spacing: -0.005em;
  overflow: hidden;
  white-space: nowrap;
  min-width: 0;
  /* GLEITENDE PILL (User-Wahl 2026-06-11: Tempo „Sanft" 0.55s, Schwung
     „Federnd"): flex-grow/padding tragen die Tab-Breiten-Animation — der
     #navPuck folgt dieser Geometrie per rAF und erbt damit exakt das federnde
     Easing. Tabs liegen ÜBER der Pill (z-index), Hintergrund kommt vom Puck. */
  z-index: 1;
  transition:
    flex-grow   0.55s cubic-bezier(0.34, 1.56, 0.64, 1),
    padding     0.55s cubic-bezier(0.34, 1.56, 0.64, 1),
    color       0.30s cubic-bezier(0.32, 0.72, 0, 1),
    opacity     0.30s cubic-bezier(0.32, 0.72, 0, 1);
}
/* Beim Antippen KEINE Größenänderung mehr (das kurze Schrumpfen beim
   Seitenwechsel wirkte unruhig) — Feedback kommt über die gleitende Pill
   und deren Innen-Glow (navPuckGlow). */
.nav-item:active {
  background: rgba(255,255,255,0.05);
}

/* Aktiver Tab — bewusst GLEICHE Breite und GLEICHES Padding wie die anderen
   Tabs (früher flex-grow 1.25 + breiteres Padding): die Umverteilung ließ beim
   Wechsel ALLE Icons rücken und wirkte, als würde die Leiste breiter werden.
   Jetzt steht jedes Icon fest — nur die Pill (#navPuck) gleitet. */
.nav-item.active {
  opacity: 1;
  color: #fff;
}

/* Die gleitende Akzent-Pill: exakt die frühere active-Pill-Optik, als eigenes
   Element unter den Tabs. uiFx.initNavPuck setzt die Zielposition EINMAL pro
   Wechsel — das Gleiten übernimmt diese Transition (gleiche Feder wie die
   Tabs). Kein Per-Frame-JS mehr (Handy-Lag-Fix, Look identisch). */
#navPuck {
  position: absolute;
  top: 6px;
  bottom: 6px;
  left: 0;
  width: 0;
  /* GLEITEN rein über transform (translateX): seit alle Tabs gleich breit sind,
     ist die Pill-Breite konstant → reines GPU-Compositing, kein Layout pro
     Frame mehr (Handy-Smoothness). Breite wird nur bei Geometrie-Änderungen
     instant gesetzt. uiFx setzt pro Sprung das gedämpfte Easing. */
  transition: transform 0.55s cubic-bezier(0.34, 1.56, 0.64, 1);
  will-change: transform;
  border-radius: var(--r-pill);
  background:
    linear-gradient(135deg,
      rgba(var(--cell-glow-rgb), 0.42),
      rgba(var(--cell-glow-rgb), 0.22));
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.25),
    inset 0 -1px 0 rgba(0,0,0,0.10),
    0 6px 18px -6px rgba(var(--cell-glow-rgb), 0.50),
    0 0 0 1px rgba(var(--cell-glow-rgb), 0.28);
  pointer-events: none;
  z-index: 0;
}
/* Klick-Glow NUR INNERHALB der Pill (User-Wunsch): eine weiche Lichtschicht
   (::after, radialer Verlauf, von border-radius geclippt) blendet sanft auf
   und wieder ab. BEWUSST nur opacity animiert — reines GPU-Compositing statt
   Schatten-Repaints pro Frame, dadurch fühlt es sich am Handy smooth an.
   Außerhalb der Pill ändert sich nichts (Schicht liegt komplett innen). */
#navPuck::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(ellipse at 50% 45%,
    rgba(255,255,255,0.16) 0%,
    rgba(var(--cell-glow-rgb), 0.34) 42%,
    transparent 80%);
  opacity: 0;
  will-change: opacity;
}
#navPuck.no-trans { transition: none; }   /* für Instant-Syncs (Resize/Dev-Toggle) */
#navPuck.glow::after { animation: navPuckGlow 0.75s cubic-bezier(0.4, 0, 0.2, 1) both; }
@keyframes navPuckGlow {
  0%   { opacity: 0; }
  32%  { opacity: 1; }
  100% { opacity: 0; }
}

/* Icon-Wrap */
.nav-item .nav-icon-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  position: relative;
}

/* Notification-Badge: blauer Punkt mit KRÄFTIGEM, reinem weißen Ring rechts oben am Icon.
   Das Weiß ist bewusst dick & pur (#fff) – genau wie das gut erkennbare Weiß des
   Kalender-Icons. Nur ein Hauch Glow GANZ außen, damit das Weiß knackig bleibt und nicht
   ausgewaschen wird (das war vorher das Problem: dünner Ring + zu starker Glow). */
.nav-badge {
  position: absolute;
  top: -3px;
  right: -3px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--blue);
  box-shadow:
    0 0 0 2px #ffffff,                           /* reiner weißer Ring (voll #fff) */
    0 0 0 3.5px var(--nav-bg),                   /* dunkle Trennkante zur Leiste */
    0 0 7px 1.5px rgba(var(--blue-rgb), 0.85);   /* hellerer blauer Glow */
  opacity: 0;
  transform: scale(0);
  transition: opacity 0.25s, transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
  pointer-events: none;
}
.nav-item.has-badge .nav-badge {
  opacity: 1;
  transform: scale(1);
  /* Erst mit Overshoot reinploppen, danach das gewohnte Glow-Atmen */
  animation:
    navBadgePop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1),
    navBadgePulse 1.8s ease-in-out 0.5s infinite;
}
@keyframes navBadgePop {
  0%   { transform: scale(0); }
  60%  { transform: scale(1.45); }
  100% { transform: scale(1); }
}
.nav-item.active .nav-badge {
  opacity: 0;
  transform: scale(0);
  animation: none;
}
/* Sanftes „Atmen" nur des äußeren Glows — der dicke weiße Ring bleibt konstant & knackig. */
@keyframes navBadgePulse {
  0%, 100% {
    box-shadow:
      0 0 0 2px #ffffff,
      0 0 0 3.5px var(--nav-bg),
      0 0 7px 1.5px rgba(var(--blue-rgb), 0.85);
  }
  50% {
    box-shadow:
      0 0 0 2px #ffffff,
      0 0 0 3.5px var(--nav-bg),
      0 0 12px 2.5px rgba(var(--blue-rgb), 1);
  }
}
.nav-svg {
  width: 22px;
  height: 22px;
  stroke: currentColor;
  fill: none;
  flex-shrink: 0;
  /* Dimmung inaktiver Tabs liegt jetzt auf dem ICON (nicht mehr auf dem ganzen
     Button-Element) – so bleibt der Benachrichtigungs-Badge bei vollem #fff,
     genauso hell wie das Icon des aktiven Tabs. */
  opacity: 0.45;
  transition: transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.30s cubic-bezier(0.32, 0.72, 0, 1);
}
.nav-item.active .nav-svg {
  transform: scale(1.0);
  opacity: 1;
}

/* Label-Morph: collapse via max-width auf 0 für inaktive Tabs.
   Beim aktiv-werden expandiert max-width auf den natürlichen Wert mit Spring. */
.nav-label {
  max-width: 0;
  opacity: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;   /* Sicherheitsnetz: bei extrem schmal „Kalender…" statt hartem „Kalend" */
  margin-left: 0;
  transition:
    max-width   0.55s cubic-bezier(0.34, 1.56, 0.64, 1),
    opacity     0.30s cubic-bezier(0.32, 0.72, 0, 1) 0.05s,
    margin-left 0.55s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.nav-item.active .nav-label {
  max-width: 80px;
  opacity: 1;
  margin-left: 7px;
}

/* ── 4 Tabs IMMER (Kalender-Tab ist dauerhaft sichtbar, auch ohne Dev-Modus):
   kompaktere Leiste, damit „Kalender" (längstes Label) im aktiven Tab voll passt —
   in JEDEM Modus. Früher an html.dev-mode-on gekoppelt → ohne Dev waren die 4 Tabs
   mit den großen Standard-Maßen gequetscht/abgeschnitten. Die Nav-Pill (uiFx) liest
   gap/padding/Tab-Padding DYNAMISCH → Geometrie bleibt exakt. */
.bottom-nav { margin-left: 6px; margin-right: 6px; gap: 2px; }
.nav-item { padding-left: 4px; padding-right: 4px; }   /* schmaleres Tab-Padding → mehr Platz fürs Label */
.nav-svg { width: 20px; height: 20px; }
.nav-label { font-size: 11px; letter-spacing: -0.2px; }
.nav-item.active .nav-label { margin-left: 4px; max-width: 100px; }   /* max-width nicht mehr die Engstelle (Tabbreite begrenzt) */
/* Sehr schmale Handys / größere Display-Skalierung (≤374px): eine Stufe kompakter. */
@media (max-width: 374px) {
  .bottom-nav { gap: 1px; }
  .nav-item { padding-left: 3px; padding-right: 3px; }
  .nav-label { font-size: 10.5px; }
  .nav-item.active .nav-label { margin-left: 3px; }
}

