/* ================================================================
   app.css — hell, farbig, rund

   Zwei Anläufe waren daneben, und beide auf lehrreiche Weise:

   Der erste war eine iOS-Vorlage mit Grün darin — Karten in Karten,
   ein Akzent von der Stange, Unicode-Glyphen als Symbole. Beliebig.
   Der zweite war eine Kassenbon-Ästhetik: Sepia, Versalien, Monospace,
   Haarlinien. Konsequent hergeleitet — und kalt wie ein Formular von
   1974. Strenge ist keine Gestaltung, sie ist nur die andere Art,
   sich zu drücken.

   Was hier gilt: freundlich, hell, farbig, rund. Und trotzdem nicht
   beliebig — der Unterschied liegt in vier Dingen, die Mühe machen:

     1. EINE ECHTE PALETTE, nicht ein Akzent — und sie steht nicht
        hier, sondern in theme.css: Cream, Forest Green und Sage als
        Marke, Erfolgsgrün, Coral, Rot, Apricot, Blau und Violett mit
        je einer Aufgabe, Pink nur für den Begleiter. Diese Datei
        benutzt ausschließlich die Rollen von dort (test/contrast.js
        prüft, dass hier kein Farbwert steht).
     2. GEZEICHNETE MARKEN. Fünf Strichzeichnungen in getönten Kreisen,
        jede in ihrer Farbe. Keine Emoji, keine Glyphen.
     3. ECHTE HIERARCHIE. Große, freundliche Zahlen gegen ruhige
        Beschriftungen. Nicht alles gleich groß, nicht alles versal.
     4. EINE TIEFENSTUFE. Genau ein Schatten, überall derselbe. Karten
        liegen auf dem Grund, nicht Karten auf Karten auf Karten.

     5. EINE EIGENE SCHRIFT. Manrope, mitgeliefert statt geladen.
        Die Systemschrift war die vernünftige Wahl und zugleich der
        Grund, warum die App auf jedem Gerät wie das Betriebssystem
        aussah und auf keinem wie sie selbst.

   Weiche Kanten, Bewegung mit ein wenig Nachschwingen, Ziffern in
   Tabellenbreite (damit Beträge untereinander stehen, ohne dass man
   sie liest) — aber in der Textschrift, nicht in Schreibmaschine.
   ================================================================ */

/* ---------------- Schrift ----------------
   MANROPE, und zwar aus dem eigenen Verzeichnis.

   Warum überhaupt eine eigene: die Systemschrift ist auf jedem Gerät
   eine andere. Dieselbe Zeile stand auf dem iPhone in SF Pro, auf
   Android in Roboto und auf dem Rechner in Segoe — mit
   unterschiedlicher Laufweite, Zahlenbreite und x-Höhe. Alles, was
   hier an Hierarchie eingestellt ist, galt damit immer nur für ein
   Gerät. Manrope ist auf allen dasselbe.

   Warum ausgerechnet Manrope: halb-grotesk, offene Punzen, sehr
   ruhige Ziffern — und eine hohe x-Höhe, die kleine Beschriftungen
   auf einem Handy lesbar hält. Sie wirkt freundlich, ohne rund und
   verspielt zu sein. Das trifft genau das, was diese App sein will.

   Warum ausgeliefert und nicht von Google Fonts geladen: eine
   eingebundene Schrift ist eine Anfrage an einen Dritten, bei jedem
   Start, mit IP und Browserkennung. Diese App verspricht, dass die
   Daten auf dem Gerät bleiben. 40 KB im eigenen Verzeichnis kosten
   weniger als eine Ausnahme von diesem Satz — und die App
   funktioniert damit auch ohne Netz unverändert.

   `font-display: swap`: bis die Datei da ist, steht der Text in der
   Systemschrift. Lieber ein kurzer Sprung als eine leere Seite.

   Nicht jedes Zeichen steckt drin — „→", „✓" und „↻" fehlen dem
   Schnitt. Der Browser holt sie sich Zeichen für Zeichen aus der
   Systemschrift; das sind Symbole, keine Wörter, und es fällt nicht
   auf. Ein eigener Schnitt nur dafür wäre teurer als der Gewinn. */
@font-face{
  font-family:"Manrope";
  font-style:normal;
  font-weight:200 800;          /* variabel — ein Datei für alle Schnitte */
  font-display:swap;
  src:url("fonts/manrope-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
                U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,
                U+2212,U+2215,U+FEFF,U+FFFD;
}
/* Der zweite Bereich wird nur geladen, wenn wirklich ein Zeichen
   daraus vorkommt — für Deutsch also nie. Er liegt dabei, damit ein
   polnischer oder tschechischer Produktname nicht plötzlich in einer
   anderen Schrift steht. */
@font-face{
  font-family:"Manrope";
  font-style:normal;
  font-weight:200 800;
  font-display:swap;
  src:url("fonts/manrope-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,
                U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,
                U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

:root{
  /* FARBEN stehen nicht hier, sondern in theme.css — der einzigen
     Stelle mit Farbwerten (Rollen, heller und dunkler Modus, Regeln).
     Hier bleiben Maße, Radien und Bewegung. */

  /* KANTEN: gerundet, in drei abgestuften Radien.
     ------------------------------------------------------------
     Zwischenstand: eine Weile standen diese drei Werte auf 0. Der
     Gedanke dahinter war, dass eine Fläche, die etwas MISST — ein
     Balken, ein Feld, eine Zeile —, sich eckig eher als Messwert
     liest als abgerundet. Im Ganzen gesehen hat das die App härter
     gemacht, als sie ist: sie schätzt, sie mahnt nicht.

     Die Regel selbst ist geblieben, nur die Werte sind zurück. Sie
     ist keine Geschmacksfrage, sondern eine Frage der Natur des
     Elements — nur dass „eckig" jetzt „sanft gerundet" heißt:

       --r-lg  große FLÄCHEN, die etwas umschließen — Karten,
               Gruppen, Blätter, Kacheln.
       --r-md  bedienbare Flächen — Knöpfe, Eingabefelder,
               Segmente, Balken.
       --r-sm  kleine Flächen innerhalb einer anderen — Chips im
               Toast, Bänder, Fortschrittsspuren.
       99px    bleibt, was ein PUNKT oder ein KREIS ist — Abhak-
               Kreise, der Pfeilkreis, Streak-Punkte, der Schalter,
               das (i), die Marken („Beispieldaten", „!", „2").
               Diese Werte stehen direkt an ihrer Regel, nicht hier:
               ein Kreis ist keine Abstufung, er ist ein Kreis.

     Warum drei und nicht einer: geschachtelte Flächen mit demselben
     Radius sehen falsch aus. Der innere Radius muss kleiner sein als
     der äußere, sonst wirkt der Abstand dazwischen ungleichmäßig.

     Der Weg zurück bleibt ein Zahlenwert und keine Archäologie. */
  --r-lg:20px;
  --r-md:14px;
  --r-sm:10px;

  /* Vier Schriftstufen reichen für die persönlichen Rückmeldungen.
     Vorher hatte fast jedes Detail dort eine eigene Größe; auf dem
     kleinen Bildschirm wirkte das unruhiger als die Information ist. */
  --type-meta:.75rem;
  --type-body:.875rem;
  --type-title:1rem;
  --type-display:2.5rem;

  /* Weichzeichner der Inhaltsflächen. Der Produktrahmen weiter
     unten setzt ihn auf 0 — die Flächen sind seitdem deckend. */
  --glass-blur:22px;
  /* Die Höhe der Küche des Begleiters — auf allen Reitern dieselbe. */
  --stage-h:106px;
  /* Die linke Kante der Küche. Steht hier und nicht zweimal im Code,
     weil die Bestätigung (.toast) daran ausgerichtet ist: sie ist die
     Sprechblase des Begleiters und muss über ihm stehen, nicht
     irgendwo. Der Rechner-Zweig setzt beide gemeinsam um. */
  --companion-left:var(--pad);

  --safe-top:env(safe-area-inset-top,0px);
  --safe-bottom:env(safe-area-inset-bottom,0px);
  --nav-h:56px;
  /* Wo unten die Ebene über der Navigation beginnt: Küche des
     Begleiters, Bestätigungen, Wagenleiste, Feier und der Leerraum
     unter dem Inhalt richten sich alle danach. EINE Größe statt sechs
     gleichlautender Rechnungen — in der iOS-Hülle (unten) zeigt sie
     auf die Oberkante der nativen Glass-Leiste. */
  --dock-bottom:calc(var(--nav-h) + var(--safe-bottom));
  --text-scale:1;
  --pad:16px;
  /* Mit ein wenig Nachschwingen — das macht den Unterschied zwischen
     „reagiert" und „fühlt sich lebendig an". */
  --ease:cubic-bezier(.32,.72,0,1);
  --spring:cubic-bezier(.34,1.56,.64,1);
}

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;padding:0;min-height:100%}
/* Der Faktor sitzt auf der Wurzel, alle Schriftgrößen stehen in rem.
   Sonst hätte die Einstellung „Schriftgröße" fast keine Wirkung —
   Abstände und Rahmen bleiben in Pixeln, der Text soll wachsen, nicht
   das Gerüst. */
html{font-size:calc(16.5px * var(--text-scale))}
body{
  background:var(--bg-primary);
  color:var(--text-primary);
  font-family:"Manrope",-apple-system,BlinkMacSystemFont,"SF Pro Text","Segoe UI",system-ui,sans-serif;
  /* Zwei Korrekturen gegenüber der Systemschrift, beide gemessen und
     nicht geschätzt:

     LAUFWEITE auf 0 statt -.01em. Alle Werte im Stil waren auf SF Pro
     eingestellt, die von Haus aus weiter läuft; unverändert
     übernommen klebten die Buchstaben aneinander. Sämtliche negativen
     Werte im Stil sind entsprechend halbiert.

     WORTABSTAND leicht positiv. Manropes Leerzeichen ist schmaler als
     das der Systemschriften, und Laufweite wirkt auch darauf — in
     „2 Sachen tauschen“ stand die Zahl fast am Wort. Hier wird nur
     der Abstand ZWISCHEN Wörtern zurückgegeben, nicht der zwischen
     Buchstaben. */
  font-size:1rem;line-height:1.45;letter-spacing:0;word-spacing:.055em;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overscroll-behavior-y:none;
}
h1,h2,h3{margin:0;font-weight:700;letter-spacing:-.0125em}
p{margin:0}
button{font-family:inherit;font-size:inherit;cursor:pointer;border:none;background:none;color:inherit;letter-spacing:inherit}
input,select,textarea{font-family:inherit;font-size:max(16px,0.97rem);color:inherit}
:focus-visible{outline:2.5px solid var(--focus-ring);outline-offset:2px}
.hide{display:none !important}

/* Beträge untereinander sollen sich vergleichen lassen, ohne dass man
   sie liest. Dafür Tabellenziffern — aber in der Systemschrift, nicht
   in Schreibmaschine. */
.num,.mono,.rowValue,.price,.tile .v,.totals .big,.strip .big,.sum,.bVal,.rvItem .v,.stepVal,.flag,.sp{
  font-variant-numeric:tabular-nums;font-feature-settings:"tnum"
}

/* ---------------- Gerüst ---------------- */
.shell{min-height:100vh;display:flex;flex-direction:column}
/* .col füllte die 100vh von .shell bislang nicht wirklich aus --
   flex:1 auf main (weiter unten) griff mangels eines flex-gebenden
   Vorfahren ins Leere, und ein kurzer Leerzustand (Willkommen, leere
   Ansicht) blieb oben kleben, mit einer nicht anders erklärbaren
   grauen Fläche bis zur unteren Leiste darunter. */
.col{display:flex;flex-direction:column;flex:1;min-width:0}

.appbar{
  position:sticky;top:0;z-index:40;
  padding:calc(var(--safe-top) + 7px) var(--pad) 8px;
  background:var(--bg-material);
  -webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px);
  border-bottom:1px solid transparent;
  transition:border-color .2s linear;
}
.appbar.scrolled{border-bottom-color:var(--border-subtle)}
.barRow{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:38px}
.barTitle{
  font-size:1.03rem;font-weight:650;letter-spacing:-.01em;
  opacity:0;transform:translateY(6px);
  transition:opacity .18s var(--ease),transform .18s var(--ease);
}
.appbar.scrolled .barTitle{opacity:1;transform:none}
/* Der kleine Titel erscheint NUR, wenn der große weggescrollt ist --
   auch dann, wenn rechts ein Knopf steht. Vorher stand auf jedem
   Reiter zweimal dasselbe Wort untereinander („Bestand" über
   „Bestand"), 40 px auseinander; das sah nach Versehen aus. Der Knopf
   rechts trägt eine Beschriftung („Nach Gängen", „Erfassen") und
   erklärt sich damit selbst -- genau so macht es auch das System. */
.barActions{display:flex;gap:9px;margin-left:auto}
.barBtn{
  color:var(--text-brand);font-size:0.94rem;font-weight:600;
  padding:7px 2px;min-height:38px;white-space:nowrap;
}
.barBtn:active{opacity:.45}
.barBtn.filled{
  background:var(--action-primary);color:var(--text-on-brand);border-radius:var(--r-md);
  padding:9px 17px;box-shadow:var(--shadow-lift);
  transition:transform .16s var(--spring);
}
.barBtn.filled:active{transform:scale(.94)}

.largeTitle{padding:2px var(--pad) 0}

.largeTitle.mitLevel{
  display:grid;
  grid-template-columns:minmax(0,1fr) clamp(132px,38vw,166px);
  align-items:start;
  column-gap:clamp(10px,3vw,18px);
}
.largeTitle.mitLevel>.largeTitleText{min-width:0}
.largeTitle.mitLevel>.expHeader{width:100%;margin-top:4px}
.largeTitle.mitLevel h1{font-size:1.7rem}

/* Ultra-thin EXP: keine Card, kein Kreis, kein Schatten. */
.expHeader{
  display:block;
  position:relative;
  width:100%;
  min-width:0;
  min-height:38px;
  margin:0;
  padding:2px 0 1px;
  border:0;
  border-radius:0;
  background:none;
  box-shadow:none;
  color:var(--text-primary);
  text-align:left;
  overflow:visible;
  transform-origin:center;
  -webkit-tap-highlight-color:transparent;
}
.expHeader::after{
  content:"";
  position:absolute;
  left:0;right:0;top:50%;
  height:44px;
  transform:translateY(-50%);
}
.expHeaderTop{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:12px;
  line-height:1;
}
.expHeaderLevel{
  font-size:.64rem;
  font-weight:760;
  letter-spacing:.015em;
  color:var(--mascot-pink-text);
  white-space:nowrap;
}
.expHeaderValue{
  font-size:.65rem;
  font-weight:740;
  color:var(--text-brand);
  white-space:nowrap;
  font-variant-numeric:tabular-nums;
}
.expHeaderTrack{
  display:block;
  position:relative;
  width:100%;
  height:1.5px;
  margin-top:7px;
  overflow:hidden;
  border-radius:99px;
  background:var(--divider);
}
.expHeaderTrack i{
  display:block;
  height:100%;
  border-radius:inherit;
  background:var(--mascot-pink);
  transition:width .45s var(--ease);
}
.expHeaderNext{
  display:block;
  margin-top:4px;
  font-size:.56rem;
  font-weight:520;
  line-height:1.15;
  color:var(--text-secondary);
  text-align:right;
  white-space:nowrap;
  font-variant-numeric:tabular-nums;
}
.expHeader:active{opacity:.58}

.expHeaderDock{
  display:none;
  flex:1 1 100%;
  min-width:0;
  width:100%;
}
body[data-view="start"] .appbar.scrolled .barTitle,
body[data-view="start"] .appbar.scrolled .barActions{
  display:none;
}
body[data-view="start"] .appbar.scrolled .expHeaderDock{
  display:block;
  width:100%;
}
body[data-view="start"] .appbar.scrolled .barRow{
  justify-content:stretch;
  gap:0;
}
body[data-view="start"] .appbar.scrolled .expHeader{
  width:100%;
  min-height:38px;
  padding-top:1px;
}
body[data-view="start"] .appbar.scrolled .expHeaderLevel,
body[data-view="start"] .appbar.scrolled .expHeaderValue{
  font-size:.66rem;
}
body[data-view="start"] .appbar.scrolled .expHeaderNext{
  font-size:.56rem;
}

/* Gruß verschwindet weich; seine Höhe bleibt stehen -> kein Layoutsprung. */
.largeTitleText{
  transition:opacity .18s var(--ease),transform .18s var(--ease);
}
.appbar.scrolled + .largeTitle.mitLevel .largeTitleText{
  opacity:0;
  transform:translateY(-5px);
  pointer-events:none;
}

.calendarStripSlot{padding:8px var(--pad) 0;width:100%}
.calendarStripSlot[hidden]{display:none}
/* Slot, Platzhalter und Begleiter sind drei Geschwister. Sobald die
   Leiste sichtbar ist, darf sich ihr unterer Abstand nicht mit dem
   normalen oberen Kartenabstand des Begleiters addieren. */
.largeTitleText{flex:1;min-width:0}
.largeTitle h1{font-size:1.94rem;line-height:1.14;letter-spacing:-.016em}
.largeTitle .sub{
  font-size:0.85rem;color:var(--text-secondary);margin-top:5px;padding-bottom:2px;
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;letter-spacing:-.0025em;
}

/* ================================================================
   Das Wesen
   ================================================================
   Ein Begleiter statt ein Symbol -- deshalb an einer festen
   Bildschirmstelle (position:fixed, siehe .mascotFab), die auch beim
   Scrollen nicht wandert, und deshalb mit einer Stimmung statt nur
   einer Pose. Die Stimmung kommt aus genau den Signalen, die die App
   ohnehin schon hat (Kühlkette, Verderb heute, Streak) -- siehe
   mascotMood() in views.js. Kein neuer Zustand, nur eine neue Lesart
   des alten.

   Lebt bewusst außerhalb von .shell/.largeTitle (siehe index.html) --
   ein fest positioniertes Element bliebe sonst von einem Vorfahren
   mit eigenem Stacking-Context abhängig. App.renderBar() aktualisiert
   nur sein Aussehen (Stimmung, Beschriftung), nicht seinen Ort im DOM.

   Antippen öffnet keine neue Fensterebene, sondern .mascotBubble
   daneben -- eine leicht durchsichtige Sprechblase, die den Rest der
   Seite nicht blockiert. Ihr Text kommt aus mascotMessage() in
   views.js: regelbasiert, je Reiter, aus vorhandenen ctx-Daten.

   Absichtlich flache SVG-Form statt echtem 3D: dieselbe Technik, mit
   der auch Maskottchen wie das von Duolingo im Web laufen. Die Form
   selbst ist Platzhalter (siehe Kommentar bei MASCOT_BODY_PATH in
   views.js) -- was hier bleibt, auch wenn sie ersetzt wird, ist die
   Bewegung, die Stimmungsfarben und die Antippbarkeit. */
.mascotFab{
  /* Knapp unter der Kopfleiste statt darin: die Leiste trägt rechts
     schon eigene Knöpfe („Nach Gängen“, „Erfassen“) -- ein Stück
     tiefer kollidiert das Wesen nicht mit ihnen und bleibt trotzdem
     an derselben Bildschirmstelle, egal was darunter scrollt. */
  position:relative;z-index:1;
  padding:0;border:none;background:none;line-height:0;
  /* Der Animationsdirektor liefert fertige Zwischenbilder. Eine CSS-
     Transition würde jedes Bild erneut interpolieren und Mimik verschmieren. */
  transition:none;
}
/* ================================================================
   Die Figur: neun Posen übereinander
   ================================================================
   Ein Bilderbogen (3×3), neunmal als Hintergrund angezeigt, jedes Mal
   mit anderem Ausschnitt. Sichtbar sind meist nur ein oder zwei davon
   -- die Fachschicht (mascotAnimation.js) liefert je Bild neun
   Deckkraft-Werte, und das Überblenden zwischen zwei Posen ist genau
   die Summe dieser Werte.

   WARUM NICHT NEUN EINZELDATEIEN: neun Anfragen statt einer, neun
   Dekodierungen statt einer, und beim Posenwechsel ein Aufblitzen,
   solange das nächste Bild noch nicht da ist.

   `transform-origin:bottom` ist nicht kosmetisch: die Figur steht auf
   dem Boden. Dreht oder staucht sie um ihre Mitte, hebt sie beim
   Nicken ab. */
/* Bewusst OHNE `position`: die Figur sitzt in zwei verschiedenen
   Hosts, und die bringen ihre eigene Positionierung mit (.mascotFab
   ist fixiert). Eine Angabe hier
   überschrieb `position:fixed` des Wesens-Knopfes -- es rutschte
   dann aus dem Kopfbereich heraus und war nicht mehr zu sehen. */
.mFig{
  display:inline-block;
  width:var(--mSize);height:var(--mSize);
  transform-origin:bottom center;
  will-change:transform;
  /* Eigener Mischraum: die Posen addieren sich untereinander
     (plus-lighter), sollen aber nicht mit der Seite dahinter
     verrechnet werden. */
  isolation:isolate;
}
/* Damit die Posen darin ihren Bezugsrahmen haben. */
.mPose{
  position:absolute;inset:0;
  background-image:url("mascot/mascot-base.webp");
  background-size:300% 300%;
  background-repeat:no-repeat;
  opacity:0;
  /* Aufhellung und Sättigung sitzen an der Pose, nicht an der ganzen
     Figur -- der Farbstich darüber darf davon NICHT erfasst werden. */
  filter:brightness(var(--mBody,1)) saturate(var(--mSat,1));
  /* Zwei überblendende Posen addieren sich, statt sich gegenseitig
     abzudunkeln. Ohne das entsteht bei jedem Posenwechsel ein
     dunkler Saum an den Fellrändern. */
  mix-blend-mode:plus-lighter;
  will-change:opacity;
}
/* Karottenwurf (carrotToss): Pose 2 ohne Karotte und die freie
   Karotte, beide zur Laufzeit aus dem Bogen gelöst (Mascot.loeseKarotte).
   Die Pose mischt sich wie die anderen neun additiv; die Karotte liegt
   NORMAL darüber — additiv würde sie über dem Fell doppelt hell. Sie
   bekommt dieselbe Aufhellung/Sättigung, damit sie im gedämpften
   Zustand nicht leuchtet. */
/* Eigene Klasse, nicht .mPose: die neun Posen bleiben genau neun. */
.mPoseToss{
  position:absolute;inset:0;opacity:0;visibility:hidden;
  background-size:100% 100%;background-position:0 0;background-repeat:no-repeat;
  filter:brightness(var(--mBody,1)) saturate(var(--mSat,1));
  mix-blend-mode:plus-lighter;
  will-change:opacity;
}
.mCarrot{
  position:absolute;inset:0;pointer-events:none;visibility:hidden;
  background-size:100% 100%;background-repeat:no-repeat;
  filter:brightness(var(--mBody,1)) saturate(var(--mSat,1));
  will-change:transform,opacity;
}
/* Das Licht HINTER der Figur: eine weiche, breite Ellipse, leicht
   nach unten versetzt -- die Vorlage setzt sie dorthin, wo die Figur
   auf dem Boden aufsitzt. */
.mGlow{
  position:absolute;
  left:12.5%;top:24%;width:75%;height:66%;
  pointer-events:none;
  border-radius:50%;
  filter:blur(calc(var(--mSize) * 0.11));
}
/* Farbstich und Innenlicht AUF der Figur, entlang ihrer Silhouette
   ausgeschnitten. Das ist der Unterschied zwischen „dunkel" und
   „gedämpft": ohne diese Schicht wäre der Zustand nur grau statt
   blau, und die acht Dauerzustände wären nicht auseinanderzuhalten. */
.mLight{
  position:absolute;inset:0;
  pointer-events:none;
  -webkit-mask-image:url("mascot/mascot-base.webp");
  mask-image:url("mascot/mascot-base.webp");
  -webkit-mask-size:300% 300%;
  mask-size:300% 300%;
  -webkit-mask-repeat:no-repeat;
  mask-repeat:no-repeat;
}

/* Text und Weiter-Knopf in der Sprechblase. Der Knopf ist immer
   erreichbar, auch wenn sich die Karte von selbst schließen würde --
   sonst hätte, wer langsamer liest, keinen Ausgang. */
.mText{margin:0}
.mGo{
  display:block;margin:10px 0 0 auto;padding:5px 13px;
  border:none;border-radius:999px;
  background:var(--action-primary);color:var(--text-on-brand);
  font:inherit;font-size:0.8rem;font-weight:600;
}
.mGo:active{transform:scale(.94)}

/* Konfetti. Menge und Anlass stehen in der Ereignismatrix, nicht hier
   -- diese Regeln beschreiben nur den Flug. */
.mConfetti{position:fixed;inset:0;z-index:60;pointer-events:none;overflow:hidden}
.mConfetti i{
  position:absolute;top:-6%;
  width:8px;height:12px;
  animation:mFall 2.2s cubic-bezier(.3,.6,.5,1) forwards;
}
@keyframes mFall{
  0%{opacity:0;transform:translateY(0) rotate(0)}
  10%{opacity:1}
  100%{opacity:0;transform:translateY(108vh) rotate(540deg)}
}
@media (prefers-reduced-motion:reduce){
  .mConfetti{display:none}
}
/* Punkt statt Text: „seit dem letzten Antippen ist ein neues
   Alarmsignal aufgetaucht" (Kühlkette oder Verderb heute, siehe
   mascotAlarmSignature() in views.js). Der Rand in der Seitenfarbe
   schneidet den Punkt optisch aus dem Wesen heraus, statt nur davor
   zu liegen. Wer nicht sieht, bekommt dieselbe Information über das
   „Neu: "-Präfix im aria-label -- ein Punkt allein wäre für
   Vorleseprogramme stumm. */
.mascotFab.hasNew::after{
  content:"";position:absolute;top:2px;right:2px;
  width:11px;height:11px;border-radius:50%;
  background:var(--critical);border:2px solid var(--bg-primary);
}

/* Dieselbe Sprechblasen-Optik läuft an zwei Stellen: fest am Wesen im
   Kopfbereich (.mascotBubble) und, seit die Feier ebenfalls ein
   antippbares Wesen hat, in der Meilenstein-Karte (.partyMascotBubble).
   .speechBubble trägt alles Gemeinsame, jede Variante nur noch ihre
   eigene Position und die Richtung der Sprechblasen-Spitze. */
.speechBubble{
  z-index:44;
  max-width:min(76vw,290px);
  padding:12px 14px;
  background:var(--bg-material);
  -webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px);
  border:1px solid var(--border-subtle);
  box-shadow:var(--shadow-lift);
  font-size:0.86rem;line-height:1.42;color:var(--text-primary);
  animation:bubbleIn .22s var(--spring);
}
.speechBubble::before{
  content:"";position:absolute;top:-7px;
  width:11px;height:11px;background:var(--bg-material);
  border-left:1px solid var(--border-subtle);border-top:1px solid var(--border-subtle);
  transform:rotate(45deg);
}
.mascotBubble{position:relative;max-width:none;flex:1}
.mascotBubble::before{right:20px}
/* Eine Hilfe des Begleiters: Titel, Begründung, Weg dorthin. */
.mGuideTitle{font-weight:650}
.mGuideText{font-size:.82rem;color:var(--text-secondary);margin:5px 0 0;line-height:1.45}

/* Innerhalb der Feier-Karte (.partyCard ist position:relative) statt
   fest im Bildschirm -- die Karte selbst sitzt schon mittig, die
   Blase muss ihr nur folgen, nicht dem Viewport. Zentriert über
   `left:0;right:0;margin-inline:auto` statt `transform:translateX()`,
   weil dieselbe Eigenschaft schon die Einblend-Animation trägt --
   zwei Transforms auf einer Regel überschreiben sich sonst. */
@keyframes bubbleIn{from{opacity:0;transform:translateY(-6px) scale(.96)}to{opacity:1;transform:none}}

.mascot{
  /* Größe kommt vom width/height-Attribut (mascotSvg()-Parameter),
     absichtlich nicht hier fest verdrahtet -- sonst überschreibt
     diese Regel jede andere Größe, in der das Wesen einmal auftaucht. */
  display:block;
  animation:mascotBob 3.2s var(--ease) infinite;
}
.mascotBlink{
  animation:mascotBlink 4.6s ease-in-out infinite;
  transform-box:fill-box;transform-origin:center;
}
/* Die Farben der gezeichneten SVG-Figur (Fell, Wangen, Augen, vier
   Stimmungen) sind entfallen: die Figur wird seit dem Bilderbogen
   nicht mehr erzeugt, ihre Farben kommen aus dem Bild selbst. */
.mascot.alarm{
  animation:mascotBob 3.2s var(--ease) infinite,mascotShiver 2.6s ease-in-out infinite;
}

@keyframes mascotBob{
  0%,100%{transform:translateY(0) rotate(0deg)}
  50%{transform:translateY(-3px) rotate(-1.5deg)}
}
@keyframes mascotShiver{
  0%,100%{transform:translateX(0)}
  25%{transform:translateX(-.6px) rotate(-1deg)}
  75%{transform:translateX(.6px) rotate(1deg)}
}
@keyframes mascotBlink{0%,92%,100%{transform:scaleY(1)}96%{transform:scaleY(.12)}}

@media (prefers-reduced-motion: reduce){
  .mascot,.mascot.alarm,.mascotBlink{animation:none}
}

/* Der untere Abstand hält seit dem angedockten Begleiter dessen
   Platz frei: er sitzt beim Scrollen fest über der Leiste, und die
   letzte Zeile einer Liste soll nicht unter ihm enden. Konstant,
   nicht nur beim Andocken -- eine Polsterung, die sich beim
   Scrollen ändert, verschiebt die Seite unter dem Finger. */
main{flex:1;padding:4px var(--pad) calc(var(--dock-bottom) + var(--stage-h) + 22px);width:100%}
/* Ist der Begleiter abgeschaltet, gibt es auch keine Küche, der man
   Platz freihalten müsste. */
body:has(#companion[hidden]) main{padding-bottom:calc(var(--dock-bottom) + 22px)}
/* Ein Leerzustand (Willkommen, "noch keine Angebote" ...) ist immer
   genau eine einzelne .card als einziges Kind von main -- kein
   anderer Bildschirm sieht so aus, uiGroup()-Abschnitte tragen eine
   andere Klasse. Statt oben zu kleben und darunter eine unerklärte
   graue Fläche bis zur Leiste offenzulassen, sitzt die Karte dann in
   der Mitte des verfügbaren Raums. align-items bleibt beim
   Vorgabewert (stretch), damit die Karte ihre volle Breite behält --
   nur die Höhe wird zentriert. */
main:has(> .card:only-child){display:flex;flex-direction:column;justify-content:center}

/* ---------------- Tableiste ---------------- */
.nav{
  position:fixed;left:0;right:0;bottom:0;z-index:50;display:flex;
  background:var(--nav-bg);
  -webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px);
  border-top:1px solid var(--border-subtle);
  padding-bottom:var(--safe-bottom);
}
.nav button{
  flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  height:var(--nav-h);font-size:min(0.6rem,12px);font-weight:600;letter-spacing:-.0025em;
  color:var(--nav-inactive);transition:color .16s linear;
}
.nav button svg{
  width:25px;height:25px;stroke:currentColor;fill:none;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;
  transition:transform .3s var(--spring);
}
.nav button[aria-current="page"]{color:var(--nav-active)}
.nav button[aria-current="page"] svg{stroke-width:2.1;transform:translateY(-1px) scale(1.06)}
/* Die Bildsymbole bringen ihre Farben mit — sie werden nicht eingefärbt
   wie die Strichzeichnungen (die bleiben als Ersatz, siehe imageIcon()).
   Aktiv heißt deshalb nur: eine Spur größer, volle Deckkraft und die
   ruhige Fläche dahinter (weiter unten). Inaktiv treten sie etwas
   zurück, damit die Leiste nicht bunter wirkt als der Inhalt.
   Die Bilder tragen im Feld rund 27 % Rand (tools/iconAssets.js) —
   30 px Kästchen ergeben rund 22 px sichtbares Symbol; die Leiste ist
   bewusst niedrig gehalten, damit Inhalt und Küche Platz haben. */
.nav button .navImageIcon{
  width:30px;height:30px;opacity:.8;
  transition:transform .3s var(--spring),opacity .16s linear;
}
.nav button[aria-current="page"] .navImageIcon{opacity:1;transform:scale(1.05)}
.nav button:active .navImageIcon{transform:scale(.88)}
.nav button:active svg{transform:scale(.88)}

/* ---------------- Gruppe: ruhige Überschrift, weiße Karte ---------
   Der Titel steht in normaler Schreibweise. Gesperrte Versalien über
   jedem Block waren der Hauptgrund, warum die Fassung davor wie ein
   Formular aussah.                                                  */
.group{margin:22px 0 0}
.group:first-child{margin-top:14px}
.groupTitle{
  /* Oben ausgerichtet: bei einer Überschrift über zwei Zeilen stand das
     (i) sonst mittig am rechten Rand und sah aus, als gehöre es zu
     nichts. */
  display:flex;align-items:flex-start;gap:7px;
  font-size:0.82rem;font-weight:600;color:var(--text-secondary);
  padding:0 4px 8px;letter-spacing:-.0025em;
}
/* Die Gruppe ist die Glasscheibe, nicht die einzelne Zeile: der
   Weichzeichner liegt EINMAL auf dem Behälter statt auf jeder Zeile
   darin. Deshalb sind die Zeilen darin durchsichtig (siehe unten) --
   sonst läge über dem Glas wieder eine deckende Fläche und der
   ganze Aufwand wäre unsichtbar. */
.groupBody{
  background:var(--surface-primary);border-radius:var(--r-lg);overflow:hidden;
  -webkit-backdrop-filter:saturate(140%) blur(var(--glass-blur));
  backdrop-filter:saturate(140%) blur(var(--glass-blur));
  box-shadow:var(--shadow-lift);
  position:relative;
}
.groupNote{font-size:0.79rem;color:var(--text-secondary);padding:8px 4px 0;line-height:1.4}

.row{
  display:flex;align-items:center;gap:12px;
  padding:12px 16px;min-height:48px;position:relative;
  background:var(--surface-primary);width:100%;text-align:left;
}
/* In einer Gruppe trägt der Behälter die Fläche (siehe .groupBody).
   Eine deckende Zeile darin würde das Glas wieder zumauern. */
.groupBody .row,.card .row{background:transparent}
.row + .row::before{
  content:"";position:absolute;left:16px;right:0;top:0;height:1px;background:var(--divider);
}

/* Wischen im Bestand: „ist alle" (siehe attachStockSwipe() in
   views.js). Die Zeile liegt über einer Fläche, die beim Ziehen zum
   Vorschein kommt.

   touch-action:pan-y statt none -- die Zeilen stehen in einer langen
   Liste, und `none` würde das senkrechte Scrollen darüber abwürgen.
   Die waagerechte Achse gehört uns, die senkrechte dem Browser. */
.swipeWrap{position:relative;overflow:hidden}
.swipeWrap + .swipeWrap > .row::before,
.inventorySupplyFirst > .row::before{
  content:"";position:absolute;left:16px;right:0;top:0;height:1px;background:var(--divider);
}
.swipeWrap > .row{
  touch-action:pan-y;position:relative;z-index:1;
  transition:transform .2s var(--ease);
}
/* Während des Ziehens ist die Zeile deckend: sie liegt als Blatt über
   der Fläche darunter, sonst schiene das Rot durch die Schrift. In
   Ruhe ist sie durchsichtig, damit das Glas der Gruppe sichtbar
   bleibt (siehe .groupBody .row). */
.swipeWrap.swiping > .row{
  transition:none;background:var(--surface-primary);
  -webkit-user-select:none;user-select:none;
}
/* Die Fläche dahinter erscheint erst beim Ziehen. Dauerhaft sichtbar
   wäre sie ein rotes Band hinter JEDER Zeile -- die Zeilen darüber
   sind durchsichtig, das Rot schlüge überall durch. */
.swipeBack{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:flex-end;
  padding-right:20px;background:var(--critical-soft);
  opacity:0;transition:opacity .12s linear;
}
.swipeWrap.swiping .swipeBack{opacity:1}
.swipeLabel{
  font-size:0.88rem;font-weight:650;color:var(--critical-text);letter-spacing:-.005em;
  opacity:.55;transition:opacity .14s linear,transform .18s var(--ease);
}
/* Weit genug gezogen: das Loslassen löst aus. Ohne diese Rückmeldung
   ist die Auslöseschwelle unsichtbar und die Geste ein Glücksspiel. */
.swipeWrap.armed .swipeBack{background:var(--critical)}
.swipeWrap.armed .swipeLabel{color:var(--text-on-critical);opacity:1;transform:scale(1.04)}
button.row,label.row{transition:background .14s linear}
button.row:active,label.row:active{background:var(--fill-subtle)}

/* Gangreihenfolge: Griff zum Ziehen (siehe attachAisleDrag() in
   views.js). touch-action:none verhindert, dass das Ziehen auf einem
   Telefon stattdessen die Seite scrollt. */
