/* ============================================================
   Komponente: nav (Bottom Navigation)
   ------------------------------------------------------------
   Quelle: SKILL.md §7, Figma „Navigation bars & menu".
   Freigegeben am 28.08.2026 — vorher Entwurf im CSS von
   examples/motion-demo.html.

   Setzt tokens.css und base.css voraus. Die Bewegung — Bubble
   700 ms, Icon-Aufstieg, Farbwechsel bei 55 % — steht in
   components/motion.css (§23.3). Diese Datei setzt keine
   transition.

   Die Bottom Nav ist die einzige jederzeit sichtbare Struktur
   der App. Daran hängt §19: solange sie steht, zeigt der Screen
   ein ←; ist sie verdeckt, ein ✕.

   VERWENDUNG
     <nav class="nav" aria-label="Hauptnavigation">
       <span class="nav__grund" aria-hidden="true"></span>
       <span class="nav__bubble" aria-hidden="true">
         <span class="nav__bubble-kern"></span>
       </span>
       <button class="nav__item" aria-current="page">
         <span class="nav__icon"><svg …></svg></span>
         <span class="nav__label nav-label nav-label--active">Entdecken</span>
       </button>
       <button class="nav__item">
         <span class="nav__icon"><svg …></svg></span>
         <span class="nav__label nav-label">Suche</span>
       </button>
     </nav>

   Der aktive Tab hängt an aria-current="page" — nicht an einer
   Klasse. Der Zustand muss auch für Screenreader da sein, und
   motion.css hört auf dasselbe Attribut.

   ZWEI DINGE, DIE IN JS GEHÖREN
   · --nav-rise: die Höhe, um die das Icon aufsteigt, aus der
     tatsächlichen Geometrie gemessen, damit es exakt im
     Bubble-Mittelpunkt landet.
   · --nav-bubble-x: wie weit die Bubble vom linken Rand der Bar
     entfernt steht, damit sie über dem aktiven Tab sitzt.
     NICHT MEHR transform DIREKT — siehe „Ein Wert, zwei Leser"
     weiter unten.
   Beides ist Layout-Rechnung, keine Gestaltung — deshalb kein
   fester Wert hier.
   ============================================================ */

/* DIE BAR IST DECKEND, NICHT TRANSLUZENT. Bis zum 08.09.2026
   stand hier --nav-bg-fill mit einem Blur dahinter. Die
   Komponente benutzt aber gar nicht dieses Token: an
   11136:1400 hängt Surface/surface-secondary (#073359 in Dark,
   Weiß in Light) — eine volle Fläche.

   --nav-bg-fill zeigt in Dark auf transparent-gray-15; darüber
   schimmerten die Bilder durch und die Bar sah grau und
   ausgewaschen aus (Lisi: „der Hintergrund ist transparent und
   blur anstatt volle Fläche").

   Damit fällt auch der Blur weg — hinter einer deckenden Fläche
   gibt es nichts zu verwischen — und die Linie oben: die
   Komponente trägt keinen Strich, die Kante entsteht aus dem
   Farbunterschied zu surface-primary.

   position wird vom Screen gesetzt, nicht hier — im Prototyp
   fixed, im Telefonrahmen absolute. */
/* DIE POLSTER SIND GEMESSEN, nicht Tokens. Figma 11136:1400:
   die Bar ist 81 hoch, ein Feld 62, und es sitzt 15,85 unter der
   Oberkante — unten bleiben 3,15. Vorher standen hier 24 und 12
   aus dem Entwurf in motion-demo.html; damit wäre die Bar 98
   statt 81 hoch. Nachgezogen am 08.09.2026. */