.aisleHandle{
  flex:0 0 auto;width:26px;height:26px;margin-left:-6px;
  display:flex;align-items:center;justify-content:center;
  color:var(--text-muted);touch-action:none;cursor:grab;
  -webkit-user-select:none;user-select:none;
}
/* Während des Ziehens darf der Zeiger nicht aus Versehen Text auf der
   ganzen Seite markieren -- ohne das gewann auf dem Desktop (Maus)
   regelmäßig die Textauswahl gegen das Verschieben der Zeile. */
.aisleRow.dragging,.aisleRow.dragging *{-webkit-user-select:none;user-select:none}
.aisleHandle svg{width:20px;height:20px;fill:currentColor}
.aisleRow.dragging{
  position:relative;z-index:3;background:var(--surface-primary);box-shadow:var(--shadow-lift);cursor:grabbing;
}
.aisleRow.dragging .aisleHandle{cursor:grabbing;color:var(--text-primary)}
.aisleRow:not(.dragging){transition:transform .16s var(--ease)}
.row .rowMain{flex:1;min-width:0}
.row .rowTitle{font-size:1rem;letter-spacing:-.0075em}
.row .rowSub{font-size:0.8rem;color:var(--text-secondary);margin-top:1px;line-height:1.35}
.row .rowValue{font-size:1rem;color:var(--text-secondary);flex:0 0 auto;text-align:right}
.row .rowValue small{display:block;font-size:0.7rem;color:var(--text-muted);text-align:right}
.row .chev{
  width:8px;height:8px;flex:0 0 auto;
  border-right:2px solid var(--text-muted);border-top:2px solid var(--text-muted);
  transform:rotate(45deg);
}
.row.stacked{flex-direction:column;align-items:stretch;gap:11px;padding:14px 16px}
.row.stacked .segmented{width:100%}

.card{
  background:var(--surface-primary);border-radius:var(--r-lg);padding:16px;box-shadow:var(--shadow-lift);
  -webkit-backdrop-filter:saturate(140%) blur(var(--glass-blur));
  backdrop-filter:saturate(140%) blur(var(--glass-blur));
  position:relative;
}
.card + .card{margin-top:12px}
.card h2{font-size:1.15rem}
.card h3{font-size:0.94rem;margin-bottom:6px}
.sub{font-size:0.85rem;color:var(--text-secondary);margin:4px 0 14px;line-height:1.42}

/* ---------------- Aufgehen ----------------
   Eine einzige Bewegung für alles, was AUFGEHT: ein
   Segmentwechsel, ein angetippter Tag im Kalender, nachgeladene
   Zeilen, der Inhalt eines aufgeklappten `details`.

   WARUM NUR EINE. Vier verschiedene Öffnen-Animationen in einer App
   sind vier verschiedene Aussagen über dieselbe Sache. Eine, überall
   gleich, macht die Bewegung zur Sprache statt zur Verzierung.

   WARUM SO KURZ (unter einer drittel Sekunde). Alles darüber wird
   beim zehnten Mal zur Wartezeit. Bewegung darf man beim ersten Mal
   bemerken und danach nie wieder.

   Abgeschaltet wird das nicht hier, sondern zentral über
   prefers-reduced-motion ganz am Ende der Datei -- weniger Bewegung
   heißt dort: keine. */
@keyframes oeffnen{
  from{opacity:0;transform:translateY(7px)}
  to{opacity:1;transform:none}
}
.oeffnet{animation:oeffnen .3s var(--ease) both}
/* Nach einem Segmentwechsel laufen die Blöcke der Seite gestaffelt
   ein. Die Staffelung endet nach vier Schritten: was danach kommt,
   steht ohnehin unter dem Falz, und eine Treppe aus zwölf Stufen
   wäre eine Ladeanimation. */
main.oeffnet > *{animation:oeffnen .32s var(--ease) both}
main.oeffnet > *:nth-child(2){animation-delay:.05s}
main.oeffnet > *:nth-child(3){animation-delay:.1s}
main.oeffnet > *:nth-child(n+4){animation-delay:.14s}
/* Aufgeklapptes `details`: nur der Inhalt bewegt sich, die
   Zusammenfassung bleibt stehen -- sie war ja schon da. */
details[open] > *:not(summary){animation:oeffnen .26s var(--ease) both}

/* ---------------- Kalender ---------------- */
.kIntro{margin:0 2px 15px}
.kIntro p{margin:0;color:var(--text-secondary);font-size:.82rem;line-height:1.45}
.kMonat{display:flex;align-items:center;gap:8px;margin:0 0 8px}
.kTitel{
  flex:1;text-align:center;font-size:1.18rem;font-weight:760;letter-spacing:-.025em;color:var(--text-primary);
}
.kNav{
  width:44px;height:44px;flex:0 0 auto;border:1px solid var(--border-subtle);border-radius:99px;
  font-size:1.25rem;line-height:1;color:var(--text-brand);background:var(--surface-primary);
  box-shadow:var(--shadow-control);
  transition:background .14s linear,transform .18s var(--spring);
}
.kNav:active{background:var(--fill-strong);transform:scale(.9)}
.kHeute{display:block;min-height:38px;margin:0 auto 13px;padding:0 14px;border:1px solid var(--border-subtle);border-radius:99px;background:var(--surface-primary);color:var(--text-brand);font:inherit;font-size:.75rem;font-weight:700}
.kHeute:active{background:var(--brand-soft)}
.kAnsicht{margin:0 0 12px;padding:12px;border:1px solid var(--border-subtle);border-radius:var(--r-lg);background:var(--surface-secondary)}
.kAnsichtLabel{display:block;margin:0 2px 8px;color:var(--text-muted);font-size:.66rem;font-weight:780;letter-spacing:.08em;text-transform:uppercase}
.kAnsicht .segmented{background:color-mix(in srgb,var(--surface-primary) 72%,transparent);border-radius:var(--r-md)}
.kAnsicht .segmented button{min-height:42px;border-radius:var(--r-sm);font-weight:700}
.kAnsicht .segmented button[aria-selected="true"]{background:var(--surface-primary);color:var(--text-brand);box-shadow:var(--shadow-control)}
.kAnsichtHinweis{margin:8px 2px 0;color:var(--text-secondary);font-size:.72rem;line-height:1.4}

.kalender{
  background:var(--surface-primary);border:1px solid var(--border-subtle);border-radius:var(--r-lg);padding:12px 9px 9px;
  -webkit-backdrop-filter:saturate(140%) blur(var(--glass-blur));
  backdrop-filter:saturate(140%) blur(var(--glass-blur));
  box-shadow:var(--shadow-lift);margin-bottom:14px;
}
.kWochenkopf{display:grid;grid-template-columns:repeat(7,1fr);gap:3px;margin-bottom:4px}
.kWt{
  text-align:center;font-size:0.68rem;font-weight:650;color:var(--text-muted);
  letter-spacing:.02em;
}
.kGitter{display:grid;grid-template-columns:repeat(7,1fr);gap:3px}
.kLeer{aspect-ratio:1}

/* Eine Zelle ist ein Knopf mit drei Lagen: Datumszahl oben, Balken
   unten, Betrag darüber. `aspect-ratio` statt fester Höhe, damit das
   Gitter auf jedem Gerät quadratisch bleibt. */
.kTag{
  position:relative;aspect-ratio:1;border-radius:var(--r-sm);
  display:flex;flex-direction:column;align-items:center;justify-content:flex-start;
  padding:4px 2px 3px;overflow:hidden;
  background:var(--fill-subtle);color:var(--text-secondary);
  transition:background .16s linear,transform .2s var(--spring);
}
.kTag:active{transform:scale(.93)}
.kTag:focus-visible,.kNav:focus-visible,.kHeute:focus-visible{outline:2px solid var(--text-brand);outline-offset:2px}
.kZahl{font-size:0.74rem;font-weight:650;line-height:1;position:relative;z-index:2;color:var(--text-primary)}
.kTag.zukunft .kZahl{color:var(--text-secondary)}

/* Die Trennlinie der ganzen Ansicht: was war, ist eine FLÄCHE; was
   kommt, ist nur eine KONTUR. Kein blasseres Grau -- blass liest sich
   als „unwichtig", eine offene Kontur als „noch nicht wahr".
   (Schraffur stand hier zuerst und war in einem Monat, der fast ganz
   in der Zukunft liegt, ein einziges Streifenmuster.) */
.kTag.zukunft{
  background:transparent;
  box-shadow:inset 0 0 0 1px var(--border-subtle);
}
.kTag.heute{box-shadow:inset 0 0 0 1.5px var(--brand-primary)}
.kTag.heute .kZahl{color:var(--text-brand);font-weight:750}
.kTag.gewaehlt{background:var(--brand-soft)}
.kTag.gewaehlt .kZahl{color:var(--text-brand)}

.kBalken{
  position:absolute;left:3px;right:3px;bottom:0;height:var(--h,0%);
  background:var(--brand-primary);opacity:.26;
  z-index:1;
  animation:kBalkenAuf .42s var(--ease) both;
}
.kTag.zukunft .kBalken{opacity:.16}
@keyframes kBalkenAuf{from{transform:scaleY(0)}to{transform:scaleY(1)}}
.kBalken{transform-origin:bottom}
.kBetrag{
  position:relative;z-index:2;margin-top:auto;
  font-size:0.6rem;font-weight:650;color:var(--text-primary);line-height:1;
}
.kTag.zukunft .kBetrag{color:var(--text-secondary)}

/* Vorrats-Ebene: Punkte statt Zahlen. „Zwei gehen aus, eines
   verdirbt" ist an drei Punkten schneller gelesen als an „2 · 1". */
.kPunkte{
  position:relative;z-index:2;margin-top:auto;
  display:flex;gap:2px;flex-wrap:wrap;justify-content:center;max-width:100%;
}
.kPunkt{width:5px;height:5px;border-radius:99px;flex:0 0 auto}
.kPunkt.leer{background:var(--info)}
.kPunkt.verderb{background:var(--accent-warm)}
/* Verdirbt, bevor es aufgebraucht ist -- das ist die Verschwendung,
   um die es dieser App geht, und die einzige rote Aussage hier. */
.kPunkt.droht{background:var(--warning)}
/* Geld-Ebene: „hier geht etwas aus" ist ein Ereignis, kein Einkauf.
   Deshalb gedämpftes Grau statt eines Balkens -- der Balken gehört
   allein den Tagen, an denen wirklich Geld fließt. */
.kPunkt.faellig{background:var(--text-muted);opacity:.75}
.calendarLegend .kBalkenMini{
  display:inline-block;width:7px;height:12px;border-radius:99px;
  background:var(--brand-primary);opacity:.42;
}
.calendarLegend{
  display:flex;flex-wrap:wrap;gap:8px 16px;align-items:center;
  /* Oben 12 px, nicht -4: `.group` hat KEINEN unteren Abstand
     (margin:22px 0 0), der negative Wert zog die Legende also in die
     Umschalter „Geld/Vorrat" hinein — bei zwei Zeilen Legende stand die
     erste sichtbar auf deren Kante. Unten bleibt es enger als oben:
     die Legende gehört zum Gitter darunter, nicht zu den Umschaltern. */
  margin:12px 2px 10px;color:var(--text-secondary);font-size:.76rem;line-height:1.45;
}
.calendarLegend span{display:inline-flex;align-items:center;gap:6px}
.calendarLegend .kPunkt{display:inline-block;width:8px;height:8px}
.row.kWarn .rowTitle{color:var(--warning-text)}

@media (min-width:600px){
  .kTag{border-radius:var(--r-md)}
  .kZahl{font-size:0.82rem}
  .kBetrag{font-size:0.7rem}
  .kPunkt{width:6px;height:6px}
}
.headrow{display:flex;justify-content:space-between;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:2px}
.stat{font-size:0.79rem;color:var(--text-secondary)}
.srcnote{font-size:0.73rem;color:var(--text-muted);margin-top:13px;line-height:1.45}
/* Eine Quellenangabe direkt unter einer Gruppe (nicht in ihrer
   Glasfläche) rückt auf dieselbe Kante ein wie deren Überschrift. */
.group > .srcnote{padding:0 4px}
/* Der schnellste Weg im Bestand ist eine Wischgeste — also unsichtbar.
   Diese Zeile steht deshalb VOR den Zeilen, nicht als Fußnote danach. */
.hintRow{margin:-2px 0 9px;padding:0 4px}
/* Der Grund, aus dem ein Rezept vorgeschlagen wird -- eine eigene
   Zeile, weil er etwas anderes sagt als Zeit und fehlende Zutat:
   nicht was es kostet, sondern was es rettet. */
.rowWhy{font-size:.76rem;color:var(--success-text);margin-top:2px;line-height:1.4}
/* Dieselbe Zeile, andere Aussage: hier verdirbt etwas, statt dass
   es rettet. */
.rowWhy.warn{color:var(--warning-text)}

/* ================================================================
   Produktmotive
   ================================================================
   84 Motive auf EINEM Bilderbogen (12 x 7, 128 px je Feld), gesetzt
   über background-position — dasselbe Verfahren wie bei den Posen des
   Wesens (.mPose weiter oben). Eine Liste mit vierzig Zeilen holt
   damit ein Bild statt vierzig, und offline liegt genau eine Datei im
   Cache.

   Die Motive bringen ihre Farben mit; es gibt hier deshalb keine
   Farbregeln und keine Themevarianten. Sie sind freigestellt, liegen
   also in hellem wie dunklem Modus richtig. */
/* Grundklasse aller Bildsymbole (Leiste, Meilensteine, Toast): nie
   verzerrt, nie gestreckt, nie abgeschnitten. */
.uiImageIcon{display:block;flex:0 0 auto;object-fit:contain;-webkit-user-select:none;user-select:none}
.pIcon{
  flex:0 0 auto;width:26px;height:26px;
  background-image:url("produkte/produkte-base.webp");
  background-size:1200% 700%;
  background-repeat:no-repeat;
}
/* Feine Motive ersetzen den Bilderbogen vollständig und werden nicht
   gekachelt. */
.pIcon.pIconFein{background-repeat:no-repeat}
.row > .pIcon,.top > .pIcon{margin-right:11px}
/* Im Produktblatt steht das Motiv auf einer ruhigen Plakette rechts
   neben dem Leitwert — sichtbar, aber nicht lauter als die Zahl. 44 px
   aus einem 128er-Feld bleiben auch auf einem Dreifach-Bildschirm scharf. */
.pPlate{
  width:64px;height:64px;border-radius:50%;
  display:grid;place-items:center;background:var(--surface-secondary);
}
.pPlate .pIcon{width:44px;height:44px}
/* Im Ladenmodus wie in der Liste vor dem Namen. */
.sItem .pIcon{width:28px;height:28px}
/* Derselbe Grund für die ganze Gruppe: dann trägt ihn eine Zeile
   über der Liste, mit dem Innenabstand einer Zeile. */
.groupWhy{margin:0;padding:12px 15px 2px}
.empty{font-size:0.9rem;color:var(--text-secondary);padding:0 0 26px;text-align:center}

/* ---------------- Wo dein Geld hingeht: eigener Bereich -----------
   Ein eigenständiger, erhöhter Bereich wie `.hero` (Vorrat) -- weiße
   Fläche, kräftiger Schatten, GROSSE Zahl -- statt einer weiteren
   Karte in der Liste. Farbe bleibt bewusst der Rückblick-Karte
   vorbehalten ("die einzige farbige Karte der App", siehe oben);
   diese Fläche hebt sich stattdessen über Fläche, Schatten und
   Zahlengröße ab, nicht über Farbe.

   Die Balken sind dieselbe Form wie beim Vorrat-Balken: eine SVG-Linie
   mit rundem Kappenende (`stroke-linecap="round"`), nicht ein Rechteck
   mit `border-radius` -- die einzige runde Form dieser sonst kantigen
   Oberfläche (`--r-*` steht überall sonst auf 0), reserviert für
   Mengen und Anteile. Eine Kategorie ist keine Rangfolge mit
   Eigenbedeutung (anders als z. B. Ampelstufen), deshalb EIN Farbton
   für jeden Balken -- eine Skala von hell zu dunkel würde die
   Balkenlänge ein zweites Mal verschlüsseln, ohne dass „dunkler"
   irgendetwas Eigenes bedeutet. */
.moneyHero{background:var(--surface-primary);border-radius:var(--r-lg);box-shadow:var(--shadow-lift);
  padding:18px 18px 8px;margin-top:14px}
.moneyHeroHead{display:flex;align-items:center;gap:6px;font-size:1.02rem;font-weight:650;letter-spacing:-.0075em}
.moneyTotal{margin-top:16px;display:flex;align-items:baseline;gap:9px;flex-wrap:wrap}
.moneyTotal .n{font-size:2.15rem;font-weight:750;letter-spacing:-.02em;line-height:1}
.moneyTotal .sub{font-size:0.82rem;color:var(--text-secondary)}
/* Bewusst KEINE Ampelfarbe (rot/grün): mehr ausgegeben ist nicht
   automatisch schlecht (Vorräte, ein Fest, ein teurerer Laden aus
   gutem Grund) -- die Pfeilrichtung reicht als Information, ohne ein
   Urteil zu fällen, das die Zahl allein nicht hergibt. */
.moneyDelta{color:var(--text-secondary);font-weight:600}
/* Normale Schreibweise statt Großbuchstaben+Sperrung -- dieselbe
   Abwägung wie bei .sheetGroupTitle: eine Zwischenüberschrift soll
   trennen, nicht schreien. */
.moneySection{font-size:0.79rem;font-weight:650;color:var(--text-secondary);
  letter-spacing:0;margin:22px 0 2px}
.moneyBarRow{display:block;width:100%;text-align:left;padding:11px 0;position:relative}
.moneyBarRow + .moneyBarRow::before{content:"";position:absolute;left:0;right:0;top:0;height:1px;background:var(--divider)}
/* Nur Produktzeilen sind Knöpfe (öffnen das Detail-Blatt) -- Kategorien
   und Märkte bleiben unklickbare div, es gibt für sie kein Blatt. */
button.moneyBarRow{transition:opacity .14s linear}
button.moneyBarRow:active{opacity:.6}
.moneyBarHead{display:flex;align-items:baseline;gap:9px;margin-bottom:7px}
/* Öffnet die restlichen Zeilen einer Rangliste (siehe moneyBarSection()
   in views.js) -- dieselbe Kante wie zwischen zwei Zeilen, damit sie
   sich als Teil der Liste liest und nicht als loser Zusatz. */
.moneyMore{
  display:block;width:100%;text-align:left;position:relative;
  padding:12px 0;color:var(--text-brand);font-size:0.87rem;font-weight:600;
}
.moneyMore::before{content:"";position:absolute;left:0;right:0;top:0;height:1px;background:var(--divider)}
.moneyMore:active{opacity:.55}
.moneyBarLabel{flex:1 1 auto;font-size:0.92rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Kleine Verlaufslinie der letzten sechs Monate -- "trend"-Baustein
   einer Kennzahl, hier neben statt in einer eigenen Kachel, damit die
   Rangliste nicht in zwei Bereiche zerfällt. Feste Breite, damit die
   Spalte bei wechselnden Kategorien nicht springt. */
.moneySparklineWrap{flex:0 0 auto;display:flex;align-items:center}
.moneySparkline{width:44px;height:16px;display:block;overflow:visible}
.moneyBarValue{font-size:0.88rem;font-variant-numeric:tabular-nums;flex:0 0 auto;color:var(--text-primary)}
.moneyBarValue small{margin-left:5px;font-size:0.78rem;color:var(--text-muted);font-variant-numeric:normal}
.moneyBarSvg{width:100%;height:9px;display:block;overflow:visible}
/* Verbindet Ausgabe und Verlust: dieselbe Ampelfarbe wie die
   "Verlust"-Kachel ganz oben, damit "rot = verdorben" app-weit
   dasselbe bedeutet -- anders als der neutrale Vorperioden-Vergleich
   oben, der bewusst KEINE Ampelfarbe trägt (mehr ausgegeben ist kein
   Fehlverhalten, Lebensmittel wegwerfen schon eher). */
/* --amber-ink statt --red: das ist ein Rückblick auf Vergangenes
   ("X % davon meist verschwendet"), keine akute Warnung -- --red
   bleibt damit dem einen Fall vorbehalten, der wirklich dringend ist
   (Kühlkette, Verbrauchsdatum). */
/* "Sonstige" ist keine echte Kategorie, sondern eine Sammelzeile für
   alles jenseits der Top 7 -- tritt bewusst zurück (graue statt
   Akzentfarbe im Balken, siehe moneyBarSvg, und hier gedämpfter Text),
   damit sie nicht wie ein weiterer gleichwertiger Rang aussieht. */
.moneyBarRow.muted .moneyBarLabel{color:var(--text-secondary);font-style:italic}
.moneyEmpty{padding:16px 0 20px;font-size:0.9rem;color:var(--text-secondary)}
/* Fünf Zeiträume passen nicht in eine Zeile wie die sonst nur zwei-
   oder dreistufigen `.segmented`-Regler (Erscheinungsbild,
   Schriftgröße). Umgebrochen sah das nach kaputtem Raster aus: drei
   breite Knöpfe oben, zwei viel breitere darunter. Also EINE Zeile,
   die sich schieben lässt -- dieselbe Geste wie beim Wochenstreifen
   und bei den Kennzahlkarten darüber, und der Regler bleibt als ein
   Stück erkennbar. Die Leiste selbst bleibt unsichtbar; dass es
   weitergeht, zeigt der angeschnittene letzte Knopf. */
.moneyRange{margin:12px 0 0}
/* Der fuenfte Zeitraum: eine Zeile unter dem Regler statt eines
   fuenften Knopfes darin. Ausgewaehlt traegt sie die Akzentfarbe --
   dann steht im Regler daruber bewusst nichts ausgewaehlt. */
.moneyRangeOwn{
  display:block;margin:8px 0 0;padding:4px 2px;min-height:32px;
  font-size:0.8rem;font-weight:600;color:var(--text-secondary);text-align:left;
}
.moneyRangeOwn.on{color:var(--text-brand)}
.moneyRangeOwn:active{opacity:.5}
.moneyHero .segmented{
  flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-x:contain;
  scrollbar-width:none;-ms-overflow-style:none;
}
.moneyHero .segmented::-webkit-scrollbar{display:none}
.moneyHero .segmented button{flex:0 0 auto;scroll-snap-align:start}

.infoBtn{
  width:17px;height:17px;flex:0 0 auto;border-radius:99px;margin-top:1px;
  background:var(--fill-subtle);color:var(--text-secondary);border:none;
  font-size:0.64rem;font-weight:700;font-style:normal;line-height:1;
  display:inline-flex;align-items:center;justify-content:center;letter-spacing:0;
}
.infoBtn:active{background:var(--fill-strong)}

/* ---------------- Hinweise: getönte Karte, kein Randstrich ------- */
.note{
  font-size:0.85rem;line-height:1.45;padding:12px 14px;border-radius:var(--r-md);
  background:var(--brand-soft);color:var(--text-primary);margin:11px 0;
}
.note b{font-weight:650}
.note.gold{background:var(--accent-warm-soft)}
.note.blue{background:var(--info-soft)}
.note.red{background:var(--warning-soft)}
.note.green{background:var(--success-soft)}

/* ---------------- Vorrat: große Zahl, weicher Balken -------------
   Kein Fortschrittsring (der steckt in jeder zweiten App) und keine
   Messskala (die war das Formular). Eine große, freundliche Zahl und
   ein Balken mit runden Enden.                                      */
.hero{
  display:block;width:100%;text-align:left;cursor:pointer;position:relative;
  background:var(--surface-primary);border-radius:var(--r-lg);padding:17px 18px 19px;
  box-shadow:var(--shadow-lift);margin-top:14px;
  transition:transform .18s var(--spring);
}
.hero:active{transform:scale(.985)}
.hero .txt{min-width:0;padding-right:78px}
.hero .txt b{display:block;font-size:1.09rem;font-weight:650;letter-spacing:-.011em}
.hero .txt small{display:block;font-size:0.82rem;color:var(--text-secondary);margin-top:3px;line-height:1.4}
.heroRing{display:block;width:100%;margin-top:15px;position:relative}
.heroRing svg{width:100%;height:12px;display:block}
.heroRing .val{position:absolute;right:0;top:-58px;display:flex;align-items:baseline;gap:4px}
.heroRing .n{font-size:2.06rem;font-weight:750;letter-spacing:-.0225em;line-height:1;font-variant-numeric:tabular-nums}
.heroRing .u{font-size:0.79rem;font-weight:600;color:var(--text-secondary)}
.hero .chev{display:none}

/* Direktzugang für Dinge, die ohne Bon in den Haushalt kamen. Eine
   kompakte Zeile statt einer zweiten großen Hauptaktion; sie bleibt
   dadurch sichtbar, konkurriert aber nicht mit dem dringenden Status. */
.stockAddShortcut{
  width:100%;display:flex;align-items:center;gap:11px;text-align:left;
  margin:10px 0 2px;padding:11px 13px;border:1px solid var(--border-subtle);
  border-radius:var(--r-md);background:var(--surface-primary);
}
.stockAddShortcut:active{background:var(--fill-subtle);transform:scale(.985)}
.stockAddMark{
  width:30px;height:30px;flex:0 0 auto;display:grid;place-items:center;
  border-radius:50%;background:var(--action-secondary);color:var(--text-brand);
  font-size:1.15rem;font-weight:650;
}
.stockAddText{min-width:0;display:flex;flex-direction:column;gap:1px}
.stockAddText b{font-size:.9rem;font-weight:650;color:var(--text-primary)}
.stockAddText small{font-size:.75rem;color:var(--text-secondary)}
.stockAddShortcut .chev{margin-left:auto}
.stockAddShortcut + .group{margin-top:12px}

/* ---------------- Kennzahlen ---------------- */
.scroller{
  display:flex;gap:10px;overflow-x:auto;scrollbar-width:none;
  margin:14px calc(var(--pad) * -1) 0;padding:2px var(--pad) 4px;
  /* Weicher rechter Rand statt hartem Schnitt an der letzten Kachel --
     sagt "hier geht's weiter", ohne ein eigenes Zeichen dafür zu
     brauchen. Fünf Kacheln passen auf Telefonbreite so gut wie nie
     ganz hin, der Rand ist also praktisch immer sichtbar begründet. */
  /* 28px waren neben einer 138px breiten Kachel kaum wahrnehmbar --
     die angeschnittene Kachel wirkte einfach abgeschnitten statt
     einladend. Breiter gefadet liest sich derselbe Anschnitt als
     Geste, nicht als Kante. */
  -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 52px),transparent 100%);
  mask-image:linear-gradient(to right,#000 calc(100% - 52px),transparent 100%);
}
.scroller::-webkit-scrollbar{display:none}
.tile{
  flex:0 0 auto;min-width:138px;background:var(--surface-primary);
  border-radius:var(--r-lg);padding:14px 15px 15px;box-shadow:var(--shadow-lift);
  -webkit-backdrop-filter:saturate(140%) blur(var(--glass-blur));
  backdrop-filter:saturate(140%) blur(var(--glass-blur));
}
.tile .l{font-size:0.76rem;color:var(--text-secondary);font-weight:500}
.tile .v{font-size:1.55rem;font-weight:750;margin-top:5px;letter-spacing:-.02em;line-height:1.05}
.tile .v.good{color:var(--success-text)}
.tile .v.warn{color:var(--warning-text)}
.tile .t{font-size:0.7rem;color:var(--text-muted);margin-top:4px}

/* ---------------- Steuerelemente ---------------- */
.stepper{display:flex;align-items:center;background:var(--fill-subtle);border-radius:var(--r-sm);flex:0 0 auto;overflow:hidden}
.stepper button{
  width:42px;height:34px;font-size:1.15rem;color:var(--text-primary);position:relative;
  transition:background .14s linear,transform .16s var(--spring);
}
.stepper button:active{background:var(--fill-strong);transform:scale(.9)}
.stepper button:disabled{opacity:.3;cursor:default;transform:none}
.stepper button:first-child::after{content:"";position:absolute;right:0;top:8px;bottom:8px;width:1px;background:var(--border-subtle)}
.stepVal{min-width:76px;text-align:right;font-size:1rem;color:var(--text-secondary);flex:0 0 auto}
.stepWrap{display:flex;align-items:center;gap:11px;flex:0 0 auto}

.switch{position:relative;width:50px;height:30px;flex:0 0 auto}
.switch input{position:absolute;inset:0;opacity:0;margin:0;width:100%;height:100%;cursor:pointer}
.switch .track{position:absolute;inset:0;border-radius:99px;background:var(--fill-strong);transition:background .24s var(--ease)}
.switch .track::after{
  content:"";position:absolute;top:3px;left:3px;width:24px;height:24px;border-radius:99px;
  background:var(--switch-knob);box-shadow:var(--shadow-knob);
  transition:transform .28s var(--spring);
}
.switch input:checked + .track{background:var(--action-primary)}
.switch input:checked + .track::after{transform:translateX(20px)}
.switch input:focus-visible + .track{outline:2.5px solid var(--focus-ring);outline-offset:2px}

.segmented{display:flex;background:var(--fill-subtle);border-radius:var(--r-sm);padding:3px;gap:3px}
.segmented button{
  flex:1;padding:7px 10px;font-size:0.82rem;font-weight:600;border-radius:calc(var(--r-sm) - 3px);
  color:var(--text-secondary);transition:background .2s var(--ease),color .2s linear;white-space:nowrap;
}
.segmented button[aria-selected="true"]{
  background:var(--surface-elevated);color:var(--text-primary);
  box-shadow:var(--shadow-control);
}

.field{display:block;margin:14px 0}
.field .lbl{display:block;font-size:0.79rem;font-weight:600;color:var(--text-secondary);margin-bottom:6px}
.field input,.field select,.field textarea{
  width:100%;padding:12px 14px;border:none;border-radius:var(--r-md);
  background:var(--bg-secondary);min-height:46px;
}
.field textarea{
  min-height:190px;font-family:ui-monospace,"SF Mono",Menlo,monospace;font-size:0.79rem;
  line-height:1.55;white-space:pre;overflow-wrap:normal;overflow-x:auto;resize:vertical;
}
.row2{display:flex;gap:10px}
.row2 > *{flex:1}
.dateRow{display:flex;gap:10px;padding:12px 16px;background:var(--surface-primary)}
.dateRow .field{margin:0;flex:1}

/* ---------------- Knöpfe ---------------- */
.cta{
  display:block;width:100%;margin-top:14px;padding:14px;border-radius:var(--r-md);
  background:var(--action-primary);color:var(--text-on-brand);font-weight:650;font-size:1rem;min-height:50px;
  letter-spacing:-.0075em;box-shadow:var(--shadow-lift);
  transition:transform .18s var(--spring),opacity .14s linear;
}
.cta:active{transform:scale(.975);background:var(--action-primary-pressed)}
.cta.light:active{background:var(--action-secondary)}
.cta.danger:active{background:var(--critical-soft)}
/* Kein pauschales opacity:.35 mehr -- das verblasste Fläche UND
   weiße Schrift gemeinsam und ließ z. B. „Einkauf buchen" im
   Ladenmodus vor dem ersten Häkchen kaum lesbar werden (blasses Weiß
   auf blassem Grün). Eigene, geprüfte Farben statt einer
   Deckkraft-Reduktion: dieselben Töne, die die App auch sonst für
   „da, aber gerade nicht dran" verwendet (z. B. deaktivierte
   Pfeil-Knöpfe bei der Gangreihenfolge). */
.cta:disabled{
  opacity:1;background:var(--action-disabled-bg);color:var(--action-disabled-text);
  cursor:default;transform:none;box-shadow:none;
}
.cta.light{background:var(--action-secondary);color:var(--text-brand);box-shadow:none}
.cta.danger{background:var(--critical-soft);color:var(--critical-text);box-shadow:none}
.listOpenCta{margin:10px 0 0;border-radius:var(--r-lg);min-height:54px}
.listOpenCta + .prepEntry{margin:8px 0}
.prepEntry + .hintRow{margin:0 0 8px}
.listOpenCta + .hintRow{margin:8px 0}
.prepEntry + .group,.hintRow + .group,.listOpenCta + .group{margin-top:10px}
.ctaRow{display:flex;gap:10px;margin-top:14px}
.ctaRow .cta{margin-top:0;flex:1}
.ctaRow .cta.light{flex:0 0 34%}
/* Sind beide hell, sind beide gleich breit: es gibt dann keinen
   Hauptknopf mehr in dieser Reihe — der steht in der Wagenleiste. */
.ctaRow .cta.light:first-child{flex:1}

.pillBtn{
  padding:8px 15px;background:var(--fill-subtle);border-radius:var(--r-md);
  font-size:0.85rem;font-weight:600;color:var(--text-primary);min-height:34px;white-space:nowrap;
  transition:transform .18s var(--spring),background .14s linear;
}
.pillBtn.on{background:var(--action-primary);color:var(--text-on-brand)}
/* "Getauscht" auf "Fällig": eine Kontur statt der vollen Fläche.
   Dieselbe Farbe wie .pillBtn.on wäre dieselbe Aussage wie der
   Hauptknopf der Seite (.cta) -- richtig für einen einzelnen Knopf,
   zu laut für eine Zeile, die je fälligem Produkt einmal auftaucht. */
.swapBtn.on{background:none;border:1.5px solid var(--brand-primary);color:var(--text-brand)}
.pillBtn:active{transform:scale(.92)}
.pillBtn:disabled{opacity:.3;cursor:default;transform:none}
.rowActions{display:flex;gap:7px;flex:0 0 auto}
.hintDecisionRow{display:block;padding-top:13px;padding-bottom:13px}
.hintDecisionRow .rowMain{width:100%;padding:0;text-align:left}
.hintDecisionRow .rowActions{margin-top:10px;justify-content:flex-start}
.hintDecisionRow .pillBtn{min-height:38px}
.linkBtn{color:var(--text-brand);font-size:0.9rem;font-weight:600;padding:6px 0}
.linkBtn:active{opacity:.5}

/* ---------------- Positionen ---------------- */
.items{list-style:none;margin:0;padding:0}
.item{padding:0;position:relative;background:var(--surface-primary)}
/* Der Zeileninhalt als eigenes Blatt: er lässt sich wischen, die
   Fläche dahinter kommt zum Vorschein. Der Innenabstand wandert
   deshalb von der Zeile in das Blatt. */
.item .itemBody{padding:12px 16px;position:relative;z-index:1;touch-action:pan-y;
  transition:transform .2s var(--ease)}
.swipeWrap.swiping > .itemBody{
  transition:none;background:var(--surface-primary);
  -webkit-user-select:none;user-select:none;
}
/* „Brauche ich nicht" ist keine Katastrophe: die Fläche trägt den
   ruhigen Ton, nicht das Rot des Bestands („ist alle" korrigiert
   Daten, das hier ist eine Meinung). */
.swipeBack.sanft{background:var(--fill-subtle)}
.swipeBack.sanft .swipeLabel{color:var(--text-secondary)}
.swipeWrap.armed .swipeBack.sanft{background:var(--action-secondary)}
.swipeWrap.armed .swipeBack.sanft .swipeLabel{color:var(--text-brand);opacity:1}
.item + .item::before{content:"";position:absolute;left:16px;right:0;top:0;height:1px;background:var(--divider)}
/* ABGEWÄHLT HEISST ABGEWÄHLT — NICHT ABGESCHALTET.
   Das Dimmen lag auf der ganzen Zeile und damit auch auf den vier
   Antworten, die ja gerade erscheinen, WEIL jetzt etwas zu tun ist.
   Nachgerechnet: der Kontrast der Knopfbeschriftung fiel dadurch von
   4,92:1 auf 1,74:1. Das ist nicht nur unter jeder Lesbarkeitsgrenze,
   es sieht aus wie „deaktiviert" — und damit war der Rückkanal, über
   den die App ihre Rhythmen korrigiert, optisch ausgeschaltet.
   Gedimmt wird jetzt nur noch die Zeile selbst. */
.item.off .top{opacity:.72}
/* Im Wagen: durchgestrichen und zurückgenommen — dieselbe Sprache
   wie in der Gangansicht, weil es dieselbe Sache ist. */
.imWagen .top{opacity:.72}
.imWagen .nm{text-decoration:line-through;text-decoration-color:var(--text-muted)}

/* Die Wagenleiste. Klebt am unteren Rand, solange die Liste
   weiterläuft, und setzt sich am Seitenende an ihren eigenen Platz. */
.cartBar{
  /* +26px statt +16: darüber liegt der Verlauf, mit dem der Inhalt an
     der Küche ausläuft (siehe .companion::before). Die Leiste gehört
     zum Inhalt und soll nicht hineinragen. */
  position:sticky;bottom:calc(var(--dock-bottom) + var(--stage-h) + 26px);z-index:4;
  display:flex;align-items:center;gap:12px;margin-top:14px;
  background:var(--surface-primary);padding:12px 14px;box-shadow:var(--shadow-lift);
  border:1px solid var(--border-subtle);border-radius:var(--r-lg);
}
.cartBar .t{flex:1;min-width:0;font-size:0.82rem;color:var(--text-secondary)}
.cartBar .t b{display:block;font-size:1.03rem;font-weight:650;color:var(--text-primary)}
.cartBar .cta{margin-top:0;width:auto;flex:0 0 auto;padding:12px 16px;font-size:0.94rem}

/* Die gewählte Antwort im Blatt. */
.row.chosen{background:var(--brand-soft)}
.row.chosen .rowTitle{color:var(--text-brand);font-weight:650}
.row.chosen .rowValue{color:var(--text-brand)}
.item .top{display:flex;align-items:flex-start;gap:13px}

/* Gefüllter Kreis, kein Haken darin — die Füllung allein sagt genug. */
.box{
  appearance:none;-webkit-appearance:none;
  width:24px;height:24px;flex:0 0 auto;margin:1px 0 0;
  border:2px solid var(--text-muted);border-radius:99px;background:transparent;
  position:relative;cursor:pointer;
  transition:background .18s var(--ease),border-color .18s var(--ease),transform .3s var(--spring);
}
.box:checked{background:var(--success);border-color:var(--success)}
.listRemoveTrigger{
  display:grid;place-items:center;
  transition:border-color .18s ease-out,background .18s ease-out,transform .18s ease-out;
}
.listRemoveTrigger::before,.listRemoveTrigger::after{
  content:"";position:absolute;width:12px;height:2px;border-radius:99px;
  background:var(--critical-text);opacity:0;
  transition:opacity .18s ease-out,transform .18s ease-out;
}
.listRemoveTrigger::before{transform:rotate(45deg) scale(.65)}
.listRemoveTrigger::after{transform:rotate(-45deg) scale(.65)}
.listRemoveTrigger.active-x{
  border-color:var(--critical);background:var(--critical-soft);
}
.listRemoveTrigger.active-x::before{opacity:1;transform:rotate(45deg) scale(1)}
.listRemoveTrigger.active-x::after{opacity:1;transform:rotate(-45deg) scale(1)}

/* Entfernen bleibt in derselben Produktzeile. Die 0fr-Zeile nimmt im
   geschlossenen Zustand wirklich keinen Platz ein und klappt ohne
   Bounce in der von iOS gewohnten kurzen Bewegung auf. */
.inlineRemove{
  display:grid;grid-template-rows:0fr;opacity:0;margin-top:0;
  pointer-events:none;
  transition:grid-template-rows .2s ease-out,opacity .16s ease-out,margin-top .2s ease-out;
}
.inlineRemoveInner{min-height:0;overflow:hidden}
.inlineRemoveActions{
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px;
  padding:10px;border-radius:var(--r-md);
  background:color-mix(in srgb,var(--surface-primary) 92%,#000 8%);
}
.inlineRemoveReason{
  min-width:0;min-height:40px;padding:6px 5px;border-radius:var(--r-sm);
  background:color-mix(in srgb,var(--surface-primary) 84%,#000 16%);
  color:var(--text-primary);font-size:.7rem;font-weight:720;line-height:1.15;
  text-align:center;
}
.inlineRemoveReason:active{background:var(--action-secondary)}
.item.removeOpen .inlineRemove{
  grid-template-rows:1fr;opacity:1;margin-top:10px;pointer-events:auto;
}
.item.removing{
  opacity:0;transform:translateX(-10px);pointer-events:none;
  transition:opacity .18s ease-out,transform .18s ease-out;
}
@media(max-width:360px){
  .inlineRemoveActions{gap:5px;padding:8px}
  .inlineRemoveReason{font-size:.66rem;padding-inline:3px}
}
@media(prefers-reduced-motion:reduce){
  .listRemoveTrigger,.listRemoveTrigger::before,.listRemoveTrigger::after,
  .inlineRemove,.item.removing{transition:none}
}
.item .main{flex:1;min-width:0;text-align:left;padding:0;background:none;display:block;cursor:pointer}
/* Nur die Zeile selbst blasst beim Tippen ab, nicht ihre Marken —
   die haben ihre eigene Rückmeldung und ihr eigenes Ziel. */
.item .main:active{opacity:.55}
.item .main .pill:active{opacity:1}
.item .nm{font-size:1rem;font-weight:520;display:flex;flex-wrap:wrap;align-items:center;gap:6px;letter-spacing:-.009em}
.item .itemNote{font-size:.74rem;color:var(--text-secondary);margin-top:2px;line-height:1.35}
.item .price{font-size:1rem;text-align:right;flex:0 0 auto}
/* Der Winkel sitzt auf der Höhe der ersten Zeile, nicht mittig: eine
   Position mit Marke ist zweizeilig, und ein mitwanderndes Zeichen
   sähe aus, als gehöre es zur Marke statt zur Zeile. */
.item .top > .chev{
  width:8px;height:8px;flex:0 0 auto;margin-top:7px;
  border-right:2px solid var(--text-muted);border-top:2px solid var(--text-muted);
  transform:rotate(45deg);
}
.item .price small{display:block;font-size:0.7rem;color:var(--text-muted);font-weight:400}
.item .calc{font-size:0.8rem;color:var(--text-secondary);margin-top:4px;padding-left:37px;line-height:1.4}
.item .why{padding-left:37px}
.inlineActions{padding:9px 0 2px 37px}
.item .opts{padding:9px 0 3px 37px}

/* Die Liste sagt oben, was sie ist und woher sie kommt. */
.listLead{
  padding:11px 16px 10px;background:var(--surface-primary);position:relative;
  font-size:0.79rem;color:var(--text-secondary);
}
.listLead::after{content:"";position:absolute;left:16px;right:0;bottom:0;height:1px;background:var(--divider)}

/* Der Hinzufügen-Knopf: dieselbe Zeilenform wie alles andere, aber
   mit einem Pluszeichen, das man von weitem sieht. */
.addRow{position:relative}
.addRow::before{content:"";position:absolute;left:16px;right:0;top:0;height:1px;background:var(--divider)}
.addRow .plusMark{
  width:26px;height:26px;flex:0 0 auto;border-radius:99px;
  background:var(--brand-soft);color:var(--text-brand);
  display:flex;align-items:center;justify-content:center;
  font-size:1.03rem;font-weight:600;line-height:1;
  transition:transform .22s var(--spring);
}
.addRow:active .plusMark{transform:rotate(90deg) scale(.9)}
.addRow .rowTitle{color:var(--text-brand);font-weight:600}

/* Freie Zeile im Suchblatt — sichtbar anders als ein Katalogtreffer. */
.results .freeRow{background:var(--brand-soft)}
.results .freeRow .rn{color:var(--text-brand);font-weight:600}

/* ================================================================
   Erfassen: aufnehmen, abgleichen, buchen
   ================================================================
   Schritt 1 ist eine kleine Karte — ein Symbol, ein Satz, zwei
   Knöpfe. Sie war einmal ein halber Bildschirm aus Textfeld,
   Datums- und Marktfeld; die Arbeit passiert aber erst im Abgleich,
   und der braucht den Platz. */
.captureEntry{padding:16px}
.captureEntry + .group{margin-top:12px}
.shotHead{display:flex;gap:12px;align-items:flex-start;margin-bottom:14px}
.shotHead .milestoneImageIcon{width:40px;height:40px;flex:0 0 auto}
.shotCopy{min-width:0}
.shotSub{font-size:var(--type-body);line-height:1.5;color:var(--text-secondary)}
.shot{margin-bottom:0}
.shotRow{display:flex;gap:10px}
.shotRow .cta{margin-top:0;flex:1;font-size:0.95rem;white-space:nowrap}
.shotRow .cta.light{flex:0 0 34%}
.shotHand{width:100%}
.shot.over{outline:2px dashed var(--brand-primary);outline-offset:6px;border-radius:var(--r-lg)}
/* Mehrere Fotos, ein Bon: Zahl am Vorschaubild, Titel im Foto-Blatt */
.reviewShot{position:relative}
.reviewShotZahl{position:absolute;right:3px;top:3px;min-width:18px;height:18px;padding:0 5px;border-radius:99px;background:var(--brand-primary);color:var(--text-on-brand);font-size:.7rem;font-weight:700;line-height:18px;text-align:center}
.bonFotoTitel{margin:14px 0 6px;font-size:.82rem;font-weight:600;color:var(--text-secondary)}
.bonFotoTitel:first-child{margin-top:0}
.shotStatus{font-size:0.82rem;color:var(--text-secondary);margin-top:10px;min-height:1.1em}
.shotBar{height:6px;background:var(--fill-subtle);overflow:hidden;margin-top:6px;border-radius:99px}
.shotBar i{display:block;height:100%;background:var(--brand-primary);transition:width .2s linear}
.captureInfo{margin-top:12px}
.captureInfo > summary{font-size:var(--type-body)}
.captureInfo .srcnote{margin:0;padding:5px 0 3px;font-size:var(--type-meta);line-height:1.55}

/* Schritt 2: der Abgleich. Kopf mit Anzahl, Datum und Markt. */
.reviewHead{padding:16px}
.reviewTitle{font-size:1.02rem;margin-bottom:12px;color:var(--text-secondary)}
.reviewTitle b{font-size:1.3rem;color:var(--text-primary);font-weight:750;margin-right:2px}
.reviewHead .row2{margin:0}
.groupNote{margin:0;padding:12px 16px 2px;font-size:var(--type-meta);line-height:1.5;color:var(--text-secondary)}
.reviewTop{display:flex;align-items:flex-start;gap:12px;margin-bottom:12px}
.reviewTop .reviewTitle{flex:1;margin-bottom:0}
/* Das Foto bleibt griffbereit: klein im Kopf, groß im Blatt. */
.reviewShot{
  flex:0 0 auto;width:52px;height:52px;border-radius:var(--r-sm);overflow:hidden;padding:0;
  background:var(--fill-subtle);box-shadow:inset 0 0 0 1px var(--divider);
  transition:transform .18s var(--spring);
}
.reviewShot:active{transform:scale(.94)}
.reviewShot img{width:100%;height:100%;object-fit:cover;display:block}
.bonFoto img{width:100%;border-radius:var(--r-md);display:block}
.reviewBar{margin-bottom:4px}
.reviewAll{display:block;width:100%;padding:12px 16px;text-align:left;color:var(--text-brand);font-size:0.88rem;font-weight:650}
/* „Jetzt zu tun": Zeilen, die genau ein Produkt betreffen, tragen die
   Handlung gleich mit. Kopf (Titel, Untertitel, Fähnchen/Betrag) oben,
   die Knöpfe darunter — auf 360 px steht sonst beides gequetscht. */
.row.stacked.todoRow{gap:9px;padding:13px 16px}
.todoRow .todoHead{display:flex;align-items:flex-start;gap:11px;width:100%}
.todoRow .pillBtn{min-height:38px}
.todoRow .rowMain{flex:1;min-width:0;text-align:left;padding:0}
.todoRow .rowActions{align-self:flex-start}
.todoRest{margin:2px 16px 12px;font-size:var(--type-meta);line-height:1.45;color:var(--text-muted)}
.reviewHint{margin:8px 2px 0;font-size:var(--type-meta);line-height:1.5;color:var(--text-secondary);text-align:center}
.reviewDiscard{display:block;margin:14px auto 4px;color:var(--text-muted);font-size:0.84rem}
.manualSearch.field{margin-top:0}

/* Getönte Chips: farbig, rund, ohne Rahmen */
.pill{
  font-size:0.68rem;font-weight:650;padding:3px 9px;border-radius:99px;
  background:var(--fill-subtle);color:var(--text-secondary);white-space:nowrap;letter-spacing:0;
}
.pill.rh{background:var(--success-soft);color:var(--success-text)}
.pill.risk{background:var(--warning-soft);color:var(--warning-text)}
.pill.dup{background:var(--info-soft);color:var(--info-text)}
.pill.warn{background:var(--badge-bg);color:var(--badge-text)}
.pill.state{background:var(--fill-strong);color:var(--text-secondary)}
.pill.safety{background:var(--critical);color:var(--text-on-critical)}
.pill.cheap{background:var(--success-soft);color:var(--success-text)}
.pill.own{background:var(--achievement-soft);color:var(--achievement-text)}

/* Antippbare Marken: erklären sich auf Tippen (Telefon) oder beim
   Verweilen mit dem Zeiger (Rechner). Der Unterschied zur stummen
   Marke muss sichtbar sein, ohne laut zu werden — deshalb nur der
   Zeiger, ein kleiner Druckpunkt und ein Fokusring für die Tastatur. */
.pill[role="button"],.flag[role="button"]{cursor:help;transition:transform .12s var(--spring)}
.pill[role="button"]:active,.flag[role="button"]:active{transform:scale(.9)}
.pill[role="button"]:focus-visible,.flag[role="button"]:focus-visible{
  outline:2px solid var(--focus-ring);outline-offset:2px;
}

.reasons{margin-top:11px;padding-left:37px}
.reasons .q{font-size:0.79rem;color:var(--text-secondary);margin-bottom:8px}
.opts{display:flex;gap:8px;flex-wrap:wrap}
.opt{
  flex:1 1 30%;min-width:104px;text-align:center;padding:9px 12px;
  background:var(--bg-secondary);border:1.5px solid transparent;
  font-size:0.85rem;font-weight:550;color:var(--text-secondary);
  transition:border-color .16s linear,color .16s linear,background .16s linear;
}
.opt[aria-pressed="true"]{border-color:var(--brand-primary);color:var(--text-brand);background:var(--brand-soft)}
.opt span{display:block}
.out{margin-top:10px;font-size:0.82rem;padding:10px 12px;border-radius:var(--r-md);background:var(--bg-secondary)}
.out.watch{background:var(--accent-warm-soft)}

.totals{
  display:flex;justify-content:space-between;align-items:flex-end;
  padding:15px 16px;background:var(--surface-primary);position:relative;
}
.totals::before{content:"";position:absolute;left:16px;right:0;top:0;height:1px;background:var(--divider)}
.totals .big{font-size:1.7rem;font-weight:750;line-height:1;letter-spacing:-.021em}
.totals .l{font-size:0.79rem;color:var(--text-secondary);margin-bottom:5px}
.totals .saved{font-size:0.85rem;color:var(--success-text);font-weight:600;text-align:right}
.totals.bare{background:none;padding:14px 0 0}
.totals.bare::before{display:none}

.sectionRow{
  padding:10px 16px 6px;font-size:0.73rem;font-weight:650;
  color:var(--text-secondary);background:var(--surface-primary);position:relative;letter-spacing:-.0025em;
}

/* ---------------- Tabellen und Listen ---------------- */
.tableWrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table{width:100%;border-collapse:collapse;font-size:0.9rem}
th,td{text-align:left;padding:10px 6px;border-bottom:1px solid var(--divider);vertical-align:top}
th{font-size:0.73rem;font-weight:600;color:var(--text-secondary);white-space:nowrap}
td.num,th.num{text-align:right;white-space:nowrap}
tbody tr:last-child td{border-bottom:none}

.plain{list-style:none;margin:0;padding:0}
.plain li{display:flex;gap:12px;align-items:flex-start;padding:11px 0;border-top:1px solid var(--divider);font-size:0.9rem;line-height:1.42}
.plain li:first-child{border-top:none}

.flag{
  flex:0 0 auto;font-size:0.73rem;font-weight:650;padding:4px 10px;border-radius:99px;
  white-space:nowrap;min-width:52px;text-align:center;background:var(--fill-subtle);color:var(--text-secondary);
}
/* Zweizeiliges Fähnchen: die Frage klein darüber, die Antwort darunter.
   Nur dort, wo eine nackte Zahl sonst mit einer zweiten Zahl in
   derselben Zeile verwechselbar wäre (Bestand: „haltbar 17 Tage"
   gegen „Vorrat reicht etwa 2 Tage"). */
.flagZwei{padding:3px 10px 4px;line-height:1.15}
.flagZwei small{display:block;font-size:0.62rem;font-weight:600;opacity:.72;letter-spacing:.01em}
.f-ok{background:var(--success-soft);color:var(--success-text)}
.f-gold{background:var(--accent-warm-soft);color:var(--accent-warm-text)}
.f-miss{background:var(--warning-soft);color:var(--warning-text)}
/* Die Kühlkette ist kein „bald", sondern ein Sicherheitsfall — Rot. */
.f-crit{background:var(--critical-soft);color:var(--critical-text)}
.f-new{background:var(--info-soft);color:var(--info-text)}

.chartBox{padding:15px 16px 16px}
.chart{width:100%;height:auto;display:block}
.legend{display:flex;gap:18px;font-size:0.76rem;color:var(--text-secondary);margin-top:11px;flex-wrap:wrap}
.legend i{display:inline-block;width:10px;height:10px;margin-right:6px;vertical-align:-1px}

.save{display:flex;align-items:center;gap:13px;padding:13px 16px;position:relative;background:var(--surface-primary)}
.save + .save::before{content:"";position:absolute;left:16px;right:0;top:0;height:1px;background:var(--divider)}
.save .amt{font-size:1rem;font-weight:750;color:var(--success-text);flex:0 0 66px;letter-spacing:-.015em;font-variant-numeric:tabular-nums}
.save .txt{flex:1;min-width:0}
.save .txt b{display:block;font-size:0.94rem;font-weight:550}
.save .txt small{display:block;font-size:0.76rem;color:var(--text-secondary);line-height:1.4;margin-top:2px}
.strip{display:flex;justify-content:space-between;padding:15px 16px;position:relative;background:var(--surface-primary)}
.strip::before{content:"";position:absolute;left:16px;right:0;top:0;height:1px;background:var(--divider)}
.strip .big{font-size:1.4rem;font-weight:750;letter-spacing:-.02em}
.strip .l{font-size:0.76rem;color:var(--text-secondary);margin-top:3px}

/* ---------------- Erfassen ---------------- */
/* Eine Zeile im Abgleich: links das Motiv, in der Mitte Name und
   Bonzeile, rechts der Betrag — und darunter, über die ganze Breite,
   genau die Handlungen, die dieser Zustand braucht. Zeilen, die noch
   etwas von der Nutzerin wollen, tragen links eine warme Kante. */
.matchRow{
  display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:4px 12px;
  align-items:start;padding:12px 16px;position:relative;background:var(--surface-primary);
}
.matchRow + .matchRow::before{content:"";position:absolute;left:16px;right:0;top:0;height:1px;background:var(--divider)}
.matchRow .pIcon{width:32px;height:32px;flex:0 0 auto}
.matchRow .raw{min-width:0}
.matchRow .raw .r{font-size:0.76rem;color:var(--text-muted);font-family:ui-monospace,"SF Mono",Menlo,monospace;word-break:break-word}
.matchRow .raw .n{font-size:0.94rem;font-weight:550}
.matchRow .amt{flex:0 0 auto;text-align:right;font-size:0.9rem;font-variant-numeric:tabular-nums}
.matchRow .amt small{display:block;font-size:0.7rem;color:var(--text-muted)}
.matchRow .srcnote{margin:2px 0 0}
.mrBefund{font-size:0.76rem;color:var(--text-secondary);margin-top:3px;font-variant-numeric:tabular-nums}
.mrUnknown{display:grid;place-items:center;background:var(--fill-subtle);border-radius:var(--r-sm);
  color:var(--text-muted);font-size:1rem;font-weight:700}
.mrActions{grid-column:1/-1;display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.mrOk,.mrAlt{
  min-height:40px;padding:8px 14px;border-radius:var(--r-md);font-size:0.86rem;font-weight:600;
  max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.mrOk{background:var(--action-primary);color:var(--text-on-brand);flex:1 1 auto}
.mrOk:active{background:var(--action-primary-pressed)}
.mrAlt{background:var(--fill-subtle);color:var(--text-secondary)}
.mrAlt:active{background:var(--fill-strong)}
.mr-pruefen{box-shadow:inset 3px 0 0 var(--accent-warm)}
.mr-offen{box-shadow:inset 3px 0 0 var(--info)}
.mr-weg .raw,.mr-weg .amt{opacity:.6}
/* Entschiedene Zeilen sind selbst der Knopf: Text links, Pfeil rechts. */
button.matchRow{width:100%;text-align:left;align-items:center;grid-template-columns:auto minmax(0,1fr) auto auto}
button.matchRow:active{background:var(--fill-subtle)}
button.matchRow .chev{
  width:8px;height:8px;flex:0 0 auto;align-self:center;margin-left:2px;
  border-right:2px solid var(--text-muted);border-top:2px solid var(--text-muted);
  transform:rotate(45deg);
}

.results{list-style:none;margin:10px 0 0;padding:0;max-height:288px;overflow-y:auto;background:var(--bg-secondary);border-radius:var(--r-md)}
.results li{position:relative}
.results li + li::before{content:"";position:absolute;left:14px;right:0;top:0;height:1px;background:var(--divider)}
.results button{display:flex;width:100%;justify-content:space-between;align-items:center;gap:10px;padding:12px 14px;text-align:left;min-height:48px}
.results button:active{background:var(--fill-subtle)}
.results .rn{font-size:0.97rem}
.results .rc{font-size:0.76rem;color:var(--text-secondary)}
.noHit{padding:13px 14px;font-size:0.9rem;color:var(--text-secondary)}
/* Nichts gefunden ist kein Ende: der Katalog kennt 2188 Produkte und
   trotzdem nicht den Kaese vom Hofladen. Die Zeile sieht aus wie ein
   Treffer, weil sie sich auch so anfuehlt -- ein Tipp, und es gibt das
   Produkt. */
.noHitBtn .rn{color:var(--text-brand);font-weight:600}
.eigenAnlegen{margin-top:16px}
.eigenProdukt .segmented{margin:14px 0}
.eigenProdukt .field:first-of-type{margin-top:0}

/* Das Blatt „Zeile zuordnen": drei Vorschläge zum Antippen, eine
   eigene Suche, und der Weg, die Zeile wegzulassen. Kein Dropdown mit
   dem ganzen Katalog — genau DAS war die Beschwerde, aus der dieser
   Weg entstanden ist. */
.zuRaw{font-size:1rem;font-weight:650;word-break:break-word;font-family:ui-monospace,"SF Mono",Menlo,monospace}
.zuBefund{font-size:0.82rem;color:var(--text-secondary);margin-top:4px;font-variant-numeric:tabular-nums}
.zuordnen .srcnote{margin:4px 0 0}
.zuLabel{font-size:var(--type-meta);font-weight:700;color:var(--text-secondary);margin:16px 0 8px;letter-spacing:.02em}
.confirmChoices{display:flex;flex-direction:column;gap:8px}
.confirmChoice{display:flex;align-items:center;gap:10px;width:100%;padding:11px 14px;text-align:left;border-radius:var(--r-md);
  background:var(--brand-soft);color:var(--text-brand);font-size:0.97rem;font-weight:600;min-height:48px}
.confirmChoice .pIcon{width:28px;height:28px;flex:0 0 auto}
.confirmChoice:active{transform:scale(.98)}
.confirmChoice .confirmWhy{margin-left:auto;font-size:.78rem;font-weight:500;text-align:right}
.zuordnen .results{max-height:220px}
.zuFelder{display:grid;grid-template-columns:auto 1fr;gap:10px 12px;align-items:center;margin-top:14px}
.zuFeldLabel{font-size:var(--type-meta);font-weight:650;color:var(--text-secondary)}
.zuFelder .stepWrap{justify-self:start}
.zuFelder .priceIn{justify-self:start;width:104px}
.confirmSkip{display:block;margin:16px auto 0;color:var(--text-muted);font-size:0.86rem}
.mono{font-family:ui-monospace,"SF Mono",Menlo,monospace;word-break:break-word}
.manualAddTo{margin-bottom:10px}
.basket .pIcon{width:28px;height:28px;flex:0 0 auto}

.basket{list-style:none;margin:0;padding:0}
.basket li{display:flex;align-items:center;gap:11px;padding:11px 16px;position:relative;background:var(--surface-primary)}
.basket li + li::before{content:"";position:absolute;left:16px;right:0;top:0;height:1px;background:var(--divider)}
.basket .bn{flex:1;font-size:0.97rem;min-width:0}
.priceIn{width:86px;padding:9px;border:none;border-radius:var(--r-sm);background:var(--bg-secondary);text-align:right}
.del{color:var(--critical-text);font-size:1.3rem;line-height:1;padding:6px 8px;flex:0 0 auto;transition:transform .18s var(--spring)}
.del:active{transform:scale(.85)}

.row.action .rowTitle{color:var(--text-brand);font-weight:550}
.row.action.danger .rowTitle{color:var(--critical-text)}
/* Unwiderrufliches bekommt einen eigenen Ton, nicht nur eine eigene
   Textfarbe -- der Unterschied zwischen "eine Meldung tippen" und
   "unwiderruflich" verdient mehr als ein einzelnes rotes Wort in einer
   Liste sonst harmloser Zeilen. */
.row.action.danger{background:var(--critical-soft)}
button.row.action.danger:active{background:var(--critical-soft)}
button.row.action,label.row.action{cursor:pointer}

/* ---------------- Ladenmodus ---------------- */
.store{position:fixed;inset:0;z-index:90;background:var(--bg-primary);display:flex;flex-direction:column}
.store[hidden]{display:none}
.storeTop{
  display:flex;align-items:center;gap:12px;padding:calc(var(--safe-top) + 13px) var(--pad) 12px;
  background:var(--bg-material);
  -webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px);
  border-bottom:1px solid var(--border-subtle);
}
.storeTop h2{font-size:1.09rem;flex:0 0 auto}
.storeTop .prog{flex:1;font-size:0.85rem;color:var(--text-secondary)}
.storeTop .add{
  color:var(--text-brand);font-size:1.3rem;font-weight:650;line-height:1;
  width:38px;height:38px;display:flex;align-items:center;justify-content:center;
  border-radius:var(--r-md);background:var(--fill-subtle);flex:0 0 auto;
}
.storeTop .close{color:var(--text-brand);font-size:1rem;font-weight:650;padding:6px 2px;min-height:38px}
.storeBody{flex:1;overflow-y:auto;padding:6px var(--pad) 18px;-webkit-overflow-scrolling:touch}
.aisle{font-size:0.82rem;font-weight:600;color:var(--text-secondary);margin:18px 4px 7px}
.aisleGroup{background:var(--surface-primary);border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--shadow-lift)}
.sItem{
  display:flex;align-items:center;gap:14px;width:100%;background:var(--surface-primary);
  padding:15px 16px;text-align:left;min-height:60px;position:relative;
  transition:background .15s linear;
}
.sItem + .sItem::before{content:"";position:absolute;left:16px;right:0;top:0;height:1px;background:var(--divider)}
.sItem .tick{
  width:25px;height:25px;flex:0 0 auto;border:2px solid var(--text-muted);border-radius:99px;position:relative;
  transition:background .18s var(--ease),border-color .18s var(--ease);
}
/* Wie bei der Position in der Liste: .44 hieß 2,84:1 auf dem Namen
   des Artikels, den man gerade in den Wagen gelegt hat — und den man
   noch lesen können muss, um zu prüfen, ob es der richtige war. Der
   gefüllte Kreis und der Strich tragen die Aussage ohnehin. */
.sItem.done{opacity:.72}
.sItem.done .tick{background:var(--success);border-color:var(--success)}
.sItem .sn{flex:1;font-size:1rem;font-weight:520;letter-spacing:-.009em}
.sItem .sn small{display:block;font-size:0.76rem;font-weight:400;color:var(--text-secondary);margin-top:1px}
.sItem .sp{font-size:0.97rem;color:var(--text-secondary)}

/* Der Strich wird GEZOGEN, nicht gesetzt. `text-decoration` lässt sich
   nicht animieren — es ist im selben Bild da oder nicht. Deshalb ein
   Farbverlauf als Hintergrundbild mit wachsender Breite; der trägt
   auch über einen Zeilenumbruch. Bei „Bewegung reduzieren" entfällt
   der Übergang und der Strich steht sofort. */
.sItem .sn .strike{
  background-image:linear-gradient(currentColor,currentColor);
  background-repeat:no-repeat;
  background-position:0 58%;
  background-size:0 1.5px;
  transition:background-size .34s var(--ease);
}
.sItem.done .sn .strike{background-size:100% 1.5px}

.storeFoot{
  display:flex;justify-content:space-between;align-items:center;gap:14px;
  background:var(--bg-material);
  -webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px);
  border-top:1px solid var(--border-subtle);
  padding:12px var(--pad) calc(var(--safe-bottom) + 12px);
}
.storeFoot .stat{display:block;margin-bottom:2px}
.storeFoot .sum{font-size:1.33rem;font-weight:750;letter-spacing:-.02em}
.storeFoot .cta{margin:0;width:auto;padding:13px 22px;flex:0 0 auto}

/* ---------------- Blatt ---------------- */
.sheet{
  position:fixed;inset:0;z-index:100;display:flex;align-items:flex-end;justify-content:center;
  background:var(--bg-scrim);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
  animation:fade .22s var(--ease);
}
.sheet[hidden]{display:none}
/* Das Blatt kommt von unten und deckt die Seite darunter zum
   grössten Teil ab. Oben rund, unten nicht -- es sitzt auf der Kante
   des Bildschirms auf. */
.sheetBody{
  width:100%;max-width:540px;background:var(--surface-elevated);
  border-radius:var(--r-lg) var(--r-lg) 0 0;
  -webkit-backdrop-filter:saturate(150%) blur(30px);
  backdrop-filter:saturate(150%) blur(30px);
  padding:8px 18px calc(var(--safe-bottom) + 18px);
  max-height:88vh;overflow-y:auto;animation:rise .34s var(--ease);
  position:relative;
}
@keyframes fade{from{opacity:0}to{opacity:1}}
@keyframes rise{from{transform:translateY(100%)}to{transform:none}}
.grabber{width:38px;height:5px;border-radius:99px;background:var(--fill-strong);margin:0 auto 16px}
.sheetTitle{font-size:1.21rem;font-weight:700;letter-spacing:-.0125em}
.sheetSub{font-size:0.9rem;color:var(--text-secondary);margin:6px 0 16px;line-height:1.42}
.sheetPara{font-size:0.9rem;line-height:1.5;color:var(--text-primary);margin:0 0 12px}
.sheetPara:last-child{margin-bottom:0}
.shareText{
  font-family:ui-monospace,"SF Mono",Menlo,monospace;font-size:0.79rem;line-height:1.5;
  background:var(--bg-secondary);border-radius:var(--r-md);padding:14px;
  white-space:pre-wrap;word-break:break-word;margin:0 0 12px;
}
.facts{margin:0 0 14px;display:grid;grid-template-columns:auto 1fr;gap:0}
.facts dt{font-size:0.79rem;color:var(--text-secondary);padding:11px 14px 11px 0;border-top:1px solid var(--divider);white-space:nowrap}
.facts dd{margin:0;font-size:0.9rem;padding:11px 0;text-align:right;border-top:1px solid var(--divider)}
.facts dt:first-of-type,.facts dd:first-of-type{border-top:none}
/* Lange Werte dürfen umbrechen statt über den Rand zu laufen; der
   Wortumbruch bleibt an sinnvollen Stellen, deshalb kein break-all. */
.facts dd{overflow-wrap:anywhere}

/* ---------------- Produkt-Blatt ----------------
   Der Leitwert: EINE Aussage, groß, ganz oben. Kein Kasten mit
   Rahmen -- das Blatt hat schon einen. Die Farbe trägt hier
   ausnahmsweise Bedeutung (rot = Verbrauchsdatum oder hoher
   Verlust), deshalb nur als Textfarbe und dünner Trennstrich,
   nicht als Fläche: eine rote Fläche direkt unter der Überschrift
   erschlägt das ganze Blatt. */
/* Die Handlung steht über dem Leitwert und ist als einzige Aussage
   im Blatt eine Aufforderung. Deshalb Fläche statt bloßer Größe: der
   Leitwert darunter ist größer gesetzt und würde sie sonst schlucken.
   Die Farbe folgt derselben Rangfolge wie beim Leitwert. */
.pAction{
  background:var(--fill-subtle);border-radius:var(--r-md);
  padding:13px 15px;margin:2px 0 18px;
}
.pActionText{font-size:1.02rem;font-weight:700;line-height:1.25;color:var(--text-primary)}
.pActionWhy{font-size:0.82rem;color:var(--text-secondary);margin-top:4px;line-height:1.45}
.pAction.red{background:var(--warning-soft)}
.pAction.red .pActionText{color:var(--warning-text)}
.pAction.gold{background:var(--accent-warm-soft)}
.pAction.gold .pActionText{color:var(--accent-warm-text)}

/* Die häufigste Handlung im Bestandsblatt. Die Schätzung bleibt als
   Kontext sichtbar, die drei Antworten haben dieselbe Größe und sind
   mit dem Daumen erreichbar. Keine Formularoptik, kein versteckter
   Klappbereich. */
.stockAdjust{
  margin:0 0 20px;padding:13px;border:1px solid var(--border-subtle);
  border-radius:var(--r-lg);background:var(--fill-subtle);
}
.stockAdjustHead{display:block}
.stockAdjustTop{display:flex;align-items:center;justify-content:space-between;gap:8px}
.stockAdjustTitle{font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-secondary)}
.stockAdjustSource{
  font-size:.7rem;font-weight:650;padding:3px 8px;border-radius:99px;
  background:var(--surface-primary);color:var(--text-secondary);box-shadow:inset 0 0 0 1px var(--border-subtle);
}
.stockAdjustSource.eigen{background:var(--brand-soft);color:var(--text-brand);box-shadow:none}
.stockAdjustDays{font-size:1.6rem;font-weight:720;letter-spacing:-.02em;line-height:1.15;color:var(--text-primary);margin-top:4px}
.stockAdjustValue{font-size:.8rem;color:var(--text-secondary);margin-top:1px}
.stockAdjustActions{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px;margin-top:12px}
.stockAdjustBtn{
  min-width:0;min-height:44px;padding:8px 5px;border-radius:var(--r-md);
  background:var(--surface-primary);border:1px solid var(--border-subtle);
  color:var(--text-primary);font-size:.82rem;font-weight:650;line-height:1.15;
  transition:transform .18s var(--spring),background .14s linear;
}
.stockAdjustBtn:first-child{color:var(--critical-text);background:var(--critical-soft);border-color:transparent}
.stockAdjustBtn.on{background:var(--action-secondary);color:var(--text-brand);border-color:transparent}
.stockAdjustBtn:active{transform:scale(.96);background:var(--action-secondary)}

/* „Noch etwa N Tage da" einstellen — in derselben Karte, ohne zweites
   Blatt. Große Zahl mit Plus/Minus für den Daumen, darunter die
   üblichen Sprünge; das Datum sagt, was die Zahl bedeutet. */
.availPicker{margin-top:12px;padding-top:12px;border-top:1px solid var(--divider)}
.availStepper{display:grid;grid-template-columns:48px 1fr 48px;align-items:center;gap:8px}
.availStep{
  width:48px;height:48px;border-radius:50%;font-size:1.4rem;font-weight:500;line-height:1;
  background:var(--surface-primary);color:var(--text-primary);box-shadow:inset 0 0 0 1px var(--border-subtle);
  transition:transform .18s var(--spring);
}
.availStep:active{transform:scale(.9)}
.availStep:disabled{opacity:.35;transform:none}
.availValue{text-align:center;font-size:1.45rem;font-weight:720;letter-spacing:-.015em;color:var(--text-primary)}
.availChips{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin-top:10px}
.availChip{
  min-height:36px;padding:0 4px;border-radius:99px;font-size:.76rem;font-weight:650;
  background:var(--surface-primary);color:var(--text-secondary);box-shadow:inset 0 0 0 1px var(--border-subtle);
}
.availChip.on{background:var(--action-primary);color:var(--text-on-brand);box-shadow:none}
.availFoot{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:12px}
.availUntil{font-size:.82rem;color:var(--text-secondary)}
.availApply{
  min-height:44px;padding:0 16px;border-radius:var(--r-md);
  background:var(--action-primary);color:var(--text-on-brand);font-size:.86rem;font-weight:680;
}
.availApply:active{transform:scale(.97);background:var(--action-primary-pressed)}
.availWarn{margin:9px 2px 0;font-size:.76rem;line-height:1.4;color:var(--warning-text)}
.availWarn[hidden]{display:none}

.pLead{padding:2px 0 20px;display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:14px}
.pLead.hasStockAdjust{padding-bottom:12px}
.pLead > .pPlate{grid-column:2;grid-row:1 / span 3;align-self:start}
.pLeadVal{
  font-size:2.15rem;font-weight:750;letter-spacing:-.025em;line-height:1.02;
  font-variant-numeric:tabular-nums;
}
.pLeadWhat{font-size:0.97rem;font-weight:600;color:var(--text-primary);margin-top:5px}
.pLeadSub{font-size:0.82rem;color:var(--text-secondary);margin-top:5px;line-height:1.45}
.pLead.red .pLeadVal{color:var(--warning-text)}
.pLead.red .pLeadWhat{color:var(--warning-text)}