.nav {
  display: flex;
  padding-top: 15.85px;
  padding-bottom: 3.15px;
  /* DIE FLÄCHE LIEGT AUF EINEM PSEUDO-ELEMENT, nicht auf .nav
     selbst. Grund ist die Kerbe: eine Maske an .nav würde auch
     die Kinder beschneiden, und die Bubble sitzt genau in der
     Kerbe — sie verschwand vollständig. Maskiert wird deshalb
     nur der Untergrund. */
  position: relative;

  /* z-index STATT isolation: isolate — BEIDES MACHT EINEN
     STAPELKONTEXT, ABER NUR EINES VERTRÄGT SICH MIT DEM BLUR.

     Gebraucht wird der Stapelkontext, damit die beiden Schichten
     mit negativem z-index (::after und ::before) nicht hinter
     den Untergrund der Seite fallen.

     isolation: isolate macht daraus aber zusätzlich eine
     „Backdrop Root": alles darin sieht nichts mehr, was
     dahinterliegt, und backdrop-filter am ::after hätte nichts
     mehr zu verwischen. z-index: 0 macht denselben
     Stapelkontext ohne diese Nebenwirkung. Nachgemessen am
     09.09.2026. */
  z-index: 0;
}

/* ------------------------------------------------------------
   Der Grund unter der Leiste: „card blur"
   ------------------------------------------------------------
   Quelle: der Wurzelrahmen der Komponente (11136:1400 und
   Geschwister), ausgelesen am 09.09.2026.

   HIER STAND EINE DECKENDE FLÄCHE, UND DAS WAR ZU HART. Am
   08.09.2026 lag unter der maskierten Leiste eine zweite Fläche
   in surface-primary — als Antwort darauf, dass durch die Kerbe
   der scrollende Inhalt blitzte. Das hat den Inhalt zwar
   abgedeckt, aber mit einer harten Kante: in der Kerbe stand ein
   dunkler Fleck (Lisi, 09.09.2026: „bei der nav ist noch der
   hintergrund hinter dem icon hart gefüllt. in figma ist es ein
   leichter blur und gradient damit es leicht überfliest").

   IN FIGMA IST ES DER STIL „card blur". Der Wurzelrahmen der
   Komponente ist 105 hoch — 24 MEHR als die 81 der Leiste — und
   trägt zwei Dinge:

     backdrop-filter  blur(10)
     background       linear-gradient(180deg,
                        Surface/blur-gradient-0  0 %,
                        Surface/surface-card     90,385 %)

   Es ist derselbe Verlauf, den dialog.css schon für das
   Verlaufsband über einer Fußzeile benutzt — und
   --surface-blur-gradient-0 hieß in Figma ursprünglich
   --nav-blur-gradient-0. Der Token gehört also von Anfang an
   hierher.

   DAS LÖST BEIDE PROBLEME AUF EINMAL:
   · In der Kerbe steht kein Loch und kein Fleck, sondern ein
     verwischter, nach unten dichter werdender Schleier. Was
     dahinter scrollt, ist zu ahnen, aber nicht zu lesen.
   · Über der Leiste läuft der Inhalt nicht mehr gegen eine harte
     Kante, sondern in den Verlauf hinein — das ist der Sinn der
     24 zusätzlichen Pixel.

   Die Schicht liegt auf ::after mit z-index -2 und damit UNTER
   ::before (-1), das die Leiste selbst trägt.
   ------------------------------------------------------------ */

.nav::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  /* Die 24, um die der Rahmen in Figma höher ist als die Leiste. */
  top: -24px;
  z-index: -2;
  pointer-events: none;

  /* Der Schleier — Figmas Füllung, unverändert über die vollen
     105. In der Kerbe ist er absichtlich nur teilweise deckend,
     sonst stünde dort wieder ein Fleck. */
  background: linear-gradient(
    180deg,
    var(--surface-blur-gradient-0) 0%,
    var(--surface-card) 90.4%
  );
}