/* Kennzahlen unter dem Leitwert: die zweit- und drittwichtigste
   Aussage, die der Leitwert nicht schon trägt.
   OHNE Kästchen. Die erste Fassung setzte jede Kennzahl auf eine
   eigene Fläche mit Haarlinien-Fugen dazwischen -- drei Kennzahlen
   plus drei Preisfelder ergaben sechs Kästchen und ein halbes
   Dutzend zusätzlicher Linien auf einem Bildschirm, der ohnehin
   schon Karten, Faktenzeilen und einen roten Hinweis trägt. Zahlen
   brauchen keinen Rahmen, um als Zahlen gelesen zu werden; Abstand
   genügt. */
.pStats{display:flex;gap:26px;margin:0 0 22px;flex-wrap:wrap}
.pStat{min-width:0}
.pStat .v{
  font-size:1.06rem;font-weight:700;letter-spacing:-.012em;
  font-variant-numeric:tabular-nums;overflow-wrap:anywhere;
}
.pStat .l{font-size:0.74rem;color:var(--text-secondary);margin-top:2px}
.pStat.warn .v{color:var(--warning-text)}
.pStat.good .v{color:var(--success-text)}

/* Herkunft der Zahlen: eingeklappt, aber im Dokument. `details`
   bringt Tastaturbedienung und Vorlesehilfe von sich aus mit. */
.pMore{margin-top:18px;border-top:1px solid var(--divider);padding-top:4px}
/* EIN Aufklapper für die ganze App: ein kleines Winkelzeichen, das
   sich beim Öffnen dreht. Das schwarze Systemdreieck von <details>
   fällt in einer sonst durchgezeichneten Oberfläche sofort auf --
   und es gab es in drei Abstufungen, je nachdem welche Stelle man
   erwischte. Wer einen neuen Aufklapper baut, hängt ihn hier an. */
.pMore > summary,
.homeProgress > summary,
.settingsSection > summary,
.welcomeWhy > summary{
  list-style:none;cursor:pointer;
  display:flex;align-items:center;gap:7px;
}
.pMore > summary::-webkit-details-marker,
.homeProgress > summary::-webkit-details-marker,
.settingsSection > summary::-webkit-details-marker,
.welcomeWhy > summary::-webkit-details-marker{display:none}
.pMore > summary::before,
.homeProgress > summary::before,
.settingsSection > summary::before,
.welcomeWhy > summary::before{
  content:"";width:7px;height:7px;flex:0 0 auto;
  border-right:1.6px solid currentColor;border-bottom:1.6px solid currentColor;
  transform:rotate(-45deg);transition:transform .18s var(--ease);
}
.pMore[open] > summary::before,
.homeProgress[open] > summary::before,
.settingsSection[open] > summary::before,
.welcomeWhy[open] > summary::before{transform:rotate(45deg)}
.pMore > summary:active,
.homeProgress > summary:active,
.settingsSection > summary:active,
.welcomeWhy > summary:active{opacity:.55}
.pMore > summary{
  padding:11px 0;font-size:0.79rem;font-weight:600;color:var(--text-secondary);
}
.pMore .facts{margin-top:2px}
.useUpGroup>.groupTitle{min-height:30px;justify-content:flex-end;align-items:center;padding:0 14px}
.useUpGroup>.groupTitle>span:first-child{display:none}
.useUpStorage{margin-top:8px;padding-top:0;border-top:1px solid var(--divider)}
.useUpStorage>summary{min-height:44px;padding:10px 2px;font-size:.82rem;color:var(--text-brand)}
.storageAdvice{padding:0 0 12px;animation:storageAdviceIn .22s var(--ease)}
.storageAdviceIntro{margin:0 0 8px;padding:10px 12px;border-radius:var(--r-md);background:var(--fill-subtle);color:var(--text-secondary);font-size:var(--type-meta);line-height:1.45}
.storageAdviceList{display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--divider);border-radius:var(--r-md);background:var(--surface-primary)}
.storageAdviceRow{display:flex;align-items:center;gap:10px;width:100%;min-height:58px;padding:10px 11px;background:transparent;text-align:left;color:var(--text-primary)}
.storageAdviceRow+.storageAdviceRow{border-top:1px solid var(--divider)}
.storageAdviceRow>.pIcon{width:30px;height:30px;flex:0 0 30px}
.storageAdviceCopy{display:flex;flex:1;min-width:0;flex-direction:column;gap:3px}
.storageAdviceCopy b{font-size:var(--type-body);font-weight:680}
.storageAdviceCopy>span{font-size:var(--type-meta);line-height:1.4;color:var(--text-secondary)}
.storageAdvicePlace{flex:0 0 auto;max-width:34%;padding:5px 8px;border-radius:99px;background:var(--brand-soft);color:var(--text-brand);font-size:.68rem;line-height:1.2;text-align:center}
@keyframes storageAdviceIn{from{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:none}}

/* ---------------- Bestätigung ---------------- */
/* Sie kommt vom Begleiter. Vorher stand sie mittig über der Küche und
   wirkte wie eine Meldung des Geräts — „Bier ist alle" kam aus dem
   Nichts. Jetzt ist sie linksbündig über ihm verankert und hat einen
   Zipfel nach unten: eine Sprechblase, und zwar seine.
   Was sich dabei NICHT ändert: es bleibt eine reine Sachbestätigung
   ohne Stimmung, und sie löst KEINE Bewegung aus. Ein Toast ist keine
   bestätigte Fachmeldung im Sinne von App.melde() — die Regeln in
   CLAUDE.md („genau ein Präsentationspfad") gelten unverändert. */
.toast{
  position:fixed;left:var(--companion-left);right:auto;width:fit-content;
  bottom:calc(var(--dock-bottom) + var(--stage-h) + 14px);z-index:120;
  background:var(--toast-bg);color:var(--toast-text);padding:12px 20px 12px 14px;border-radius:var(--r-lg);
  font-size:var(--type-body);max-width:calc(100vw - var(--companion-left) - var(--pad));text-align:left;
  box-shadow:var(--shadow-toast);
  -webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);
  display:flex;align-items:center;gap:11px;
  animation:pop .3s var(--spring);
}
/* Der Zipfel zielt auf die MITTE der Figur, nicht auf ihren Rand.
   Gemessen bei 375 px Breite: Küche ab 16 px, Figur 18 px weiter mit
   52 px Breite — Mitte also bei 60 px, und die Blase beginnt bei 16.
   38 + halbe Zipfelbreite (7) trifft genau dorthin. */
.toast::after{
  content:"";position:absolute;top:100%;left:38px;
  border:7px solid transparent;border-top-color:var(--toast-bg);border-bottom:0;
}
.toast[hidden]{display:none}
/* Eine Blase zur Zeit über der Figur — siehe App.toast(). `visibility`
   und nicht `display`: die Sprechblase behält ihren Platz und ihre
   Höhe, sonst springt die Küche beim Erscheinen der Bestätigung. */
body.toastAn .mascotBubble{visibility:hidden}
/* Die Blase wächst aus dem Zipfel, nicht aus der Mitte — sonst sieht
   es aus, als schwebte sie zufällig dorthin. */
@keyframes pop{from{opacity:0;transform:translateY(10px) scale(.94)}to{opacity:1;transform:none}}
.toast{transform-origin:45px 100%}
.toast .tIcon.hatBild{background:none;width:32px;height:32px}
.toastImageIcon{width:32px;height:32px}
.toast .tIcon{
  flex:0 0 auto;width:24px;height:24px;border-radius:99px;
  background:var(--toast-icon-bg);color:var(--toast-icon-text);
  display:flex;align-items:center;justify-content:center;
  font-size:0.79rem;font-weight:700;line-height:1;
}
.toast.in .tIcon{animation:tick .46s var(--spring) .04s both}
.toast.in.fromMascot{animation:toastFromMascot .52s var(--spring)}
@keyframes toastFromMascot{
  0%{opacity:0;transform:translateY(22px) scale(.16)}
  68%{opacity:1;transform:translateY(-2px) scale(1.025)}
  100%{opacity:1;transform:none}
}
@media(prefers-reduced-motion:reduce){.toast.in.fromMascot{animation:fade .12s ease-out}}
.toast .tTxt{min-width:0}
.toast .tTxt b{display:block;font-size:var(--type-body);font-weight:650;line-height:1.35}
.toast .tTxt small{display:block;font-size:var(--type-meta);opacity:.72;margin-top:2px;line-height:1.35}
/* Rückweg nach einer Geste. Weiß auf dunklem Grund statt Akzentfarbe:
   der Toast ist der einzige Ort der App mit dunklem Untergrund, und
   der Akzent hätte darauf zu wenig Kontrast. */
.toast .tAct{
  flex:0 0 auto;margin-left:2px;padding:7px 12px;
  background:var(--toast-action-bg);color:var(--toast-text);
  border-radius:var(--r-md);font-size:var(--type-body);font-weight:650;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
}
.toast .tAct:active{background:var(--toast-action-bg-pressed)}

/* Informationsblätter bleiben sachlich. Die persönliche Reaktion und
   Sprechblase hat ausschließlich der feste Begleiter unten. */
.noticeCopy{
  position:relative;min-width:0;padding:14px 15px;
  background:var(--fill-subtle);border:1px solid var(--border-subtle);border-radius:var(--r-lg);
}
.noticeCopy .sheetPara{position:relative;font-size:var(--type-body);line-height:1.5}
@keyframes tick{
  0%{transform:scale(.2);opacity:0}
  100%{transform:scale(1);opacity:1}
}
.sItem.done .tick{animation:tick .4s var(--spring)}
.box:checked{animation:tick .36s var(--spring)}

/* ================================================================
   Rückblick, Streak, Meilensteine
   ================================================================ */

/* Die einzige farbige Karte der App — sie ist höchstens drei Tage in
   der Woche da, also darf sie auffallen. */
.reviewCard{
  background:var(--review-wash);
  border:1px solid color-mix(in srgb,var(--mascot-pink) 22%,transparent);
  border-radius:var(--r-lg);overflow:hidden;margin:14px 0 0;
  box-shadow:0 12px 34px var(--gami-shade);
}
.rvHead{display:flex;align-items:center;justify-content:space-between;padding:14px 16px 0}
.rvTag{font-size:var(--type-meta);font-weight:700;color:var(--text-brand)}
.rvClose{font-size:1.3rem;line-height:1;color:var(--text-muted);padding:2px 6px;margin:-4px -6px 0 0;transition:transform .18s var(--spring)}
.rvClose:active{transform:scale(.85)}
.rvBody{display:block;width:100%;text-align:left;padding:6px 16px 16px;transition:opacity .14s linear}
.rvBody:active{opacity:.65}
.rvHero{display:flex;align-items:center;gap:11px;min-height:76px}
.rvMascot{display:block;position:relative;flex:0 0 62px;filter:drop-shadow(0 6px 9px var(--gami-shade))}
.rvWords{min-width:0;flex:1;position:relative;background:var(--review-bubble-bg);padding:10px 12px;border-radius:var(--r-md)}
.rvWords::before{
  content:"";position:absolute;left:-6px;top:25px;width:12px;height:12px;
  background:var(--review-bubble-bg);transform:rotate(45deg);
}
.rvKicker{position:relative;font-size:var(--type-meta);font-weight:700;color:var(--mascot-pink-text);margin-bottom:3px}
.rvHead2{font-size:var(--type-title);font-weight:700;letter-spacing:-.01em;line-height:1.35}
.rvStrip{display:flex;gap:8px;margin-top:14px;flex-wrap:wrap}
.rvItem{
  flex:1 1 88px;min-width:88px;background:var(--surface-primary);border-radius:var(--r-md);padding:10px 12px;
}
.rvItem .v{font-size:var(--type-title);font-weight:750;letter-spacing:-.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rvItem .l{font-size:var(--type-meta);color:var(--text-secondary);margin-top:2px;line-height:1.35;font-weight:500}
.rvStreak{display:flex;align-items:center;gap:7px;font-size:var(--type-body);color:var(--text-secondary);margin-top:12px}
.rvStreak span{color:var(--success);font-size:var(--type-meta)}
.rvOpen{display:flex;justify-content:space-between;align-items:center;margin-top:13px;padding-top:12px;border-top:1px solid var(--divider);font-size:var(--type-body);font-weight:700;color:var(--text-brand)}
body[data-view="start"] .startMain > .reviewCard:first-child{margin-top:0}

/* Das geöffnete Wochenbild beginnt als Gespräch und wird danach erst
   zur Auswertung. */
.reviewIntro{display:flex;align-items:center;gap:10px;margin:2px 0 18px}
.reviewSpeech{position:relative;flex:1;min-width:0;background:var(--mascot-pink-soft);padding:14px 15px;border-radius:var(--r-lg)}
.reviewSpeechLabel{position:relative;display:block;font-size:var(--type-meta);font-weight:750;color:var(--mascot-pink-text);margin-bottom:4px}
.reviewSpeech p{position:relative;font-size:var(--type-title);font-weight:700;line-height:1.4;margin:0}
.reviewHighlights{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));margin:0 0 20px;background:var(--fill-subtle);border:1px solid var(--border-subtle);border-radius:var(--r-lg);overflow:hidden}
.reviewHighlight{position:relative;min-width:0;padding:13px 11px}
.reviewHighlight + .reviewHighlight::before{content:"";position:absolute;left:0;top:11px;bottom:11px;width:1px;background:var(--divider)}
.reviewHighlight strong{display:block;font-size:var(--type-title);line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.reviewHighlight span{display:block;font-size:var(--type-meta);color:var(--text-secondary);line-height:1.35;margin-top:4px}
.reviewGroupTitle{margin-top:20px;font-size:var(--type-body)}
.reviewFacts{background:var(--fill-subtle);border:1px solid var(--border-subtle);border-radius:var(--r-lg);padding:2px 13px;margin-bottom:4px}
.reviewSheetContent > .sheetPara{font-size:var(--type-body)}
.reviewSheetContent .streak{border:1px solid var(--border-subtle);border-radius:var(--r-lg);background:var(--fill-subtle)}
.reviewMethod{margin-top:18px;border-top:1px solid var(--divider);padding-top:4px}
.reviewMethod > summary{font-size:var(--type-body)}
.reviewMethod .srcnote{margin:0;padding:5px 0 4px;font-size:var(--type-meta);line-height:1.55}

/* Streak: runde Perlen, gefüllt was gehalten wurde. */
.streak{display:flex;align-items:center;gap:13px;padding:13px 16px;background:var(--surface-primary);flex-wrap:wrap}
.sDots{display:flex;gap:6px;flex:0 0 auto}
.sDot{width:11px;height:11px;border-radius:99px;background:var(--fill-strong);display:block}
.sDot.on{background:var(--success)}
.sDot.vac{background:var(--info-soft);box-shadow:inset 0 0 0 2px var(--info)}
.sDot.now{box-shadow:0 0 0 3.5px var(--success-soft)}
.sDot.on.now{box-shadow:0 0 0 3.5px var(--success-soft)}
.streak .sTxt{font-size:0.82rem;color:var(--text-secondary);flex:1;min-width:0}

/* ================================================================
   Startseite
   ================================================================
   Der Wochenstreifen ist das einzige große Element der App. Er darf
   das sein, weil er das Einzige ist, was drei Quellen zu einer
   Aussage zusammenfasst.

   Ein Feld = ein Ereignis. Die Höhe eines Feldes ist FEST (10 px),
   nicht auf das Maximum normiert: nur so bleibt eine ruhige Woche
   auch flach. Ein Balkendiagramm, das sich selbst skaliert, sieht
   bei einer Sache genauso dramatisch aus wie bei zwölf.
   ================================================================ */
.welcomeTitle{
  font-size:1.2rem;font-weight:650;line-height:1.3;color:var(--text-primary);
  padding:22px 4px 6px;letter-spacing:-.012em;
}
/* Der Satz, der sagt, worum es geht — größer als die Aufzählung
   darunter, kleiner als die Überschrift darüber. Er trägt die einzige
   fremde Zahl auf diesem Bildschirm und muss gelesen werden, bevor
   jemand auf den Knopf tippt. */
.welcomeLead{
  margin:0;padding:0 4px 14px;
  font-size:1rem;line-height:1.45;color:var(--text-secondary);
}
.welcomePoints{
  list-style:none;margin:0;padding:0 4px 18px;
  display:flex;flex-direction:column;gap:11px;
}
.welcomePoints li b{color:var(--text-primary);font-weight:600}
/* Anleitung im leeren "Von Hand"-Korb. */
.manualHint{margin:2px 2px 0;padding:0;font-size:var(--type-body);line-height:1.5;color:var(--text-secondary)}
.welcomePoints li{
  position:relative;padding-left:15px;
  font-size:0.95rem;line-height:1.4;color:var(--text-secondary);
}
.welcomePoints li::before{
  content:"";position:absolute;left:0;top:0.55em;
  width:5px;height:5px;border-radius:50%;background:var(--brand-primary);
}

/* Start, zweite Spalte: nur auf dem Rechner (≥900px). Die
   Kalenderwoche steht inzwischen sichtbar oben im Hauptinhalt; hier
   bleibt nur der ergänzende Weg zum nächsten Bon. */
.startAside{display:none}
.startMascotCard{
  background:var(--surface-primary);box-shadow:var(--shadow-lift);
  padding:20px 18px;display:flex;flex-direction:column;align-items:center;gap:10px;
  text-align:center;
}
.startMascotCard svg{width:40px;height:40px;flex:0 0 auto}
.startMascotCard p{margin:0;font-size:0.92rem;color:var(--text-secondary);line-height:1.45}

/* Dreißig Tage als knappe, waagerecht scrollbare Vorschau. Eine feine
   Scrollspur macht sichtbar, dass nach der ersten Woche mehr folgt,
   ohne der Leiste eine zusätzliche Erklärung zu geben. */
.weekLookahead{overflow:hidden;margin:0}
.weekStrip{
  display:grid;grid-auto-flow:column;grid-auto-columns:64px;gap:4px;
  overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x proximity;
  padding:2px 0 6px;scrollbar-width:none;-ms-overflow-style:none;
}
/* Kein sichtbarer Rollbalken: auf dem Telefon gibt es ohnehin keinen,
   am Rechner lag ein grauer Strich unter den ersten beiden Tagen und
   sah aus wie ein vergessenes Element. Dass es weitergeht, zeigt der
   angeschnittene Tag am rechten Rand. */
.weekStrip::-webkit-scrollbar{display:none}
/* Die rechte Kante läuft weich aus: sonst endet die Leiste mitten in
   einem Tag („lä" statt „läuft ab"), und ein abgeschnittenes Wort
   sieht aus wie ein Fehler statt wie „hier geht es weiter". */
.weekStrip{
  -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 34px),transparent);
  mask-image:linear-gradient(to right,#000 calc(100% - 34px),transparent);
}
.weekDay{
  min-height:64px;padding:5px 2px;border-radius:var(--r-sm);
  background:transparent;border:0;
  display:flex;flex-direction:column;align-items:center;text-align:center;
  scroll-snap-align:start;transition:background .14s linear;
}
.weekDay:active{background:var(--bg-secondary)}
.weekDay.today{box-shadow:none}
.weekTop{display:flex;align-items:center;justify-content:center;gap:4px;min-height:24px}
.weekWeekday{font-size:.64rem;font-weight:700;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.05em}
.weekDate{
  width:24px;height:24px;border-radius:50%;
  display:grid;place-items:center;font-size:.83rem;font-weight:720;
}
.weekDay.today .weekDate{background:var(--action-primary);color:var(--text-on-brand)}
.weekSignals{margin-top:auto;min-height:18px;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:1px;line-height:1.2}
.weekMoney{font-size:.67rem;font-weight:650;color:var(--text-brand);white-space:nowrap}
.weekAlert{font-size:.65rem;font-weight:650;color:var(--warning-text);white-space:nowrap}

/* Die Liste als ein Feld: eine Zeile, die aussieht, als könne man
   sie drücken — weil man genau das tun soll. */
.bigAction{
  display:flex;align-items:center;gap:14px;width:100%;text-align:left;
  padding:17px 16px;background:var(--surface-primary);
  transition:background .14s linear;
}
.bigAction:active{background:var(--fill-subtle)}
.baPreview{
  font-size:0.79rem;color:var(--text-secondary);margin-top:5px;
  display:flex;gap:.4em;white-space:nowrap;min-width:0;
}
/* Nur die Namen dürfen weichen -- die Restzahl ist fix und bleibt
   deshalb ein eigenes, nicht schrumpfendes Element (siehe listCard()
   in views.js). */
.baNames{overflow:hidden;text-overflow:ellipsis;min-width:0;flex-shrink:1}
.baRest{flex-shrink:0}

.runRow{display:flex;align-items:center;width:100%;background:var(--surface-primary);padding-right:16px}
.runRow .streak{flex:1;min-width:0}

/* Meilensteine: je eine Farbe, gezeichnete Marke im getönten Kreis. */
.badgeRow{display:block;background:var(--surface-primary);padding:0}
.badge{
  display:grid;grid-template-columns:38px 1fr auto;grid-template-rows:auto auto;
  column-gap:13px;row-gap:7px;align-items:center;
  width:100%;text-align:left;background:var(--surface-primary);
  padding:13px 16px;position:relative;transition:background .14s linear;
}
.badge + .badge::before{content:"";position:absolute;left:16px;right:0;top:0;height:1px;background:var(--divider)}
.badge:active{background:var(--fill-subtle)}
.badge .bIcon{
  grid-row:1 / span 2;width:38px;height:38px;
  display:flex;align-items:center;justify-content:center;
  background:var(--fill-subtle);color:var(--text-muted);
}
/* Das Bild ist das Zeichen selbst — die getönte Kachel dahinter
   war für die Strichzeichnung da und bleibt nur für deren Ersatz. Noch
   nicht erreicht heißt wie vorher „grau": entsättigt und leiser. */