/* ------------------------------------------------------------
   Die weichgezeichnete Schicht darunter
   ------------------------------------------------------------
   SCHLEIER UND BLUR BRAUCHEN VERSCHIEDENE RAMPEN, und eine Maske
   kann nur eine tragen — sie gilt für alles, was ihr Element
   malt. Deshalb liegen sie auf zwei Schichten:

     .nav__grund   z-index -3   der Blur
     .nav::after   z-index -2   der Schleier
     .nav::before  z-index -1   die Leiste mit der Kerbe

   Und deshalb ist .nav__grund ein echtes Element: ::before und
   ::after sind vergeben.

   ZWEIMAL DANEBEN, BEIDE MALE AUS DEMSELBEN GRUND
   1. Blur ohne Rampe (08.09.2026): eine harte waagerechte Kante
      quer durch die Cover, dort wo die Fläche beginnt.
   2. Blur an derselben Rampe wie der Schleier (09.09.2026): im
      ganzen sichtbaren Bereich nur noch ein Viertel bis zwei
      Drittel Blur — „ich sehe jetzt gar keinen blur mehr".

   DIE RAMPE HÄNGT JETZT AM KREIS, NICHT AM RAHMEN (Lisi,
   09.09.2026: „aktuell ist es verschwommen über dem nav blauem
   hintergrund. am besten wenn es dort nicht so stark verschwimmt
   sondern hauptsächlich hinter dem blauen kreis verschwimmt").

   Beide Marken sind gemessen, keine gegriffenen Zahlen:

     16,85   Oberkante des Kreises. 24 − 7,15: der Kreis ragt
             7,15 über die Leiste hinaus. Darüber kein Blur.
     36,86   Mitte des Kreises. 16,85 + 40,02/2. Ab hier voll.

   Über der Leiste bleibt damit nur ein Hauch Blur — und der
   Schleier trägt dort weiter, damit der Inhalt nicht gegen eine
   Kante läuft. Ungebremst ist der Blur genau dort, wo der Kreis
   sitzt und die Kerbe am tiefsten ist.

   Die Maske wirkt in Chrome auf den backdrop-filter; am
   09.09.2026 gegengeprüft, indem sie ab- und wieder angeschaltet
   wurde.
   ------------------------------------------------------------ */