.badge .bIcon:has(img){background:none}
/* Die getönten Kacheln je Reihe (unten) gelten nur noch für den Ersatz. */
.badge .milestoneImageIcon{width:44px;height:44px;margin:-3px}
.badge:not(.on) .milestoneImageIcon{filter:grayscale(1);opacity:.5}
.badge .bIcon svg{width:21px;height:21px;stroke:currentColor;fill:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
/* Jede Reihe hat ihre eigene Farbe — das ist der eine Ort, an dem die
   App bunt sein darf. Erreicht heißt getönt, offen heißt grau. */
.badge.m-gerettet.on  .bIcon:not(:has(img)){background:var(--success-soft);color:var(--success-text)}
.badge.m-guenstig.on  .bIcon:not(:has(img)){background:var(--accent-warm-soft);color:var(--accent-warm-text)}
.badge.m-getauscht.on .bIcon:not(:has(img)){background:var(--info-soft);color:var(--info-text)}
.badge.m-erfasst.on   .bIcon:not(:has(img)){background:var(--achievement-soft);color:var(--achievement-text)}
.badge.m-wochen.on    .bIcon:not(:has(img)){background:var(--mascot-pink-soft);color:var(--mascot-pink-text)}
.badge.m-gerettet  .bBar i{background:var(--success)}
.badge.m-guenstig  .bBar i{background:var(--accent-warm)}
.badge.m-getauscht .bBar i{background:var(--info)}
.badge.m-erfasst   .bBar i{background:var(--achievement)}
.badge.m-wochen    .bBar i{background:var(--mascot-pink)}
.badge .bLbl{grid-column:2;grid-row:1;font-size:0.94rem;font-weight:600;letter-spacing:-.0075em}
.badge .bVal{grid-column:3;grid-row:1;text-align:right;font-size:1.03rem;font-weight:750;letter-spacing:-.015em}
.badge .bBar{grid-column:2;grid-row:2;height:7px;background:var(--fill-strong);overflow:hidden}
.badge .bBar i{display:block;height:100%;background:var(--text-muted);transition:width .6s var(--ease)}
.badge .bNext{grid-column:3;grid-row:2;text-align:right;font-size:0.7rem;color:var(--text-muted);white-space:nowrap}

/* Glückwunsch */
/* ================================================================
   Der Auftritt bei einem Meilenstein
   ================================================================
   Der einzige Ort in dieser App, an dem etwas laut sein darf. Das
   ist Absicht und zugleich die Grenze: laut ist die BEWEGUNG, nicht
   die Aussage. Die Zahl in der Mitte ist die echte, sie läuft nur
   hoch wie eine Walze und rastet ein.

   Alles hier hat einen Aus-Schalter: unter `prefers-reduced-motion`
   erscheint dasselbe Fenster mit derselben Zahl, sofort und still.
   ================================================================ */
/* Die Feier lässt die Küche frei. Es gibt genau einen Begleiter, und
   er steht unten — während die Karte die Auszeichnung zeigt, macht er
   dort die Bewegung dazu. Ein Schleier über ihm hätte genau das
   verdeckt, was man sehen soll. */
.party{
  position:fixed;left:0;right:0;top:0;
  bottom:calc(var(--dock-bottom) + var(--stage-h) + 14px);
  z-index:80;display:flex;align-items:center;justify-content:center;
  padding:24px;background:var(--bg-scrim-strong);backdrop-filter:blur(3px);
  opacity:0;transition:opacity .22s ease;
}
/* Während der Feier ist die Küche zum Zusehen da, nicht zum Bedienen —
   und der Tipp in der Sprechblase tritt zurück: gefeiert wird eins
   nach dem anderen, nicht zwei Dinge gleichzeitig. */
body.feier .companion{pointer-events:none}
body.feier .companionPanel,body.feier .kGoal{visibility:hidden}
.party.show{opacity:1}
.party[hidden]{display:none}

/* Der Schein hinter der Karte trägt die Farbe der Reihe. Er ist der
   einzige Farbträger — die Karte selbst bleibt weiß, sonst wird aus
   dem Moment eine Litfaßsäule. */
.partyGlow{
  position:absolute;width:min(520px,120vw);aspect-ratio:1;border-radius:50%;
  /* Der Schein ist die Reihenfarbe, auf 42 % gemischt. Ohne color-mix
     (ältere Browser) bleibt die getönte Stufe derselben Farbe. */
  background:radial-gradient(circle,var(--party-soft) 0%,transparent 62%);
  background:radial-gradient(circle,color-mix(in srgb,var(--party) 42%,transparent) 0%,transparent 62%);
  opacity:.55;filter:blur(6px);
}
.party:not(.still) .partyGlow{animation:glowPulse 2.4s ease-out}
@keyframes glowPulse{
  0%{transform:scale(.2);opacity:0}
  22%{transform:scale(1.06);opacity:.75}
  100%{transform:scale(1);opacity:.45}
}

.partyCard{
  position:relative;z-index:2;width:100%;max-width:370px;text-align:center;
  background:var(--surface-primary);padding:16px 16px 18px;
  border:1px solid var(--border-subtle);border-radius:var(--r-lg);
  box-shadow:var(--shadow-party-card),var(--shadow-lift);
}
.party:not(.still) .partyCard{animation:cardIn .5s var(--spring) both}
@keyframes cardIn{
  from{transform:scale(.86) translateY(14px);opacity:0}
  to{transform:scale(1) translateY(0);opacity:1}
}

.partyKicker{
  font-size:var(--type-meta);font-weight:750;letter-spacing:0;text-transform:none;
  color:var(--party-ink);margin-top:16px;text-align:left;
}

.partyAchievement{display:grid;grid-template-columns:auto minmax(0,1fr);gap:14px;align-items:center;margin-top:8px;text-align:left}

.partyMark{
  width:74px;height:74px;margin:0;
  display:grid;place-items:center;background:var(--party-soft);color:var(--party-ink);
  position:relative;overflow:hidden;border-radius:var(--r-md);
}
.partyMark .milestoneImageIcon{width:66px;height:66px}
.partyMark svg{width:38px;height:38px;stroke:currentColor;fill:none;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}
.party:not(.still) .partyMark{animation:markIn .62s var(--spring) .08s both}
@keyframes markIn{
  from{transform:scale(.3) rotate(-14deg);opacity:0}
  to{transform:scale(1) rotate(0);opacity:1}
}
/* Ein Lichtstreifen, der einmal über das Zeichen läuft. Genau
   einmal — als Dauerschleife wäre es ein Werbebanner. */
.party:not(.still) .partyMark::after{
  content:"";position:absolute;inset:-40% -120%;
  background:linear-gradient(76deg,transparent 42%,var(--shine) 50%,transparent 58%);
  animation:shine 1.1s ease-in-out .7s 1 both;
}
@keyframes shine{from{transform:translateX(-100%)}to{transform:translateX(100%)}}

/* Die Walze. Tabellenziffern, damit die Zahl beim Hochlaufen nicht
   zappelt — proportionale Ziffern sind verschieden breit, und eine
   Zahl, die bei jedem Bild ihre Breite ändert, wirkt kaputt. */
.partyNum{
  font-size:var(--type-display);font-weight:800;letter-spacing:-.02em;line-height:1;
  font-variant-numeric:tabular-nums;color:var(--text-primary);margin:0;
}
.partyNum.land{animation:landPunch .34s var(--spring)}
@keyframes landPunch{
  0%{transform:scale(1)}
  40%{transform:scale(1.16)}
  100%{transform:scale(1)}
}

.partyTitle{font-size:var(--type-title);font-weight:650;line-height:1.35;margin:5px 0 0;color:var(--text-primary)}
.partyLevel{font-size:var(--type-meta);font-weight:650;color:var(--party-ink);margin-top:7px}

.partyPips{display:flex;gap:6px;justify-content:flex-start;margin-top:8px}
.partyPips i{width:7px;height:7px;border-radius:50%;background:var(--fill-strong)}
.partyPips i.on{background:var(--party-ink)}

.partyNote{
  font-size:var(--type-body);color:var(--text-secondary);line-height:1.5;text-align:left;
  margin:15px 0 0;padding:11px 12px;background:var(--fill-subtle);border-radius:var(--r-md);
}

/* Der Knopf bleibt im Grün der App und nimmt NICHT die Farbe der
   Reihe an. Zwei Gründe: „Weiter" ist überall dieselbe Handlung, und
   Grün ist in dieser App die Farbe des Handelns. Und praktisch: Weiß
   auf dem Gelb der Sparreihe wäre kaum lesbar. Die Zugehörigkeit
   tragen schon vier Elemente — Überzeile, Zeichen, Stufe, Punkte. */
.partyCard .cta{margin-top:18px}

/* Die Schnipsel. Sechs Farben aus der Palette, kein Regenbogen —
   es sind dieselben Farben, die die App sonst auch benutzt. */
/* HINTER der Karte, nicht davor. Davor legen sich die Schnipsel
   über die Schrift und man liest nicht mehr, wofür man gerade
   gefeiert wird — der Auftritt verdeckte seine eigene Aussage. So
   fliegen sie unter der Karte hervor nach außen, was ohnehin mehr
   nach Wurf aussieht. */
.partyBurst{position:absolute;inset:0;z-index:1;pointer-events:none;
  display:grid;place-items:center}
.partyBurst i{
  position:absolute;width:9px;height:14px;opacity:0;
  animation:confetti 1.5s cubic-bezier(.2,.7,.35,1) var(--d) both;
}
.partyBurst .p0{background:var(--success)}
.partyBurst .p1{background:var(--accent-warm)}
.partyBurst .p2{background:var(--info)}
.partyBurst .p3{background:var(--achievement)}
.partyBurst .p4{background:var(--mascot-pink)}
.partyBurst .p5{background:var(--warning)}
@keyframes confetti{
  0%{transform:translate(0,0) rotate(0);opacity:0}
  12%{opacity:1}
  /* Der Bogen: erst nach außen und oben, dann fallen. Ein gerader
     Strahl sieht aus wie ein Fehler, kein Wurf. */
  55%{transform:translate(var(--x),var(--y)) rotate(var(--r));opacity:1}
  100%{transform:translate(calc(var(--x) * 1.18),calc(var(--y) + 260px)) rotate(calc(var(--r) * 2));opacity:0}
}

/* Farbe je Reihe. Sie kommt aus derselben Palette wie die Abzeichen
   in „Zahlen" — dieselbe Sache, dieselbe Farbe. */
.party{--party:var(--success);--party-soft:var(--success-soft);--party-ink:var(--success-text)}
.party.m-guenstig{--party:var(--accent-warm);--party-soft:var(--accent-warm-soft);--party-ink:var(--accent-warm-text)}
.party.m-getauscht{--party:var(--info);--party-soft:var(--info-soft);--party-ink:var(--info-text)}
.party.m-erfasst{--party:var(--achievement);--party-soft:var(--achievement-soft);--party-ink:var(--achievement-text)}
.party.m-wochen{--party:var(--mascot-pink);--party-soft:var(--mascot-pink-soft);--party-ink:var(--mascot-pink-text)}

/* Weniger Bewegung heißt: keine. Nicht „etwas weniger". */
@media (prefers-reduced-motion: reduce){
  .party,.party *{animation:none !important;transition:none !important}
  .partyBurst{display:none}
}
@keyframes cheer{
  0%{transform:scale(.3) rotate(-12deg);opacity:0}
  100%{transform:scale(1) rotate(0);opacity:1}
}

/* Konfidenzmarken: gefüllt heißt gelernt, hohl heißt geschätzt. */
.supplyVal{display:flex;align-items:center;gap:9px;flex:0 0 auto}
.supplyVal .rowValue{max-width:none;white-space:nowrap;overflow-wrap:normal}
/* Etwas größer als die ursprünglichen 8px: bei "half" (Verlaufskante
   mittig durch den Punkt) war der Unterschied zu "full"/"none" auf
   einem Telefon-Display nur schwer zu erkennen. */
.dot{width:11px;height:11px;flex:0 0 auto;border-radius:99px;border:1.5px solid var(--text-muted);background:transparent}
.dot.full{background:var(--success);border-color:var(--success)}
.dot.half{background:linear-gradient(90deg,var(--success) 50%,transparent 50%);border-color:var(--success)}
.dot.none{border-style:dashed;opacity:.5}

/* Die Öffnen-Fläche einer Bonzeile. Sie liegt neben dem Betrag und
   dem ×, deshalb eine eigene schmale Schaltfläche statt einer Zeile,
   die als Ganzes klickt — sonst träfe man beim Löschen daneben. */
.rowOpen{flex:0 0 auto;padding:8px 2px 8px 8px;display:flex;align-items:center;background:none}
.rowOpen:active{opacity:.5}

/* Zwischenüberschrift in einem Blatt — trennt die gesammelten
   Hinweise nach Art, ohne dass jede Art eine eigene Karte braucht. */
/* Der Vorschlag zur halben Menge. Kein Knopf, der aussieht wie ein
   Knopf — ein Satz, den man antippen kann. Er steht eingerückt unter
   seiner Zeile und gehört sichtbar dazu. */
.halfRow{
  display:flex;align-items:center;gap:9px;width:100%;margin:2px 0 4px 37px;
  padding:8px 12px 8px 9px;background:var(--accent-warm-soft);
  color:var(--accent-warm-text);font-size:0.82rem;font-weight:550;text-align:left;
  width:calc(100% - 37px);
}
.halfRow .hMark{
  flex:0 0 auto;width:20px;height:20px;border-radius:50%;display:grid;place-items:center;
  background:var(--accent-warm-text);color:var(--surface-primary);font-size:0.72rem;font-weight:700;
}
.halfRow:active{transform:scale(.985)}
.halfRow.on{background:var(--success-soft);color:var(--success-text)}
.halfRow.on .hMark{background:var(--success-text)}

/* Zwischenüberschrift im Blatt. Versalien mit Sperrung und Fettung
   waren drei Auszeichnungen gleichzeitig für eine Beschriftung, die
   nur trennen soll -- neben Karten, Kennzahlen und einem roten
   Hinweis las sich das lauter als der Inhalt darunter. Eine Stufe
   leiser: normale Schreibweise, kräftig genug zum Trennen, mehr Luft
   davor. */
.sheetGroupTitle{
  font-size:0.79rem;font-weight:650;letter-spacing:0;
  color:var(--text-secondary);margin:22px 0 2px;
}
.sheetGroupTitle:first-child{margin-top:4px}

.plainBtn{text-align:left;padding:0;background:none;display:block}
.plainBtn:active{opacity:.55}
.card:empty{display:none}

/* ================================================================
   Ab 900 px: Seitenleiste statt Leiste unten.
   ================================================================ */
@media (min-width:900px){
  :root{--nav-h:0px}
  .shell{flex-direction:row;min-height:100vh}
  .nav{
    position:sticky;top:0;left:auto;right:auto;bottom:auto;height:100vh;
    flex-direction:column;justify-content:flex-start;gap:3px;
    width:248px;flex:0 0 248px;padding:calc(var(--safe-top) + 22px) 12px 16px;
    border-top:none;border-right:1px solid var(--border-subtle);
    background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none;
  }
  .nav::before{
    content:"";display:block;flex:0 0 auto;height:30px;margin:6px 12px 20px;
    background:url("brand/wortmarke.png") left center/contain no-repeat;
  }
  .nav button{
    flex:0 0 auto;flex-direction:row;justify-content:flex-start;gap:12px;
    height:44px;padding:0 12px;font-size:0.94rem;font-weight:550;
  }
  .nav button svg{width:22px;height:22px}
  .nav button .navImageIcon{width:30px;height:30px}
  .nav button[aria-current="page"]{background:var(--nav-active-bg)}
  .nav button[aria-current="page"] svg{transform:none}
  .col{flex:1;min-width:0;display:flex;flex-direction:column}
  .appbar{padding:calc(var(--safe-top) + 16px) 32px 10px;background:transparent;
    -webkit-backdrop-filter:none;backdrop-filter:none;max-width:840px}
  .largeTitle{padding:2px 32px 0;max-width:840px}
  .calendarStripSlot{padding:8px 32px 0;max-width:840px}
  main{padding:6px 32px 56px;max-width:840px}
  .scroller{margin:14px 0 0;padding:2px 0 4px;flex-wrap:wrap}
  /* flex:1 ließ die letzte Kachel einer Zeile (z.B. die fünfte, wenn
     vier in die erste Zeile passen) allein umbrechen und sich dabei
     über die volle Restbreite ziehen -- eine fast leere, sehr breite
     Fläche. flex:0 1 hält jede Kachel bei ihrer eigenen Breite, auch
     wenn sie allein in ihrer Zeile steht. */
  .tile{flex:0 1 200px}
  /* Start: zweite Spalte für die dauerhafte Wesen-Nachricht und die
     Kalender-Vorschau -- der Inhalt endete sonst bei ~660px Höhe,
     während der Rest des Fensters leer blieb. */
  .startLayout{display:flex;gap:24px;align-items:flex-start}
  .startMain{flex:1;min-width:0}
  .startAside{display:flex;flex-direction:column;gap:20px;flex:0 0 280px}
  .startAside .group{margin-top:0}
  .cards2{display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:start}
  .cards2 .card + .card{margin-top:0}
  /* Erfassen: "Fotografieren" blieb auch auf dem Rechner der
     volltonig grüne, optisch dominante Knopf -- ohne Rückkamera in
     Bon-Haltung ist dort "Bild wählen" oder eingefügter Text (die
     Fläche direkt darunter) der naheliegendere Weg. Reine Gewichtung,
     kein Eingriff in die Erkennung: Farbe und Reihenfolge tauschen,
     beide Knöpfe bleiben gleich groß und gleich bedienbar. */
  .shotRow .shotFoto{background:var(--action-secondary);color:var(--text-brand);box-shadow:none;order:2}
  .shotRow .shotWaehlen{background:var(--action-primary);color:var(--text-on-brand);box-shadow:var(--shadow-lift);order:1}
  .sheet{align-items:center}
  .sheetBody{max-width:560px;padding-bottom:20px;animation:zoom .26s var(--spring)}
  @keyframes zoom{from{opacity:0;transform:scale(.94)}to{opacity:1;transform:none}}
  .storeTop{padding:18px 32px 12px}
  .storeBody{padding:8px 32px 20px;max-width:840px;width:100%;margin:0 auto}
  .storeFoot{padding:14px 32px}
  /* Ohne das hängt das Wesen am Fensterrand statt am Inhalt -- bei
     248px Leiste + 840px Inhaltsspalte endet der Inhalt 1088px vom
     linken Rand, aber .mascotFab bleibt bei right:14px relativ zum
     GANZEN Fenster stehen. Auf einem breiten Bildschirm liegen dann
     hunderte Pixel Leerraum zwischen Inhalt und Wesen, und der
     namensgebende "immer an derselben Stelle"-Begleiter wirkt
     losgelöst. max() lässt den Ursprungswert unangetastet, solange
     die Inhaltsspalte den Rand ohnehin schon erreicht (900–1088px),
     und verankert erst darüber an ihrer rechten Kante. */
}

@media (max-width:360px){
  :root{--pad:13px}
  .nav button .navImageIcon{width:28px;height:28px}
}

/* Ruhiger Produktrahmen: ein Hauptziel, Begleitung im Inhalt und
   gemeinsame Flächen für alle bestehenden Werkzeuge. */
:root{
  --glass-blur:0px;
  --r-lg:22px;
  --r-md:14px;
  --pad:20px;
  --nav-h:56px;
}
.largeTitle h1{letter-spacing:-.045em;font-weight:750;font-size:2rem}
.groupTitle{font-size:.9rem;font-weight:700;color:var(--text-primary);padding:0 2px 10px}
.groupBody,.card{background:var(--surface-primary);border:1px solid var(--divider);backdrop-filter:none;-webkit-backdrop-filter:none}
.row{padding-top:16px;padding-bottom:16px}
.rowSub{line-height:1.5}
.nav button{font-size:.64rem;gap:2px}
.nav button[aria-current="page"]{color:var(--nav-active)}
.nav button[aria-current="page"] svg{background:var(--nav-active-bg);box-shadow:0 0 0 7px var(--nav-active-bg);border-radius:var(--r-sm);transform:none}
.nav button[aria-current="page"] .navImageIcon{background:var(--nav-active-bg);box-shadow:0 0 0 3px var(--nav-active-bg);border-radius:var(--r-sm)}
.cta{min-height:48px;border-radius:var(--r-md)}
button:focus-visible,summary:focus-visible{outline:3px solid var(--focus-ring);outline-offset:4px}
/* ================================================================
   Die Küche des Begleiters
   ================================================================
   Der Begleiter hat einen festen Ort: eine kleine Küche unten über der
   Leiste, auf JEDEM Reiter an derselben Stelle und in derselben Größe.
   Beim Wechsel der Reiter bewegt sie sich nicht — nur der Inhalt
   darum und der Satz in ihrer Sprechblase ändern sich. Dafür drei
   Dinge, die zusammen gelten müssen:
     1. fest positioniert (kein Fluss, der sie verschieben könnte),
     2. feste Höhe (--stage-h; kein Text kann sie wachsen lassen —
        Titel und Satz werden gekürzt, die volle Hilfe öffnet sich
        ÜBER der Küche, siehe .manualHelp),
     3. das Element wird nie neu gebaut (renderBar() fasst die Figur
        nicht an, kitchen.js zeichnet die Kulisse einmal beim Start).

   Früher war das eine Karte im Inhalt der Startseite, die beim
   Scrollen unten rechts andockte. Beides ist entfallen.

   Von hinten nach vorn: Wand mit Kacheln (.kitchenScene), Regal mit
   Dingen, Arbeitsplatte, darauf die Figur, rechts die Sprechblase
   (.companionPanel). Die Küche ist zugleich der Ort, den man künftig
   per Gamification einrichtet (kitchen.js, Kitchen.belegung()). */
.companion{
  position:fixed;z-index:39;
  left:var(--pad);right:var(--pad);
  /* Direkt auf der Leiste, ohne Spalt: in den 8 px dazwischen schaute
     vorher der scrollende Inhalt durch und wurde dort quer
     durchgeschnitten -- ein halbes Wort in einem Streifen zwischen
     zwei schwebenden Flächen. */
  bottom:calc(var(--dock-bottom));
  height:var(--stage-h);
  border-radius:var(--r-lg);
  box-shadow:var(--shadow-lift);
}
/* Der Inhalt endet über der Küche nicht mit einem Schnitt: ein kurzer
   Verlauf in der Seitenfarbe lässt ihn auslaufen. Sonst schnitt die
   Kante der Küche mitten durch Zeilen, die gerade vorbeiscrollen --
   dieselbe Karte, derselbe Text, nur horizontal abgeschnitten; das
   sah nach Fehler aus statt nach einer Ebene darüber. */
.companion::before{
  content:"";position:absolute;z-index:0;pointer-events:none;
  left:calc(var(--pad) * -1);right:calc(var(--pad) * -1);
  bottom:100%;height:18px;
  background:linear-gradient(to top,var(--bg-primary),transparent);
}
.companion[hidden]{display:none}
.kitchenScene{
  position:absolute;inset:0;border-radius:inherit;overflow:hidden;
  border:1px solid var(--divider);
  background:
    linear-gradient(var(--kitchen-tile) 1px,transparent 1px) 0 0 / 24px 24px,
    linear-gradient(90deg,var(--kitchen-tile) 1px,transparent 1px) 0 0 / 24px 24px,
    var(--kitchen-wall);
}
/* ---------------- Die 14 Module der Küche (kitchen.js) ----------------
   Jedes Modul hat einen festen Platz — dieselben Plätze für jedes
   Design, damit ein neues Design die Küche verändert und nicht ihren
   Aufbau. Waagerecht in Prozent (die Küche ist 343–400 px breit),
   senkrecht in Pixeln (sie ist immer --stage-h hoch). Wand und Boden
   sind keine Kästchen, sie färben die Kulisse (data-wall, data-floor).
   Rechts bleiben ~40 px frei für die drei Knöpfe. */
.kitchenScene[data-wall="salbei"]{--kitchen-wall:var(--gami-wall-salbei)}
.kitchenScene[data-wall="nordic"]{--kitchen-wall:var(--gami-wall-nordic)}
.kitchenScene[data-wall="midnight"]{--kitchen-wall:var(--gami-wall-midnight)}
.kitchenScene[data-wall="golden"]{--kitchen-wall:var(--gami-wall-golden)}
.kitchenScene::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:14px;
  background:linear-gradient(var(--kitchen-counter-top) 0 2px,var(--gami-floor,var(--kitchen-counter)) 2px);
}
.kitchenScene[data-floor="morgen"]{--gami-floor:var(--gami-floor-morgen)}
.kitchenScene[data-floor="salbei"]{--gami-floor:var(--gami-floor-salbei)}
.kitchenScene[data-floor="nordic"]{--gami-floor:var(--gami-floor-nordic)}
.kitchenScene[data-floor="midnight"]{--gami-floor:var(--gami-floor-midnight)}
.kitchenScene[data-floor="golden"]{--gami-floor:var(--gami-floor-golden)}
.kMod{position:absolute;z-index:1;display:block;border-radius:8%}
.kMod[hidden]{display:none}
.kMod:focus-visible{outline:2px solid var(--text-brand);outline-offset:2px}
.kitchenV9{background:var(--kitchen-wall);isolation:isolate}
.companion:has(.kitchenV9){--kitchen-glass:var(--surface-primary)}
.kitchenBase,.kitchenCanvas{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
.kitchenBase{object-fit:fill}
.kitchenWorld{position:absolute;inset:0 auto 0 0;width:min(100%,362px);z-index:1}
.kitchenCanvas{z-index:1}
.kitchenV9::after{height:20.75%;background:var(--gami-floor);mix-blend-mode:multiply;pointer-events:none}
.kitchenV9[data-wall]:not([data-wall="morgen"]) .kitchenBase{opacity:.55}
.kitchenV9 .kMod{padding:0;background:none}
.kitchenReady .kMod[data-packaged="true"] .kMotif{visibility:hidden}
.kitchenV9 .kMod.m-oberschrank{left:26.5%;top:14%;width:10%;height:22%;bottom:auto}
.kVariantChoices{display:flex;gap:10px;margin:16px 0}
.kVariantChoice{flex:1;min-height:80px;padding:10px;border:1px solid var(--border-subtle);border-radius:var(--r-md);background:var(--surface-primary);color:var(--text-primary)}
.kVariantChoice[aria-pressed="true"]{border:2px solid var(--text-brand);background:var(--fill-subtle)}
.kVariantChoice img{display:block;width:100%;height:60px;object-fit:contain;margin-bottom:6px}
.kMod[data-state="closed"]{border:1px dashed var(--border-subtle);opacity:.55}
.kMod[data-state="empty"]{border:1px dashed var(--brand-primary);opacity:.7;cursor:pointer}
.kMod[data-state="equipped"]{cursor:pointer}
.kMod.m-teppich{left:3%;width:25%;bottom:1px;height:9px;z-index:2;border-radius:50%}
.kMod.m-kucheninsel{left:21%;width:15%;bottom:4px;height:17px;z-index:3}
.kMod.m-unterschrank-l{left:30%;width:13%;bottom:14px;height:30px}
.kMod.m-ofen{left:43.4%;width:12.6%;bottom:14px;height:30px}
.kMod.m-spule-unterschrank-r{left:56.4%;width:14.6%;bottom:14px;height:30px}
.kMod.m-kuhlschrank{left:71.6%;width:10.4%;bottom:14px;height:68px}
.kMod.m-oberschrank{left:30%;width:13%;top:11px;height:24px}
.kMod.m-dunstabzug{left:44.2%;width:11%;top:9px;height:26px}
.kMod.m-wandregal{left:57%;width:13%;top:34px;height:5px}
.kMod.m-gadget{left:33%;width:14px;bottom:44px;height:14px;z-index:2}
.kMod.m-deko{left:60.5%;width:14px;top:19px;height:15px;z-index:2}
/* Seltenes leuchtet ein wenig — nur ein Rand, keine Bewegung. */
.kMod[data-rarity="episch"] .kMotif{box-shadow:0 0 0 1px var(--achievement),0 0 6px var(--achievement-soft)}
.kMod[data-rarity="legendaer"] .kMotif{box-shadow:0 0 0 1px var(--accent-warm),0 0 8px var(--accent-warm-soft)}

/* Ein Design: Bild, oder Platzhalter in Form des Moduls und Farben des Stils. */
.kMotif{position:relative;display:block;width:100%;height:100%;border-radius:inherit}
.kMotif[data-style="morgen"]{--k1:var(--gami-morgen);--k2:var(--gami-morgen-2)}
.kMotif[data-style="salbei"]{--k1:var(--gami-salbei);--k2:var(--gami-salbei-2)}
.kMotif[data-style="nordic"]{--k1:var(--gami-nordic);--k2:var(--gami-nordic-2)}
.kMotif[data-style="midnight"]{--k1:var(--gami-midnight);--k2:var(--gami-midnight-2)}
.kMotif[data-style="golden"]{--k1:var(--gami-golden);--k2:var(--gami-golden-2)}
.kMotifImg{display:block;width:100%;height:100%;object-fit:contain}
.kMotif > i,.kMotif > b{position:absolute;display:none}
.kMotif.platzhalter{background:var(--k1);box-shadow:inset 0 0 0 1px var(--gami-shade),inset 0 -2px 0 var(--gami-shade)}
.kMotif.platzhalter > i,.kMotif.platzhalter > b{display:block;background:var(--k2);border-radius:99px}
/* Unterschränke: Fuge und Griff. */
.m-unterschrank-l.platzhalter > i,.m-spule-unterschrank-r.platzhalter > i{left:50%;top:16%;bottom:10%;width:1px;background:var(--gami-shade)}
.m-unterschrank-l.platzhalter > b,.m-spule-unterschrank-r.platzhalter > b{left:36%;right:36%;top:22%;height:2px}
/* Spüle: das Becken oben. */
.m-spule-unterschrank-r.platzhalter::before{content:"";position:absolute;left:18%;right:18%;top:-3px;height:5px;border-radius:0 0 50% 50%;background:var(--k2);opacity:.75}
/* Ofen: Sichtfenster und Knopfleiste. */
.m-ofen.platzhalter > i{left:17%;right:17%;top:36%;bottom:14%;border-radius:8%;opacity:.6}
.m-ofen.platzhalter > b{left:14%;right:14%;top:12%;height:3px}
/* Kühlschrank: Türfuge und Griff. */
.m-kuhlschrank.platzhalter{border-radius:10% / 6%}
.m-kuhlschrank.platzhalter > i{left:0;right:0;top:34%;height:1px;border-radius:0;background:var(--gami-shade)}
.m-kuhlschrank.platzhalter > b{right:14%;top:12%;width:2px;height:14%}
/* Oberschrank: zwei Türen. */
.m-oberschrank.platzhalter > i{left:50%;top:10%;bottom:10%;width:1px;background:var(--gami-shade)}
.m-oberschrank.platzhalter > b{left:40%;right:40%;bottom:16%;height:2px}
/* Dunstabzug: ein Trichter mit Lichtleiste. */
.m-dunstabzug.platzhalter{-webkit-clip-path:polygon(34% 0,66% 0,66% 52%,100% 82%,100% 100%,0 100%,0 82%,34% 52%);clip-path:polygon(34% 0,66% 0,66% 52%,100% 82%,100% 100%,0 100%,0 82%,34% 52%);border-radius:0}
.m-dunstabzug.platzhalter > i{left:10%;right:10%;bottom:1px;height:2px}
/* Wandregal: ein Brett, darauf zwei Gläser. */
.m-wandregal.platzhalter{border-radius:99px}
.m-wandregal.platzhalter > i{left:12%;bottom:100%;width:6px;height:8px;border-radius:30% 30% 12% 12%}
.m-wandregal.platzhalter > b{left:34%;bottom:100%;width:5px;height:6px;border-radius:30% 30% 12% 12%;background:var(--k1);box-shadow:inset 0 0 0 1px var(--k2)}
/* Kücheninsel: Platte und Korpus. */
.m-kucheninsel.platzhalter > b{left:-4%;right:-4%;top:0;height:3px;border-radius:99px}
.m-kucheninsel.platzhalter > i{left:44%;right:44%;top:40%;height:2px}
/* Teppich: oval mit Borte. */
.m-teppich.platzhalter{border-radius:50%}
.m-teppich.platzhalter > i{left:12%;right:12%;top:40%;height:2px;opacity:.7}
/* Gadget: ein Kessel mit Tülle. */
.m-gadget.platzhalter{border-radius:45% 45% 12% 12%}
.m-gadget.platzhalter > b{right:-3px;top:34%;width:4px;height:2px}
.m-gadget.platzhalter > i{left:30%;right:30%;top:-2px;height:2px}
/* Deko: ein Topf mit Pflanze. */
.m-deko.platzhalter{background:transparent;box-shadow:none}
.m-deko.platzhalter > b{left:18%;right:18%;bottom:0;height:45%;border-radius:8% 8% 30% 30%;background:var(--k1);box-shadow:inset 0 -1px 0 var(--gami-shade)}
.m-deko.platzhalter > i{left:10%;right:10%;top:0;height:60%;border-radius:50%}
/* Das Outfit der Figur: ein Halstuch in den Farben des Stils. Bleibt
   liegen, wo die Figur steht — es ist Ausstattung, keine Figur. */
.kOutfit{position:absolute;left:31%;right:31%;top:52%;height:18%;z-index:3;pointer-events:none}
.kOutfitMotif.platzhalter{-webkit-clip-path:polygon(0 0,100% 0,62% 100%,38% 100%);clip-path:polygon(0 0,100% 0,62% 100%,38% 100%);border-radius:0}
.kOutfitMotif.platzhalter > i{left:30%;right:30%;top:20%;height:2px}
.kOutfitMotif.platzhalter > b{display:none}

/* Level und EXP, links oben in der Küche. */
.kHud{
  position:absolute;left:7px;top:7px;z-index:4;display:grid;place-items:center;
  width:30px;height:30px;padding:0;border-radius:50%;background:transparent;
}
.kHud[hidden]{display:none}
.kHudLv{
  position:relative;width:28px;height:28px;border-radius:50%;display:grid;place-items:center;
  font-size:.68rem;font-weight:800;color:var(--text-primary);
  box-shadow:0 0 0 1px var(--kitchen-glass-edge);
}
.kHudLv::before{content:"";position:absolute;inset:3px;border-radius:50%;background:var(--surface-primary)}
.kHudLv span{position:relative;z-index:1}
/* Die drei Knöpfe rechts: Aufgaben, Sammlung, Küchenfund. */
.kActions{
  position:absolute;right:6px;top:6px;bottom:6px;z-index:4;
  display:flex;flex-direction:column;justify-content:space-between;
}
.kActions[hidden]{display:none}
.kAct{
  position:relative;width:28px;height:28px;border-radius:50%;padding:0;
  display:grid;place-items:center;color:var(--accent-warm-text);font-size:.8rem;
  background:var(--kitchen-glass);box-shadow:inset 0 0 0 1px var(--kitchen-glass-edge);
  -webkit-backdrop-filter:var(--kitchen-frost);backdrop-filter:var(--kitchen-frost);
  transition:transform .18s var(--spring);
}
.kAct:active{transform:scale(.9)}
.kAct.hervor{box-shadow:inset 0 0 0 1.5px var(--accent-warm)}
.kActIcon{width:22px;height:22px}
/* Das Abzeichen bleibt INNERHALB der Küchenkarte. Ragte es über die
   Kante, lag es auf dem scrollenden Inhalt dahinter und sah aus wie
   ein Rest, der vergessen wurde wegzuräumen. */
.kActBadge{
  position:absolute;right:-3px;top:-3px;min-width:15px;height:15px;padding:0 4px;border-radius:99px;
  font-size:.54rem;font-weight:800;line-height:15px;text-align:center;
  background:var(--accent-warm);color:var(--text-on-warm);
}
.kActBadge[hidden]{display:none}
/* Das nächste Ziel: auf den übrigen Reitern, wo keine Sprechblase steht. */
/* Das naechste Ziel darf umbrechen statt abzuschneiden: „Noch 3
   Aufgaben bis zum Küchenf…" war acht Pixel zu lang und las sich wie
   ein Fehler. Ohne Zipfel braucht die Zeile keinen Abstand zur Figur
   wie die Sprechblase -- deshalb faengt sie weiter links an. */
.kGoal{
  position:absolute;left:78px;right:42px;bottom:18px;z-index:4;
  min-height:0;padding:3px 10px;border-radius:var(--r-md);
  font-size:.66rem;font-weight:650;line-height:1.3;color:var(--text-secondary);text-align:left;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;
  background:var(--kitchen-glass);box-shadow:inset 0 0 0 1px var(--kitchen-glass-edge);
  -webkit-backdrop-filter:var(--kitchen-frost);backdrop-filter:var(--kitchen-frost);
}
.kGoal[hidden],body[data-view="start"] .kGoal{display:none}
.companion:has(.mascotBubble:not(.manualHelp):not([hidden])) .kGoal{visibility:hidden}
/* Prestige: alle 10 Level eine Farbe (rein kosmetisch). */
[data-prestige="pb-10"]{--prestige:var(--prestige-10)}
[data-prestige="pb-20"]{--prestige:var(--prestige-20)}
[data-prestige="pb-30"]{--prestige:var(--prestige-30)}
[data-prestige="pb-40"]{--prestige:var(--prestige-40)}
[data-prestige="pb-50"]{--prestige:var(--prestige-50)}
[data-prestige="pb-60"]{--prestige:var(--prestige-60)}
[data-prestige="pb-70"]{--prestige:var(--prestige-70)}
[data-prestige="pb-80"]{--prestige:var(--prestige-80)}
[data-prestige="pb-90"]{--prestige:var(--prestige-90)}
[data-prestige="pb-100"]{--prestige:var(--prestige-100)}
/* Die Figur steht auf der Arbeitsplatte. */
.companionFigure{position:absolute;z-index:3;left:18px;bottom:9px;line-height:0}
/* Die Sprechblase: der Tipp auf Start, sonst leer — die Küche soll zu
   sehen sein, denn dort findet künftig die Gamification statt. Wenn
   Text dasteht, dann auf mattiertem Glas: lesbar, und dahinter bleibt
   sichtbar, was in der Küche steht. */
/* Verankert am UNTEREN Rand, Höhe nach Inhalt: braucht der Tipp mehr
   als die Küche hoch ist, wächst er nach oben aus ihr heraus, statt
   mitten im Wort abzuschneiden („Die geschätzte Haltbarkeit ende…").
   Die Küche behält dabei ihre feste Höhe -- sie ist die Bühne, nicht
   der Rahmen des Textes. */
.companionPanel{
  position:absolute;z-index:4;left:92px;right:42px;bottom:8px;
  display:flex;flex-direction:column;gap:2px;min-width:0;
  padding:7px 11px 8px;
}
.companionPanel[hidden]{display:none}
/* Die Sprechblase selbst: durchsichtiges, unscharfes Glas mit einem
   Zipfel zur Figur. Der Zipfel ist ein eigenes Stück Glas, das genau
   an der linken Kante ansetzt (kein Überlappen — sonst läge dort das
   Glas doppelt und zeichnete einen Streifen). Die helle Kante liegt
   nur OBEN, damit keine Linie quer über den Ansatz des Zipfels läuft;
   die Form trägt der weiche Schatten darunter. */
.companionPanel,
.companion .mascotBubble:not(.manualHelp):not([hidden]){
  border-radius:var(--r-md);
  background:var(--kitchen-glass);
  -webkit-backdrop-filter:var(--kitchen-frost);backdrop-filter:var(--kitchen-frost);
  box-shadow:inset 0 1px 0 var(--kitchen-glass-edge),var(--shadow-bubble);
}
/* Der Zipfel: geschwungen, er zeigt auf den Kopf der Figur. Die Form
   ist ein Pfad (16 × 26 px, feste Größe — deshalb path() statt einer
   Bilddatei); die Lichtkante darauf folgt seiner oberen Linie wie die
   Kante oben an der Blase. */
.companionPanel::before,
.companion .mascotBubble:not(.manualHelp)::before,
.companionPanel::after,
.companion .mascotBubble:not(.manualHelp)::after{
  content:"";display:block;position:absolute;
  left:-16px;right:auto;top:30px;width:16px;height:26px;
  border:0;transform:none;pointer-events:none;
}
.companionPanel::before,
.companion .mascotBubble:not(.manualHelp)::before{
  background:var(--kitchen-glass);
  -webkit-backdrop-filter:var(--kitchen-frost);backdrop-filter:var(--kitchen-frost);
  -webkit-clip-path:path("M16 3C12 10 7 16 0 22C7 21.5 12 19 16 16Z");clip-path:path("M16 3C12 10 7 16 0 22C7 21.5 12 19 16 16Z");
}
.companionPanel::after,
.companion .mascotBubble:not(.manualHelp)::after{
  background:var(--kitchen-glass-edge);
  -webkit-clip-path:path("M16 3C12 10 7 16 0 22L0.6 22.9C7.4 17 12.5 10.9 16 4.4Z");clip-path:path("M16 3C12 10 7 16 0 22L0.6 22.9C7.4 17 12.5 10.9 16 4.4Z");
}
body:not([data-view="start"]) .companionPanel{display:none}
.companionCopy{min-width:0}
.companionPanel .companionLabel{display:none}
.companion .companionPanel h2{
  margin:0;font-size:.84rem;line-height:1.25;letter-spacing:-.02em;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;
}
.companionPanel #companionText{
  margin:0;font-size:.72rem;line-height:1.35;color:var(--text-secondary);
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;
}
.companionHelp{min-width:0}
/* Die Handlungszeile bricht nicht um -- zwei kurze Knöpfe nebeneinander
   lesen sich als ein Paar; untereinander sähen sie aus wie zwei
   getrennte Angebote. Platz dafür hat die Blase jetzt, sie wächst. */
.companion .companionPanel .companionActions{margin-top:5px;flex-wrap:nowrap;gap:4px 10px;min-width:0}
.companion .companionPanel .companionActions.compact .companionAction{min-height:26px;padding:3px 10px;font-size:.72rem;white-space:nowrap}
.companionPanel .companionMore,.companionPanel .companionHelpLink{min-height:26px;padding:3px 0;font-size:.73rem;font-weight:650;white-space:nowrap}

.companionCopy[hidden],.companionTopics[hidden],.companionHelp[hidden]{display:none}
.companionCopy h2,.companionHelpTitle{font-size:1.06rem;line-height:1.3;letter-spacing:-.025em;margin:5px 0 0}
.companionActions{display:flex;flex-wrap:wrap;gap:6px;margin-top:12px}
.companionControls{display:flex;flex-wrap:wrap;column-gap:14px;align-items:baseline}
.companionControls .companionActions{flex-basis:100%}
.companionAction{
  min-height:44px;padding:9px 13px;border-radius:var(--r-sm);font-size:.8rem;font-weight:650;
  background:var(--action-primary);color:var(--text-on-brand);text-align:left;
}
.companionAction:active{background:var(--action-primary-pressed)}
.companionAction.secondary{background:var(--surface-primary);color:var(--text-brand)}
.companionAction.secondary:active{background:var(--action-secondary)}
.companionAction:hover{filter:brightness(.96)}
.companionWhy{margin-top:5px;font-size:.74rem;color:var(--text-secondary)}
.companionWhy summary{min-height:36px;padding:10px 0;cursor:pointer}
.companionWhy p{font-size:.78rem;line-height:1.5;margin:0 0 8px}
.companionNext,.companionHelpLink,.companionHelpClose{
  min-height:40px;padding:8px 0;font-size:.75rem;color:var(--text-brand);text-align:left;
}
.companionNext{padding-top:2px;min-height:32px}
.companionTopics{display:flex;gap:6px;border-top:1px solid var(--border-subtle);padding-top:10px}
.companionTopic{
  flex:1;min-width:0;min-height:42px;padding:8px 10px;border-radius:var(--r-sm);
  font-size:.76rem;font-weight:650;color:var(--text-secondary);white-space:nowrap;
}
.companionTopic[aria-pressed="true"]{background:var(--surface-primary);color:var(--text-brand);box-shadow:var(--shadow-lift)}
.companionActions.compact{align-items:center;gap:4px 14px}
.companionActions.compact .companionAction{min-height:36px;padding:7px 12px;font-size:.78rem}
.companionMore{min-height:36px;padding:7px 0;font-size:.78rem;font-weight:650;color:var(--text-brand)}
.mascotBubble.manualHelp .companionTopics{flex-wrap:wrap;margin-top:8px}

/* Eine Reaktion (Ereignis) erscheint IN der Sprechblase, an derselben
   Stelle und in derselben Größe — sie ist kurz, ein Satz und „Weiter". */
/* Nur die SICHTBARE Blase bekommt ihre Anzeigeform — sonst überschriebe
   sie `hidden`, und eine leere Blase läge über dem Tipp. */
/* Steht eine Reaktion da, weicht der Tipp — zwei Blasen übereinander
   zeigten zwei Zipfel und doppeltes Glas. */
.companion:has(.mascotBubble:not(.manualHelp):not([hidden])) .companionPanel{visibility:hidden}
.companion .mascotBubble:not(.manualHelp):not([hidden]){
  position:absolute;left:92px;right:42px;bottom:14px;z-index:5;
  display:flex;flex-direction:column;
  max-width:none;padding:8px 11px 9px;border:0;
  font-size:.76rem;line-height:1.35;
}
/* Drei Zeilen statt zwei: die längste Reaktion der Matrix hat 74
   Zeichen, aber die Meldungen der Gamification werden länger. Die
   Blase wächst dafür nach oben aus der Küche heraus. */
.companion .mascotBubble:not(.manualHelp) .mText{
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden;
}
.companion .mGo{min-height:26px;margin:4px 0 0 auto;padding:3px 13px;font-size:.74rem}
/* Die volle Hilfe („Mehr Tipps", Tipp auf die Figur) ist länger als
   jede Küche. Sie öffnet sich deshalb ÜBER ihr, statt sie wachsen zu
   lassen — die Küche selbst bleibt, wo sie ist. */
.companion .mascotBubble.manualHelp{
  position:absolute;left:0;right:0;bottom:calc(100% + 10px);
  max-width:none;max-height:min(62vh,480px);overflow-y:auto;overscroll-behavior:contain;
  padding:14px 16px;border-radius:var(--r-lg);
  background:var(--surface-elevated);border:1px solid var(--border-subtle);box-shadow:var(--shadow-toast);
  -webkit-backdrop-filter:none;backdrop-filter:none;
}
.companion .mascotBubble.manualHelp::before{display:none}

/* ---------------- Die Sammlung (Entwurf, kitchen.js) ----------------
   Noch kein Shop: sie zeigt, was man gesammelt hat, in Kategorien und
   Seltenheitsgraden, und stellt ein Teil zur Vorschau in die Küche.
   Seltenheit trägt eine Farbe aus dem Farbsystem — gewöhnlich neutral,
   selten Blau, episch Violett, legendär Apricot. */
.kPreview{position:relative;height:var(--stage-h);border-radius:var(--r-lg);margin:2px 0 14px}
.kPreview .kitchenScene{pointer-events:none}
.kPreviewFigure{position:absolute;left:14px;bottom:8px;line-height:0}
.kStand{display:flex;flex-direction:column;gap:8px;margin:0 0 12px}
.kStandZahl{font-size:.86rem;color:var(--text-secondary)}
.kStandZahl b{color:var(--text-primary);font-size:1.05rem}
.kRarities{display:flex;flex-wrap:wrap;gap:6px}
.kRarity{font-size:.7rem;font-weight:650;padding:3px 9px;border-radius:99px}
.kRarity b{margin-left:3px}
.kRarity.r-gewoehnlich{background:var(--fill-subtle);color:var(--text-secondary)}
.kRarity.r-selten{background:var(--info-soft);color:var(--info-text)}
.kRarity.r-episch{background:var(--achievement-soft);color:var(--achievement-text)}
.kRarity.r-legendaer{background:var(--accent-warm-soft);color:var(--accent-warm-text)}
.kCatTitle{font-size:.86rem;font-weight:700;margin:18px 2px 8px}
.kCatTitle span{display:block;font-size:.72rem;font-weight:500;color:var(--text-muted);margin-top:1px}
.kGrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.kCard{
  position:relative;display:flex;flex-direction:column;align-items:center;gap:3px;
  padding:12px 6px 9px;border-radius:var(--r-md);text-align:center;
  background:var(--surface-primary);box-shadow:inset 0 0 0 1.5px var(--divider);
  transition:transform .16s var(--spring);
}
.kCard:not(:disabled):active{transform:scale(.95)}
.kCard.r-selten{box-shadow:inset 0 0 0 1.5px var(--info-soft)}
.kCard.r-episch{box-shadow:inset 0 0 0 1.5px var(--achievement-soft)}
.kCard.r-legendaer{box-shadow:inset 0 0 0 1.5px var(--accent-warm);background:var(--accent-warm-soft)}
.kCardImg{width:44px;height:44px}
.kCardName{font-size:.74rem;font-weight:650;line-height:1.25;color:var(--text-primary)}
.kCardRarity{font-size:.64rem;font-weight:700;letter-spacing:.02em;color:var(--text-muted)}
.kCard.r-selten .kCardRarity{color:var(--info-text)}
.kCard.r-episch .kCardRarity{color:var(--achievement-text)}
.kCard.r-legendaer .kCardRarity{color:var(--accent-warm-text)}
.kCardPlaced{
  position:absolute;top:5px;right:5px;font-size:.58rem;font-weight:700;
  padding:2px 6px;border-radius:99px;background:var(--success-soft);color:var(--success-text);
}
.kCard:disabled{cursor:default}
/* Noch nicht gesammelt: nur die Umrisse, der Grad bleibt lesbar. */
.kCard.locked .kCardImg{filter:grayscale(1) brightness(.6);opacity:.28}
.kCard.locked .kCardName{color:var(--text-muted);font-weight:500}
.kNote{font-size:.76rem;line-height:1.5;color:var(--text-muted);margin:18px 2px 6px}
.kCard.placed{box-shadow:inset 0 0 0 2px var(--brand-primary)}
.kCard .gNew{background:var(--accent-warm-soft);color:var(--accent-warm-text)}
.kCardImg.m-kuhlschrank{width:26px}
.kCardImg.m-wandregal{height:8px;margin:28px 0 8px}
.kCardImg.m-teppich{height:20px;margin:12px 0}
.kCardImg.m-deko,.kCardImg.m-gadget{width:30px;height:32px;margin:6px 0}
.kCardImg.m-kuchenhintergrund{background-image:linear-gradient(var(--gami-shade) 1px,transparent 1px),linear-gradient(90deg,var(--gami-shade) 1px,transparent 1px);background-size:11px 11px}
.kCardImg.m-boden{height:18px;margin:13px 0;background-image:repeating-linear-gradient(90deg,transparent 0 10px,var(--gami-shade) 10px 11px)}
.kCardImg.m-maskottchen{-webkit-clip-path:polygon(0 18%,100% 18%,62% 86%,38% 86%);clip-path:polygon(0 18%,100% 18%,62% 86%,38% 86%)}
.kCard.locked .kMotif{filter:grayscale(1);opacity:.3}