.nav__grund {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  top: -24px;                              /* wie .nav::after */
  z-index: -3;
  pointer-events: none;

  -webkit-mask-image: linear-gradient(180deg, transparent 0, transparent 16.85px, #000 36.86px);
  mask-image: linear-gradient(180deg, transparent 0, transparent 16.85px, #000 36.86px);

  -webkit-backdrop-filter: blur(var(--card-blur));
  backdrop-filter: blur(var(--card-blur));
}

.nav::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;

  background-color: var(--surface-secondary);
}

/* ------------------------------------------------------------
   Bubble
   ------------------------------------------------------------
   Zwei Ebenen mit Absicht: das äußere Element WANDERT
   (translateX), das innere trägt den Kreis. Getrennt, damit sich
   Wandern und ein etwaiger Zug nicht dieselbe
   transform-Eigenschaft teilen und gegenseitig überschreiben.

   DER KREIS BLEIBT IMMER RUND (§23.5). Keine
   Squash-and-Stretch-Verformung beim Wandern: ein Kreis, der
   sich zieht, liest sich als Material, und Material erwartet man
   anfassen zu können. Die Bubble ist eine Ortsmarke, kein
   Objekt.

   KEIN GLOW am aktiven Icon-Kreis — Glow ist Buttons und Chips
   vorbehalten (§7).
   ------------------------------------------------------------ */

/* 40, NICHT 48. Die 48 stammten aus dem Entwurf in
   motion-demo.html. An der Komponente abgelesen (Figma
   11136:1400, Ellipse 26): 40,02 x 40,02. Ihr Mittelpunkt liegt
   3 px über der Oberkante des aktiven Feldes — daher das top.
   Nachgezogen am 08.09.2026. */
.nav__bubble {
  position: absolute;
  /* −7,15 von der Oberkante der Bar. Der Mittelpunkt liegt damit
     bei 12,85 und das sind 3 über der Oberkante des Feldes
     (15,85) — so steht es in Figma. */
  top: -7.15px;
  left: 0;
  display: block;
  width: 40px;
  height: 40px;
  pointer-events: none;

  transform: translateX(var(--nav-bubble-x, 0px));
}

/* ------------------------------------------------------------
   EIN WERT, ZWEI LESER
   ------------------------------------------------------------
   Der Kreis und die Kerbe sind zwei verschiedene Dinge im
   Dokument: der Kreis ist ein Element, die Kerbe ein Loch in der
   Fläche darunter. Beide müssen aber immer an derselben Stelle
   stehen — der Kreis sitzt IN der Kerbe.

   BIS ZUM 09.09.2026 WAREN ES ZWEI BEWEGUNGEN. Der Kreis bekam
   ein transform mit 700 ms Übergang, die Kerbe eine
   Maskenposition aus einer gewöhnlichen Custom Property. Eine
   gewöhnliche Custom Property kennt keinen Übergang: sie
   springt. Der Kreis glitt also zum neuen Tab, und die Kerbe war
   schon dort — sie liefen sichtbar auseinander (Lisi: „der blaue
   kreis smoothed separat von dem dunkelblauem hintergrund").

   JETZT GIBT ES NUR NOCH EINEN WERT. --nav-bubble-x ist über
   @property als Länge angemeldet und damit animierbar; der
   Übergang liegt in motion.css an .nav. Der Kreis liest ihn für
   sein transform, die Kerbe für ihre Maskenposition. Es gibt
   nichts mehr, was auseinanderlaufen könnte — nicht weil zwei
   Bewegungen gut abgestimmt wären, sondern weil es nur eine
   gibt.

   DIE KERBE STEHT 21,16255 LINKS VOM KREIS. Beide haben
   denselben Mittelpunkt, die Kerbe ist 82,3251 breit und der
   Kreis 40: (82,3251 − 40) / 2. Keine gemessene Zahl, sondern
   die Folge der beiden gemessenen Breiten.
   ------------------------------------------------------------ */

@property --nav-bubble-x {
  syntax: '<length>';
  inherits: true;
  initial-value: 0px;
}

.nav {
  --nav-kerbe-x: calc(var(--nav-bubble-x, 0px) - 21.16255px);
}

.nav__bubble-kern {
  /* display MUSS gesetzt sein: ein <span> ist inline, und für
     inline-Elemente gelten weder width/height noch transform —
     der Kreis wäre unsichtbar. */
  display: block;
  width: 100%;
  height: 100%;
  border-radius: var(--radius-full);
  background-color: var(--nav-icon-background-active);
}

/* ------------------------------------------------------------
   Die Kerbe
   ------------------------------------------------------------
   HIER STAND EIN RING, UND DAS WAR FALSCH. Die frühere Fassung
   legte einen 6 px breiten Ring in der Screenfarbe um die Bubble
   — mit der Begründung, eine echte Aussparung müsse bei jeder
   Bewegung neu gemalt werden. Sie sieht aber nicht gleich aus:
   der Ring ist ein harter Kreis von 52 auf der Bar, die Kerbe in
   Figma ist 82,3 breit und läuft mit zwei Schultern weich in die
   Oberkante aus (Lisi, 08.09.2026).

   Die Form ist der Pfad aus Figma (11136:1403, „Subtract"),
   umgerechnet auf den eigenen Nullpunkt: 82,3251 x 39,168. Sie
   liegt als Maske über der Bar und wird abgezogen, statt gemalt
   zu werden — dadurch sieht man dort wirklich die Seite dahinter
   und nicht eine Fläche, die ihr ähnelt.

   Wo sie liegt, sagt --nav-kerbe-x, und das rechnet sich aus
   --nav-bubble-x — demselben Wert, der auch den Kreis bewegt
   (siehe „Ein Wert, zwei Leser“). Die Bubble ist 40 hoch und
   endet bei 32,85; die Kerbe geht bis 39,17 — die 6,3 Luft
   dazwischen sind dieselben, die vorher der Ring hatte.
   ------------------------------------------------------------ */

.nav::before {
  --nav-kerbe: url('data:image/svg+xml;utf8,\
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 82.3251 39.168">\
<path d="M0 0C7.2183 1.21738 11.7771 4.59055 14.2393 11.8281C15.4105 15.271 \
16.8084 20.3294 17.3457 22.2197C20.1202 31.9796 29.5813 39.1678 40.8262 39.168\
C40.9382 39.168 41.0505 39.1645 41.1621 39.1631C41.2741 39.1645 41.3867 39.168 \
41.499 39.168C52.744 39.1678 62.205 31.9796 64.9795 22.2197C65.5169 20.3294 \
66.9148 15.271 68.086 11.8281C70.5481 4.5906 75.1071 1.21741 82.3251 0Z" \
fill="%23000"/></svg>');

  -webkit-mask-image: linear-gradient(#000, #000), var(--nav-kerbe);
  mask-image: linear-gradient(#000, #000), var(--nav-kerbe);
  -webkit-mask-size: 100% 100%, 82.3251px 39.168px;
  mask-size: 100% 100%, 82.3251px 39.168px;
  /* Ohne Ersatzwert: --nav-kerbe-x ist an .nav immer gesetzt.
     Die frühere 18,42 stand für „Kerbe über dem ersten Tab" und
     wäre jetzt eine zweite, stillschweigende Quelle. */
  -webkit-mask-position: 0 0, var(--nav-kerbe-x) 0;
  mask-position: 0 0, var(--nav-kerbe-x) 0;
  -webkit-mask-repeat: no-repeat, no-repeat;
  mask-repeat: no-repeat, no-repeat;
  mask-composite: subtract;
}

/* ------------------------------------------------------------
   Tabs
   ------------------------------------------------------------ */

.nav__item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2xs);
  padding-block: var(--space-2xs);
  background: none;
  border: 0;
  color: var(--nav-text);
  cursor: pointer;
}

.nav__item:active {
  background-color: var(--nav-bg-fill-press);
}

/* Icons liegen ÜBER der Bubble: das aufsteigende Icon muss im
   Kreis sichtbar bleiben. */
.nav__icon {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  height: 28px;
  color: var(--nav-icon);
}

.nav__item[aria-current="page"] .nav__icon {
  color: var(--nav-icon-active);
}

/* ------------------------------------------------------------
   Label
   ------------------------------------------------------------
   Trägt die Information „du bist jetzt hier" und wechselt
   deshalb OHNE Übergang (§23.3). Nachlaufen darf die Form, nicht
   die Auskunft.

   Der frühere eigene Textstil „Bottom Navigation" (14 / 125) ist
   am 28.08.2026 aus Figma entfernt worden. Gewicht und Farbe
   unterscheiden die Zustände, die Größe kommt aus einem
   Standard-Stil.

   GRÖSSE: extra small text (12/18). Am 08.09.2026 an der
   Komponente abgelesen (11136:1400): die Textknoten sind 18 hoch
   — das ist die Zeilenhöhe von extra small, nicht die 21 von
   small. Es passt auch zur Breite: „Entdecken" misst dort 61 in
   einem 72 breiten Feld; mit 14 px wären es rund 71 und das Wort
   stieße an. Die frühere Annahme `small text` kam aus dem
   Entwurf in motion-demo.html und ist damit erledigt.
   Die Klassen .nav-label / .nav-label--active aus base.css
   tragen das Gewicht.
   ------------------------------------------------------------ */

.nav__label {
  font-family: var(--font-family-inter);
  font-size: var(--font-size-extra-small-text);
  line-height: var(--line-height-extra-small-text);
}

.nav__item[aria-current="page"] {
  color: var(--nav-text-active);
}

.nav__item[aria-current="page"] .nav__label {
  font-weight: var(--font-weight-bold);
}

/* ------------------------------------------------------------
   Fokus
   ------------------------------------------------------------ */

.nav__item.is-focus {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}