/* ---------------- Die Blätter der Gamification (gamification.js) ---------------- */
.gSheet{display:flex;flex-direction:column;gap:2px}
.gBar{display:block;height:6px;border-radius:99px;background:var(--accent-warm-soft);overflow:hidden}
.gBar i{display:block;height:100%;border-radius:inherit;background:var(--accent-warm)}
.gBar.done i{background:var(--success)}
.gLevelHead{display:flex;align-items:center;gap:14px;margin:2px 0 14px}
.gLevelBadge{
  flex:0 0 auto;width:52px;height:52px;border-radius:50%;display:grid;place-items:center;
  font-size:1.3rem;font-weight:800;color:var(--text-primary);
  background:var(--surface-primary);box-shadow:inset 0 0 0 4px var(--prestige,var(--accent-warm));
}
.gLevelText{flex:1;display:flex;flex-direction:column;gap:6px;min-width:0}
.gLevelName{font-size:1rem;font-weight:750;letter-spacing:-.02em}
.gLevelSub{font-size:.76rem;color:var(--text-secondary)}
.gRows{display:flex;flex-direction:column;border-radius:var(--r-md);background:var(--surface-primary);box-shadow:inset 0 0 0 1px var(--divider);overflow:hidden}
.gRow{
  display:flex;justify-content:space-between;align-items:baseline;gap:12px;
  min-height:44px;padding:11px 14px;font-size:.84rem;text-align:left;color:var(--text-primary);
  border-top:1px solid var(--divider);background:transparent;
}
.gRows .gRow:first-child{border-top:0}
.gRow b{font-weight:650;color:var(--text-secondary);text-align:right}
button.gRow:active{background:var(--fill-subtle)}
.gSheet > .gRow{border:0;padding:8px 2px;min-height:0}
.gSectionTitle{font-size:.86rem;font-weight:750;margin:20px 2px 8px}
.gList{margin:0 0 4px;padding-left:18px;font-size:.8rem;line-height:1.55;color:var(--text-secondary)}
.gNote{font-size:.76rem;line-height:1.5;color:var(--text-muted);margin:8px 2px}
.gRateGrid{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:4px}
.gRate{font-size:.72rem;font-weight:650;padding:4px 10px;border-radius:99px}
.gRate b{margin-left:4px}
.gRate{background:var(--rar-soft);color:var(--rar-text)}
.gWeekGoal{display:flex;flex-direction:column;gap:6px;margin:0 2px 10px;font-size:.8rem;color:var(--text-secondary)}
.gTask{
  display:flex;flex-direction:column;gap:5px;padding:12px 14px;margin-bottom:8px;
  border-radius:var(--r-md);background:var(--surface-primary);box-shadow:inset 0 0 0 1px var(--divider);
}
.gTask.done{box-shadow:inset 0 0 0 1.5px var(--success-soft)}
.gTaskTop{display:flex;justify-content:space-between;align-items:baseline;gap:10px}
.gTaskTitle{font-size:.86rem;font-weight:700;color:var(--text-primary)}
.gTaskXp{flex:0 0 auto;font-size:.72rem;font-weight:700;color:var(--accent-warm-text)}
.gTask.done .gTaskXp{color:var(--success-text)}
.gTaskSub{font-size:.76rem;line-height:1.45;color:var(--text-secondary)}
.gTaskProgress{display:flex;align-items:center;gap:10px;font-size:.7rem;color:var(--text-muted)}
.gTaskProgress .gBar{flex:1}
.gTaskHint{font-size:.7rem;color:var(--text-muted)}
.gTaskActions{display:flex;align-items:center;gap:18px;margin-top:1px}
.gSwap,.gDecline{min-height:32px;padding:4px 0;font-size:.76rem}
.gDecline{color:var(--text-muted)}
.gFilters{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin:4px 0 8px}
.gSelect{display:flex;flex-direction:column;gap:3px;min-width:0}
.gSelect .lbl{font-size:.66rem;font-weight:700;color:var(--text-muted);letter-spacing:.04em}
.gSelect select{min-height:40px;width:100%;border-radius:var(--r-sm);padding:6px 8px;font:inherit;font-size:.8rem;
  color:var(--text-primary);background:var(--surface-primary);border:1px solid var(--border-subtle)}
.developerIntro{padding:14px 14px 0;font-size:var(--type-body);line-height:1.5;color:var(--text-secondary)}
.settingsSection > .group:has(.developerIntro) > .groupTitle{display:none}
.developerAnimation{display:flex;flex-direction:column;gap:8px;padding:14px}
.developerAnimation .gSelect{gap:6px}
.developerAnimation .gSelect .lbl,.developerSectionTitle{font-size:var(--type-meta);font-weight:700;color:var(--text-secondary);letter-spacing:0}
.developerAnimation .gSelect select{min-height:44px;font-size:var(--type-body);border-radius:var(--r-md);padding-inline:12px}
.developerPlay{width:100%;min-height:44px;padding-inline:14px;background:var(--action-secondary);font-size:var(--type-body)}
.developerSectionTitle{padding:2px 14px 8px}
.developerActions{display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:0 14px 14px}
.developerAction{
  min-height:46px;padding:10px;text-align:center;font-size:var(--type-body);font-weight:650;
  color:var(--text-brand);background:var(--brand-soft);border-radius:var(--r-md);
}
.developerAction:active{background:var(--action-secondary);transform:scale(.98)}
.gCollection .segmented{margin:4px 0}
.gCollection>.segmented{
  flex-wrap:nowrap;gap:2px;padding:3px;overflow-x:auto;scrollbar-width:none;
}
.gCollection>.segmented::-webkit-scrollbar{display:none}
.gCollection>.segmented button{
  flex:0 0 auto;min-width:max-content;min-height:34px;padding:5px 8px;
  font-size:.72rem;line-height:1.1;white-space:nowrap;
}
.gSet{display:flex;flex-direction:column;gap:6px;padding:11px 14px;margin-bottom:8px;border-radius:var(--r-md);background:var(--surface-primary);box-shadow:inset 0 0 0 1px var(--divider)}
.gSetSteps{display:flex;flex-direction:column;gap:2px}
.gSetStep{font-size:.7rem;color:var(--text-muted)}
.gSetStep.reached{color:var(--success-text);font-weight:650}
.gBack{align-self:flex-start;min-height:36px;padding:6px 0;font-size:.8rem}
.gItemDetail{display:flex;flex-direction:column;align-items:center;gap:6px;padding:18px 12px;margin:4px 0 10px;border-radius:var(--r-lg);background:var(--surface-primary);box-shadow:inset 0 0 0 1px var(--divider)}
.gItemDetail.r-selten{box-shadow:inset 0 0 0 1.5px var(--info-soft)}
.gItemDetail.r-episch{box-shadow:inset 0 0 0 1.5px var(--achievement-soft)}
.gItemDetail.r-legendaer{box-shadow:inset 0 0 0 1.5px var(--accent-warm);background:var(--accent-warm-soft)}
.gItemDetail.locked .kMotif{filter:grayscale(1);opacity:.3}
.gItemMeta{font-size:.74rem;color:var(--text-secondary);text-align:center}
/* Der Küchenfund: eine Kiste, keine Maschine. */
/* ---------- Küchenfund ----------
   Seltenheit als Farbe, überall dieselbe: --rar (Linie, Licht),
   --rar-soft (Fläche), --rar-text (Schrift). */
.r-gewoehnlich{--rar:var(--text-muted);--rar-soft:var(--fill-subtle);--rar-text:var(--text-secondary)}
.r-selten{--rar:var(--info);--rar-soft:var(--info-soft);--rar-text:var(--info-text)}
.r-episch{--rar:var(--achievement);--rar-soft:var(--achievement-soft);--rar-text:var(--achievement-text)}
.r-legendaer{--rar:var(--accent-warm);--rar-soft:var(--accent-warm-soft);--rar-text:var(--accent-warm-text)}

/* Die Kiste */
.gCrate{position:relative;width:148px;height:130px;margin:0 auto;--lid:0}
.gCrate svg{position:relative;z-index:1;width:100%;height:100%;overflow:visible}
.gCrateShadow{fill:var(--text-primary);opacity:.12}
.gCrateFront{fill:var(--gami-salbei)}
.gCrateShade{fill:var(--gami-shade)}
.gCrateLidTop{fill:var(--gami-morgen)}
.gCrateBand,.gCrateBow{fill:var(--gami-salbei-2)}
.gCrateKnot{fill:var(--gami-golden-2)}
.gCrateLid{transform-box:view-box;transform-origin:80px 58px}
.gCrateGlow{position:absolute;left:50%;top:52%;width:190px;height:190px;margin:-95px 0 0 -95px;border-radius:50%;
  background:radial-gradient(circle,color-mix(in srgb,var(--rar,var(--accent-warm)) 42%,transparent) 0,transparent 68%);opacity:0;pointer-events:none}
.gCrateCount{position:absolute;z-index:2;right:2px;top:20px;min-width:34px;padding:3px 8px;border-radius:99px;background:var(--brand-primary);color:var(--text-on-brand);font-size:.8rem;font-weight:800;text-align:center;box-shadow:0 0 0 3px var(--surface-elevated)}
.gSpark{position:absolute;z-index:2;width:7px;height:7px;border-radius:50%;background:var(--accent-warm);opacity:0}
.gSpark.s1{left:14px;top:34px}.gSpark.s2{right:10px;top:58px}.gSpark.s3{left:36px;top:6px}
.gCrate.ruht{filter:saturate(.35);opacity:.72}
.gCrate.schwebt{--rar:var(--accent-warm)}
.gCrate.schwebt svg{animation:gSchweben 3.2s var(--ease) infinite}
.gCrate.schwebt .gCrateGlow{animation:gGluehen 3.2s var(--ease) infinite}
.gCrate.schwebt .gCrateLid{animation:gDeckelZucken 3.2s var(--ease) infinite}
.gCrate.schwebt .gSpark{animation:gFunkeln 2.4s var(--ease) infinite}
.gCrate.schwebt .gSpark.s2{animation-delay:.8s}.gCrate.schwebt .gSpark.s3{animation-delay:1.6s}
@keyframes gSchweben{0%,100%{transform:translateY(0)}50%{transform:translateY(-6px)}}
@keyframes gGluehen{0%,100%{opacity:.45;transform:scale(.92)}50%{opacity:.85;transform:scale(1.04)}}
@keyframes gDeckelZucken{0%,78%,100%{transform:none}84%{transform:translateY(-3px) rotate(-2deg)}90%{transform:translateY(-1px) rotate(1.5deg)}}
@keyframes gFunkeln{0%,100%{opacity:0;transform:scale(.3)}40%{opacity:1;transform:scale(1)}70%{opacity:0;transform:scale(.4)}}

/* Das Blatt */
.gLootHero{display:flex;flex-direction:column;align-items:center;text-align:center;padding:10px 6px 18px}
.gLootTitle{margin:6px 0 0;font-size:1.28rem;font-weight:780;letter-spacing:-.01em;color:var(--text-primary)}
.gLootLead{margin:6px auto 0;max-width:30ch;font-size:.88rem;line-height:1.5;color:var(--text-secondary)}
.gLootCta{align-self:stretch;margin-top:18px}
.gLootPanel{margin-top:12px;padding:16px;border-radius:var(--r-lg);background:var(--surface-primary);box-shadow:inset 0 0 0 1px var(--divider)}
.gLootPanelTitle{margin:0 0 12px;font-size:.74rem;font-weight:750;letter-spacing:.07em;text-transform:uppercase;color:var(--text-muted)}
.gLootStat+.gLootStat{margin-top:14px}
.gLootStatHead{display:flex;justify-content:space-between;align-items:baseline;gap:12px;margin-bottom:6px;font-size:.88rem;color:var(--text-primary)}
.gLootStatHead b{font-size:.82rem;font-weight:650;color:var(--text-secondary)}
.gLootStatNote{margin:6px 0 0;font-size:.76rem;line-height:1.45;color:var(--text-muted)}
.gLootPanel .gBar,.gStepResult .gBar{height:6px;background:var(--fill-strong)}
.gLootPanel .gBar i,.gStepResult .gBar i{background:var(--brand-primary)}
.gLootStat.r-selten .gBar i,.gLootStat.r-legendaer .gBar i{background:var(--rar)}
.gLootWays{list-style:none;margin:0 0 14px;padding:0}
.gLootWays li{display:flex;align-items:flex-start;gap:12px;padding:9px 0}
.gLootWays li+li{border-top:1px solid var(--divider)}
.gLootWayIcon{flex:0 0 22px;height:22px;border-radius:50%;box-shadow:inset 0 0 0 1.5px var(--border-strong);font-size:.72rem;font-weight:800;line-height:22px;text-align:center;color:var(--text-on-brand)}
.gLootWays li.fertig .gLootWayIcon{background:var(--success-soft);color:var(--success-text);box-shadow:none}
.gLootWayText{display:flex;flex-direction:column;gap:2px;font-size:.88rem;color:var(--text-primary)}
.gLootWayText b{font-weight:600}
.gLootWayText small{font-size:.76rem;color:var(--text-muted)}

/* Wahrscheinlichkeiten und Regeln */
.gRates{margin-top:12px;padding:0 16px;border-radius:var(--r-lg);background:var(--surface-primary);box-shadow:inset 0 0 0 1px var(--divider)}
.gRates>summary{padding:15px 0;font-size:.9rem;font-weight:650;color:var(--text-primary);cursor:pointer;list-style:none;display:flex;justify-content:space-between;align-items:center}
.gRates>summary::-webkit-details-marker{display:none}
.gRates>summary::after{content:"";width:8px;height:8px;border-right:2px solid var(--text-muted);border-bottom:2px solid var(--text-muted);transform:rotate(45deg);transition:transform .2s var(--ease)}
.gRates[open]>summary::after{transform:rotate(-135deg)}
.gRateBar{display:flex;height:10px;border-radius:99px;overflow:hidden;gap:2px;margin:2px 0 10px}
.gRateBar i{display:block;flex:1 1 0;background:var(--rar-soft)}
.gRateBar i.r-gewoehnlich{background:var(--border-strong)}
.gRateBar i:not(.r-gewoehnlich){background:var(--rar)}
.gRules{margin:14px 0 16px}
.gRules dt{font-size:.8rem;font-weight:700;color:var(--text-primary)}
.gRules dd{margin:2px 0 11px;font-size:.8rem;line-height:1.5;color:var(--text-secondary)}

/* Die Bühne */
.gReveal{position:relative;display:flex;flex-direction:column;align-items:center;min-height:360px;padding:24px 16px 18px;border-radius:var(--r-lg);overflow:hidden;cursor:pointer;
  background:radial-gradient(120% 70% at 50% 18%,color-mix(in srgb,var(--rar) 16%,transparent),transparent 70%),var(--surface-primary);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--rar) 38%,var(--divider))}
.gRevealLight{position:absolute;left:50%;top:128px;width:0;height:0;pointer-events:none}
.gRays{position:absolute;left:-190px;top:-190px;width:380px;height:380px;border-radius:50%;opacity:0;
  background:repeating-conic-gradient(from 0deg,color-mix(in srgb,var(--rar) 34%,transparent) 0 7deg,transparent 7deg 22deg);
  -webkit-mask:radial-gradient(circle,#000 0,transparent 68%);mask:radial-gradient(circle,#000 0,transparent 68%)}
.gRing{position:absolute;left:-40px;top:-40px;width:80px;height:80px;border-radius:50%;box-shadow:0 0 0 3px var(--rar);opacity:0}
.gBurst>span{position:absolute;left:0;top:0;width:0;height:0}
.gBurst i{position:absolute;left:-4px;top:-4px;width:8px;height:8px;border-radius:50%;background:var(--rar);opacity:0}
.gReveal .gCrate{position:absolute;left:50%;top:62px;margin-left:-74px;transition:opacity .3s var(--ease),transform .45s var(--ease)}
.gRevealCard{position:relative;z-index:2;display:flex;flex-direction:column;align-items:center;width:100%;opacity:0;pointer-events:none}
.gStepBranch{font-size:.78rem;color:var(--text-secondary);margin-bottom:14px}
.gStepBranch b{color:var(--text-primary);font-weight:650}
.gStepItem{display:flex;flex-direction:column;align-items:center;gap:10px}
.gItemPlate{display:grid;place-items:center;width:132px;height:132px;border-radius:var(--r-lg);
  background:radial-gradient(circle at 50% 40%,var(--surface-elevated),var(--rar-soft));
  box-shadow:0 0 0 1.5px color-mix(in srgb,var(--rar) 55%,transparent),0 14px 34px color-mix(in srgb,var(--rar) 26%,transparent)}
.gItemBig{width:92px;height:92px}
.gItemBig.m-kuhlschrank{width:56px}
.gItemBig.m-wandregal{height:14px;margin:0}
.gItemBig.m-teppich,.gItemBig.m-boden{height:38px;margin:0}
.gItemBig.m-maskottchen{-webkit-clip-path:polygon(0 18%,100% 18%,62% 86%,38% 86%);clip-path:polygon(0 18%,100% 18%,62% 86%,38% 86%)}
.gItemBig.m-kuchenhintergrund{background-image:linear-gradient(var(--gami-shade) 1px,transparent 1px),linear-gradient(90deg,var(--gami-shade) 1px,transparent 1px);background-size:14px 14px}
.gItemBig.m-boden{background-image:repeating-linear-gradient(90deg,transparent 0 16px,var(--gami-shade) 16px 17px)}
.gStepRarity{margin-top:4px;padding:4px 12px;border-radius:99px;background:var(--rar-soft);color:var(--rar-text);font-size:.7rem;font-weight:800;letter-spacing:.09em;text-transform:uppercase}
.gItemName{font-size:1.22rem;font-weight:780;letter-spacing:-.01em;text-align:center;color:var(--text-primary)}
.gStepResult{align-self:stretch;margin-top:18px;display:flex;flex-direction:column;gap:2px}
.gResultRow{display:flex;gap:12px;align-items:flex-start;padding:11px 12px;border-radius:var(--r-md);background:var(--fill-subtle);text-align:left}
.gResultRow+.gResultRow{margin-top:6px}
.gResultIcon{flex:0 0 26px;height:26px;border-radius:50%;background:var(--surface-elevated);font-size:.8rem;line-height:26px;text-align:center;color:var(--text-secondary)}
.gResultRow.neu .gResultIcon,.gSetLine.reached .gResultIcon{background:var(--success-soft);color:var(--success-text)}
.gResultRow.hervor .gResultIcon{background:var(--rar-soft);color:var(--rar-text)}
.gResultText{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;font-size:.86rem;color:var(--text-primary)}
.gResultText b{font-weight:650}
.gResultText small{font-size:.76rem;line-height:1.4;color:var(--text-secondary)}
.gResultText .gBar{margin-top:6px}
.gRevealActions{display:flex;flex-direction:column;gap:8px;margin-top:14px}

/* Phasen: laden → auf → fund → fertig */
.gReveal.phase-laden .gCrate{--rar:inherit}
.gReveal.phase-laden .gCrate svg{animation:gSpannen .85s var(--ease) both}
.gReveal.phase-laden .gCrateGlow{animation:gAufladen .85s var(--ease) both}
.gReveal.phase-auf .gCrateGlow{opacity:1;transform:scale(1.25);transition:transform .4s var(--ease)}
.gReveal.phase-auf .gCrateLid{animation:gDeckelAuf .45s cubic-bezier(.2,.7,.3,1) both}
.gReveal.phase-auf .gRays{animation:gStrahlen 1.6s var(--ease) both}
.gReveal.phase-auf .gRing{animation:gRingAus .6s var(--ease) both}
.gReveal.phase-auf .gBurst i{animation:gFunkenFlug .8s cubic-bezier(.15,.7,.3,1) both}
.gReveal.phase-auf .gBurst .weit i{animation-name:gFunkenWeit}
.gReveal.phase-auf .gBurst .nah i{animation-name:gFunkenNah}
.gReveal.phase-fund .gCrate,.gReveal.phase-fertig .gCrate{opacity:0;transform:translateY(26px) scale(.9)}
.gReveal.phase-fund .gCrateLid{transform:translateY(-70px) rotate(-24deg);opacity:0}
.gReveal.phase-fund .gRays{opacity:.55;animation:gDrehen 14s linear infinite}
.gReveal.phase-fertig .gRays{opacity:.35;animation:gDrehen 20s linear infinite}
.gReveal.r-gewoehnlich.phase-fund .gRays,.gReveal.r-gewoehnlich.phase-fertig .gRays{opacity:.18}
.gReveal.phase-fund .gRevealCard,.gReveal.phase-fertig .gRevealCard{opacity:1;pointer-events:auto}
.gReveal.phase-fund .gStepBranch{animation:gAuf .4s var(--ease) both}
.gReveal.phase-fund .gItemPlate{animation:gAufsteigen .6s cubic-bezier(.2,1.3,.4,1) both}
.gReveal.phase-fund .gStepRarity{animation:gAuf .4s var(--ease) .18s both}
.gReveal.phase-fund .gItemName{animation:gAuf .4s var(--ease) .26s both}
.gReveal.phase-fund .gStepResult{opacity:0}
.gReveal.phase-fertig .gStepResult{animation:gAuf .4s var(--ease) both}
@keyframes gSpannen{0%{transform:none}20%{transform:rotate(-2deg)}35%{transform:rotate(2.5deg)}50%{transform:rotate(-3.5deg) translateY(-2px)}65%{transform:rotate(4deg) translateY(-3px)}80%{transform:rotate(-4deg) translateY(-4px) scale(1.03)}100%{transform:translateY(-6px) scale(1.06)}}
@keyframes gAufladen{from{opacity:0;transform:scale(.6)}to{opacity:1;transform:scale(1.1)}}
@keyframes gDeckelAuf{from{transform:none}to{transform:translateY(-70px) rotate(-24deg);opacity:0}}
@keyframes gStrahlen{0%{opacity:0;transform:scale(.4) rotate(0)}30%{opacity:1}100%{opacity:.55;transform:scale(1) rotate(40deg)}}
@keyframes gDrehen{from{transform:rotate(40deg)}to{transform:rotate(400deg)}}
@keyframes gRingAus{0%{opacity:.9;transform:scale(.4)}100%{opacity:0;transform:scale(3.2)}}
@keyframes gFunkenFlug{0%{opacity:0;transform:translateY(0) scale(.4)}25%{opacity:1}100%{opacity:0;transform:translateY(-92px) scale(1)}}
@keyframes gFunkenWeit{0%{opacity:0;transform:translateY(0) scale(.4)}25%{opacity:1}100%{opacity:0;transform:translateY(-118px) scale(1)}}
@keyframes gFunkenNah{0%{opacity:0;transform:translateY(0) scale(.4)}25%{opacity:1}100%{opacity:0;transform:translateY(-70px) scale(.9)}}
@keyframes gAufsteigen{from{opacity:0;transform:translateY(34px) scale(.6)}to{opacity:1;transform:none}}
@keyframes gAuf{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){
  .gCrate *,.gReveal *{animation:none!important;transition:none!important}
}
.mascotBubble.manualHelp .companionTopic{flex:1 0 auto}
.companionRecipe>p{color:var(--text-secondary);font-size:.85rem;line-height:1.5}
.companionLabel,.eyebrow{font-size:.65rem;letter-spacing:.12em;font-weight:750;color:var(--text-secondary)}
/* Der nächste Einkauf und der Wochenrückblick sind die beiden großen
   Einstiege auf Start. Sie sprechen deshalb dieselbe warme Sprache:
   heller Verlauf, feine rosa Kontur, ruhige Kennzahlenfelder und eine
   abgetrennte Fußhandlung. Nur der Rückblick trägt das Wesen als
   unbewegtes Absendermotiv; die Einkaufskarte bleibt rein sachlich. */
.shoppingHero .groupBody{
  background:var(--review-wash);
  border:1px solid color-mix(in srgb,var(--mascot-pink) 22%,transparent);
  box-shadow:0 12px 34px var(--gami-shade);
}
.shoppingHero .bigAction{
  display:block;background:transparent;color:var(--text-primary);
  padding:14px 16px 13px;
}
.shoppingHero .bigAction:active{background:var(--fill-subtle)}
/* Zeile 1: wofür und für wann, dazu der Winkel. Kein Kreis mit Pfeil
   — die ganze Fläche ist die Schaltfläche, und der Winkel sagt das
   in derselben Sprache wie jede andere Zeile der App. */
.baMeta{display:flex;align-items:center;gap:8px}
.baLabel{
  flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:var(--type-meta);font-weight:700;color:var(--text-brand);letter-spacing:-.005em;
}
.baChev{
  flex:0 0 auto;width:7px;height:7px;opacity:.75;
  border-right:2px solid var(--text-brand);
  border-top:2px solid var(--text-brand);
  transform:rotate(45deg);
}
/* Zeile 2 folgt den Kennzahlenfeldern des Wochenrückblicks. Anzahl
   und Preis sind gleichrangig, ihre kurzen Beschriftungen stehen
   jeweils direkt darunter. */
.baLine{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-top:14px}
.baMetric{
  min-width:0;min-height:72px;display:flex;flex-direction:column;align-items:flex-start;
  justify-content:center;padding:10px 12px;background:var(--surface-primary);border-radius:var(--r-md);
}
.baAmount{gap:2px}
.baCount{font-size:var(--type-title);line-height:1.05;letter-spacing:-.025em;font-weight:750;font-variant-numeric:tabular-nums}
.baUnit,.baMetricLabel{font-size:var(--type-meta);font-weight:500;color:var(--text-secondary);line-height:1.35;margin-top:2px}
.baEmpty{
  grid-column:1 / -1;padding:12px;background:var(--surface-primary);border-radius:var(--r-md);
  font-size:var(--type-title);font-weight:700;letter-spacing:-.02em;line-height:1.2;
}
.baMoneyMetric{gap:2px}
.baMoney{
  max-width:100%;font-size:var(--type-title);font-weight:750;line-height:1.05;
  font-variant-numeric:tabular-nums;letter-spacing:-.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
/* Zeile 3: die Motive der ersten Positionen, leicht überlappend wie
   ein Stapel Karten. Sie stehen auf einer hellen Scheibe, damit sie
   sich vom Grün lösen — ohne Scheibe verschwinden die dunklen Teile
   der Zeichnungen darin. */
.baStack{display:flex;align-items:center;margin-top:12px;padding:1px 2px}
.baChip{
  width:28px;height:28px;border-radius:50%;flex:0 0 auto;
  display:grid;place-items:center;
  background:var(--surface-primary);
  box-shadow:0 0 0 2px color-mix(in srgb,var(--brand-secondary) 72%,var(--surface-primary));
  margin-left:-8px;
}
.baChip:first-child{margin-left:0}
.baChip .pIcon{width:21px;height:21px}
.shoppingHero .baRest{
  margin-left:9px;font-size:.8rem;font-weight:620;
  color:var(--text-secondary);font-variant-numeric:tabular-nums;
}

.homeShortcuts{display:flex;border-top:1px solid var(--divider)}
.homeShortcuts button{
  color:var(--text-brand);min-height:48px;flex:1;
  font-size:var(--type-body);font-weight:700;text-align:center;letter-spacing:-.005em;
}
.homeShortcuts button:hover,.homeShortcuts button:active{background:var(--fill-subtle)}
.homeProgress{margin-top:24px;border-top:1px solid var(--border-subtle);padding-top:4px}
.homeProgress>summary{padding:16px 2px;color:var(--text-secondary);font-size:.86rem;font-weight:650}
.homeProgress .group{margin-top:0}
.captureCard{padding:24px;border:1px solid var(--border-subtle);border-radius:var(--r-lg);background:var(--surface-primary)}
.captureCard h2{font-size:1.25rem;line-height:1.35;letter-spacing:-.03em;margin:12px 0}
.captureCard p{font-size:.84rem;line-height:1.6;color:var(--text-secondary);margin-bottom:18px}
.captureCard .cta{width:100%;font-size:.85rem}
.welcomeCard{padding:28px 24px;margin-top:16px}
.welcomeTitle{font-size:clamp(1.65rem,5vw,2.5rem);line-height:1.2;letter-spacing:-.025em;max-width:580px;margin:12px 0;padding:0}
.welcomeLead{font-size:1rem;line-height:1.65;max-width:580px}
.welcomePoints{display:grid;gap:18px;margin:24px 0;padding:0;list-style:none}
.welcomePoints li{padding-left:20px;font-size:.9rem}
.welcomePoints li b,.welcomePoints li span{display:block}
.welcomePoints li span{margin-top:4px;font-size:.83rem}
.welcomePrivacy{font-size:.76rem;color:var(--text-secondary);text-align:center;line-height:1.5;margin:10px 0 14px}
.welcomeWhy{border-top:1px solid var(--divider);padding-top:14px;font-size:.8rem;color:var(--text-secondary)}
.welcomeWhy>summary{min-height:30px}
.settingsSection{margin-top:12px;background:var(--surface-primary);border:1px solid var(--divider);border-radius:var(--r-md)}
.settingsSection>summary{padding:20px;font-size:.94rem;font-weight:650;cursor:pointer}
.settingsSection>.group{margin:0;padding:0 12px 12px}
.settingsSection>.group>.groupTitle{padding:0 6px 10px}
.settingsSection .groupBody{box-shadow:none;border:0}
@media(min-width:900px){
  .shell{max-width:1440px;margin:0 auto}
  .nav{width:220px;flex-basis:220px;padding:30px 16px;background:var(--nav-bg);gap:7px}
  .nav::before{padding:4px 12px 34px;font-size:1.1rem}
  .nav button{height:48px;border-radius:var(--r-md);font-size:.9rem}
  .nav button[aria-current="page"] svg{box-shadow:none;background:none}
  .nav button[aria-current="page"] .navImageIcon{box-shadow:none;background:none}
  .appbar,.largeTitle,.calendarStripSlot,main{max-width:1100px}
  .largeTitle{padding-top:12px}
  .largeTitle h1{font-size:2.35rem}
  main{padding-top:10px}
  /* Auf dem Rechner an der Inhaltsspalte ausgerichtet, nicht am
     Fenster: Seitenleiste 220 px, Spalte mit 32 px Rand. */
  /* Eine Quelle für beide: die Blase hängt an derselben Kante wie die
     Küche, sonst zeigt ihr Zipfel am Rechner ins Leere. */
  :root{--companion-left:calc(max(0px, (100vw - 1440px) / 2) + 220px + 32px)}
  .companion{
    left:var(--companion-left);right:auto;
    width:min(1036px, calc(100vw - 220px - 64px));bottom:16px;
  }
  main{padding-bottom:calc(var(--stage-h) + 40px)}
  .toast{bottom:calc(var(--stage-h) + 28px)}
  .cartBar{bottom:calc(var(--stage-h) + 28px)}
  .startLayout{gap:28px}
  .startAside{flex-basis:300px;padding-top:14px;gap:26px}
  .shoppingHero .bigAction{padding:22px 26px}
  .welcomeCard{padding:36px;max-width:760px}
  .welcomePoints{grid-template-columns:repeat(3,1fr);gap:24px}
}
@media(max-width:400px){
  :root{--pad:16px}
  .companionAction{font-size:.75rem;padding:9px 10px}
  .shoppingHero .bigAction{padding:14px 15px 15px}
}

@media (prefers-reduced-motion:reduce){
  *{transition:none !important;animation:none !important}
}

/* Release-Schliff: gemeinsame Lesbarkeit und erreichbare Aktionen.
   Keine neue Farbwelt; auch die kleinen Ansichten nutzen die Tokens. */
.rowTitle,.rowSub,.sheetTitle,.groupTitle,.rvHead2{overflow-wrap:anywhere}
.segmented{flex-wrap:wrap}
.segmented button{min-height:44px;min-width:0;flex:1 1 auto;white-space:normal;line-height:1.3}
.srcnote,.hintRow,.pLeadSub,.pActionWhy,.stockAdjustValue,.shotSub{font-size:var(--type-body);line-height:1.5}
.weekWeekday,.weekMoney,.weekAlert,.kWt,.kBetrag{font-size:var(--type-meta)}
.nav button{font-size:min(.75rem,12px);padding-left:0;padding-right:0;min-width:0}
.weekDay{min-width:48px}
.weekMoney,.weekAlert{white-space:nowrap}
.kTag{min-height:44px}
.kNav,.infoBtn,.rvClose{min-width:44px;min-height:44px}
.infoBtn{flex-shrink:0;background:transparent;font-size:.75rem;width:32px;height:32px;min-width:32px;min-height:32px;margin:0;position:relative}
.infoBtn::before{content:"";position:absolute;inset:7px;border:1px solid var(--border-subtle);border-radius:50%;pointer-events:none}
.groupTitle{align-items:center;gap:4px}
.rvClose{margin:-10px -10px -10px 0}
.pillBtn,.hintDecisionRow .pillBtn{min-height:44px}
.sheetHeader{position:sticky;top:-8px;z-index:2;display:flex;align-items:center;gap:12px;
  background:var(--surface-elevated);padding:8px 0;border-bottom:1px solid var(--divider);margin-bottom:12px}
.sheetHeader .sheetTitle{flex:1;min-width:0;font-size:1.15rem}
.sheetClose{flex:0 0 44px;min-height:44px;border-radius:50%;font-size:1.5rem;
  color:var(--text-secondary);background:var(--fill-subtle);line-height:1}
.sheetBody{overscroll-behavior:contain;scroll-padding-top:76px}
body:has(.sheet:not([hidden])){overflow:hidden}
.facts{grid-template-columns:minmax(0,1fr) minmax(0,1.3fr)}
.facts dt{white-space:normal;overflow-wrap:anywhere}
.captureEntry .shotHead{margin-top:16px}
.captureEntry .captureInfo{margin-top:16px;padding-top:12px}
.captureEntry .shotHead .shotSub{font-size:var(--type-body)}
.welcomeCard{padding:22px 20px;margin-top:8px}
.welcomeCard .eyebrow{font-size:var(--type-meta);letter-spacing:.04em}
.welcomeLead{line-height:1.5;padding:0 0 8px}
/* Einzug behalten: der Aufzählungspunkt (::before) steht bei left:0 —
   ohne Einzug lag er auf dem ersten Buchstaben. */
.welcomePoints li{padding-left:16px}
.save{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px 12px}
.save .pillBtn{grid-column:2;justify-self:start}
.save .amt{align-self:start}
.save .txt b{font-size:var(--type-body)}
.pLeadVal{font-size:2rem;line-height:1.2}
.receiptRow{width:100%;text-align:left}
.barTitle{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.barActions{flex-shrink:0}
.shotRow{flex-wrap:wrap}
.shotRow .cta,.shotRow .cta.light{flex:1 1 auto;min-width:0;white-space:normal}
.item .main>.nm{width:100%;text-align:left;min-height:32px}
.item .main>.pill{margin-top:4px}
.companion .mascotBubble:not(.manualHelp) .mText{display:block;-webkit-line-clamp:unset;overflow:visible}
.companion .mascotBubble:not(.manualHelp):not([hidden]){left:76px;max-height:50vh;overflow-y:auto}
.companion .mGo{min-height:36px}
.gTaskTop{flex-wrap:wrap}
.expHeaderLevel{color:var(--mascot-pink-text)}
.gBar{background:var(--mascot-pink-track)}
.gBar i{background:var(--mascot-pink)}
.gTaskXp{color:var(--mascot-pink-text)}
.gTaskSub{font-size:var(--type-body)}
.gTaskActions{flex-wrap:wrap;gap:8px 14px}
.gTaskActions button{min-height:44px}
.gTaskHint,.gTaskProgress{font-size:var(--type-meta)}
.basket li{display:grid;grid-template-columns:32px minmax(0,1fr) minmax(0,1fr) 36px;gap:10px 8px;align-items:center;padding:14px 0}
.basket li>.pIcon{grid-column:1;grid-row:1}
.basket .bn{grid-column:2 / 4;grid-row:1;min-width:0;overflow-wrap:anywhere}
.basket .del{grid-column:4;grid-row:1;width:36px;min-height:44px}
.basketQuantity{grid-column:1 / 3;grid-row:2;min-width:0;display:grid;gap:4px}
.basketQuantity>span{font-size:var(--type-meta);color:var(--text-secondary)}
.basket .stepWrap{justify-content:flex-start;gap:8px;min-width:0;min-height:44px}
.basketPrice{grid-column:3 / 5;grid-row:2;min-width:0;display:grid;gap:4px}
.basketPrice>span{font-size:var(--type-meta);color:var(--text-secondary)}
.basket .priceIn{width:100%;max-width:100%;min-width:0;text-align:left}
.row2{grid-template-columns:repeat(2,minmax(0,1fr))}
.row2>.field{min-width:0}
.swapRow{flex-wrap:wrap}
.swapRow .rowMain{flex-basis:100%}
.swapRow .rowActions{width:100%;justify-content:flex-start}
.useUpIntro{margin:16px 0 20px}
.useUpIntro h2{font-size:1.2rem;margin:0 0 6px}
.useUpIntro p,.putAwayHelp{font-size:var(--type-body);line-height:1.5;color:var(--text-secondary);margin:0}
.useUpItem{padding:16px}
.useUpItem+.useUpItem{border-top:1px solid var(--divider)}
.useUpItemHead{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.useUpItemHead .rowMain{flex:1;min-width:120px}
.useUpItemHead h3{font-size:1rem;margin:0;font-weight:650}
.useUpItemHead p{font-size:var(--type-meta);margin:4px 0;color:var(--text-secondary)}
.useUpItemHead>.pIcon{width:32px;height:32px}
.useUpSafety{font-size:var(--type-body);line-height:1.5;color:var(--warning-text);margin:8px 0}
.useUpActions{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}
.useUpActions button{flex:1 1 auto}
.useUpActions button:first-child{background:var(--brand-soft);color:var(--text-brand)}
.useUpIdeas{margin-top:22px;background:var(--surface-primary);border:1px solid var(--divider);border-radius:var(--r-lg);padding:0 16px 12px}
.useUpIdeas>summary{font-size:var(--type-title);font-weight:650;min-height:52px;padding:14px 0;cursor:pointer}
.recipeDiscoveryHead{margin:10px 0 16px;padding:17px 18px;border:1px solid var(--divider);border-radius:var(--r-lg);background:linear-gradient(145deg,var(--brand-soft),var(--surface-primary))}
.recipeDiscoveryHead .eyebrow{display:block;margin-bottom:5px}
.recipeDiscoveryHead h2{margin:0;color:var(--text-primary);font-size:1.35rem;letter-spacing:-.025em}
.recipeDiscoveryHead p{margin:5px 0 0;color:var(--text-secondary);font-size:var(--type-body);line-height:1.4}
.recipeDiscoveryResults{margin-top:0;padding:12px 14px 15px}
.recipeDiscoveryResults .recipeFilters{margin:0 -2px 5px}
.recipeEntryCta{display:flex;align-items:center;gap:11px;width:100%;min-height:70px;margin:16px 0;padding:12px 15px;border:1px solid var(--divider);border-radius:var(--r-lg);background:var(--surface-primary);color:var(--text-primary);text-align:left;box-shadow:var(--shadow-lift)}
.recipeEntryIcon{display:grid;place-items:center;flex:0 0 38px;height:38px;border-radius:50%;background:var(--brand-soft);font-size:1.15rem}
.recipeEntryCopy{display:grid;gap:3px;flex:1;min-width:0}
.recipeEntryCopy b{font-size:.9rem;font-weight:700}
.recipeEntryCopy small{color:var(--text-secondary);font-size:var(--type-meta);line-height:1.35}
.useUpIdeas .row{flex-wrap:wrap;gap:8px}
.useUpIdeas .rowMain{flex-basis:100%}
/* Rezeptfilter: eine Zeile Chips, wischbar statt umbrechend. */
.recipeFilters{display:flex;gap:6px;overflow-x:auto;padding:2px 0 12px;scrollbar-width:none}
.recipeFilters::-webkit-scrollbar{display:none}
.recipeChip{
  flex:0 0 auto;min-height:36px;padding:0 13px;border-radius:99px;font-size:.8rem;font-weight:650;white-space:nowrap;
  background:var(--surface-primary);color:var(--text-secondary);box-shadow:inset 0 0 0 1px var(--border-subtle);
}
.recipeChip.on{background:var(--action-primary);color:var(--text-on-brand);box-shadow:none}
.useUpIdeas .rowValue{font-size:var(--type-meta);margin-right:auto}
.putAwayHelp{padding:14px 16px}
.putAwayRow{gap:12px;background:var(--surface-primary)}
.putAwayRow .box{flex:0 0 26px}
.putAwayRemove{min-width:44px;min-height:44px;color:var(--text-secondary);font-size:1.2rem}
@media(max-width:360px){
  .largeTitle.mitLevel{grid-template-columns:minmax(0,1fr) 128px;column-gap:7px}
  .largeTitle.mitLevel h1{font-size:1.5rem}
  .expHeaderNext{font-size:.53rem}
}
@media(min-width:900px){
  .largeTitle.mitLevel{grid-template-columns:minmax(0,1fr) 190px;column-gap:24px}
  .largeTitle.mitLevel h1{font-size:2.35rem}
  .welcomeCard{padding:32px}
}

/* ---------------- Kurze Entscheidungsblätter (choiceSheet) ----------------
   Große Antworten, kein Fließtext. Die Wirkung einer Antwort steht im
   Detail-Blatt des Produkts, nicht hier. */
.choiceList{display:flex;flex-direction:column;gap:8px}
.choiceBtn{
  width:100%;min-height:54px;padding:0 18px;border-radius:var(--r-md);text-align:left;
  background:var(--fill-subtle);color:var(--text-primary);font-size:1rem;font-weight:620;
  transition:transform .18s var(--spring),background .14s linear;
}
.choiceBtn.on{background:var(--action-primary);color:var(--text-on-brand)}
.choiceBtn:active{transform:scale(.98)}
.choiceLink{align-self:center;margin-top:4px}

/* ---------------- „Jetzt zu tun": wischbare Zeilen ---------------- */
.todoSwipe > .row{background:transparent}
.todoSwipe.swiping > .row{background:var(--surface-primary)}

/* ---------------- „Liste vorbereiten" (prepFlow in views.js) ---------------- */
.prepEntry{
  display:flex;align-items:center;gap:12px;width:100%;margin:2px 0 12px;padding:12px 14px;
  border-radius:var(--r-lg);background:var(--surface-primary);box-shadow:inset 0 0 0 1px var(--divider);
  text-align:left;color:var(--text-primary);transition:transform .18s var(--spring);
}
.prepEntry:active{transform:scale(.985)}
.prepEntryMark{
  flex:0 0 auto;width:34px;height:34px;border-radius:50%;display:grid;place-items:center;
  font-weight:750;font-size:.95rem;background:var(--success-soft);color:var(--success-text);
}
.prepEntry.offen .prepEntryMark{background:var(--action-primary);color:var(--text-on-brand)}
.prepEntryText{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.prepEntryText b{font-size:1rem;font-weight:680}
.prepEntryText small{font-size:.82rem;color:var(--text-secondary)}

body.prepOffen{overflow:hidden}
.prep{
  position:fixed;inset:0;z-index:110;display:flex;flex-direction:column;
  padding:calc(var(--safe-top) + 14px) var(--pad) calc(var(--safe-bottom) + 18px);
  background:var(--bg-primary);animation:prepEin .22s var(--ease);
}
@keyframes prepEin{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
.prepTop{display:flex;align-items:center;gap:12px;min-height:44px}
.prepClose{
  width:36px;height:36px;border-radius:50%;font-size:1.35rem;line-height:1;
  background:var(--fill-subtle);color:var(--text-secondary);
}
.prepBar{flex:1;height:5px;border-radius:99px;background:var(--fill-subtle);overflow:hidden}
.prepBar i{display:block;height:100%;width:0;border-radius:inherit;background:var(--action-primary);transition:width .3s var(--ease)}
.prepCount{min-width:34px;text-align:right;font-size:.85rem;font-weight:650;color:var(--text-secondary)}
.prepStage{position:relative;flex:1;display:grid;place-items:center;margin:14px 0}
.prepCard{
  --ja:0;--nein:0;
  grid-area:1/1;position:relative;width:100%;max-width:360px;min-height:min(420px,58vh);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;
  padding:28px 22px;border-radius:var(--r-lg);text-align:center;
  background:var(--surface-elevated);box-shadow:var(--shadow-lift),inset 0 0 0 1px var(--divider);
  touch-action:none;-webkit-user-select:none;user-select:none;cursor:grab;
  transition:transform .28s var(--spring),opacity .2s linear;
}
.prepCard.zieht{transition:none;cursor:grabbing}
.prepCard.hinten{transform:scale(.94) translateY(14px);opacity:.55;pointer-events:none}
.prepCard.weg{transition:transform .21s var(--ease),opacity .21s linear;opacity:0}
.prepCard.weg.rechts{transform:translateX(120%) rotate(14deg)}
.prepCard.weg.links{transform:translateX(-120%) rotate(-14deg)}
.prepCard .pIcon{width:88px;height:88px;margin-bottom:10px}
.prepEyebrow{font-size:.78rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-brand)}
.prepTitle{font-size:1.55rem;font-weight:720;line-height:1.2;letter-spacing:-.015em;color:var(--text-primary);text-wrap:balance}
.prepSub{font-size:1rem;color:var(--text-secondary)}
.prepStamp{
  position:absolute;top:18px;padding:6px 12px;border-radius:var(--r-sm);
  font-size:.85rem;font-weight:750;letter-spacing:.02em;pointer-events:none;
}
.prepStamp.ja{left:18px;opacity:var(--ja);background:var(--success-soft);color:var(--success-text)}
.prepStamp.nein{right:18px;opacity:var(--nein);background:var(--fill-strong);color:var(--text-primary)}
.prepDone{cursor:default;touch-action:auto}
.prepDoneMark{
  width:72px;height:72px;border-radius:50%;display:grid;place-items:center;margin-bottom:10px;
  font-size:2rem;font-weight:700;background:var(--success-soft);color:var(--success-text);
  animation:prepPop .4s var(--spring);
}
@keyframes prepPop{from{transform:scale(.6);opacity:0}to{transform:none;opacity:1}}
.prepActions{display:flex;gap:10px}
.prepBtn{
  flex:1;min-height:56px;border-radius:var(--r-md);font-size:1rem;font-weight:680;
  transition:transform .18s var(--spring);
}
.prepBtn:active{transform:scale(.97)}
.prepNo{background:var(--fill-subtle);color:var(--text-primary)}
.prepYes{background:var(--action-primary);color:var(--text-on-brand)}
.prepSkip{align-self:center;margin-top:8px}
.prepSkip[hidden]{display:none}
@media (prefers-reduced-motion:reduce){
  .prep,.prepDoneMark{animation:none}
  .prepCard,.prepCard.weg{transition:opacity .15s linear}
}

/* Auswahlkarte „Brauchst du davon etwas?": kleine Produktbilder mit
   Restzeit; die Auswahl bleibt als klarer Haken sichtbar. */
.prepGridCard{justify-content:flex-start;padding:22px 16px 18px;gap:6px}
.prepGrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;width:100%;margin-top:14px}
.prepPick{
  display:grid;grid-template-columns:38px minmax(0,1fr);grid-template-rows:auto auto;
  align-items:center;column-gap:9px;row-gap:2px;min-width:0;min-height:58px;
  padding:8px;border:1px solid var(--border-subtle);border-radius:var(--r-md);
  background:var(--surface-primary);text-align:left;touch-action:manipulation;
  transition:background .15s linear,border-color .15s linear,transform .2s var(--spring);
}
.prepPick:active{transform:scale(.98)}
.prepPick.on{border-color:color-mix(in srgb,var(--action-primary) 42%,var(--border-subtle));background:var(--brand-soft)}
.prepPickCircle{
  position:relative;grid-column:1;grid-row:1/3;width:38px;height:38px;
  border-radius:var(--r-sm);display:grid;place-items:center;
  background:var(--fill-subtle);transition:background .15s linear;
}
.prepPickCircle .pIcon{width:29px;height:29px}
.prepPick.on .prepPickCircle{background:var(--surface-primary)}
.prepPickCheck{
  position:absolute;right:-5px;top:-5px;width:18px;height:18px;border-radius:50%;
  display:grid;place-items:center;font-size:.72rem;font-weight:800;
  background:var(--action-primary);color:var(--text-on-brand);box-shadow:0 0 0 2px var(--surface-elevated);
  transform:scale(0);transition:transform .2s var(--spring);
}
.prepPick.on .prepPickCheck{transform:scale(1)}
.prepPickName{grid-column:2;grid-row:1;max-width:100%;font-size:.78rem;font-weight:650;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.prepPickDays{grid-column:2;grid-row:2;font-size:.68rem;color:var(--text-secondary);line-height:1.2}
.prepBtn:disabled{background:var(--action-disabled-bg);color:var(--action-disabled-text);transform:none}

/* Karte mit Antworten zum Antippen („Wie lange hält das bei dir?"). */
.prepOptions{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-top:14px}
.prepOptions[hidden]{display:none}
.prepOption{
  min-height:44px;padding:0 16px;border-radius:99px;font-size:.9rem;font-weight:650;
  background:var(--surface-primary);color:var(--text-primary);box-shadow:inset 0 0 0 1px var(--border-subtle);
}
.prepOption:active{background:var(--action-secondary)}

/* Übersicht nach dem Einkauf (einkaufUebersicht in views.js). */
.tripSummary{justify-content:flex-start;gap:6px;padding-top:22px}
.tripHead{display:flex;align-items:flex-end;gap:10px;width:100%;margin-bottom:8px}
.tripFigure{flex:0 0 auto;line-height:0}
.tripBubble{
  position:relative;flex:1;text-align:left;padding:10px 13px;border-radius:var(--r-lg) var(--r-lg) var(--r-lg) var(--r-sm);
  font-size:.9rem;font-weight:600;line-height:1.35;color:var(--text-primary);background:var(--review-bubble-bg);
  box-shadow:var(--shadow-bubble);animation:prepPop .4s var(--spring);
}
.tripTotal{font-size:2.2rem;font-weight:760;letter-spacing:-.025em;color:var(--text-primary);line-height:1.1}
.tripFacts{list-style:none;margin:14px 0 0;padding:0;width:100%;display:flex;flex-direction:column;gap:8px;text-align:left}
.tripFacts li{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:var(--r-md);background:var(--fill-subtle);font-size:.88rem;line-height:1.35;color:var(--text-primary)}
.tripFactMark{
  flex:0 0 auto;width:26px;height:26px;border-radius:50%;display:grid;place-items:center;
  font-size:.8rem;font-weight:800;background:var(--brand-soft);color:var(--text-brand);
}

/* Ein fester Anker; nur die Bühne öffnet sich, die Figur wandert nicht. */
.companion{
  right:auto;width:124px;
  background:transparent;box-shadow:var(--shadow-lift);
  transition:width .38s cubic-bezier(.22,.7,.25,1),height .38s cubic-bezier(.22,.7,.25,1),box-shadow .3s ease;
}

/* Eingeklappt: transparente Glass-Pille.
   Maße, Figur, HUD und der aufgeklappte Zustand bleiben unverändert. */
.companion:not(.isExpanded){
  height:80px;border-radius:var(--r-lg);

  /* Vorher nahezu deckend (97/88 % Surface).
     Jetzt bleibt der scrollende Inhalt hinter der Pille sichtbar. */
  background:linear-gradient(
    145deg,
    color-mix(in srgb,var(--surface-primary) 26%,transparent),
    color-mix(in srgb,var(--surface-primary) 14%,transparent)
  );

  -webkit-backdrop-filter:blur(28px) saturate(185%);
  backdrop-filter:blur(28px) saturate(185%);

  /* Feine Lichtkante statt einer weißen Kartenfläche. */
  border:1px solid color-mix(in srgb,var(--kitchen-glass-edge) 72%,transparent);

  box-shadow:
    inset 0 1px 0 color-mix(in srgb,var(--kitchen-glass-edge) 92%,transparent),
    0 8px 24px color-mix(in srgb,var(--text-primary) 7%,transparent);
}
.companion:not(.isExpanded) .kHud{left:auto;right:8px;top:auto;bottom:2px;width:44px;height:44px}
.companion:not(.isExpanded) .kHudLv{width:30px;height:30px}
.companion:not(.isExpanded) .kAct[data-act="tasks"]{width:44px;height:44px;background:none;box-shadow:none}
/* Eingeklappt steht die Figur auf keinem Boden: die Küche ist
   unsichtbar (siehe unten), also ist das bodennahe bottom:9px der
   Bühne hier ein Hängen. 52px Figur in 88px Pille heißt 18px oben
   wie unten. */
.companion:not(.isExpanded) .companionFigure{bottom:14px}
/* Die Ecke der Pille hat 22px Radius. Eine Marke bei top:3/right:2
   liegt damit IN der Rundung -- sie ragt über das Glas hinaus und
   sieht aufgeklebt aus. 6/12 hält sie davor. */
.companion:not(.isExpanded) .kActBadge{top:7px;right:14px}

/* Fallback: ebenfalls transparent statt wieder voll weiß. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .companion:not(.isExpanded){
    background:color-mix(in srgb,var(--surface-primary) 29%,transparent)
  }
}

/* Accessibility-Einstellung respektieren: weniger Transparenz = feste Fläche. */
@media(prefers-reduced-transparency:reduce){
  .companion:not(.isExpanded){
    background:var(--surface-primary);
    -webkit-backdrop-filter:none;
    backdrop-filter:none
  }
}
.companion.isExpanded{width:calc(100% - var(--pad) * 2);background:transparent;box-shadow:var(--shadow-lift)}
.companion.isExpanded{touch-action:pan-y pinch-zoom}
.companion.isDragging{transition:none;user-select:none;-webkit-user-select:none}
.companion .kitchenScene,.companion::before{
  transition:opacity .24s ease,visibility .24s;
}
.companion:not(.isExpanded) .kitchenScene,
.companion:not(.isExpanded)::before{opacity:0;visibility:hidden;pointer-events:none}
.companion:not(.isExpanded) .companionPanel,
.companion:not(.isExpanded) .mascotBubble,
.companion:not(.isExpanded) .kGoal,
.companion:not(.isExpanded) .kAct:not([data-act="tasks"]){visibility:hidden;pointer-events:none}
.companion:not(.isExpanded) .kActions{right:8px;top:2px;bottom:auto}
@media(min-width:900px){
  .companion.isExpanded{width:min(1036px, calc(100vw - 220px - 64px))}
}
/* Beim Aufklappen wächst die Bühne in .38s von 132 px auf volle
   Breite. Die Nachricht war dabei von der ersten Millisekunde an
   sichtbar und brach währenddessen in der schmalen Pille um -- ein
   Wort pro Zeile, für eine knappe halbe Sekunde, bei jedem Aufklappen.
   Sie erscheint deshalb erst, wenn die Breite steht: .24s Wartezeit
   plus .16s Einblenden endet bei .40s, zwei Hundertstel nach der
   Breite. Eingeklappt ist sie ohnehin unsichtbar (visibility weiter
   unten); die Deckkraft hier sorgt nur dafür, dass sie beim Öffnen
   nicht schon im Schmalen steht. */
.companion .companionPanel{transition:opacity .16s ease .24s}
.companion:not(.isExpanded) .companionPanel{opacity:0;transition-delay:0s}
@media(prefers-reduced-motion:reduce){
  .companion,.companion .kitchenScene,.companion::before{transition:none}
  /* Ohne Bewegung ist eine Wartezeit keine Choreografie, sondern
     Trägheit -- die Nachricht steht dann sofort da. */
  .companion .companionPanel{transition:none}
}

/* Benennen hilft allen (zuordnenSheet): ein Satz und ein leiser Knopf. */
.zuTeilen{
  display:flex;flex-direction:column;align-items:flex-start;gap:4px;margin-top:16px;padding:12px 14px;
  border-radius:var(--r-md);background:var(--fill-subtle);
}
.zuTeilen.an{background:var(--brand-soft)}
.zuTeilenText{font-size:.84rem;line-height:1.4;color:var(--text-secondary)}
.zuTeilen.an .zuTeilenText{color:var(--text-brand)}

/* ================================================================
   Native iOS shell: eine Navigation, sichere Ebenen
   ================================================================ */
html.native-ios-shell{
  --native-glass-height:60px;
  --native-glass-bottom:18px;
  /* Swift darf den Wert setzen (BridgeViewController). */
  --native-companion-bottom:90px;
  --nav-h:0px;
  /* Der Begleiter und alles, was an ihm hängt, steht ÜBER der nativen
     Liquid-Glass-Leiste — und zwar ab dem ersten Bild, nicht erst,
     wenn der native Teil sein CSS nachgeschoben hat. Vorher rechnete
     die Web-Seite hier mit --nav-h = 0 und stellte die Küche auf den
     Rand der sicheren Zone, also UNTER die Leiste; nach jedem Neuladen
     lag sie dort, bis Swift wieder eingriff. Und maß Swift einmal zu
     knapp (Koordinatenumrechnung der WebView), rutschte sie ebenfalls
     darunter. Deshalb eine Untergrenze aus den Maßen der Leiste
     selbst: Abstand zum Rand + Höhe + 12 px Luft. Tiefer geht es
     nicht, egal was gemessen wurde. */
  --native-dock-min:calc(var(--native-glass-bottom) + var(--native-glass-height) + 12px);
  --dock-bottom:max(var(--native-companion-bottom), var(--native-dock-min));
}
html.native-ios-shell #nav{display:none!important;visibility:hidden!important;pointer-events:none!important}
/* Etwas spezifischer als das CSS, das der native Teil einspielt
   (dort „html.native-ios-shell .companion{bottom:…!important}") —
   so gilt die Untergrenze aus --dock-bottom auch dann, wenn dessen
   Messwert zu klein ausfällt. */
html.native-ios-shell body .companion{bottom:var(--dock-bottom)!important}
html.native-ios-shell body .toast{bottom:calc(var(--dock-bottom) + var(--stage-h) + 14px)!important}
html.native-ios-shell body .cartBar{bottom:calc(var(--dock-bottom) + var(--stage-h) + 26px)!important}
html.native-ios-shell body .party{bottom:calc(var(--dock-bottom) + var(--stage-h) + 14px)}
/* Der Verlauf über der eingeklappten Pille hätte über der Glasleiste
   einen hellen Streifen gezogen. */
html.native-ios-shell .companion:not(.isExpanded)::before{opacity:0;visibility:hidden}
html.native-ios-shell main{
  padding-bottom:calc(var(--stage-h) + var(--dock-bottom) + 24px)!important;
}
html.native-ios-shell body:has(#companion[hidden]) main{padding-bottom:112px!important}
html.native-ios-shell .sheetBody{
  max-height:calc(100dvh - max(var(--safe-top),20px) - 16px);
  padding-bottom:calc(var(--native-glass-height) + var(--native-glass-bottom) + 24px);
  border:1px solid var(--border-subtle);
  border-bottom:0;
  box-shadow:0 -18px 50px color-mix(in srgb,var(--text-primary) 12%,transparent);
}
html.native-ios-shell .storeFoot{
  padding-bottom:calc(var(--native-glass-height) + var(--native-glass-bottom) + 16px);
}
html.native-ios-shell .prep{
  padding-bottom:calc(var(--native-glass-height) + var(--native-glass-bottom) + 20px);
}

/* Lange Inhalte dürfen in allen Karten umbrechen. Das behebt nicht
   einzelne Screenshots, sondern dieselbe Ursache in Liste, Bestand,
   Auswertung und Blättern. */
.rowMain,.rowTitle,.rowSub,.rowValue,.sheetBody,#sheetOpts,.gSheet{min-width:0}
.rowTitle,.rowSub,.sheetPara,.srcnote,.gProgressTaskDesc,.gProgressFoldNote{
  overflow-wrap:break-word;
  word-break:normal;
}
.rowValue{max-width:44%;overflow-wrap:anywhere;text-align:right}
.sheetBody img,.sheetBody svg{max-width:100%}
.sheetBody .cta,.sheetBody .pillBtn{white-space:normal}

/* Hinweise im Blatt sind eigenständige Entscheidungen. Abgerundete,
   ruhige Flächen sprechen dieselbe Sprache wie Wochenrückblick und
   Startkarte; die Gruppen bleiben dabei klar voneinander getrennt. */
.sheet .sheetGroupTitle{margin:20px 2px 8px;color:var(--text-secondary)}
.sheet .sheetGroupTitle:first-child{margin-top:4px}
.sheet .hintDecisionRow{
  margin:0 0 10px;
  padding:15px;
  border:1px solid var(--border-subtle);
  border-radius:var(--r-lg);
  background:var(--surface-primary);
  box-shadow:var(--shadow-lift);
}
.sheet .hintDecisionRow+.hintDecisionRow{border-top:1px solid var(--border-subtle)}
.sheet .hintDecisionRow .rowActions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
.sheet .hintDecisionRow .pillBtn{width:100%;min-height:44px;border-radius:var(--r-md)}

/* Fortschritt: auf Telefonen zwei gut lesbare Kennzahlen pro Zeile
   statt vier Mini-Kreise. Die Inhalte bleiben unverändert. */
.gProgressLevelCard{
  background:linear-gradient(145deg,var(--review-wash),color-mix(in srgb,var(--accent-warm-soft) 58%,var(--surface-primary)));
  border-color:color-mix(in srgb,var(--mascot-pink) 18%,var(--border-subtle));
  box-shadow:var(--shadow-lift);
}
.gProgressRingGrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
.gProgressRingCard{
  display:grid;
  grid-template-columns:58px minmax(0,1fr);
  grid-template-rows:auto auto;
  align-items:center;
  column-gap:11px;
  min-height:82px;
  padding:11px 12px;
  text-align:left;
  border-radius:var(--r-lg);
  box-shadow:var(--shadow-lift);
}
.gProgressRing{grid-column:1;grid-row:1 / 3;width:56px;height:56px;margin:0}
.gProgressRingLabel{grid-column:2;grid-row:1;align-self:end;font-size:.72rem;line-height:1.25}
.gProgressRingDetail{grid-column:2;grid-row:2;align-self:start;font-size:.62rem;white-space:normal;line-height:1.3}
.gProgressTaskCard,.gProgressFold{border-radius:var(--r-lg);box-shadow:var(--shadow-lift)}
.gProgressTaskActions{gap:8px;flex-wrap:wrap}
.gProgressTaskAction{min-height:38px;padding:0 12px;border-radius:99px;background:var(--fill-subtle)}
.gProgressTaskAction.primary{background:var(--brand-soft)}

@media(max-width:360px){
  .gProgressRingGrid{grid-template-columns:1fr}
  .gProgressRingCard{min-height:76px}
  .rowValue{max-width:40%}
}

/* ==========================================================
   Trefferflächen: 44 px, ohne dass sich etwas sichtbar ändert
   ==========================================================
   Drei Bedienelemente waren kleiner als die 44 px, die ein
   Finger zuverlässig trifft: die Marke „Beispieldaten"
   (92×21), das Fähnchen mit der Erklärung (52×25) und der
   kleine Level-Knopf in der Kopfleiste (41×34).

   Vergrößert wird NICHT das Aussehen, sondern nur die Fläche,
   die auf den Tipser reagiert -- über ein Pseudo-Element, das
   mittig hinter dem Element liegt. Das Element bleibt optisch
   exakt so groß wie vorher.

   Warum nur diese drei: gemessen wurde für jeden Kandidaten,
   ob die vergrößerte Fläche einen Nachbarn überdeckt. Diese
   drei haben null Kollisionen. Die Knöpfe im Begleiter-Feld
   („Produkt prüfen", „Mehr Tipps", je 26 px hoch) haben sechs
   bzw. zwei -- ihre Fläche würde über den Rand ihrer Karte
   hinaus auf die Liste dahinter greifen und dort Tipser
   stehlen. Die Möbel in der Küche (bis hinunter zu 3×11 px)
   bleiben ebenfalls, wie sie sind: 44 px pro Möbelstück
   würden sich in einer 343 px breiten Kulisse gegenseitig
   überdecken, und die Sammlung ist über den eigenen Knopf
   ohnehin erreichbar. */
button.pill.warn,
.flag.f-gold{position:relative}
button.pill.warn::after,
.flag.f-gold::after{
  content:"";position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);
  height:44px;width:100%;min-width:44px;
}
/* Dieselbe Rechnung für die Erklär-Knöpfe („i" neben einer
   Überschrift): 32 × 32 px, dreizehn Stück in sechs Ansichten, und
   für jeden einzelnen nachgemessen — keine einzige Kollision bei
   44 px. Sie stehen immer allein neben einer Überschrift, deshalb
   ist ringsherum Platz. `::before` trägt schon den Ring, die Fläche
   liegt also auf `::after`; `position:relative` hat .infoBtn bereits.
   Dass 44 die Absicht des Hauses ist, steht ein paar Zeilen höher:
   .pillBtn hat min-height:44px. */
.infoBtn::after{
  content:"";position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);width:44px;height:44px;
}
/* Dieselbe unsichtbare 44-px-Fläche für die kleinsten Bedienelemente:
   den Abhak-Kreis der Liste (24 px, die meistgetippte Stelle der App;
   nicht der Abwahl-Knopf — der zeichnet sein „X" mit ::before/::after),
   antippbare Marken (21 px hoch) und den Knopf der Kühlhinweise. Sichtbar
   ändert sich nichts. */
.box:not(.listRemoveTrigger)::after,.coolingDecisionTrigger::after{
  content:"";position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);width:44px;height:44px;border-radius:50%;
}
.coolingDecisionTrigger{position:relative}
.pill[role="button"],.flag[role="button"]{position:relative}
.pill[role="button"]::after,.flag[role="button"]::after{
  content:"";position:absolute;left:-4px;right:-4px;top:50%;
  transform:translateY(-50%);height:44px;
}

/* Langes Tippen auf einen Knopf öffnet in der iOS-Hülle das
   System-Menü („Kopieren", „Nachschlagen") und färbt die Beschriftung
   blau ein -- eine Web-Geste mitten in einer App, die sich nativ
   anfühlen soll. Das Menü wird deshalb für Knöpfe und Bilder
   abgeschaltet, NICHT für Fließtext und Eingabefelder: Produktnamen,
   Beträge und eingetippte Zeilen bleiben markierbar und kopierbar,
   weil das dort eine Hilfe ist und keine Störung. */
button,
[role="button"],
img,
.uiImageIcon{-webkit-touch-callout:none}

/* Der Leerzustand von „Aufbrauchen“ stellt ein (i) neben die Überschrift. */
.useUpHead{display:flex;align-items:center;gap:6px}
.useUpHead h2{margin:0 0 6px}


/* ================================================================
   BESTAND — HERO VARIANTE 09
   Ruhige Premium-Health-Karte + dezente Produktreihe.
   ================================================================ */

.inventoryHealthHero{
  width:100%;
  display:block;
  margin:14px 0 2px;
  padding:18px;
  text-align:left;
  border:1px solid var(--border-subtle);
  border-radius:calc(var(--r-lg) + 2px);

  background:
    linear-gradient(
      145deg,
      color-mix(in srgb,var(--brand-soft) 52%,var(--surface-primary)),
      color-mix(in srgb,var(--surface-secondary) 74%,var(--surface-primary))
    );

  box-shadow:var(--shadow-lift);
  cursor:pointer;

  transition:
    transform .18s var(--spring),
    box-shadow .18s var(--ease);
}

.inventoryHealthHero:active{
  transform:scale(.988);
}

.inventoryHealthHead{
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:18px;
}

.inventoryHealthCopy{
  min-width:0;
  padding-top:2px;
}

.inventoryHealthTitle{
  font-size:1.08rem;
  line-height:1.2;
  font-weight:700;
  letter-spacing:-.018em;
  color:var(--text-primary);
}

.inventoryHealthSub{
  margin-top:5px;
  max-width:230px;
  font-size:.78rem;
  line-height:1.38;
  font-weight:500;
  color:var(--text-secondary);
}

.inventoryHealthScore{
  width:50px;
  height:50px;
  flex:0 0 50px;
  display:grid;
  place-items:center;
  border-radius:50%;

  background:
    color-mix(
      in srgb,
      var(--surface-primary) 84%,
      var(--brand-soft)
    );

  box-shadow:
    inset 0 0 0 1px var(--border-subtle);

  color:var(--text-brand);
  font-size:1.28rem;
  line-height:1;
  font-weight:760;
  letter-spacing:-.025em;
  font-variant-numeric:tabular-nums;
}

.inventoryHealthStrip{
  min-width:0;
  width:100%;

  display:flex;
  align-items:center;
  flex-wrap:nowrap;
  gap:8px;

  margin-top:16px;
  padding-top:14px;
  padding-bottom:2px;

  overflow-x:auto;
  overflow-y:hidden;

  -webkit-overflow-scrolling:touch;
  overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;
  scrollbar-width:none;

  border-top:
    1px solid
    color-mix(
      in srgb,
      var(--divider) 76%,
      transparent
    );
}

.inventoryHealthStrip::-webkit-scrollbar{
  display:none;
}

.inventoryHealthChip{
  flex:0 0 auto;
  width:clamp(138px,42vw,166px);
  min-width:138px;
  height:42px;

  display:grid;
  grid-template-columns:26px minmax(0,1fr) auto;
  align-items:center;
  gap:7px;

  padding:6px 9px 6px 7px;
  border-radius:999px;

  scroll-snap-align:start;

  background:
    color-mix(
      in srgb,
      var(--surface-primary) 74%,
      transparent
    );

  box-shadow:
    inset 0 0 0 1px
    color-mix(
      in srgb,
      var(--border-subtle) 82%,
      transparent
    );
}

.inventoryHealthChip .pIcon,
.inventoryHealthIcon{
  width:26px;
  height:26px;
  flex:0 0 auto;
}

.inventoryHealthChipName{
  min-width:0;
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
  font-size:.75rem;
  line-height:1;
  font-weight:650;
  color:var(--text-primary);
}

.inventoryHealthChipValue{
  white-space:nowrap;
  font-size:.72rem;
  line-height:1;
  font-weight:720;
  color:var(--text-secondary);
  font-variant-numeric:tabular-nums;
}
.inventoryHealthChipValue.needsCheck{color:var(--accent-warm-text)}

.inventoryHealthMore{
  width:42px;
  height:42px;
  flex:0 0 42px;
  display:grid;
  place-items:center;
  border-radius:999px;

  background:
    color-mix(
      in srgb,
      var(--brand-soft) 64%,
      var(--surface-primary)
    );

  box-shadow:
    inset 0 0 0 1px
    color-mix(
      in srgb,
      var(--border-subtle) 76%,
      transparent
    );

  color:var(--text-brand);
  font-size:.76rem;
  font-weight:760;
  font-variant-numeric:tabular-nums;
}

.inventoryHealthEmpty{
  min-height:42px;
  display:flex;
  align-items:center;
  padding:0 13px;
  border-radius:999px;

  background:
    color-mix(
      in srgb,
      var(--surface-primary) 72%,
      transparent
    );

  color:var(--text-secondary);
  font-size:.76rem;
  font-weight:620;

  box-shadow:
    inset 0 0 0 1px
    color-mix(
      in srgb,
      var(--border-subtle) 78%,
      transparent
    );
}

@media(max-width:360px){

  .inventoryHealthHero{
    padding:16px;
  }

  .inventoryHealthHead{
    gap:12px;
  }

  .inventoryHealthScore{
    width:46px;
    height:46px;
    flex-basis:46px;
    font-size:1.18rem;
  }

  .inventoryHealthStrip{
    gap:6px;
  }

  .inventoryHealthChip{
    width:136px;
    min-width:136px;
    grid-template-columns:24px minmax(0,1fr) auto;
    gap:5px;
    padding-right:7px;
  }

  .inventoryHealthChip .pIcon,
  .inventoryHealthIcon{
    width:24px;
    height:24px;
  }

  .inventoryHealthChipName{
    font-size:.71rem;
  }

  .inventoryHealthChipValue{
    font-size:.68rem;
  }

}


/* ================================================================
   FORTSCHRITT-MODAL — FINAL V2
   Referenz: Levelkarte + 4 Kreise + echte Wochenaufgaben + Accordions
   ================================================================ */

.gProgressSheet{
  display:flex;
  flex-direction:column;
  gap:0;
}


/* ------------------------------------------------
   1. LEVEL / EXP
   ------------------------------------------------ */

.gProgressLevelCard{
  margin:2px 0 0;
  padding:18px 18px 16px;

  border-radius:var(--r-lg);
  border:1px solid var(--border-subtle);

  background:
    linear-gradient(
      180deg,
      var(--surface-primary) 0%,
      color-mix(in srgb,var(--surface-primary) 94%,var(--mascot-pink-soft)) 100%
    );

  box-shadow:
    0 12px 30px
    color-mix(in srgb,var(--text-primary) 3%,transparent);
}

.gProgressLevelTop{
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:12px;
}

.gProgressLevelCopy{
  min-width:0;
}

.gProgressEyebrow{
  color:var(--text-secondary);

  font-size:.68rem;
  line-height:1;
  font-weight:760;

  text-transform:uppercase;
  letter-spacing:.045em;
}

.gProgressLevelName{
  margin-top:7px;

  color:var(--text-primary);

  font-size:1.18rem;
  line-height:1.15;
  font-weight:760;

  letter-spacing:-.025em;
}

.gProgressExpBadge{
  min-width:74px;
  height:38px;

  display:flex;
  align-items:center;
  justify-content:center;

  padding:0 11px;

  border-radius:var(--r-md);

  background:
    color-mix(
      in srgb,
      var(--mascot-pink-soft) 86%,
      var(--surface-primary)
    );

  color:var(--mascot-pink-text);

  font-size:.76rem;
  line-height:1;
  font-weight:800;

  white-space:nowrap;
  font-variant-numeric:tabular-nums;
}

.gProgressLevelTrack{
  position:relative;

  height:18px;

  margin-top:14px;

  overflow:hidden;

  border-radius:999px;

  background:
    linear-gradient(
      90deg,
      color-mix(in srgb,var(--mascot-pink-soft) 76%,var(--surface-primary)),
      color-mix(in srgb,var(--mascot-pink-soft) 54%,var(--surface-primary))
    );
}

.gProgressLevelFill{
  position:absolute;
  inset:0 auto 0 0;

  width:0;

  border-radius:inherit;

  background:
    linear-gradient(
      90deg,
      var(--mascot-pink),
      color-mix(in srgb,var(--mascot-pink) 72%,white)
    );

  transition:width .3s var(--ease);
}

.gProgressRangeOverlay{
  position:absolute;
  inset:0;

  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:12px;

  padding:0 10px;

  pointer-events:none;

  font-size:.61rem;
  line-height:1;
  font-weight:800;
}

.gProgressRangeCurrent{
  color:white;
}

.gProgressRangeNext{
  margin-left:auto;
  color:var(--mascot-pink-text);
}


/* ------------------------------------------------
   SECTION SYSTEM
   ------------------------------------------------ */

.gProgressSection{
  margin-top:18px;
}

.gProgressSectionTitle{
  margin:0 2px 12px;

  color:var(--text-primary);

  font-size:1rem;
  line-height:1.2;
  font-weight:750;

  letter-spacing:-.018em;
}


/* ------------------------------------------------
   2. 4 PROGRESS-RINGE
   ------------------------------------------------ */

.gProgressRingGrid{
  display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:8px;
}

.gProgressRingCard{
  min-width:0;

  display:flex;
  flex-direction:column;
  align-items:center;

  padding:12px 6px 11px;

  border:1px solid var(--border-subtle);
  border-radius:var(--r-lg);

  background:var(--surface-primary);

  color:var(--text-primary);
  text-align:center;
}

button.gProgressRingCard:active{
  background:var(--fill-subtle);
}

.gProgressRing{
  --ring-progress:0%;
  --ring-color:var(--success);

  width:64px;
  height:64px;

  display:grid;
  place-items:center;

  margin:0 auto 9px;

  border-radius:50%;

  background:
    radial-gradient(
      closest-side,
      var(--surface-primary) 76%,
      transparent 77% 100%
    ),
    conic-gradient(
      var(--ring-color) var(--ring-progress),
      color-mix(in srgb,var(--ring-color) 13%,var(--surface-primary)) 0
    );
}

.gProgressRingCard.collection .gProgressRing{
  --ring-color:var(--success);
}

.gProgressRingCard.modules .gProgressRing{
  --ring-color:var(--warning);
}

.gProgressRingCard.loot .gProgressRing{
  --ring-color:var(--achievement);
}

.gProgressRingCard.shards .gProgressRing{
  --ring-color:var(--mascot-pink);
}

.gProgressRingValue{
  color:var(--text-primary);

  font-size:.84rem;
  line-height:1;
  font-weight:800;

  font-variant-numeric:tabular-nums;
}

.gProgressRingLabel{
  max-width:100%;

  color:var(--text-secondary);

  font-size:.61rem;
  line-height:1.2;
  font-weight:720;

  white-space:normal;
}

.gProgressRingDetail{
  max-width:100%;

  margin-top:4px;

  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;

  color:var(--text-muted);

  font-size:.54rem;
  line-height:1.2;

  font-variant-numeric:tabular-nums;
}


/* ------------------------------------------------
   3. WOCHENAUFGABEN
   ------------------------------------------------ */

.gProgressWeekOverview{
  margin:0 2px 12px;
  padding-bottom:2px;
}

.gProgressWeekOverviewTop{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:12px;

  margin-bottom:8px;
}

.gProgressWeekLabel{
  color:var(--text-secondary);

  font-size:.74rem;
  line-height:1.25;
  font-weight:620;
}

.gProgressWeekPercent{
  flex:0 0 auto;

  color:var(--mascot-pink-text);

  font-size:.68rem;
  line-height:1;
  font-weight:800;
}

.gProgressWeekTrack,
.gProgressTaskTrack{
  display:block;

  overflow:hidden;

  border-radius:999px;

  background:
    color-mix(
      in srgb,
      var(--mascot-pink-soft) 80%,
      var(--surface-primary)
    );
}

.gProgressWeekTrack{
  height:9px;
}

.gProgressWeekFill,
.gProgressTaskFill{
  display:block;

  height:100%;

  border-radius:inherit;

  background:
    linear-gradient(
      90deg,
      var(--mascot-pink),
      color-mix(in srgb,var(--mascot-pink) 72%,white)
    );

  transition:width .3s var(--ease);
}

.gProgressTaskList{
  display:grid;
  gap:10px;
}

.gProgressTaskCard{
  display:block;

  padding:15px;

  border:1px solid var(--border-subtle);
  border-radius:var(--r-lg);

  background:var(--surface-primary);
}

.gProgressTaskCard.done{
  border-color:
    color-mix(
      in srgb,
      var(--success) 20%,
      var(--border-subtle)
    );
}

.gProgressTaskHead{
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:12px;
}

.gProgressTaskTitle{
  min-width:0;

  color:var(--text-primary);

  font-size:.86rem;
  line-height:1.2;
  font-weight:760;

  letter-spacing:-.014em;
}

.gProgressTaskXp{
  flex:0 0 auto;

  color:var(--mascot-pink-text);

  font-size:.7rem;
  line-height:1.2;
  font-weight:800;

  white-space:nowrap;
}

.gProgressTaskDesc{
  margin-top:6px;

  color:var(--text-secondary);

  font-size:.72rem;
  line-height:1.4;
}

.gProgressTaskProgress{
  display:grid;
  grid-template-columns:minmax(0,1fr) auto;
  align-items:center;
  gap:11px;

  margin-top:13px;
}

.gProgressTaskTrack{
  height:8px;
}

.gProgressTaskCount{
  min-width:36px;

  color:var(--text-secondary);

  font-size:.68rem;
  line-height:1;
  text-align:right;

  font-variant-numeric:tabular-nums;
}

.gProgressTaskMeta{
  margin-top:9px;

  color:var(--text-muted);

  font-size:.66rem;
  line-height:1.35;
}

.gProgressTaskActions{
  display:flex;
  align-items:center;
  gap:20px;

  margin-top:12px;
}

.gProgressTaskAction{
  min-height:28px;

  padding:0;

  background:none;

  font-size:.7rem;
  line-height:1;
  font-weight:720;
}

.gProgressTaskAction.primary{
  color:var(--text-brand);
}

.gProgressTaskAction.secondary{
  color:var(--text-secondary);
}

.gProgressTaskEmpty{
  padding:15px;

  border:1px solid var(--border-subtle);
  border-radius:var(--r-lg);

  background:var(--surface-primary);

  color:var(--text-secondary);

  font-size:.74rem;
  line-height:1.4;
}


/* ------------------------------------------------
   4 + 5. ACCORDIONS
   ------------------------------------------------ */

.gProgressFold{
  margin-top:12px;

  overflow:hidden;

  border:1px solid var(--border-subtle);
  border-radius:var(--r-lg);

  background:var(--surface-primary);
}

.gProgressFold summary{
  position:relative;

  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:14px;

  min-height:54px;

  padding:15px 16px;

  list-style:none;
  cursor:pointer;
  user-select:none;

  color:var(--text-primary);

  font-size:.84rem;
  line-height:1.2;
  font-weight:740;
}

.gProgressFold summary::-webkit-details-marker{
  display:none;
}

.gProgressFold summary::after{
  content:"⌄";

  width:28px;
  height:28px;

  flex:0 0 28px;

  display:grid;
  place-items:center;

  border-radius:50%;

  background:var(--fill-subtle);

  color:var(--text-secondary);

  font-size:.8rem;
  line-height:1;

  transition:
    transform .2s var(--ease),
    background .2s var(--ease);
}

.gProgressFold[open] summary::after{
  transform:rotate(180deg);
}

.gProgressFoldContent{
  padding:0 16px 16px;

  border-top:1px solid var(--divider);

  animation:gProgressFoldIn .2s var(--ease);
}

@keyframes gProgressFoldIn{
  from{
    opacity:0;
    transform:translateY(-4px);
  }
  to{
    opacity:1;
    transform:none;
  }
}

.gProgressInfoList{
  margin:13px 0 0;
  padding-left:18px;

  color:var(--text-secondary);

  font-size:.72rem;
  line-height:1.48;
}

.gProgressInfoList li{
  margin:6px 0;
}

.gProgressFoldNote{
  margin:12px 0 0;

  color:var(--text-muted);

  font-size:.69rem;
  line-height:1.48;
}


/* Rarity Pills */

.gProgressRarityRow{
  display:flex;
  flex-wrap:wrap;
  gap:7px;

  margin-top:13px;
}

.gProgressRarity{
  display:inline-flex;
  align-items:center;

  min-height:29px;

  padding:0 10px;

  border-radius:999px;

  font-size:.63rem;
  line-height:1;
  font-weight:800;
}

.gProgressRarity.r-gewoehnlich{
  background:var(--fill-subtle);
  color:var(--text-secondary);
}

.gProgressRarity.r-selten{
  background:var(--info-soft);
  color:var(--info-text);
}

.gProgressRarity.r-episch{
  background:var(--achievement-soft);
  color:var(--achievement-text);
}

.gProgressRarity.r-legendaer{
  background:var(--accent-warm-soft);
  color:var(--accent-warm-text);
}


/* ------------------------------------------------
   Kleine Telefone
   ------------------------------------------------ */

@media(max-width:380px){

  .gProgressLevelCard{
    padding:16px;
  }

  .gProgressLevelName{
    font-size:1.06rem;
  }

  .gProgressExpBadge{
    min-width:68px;
    height:36px;
    padding:0 9px;
    font-size:.7rem;
  }

  .gProgressRingGrid{
    gap:6px;
  }

  .gProgressRingCard{
    padding:10px 4px;
  }

  .gProgressRing{
    width:56px;
    height:56px;
  }

  .gProgressRingLabel{
    font-size:.56rem;
  }

  .gProgressRingDetail{
    font-size:.5rem;
  }
}


/* ------------------------------------------------
   Reduced Motion
   ------------------------------------------------ */

@media(prefers-reduced-motion:reduce){

  .gProgressLevelFill,
  .gProgressWeekFill,
  .gProgressTaskFill,
  .gProgressFoldContent,
  .gProgressFold summary::after{
    transition:none;
    animation:none;
  }
}


/* ================================================================
   START — DEINE FORTSCHRITTE / SNEAK PEEK FINAL
   Finale Referenz: Streak-Hero + 3 kompakte Analyse-Karten.
   Immer sichtbar, kein <details>, kein Chevron.
   ================================================================ */

.homeProgressStatic{
  margin-top:24px;
  padding-top:18px;
  border-top:1px solid var(--border-subtle);
}

.homeProgressTitle{
  margin:0 3px 12px;

  color:var(--text-secondary);

  font-size:.92rem;
  line-height:1.2;
  font-weight:720;
  letter-spacing:-.012em;
}


/* ------------------------------------------------
   Gemeinsamer weißer Container
   ------------------------------------------------ */

.progressSneak{
  overflow:hidden;

  border:1px solid var(--border-subtle);
  border-radius:var(--r-lg);

  background:var(--surface-primary);

  box-shadow:
    0 8px 22px
    color-mix(in srgb,var(--text-primary) 3.5%,transparent);

  padding:10px 0 12px;
}


/* ------------------------------------------------
   Streak Hero
   ------------------------------------------------ */

.progressStreakHero{
  width:calc(100% - 24px);

  display:block;

  margin:0 12px;
  padding:13px;

  border:0;
  border-radius:var(--r-lg);

  text-align:left;

  color:var(--text-primary);

  background:
    linear-gradient(
      135deg,
      color-mix(
        in srgb,
        var(--mascot-pink-soft) 78%,
        var(--surface-primary)
      ),
      color-mix(
        in srgb,
        var(--accent-warm-soft) 68%,
        var(--surface-primary)
      )
    );

  transition:
    transform .16s var(--ease),
    opacity .16s var(--ease);
}

.progressStreakHero:active{
  transform:scale(.992);
  opacity:.88;
}

.progressStreakTop{
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:12px;
}

.progressStreakCopy{
  min-width:0;
}

.progressStreakKicker{
  color:var(--text-secondary);

  font-size:.57rem;
  line-height:1;
  font-weight:820;
  letter-spacing:.035em;
}

.progressStreakValue{
  margin-top:5px;

  color:var(--text-primary);

  font-size:1.38rem;
  line-height:1;
  font-weight:820;

  letter-spacing:-.035em;
  font-variant-numeric:tabular-nums;
}

.progressStreakSub{
  margin-top:4px;

  color:var(--text-secondary);

  font-size:.62rem;
  line-height:1.15;
  font-weight:520;
}

.progressStreakBadge{
  width:48px;
  height:48px;
  flex:0 0 48px;

  display:grid;
  place-items:center;

  border-radius:var(--r-md);

  background:
    color-mix(
      in srgb,
      var(--mascot-pink-soft) 88%,
      var(--surface-primary)
    );

  color:var(--mascot-pink-text);

  font-size:1.32rem;
  line-height:1;
  font-weight:760;
}

.progressStreakDots{
  display:flex;
  align-items:center;
  gap:5px;

  margin-top:10px;
}

.progressStreakDot{
  width:10px;
  height:10px;
  flex:0 0 10px;

  display:block;

  border-radius:50%;

  background:
    color-mix(
      in srgb,
      var(--mascot-pink) 24%,
      var(--surface-primary)
    );
}

.progressStreakDot.on{
  background:var(--mascot-pink);
}

.progressStreakDot.vacation{
  background:
    color-mix(
      in srgb,
      var(--mascot-pink) 48%,
      var(--surface-primary)
    );
}

.progressStreakDot.current{
  box-shadow:
    0 0 0 4px
    color-mix(
      in srgb,
      var(--mascot-pink) 15%,
      transparent
    );
}

.progressStreakDots.empty{
  opacity:.38;
}


/* ------------------------------------------------
   Drei Analyse-Karten
   ------------------------------------------------ */

.progressAnalyticsCards{
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:8px;

  padding:8px 12px 0;
}

.progressAnalyticsCard{
  min-width:0;
  min-height:98px;

  display:flex;
  flex-direction:column;

  padding:10px;

  overflow:hidden;

  border:0;
  border-radius:var(--r-lg);

  text-align:left;

  color:var(--text-primary);

  transition:
    transform .16s var(--ease),
    opacity .16s var(--ease);
}

.progressAnalyticsCard:active{
  transform:scale(.975);
  opacity:.84;
}

.progressAnalyticsCard.expenses{
  background:
    color-mix(
      in srgb,
      var(--brand-soft) 78%,
      var(--surface-primary)
    );

  color:var(--text-brand);
}

.progressAnalyticsCard.rhythms{
  background:
    color-mix(
      in srgb,
      var(--info-soft) 86%,
      var(--surface-primary)
    );

  color:var(--info-text);
}

.progressAnalyticsCard.impact{
  background:
    color-mix(
      in srgb,
      var(--accent-warm-soft) 86%,
      var(--surface-primary)
    );

  color:var(--accent-warm-text);
}

.progressAnalyticsTop{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:6px;
}

.progressAnalyticsLabel{
  min-width:0;

  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;

  color:currentColor;
  opacity:.72;

  font-size:.53rem;
  line-height:1;
  font-weight:820;
  letter-spacing:.015em;
}

.progressAnalyticsIcon{
  flex:0 0 auto;

  color:currentColor;

  font-size:.8rem;
  line-height:1;
  font-weight:820;
}

.progressAnalyticsValue{
  min-height:19px;

  margin-top:5px;

  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;

  color:currentColor;

  font-size:.9rem;
  line-height:1.08;
  font-weight:820;

  letter-spacing:-.025em;
  font-variant-numeric:tabular-nums;
}

.progressAnalyticsValue.empty{
  font-size:.62rem;
  font-weight:700;
  letter-spacing:-.01em;
}

.progressAnalyticsSub{
  min-height:12px;

  margin-top:3px;

  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;

  color:var(--text-secondary);

  font-size:.54rem;
  line-height:1.2;
  font-weight:540;
}


/* ------------------------------------------------
   Micro-Sparklines
   ------------------------------------------------ */

.progressMiniChart{
  width:100%;
  height:24px;

  display:block;

  margin-top:auto;
  padding-top:4px;

  color:currentColor;
}

.progressMiniChart svg{
  width:100%;
  height:100%;

  display:block;

  overflow:visible;
}

.progressMiniChart .base{
  stroke:currentColor;
  stroke-width:1;
  opacity:.10;
}

.progressMiniChart .line{
  fill:none;

  stroke:currentColor;
  stroke-width:2.2;

  stroke-linecap:round;
  stroke-linejoin:round;

  vector-effect:non-scaling-stroke;
}

.progressMiniChart .dot{
  fill:currentColor;
}

.progressMiniChart.empty{
  opacity:.24;
}


/* ------------------------------------------------
   Kleine iPhones
   ------------------------------------------------ */

@media(max-width:360px){

  .homeProgressStatic{
    margin-top:20px;
  }

  .progressSneak{
    border-radius:var(--r-lg);
  }

  .progressStreakHero{
    width:calc(100% - 20px);
    margin-left:10px;
    margin-right:10px;
  }

  .progressStreakValue{
    font-size:1.28rem;
  }

  .progressStreakBadge{
    width:44px;
    height:44px;
    flex-basis:44px;

    border-radius:var(--r-md);
  }

  .progressAnalyticsCards{
    gap:6px;
    padding-left:10px;
    padding-right:10px;
  }

  .progressAnalyticsCard{
    min-height:94px;
    padding:9px 8px;
    border-radius:var(--r-md);
  }

  .progressAnalyticsLabel{
    font-size:.49rem;
  }

  .progressAnalyticsValue{
    font-size:.82rem;
  }

  .progressAnalyticsSub{
    font-size:.5rem;
  }
}


/* ------------------------------------------------
   Größere Accessibility-Schrift:
   lieber robust stapeln als Text abschneiden.
   ------------------------------------------------ */

@media(max-width:430px) and (min-resolution:1dppx){
  html[style*="--text-scale: 1.2"] .progressAnalyticsCards,
  html[style*="--text-scale: 1.3"] .progressAnalyticsCards,
  html[style*="--text-scale: 1.4"] .progressAnalyticsCards{
    grid-template-columns:1fr;
  }

  html[style*="--text-scale: 1.2"] .progressAnalyticsCard,
  html[style*="--text-scale: 1.3"] .progressAnalyticsCard,
  html[style*="--text-scale: 1.4"] .progressAnalyticsCard{
    min-height:88px;
  }
}


/* ------------------------------------------------
   Reduced motion
   ------------------------------------------------ */

@media(prefers-reduced-motion:reduce){

  .progressStreakHero,
  .progressAnalyticsCard{
    transition:none;
  }
}

/* Finaler mobiler Schliff nach den komponenteneigenen Regeln. */
.gProgressLevelCard{
  background:linear-gradient(145deg,var(--review-wash),color-mix(in srgb,var(--accent-warm-soft) 58%,var(--surface-primary)));
  border-color:color-mix(in srgb,var(--mascot-pink) 18%,var(--border-subtle));
  box-shadow:var(--shadow-lift);
}
.gProgressRingGrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
.gProgressRingCard{
  display:grid;grid-template-columns:58px minmax(0,1fr);grid-template-rows:auto auto;
  align-items:center;column-gap:11px;min-height:82px;padding:11px 12px;
  text-align:left;border-radius:var(--r-lg);box-shadow:var(--shadow-lift);
}
.gProgressRing{grid-column:1;grid-row:1 / 3;width:56px;height:56px;margin:0}
.gProgressRingLabel{grid-column:2;grid-row:1;align-self:end;font-size:.72rem;line-height:1.25}
.gProgressRingDetail{grid-column:2;grid-row:2;align-self:start;font-size:.62rem;white-space:normal;line-height:1.3}
.gProgressTaskCard,.gProgressFold{border-radius:var(--r-lg);box-shadow:var(--shadow-lift)}
.gProgressTaskActions{gap:8px;flex-wrap:wrap}
.gProgressTaskAction{min-height:38px;padding:0 12px;border-radius:99px;background:var(--fill-subtle)}
.gProgressTaskAction.primary{background:var(--brand-soft)}
@media(max-width:360px){
  .gProgressRingGrid{grid-template-columns:1fr}
  .gProgressRingCard{min-height:76px}
}


/* ===== Inventory V2 — einzelne Packungen im Produktdetail ===== */
.batchSection{margin:12px 0 4px;padding:12px;border:1px solid var(--divider);border-radius:var(--r-lg);background:var(--surface-primary)}
.batchHead{padding:2px 2px 10px}.batchTitle{font-size:.9rem;font-weight:760;color:var(--text-primary)}.batchHint{margin-top:3px;font-size:.73rem;line-height:1.35;color:var(--text-secondary)}
.batchCard{padding:11px 0;border-top:1px solid var(--divider)}.batchCard:first-of-type{border-top:0}.batchCardTop{display:flex;align-items:baseline;justify-content:space-between;gap:12px}.batchIndex{font-size:.78rem;font-weight:720;color:var(--text-primary)}.batchAmount{font-size:.78rem;font-weight:720;color:var(--text-primary)}
.batchMeta,.batchRaw,.batchFlags{margin-top:3px;font-size:.7rem;line-height:1.35;color:var(--text-secondary)}.batchRaw{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;overflow-wrap:anywhere}.batchFlags{color:var(--text-secondary)}
.batchActions{display:flex;gap:6px;flex-wrap:wrap;margin-top:9px}.batchActions .pillBtn{min-height:32px;padding:6px 10px}

.batchDateRow{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:9px;padding:9px 10px;border:1px solid var(--divider);border-radius:var(--r-md);background:var(--surface-primary)}
.batchDateLabel{font-size:.78rem;color:var(--text-secondary);font-weight:650}
.batchDateInput{min-width:142px;border:0;background:transparent;color:var(--text-primary);font:inherit;font-size:.82rem;text-align:right;outline:none}

/* ===== Anmeldegitter (auth.js) — Konto ist seit Supabase Pflicht ===== */
/* [hidden] zuerst und eigens: sonst gewinnt die display:flex-Regel
   unten gegen die UA-Regel [hidden]{display:none} (gleiche
   Spezifität, Autor-Herkunft schlägt User-Agent) und das Gitter
   bliebe sichtbar, obwohl auth.js es längst versteckt hat. */
.authGate[hidden]{display:none}
.authCard [hidden]{display:none}
.authGate{position:fixed;inset:0;z-index:500;display:flex;align-items:center;justify-content:center;overflow-y:auto;padding:24px 18px;background:radial-gradient(ellipse at 50% 0%,var(--brand-soft),transparent 56%),var(--bg-primary)}
.authCard{position:relative;width:100%;max-width:420px;padding:clamp(24px,6vw,38px);border:1px solid var(--border-subtle);border-radius:var(--r-xl,24px);background:var(--surface-primary);box-shadow:var(--shadow-lift)}
.authBrand{display:flex;align-items:center;gap:12px;margin-bottom:34px}
.authLogo{width:48px;height:48px;flex:0 0 auto;border-radius:15px;box-shadow:0 4px 12px var(--brand-soft)}
.authBrand span{display:block}
/* Der Schriftzug aus dem Logo (tools/markenbilder.swift), nicht als Text
   gesetzt: das „oo" ist eine gezeichnete Schleife, keine Schrift. Zwei
   Bilder, weil die dunkle Fassung Petrol gegen Creme tauscht. */
.authWortmarke{display:block;height:26px;width:auto}
.wmDunkel{display:none}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="hell"]) .wmHell{display:none}
  :root:not([data-theme="hell"]) .wmDunkel{display:block}
}
:root[data-theme="dunkel"] .wmHell{display:none}
:root[data-theme="dunkel"] .wmDunkel{display:block}
/* Seitenleiste (ab 900 px): derselbe Schriftzug, dunkel in Creme. */
@media (min-width:900px) and (prefers-color-scheme:dark){
  :root:not([data-theme="hell"]) .nav::before{background-image:url("brand/wortmarke-dunkel.png")}
}
@media (min-width:900px){
  :root[data-theme="dunkel"] .nav::before{background-image:url("brand/wortmarke-dunkel.png")}
}
.authBrand span{margin-top:2px;color:var(--text-muted);font-size:.72rem}
.authIntro{margin-bottom:22px}
.authEyebrow{display:block;margin-bottom:8px;color:var(--text-brand);font-size:.66rem;font-weight:780;letter-spacing:.1em}
.authCard h1{font-size:1.8rem;line-height:1.12;letter-spacing:-.035em;font-weight:780;color:var(--text-primary);margin:0 0 9px}
.authHint{font-size:.86rem;line-height:1.5;color:var(--text-secondary);margin:0}
.authFields{display:grid;gap:7px}
.authCard label{display:block;font-size:.76rem;font-weight:680;color:var(--text-primary);margin:8px 0 1px}
.authCard input{width:100%;min-height:48px;padding:12px 13px;border:1px solid var(--border-subtle);border-radius:var(--r-md);background:var(--bg-primary);color:var(--text-primary);font:inherit;font-size:.9rem;transition:border-color .16s ease,box-shadow .16s ease}
.authCard input::placeholder{color:var(--text-muted);opacity:.8}
.authCard input:focus{outline:none;border-color:var(--text-brand);box-shadow:0 0 0 3px var(--brand-soft)}
.authCard input[hidden]{display:none}
.authSubmit{width:100%;min-height:48px;margin-top:20px;border-radius:var(--r-md);font-size:.9rem;font-weight:750}
.authSubmit:disabled{opacity:.62;cursor:wait}
.authError{margin:12px 0 0;padding:9px 10px;border-radius:var(--r-md);background:var(--critical-soft);color:var(--critical-text);font-size:.78rem;line-height:1.4}
.authError.info{background:var(--info-soft);color:var(--info-text)}
.authSwitch{display:block;width:100%;min-height:40px;margin-top:8px;padding:8px;background:none;border:0;color:var(--text-brand);font-size:.8rem;font-weight:680;text-align:center}
.authSwitch:hover{text-decoration:underline;text-underline-offset:3px}
.authForgot{min-height:34px;margin-top:0;color:var(--text-secondary);font-size:.76rem;font-weight:600}
.authSyncNote{display:flex;align-items:center;justify-content:center;gap:7px;margin:20px 0 0;padding-top:15px;border-top:1px solid var(--divider);color:var(--text-muted);font-size:.7rem;line-height:1.4;text-align:center}
.authSyncNote span{color:var(--text-brand);font-size:.95rem;font-weight:800}
.authTestUser{display:block;width:100%;min-height:44px;margin-top:16px;padding:10px 12px;border:1px solid var(--border-subtle);border-radius:var(--r-md);background:var(--fill-subtle);color:var(--text-brand);font:inherit;font-size:.82rem;font-weight:700}
.authTestUser[hidden],.authTestNote[hidden]{display:none}
.authTestUser:active{background:var(--action-secondary)}
.authTestUser:disabled{opacity:.6}
.authTestNote{margin:6px 0 0;text-align:center;color:var(--text-muted);font-size:.68rem;line-height:1.35}
.authCard button:focus-visible{outline:2px solid var(--text-brand);outline-offset:3px}
@media(max-height:600px){.authGate{align-items:flex-start}.authBrand{margin-bottom:22px}.authCard{margin:auto 0}}
.batchDateInput:focus-visible{outline:2px solid currentColor;outline-offset:3px;border-radius:var(--r-sm)}

/* ===== Vorrat & Haltbarkeit: zwei Ringe statt Fähnchen + Hinweistext =====
   "Vorrat" und "Haltbarkeit" stehen als Spaltenkopf EINMAL oben
   (.invShelfColHead) statt auf jeder Zeile zu wiederholen — dieselben
   Spaltenbreiten wie .invShelfRow, damit die Ringe darunter genau
   passen. Die Ringe selbst: ein conic-gradient als Fortschrittsrand
   um ein Loch in Kartenfarbe (dieselbe Technik wie ein Ladekreis),
   die Zeitangabe (T/W/M, siehe invRingZeit()) steht mittig darin. */
.invShelfColHead{
  display:flex;align-items:center;gap:12px;padding:4px 16px 2px;
}
.inventoryAreaNav{margin:8px 0 14px}
.inventoryAreaNav .segmented{
  flex-wrap:nowrap;gap:3px;padding:4px;overflow-x:auto;scrollbar-width:none;
  border:1px solid var(--border-subtle);border-radius:var(--r-lg);
  background:var(--surface-secondary);
}
.inventoryAreaNav .segmented::-webkit-scrollbar{display:none}
.inventoryAreaNav .segmented button{
  flex:1 0 auto;min-height:40px;padding:8px 6px;border-radius:var(--r-md);font-size:.78rem;
  color:var(--text-secondary);font-weight:650;line-height:1.15;white-space:nowrap;
}
/* Waagerecht scrollende Streifen (scrollHinweis() in views.js): folgt
   rechts noch etwas, blendet der Rand weich aus — statt „Aufbra…" oder
   eine halbe Kennzahl hart abzuschneiden. Am Ende verschwindet er. */
.scrollt:not(.amEnde){
  -webkit-mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 36px),transparent);
  mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 36px),transparent);
}
.scrollt.vonLinks:not(.amEnde){
  -webkit-mask-image:linear-gradient(to right,transparent,#000 28px,#000 calc(100% - 36px),transparent);
  mask-image:linear-gradient(to right,transparent,#000 28px,#000 calc(100% - 36px),transparent);
}
.scrollt.vonLinks.amEnde{
  -webkit-mask-image:linear-gradient(to right,transparent,#000 28px);
  mask-image:linear-gradient(to right,transparent,#000 28px);
}
.inventoryAreaNav .segmented button[aria-selected="true"]{
  background:var(--surface-primary);color:var(--text-brand);box-shadow:var(--shadow-control);
}
.inventoryFilterDisclosure{border-bottom:1px solid var(--divider)}
.inventoryFilterDisclosureSummary{min-height:48px;display:flex;align-items:center;gap:8px;padding:7px 14px;color:var(--text-secondary);cursor:pointer;list-style:none}
.inventoryFilterDisclosureSummary::-webkit-details-marker{display:none}
.inventoryFilterDisclosureTitle{color:var(--text-brand);font-size:var(--type-body);font-weight:700}
.inventoryFilterDisclosureMeta{margin-left:auto;color:var(--text-muted);font-size:var(--type-meta)}
.inventoryFilters{display:grid;gap:9px;padding:0 14px 13px}
.inventoryCategoryControl,.inventoryCustomField{display:grid;gap:5px;min-width:0;color:var(--text-secondary);font-size:var(--type-meta);font-weight:650}
.inventoryFilterSelect,.inventoryFilterName{width:100%;min-width:0;min-height:42px;padding:8px 11px;border:1px solid var(--border-subtle);border-radius:var(--r-md);background:var(--bg-secondary);color:var(--text-primary);font:inherit;font-size:var(--type-body)}
.inventoryQuickFilters,.inventorySavedFilters{display:flex;gap:7px;overflow-x:auto;padding:1px 0 3px;scrollbar-width:none}
.inventoryQuickFilters::-webkit-scrollbar,.inventorySavedFilters::-webkit-scrollbar{display:none}
.inventoryFilterChip,.inventorySavedFilterName{flex:0 0 auto;min-height:36px;padding:0 12px;border-radius:99px;background:var(--fill-subtle);color:var(--text-secondary);font:inherit;font-size:.76rem;font-weight:650;white-space:nowrap}
.inventoryFilterChip.on,.inventorySavedFilter.on{background:var(--brand-soft);color:var(--text-brand);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--text-brand) 18%,transparent)}
.inventorySavedFilter{display:flex;align-items:center;flex:0 0 auto;gap:2px;padding:2px;border:1px solid var(--border-subtle);border-radius:99px;background:var(--fill-subtle)}
.inventorySavedFilterName{background:transparent}
.inventorySavedFilterRemove{width:30px;min-height:34px;border-radius:50%;color:var(--text-muted);font-size:1.1rem}
.inventoryFilterBuilder{border-top:1px solid var(--divider);padding-top:8px}
.inventoryFilterBuilder>summary{
  min-height:42px;display:flex;align-items:center;justify-content:space-between;
  color:var(--text-brand);font-size:.84rem;font-weight:680;cursor:pointer;list-style:none;
}
.inventoryFilterBuilder>summary::-webkit-details-marker{display:none}
.inventoryFilterBuilder>summary::after{
  content:"+";width:26px;height:26px;display:grid;place-items:center;
  border-radius:50%;background:var(--brand-soft);font-size:1rem;
}
.inventoryFilterBuilder[open]>summary::after{content:"−"}
.inventoryFilterForm{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px;padding:4px 0 8px}
.inventoryCustomName,.inventoryFilterSave{grid-column:1/-1}
.inventoryFilterSave{min-height:42px;padding:8px 12px;border-radius:var(--r-md);background:var(--action-primary);color:var(--text-on-brand);font:inherit;font-size:var(--type-body);font-weight:700}
.inventoryFilterSave:disabled{opacity:.55}
.inventoryFilterLimit,.inventoryFilterSummary{margin:0;color:var(--text-muted);font-size:var(--type-meta)}
.inventoryFilterReset{justify-self:start;min-height:36px;color:var(--text-brand);font-size:var(--type-meta);font-weight:650}
.inventoryCategoryRows{padding:0 14px}
.inventoryCategoryGroup+.inventoryCategoryGroup{border-top:1px solid var(--divider)}
.inventoryCategoryHeading{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0;padding:8px 2px 4px;color:var(--text-secondary);font-size:.75rem;font-weight:760;letter-spacing:.045em;text-transform:uppercase}
.inventoryCategoryCount{min-width:24px;padding:2px 7px;border-radius:99px;background:var(--fill-subtle);color:var(--text-muted);font-size:.68rem;text-align:center}
.inventoryCategoryGroup .swipeWrap+.swipeWrap{border-top:1px solid var(--divider)}
.inventoryNoMatches{padding:10px 2px}
.coolingAdviceItem+.coolingAdviceItem{border-top:1px solid var(--divider)}
.coolingAdviceRow{display:flex;align-items:center;gap:11px;padding:12px 14px}
.coolingDecisionTrigger{display:grid;place-items:center;flex:0 0 24px;width:24px;height:24px;padding:0;border:2px solid var(--text-muted);border-radius:50%;background:transparent;color:var(--text-brand);font:inherit;font-size:1rem;font-weight:700;line-height:1;transition:background .16s ease,border-color .16s ease,transform .2s ease}
.coolingAdviceItem.decisionOpen .coolingDecisionTrigger{border-color:var(--brand-primary);background:var(--brand-soft);transform:rotate(90deg)}
.stockCheckBody>.row{display:block;padding:15px 2px;background:transparent}
.stockCheckBody>.row+.row{border-top:1px solid var(--divider)}
.stockCheckBody .rowMain{padding:0 0 10px}
.stockCheckBody .rowSub{font-size:var(--type-meta)}
.stockCheckBody .rowActions{gap:8px}
.stockCheckBody .pillBtn{flex:1;min-height:42px;padding-inline:8px}
.sheet:has(.noticeCopy) #sheetCancel{margin-top:14px}
.coolingDecisionPanel{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;max-height:0;padding:0 14px;overflow:hidden;opacity:0;pointer-events:none;transition:max-height .18s ease-out,opacity .14s ease-out,padding .18s ease-out}
.coolingAdviceItem.decisionOpen .coolingDecisionPanel{max-height:64px;padding:0 14px 11px;opacity:1;pointer-events:auto}
.coolingDecisionOption{min-height:38px;padding:7px 10px;border-radius:var(--r-md);background:var(--brand-soft);color:var(--text-brand);font:inherit;font-size:var(--type-meta);font-weight:680}
.coolingDecisionOption:last-child{background:var(--fill-subtle);color:var(--text-secondary)}
.coolingDecisionOption:active{opacity:.7}
@media(prefers-reduced-motion:reduce){.coolingDecisionPanel,.coolingDecisionTrigger{transition:none}}
@media(max-width:380px){.inventoryFilterForm{grid-template-columns:1fr}}
.invShelfColHead > span:nth-child(1){flex:0 0 26px}
.invShelfColHead > span:nth-child(2){flex:1}
.invShelfColTitle{
  flex:0 0 40px;text-align:center;align-self:center;font-size:.62rem;font-weight:760;
  letter-spacing:.02em;text-transform:uppercase;color:var(--text-muted);
}
.invShelfRow{display:flex;align-items:center;gap:12px}
.invShelfRow .rowMain{padding:0}
.invShelfRings{display:flex;gap:10px;flex:0 0 auto}
.invRing{
  --p:0;--clr:var(--success);--size:40px;--thickness:2.5px;
  width:var(--size);height:var(--size);border-radius:50%;
  display:grid;place-items:center;flex:0 0 auto;
  background:
    radial-gradient(farthest-side, var(--surface-primary) calc(100% - var(--thickness) - 1px), transparent calc(100% - var(--thickness))),
    conic-gradient(var(--clr) calc(var(--p) * 1%), var(--fill-strong) 0);
}
.invRing.haltbarkeit{--clr:var(--info)}
.invRing span{font-size:.62rem;font-weight:780;color:var(--text-primary);letter-spacing:-.01em}
.invRing.needsCheck span{font-size:.52rem;letter-spacing:-.035em}
.invRing.isToday span{font-size:.56rem;letter-spacing:-.025em}
.invRing.warning{--clr:var(--warning)}
.invRing.warning span{color:var(--warning-text)}
.invRing.critical{--clr:var(--critical)}
.invRing.critical span{color:var(--critical-text);font-weight:860}
/* Reicht-Ring im Haushalt-Tab ohne Vorhersage (kein gelernter Verbrauch,
   unregelmäßiger Kauf) — ein "–" statt einer erfundenen Zahl, gedämpft
   statt grün/gelb/rot, damit es nicht als echter Status missverstanden wird. */
.invRing.unknown{--clr:var(--fill-strong)}
.invRing.unknown span{color:var(--text-muted);font-weight:700}
