/* =========================================================================
   APERTURE — Bauteil-Bibliothek
   Grundlage: exodus/APERTURE-TOKENS.md (gemessene Werte) + exodus/APERTURE-PALETTE.md
   Handwerk:  tzuki/skills/app_designer/SKILL.md Teil 1 (Skala, Raster, Zustände)

   DAS MATERIALGESETZ — drei Materialien, sonst nichts:
     1. PAPIER  ist alles. Geprägt, nie flach. Licht kommt von OBEN LINKS.
     2. TIEFE   erscheint nur, wo das Papier aufgeschnitten ist. Ein Loch,
                keine Farbfläche.
     3. LICHT   ist EIN Punkt und sitzt IMMER in der Tiefe, NIE auf dem Papier.

   Regel 3 ist gerechnet, nicht Geschmack: Gelb auf Papier = 1,4:1,
   Gelb in der Tiefe = 6,7:1. Wer Gelb aufs Papier legt, zerstört beides.

   ==========================================================================
   DIE EINE SONNE — die Regel, an der sich JEDER Schatten dieser Datei misst
   ==========================================================================
   Jakob am 01.08.2026 über die Fassung von gestern, wörtlich:
     „A ist das, was cheap aussieht, WEIL es rundherum diesen Schlagschatten
      hat und nicht sozusagen der Schatten aus derselben Richtung kommt."

   Er hatte recht, und die Ursache war mechanisch: fast jeder Schlagschatten
   hier stand auf `0 Npx` — also OHNE seitlichen Versatz. Ein Schatten ohne
   x-Versatz mit grossem Weichzeichner läuft links und rechts gleich weit
   heraus; das Auge liest ihn als Ring statt als Wurf. Fünfzig Bauteile mit
   einem Ring-Schatten ergeben eine Fläche ohne Lichtquelle.

   DIE SONNE STEHT OBEN LINKS, unter 45 Grad. Nachgemessen, nicht gewählt —
   an `43-card-window.webp` (1677 px breit), 1-px-Abtastung entlang je einer
   Zeile und einer Spalte durch die Karte:
       linke Kante  x = 212 : 246 von 255   HELL (Lichtkante), kein Schatten
       obere Kante  y = 189 : 249 von 255   HELL (Lichtkante), kein Schatten
       rechte Kante x = 1461: fällt auf 112, zurück auf Papier bei 1512
                              → Schatten 51 px WEIT nach rechts
       untere Kante y = 749 : fällt auf  92, zurück auf Papier bei  798
                              → Schatten 49 px WEIT nach unten
   51 zu 49 ist 1,04 : 1. Der Wurf liegt also auf der Diagonalen, und über und
   links vom Bauteil ist überhaupt kein Schatten. Dasselbe Bild gibt die
   Schwerpunktmessung über 24 freigegebene Bilder: die neun mit dem stärksten
   Signal liegen zwischen 101 und 131 Grad (Mittel 118 Grad, 90 = senkrecht
   oben, 135 = oben links). Kein einziges Bild zeigt oben RECHTS.

   DARAUS FOLGEN VIER ZEILEN, die für jedes Bauteil gelten:

     | Ebene     | Lichtkante        | Schatten                        |
     |-----------|-------------------|---------------------------------|
     | erhaben   | innen oben links  | AUSSEN nach unten rechts (x=+y) |
     | bündig    | keine             | keiner, nur eine Kontur         |
     | vertieft  | innen unten rechts| INNEN von oben links (x=+y)     |
     | Loch/tief | Grat unten rechts | INNEN von oben links, stärker   |

   In CSS heisst das: JEDER weiche `box-shadow` (Weichzeichner ab 3 px) hat
   einen Versatz, x und y haben dasselbe Vorzeichen, und x liegt zwischen dem
   0,4- und dem 1,6-fachen von y. Ein `0 0 Npx`-Schatten ist verboten.
   Flächenverläufe laufen auf 135deg (CSS-Winkel) — das ist genau „von oben
   links nach unten rechts".

   ZWEI AUSNAHMEN, und nur diese zwei. Beide stehen im Code mit der Marke
   `SONNE:AUSNAHME` und werden vom Gate übersprungen:
     a) DER LICHTPUNKT. Eine Lichtquelle strahlt in alle Richtungen; ihr Hof
        MUSS rund sein. Er ist kein Schatten.
     b) DIE KONTAKTVERDECKUNG. Wo zwei Flächen sich berühren, fehlt dem
        Streulicht der Weg dazwischen — das ist Umgebungsverdeckung, keine
        Richtung. Erlaubt nur hauchdünn: Weichzeichner höchstens 2 px.

   Erzwungen wird die Regel von `tzuki/tests/test_aperture_sonne.py`, das über
   `scripts/check.sh` bei jedem Commit läuft.

   ==========================================================================
   DIE EBENEN — jede Kante, nicht nur die äusserste
   ==========================================================================
   Jakob am 01.08.2026, nachdem die Sonne-Regel eingebaut war:
     „Jetzt hast du diesen Schatteneffekt auch ZU STARK gemacht, zum Beispiel
      bei dem Knopf unten, da ist er richtig stark. Bei dem Sprechknopf."
     „DER SCHATTENEFFEKT MUSS JEDE KANTE TREFFEN. Also er sollte eher an der
      oberen linken Kante leicht sein, und dann an der Knopfkante ist ja das
      Umgekehrte — da leuchtet Licht drauf, und dann unten an der Kante geht
      es runter, und an der nächsten Kante geht es wieder hoch."
     „Es muss nur eine feste Regel sein, dass man JEDES EINZELNE GEBAUTE DING
      nach der Schatten- und Lichtkonfiguration brieft."

   Das geht über die Sonne-Regel hinaus. Die Sonne sagt, WOHER das Licht
   kommt. Die Ebenen sagen, WIE OFT es umschlägt. Bis heute behandelte jedes
   Bauteil genau EINE Kante — die gegen seinen eigenen Untergrund. Ein Stapel
   aus drei Bauteilen hatte deshalb einen beleuchteten Rand und innen nichts;
   das Auge liest so etwas als Klecks, nicht als Objekt.

   DIE LEITER. Fünf benannte Höhenstufen, jede mit EINER Zahl (`--ap-hoehe`)
   und EINEM fertigen Schattensatz. Ein Bauteil wählt eine Stufe; es stellt
   sich seine Schatten nicht mehr selbst zusammen.

     | Stufe | Name    | --ap-hoehe | Satz                       |
     |-------|---------|-----------:|----------------------------|
     | Träger  | liegt hoch auf |  +2 | --praegung-erhaben-hoch    |
     | Auflage | liegt auf      |  +1 | --praegung-erhaben         |
     | Fläche  | ist der Grund  |   0 | keiner                     |
     | Senke   | eingedrückt    |  -1 | --praegung-vertieft        |
     | Loch    | durchgeschnitten| -2 | --praegung-vertieft-tief   |
     |         |                |     | bzw. --loch-innen/-kante,  |
     |         |                |     | wenn die Tiefe sichtbar ist|

   DIE REGEL IN EINEM SATZ:
     An JEDEM Übergang zwischen zwei ineinanderliegenden Bauteilen muss sich
     die Höhe ändern. Wer höher liegt als sein Untergrund, bekommt die
     Lichtkante innen oben links und wirft nach unten rechts; wer tiefer
     liegt, bekommt den Schatten innen oben links und die Lichtkante innen
     unten rechts. Zwei ineinanderliegende Bauteile derselben Höhe haben
     keine Kante — und sind damit ein Fehler, kein Sparen.

   DER SPRECHKNOPF IST DER VORFÜHRFALL. Vier Ebenen, drei Vorzeichenwechsel,
   genau Jakobs „runter, hoch, runter":

       .ap-fussleiste    +1   Papier liegt auf         Licht oben links
         .ap-mulde       -2   ins Papier geschnitten   RUNTER  → Schatten innen oben links,
                                                                heller Grat innen unten rechts
           .ap-sprechknopf +2 sitzt in der Mulde       HOCH    → Lichtkante oben links auf ihm,
                                                                Wurf nach unten rechts IN die Mulde
             .ap-symbol   -1  ins Papier geprägt       RUNTER  → dunkle Rille, heller Lippenrand
                                                                unten rechts

   WARUM DIE ZAHL UND NICHT NUR DER SCHATTEN: Ein `box-shadow` sagt einer
   Maschine nicht, ob er eine Erhebung oder eine Vertiefung meint — das war
   der ausdrückliche Grund, warum die erste Fassung des Gates nur die
   Geometrie prüfen konnte. `--ap-hoehe` schreibt die Absicht hin. Damit kann
   `tzuki/tests/test_aperture_sonne.py` die VERSCHACHTELUNG prüfen: es liest
   die HTML-Dateien, baut den Elternstapel und meldet jedes Paar, das
   ineinanderliegt, ohne dass eine Kante entsteht.

   ==========================================================================
   DIE DOSIS — abgelesen, nicht gewählt
   ==========================================================================
   Jakobs zweiter Satz war „zu stark". Die Stärke stand vorher auf runden
   Zahlen, die niemand hergeleitet hatte. Sie steht jetzt auf Messungen an
   `35-speech-button-rest.webp` (1254 px, die freigegebene Vorlage GENAU
   dieses Bauteils) und `43-card-window.webp`.

   35-speech-button-rest, Strahlen vom Mittelpunkt, Helligkeit von 255,
   Papier = 218. Scheibenradius 315 px; im Produkt ist der Sprechknopf 56 px
   breit, also Radius 28 px — Massstab 0,0889:

       oben links (135°)  Lichtkante Spitze 250  (+32), DANACH KEIN SCHATTEN
       oben       ( 90°)  Lichtkante Spitze 246  (+28)
       links      (180°)  Lichtkante Spitze 241  (+23)
       unten rechts (315°) 104 an der Kante, dann 113·115·130·137·157·171·
                           179 … 195 … 207 — Papier erst weit draussen

   In Bauteil-Pixeln umgerechnet ergibt das die Sollkurve des Wurfs:
       an der Kante  52 % dunkler   ← das ist die KONTAKTLINIE, hart
       1,4 px        40 %
       2,5 px        28 %
       3,6 px        22 %
       5   px        18 %
       9   px        11 %
      12,4 px         5 %
   Die alte Fassung lag bei 2–3 px bei rund 44 % (also die Hälfte zu dunkel)
   und trug ihren Wurf bis über 20 px hinaus (also 1,6-fach zu weit). Genau
   das ist „richtig stark".

   43-card-window, Fenster 1155 × 264 px, Grundton der Tiefe 76 von 255, von
   der Schnittkante nach innen: 13 · 29 · 39 · 42 · 52 · 56 · 62 · 66 · 68 ·
   71 — nach 27 px ist der Schatten praktisch weg. Die Karte ist im Bild
   1249 px breit und im Produkt 358 px, Massstab 0,287, also endet der
   Schlagschatten IN der Tiefe nach rund 8 px. Die alte Rampe lief bis 32 px
   und war damit rund viermal zu lang — das ist der Grund, warum der 8 px
   breite blaue Ring um den Sprechknopf durchgehend fast schwarz war.
   ==========================================================================

   Namensregel: alle Klassen beginnen mit `ap-`. Zustände als `.ist-*`.
   ========================================================================= */

/* --- Animierbare Eigenschaften -------------------------------------------
   Ohne @property sind Custom Properties für den Browser nur Text und lassen
   sich nicht animieren — die Blende könnte dann nur springen, nicht öffnen. */
@property --ap-oeffnung { syntax: "<length>"; inherits: true; initial-value: 0px; }
@property --ap-drehung  { syntax: "<angle>";  inherits: true; initial-value: 0deg; }

/* DIE HÖHE EINES BAUTEILS — der maschinenlesbare Teil des Ebenengesetzes.
   `inherits: false` ist hier keine Formsache: Erbte die Höhe nach unten, hätte
   ein Symbol IN einem Knopf automatisch die Höhe des Knopfes, und weder der
   Browser noch eine Prüfung könnte „liegt darauf" von „ist dasselbe" trennen.
   Genau diese Trennung ist der ganze Punkt (siehe DIE EBENEN weiter unten). */
@property --ap-hoehe { syntax: "<integer>"; inherits: false; initial-value: 0; }

/* IST DAS BAUTEIL EIN KÖRPER? — neu 02.08.2026, und es beantwortet eine
   Frage, die `--ap-hoehe` NICHT beantworten kann.
   Die Höhenleiter sagt, WIE TIEF etwas liegt. Sie sagt nichts über die GRÖSSE.
   Für das Auge ist das aber der Unterschied zwischen einem Objekt und einer
   Textur: gemessen an den zehn Originalbildern tragen dort die fünf grössten
   modellierten Körper 46–83 % der modellierten Fläche, im eigenen Musterbogen
   nur 25–51 % (Messung: `design/exodus/tiefe/TIEFE.md`, Abschnitt 2b). Die
   Vorlage VERTEILT ihre Tiefe nicht, sie KONZENTRIERT sie.
   `--ap-koerper: 1` heisst deshalb: dieses Bauteil ist ein tragender Körper,
   an dem das Auge Tiefe festmacht — und nicht Möblierung. Ein 6-px-Lichtpunkt
   (`.ap-zeile__signal`) steht auf Stufe −2 wie ein ganzes Kartenfenster; ohne
   diese zweite Angabe zählt eine Prüfung beides gleich und ist wertlos.
   Die Eigenschaft wird zur Laufzeit von NICHTS gelesen. Sie steht hier, damit
   die Regel „höchstens zwei Körper je Bildschirm" an EINER Stelle definiert
   ist und nicht als abgetippte Klassenliste in einem Test — diese zweite
   Liste war in diesem Projekt schon mehrfach die Fehlerquelle. */
@property --ap-koerper { syntax: "<integer>"; inherits: false; initial-value: 0; }

/* Wie stark der überstrahlte Kern eines Lichtpunkts ausgeprägt ist — 0 bei
   einem winzigen Punkt, 1 bei einem grossen. Wird aus `--punkt-groesse`
   gerechnet, nicht gesetzt; die Begründung steht bei `--punkt-kern`. */
@property --punkt-kernstaerke { syntax: "<number>"; inherits: true; initial-value: 1; }

:root {
  /* --- Materialien (gemessen, nicht geschätzt) --------------------------- */
  --papier:        #E8DCCC;
  --papier-hell:   #F0E4D8;   /* Lichtkante der Prägung, oben/links */
  --papier-dunkel: #D8CCBC;   /* Schattenkante der Prägung, unten/rechts */

  --tiefe:         #204080;
  --tiefe-rand:    #102858;
  --tiefe-kern:    #000818;

  /* --- DAS LICHT ---------------------------------------------------------
     DREI Werte statt zwei, und der dritte ist der neue: `--punkt-kern`.

     Jakob am 01.08.2026: „Der innerste Punkt darf noch ein bisschen weisser
     sein — je heller etwas leuchtet, desto weisser wird es ja auch."

     Das ist am Bild nachgemessen und stimmt. 1-px-Ringe um das hellste Pixel
     des Lichtpunkts, Buntheit als HSV-Sättigung:
         13-aperture-light   r=0 #FCEDA7 Sättigung 0,34
                             r=2 #EBC987 Sättigung 0,42
                             r=4 #D8B07A Sättigung 0,44   ← Gipfel der Buntheit
                             r=8 #A88C70 Sättigung 0,33
         21-slit-light       r=0 #F5C66B 0,56 · r=2 #DDA454 0,62 ← Gipfel
         22-slit-light-upper r=0 #F5BE4F 0,68 · r=2 #DA9A38 0,74 ← Gipfel
     In ALLEN drei Bildern liegt der Buntheitsgipfel NICHT in der Mitte,
     sondern in einem Ring darum; die Mitte ist heller UND blasser. Genau so
     verhält sich eine überstrahlende Lichtquelle. Der bisherige Punkt hatte
     diesen Kern nicht — er war Vollton plus Hof, und das ist die „zu wenig
     Nuancen"-Beobachtung.

     KORRIGIERT 01.08.2026, ABENDS. Jakob über die Fassung von heute Mittag:
     „Ich sehe jetzt schon, dass DAS WEISS ZU STARK IM KERN ist. ES SIEHT AUS
      WIE EIN PUNKT — also das Weiss muss sich auch verlaufen, zu dem Rest.
      Und vielleicht ist es auch zu stark weiss, weil das hier eigentlich
      einen GELB leuchtenden Punkt haben will." · „Und dieses Weiss in der
      Mitte hat es nur verschlechtert. Das musst du anders lösen." · „Auch in
      dem kleinen Bild, wo Tagesgeld steht, sieht man den weissen Punkt schon
      — das sieht unangenehm aus."

     Er hat mit der Beobachtung von heute Mittag recht behalten (die Mitte IST
     heller), aber die Umsetzung war an drei Stellen falsch, und alle drei
     sind mechanisch:

       1. DER WERT WAR ZU WEISS. `#FFF4CE` ist rechnerisch 73 % Weiss, gemischt
          mit dem Bernstein. Der GEMESSENE Kern im freigegebenen Bild
          `13-aperture-light` ist `#FCEDA7`, und das sind 52 %. Der Kern
          steht jetzt auf der gemessenen Zahl statt auf einer gewählten —
          `color-mix(in srgb, #FFFFFF 52%, var(--licht))` ergibt `#FCE8AF`
          gegen gemessene `#FCEDA7`, also drei Einheiten von 255 daneben.
          Zweiter Gewinn: der Kern ist damit KEIN eigener Hexwert mehr. Jede
          Akzentfarbe bekommt ihren Kern aus ihrer eigenen Farbe, und die
          Liste `--gruen-kern` / `--warnrot-kern` fällt ersatzlos weg. Ein
          weisser Kern in einer grünen Lampe war genau die zweite Liste.
       2. ER HATTE EINE KANTE. Der alte Verlauf hielt den Kern von 0 bis 13 %
          als FLÄCHE und sprang dann in einem Schritt auf eine 55-%-Mischung.
          Eine Fläche mit einem Sprung ist ein zweiter Punkt, kein Ausbrennen.
          Jetzt sieben Stopps ohne Plateau, und `closest-side` statt der
          Vorgabe `farthest-corner`: vorher lag der Hof-Anteil ab 71 %
          ausserhalb des Kreises und wurde weggeschnitten — der Punkt endete
          mitten im Verlauf, also mit einem Rand.
       3. ER SKALIERTE NICHT MIT. In der Listenzeile ist der Punkt 8 px gross.
          Ein überstrahlter Kern ist aber die Eigenschaft einer AUFGELÖSTEN
          Lichtquelle; was kleiner ist als das, was das Auge trennt, ist ein
          heller Fleck und sonst nichts. `--punkt-kernstaerke` rechnet das aus
          der Grösse: bei 8 px bleiben 17 % Weiss (der Punkt ist dann einfach
          gelb, gruen oder rot), ab 32 px die gemessenen 52 %. */
  --licht:         #F8D058;   /* die Farbe selbst, Buntheitsgipfel — 6,72:1 */
  /* `--licht-hof` steht NICHT mehr hier, sondern unten im gemeinsamen
     Erklärungskopf: er wird seit dem 02.08.2026 aus `--licht` gerechnet und
     muss deshalb dort neu aufgelöst werden, wo eine Akzentfarbe gesetzt ist.
     Stünde er in `:root`, bekäme eine grüne Lampe wieder einen gelben Rand —
     genau der Fehler vom 01.08. Die Begründung steht bei den Akzentsätzen. */

  /* --- DIE AKZENTSÄTZE ----------------------------------------------------
     Jakob hat die Reihe vom 31.07. verworfen: „Das Grün, Gelb und Rot
     leuchten in diesen Quadraten. Das hat nicht funktioniert. Das Grün ist
     immer noch sehr stark gelblich und das Rot ist immer noch sehr stark
     gelblich. Du musst schon dann das Leuchten komplett in die Farbe
     ummünzen." · „Rot wird zu Lachs. Lachs ist nicht cool." · „Dieses
     minzige Grün, so will ich das nicht."

     DER KONSTRUKTIONSFEHLER lag nicht im Geschmack, sondern in der
     Nebenbedingung: die Reihe war in OKLCH bei KONSTANTER Helligkeit und
     Buntheit gerechnet, damit die Töne „fair vergleichbar" sind. Bei der
     Helligkeit eines freundlichen Bernsteins KANN Rot nur Lachs werden, und
     Grün wird zwangsläufig blass. Gleichbehandlung war die falsche Vorgabe:
     ein Warnrot IST dunkler und satter als ein Bernstein, das ist seine
     Natur und keine Verzerrung.

     Neue Nebenbedingung: jede Farbe so satt, wie ihre Aufgabe es verlangt.
     Was das bringt, in OKLCH-Buntheit C gerechnet:
         Grün   alt #9CEC93 C = 0,143   →   neu #3ED16A C = 0,189   (+32 %)
         Rot    alt #FFAE9D C = 0,099   →   neu #FF3B21 C = 0,234  (+136 %)
     Der alte Rot-Wert lag mit C = 0,099 unter dem heutigen Bernstein — er
     war rechnerisch weniger bunt als Gelb. Das ist „Lachs" in einer Zahl.

     JEDER SATZ HAT SEINEN EIGENEN HOF. Das ist der zweite Teil von Jakobs
     Satz („das Leuchten komplett in die Farbe ummünzen"): ein grüner Kern in
     einem bernsteinfarbenen Hof ist keine grüne Lampe, sondern eine gelbe
     Lampe mit grünem Fleck.

     Kontrast auf der Tiefe (#204080), nach WCAG gerechnet — Zahlen und
     Einordnung stehen vollständig in `exodus/APERTURE-TOKENS.md`:
         Grün      Kern 9,33 · Licht 5,00 · Hof 2,59
         Bernstein Kern 9,06 · Licht 6,72 · Hof 5,03
         Warnrot   Kern 8,43 · Licht 2,80 · Hof 1,61
     DAS WARNROT LIEGT UNTER DER SCHWELLE, und das ist nicht wegzurechnen:
     Rot trägt nur 21 % zur Helligkeit bei, ein satter roter Ton ist auf
     diesem Blau zwangsläufig dunkel. Getragen wird die Sichtbarkeit vom
     weissglühenden Kern (8,43:1). Deshalb bekommt Rot zusätzlich ein
     ZWEITES, farbunabhängiges Merkmal — grösser und langsam pulsierend
     (`.ap-punkt--warnung`). Ein Nutzer mit Rot-Grün-Schwäche (rund 8 % der
     Männer) erkennt Rot dann an Grösse und Bewegung, nicht an der Farbe.

     NACHGEZOGEN 01.08.2026, ABENDS — zwei Sätze von Jakob:
     „DAS GRÜN IST MIR NOCH NICHT DUNKELGRÜN GENUG. Es sieht noch immer ein
      bisschen hellminzig aus." · „Wenn das mit dem Rot auf die konventionelle
      Art und Weise nicht passt, dann mach's halt anders. ES MUSS EINFACH EIN
      ROTER, LEUCHTENDER PUNKT SEIN, ja — und beim Grün genauso."

     GRÜN: `#3ED16A` → `#09AC40`. In OKLCH ist das L 0,761 → 0,650, also
     15 % dunkler, bei C 0,189 → 0,191. „Minzig" ist nicht der Farbwinkel,
     sondern das Verhältnis Buntheit zu Helligkeit: es steigt von 0,249 auf
     0,294, um 18 %. Ein Ton mit viel Helligkeit und wenig Farbe ist Mint,
     einer mit derselben Farbe bei weniger Helligkeit ist Grün. Der
     Farbwinkel bleibt bei 147 Grad und damit weg von 155–165 Grad, wo Grün
     tatsächlich Richtung Mint kippt. `#09AC40` liegt auf 1,5 % genau am Rand
     des sRGB-Raums — satter geht bei dieser Helligkeit nicht mehr.
     Der Hof folgt: `#12963C` → `#048824` (L 0,589 → 0,545, C 0,167 → 0,170).
     WEITER DUNKELN GEHT, ABER NICHT UNBEGRENZT: bei L = 0,60 fällt der
     Kontrast gegen die Tiefe unter 3:1, und das ist die Schwelle, die WCAG
     für grafische Elemente verlangt. `#09AC40` misst 3,32:1 und liegt damit
     knapp darüber. Wenn Jakob noch dunkler will, ist das die Grenze, an der
     es begründet werden muss.

     ROT: `#FF3B21` BLEIBT, und das ist ein Messergebnis, keine Bequemlichkeit.
     Bei seiner Helligkeit (L = 0,653) ist die maximal mögliche Buntheit im
     sRGB-Raum C = 0,234 — genau darauf steht der Wert bereits. Satter kann
     dieses Rot nur werden, indem es dunkler wird, und dunkler leuchtet es
     weniger. Was sich ändern MUSSTE, war nicht der Farbwert, sondern der
     weisse Kern darüber (siehe oben). Der Hof geht von `#C01A0E` auf
     `#C40B01`, also C 0,199 → 0,209 bei gleicher Helligkeit.

     KONTRAST, EHRLICH: auf der Tiefe misst das neue Grün 3,32:1 statt 5,00:1.
     Für Text wäre das zu wenig; der Punkt ist ein grafisches Element, und
     dort verlangt WCAG 3:1 — erfüllt. Das Warnrot bleibt bei 2,80:1 und damit
     unter jeder Schwelle. Jakob hat das ausdrücklich in Kauf genommen („dann
     mach's halt anders"). Die Zahl steht hier als HINWEIS, nicht als Sperre;
     getragen wird die Sichtbarkeit vom Kern und vom zweiten, farbunabhängigen
     Merkmal (`.ap-punkt--warnung`).

     Die Kerne `--gruen-kern` und `--warnrot-kern` sind ERSATZLOS WEG. Sie
     werden aus der jeweiligen Farbe gerechnet (siehe `--punkt-kern`), womit
     eine grüne Lampe zwangsläufig einen grünen Kern hat, statt dass jemand
     ihn danebenschreiben muss. */

  /* AUCH DIE HÖFE SIND WEG — 02.08.2026. Jakob hat den Fehler an der
     Ampel-Probe gesehen:
       „Beim gelben Punkt hast du minimal drumherum eine ORANGENE Kante
        gemacht. Ist beim grünen Punkt minimal drumherum eine dunkelgrünere
        Kante? NUN, ICH SEH DIE NUR NICHT. Das gleiche Prinzip musst du dort
        auch anwenden, damit die vergleichbar aussehen." · „Dann muss er
        eigentlich DUNKELGRÜN als Kreis, und um den roten Punkt muss auch ein
        DUNKELROT als Kreis."

     Er hat recht, und es ist nachgerechnet. Die drei Paare Farbe→Hof standen
     von Hand nebeneinander und waren dadurch drei verschiedene Schritte
     (OKLCH, Helligkeit L und Buntheit C):
         #F8D058 → #F8A808   L ×0,908   C ×1,159   Farbwinkel 90,6 → 74,5
         #09AC40 → #048824   L ×0,840   C ×0,892   Farbwinkel 147,1 → 145,0
         #FF3B21 → #C40B01   L ×0,793   C ×0,892   Farbwinkel 31,1 → 29,7
     Drei Farben, drei Schritte — das ist der Grund, warum die Ränder nicht
     vergleichbar aussahen. Am Punkt gemessen (1-px-Abtastung quer durch den
     8-px-Punkt in der Listenzeile) sah man genau das: der gelbe Rand sprang
     von #F8D058 auf #F9C746, der grüne nur von #09AC40 auf #069C34 — ein
     Schritt, den man bei 8 px nicht mehr trennt.

     JETZT WIRD DER RAND GERECHNET, nicht gesetzt: `--licht-hof` steht weiter
     unten im gemeinsamen Erklärungskopf und entsteht aus `--licht` selbst.
     Die beiden Faktoren sind AN DEM EINEN GEMESSENEN PAAR geeicht — dem
     Bernstein, dessen Werte aus den freigegebenen Bildern stammen: L ×0,908
     und C ×1,159. Damit hat jede Farbe denselben Schritt (Punkt zu Rand
     misst bei allen dreien 1,28–1,31:1 Helligkeitsverhältnis).
     DER FARBWINKEL BLEIBT, und das ist eine Entscheidung: der Bernstein
     dreht in der alten Liste um 16 Grad (Gelb → Orange), aber Jakob verlangt
     ausdrücklich „dunkelgrün" und „dunkelrot" — dieselbe Farbe, dunkler und
     satter. Eine mitgedrehte Kante hätte aus dem Grün ein Oliv gemacht.
     Der Bernstein-Rand wandert dadurch von #F8A808 (Orange) auf rund
     #E2B500 (tiefes Gold). Das ist der Preis, und er ist klein: der
     gemessene Wert war der HOF EINER LEUCHTENDEN LAMPE, und das Leuchten ist
     seit dem 02.08. nicht mehr der Standard (siehe DER FLACHE PUNKT unten).

     GRÜN MINIMAL DUNKLER — 02.08.2026, Jakob: „Ich glaub, das Grün kann noch
     ein bisschen dunkler oder kontrastreicher, minimal." · „Der Punkt ist zu
     minzig."
     `#09AC40` → `#00A83C`: OKLCH-Helligkeit 0,649 → 0,636, und die Buntheit
     steht mit C = 0,189 exakt auf dem sRGB-Rand dieser Helligkeit (vorher lag
     sie mit 0,1905 knapp INNERHALB, also 1,5 % unter dem Möglichen). Der
     Kontrast gegen die Tiefe fällt von 3,32:1 auf 3,16:1 und bleibt damit
     über den 3:1, die WCAG für grafische Elemente verlangt. Mehr geht nicht:
     bei L = 0,623 sind es 2,99:1.
     DIE MINZIGKEIT KAM ABER ÜBERWIEGEND WOANDERS HER, und das gehört dazu:
     der leuchtende Punkt mischte in seinen Kern 52 % Weiss — aus dem Grün
     wurde dabei rechnerisch `#89D7A3`, und das IST Mint. Mit dem flachen
     Punkt fällt dieser Kern ersatzlos weg. Die Farbe selbst war nur der
     kleinere Teil des Problems. */
  --gruen:         #00A83C;
  --warnrot:       #FF3B21;

  --tinte:         #1A1A1A;   /* 12,9:1 auf Papier — gemessen */
  --tinte-hell:    #FFFFFF;   /* 10,0:1 auf Tiefe — Schrift IM Ausschnitt */

  /* ABWEICHUNG VOM TOKEN-BLATT, und zwar bewusst.
     APERTURE-TOKENS.md nennt für den Nebenrang `#6E6459` und dazu „4,9:1".
     Nachgerechnet sind es 4,28:1 — das liegt UNTER der Pflichtschwelle 4,5:1,
     jeder Nebentext wäre damit ein Kontrastfehler. `#665C52` ist derselbe
     warme Ton, eine Spur dunkler, und misst 4,83:1.
     Auch die übrigen Kontrastzahlen des Token-Blatts sind gerundet danebe(n):
     Tinte 12,9 statt 14,6 · Weiss auf Tiefe 10,0 statt 9,4 · Licht auf Papier
     1,10 statt 1,40. Am Gesetz ändert das nichts — Gelb auf Papier ist sogar
     noch schlechter als dort behauptet. Das Token-Blatt gehört korrigiert. */
  --tinte-leicht:  #665C52;

  /* Der Schattenton. Kein Grau: Papier wirft einen WARMEN Schatten, ein
     neutraler Schatten lässt dieselbe Prägung sofort nach Kunststoff aussehen. */
  --schatten-0:  rgba(60, 45, 30, .07);   /* neu 01.08. — der Saum des Wurfs */
  --schatten-1:  rgba(60, 45, 30, .13);
  --schatten-2:  rgba(60, 45, 30, .20);
  --schatten-3:  rgba(60, 45, 30, .34);

  /* --- DIE KANTE ---------------------------------------------------------
     NACHGEMESSEN 01.08.2026 an den freigegebenen Bildern (40-list-row-empty,
     41-list-row-signal, 43-card-window), pixelweise über Canvas, Mittelwert
     der hellsten bzw. dunkelsten 0,5 % der Fläche:

       Lichtkante   Bild #FDF7ED · #FDF8EB · #FDF5E5   →  fast Weiss
       Kontaktlinie Bild #060F18 · #061222 · #081833   →  KALT, blauschwarz

     Dagegen die bisherigen Werte: `--papier-hell` misst gegen das Papier
     1,08:1, `--papier-dunkel` 1,17:1 — die Lichtkante ist also praktisch
     unsichtbar. Der gemessene Bildwert kommt auf 1,26:1, also den rund
     dreifachen Helligkeitsschritt. DAS ist der mechanische Grund für Jakobs
     „insgesamt noch ein bisschen dull, es poppt noch nicht" (01.08.) — nicht
     das Blau (siehe Notiz beim Ausschnitt).

     Warum zwei zusätzliche Variablen statt geänderter Materialwerte:
     `--papier-hell`/`--papier-dunkel` sind FLÄCHENtöne (die Wölbung) und dort
     richtig — eine fast weisse Fläche wäre kein Papier mehr. Was fehlte, ist
     der Ton der SCHNITTKANTE selbst, und der ist im Streiflicht immer heller
     als die Fläche. Deshalb hier eigene Kantenwerte.
     Der Kontaktschatten ist bewusst KALT: direkt unter einem aufliegenden
     Blatt sieht man kein Streulicht, sondern den blauen Schatten des
     Umgebungslichts. Warm bleibt nur der weite, weiche Schatten. */
  --kante-licht:   #FCF6EC;                 /* gemessen ~#FDF7ED */
  --kante-licht-w: rgba(252, 246, 236, .72);/* dieselbe Kante, seitlich schwächer */
  --kante-tief:    rgba(6, 15, 26, .50);    /* die Kontaktlinie, gemessen ~#060F18 */
  --kante-tief-w:  rgba(6, 15, 26, .22);

  /* DIE FASE UNTER EINER VERTIEFUNG — zwei Ausklangstufen, neu 02.08.2026
     (P2 aus `design/exodus/tiefe/TIEFE.md`). Sie sind kein neuer Farbton,
     sondern `--kante-licht` in zwei fallenden Deckungen; sie stehen hier als
     eigene Namen, damit die Reichweite an EINER Stelle nachzulesen ist.
     Belegt an einer Spalte durch die Mitte von `bilder/orig-zeile.png`
     (Helligkeit von 255, Papier = 221):
         233 → 238 → 228 → 224 → 222 → 221    über 6 px
     Also: harter heller Ansatz direkt an der Kante, Spitze +17, weicher
     Ausklang über 6 px. Wir hatten dafür exakt 1 px Vollton und danach
     nichts. Das ist dieselbe Regel wie oben beim Wurf, nur gespiegelt —
     scharfer Ansatz, leiser Ausklang. */
  --kante-fase-1:  rgba(252, 246, 236, .55);
  --kante-fase-2:  rgba(252, 246, 236, .28);

  /* DIE GEGENKANTE — neu am 02.08.2026, und sie behebt einen echten Fehler.
     Auf der unteren rechten Seite eines erhabenen Bauteils lag bisher
     `--papier-dunkel` (#D8CCBC). Nachgemessen am Sprechknopf von
     `reise/09-erledigt.html` (waagerechter Schnitt durch die Mitte,
     Helligkeit von 255):
         … 47 px: 206 · 48: 204 · 49: 200 · 50: 198 · 51: 195 · 52: 192 ·
         53: 187 · 54: 205 · 55: 205 ← die „dunkle" Kante
     Die Kante war also HELLER als die Fläche unmittelbar daneben (205 gegen
     187) und las sich damit als zweite helle Lippe. Ursache ist die
     Reihenfolge der Schattenlagen: die harte 2-px-Kante wird ÜBER die weiche
     Fase gemalt, und die Fase hatte die Fläche schon auf 187 abgedunkelt.
     Eine Kante mit zwei hellen Seiten ist keine Kante — das ist genau Jakobs
     Regel vom 02.08. von der anderen Seite gelesen.
     Der neue Wert ist gegen diese Messung gerechnet und nicht gewählt: er
     muss unter 187 liegen. `--papier-dunkel` zu 80 % mit dem Schattenton
     gemischt ergibt rund 173 und damit einen sichtbaren Absatz nach unten.
     Das FLÄCHENpaar `--papier-hell`/`--papier-dunkel` bleibt unangetastet;
     das hier ist ein KANTENton, wie `--kante-licht` auch. */
  --kante-dunkel:  color-mix(in srgb, var(--papier-dunkel) 80%, rgb(60, 45, 30));

  /* --- Prägung als fertige Schattensätze ---------------------------------
     ERFAHRUNG AUS DEM ERSTEN DURCHGANG: Kanten allein reichen nicht. Mit nur
     einer Licht- und einer Schattenkante sieht die Fläche aus wie ein Rechteck
     mit Rahmen, nicht wie ein Stück Papier. Was fehlt, ist die WÖLBUNG — eine
     erhabene Fläche ist oben links minimal heller und unten rechts minimal
     dunkler als in der Mitte. Deshalb gehört zu jeder Prägung ein
     Flächenverlauf (`--wölbung-*`), nicht nur ein Schattensatz.

     VERSTÄRKT 01.08.2026 (Jakob: „die Kanten waren dicker … wie von
     dreidimensionalen Objekten", „es darf gerne etwas dreidimensionaler
     sein"). Drei Dinge sind neu, alle drei am Bild abgelesen:
       1. Die Lichtkante ist jetzt `--kante-licht` (fast Weiss) statt
          `--papier-hell` und 2 px statt 1 px dick.
       2. Dazu kommt eine weiche FASE: ein Innenschatten mit negativem
          Streuradius, der nur an der Kante sichtbar wird. Eine harte 2-px-
          Linie allein sieht aus wie ein Rahmen; erst die Fase daneben macht
          daraus eine abgerundete Materialkante.
       3. Unter dem Bauteil liegt eine KALTE Kontaktlinie (`--kante-tief`).
          Sie ist im Bild der dunkelste Punkt überhaupt und trägt fast die
          ganze Räumlichkeit — ein Bauteil ohne sie schwebt nicht, es klebt.
     AUF DIE EINE SONNE GEZOGEN 01.08.2026 (siehe den Block ganz oben). Drei
     Änderungen, alle mechanisch und alle mit demselben Grund:
       1. Licht- und Schattenkante liefen bisher als ZWEI Schatten (einer für
          oben, einer für links) mit unterschiedlicher Stärke — die Kante oben
          war 2 px in `--kante-licht`, die Kante links 1 px in der schwächeren
          Fassung. Am Bild sind beide gleich hell (obere Kante 249, linke
          Kante 246 von 255). Jetzt EIN Schatten mit gleichem x und y, der
          beide Seiten in einem Zug setzt: `inset 2px 2px 0` deckt oben UND
          links, `inset -2px -2px 0` deckt unten UND rechts.
       2. Der Schlagschatten stand auf `0 Npx`, also ohne Seitwärtsversatz —
          das ist Jakobs „rundherum". Jetzt x = y, weil der Wurf am Bild
          51 px nach rechts und 49 px nach unten reicht.
       3. Die Kontaktlinie bleibt bei 1 px Weichzeichner (Kontaktverdeckung,
          siehe Ausnahme b oben) und bekommt trotzdem den Versatz mit.

     DOSIS ZURÜCKGENOMMEN 01.08.2026, ABENDS. Jakob: „Jetzt hast du diesen
     Schatteneffekt auch zu stark gemacht … bei dem Sprechknopf." Die Kurve
     im Block DIE DOSIS ganz oben ist an `35-speech-button-rest.webp`
     abgelesen; die alte Fassung lag bei 2–3 px etwa doppelt so dunkel und
     reichte 1,6-mal so weit. Was NICHT zurückgenommen wurde, und zwar
     ebenfalls nach der Messung: die Lichtkante (dort +32 von 255, also
     kräftig) und die harte Kontaktlinie (dort 52 % dunkler). Die Vorlage
     hat einen scharfen Ansatz und einen leisen Ausklang — nicht umgekehrt.

     P1 · DER WURF WIRD ZUSAMMENGEZOGEN, 02.08.2026. Nicht nach Gefühl,
     sondern nach der Messung in `design/exodus/tiefe/TIEFE.md`: an 79
     baulichen Kanten der zehn Originalbilder ist der Übergang von 90 % auf
     10 % des Hubs im Median 9,0 Produkt-px breit und NIE breiter als 11,2.
     Gemessen am eigenen Bau (`lippentest.py`): Musterbogen 21 px,
     Morgen-Fläche 26 px — rund das 2,4-fache.
     Reichweite = Versatz + Weichzeichner, gedeckelt bei 11 px:
         Auflage  3+5 → 2+4  und  5+10 → 4+6   (Reichweite 15 → 10)
         Träger   4+7 → 2+4  und  7+13 → 5+6   (Reichweite 20 → 11)
     Die Staffelung bleibt geometrisch (jede Lage doppelt so weich wie die
     vorige, Deckung fällt) und bleibt auf der 45-Grad-Diagonalen — Gesetz 5,
     an den Bildern gemessen mit 51 px rechts zu 49 px unten.
     WAS NICHT ANGEFASST WURDE: die Innenkanten. Dieselbe Messung hat
     ausdrücklich WIDERLEGT, dass uns Modellierung fehlt (Hub 73–87 gegen
     45–80 der Vorlage, modellierte Fläche 17,7–30,9 % gegen 6,6–17,9 %).
     Wir haben schon mehr Schatten als die Vorlage — zu weit, nicht zu wenig.
     Nebenbei ist das der teuerste Teil der Darstellung: die Rechenlast eines
     Weichzeichners wächst quadratisch mit dem Radius. */
  --praegung-erhaben:                       /* STUFE +1 · Auflage */
      inset 1px 1px 0 var(--kante-licht),
      inset 4px 4px 6px -4px var(--kante-licht),
      inset -1px -1px 0 var(--kante-dunkel),
      inset -5px -5px 8px -5px var(--schatten-2),
      1px 1px 0 var(--kante-tief-w),
      1px 1px 2px var(--schatten-2),
      2px 2px 4px var(--schatten-1),
      4px 4px 6px var(--schatten-0);      /* P1 · Reichweite 4+6 = 10 px */

  /* Stärker erhaben — für die Hauptaktion und Karten, die wirklich aufliegen. */
  --praegung-erhaben-hoch:                  /* STUFE +2 · Träger */
      inset 2px 2px 0 var(--kante-licht),
      inset 7px 7px 10px -7px var(--kante-licht),
      inset -2px -2px 0 var(--kante-dunkel),
      inset -9px -9px 14px -9px var(--schatten-3),
      1.5px 1.5px 0 var(--kante-tief),
      1px 1px 2px var(--schatten-2),
      2px 2px 4px var(--schatten-1),
      5px 5px 6px var(--schatten-0);      /* P1 · Reichweite 5+6 = 11 px */

  /* Vertieft: exakt umgekehrt. Der Schatten liegt INNEN oben links (das
     Papier steht dort über), die Lichtkante INNEN unten rechts; nach aussen
     ein feiner heller Grat, weil die Kante des Lochs Licht fängt.
     AUCH HIER ZUSAMMENGEZOGEN 01.08.2026: aus `inset 0 3px 5px` plus
     `inset 3px 0 5px` (zwei Schatten mit ungleicher Stärke) wird EIN
     `inset 3px 3px 5px`. Der äussere helle Grat wandert von `0 1px 0` auf
     `1px 1px 0` — bei einem Loch fängt die Kante unten UND rechts das Licht,
     nicht nur unten. Am Bild nachgemessen, Streifen direkt neben dem Fenster
     von `43-card-window.webp`:
         oben 190 · links 196   (dunkel)      unten 225 · rechts 225 (hell)
     Die beiden hellen Werte sind auf 0,1 von 255 gleich — die Diagonale.

     P2 · DIE FASE WIRD BREIT, 02.08.2026. Bis hierher stand aussen genau
     `1px 1px 0 var(--kante-licht)` — ein Vollton-Strich und danach sofort
     Papier. Die Vorlage hat dort 6 px mit Verlauf (Messung siehe
     `--kante-fase-1` oben). Das ist der zweite belegte Unterschied neben dem
     zu weiten Wurf, und es ist der, der die „Helligkeit an den richtigen
     Stellen" trägt: das Papier kippt unterhalb eines Schnitts ZUR Sonne hin
     und fängt Licht. Ein einzelner Strich kann das nicht, ein Ausklang schon.
     Reichweite 3+3 = 6 px — genau die gemessene Breite, und damit innerhalb
     der 11-px-Decke aus P1. */
  --praegung-vertieft:                      /* STUFE -1 · Senke */
      inset 3px 3px 5px var(--schatten-3),
      inset -1px -1px 0 var(--kante-licht),
      inset -5px -5px 7px -5px var(--kante-licht),
      1px 1px 0 var(--kante-licht),
      2px 2px 2px var(--kante-fase-1),
      3px 3px 3px var(--kante-fase-2);

  --praegung-vertieft-tief:                 /* STUFE -2 · Loch im Papier */
      inset 5px 5px 9px var(--schatten-3),
      inset -2px -2px 0 var(--kante-licht),
      inset -8px -8px 10px -8px var(--kante-licht),
      1px 1px 0 var(--kante-licht),
      2px 2px 2px var(--kante-fase-1),
      3px 3px 3px var(--kante-fase-2),
      2px 2px 3px var(--schatten-1);

  /* Die Wölbung. Licht von oben links heisst: oben links heller, unten rechts
     dunkler — bei Vertiefungen genau umgekehrt.

     ANGEZOGEN 01.08.2026 zusammen mit den Kanten: Wenn die Kante deutlich
     stärker wird, die Fläche aber gleich flach bleibt, sieht das Bauteil aus
     wie ein Aufkleber mit hellem Rand. Wölbung und Kante gehören zusammen.
     WINKEL KORRIGIERT 01.08.2026 von 148deg auf 135deg. 148 war geschätzt;
     135 ist gerechnet: der Schlagschatten reicht am Bild 51 px nach rechts
     und 49 px nach unten, das ist die Diagonale, und die Diagonale „von oben
     links nach unten rechts" ist in CSS-Winkeln genau 135deg. Damit zeigen
     Wölbung, Kante und Schlagschatten in dieselbe Richtung — vorher lag die
     Wölbung 13 Grad daneben. */
  --woelbung-erhaben: linear-gradient(135deg,
      color-mix(in srgb, var(--papier-hell) 92%, transparent) 0%,
      color-mix(in srgb, var(--papier-hell) 34%, transparent) 22%,
      color-mix(in srgb, var(--papier) 0%, transparent) 52%,
      color-mix(in srgb, var(--papier-dunkel) 46%, transparent) 82%,
      color-mix(in srgb, var(--papier-dunkel) 82%, transparent) 100%);
  --woelbung-vertieft: linear-gradient(135deg,
      color-mix(in srgb, var(--papier-dunkel) 96%, transparent) 0%,
      color-mix(in srgb, var(--papier-dunkel) 38%, transparent) 24%,
      color-mix(in srgb, var(--papier) 0%, transparent) 56%,
      color-mix(in srgb, var(--papier-hell) 48%, transparent) 84%,
      color-mix(in srgb, var(--papier-hell) 88%, transparent) 100%);

  /* --- Der Ausschnitt -----------------------------------------------------
     NEU GEBAUT 01.08.2026. Jakobs Urteil über die alte Fassung war eindeutig
     und kam zweimal: „Dieses blaue Feld sieht aber noch ziemlich cheap aus.
     Das müssen wir überarbeiten. Das sieht wirklich schlecht aus."

     ZUERST GEPRÜFT, OB ES AM FARBWERT LIEGT — es liegt NICHT daran.
     Gemessen (Canvas, pixelweise) am Bauteil, um das es hier geht:
         43-card-window.webp  Blaufläche im Mittel #1E427E,
                              häufigste Bins #184078 (4,8 %) und #204080 (4,5 %)
     Der Token `--tiefe: #204080` ist also praktisch exakt das Blau der
     freigegebenen Karte mit Fenster. Der dunklere Wert #0B397E stammt aus
     `25-logo-primary` — das ist die MARKENfläche, ein anderes Bauteil mit
     einer anderen Aufgabe, und kein Beleg gegen diesen Token. Der Farbwert
     bleibt deshalb unverändert (Weiss darauf: 9,97:1, gerechnet).

     WORAN ES STATTDESSEN LAG, drei Sachen, alle am Bild abgelesen:
       1. GLANZFLECK. Der alte Grund hatte seine hellste Stelle bei 34 %/16 %
          und lief nach unten rechts ab — das liest das Auge als Spiegelung
          auf Kunststoff. Die freigegebenen Bilder haben KEINEN Glanz im Blau;
          sie sind matt und werden nur zum Rand hin dunkler.
       2. KEIN SCHLAGSCHATTEN. In `05-paper-cut` ist das Auffälligste am
          Schnitt der harte dunkle Streifen direkt unter der oberen
          Papierkante — dort steht das Papier über und wirft in die Tiefe.
          Genau dieser Streifen macht aus einer Fläche ein Loch.
       3. KEINE FASER. Das Blau im Bild hat dieselbe Papierfaser wie das
          Papier — es ist ja derselbe Karton, nur die Schicht darunter. Eine
          vollkommen glatte Fläche kann gar nichts anderes sein als Farbe.
     Alle drei zusammen sind „cheap". */

  /* Der Schlagschatten der Schnittkante IN die Tiefe. Oben stark (dort steht
     die Kante am weitesten über), links schwächer — Licht von oben links.

     DIE STOPPS SIND GEDECKELT (`min(px, %)`), und das ist kein Feinschliff:
     Mit reinen Pixelwerten verschluckt derselbe Schatten ein 10-px-Signal
     komplett — der Punkt am Profilkreis wäre schwarz statt blau. Mit reinen
     Prozentwerten würde er dagegen an einer hohen Karte über die halbe Fläche
     laufen. `min()` nimmt je Bauteil den kleineren der beiden.

     RAMPE NEU GERECHNET 01.08.2026, ABENDS — sie war rund viermal zu lang.
     Am Fenster von `43-card-window.webp` (1155 × 264 px, Grundton 76 von
     255) von der Schnittkante nach innen abgetastet und in Deckkraft
     zurückgerechnet (Schattenfarbe rgba(0,6,20) hat die Helligkeit 5):
         0,9 px .66 · 1,7 px .52 · 2,6 px .48 · 3,4 px .34 · 4,3 px .28
         5,2 px .20 · 6,0 px .14 · 6,9 px .11 · 8,6 px .07 · ~12 px 0
     (Bildpixel × 0,287, weil die Karte im Bild 1249 px und im Produkt
     358 px breit ist.) Die alte Rampe stand bei 7 px noch auf .34 und lief
     bis 32 px. Deshalb war der 8 px schmale blaue Ring der Sprechknopf-Mulde
     auf seiner ganzen Breite fast schwarz — Jakobs „richtig stark".
     Von links ist dieselbe Kurve gemessen (24·33·41·45·46·53·56·59·67 gegen
     13·29·39·42·52·56·62·66·68 von oben), die 45-Grad-Sonne bestätigt sich
     also ein zweites Mal. Beide Rampen sind jetzt gleich lang, die obere nur
     eine Spur dunkler. */
  --loch-schatten:
      linear-gradient(to bottom,
        rgba(0, 6, 20, .70) 0,
        rgba(0, 6, 20, .48) min(2.5px, 8%),
        rgba(0, 6, 20, .28) min(4.5px, 15%),
        rgba(0, 6, 20, .12) min(7px, 24%),
        rgba(0, 6, 20, 0) min(11px, 36%)),
      linear-gradient(to right,
        rgba(0, 6, 20, .62) 0,
        rgba(0, 6, 20, .44) min(2.5px, 8%),
        rgba(0, 6, 20, .26) min(4.5px, 15%),
        rgba(0, 6, 20, .11) min(7px, 24%),
        rgba(0, 6, 20, 0) min(11px, 36%));
  /* ANGEGLICHEN 01.08.2026: Der linke Schatten war mit 0,46 gegen 0,78 nur
     halb so stark wie der obere — bei einer Sonne auf 45 Grad müssten beide
     fast gleich sein. Im Fenster von `43-card-window.webp` von der Kante nach
     innen abgetastet (Helligkeit von 255):
         von oben   9 · 23 · 32 · 34 · 43 · 47 · 53 …
         von links 20 · 28 · 32 · 39 · 39 · 46 · 44 …
         von unten 74 · 69 · 65 (kein Schatten, die Wand ist beleuchtet)
         von rechts 58 · 62 · 60 (dito)
     Oben ist eine Spur dunkler als links, aber nicht doppelt so dunkel.
     Deshalb 0,62 statt 0,46 und dieselbe Länge der Rampe wie oben. */
  /* Der Grund: MATT. Vollton in der Mitte, zum Rand hin in den Kern hinein.
     Der Mittelpunkt sitzt leicht unterhalb der Mitte, weil der obere Teil
     ohnehin vom Schlagschatten verdunkelt wird. Kein Glanzfleck. */
  --loch-grund: radial-gradient(128% 148% at 52% 62%,
      var(--tiefe) 0%, var(--tiefe) 46%, var(--tiefe-rand) 84%, var(--tiefe-kern) 100%);
  /* Die Faser IM Loch. Der Ausschnitt ist derselbe Karton, nur eine Schicht
     tiefer — er muss dieselbe Faser haben.

     ERSTER ANLAUF WAR FALSCH, und der Fehler ist lehrreich: Ich hatte die
     echte Papiertextur (`--papier-bild-fein`) mit `soft-light` eingerechnet.
     Am Screenshot war das Blau danach deutlich BLASSER statt reicher — genau
     das Gegenteil des Ziels. Der Grund ist rechenbar und hätte vorher
     auffallen müssen: Die Textur ist beige und hat eine mittlere Helligkeit
     von 216 von 255. `soft-light` hellt gegenüber allem auf, was heller als
     50 % ist, also hier flächendeckend. Dasselbe gilt für `overlay` und
     `hard-light`. Eine helle Textur kann eine dunkle Fläche nicht texturieren,
     sie kann sie nur aufhellen.
     Jetzt eine Faser, die um Null herum liegt: gleich viel Licht wie Schatten,
     unregelmässig verteilt, damit kein Streifenmuster entsteht. Sie verschiebt
     die Farbe nicht und lässt die Fläche trotzdem eine Oberfläche sein.

     ACHTUNG, EINE LAGE: `--loch-korn`, `--loch-schatten` (2) und
     `--loch-grund` (1) ergeben zusammen GENAU VIER Hintergrundlagen. Die
     Listen für `background-size` und `-repeat` in §3 zählen mit. Wer hier eine
     Lage ergänzt, muss sie dort ergänzen.

     ZWEITE KORREKTUR, wieder am Screenshot: 93° sind fast senkrecht, und
     senkrechte 1-px-Linien fallen mit dem Pixelraster zusammen — daraus wurde
     sichtbarer Cord statt Faser. Dieselbe Lehre wie beim Papierkorn („der
     erste war zu laut — man sah Streifen statt Faser"). Jetzt schräg (24°),
     damit die Kantenglättung die Linien zu einem Sprenkel verwischt, und mit
     etwa halber Stärke. */
  --loch-korn:
      repeating-linear-gradient(24deg,
        rgba(255, 255, 255, .022) 0 1px,
        rgba(0, 0, 0, .030) 1px 2px,
        transparent 2px 5px,
        rgba(0, 0, 0, .018) 5px 6px,
        transparent 6px 8px,
        rgba(255, 255, 255, .014) 8px 9px,
        transparent 9px 13px);

  /* Die Schnittwand. `--tiefe-kern` als scharfer 1-px-Ring ist die Wand
     selbst; darunter fängt die untere Innenwand Licht (sie zeigt nach oben
     links) und wird sichtbar heller — ohne diese eine helle Linie kippt das
     Loch optisch zurück in eine Platte.
     UMGEBAUT 01.08.2026 — hier standen zwei Verstösse gegen die eine Sonne:
     ein 1-px-Ring RUNDHERUM (`inset 0 0 0 1px`) und eine Vignette RUNDHERUM
     (`inset 0 0 16px -3px`). Beide leuchten bzw. verdunkeln auf allen vier
     Seiten gleich, und genau das liest das Auge als „ohne Lichtquelle".
     Jetzt ist die Wand geteilt: oben/links die im Schatten liegende Wand,
     unten/rechts die beleuchtete. Die Vignette ist ersetzt durch eine
     gerichtete Verschattung aus derselben Ecke.

     ZURÜCKGENOMMEN 01.08.2026, ABENDS. Die gerichtete Verschattung stand auf
     `6px 6px 12px -5px` bei .55 — sie verdoppelte damit die Rampe von
     `--loch-schatten`, die auf denselben ersten Millimetern liegt. Solange
     jene Rampe zu lang war, fiel es nicht auf; nachdem sie an
     `43-card-window.webp` neu gerechnet ist, ist die Verdopplung genau der
     Überschuss. Nachgerechnet gegen dieselbe Messung (Grundton 76, 3 px von
     der Kante: 42, also Gesamtdeckkraft .48): Rampe allein .44, mit der alten
     Verschattung .61, mit der neuen .50. Sichtbar wurde der Fehler am
     schmalsten Loch des Systems — dem 8 px breiten blauen Ring um den
     Sprechknopf, der dadurch auf seiner ganzen Breite fast schwarz war. */
  /* DIESE WERTE SIND AM GROSSEN SCHNITT GEEICHT (43-card-window, 72-px-Mulde)
     und skalieren über EINEN Faktor: `--loch-mass`. Die drei kleinen
     Mitglieder des Materialsatzes (Zeilensignal 16 px, Profilsignal 10 px,
     Markenplatz 32 px) setzen unter §3 nur `--loch-mass: .35` — Herleitung
     und Messung dort im Block „DER RAND EINES LOCHS SKALIERT NICHT MIT".
     Bis zum 03.08.2026 standen die 0,35-Werte dort noch einmal als
     ausgeschriebene Zahlen (die zweite Liste), weil das Sonnen-Gate
     `tzuki/tests/test_aperture_sonne.py` `calc()` nicht lesen konnte.
     Das Gate rechnet einfache Faktoren jetzt selbst aus und prüft BEIDE
     Fassungen (1 und .35); wer hier nacheicht, eicht die kleinen Löcher
     automatisch mit. */
  --loch-mass: 1;
}

/* WARUM DIESE ZWEI ERKLÄRUNGEN EINE EIGENE SELEKTORLISTE TRAGEN — dieselbe
   CSS-Feinheit wie beim `--punkt-glanz`-Block weiter unten: Ein `var()`
   INNERHALB einer eigenen Eigenschaft wird dort aufgelöst, wo diese
   Eigenschaft ERKLÄRT wird, nicht dort, wo sie benutzt wird. Stünden
   `--loch-innen`/`--loch-kante` nur in `:root`, würde `var(--loch-mass)`
   dort gegen den Wurzelwert 1 aufgelöst und das FERTIGE Ergebnis vererbt —
   die kleinen Signale bekämen den vollen Rand (am gerenderten DOM belegt,
   03.08.2026: `getComputedStyle` zeigte 1px/5px statt 0,35px/1,75px).
   Deshalb stehen die Erklärungen EINMAL, aber auf `:root` UND auf jedem
   Bauteil mit eigenem Faktor. WER EINEM NEUEN BAUTEIL EINEN EIGENEN
   `--loch-mass` GIBT, MUSS ES IN DIESE LISTE AUFNEHMEN — sonst gilt sein
   Faktor still nicht. */
:root,
.ap-zeile__signal,
.ap-profil__signal,
.ap-marke-platz {
  --loch-innen:
      inset calc(1px * var(--loch-mass)) calc(1px * var(--loch-mass)) 0 rgba(0, 4, 14, .70),
      inset calc(5px * var(--loch-mass)) calc(5px * var(--loch-mass)) calc(9px * var(--loch-mass)) calc(-5px * var(--loch-mass)) rgba(0, 4, 14, .28),
      inset calc(-2px * var(--loch-mass)) calc(-2px * var(--loch-mass)) 0 rgba(108, 142, 208, .50);
  /* Der Papiergrat rund um den Schnitt: unten der helle Grat (dort fängt die
     Schnittkante das Licht von oben links), oben ein weicher warmer Schatten
     auf dem Papier. VERSTÄRKT 01.08.: 2 px statt 1 px und in `--kante-licht`
     statt `--papier-hell` — im Bild ist dieser Grat der HELLSTE Punkt des
     ganzen Bauteils, bei uns war er 1,08:1 gegen das Papier und damit gar
     nicht da.
     ZUSAMMENGEZOGEN 01.08.2026: aus vier Einzelrichtungen mit ungleicher
     Stärke werden zwei Diagonalen. Der Grat war unten 2 px und rechts 1 px,
     der Schatten lief nur nach oben und gar nicht nach links.
     RICHTUNG DER DRITTEN LAGE KORRIGIERT 03.08.2026 (Backlog 48): sie war
     `-3px -3px 5px` — der einzige weiche AUSSENschatten der Bibliothek, und
     er zeigte nach oben links, also AUF die Sonne zu. Das Gate liess ihn
     durch, weil es nur die Diagonale prüfte (x und y gleiches Vorzeichen),
     nicht die Himmelsrichtung; seit dem 03.08. prüft es beides. Gedreht ist
     NUR die Richtung (jetzt von der Sonne weg, nach unten rechts) — Stärke
     (--schatten-2) und Weichzeichner (5 px) sind unverändert. Ob ein Loch
     überhaupt einen Aussenschatten tragen soll (die Ebenen-Tabelle im Kopf
     kennt für ein Loch keinen), ist eine Entscheidung über jede Karte des
     Baukastens und liegt bei Jakob — hier ist nur die physikalisch
     unmögliche Richtung behoben. */
  --loch-kante:
      calc(2px * var(--loch-mass)) calc(2px * var(--loch-mass)) 0 var(--kante-licht),
      calc(-1px * var(--loch-mass)) calc(-1px * var(--loch-mass)) 0 var(--schatten-1),
      calc(3px * var(--loch-mass)) calc(3px * var(--loch-mass)) calc(5px * var(--loch-mass)) var(--schatten-2);
}

:root {

  /* --- Der Lichtpunkt ------------------------------------------------------
     NEU GEBAUT 01.08.2026. Jakob: „Der Leuchteffekt der Linse, der muss ein
     bisschen mehr Nuancen haben. Hier sieht es so, es gibt einen inneren
     Leuchtpunkt und dann aussen drum herum einen schwächer werdenden. Das
     sieht noch ein bisschen zu cheap aus."

     Er beschreibt damit exakt den alten Aufbau: ZWEI Stufen (Vollton +
     ein Hof) und ein harter 1-px-Ring dazwischen. Am freigegebenen Bild sind
     es vier Zonen, und die Messung steht oben bei `--punkt-kern`:
         1  KERN        überstrahlt, fast weiss, die geringste Buntheit
         2  GIPFEL      der Buntheitsgipfel — hier ist die Farbe zu Hause
         3  ABFALL      Licht → Hof, die Farbe wird satter und dunkler
         4  SAUM        ein sehr weiter, sehr schwacher Schein in der Tiefe;
                        er reicht am Bild bis etwa das Fünffache des
                        sichtbaren Punktdurchmessers und hebt das Blau dort
                        messbar an (13-aperture-light: von #1D396C aussen
                        auf #243C6B in der Nähe des Punkts)
     Der Kern kommt als Flächenverlauf (`--punkt-verlauf`, sitzt IM Punkt),
     die Zonen 3 und 4 als sechs gestaffelte Schattenlagen statt zwei.

     SONNE:AUSNAHME (a) — eine Lichtquelle strahlt in alle Richtungen. Der
     Hof MUSS rund sein und hat deshalb bewusst keinen Versatz. Das ist kein
     Schatten, und das Gate überspringt diese beiden Eigenschaften. */
  --punkt-groesse: 8px;
  /* Die drei zusammengesetzten Werte stehen NICHT hier, sondern gleich
     darunter in einem eigenen Block. Der Grund ist ein echter Fehler und
     steht dort. */

  /* --- Papiertextur ------------------------------------------------------
     EINHÄNGEPUNKT für das spätere Bild (Codex erzeugt es):
        :root { --papier-bild: url("assets/papier.webp"); }
     Mehr ist nicht zu tun. `initial` bedeutet für var() „nicht gesetzt", also
     greift die Ersatz-Textur darunter — sobald ein Bild da ist, ersetzt es sie
     vollständig, statt sich mit ihr zu überlagern. */
  /* EINGEHÄNGT am 31.07.2026: die erzeugte Textur aus der Aperture-Runde.
     Gegengeprüft, bevor sie hier steht — 3×3 gekachelt und angesehen: keine
     sichtbare Naht. Die gemessene Kantendifferenz (5,9) klingt hoch, ist bei
     einer so feinen, kontrastarmen Faser aber optisch bedeutungslos. Das ist
     der Grund, warum hier ein BILD und keine Zahl entscheidet.
     Zum Abschalten: auf `initial` setzen, dann greift die CSS-Ersatztextur. */
  /* ACHTUNG, EINE FALLE — gefunden am 01.08.2026, abends.
     Ein relativer `url()` in einer CUSTOM PROPERTY wird von Chromium gegen die
     Datei aufgelöst, die die Variable BENUTZT, nicht gegen die, die sie
     erklärt. Für Seiten neben dieser Datei stimmt der Pfad; für jede Datei in
     einem Unterordner (`licht/`, `palette/`, `reise/`) zeigt er ins Leere —
     `licht/assets/papier.webp` gibt es nicht.

     Die Wirkung ist tückisch, weil nichts kaputtgeht: `background-image`
     bleibt einfach leer, die Fläche wird glatt, und niemand sieht einen
     Fehler — man sieht nur schlechteres Papier. Gemeldet haben es zwei
     Agenten unabhängig voneinander als 404 in der Konsole.

     Deshalb steht der Pfad ab jetzt in einer NORMALEN Regel (`.ap-papier`
     weiter unten) und nicht mehr nur in einer Variablen: dort wird er gegen
     DIESE Datei aufgelöst und stimmt überall. Die Variablen bleiben als
     Schalter erhalten — wer die Textur abschalten will, setzt sie auf
     `initial`, dann greift die CSS-Ersatztextur. */
  --papier-bild: url("assets/papier.webp");
  --papier-bild-fein: url("assets/papier-fein.webp");
  --papier-kachel: 380px;   /* Kachelgröße auf 390-px-Flächen: knapp unter der
                               Breite, damit die Wiederholung nie mit einer
                               Bauteilkante zusammenfällt und ein Raster ergibt */

  /* CSS-Ersatz: zwei grosse weiche Flecken (ungleichmässiges Streiflicht) und
     zwei sehr feine Streifenraster über Kreuz (die Faser). Bewusst schwach —
     eine sichtbare Textur wäre ein Muster, keine Oberfläche.
     ZWEITER ANLAUF: Der erste war zu laut — man sah Streifen statt Faser und
     einen hellen Fleck oben links statt Streiflicht. Eine Textur, die man als
     Muster erkennt, ist keine Oberfläche mehr. Jetzt: sehr schwache Faser in
     zwei Richtungen mit ungleichen Perioden (2 und 5 px, damit kein sichtbares
     Karo entsteht) und ein einziger, sehr weiter Lichtverlauf. */
  --papier-korn:
      radial-gradient(130% 90% at 12% 0%,
        color-mix(in srgb, var(--papier-hell) 46%, transparent), transparent 66%),
      radial-gradient(90% 70% at 96% 100%,
        color-mix(in srgb, var(--papier-dunkel) 34%, transparent), transparent 70%),
      repeating-linear-gradient(92deg,
        color-mix(in srgb, var(--papier-dunkel) 11%, transparent) 0 1px,
        transparent 1px 5px),
      repeating-linear-gradient(2deg,
        color-mix(in srgb, var(--papier-hell) 13%, transparent) 0 1px,
        transparent 1px 2px);

  /* --- Typografie -------------------------------------------------------- */
  --schrift: "Inter", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
}

/* =========================================================================
   DIE ZUSAMMENGESETZTEN LICHTWERTE — und warum sie NICHT in :root stehen
   =========================================================================
   HIER LAG EIN ECHTER FEHLER, gefunden am 01.08.2026 am eigenen Screenshot:
   Ein Feld mit `.ap-licht-gruen` zeigte einen BERNSTEINFARBENEN Punkt. Die
   Farbproben daneben waren grün, der Punkt nicht.

   Die Ursache ist eine Feinheit von CSS, die man einmal wissen muss: Ein
   `var()` INNERHALB einer eigenen Eigenschaft wird dort aufgelöst, wo diese
   Eigenschaft ERKLÄRT wird — nicht dort, wo sie benutzt wird. Stand
   `--punkt-glanz` in `:root`, wurde `var(--licht)` darin gegen den
   Wurzelwert aufgelöst (Bernstein) und der fertige Bernstein-Hof dann nach
   unten vererbt. Ein Nachkomme, der `--licht` auf Grün stellt, kam zu spät.

   Genau DAS ist Jakobs Beanstandung vom 01.08. in ihrer technischen Form:
       „Du musst schon dann das Leuchten komplett in die Farbe ummünzen."
   Der Kern war umgefärbt, der Hof nicht — nicht aus Nachlässigkeit, sondern
   weil er gar nicht mehr umgefärbt werden KONNTE.

   Die Lösung ist der Selektorenkopf unten: dieselbe eine Erklärung gilt für
   die Wurzel UND für jeden Punkt. Am Punkt wird sie neu aufgelöst und nimmt
   dort das an, was seine Vorfahren gesetzt haben. Kein zweiter Textblock,
   also keine zweite Liste.
   ========================================================================= */
:root,
.ap-licht-gruen,
.ap-licht-warnung,
.ap-punkt,
.ap-lichtwerte,
.ap-blende-svg {
  /* ERWEITERT 02.08.2026 um `.ap-licht-gruen` / `.ap-licht-warnung` und
     `.ap-blende-svg`. Der Grund ist derselbe wie unten und jetzt zwingend,
     weil auch `--licht-hof` gerechnet wird: Die Akzentklassen sind die
     Elemente, die `--licht` UMSTELLEN. Wird derselbe Erklärungssatz dort neu
     aufgelöst, kann kein Nachkomme mehr eine Farbe von der einen und einen
     Rand von der anderen Lampe bekommen — auch nicht der Punkt IM Vektor,
     der kein `.ap-punkt` ist und die Werte sonst aus der Wurzel geerbt hätte
     (`blende.svg` füllt ihn mit `var(--licht-hof, …)`).

     `--licht-hof` — DER RAND, GERECHNET STATT GESETZT (02.08.2026).
     Herleitung und die drei alten, auseinandergelaufenen Paare stehen oben
     bei den Akzentsätzen. Kurz: dieselbe Farbe, 9,2 % dunkler und 15,9 %
     satter, Farbwinkel unverändert — beide Faktoren am einzigen gemessenen
     Paar (#F8D058 → #F8A808) geeicht. Liegt das Ergebnis ausserhalb von
     sRGB, klemmt der Browser die Buntheit; das trifft Grün und Rot, die
     ohnehin am Rand liegen, und ist die ehrlichere Antwort als ein von Hand
     nachgebesserter Wert. */
  --licht-hof: oklch(from var(--licht) calc(l * 0.908) calc(c * 1.159) h);

  /* `.ap-lichtwerte` ist der dritte Ort, an dem dieselbe eine Erklärung neu
     aufgelöst werden muss: eine Farbprobe, die den KERN zeigen soll, ist
     selbst kein Punkt. Ohne diesen Selektor zeigte die Belegseite drei
     bernsteinfarbene Kernproben neben einem grünen und einem roten Punkt —
     derselbe Fehler wie am 01.08. mittags, nur eine Ebene weiter aussen.
     Ein zweiter Textblock wäre wieder die zweite Liste. */

  /* Wie stark der Kern ausbrennt, aus der GRÖSSE gerechnet. 0 bei 6 px und
     kleiner, 1 ab 32 px. Die Division zweier Längen ergibt in CSS eine reine
     Zahl; in Chromium nachgemessen (8 px → 0,0769 · 40 px → 1). */
  --punkt-kernstaerke: clamp(0, calc((var(--punkt-groesse) - 6px) / 26px), 1);

  /* Der Kern — GERECHNET, nicht gesetzt. 52 % Weiss ist der am Bild
     `13-aperture-light` gemessene Wert (dort `#FCEDA7`, hier `#FCE8AF`);
     bei einem winzigen Punkt bleiben davon 17 %, und dann ist er einfach
     gelb, grün oder rot statt weiss. */
  --punkt-kern: color-mix(in srgb,
      #FFFFFF calc(14% + 38% * var(--punkt-kernstaerke)), var(--licht));

  /* SIEBEN STOPPS, KEIN PLATEAU, und `closest-side`. Die drei Gründe stehen
     oben bei `--licht`. Kurz: eine Fläche gleicher Farbe mit einem Sprung
     dahinter liest das Auge als zweiten Punkt; und mit der Vorgabe
     `farthest-corner` lag alles ab 71 % ausserhalb des Kreises, der Verlauf
     wurde also mitten im Abfall abgeschnitten und bekam dadurch einen Rand. */
  --punkt-verlauf: radial-gradient(circle closest-side at 50% 50%,
      var(--punkt-kern) 0%,
      color-mix(in srgb, var(--punkt-kern) 76%, var(--licht)) 14%,
      color-mix(in srgb, var(--punkt-kern) 48%, var(--licht)) 27%,
      color-mix(in srgb, var(--punkt-kern) 22%, var(--licht)) 39%,
      var(--licht) 54%,
      color-mix(in srgb, var(--licht) 58%, var(--licht-hof)) 78%,
      var(--licht-hof) 100%);

  /* SONNE:AUSNAHME (a) — eine Lichtquelle strahlt rund.
     ERSTE LAGE GEÄNDERT 01.08. abends: sie war `0 0 1px var(--punkt-kern)`
     und legte damit einen fast weissen Ring AUSSEN um den ganzen Punkt. Bei
     8 px Durchmesser ist 1 px ein Achtel — das war der zweite Grund, warum
     der Punkt in der Listenzeile weiss mit gelbem Rand aussah statt gelb. */
  --punkt-glanz:   /* SONNE:AUSNAHME (a) */
      0 0 1px var(--licht),
      0 0 3px var(--licht),
      0 0 7px color-mix(in srgb, var(--licht-hof) 85%, transparent),
      0 0 14px color-mix(in srgb, var(--licht-hof) 55%, transparent),
      0 0 26px color-mix(in srgb, var(--licht-hof) 28%, transparent),
      0 0 44px color-mix(in srgb, var(--licht-hof) 13%, transparent);
  /* --- DER PUNKT, WIE ER JETZT AUSSIEHT: FLACH ---------------------------
     ENTSCHIEDEN AM 02.08.2026, von Jakob, an beiden Fassungen in
     Produktionsgrösse:
       „ICH BIN SCHOCKIERT. ICH HATTE RECHT. Das Leuchten sieht schlechter
        aus als einfach nur der gelbe Punkt. GELB, GRÜN UND ROT ALS PUNKT
        SIEHT SEHR VIEL FREUNDLICHER AUS und sehr viel weniger aufdringlich.
        Das passt zum Design besser insgesamt."
     Vorgeschlagen hatte er es am Abend zuvor: „Vielleicht nimmt man noch gar
     kein echtes Leuchten, sondern EINFACH NUR DEN GELBEN PUNKT. Der Rand des
     Punktes ist ganz, ganz leicht orange oder so was. SO CLIPART-MÄSSIG."

     Das ist keine abgeschwächte Fassung des Leuchtens, sondern eine andere
     Bauform: kein Hof, keine Überstrahlung, kein weisser Kern. Eine Fläche
     mit einem Rand, der eine Spur kippt — mehr nicht.

     DER RAND IST SCHMALER GEWORDEN (02.08.). Vorher begann er bei 64 % des
     Radius und war damit bei 8 px Durchmesser 1,44 px breit — über ein
     Drittel des Radius. Beim Bernstein, dessen Rand kräftig gegen die Tiefe
     absticht, wuchs der Punkt dadurch optisch; beim Grün und beim Rot, deren
     Ränder dunkel sind und mit dem Blau verschmelzen, schrumpfte er. Genau
     das hat Jakob gesehen: „Es kommt mir vor, als ob der grüne Punkt ein
     bisschen kleiner ist, und beim roten vielleicht auch." — obwohl alle
     drei nachgemessen 8,000 px sind. Jetzt beginnt der Rand bei 78 %, ist
     also 0,88 px breit und bleibt bei jeder Farbe das, was Jakob verlangt
     hat: „ganz, ganz leicht". */
  --punkt-flach: radial-gradient(circle closest-side at 50% 50%,
      var(--licht) 0%,
      var(--licht) 78%,
      color-mix(in srgb, var(--licht) 45%, var(--licht-hof)) 90%,
      var(--licht-hof) 100%);

  /* Der gedämpfte Zustand fürs Atmen — dieselbe Staffelung, nur kürzer. */
  --punkt-glanz-schwach:   /* SONNE:AUSNAHME (a) */
      0 0 1px var(--licht),
      0 0 3px color-mix(in srgb, var(--licht) 70%, transparent),
      0 0 8px color-mix(in srgb, var(--licht-hof) 34%, transparent),
      0 0 16px color-mix(in srgb, var(--licht-hof) 14%, transparent);
}

/* =========================================================================
   0 — Grundlagen
   ========================================================================= */

/* Browser-Vorgaben sind geratene Werte (1px/6px an <button>, 40px an <ul>) und
   fallen sonst als Raster-Verstoss auf. Deshalb hier einmal sauber genullt. */
*, *::before, *::after { box-sizing: border-box; }
html, body, h1, h2, h3, h4, p, ul, ol, li, figure, blockquote {
  margin: 0; padding: 0;
}
ul, ol { list-style: none; }
button { font: inherit; color: inherit; border: 0; background: none; padding: 0; }

/* =========================================================================
   1 — Fläche und Prägung
   Das Fundament. Trägt die Prägung nicht, trägt nichts.
   ========================================================================= */

.ap-flaeche {
  background-color: var(--papier);
  color: var(--tinte);
  font-family: var(--schrift);
  font-size: 16px;
  line-height: 24px;
  -webkit-font-smoothing: antialiased;
}

/* Die Textur liegt in einem Pseudo-Element, damit sie nie im Weg ist: kein
   Element im Baum, kein z-index-Streit, keine Kollision mit Inhalt. */
.ap-flaeche::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: var(--papier-bild, var(--papier-korn));
  /* Mit Bild wird gekachelt (die Textur ist nahtlos), ohne Bild greift die
     CSS-Ersatztextur, die die ganze Fläche füllt. `background-size` gilt für
     beide Fälle, `repeat` schadet dem Ersatz nicht. */
  background-size: var(--papier-kachel, cover);
  background-repeat: repeat;
  opacity: .55;
}
.ap-flaeche > * { position: relative; z-index: 1; }

.ap-erhaben {
  --ap-hoehe: 1;
  background-color: var(--papier);
  background-image: var(--woelbung-erhaben);
  border-radius: 16px;
  box-shadow: var(--praegung-erhaben);
}
.ap-erhaben--hoch { --ap-hoehe: 2; --ap-koerper: 1;   /* Traeger = Koerper */
                    box-shadow: var(--praegung-erhaben-hoch); }

.ap-vertieft {
  --ap-hoehe: -1;
  background-color: var(--papier);
  background-image: var(--woelbung-vertieft);
  border-radius: 16px;
  box-shadow: var(--praegung-vertieft);
}
.ap-vertieft--tief { --ap-hoehe: -2; --ap-koerper: 1;  /* Loch = Koerper */
                     box-shadow: var(--praegung-vertieft-tief); }

/* Gesperrt heisst: das Papier ist glatt. Kein Relief, keine Kante — die
   Fläche verspricht dann von sich aus nichts. Die Schrift bleibt bei
   4,9:1 lesbar; ausgegraute Schrift unter der Kontrastschwelle wäre bequem
   und falsch, ein gesperrter Knopf muss lesbar bleiben. */
.ap-erhaben.ist-gesperrt,
.ap-vertieft.ist-gesperrt {
  background-image: none;
  box-shadow: inset 0 0 0 1px var(--papier-dunkel);
  color: var(--tinte-leicht);
}

/* --- [hidden] muss gewinnen ------------------------------------------------
   VIERTES AUFTRETEN AM 01.08.2026, deshalb steht es jetzt hier statt in einem
   vierten Kommentar. Betroffen waren: ein Fazit, das zu frueh dastand; eine
   Mulde, die nach dem Nachladen stehenblieb; ein "Zurücknehmen"-Knopf, der von
   Anfang an sichtbar war; und ein Marken-Etikett.

   Ursache ist immer dieselbe: Das HTML-Attribut `hidden` wirkt ueber die
   Voreinstellung `display: none` des Browsers. Jede eigene Regel mit einem
   `display`-Wert — und `.ap-knopf` hat `inline-flex`, `.ap-zeile` hat `flex` —
   ist spezifischer und schlaegt es. Das Element bleibt sichtbar, obwohl im HTML
   `hidden` steht. Nichts stuerzt ab, nichts wird rot: Man sieht nur etwas, das
   nicht da sein sollte, und sucht den Fehler in der Logik.

   `!important` ist hier ausnahmsweise richtig und nicht Faulheit: `hidden` ist
   eine Aussage des Dokuments, keine Gestaltung. Wer ein Element sichtbar
   braucht, nimmt das Attribut weg — er ueberschreibt es nicht. */
[hidden] { display: none !important; }

/* =========================================================================
   2 — Typografie (Skala aus SKILL.md §1.1)
   ========================================================================= */
.ap-display   { font-size: 32px; line-height: 36px; font-weight: 700; letter-spacing: -0.02em; }
.ap-titel     { font-size: 24px; line-height: 30px; font-weight: 700; }
.ap-abschnitt { font-size: 20px; line-height: 26px; font-weight: 600; }
.ap-unterzeile{ font-size: 17px; line-height: 24px; font-weight: 600; }
.ap-text      { font-size: 16px; line-height: 24px; font-weight: 400; }
.ap-sekundaer { font-size: 14px; line-height: 20px; font-weight: 400; color: var(--tinte-leicht); }
.ap-label     { font-size: 13px; line-height: 16px; font-weight: 600;
                text-transform: uppercase; letter-spacing: 0.12em; }
.ap-mikro     { font-size: 11px; line-height: 14px; font-weight: 500; color: var(--tinte-leicht); }

/* Schrift IM Ausschnitt. Nur Weiss (9,4:1) oder Licht (6,7:1) — Tinte auf
   Tiefe wäre 1,6:1 und damit unlesbar. */
.ap-loch .ap-text,
.ap-loch .ap-label,
.ap-loch .ap-titel,
.ap-loch .ap-display  { color: var(--tinte-hell); }
.ap-loch .ap-sekundaer,
.ap-loch .ap-mikro    { color: var(--tinte-hell); }

/* =========================================================================
   3 — Der Ausschnitt: das Papier ist aufgeschnitten
   ========================================================================= */
/* DER MATERIALSATZ DER TIEFE — eine einzige Stelle für alle Bauteile, die ein
   Loch sind. Vorher stand derselbe Satz an vier Stellen (Loch, Blende,
   Zeilensignal, Profilsignal), und die vier waren schon auseinandergelaufen:
   das Profilsignal hatte nur `background-color` plus einen Innenschatten und
   sah deshalb aus wie ein blauer Klecks. Das ist die zweite Liste, und die ist
   in diesem Projekt dreimal die Fehlerquelle gewesen. */
.ap-tiefe,
.ap-loch,
.ap-blende,
.ap-zeile__signal,
.ap-profil__signal,
.ap-marke-platz,
.ap-schnitt {
  --ap-hoehe: -2;                          /* Stufe Loch — siehe DIE EBENEN */
  background-color: var(--tiefe);          /* deckend — sonst misst jeder
                                              Kontrastprüfer gegen das Papier */
  /* Vier Lagen, siehe Warnung bei `--loch-korn`: Faser · Schlagschatten
     (oben) · Schlagschatten (links) · Grund. */
  background-image: var(--loch-korn), var(--loch-schatten), var(--loch-grund);
  background-repeat: repeat, no-repeat, no-repeat, no-repeat;
  box-shadow: var(--loch-innen), var(--loch-kante);
}

/* =========================================================================
   DER RAND EINES LOCHS SKALIERT NICHT MIT — der Befund zum gelben Punkt
   =========================================================================
   BEFUND 01.08.2026, am gerenderten Bild gemessen. Jakob ueber die Startseite:
     „Bei Nachrichten dieser Punkt, den du da rechts hingemacht hast — die
      Schattierung ist falsch."

   Er hat recht, und es ist nicht der Punkt, sondern sein Loch. Die Randwerte
   in :root stehen in ABSOLUTEN Pixeln und sind an GROSSEN Schnitten geeicht
   (`43-card-window.webp`, dazu die 72-px-Mulde). Am 16-px-Signal der
   Listenzeile ist derselbe Rand ein Viertel des Radius. Abtastung entlang der
   45-Grad-Diagonalen durch die Lochmitte, Helligkeit von 255, Papier = 219:
       t = −7 … −4 :  175 · 38 · 32 · 45   ← 5 px dunkler Hof AUF dem Papier,
                                            oben links — also Richtung Sonne
       t = −3 … +2 :  der gelbe Punkt, 8 px
       t = +3 … +5 :   72 · 101 · 121      ← 3 px helle Innenwand
       t = +6 … +7 :  246 · 240            ← 2 px fast weisser Grat AUF dem
                                            Papier, +27 gegen das Papier
   Von 16 px Durchmesser gehen 13 an den Rand und 8 an den Inhalt (die Zonen
   ueberlappen). Deshalb liest man dort keinen Schnitt, sondern eine Perle mit
   einem weissen Mond daneben. Am Kartenfenster sind dieselben 2 px unter 1 %
   — dort stimmt es, und dort bleibt es unveraendert.

   NACHGEMESSEN NACH DER KORREKTUR, dieselbe Abtastung:
       oben links aussen:  219 · 211 · 198  (vorher 219 · 210 · 175)
       unten rechts aussen: 223 · 217 · 221  (vorher 246 · 240 · 221)
   Der weisse Mond ist weg, der Hof ist von 5 px auf 2 px geschrumpft, und die
   Innenwaende stehen unveraendert. Das Loch ist wieder ein Loch.

   DIE ZWEITE LISTE IST WEG — 03.08.2026 (Backlog 55). Hier standen die
   0,35-Werte noch einmal als ausgeschriebene Zahlen, weil das Sonnen-Gate
   (`tzuki/tests/test_aperture_sonne.py`) `calc()` nicht lesen konnte und den
   sauberen Bau — EIN Faktor, `calc(2px * var(--loch-mass))` — als Verstoss
   meldete. Das Gate rechnet einfache Faktoren jetzt selbst aus (statisch
   aufloesbare `var()` eingeschlossen; was erst der Browser bestimmt, weist
   es als „nicht statisch pruefbar" aus, statt zu raten). Damit gilt wieder
   die urspruenglich gebaute, funktionierende Fassung: die geeichten Werte
   stehen EINMAL in :root, die drei kleinen Bauteile setzen nur den Faktor.
   Wer oben nacheicht, eicht hier automatisch mit.
   Der Unterschied zu den bis dahin von Hand gerundeten Zahlen liegt unter
   einer halben Pixelbreite (z. B. 0,35 px statt 0,5 px fuer die harte
   Innenlinie, 1,75 px statt 2 px fuer die weiche) — das ist die Rueckkehr
   zum Faktor, keine neue Optik.

   DIE OFFENE FRAGE VON DAMALS IST ZUR HAELFTE ENTSCHIEDEN (03.08.2026,
   Backlog 48): Die dritte Lage von `--loch-kante` war `-3px -3px 5px` — ein
   weicher Aussenschatten AUF die Sonne zu. Die Richtung ist in :root gedreht
   (von der Sonne weg), Staerke und Weichzeichner unveraendert; das Gate
   prueft die Himmelsrichtung seither mit. NICHT entschieden ist, ob ein Loch
   ueberhaupt einen Aussenschatten braucht (die Ebenen-Tabelle im Kopf kennt
   keinen) — das betrifft jede Karte des Baukastens und liegt bei Jakob.
   ========================================================================= */
.ap-zeile__signal,
.ap-profil__signal,
.ap-marke-platz {
  /* derselbe Rand wie in :root, mal 0,35 — EIN Faktor statt einer zweiten
     Liste ausgeschriebener Zahlen (siehe der Block darueber). */
  --loch-mass: .35;
}

.ap-loch {
  /* EIN KÖRPER (siehe `@property --ap-koerper` oben). Der Ausschnitt ist die
     grösste Vertiefung der Bibliothek; er trägt die Tiefe einer Fläche.
     Die drei anderen Bauteile aus demselben Materialsatz — Zeilensignal,
     Profilsignal, Markenplatz — tragen die Markierung ausdrücklich NICHT:
     sie stehen auf derselben Höhenstufe, sind aber 6 bis 32 px gross und
     damit Möblierung. Genau diese Unterscheidung kann `--ap-hoehe` nicht. */
  --ap-koerper: 1;
  position: relative;
  border-radius: 16px;
  color: var(--tinte-hell);
}

/* KORRIGIERT 01.08.2026 — vorher stand hier „spitz zulaufend" als Absicht.
   Das war die falsche Fassung, und zwar nicht als Geschmacksfrage:
   `border-radius: 50% / 50%` auf einem sehr flachen Kasten ergibt eine
   Ellipse, deren Enden praktisch Nadelspitzen sind. Gerechnet
   (Krümmungsradius einer Ellipse an der Spitze = b² / a, mit a = halbe
   Breite, b = halbe Höhe), bei 358 px Breite:
       Streifen 24 px hoch:  12² / 179 = 0,80 px   ← eine Spitze
       Auge     56 px hoch:  28² / 179 = 4,38 px   ← eine Spitze
   Eine spitz zulaufende Mandelform liest das Auge als Katzen- oder
   Reptilienauge und damit als wachsam. Jakob will ausdrücklich das
   Gegenteil (31.07.2026): „nicht creepy wie ein Auge, das dich beobachtet …
   eher Wall-E … freundlich, also nicht gefährlich."
   Mit einem Radius grösser als die halbe Höhe wird daraus eine Kapsel, deren
   Enden mit konstantem Radius auslaufen:
       Streifen: 12 px statt 0,80 px  (15-fach stumpfer)
       Auge:     28 px statt 4,38 px  (6,4-fach stumpfer)
   Was `border-radius` NICHT kann, ist die bauchige Mitte einer Linse bei
   gleichzeitig runden Enden — dafür gibt es `design/exodus/schlitz.svg`
   (Beweisseite `schlitz.html`). Wo die Form die Marke trägt, gehört der
   Vektor hin; die Kapsel hier ist die richtige Fassung für Bauteile, die
   Inhalt tragen und in der Breite mitwachsen. */
.ap-loch--schlitz {
  border-radius: 999px;
  height: 24px;
}
.ap-loch--feld  { border-radius: 16px; }
.ap-loch--rund  { border-radius: 50%; }

/* Das Auge des Gesprächs (03-conversation): breiter Schlitz mit RUNDEN Enden,
   hoch genug für eine Zeile. Siehe die Rechnung im Block darüber — ein
   elliptischer Radius endete hier in 4,38 px und damit sichtbar spitz. */
.ap-loch--auge {
  border-radius: 999px;
  min-height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* =========================================================================
   4 — Der Lichtpunkt
   Sitzt IMMER in einem .ap-loch. Höchstens EINER je Fläche.
   ========================================================================= */
/* DER STANDARD IST FLACH — entschieden von Jakob am 02.08.2026 an beiden
   Fassungen in Produktionsgrösse: „Ich bin schockiert. Ich hatte recht. Das
   Leuchten sieht schlechter aus als einfach nur der gelbe Punkt. Gelb, grün
   und rot als Punkt sieht sehr viel freundlicher aus und sehr viel weniger
   aufdringlich. Das passt zum Design besser insgesamt."
   Kein Hof, keine Überstrahlung, kein weisser Kern. Das Leuchten steht
   weiter unten als ausdrücklich benannte Ausnahme (`.ap-punkt--leuchtend`),
   damit es niemand als Verbesserung zurückholt. */
.ap-punkt {
  display: block;
  width: var(--punkt-groesse);
  height: var(--punkt-groesse);
  border-radius: 50%;
  background-color: var(--licht);
  background-image: var(--punkt-flach);
}
.ap-punkt--mittig {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
}

/* Die zwei Akzentsätze. Sie tauschen seit dem 02.08.2026 nur noch EINEN
   Wert: die Farbe. Rand und Kern werden daraus gerechnet (siehe der
   Erklärungskopf weiter oben) — deshalb kann eine grüne Lampe keinen gelben
   Rand mehr bekommen, und es gibt nichts mehr, was auseinanderlaufen kann.
   Vorher standen hier drei Werte je Satz; genau das war die zweite Liste. */
.ap-licht-gruen   { --licht: var(--gruen); }
.ap-licht-warnung { --licht: var(--warnrot); }

/* DER PUNKT IM VEKTOR, ebenfalls flach — und zwar als Standard.
   Der Vektor zeichnet den Punkt aus zwei Kreisen (Hof r = 3,4 bei halber
   Deckkraft, Kern r = 2,2) und legt in seiner eigenen Datei einen
   Weichzeichner-Filter darüber (`filter="url(#ap-blende-glanz)"` als
   Attribut). Genau das ist das Glühen, das Jakob am 02.08. auch dort weghaben
   will: „Also hier jetzt ohne Glühen des Punktes."
   `design/exodus/blende.svg` gehört einem anderen Agenten und wird hier NICHT
   angefasst — der Filter wird von aussen abgeschaltet. Das geht, weil ein
   Präsentationsattribut jeder CSS-Erklärung unterliegt.
   Die zwei Klassen im Selektor sind kein Zierrat: die SVG bringt ihren
   eigenen `<style>` mit, und der landet beim Einbetten NACH dieser Datei im
   Dokument. Bei gleicher Spezifität gewönne der spätere. */
.ap-blende-svg .ap-blende-svg__punkt      { filter: none; }
.ap-blende-svg .ap-blende-svg__punkt-hof  { fill: var(--licht-hof); opacity: 1; }
.ap-blende-svg .ap-blende-svg__punkt-kern { fill: var(--licht); }

/* Das zweite, farbunabhängige Merkmal der Warnung. Rot allein reicht nicht:
   rund 8 % der Männer sehen Rot und Grün nicht sicher auseinander, und das
   Warnrot liegt ausserdem mit 2,80:1 auf der Tiefe unter der Schwelle. Die
   Warnung ist deshalb GRÖSSER (12 statt 8 px) und schlägt langsam — beides
   ist ohne Farbe erkennbar.
   GESCHLAGEN WIRD SEIT DEM 02.08. IN DER DECKKRAFT und nicht mehr im Hof:
   ein flacher Punkt hat keinen Hof, den man auf- und abdrehen könnte. */
.ap-punkt--warnung {
  --punkt-groesse: 12px;
  animation: ap-warnen-flach 2.4s ease-in-out infinite;
}
@keyframes ap-warnen-flach { 0%, 62%, 100% { opacity: .55; } 30% { opacity: 1; } }

/* ATMEN GIBT ES BEIM FLACHEN PUNKT NICHT. Ein flacher Punkt hat nichts zu
   dimmen — aus dem Atmen würde ein Blinken. Und Jakob hat das Durchsichtig-
   werden am 02.08. ausdrücklich abgelehnt (er sprach dabei vom Schlitz):
   „Und wenn sich das Auge schliesst, WIRD DER PUNKT SO TRANSPARENT — DAS MUSS
   NICHT SEIN."
   Die Klasse bleibt bestehen, damit die bestehenden Flächen (`musterbogen`,
   `beispiel-morgen`) nicht angefasst werden müssen; sie tut nur nichts mehr.
   Unter `.ap-leuchtend` lebt die Bewegung weiter. */
.ap-punkt--atmend { animation: none; opacity: 1; }
.ap-blende-svg--atmet .ap-blende-svg__punkt { animation: none; }

/* =========================================================================
   4b — DIE AUSNAHME: DAS LEUCHTEN
   Es ist NICHT gelöscht, aber es ist nicht mehr der Standard. Wer es haben
   will, muss es hinschreiben: `.ap-punkt--leuchtend` für einen Punkt,
   `.ap-leuchtend` für eine ganze Umgebung samt Vektor.
   WARUM ES VERLOREN HAT, damit es niemand als Verbesserung zurückholt —
   Jakob am 02.08.2026, nachdem beide Fassungen nebeneinander in
   Produktionsgrösse standen: „Ich bin schockiert. Ich hatte recht. Das
   Leuchten sieht schlechter aus als einfach nur der gelbe Punkt. Gelb, grün
   und rot als Punkt sieht sehr viel freundlicher aus und sehr viel weniger
   aufdringlich. Das passt zum Design besser insgesamt."
   Die lange Fassung steht in `design/exodus/licht/LICHT.md`.
   ========================================================================= */
.ap-punkt--leuchtend,
.ap-leuchtend .ap-punkt {
  background-image: var(--punkt-verlauf);
  box-shadow: var(--punkt-glanz);
}
.ap-leuchtend .ap-blende-svg .ap-blende-svg__punkt      { filter: url(#ap-blende-glanz); }
.ap-leuchtend .ap-blende-svg .ap-blende-svg__punkt-hof  { fill: var(--licht-hof); opacity: .5; }
.ap-leuchtend .ap-blende-svg .ap-blende-svg__punkt-kern {
  fill: color-mix(in srgb, var(--punkt-kern) 62%, var(--licht));
}
.ap-leuchtend .ap-punkt--warnung,
.ap-punkt--leuchtend.ap-punkt--warnung {
  animation: ap-warnen 2.4s ease-in-out infinite;
}
@keyframes ap-warnen {
  0%, 62%, 100% { box-shadow: var(--punkt-glanz-schwach); }
  30%           { box-shadow: var(--punkt-glanz); }
}
/* Atmend: Der Punkt wird nicht grösser, sondern nur heller — eine Grössen-
   animation liest man als Blinken (Alarm), eine Helligkeitsanimation als
   Atmen (da ist jemand). */
.ap-leuchtend .ap-punkt--atmend,
.ap-punkt--leuchtend.ap-punkt--atmend {
  animation: ap-atmen 3.2s ease-in-out infinite;
}
.ap-leuchtend .ap-blende-svg--atmet .ap-blende-svg__punkt {
  animation: ap-atmen 3.2s ease-in-out infinite;
}
@keyframes ap-atmen {
  0%, 100% { opacity: .58; box-shadow: var(--punkt-glanz-schwach); }
  50%      { opacity: 1;   box-shadow: var(--punkt-glanz); }
}

/* =========================================================================
   5 — Der Knopf
   Beim Drücken kippt die Prägung nach innen: Licht und Schatten tauschen die
   Seite. Genau das ist der „Klick"-Effekt — er entsteht nicht durch Bewegung,
   sondern dadurch, dass das Auge die Lichtquelle für einen Moment auf der
   anderen Seite sieht.
   ========================================================================= */
.ap-knopf {
  --ap-hoehe: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 48px;
  min-width: 48px;
  padding: 0 24px;
  border-radius: 24px;                    /* halbe Höhe = Kapsel */
  background-color: var(--papier);
  background-image: var(--woelbung-erhaben);
  color: var(--tinte);
  font-size: 16px;
  line-height: 24px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: var(--praegung-erhaben);
  transition: box-shadow .09s ease-out, transform .09s ease-out;
}
.ap-knopf:active {
  background-image: var(--woelbung-vertieft);
  box-shadow: var(--praegung-vertieft);
  transform: translateY(1px);
}

/* Hauptaktion: höher, stärker aufliegend, 17px/700. Die Hierarchie kommt aus
   Höhe und Relief — eine zweite Farbe gäbe es im Materialgesetz nicht. */
.ap-knopf--haupt {
  --ap-hoehe: 2;
  --ap-koerper: 1;   /* die Hauptaktion ist ein Koerper, der Nebenknopf nicht */
  min-height: 56px;
  border-radius: 28px;
  font-size: 17px;
  font-weight: 700;
  box-shadow: var(--praegung-erhaben-hoch);
}
.ap-knopf--haupt:active {
  background-image: var(--woelbung-vertieft);
  box-shadow: var(--praegung-vertieft-tief);
  transform: translateY(2px);
}

/* Nebenaktion: liegt bündig im Papier, nur eine eingeritzte Kontur. Sie
   verspricht weniger, weil sie weniger Relief hat — nicht, weil sie blasser ist. */
.ap-knopf--neben {
  --ap-hoehe: -1;
  background-image: none;
  /* AUF DIE SONNE GEZOGEN 01.08.2026: der 1-px-Ring `inset 0 0 0 1px` lief
     rundherum. Eine eingeritzte Kontur ist aber eine Kerbe — oben links
     dunkel, unten rechts hell, wie jede andere Vertiefung auch. */
  box-shadow: inset 1px 1px 2px var(--schatten-2),
              inset 1px 1px 0 var(--papier-dunkel),
              inset -1px -1px 0 var(--kante-licht-w),
              1px 1px 0 var(--papier-hell);
  font-weight: 600;
}
.ap-knopf--neben:active {
  background-image: var(--woelbung-vertieft);
  box-shadow: var(--praegung-vertieft);
  transform: translateY(1px);
}

.ap-knopf[disabled],
.ap-knopf.ist-gesperrt {
  background-image: none;
  box-shadow: inset 0 0 0 1px var(--papier-dunkel);
  color: var(--tinte-leicht);
  cursor: not-allowed;
  transform: none;
}
.ap-knopf[disabled]:active,
.ap-knopf.ist-gesperrt:active {
  box-shadow: inset 0 0 0 1px var(--papier-dunkel);
  transform: none;
}

/* Tastaturfokus: eine Tintenlinie, kein Leuchten. Gelb wäre auf Papier
   1,4:1 und damit als Fokusring unsichtbar. */
:where(.ap-knopf, .ap-zeile, .ap-profil, .ap-sprechknopf, .ap-leisten-knopf):focus-visible {
  outline: 2px solid var(--tinte);
  outline-offset: 2px;
}

/* =========================================================================
   6 — Die Listenzeile (64 px, wie in 01-start)
   ========================================================================= */
.ap-zeile {
  display: grid;
  grid-template-columns: 24px 1fr auto 24px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 64px;
  padding: 0;
  text-align: left;
  background: none;
  cursor: pointer;
  color: var(--tinte);
}
.ap-zeile__symbol { width: 24px; height: 24px; color: var(--tinte); }
.ap-zeile__text   { min-width: 0; }
/* Titel und Nebenzeile sind Blöcke, sonst laufen sie in EINE Zeile zusammen
   und die Hierarchie ist weg (im ersten Screenshot genau so passiert). */
.ap-zeile__titel  { display: block; font-size: 16px; line-height: 24px; font-weight: 400;
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ap-zeile__neben  { display: block; font-size: 14px; line-height: 20px; color: var(--tinte-leicht); }
.ap-zeile__pfeil  { width: 24px; height: 24px; color: var(--tinte); }

/* Angetippt: die ganze Zeile sinkt kurz ins Papier. */
.ap-zeile:active {
  box-shadow: var(--praegung-vertieft);
  border-radius: 16px;
}

/* „Betrifft dich": ein winziger Schnitt mit dem Lichtpunkt darin. Das ist die
   einzige Stelle einer Fläche, an der Licht auftauchen darf — deshalb gibt es
   darunter die stille Variante für alles Weitere, das ebenfalls zählt. */
.ap-zeile__signal {
  width: 16px; height: 16px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  /* Material kommt aus dem gemeinsamen Satz in §3. */
}
.ap-zeile--gedaempft .ap-zeile__titel,
.ap-zeile--gedaempft .ap-zeile__symbol,
.ap-zeile--gedaempft .ap-zeile__pfeil { color: var(--tinte-leicht); }

/* =========================================================================
   7 — Die Karte
   ========================================================================= */
.ap-karte {
  --ap-hoehe: 2;
  --ap-koerper: 1;   /* die Karte ist der groesste erhabene Koerper */
  background-color: var(--papier);
  background-image: var(--woelbung-erhaben);
  border-radius: 16px;
  padding: 16px;
  box-shadow: var(--praegung-erhaben-hoch);
}
.ap-karte--weit { padding: 24px; }

/* Das Fenster: der Ausschnitt IN der Karte. Volle Breite minus nichts — es
   ist ein Schnitt durch die Karte, kein aufgelegtes Feld. */
.ap-karte__fenster {
  border-radius: 12px;
  min-height: 64px;
  padding: 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

/* =========================================================================
   8 — Die Leisten
   ÜBERARBEITET 01.08.2026 — zwei Befunde von Jakob, die zusammengehören:

   (a) „Die untere und die obere Leiste, die sind halt schon sehr
       unspektakulär. Man müsste irgendwie dieses Blau noch dort einbauen."
   (b) „Wenn man unterhalb dieser Kachel guckt, dann ist die unten so
       abgehackt. Lass doch die Kachel enden, und dann ein paar Millimeter
       später, wenn der Schatten auch endet, dann diesen Strich durchführen,
       wenn man da drunter Text oder so was zukünftig noch haben will."

   Zu (b): Der Strich klebte als `box-shadow` direkt an der Unterkante der
   Leiste — Leiste und Trennung waren dasselbe Pixel, deshalb wirkte der
   Abschluss abgehackt. Jetzt endet die Leiste mit ihrem eigenen weichen
   Schatten, und 12 px darunter läuft der Strich als eigenes Element durch.
   Der Platz dazwischen ist der Platz, den Jakob für späteren Text meint.

   Zu (a): Dieser Strich ist kein aufgemalter Strich mehr, sondern ein
   SCHNITT — 2 px Tiefe mit dem hellen Grat darunter, dasselbe Material wie
   jedes andere Loch. Damit ist Blau in beiden Leisten, ohne Gesetz 2 zu
   brechen (Blau nur im Ausschnitt, nie als Fläche). Dazu kommt oben links
   der Platz der Marke und unten die Mulde, die jetzt ein echtes Loch ist.
   ========================================================================= */

/* Der Schnitt quer durch das Papier — 2 px Tiefe, darunter der helle Grat.
   Material aus §3, hier nur Form und Lage. */
.ap-schnitt {
  height: 2px;
  border-radius: 1px;
}

.ap-kopfleiste {
  --ap-hoehe: 1;
  position: relative;
  display: grid;
  grid-template-columns: 44px 1fr 44px;
  align-items: center;
  gap: 8px;
  height: 56px;
  /* GEMESSEN 01.08.2026 — Jakob: „oben rechts die Leiste, die ist zu kurz".
     Sie war es. In `reise/02-hoert-zu.html` mass die Kopfleiste 44 statt
     56 px und die Fussleiste 72 statt 88. Ursache ist NICHT die Höhe hier,
     sondern dass `height` in einer Flex-Spalte nur ein VORSCHLAG ist: die
     Station steckt die Leisten in `.r-standschirm` (fixed, flex column), der
     Chatverlauf darin ist um 238 px übervoll, und der Browser verteilt dieses
     Zuviel auf alle schrumpfbaren Kinder. Geschrumpft wird bis zur
     min-content-Höhe — und die ist bei einer Leiste exakt ihr grösstes Kind:
     44 px (Profilkreis) oben, 72 px (Mulde) unten. Deshalb sah es zugleich
     nach „Leiste zu kurz" UND nach „Symbol zu gross" aus: die Leiste war auf
     das Symbol zusammengeschoben, der Luftrand (6 px oben, 8 px unten) auf
     null. Beides ist derselbe Vorgang, nicht zwei Fehler.
     `flex: none` macht aus der Höhe eine Zusage. Ausserhalb einer Flexbox
     tut die Zeile nichts, die restlichen Flächen bleiben unberührt. */
  flex: none;
  padding: 0 16px;
  background-color: var(--papier);
  background-image: var(--woelbung-erhaben);
  /* Nur noch der eigene Abschluss der Leiste plus ihr Schatten. Der Strich
     hängt nicht mehr dran, er kommt als ::after 12 px später. */
  /* Die Kopfleiste liegt auf dem Papier und wirft nach unten rechts. Der
     Versatz kam am 01.08.2026 dazu — vorher stand hier `0 8px 14px`, also
     ein Schatten, der nach links genauso weit lief wie nach rechts.
     LICHTKANTE NACHGETRAGEN 02.08.2026. Jakob an Station 8: „Hier siehst du
     diese HELLERE KANTE OBEN — die müsste eigentlich auch beim unteren
     Balken der Fall sein und auch beim Knopf, in so einem 45-GRAD-WINKEL
     NACH OBEN LINKS."
     Die Kopfleiste hatte bis dahin ÜBERHAUPT keine Lichtkante, nur die
     dunkle Gegenkante und ihren Wurf. Sie ist erhaben, also gehört ihr
     dasselbe Kantenpaar wie jedem anderen Träger: hell innen oben links,
     dunkel innen unten rechts. Am oberen Bildschirmrand ist davon nur die
     linke Hälfte zu sehen — richtig ist es trotzdem, und auf einer nicht
     fixierten Leiste (`licht.html`) sieht man beide.
     P1 · ZUSAMMENGEZOGEN 02.08.2026. Die letzte Lage stand auf
     `6px 8px 14px` und reichte damit 22 px weit — der breiteste Einzelposten
     der ganzen Fläche, doppelt so weit wie die Vorlage je geht (Messung:
     `design/exodus/tiefe/TIEFE.md`). 6/8 war ausserdem gar nicht die
     Diagonale, obwohl Gesetz 5 sie verlangt. Jetzt `3px 3px 6px`,
     Reichweite 9 px, und der Winkel stimmt. */
  box-shadow:
      inset 2px 2px 0 var(--kante-licht),
      inset 7px 7px 10px -7px var(--kante-licht),
      inset -2px -2px 0 var(--kante-dunkel),
      1px 1px 2px var(--schatten-1),
      3px 3px 6px var(--schatten-1);
}
.ap-kopfleiste::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -14px;
  /* NACHKORRIGIERT nach dem ersten Screenshot: 2 px Tiefe mit einer dunklen
     Innenkante lasen sich über die volle Breite nicht als feiner Schnitt,
     sondern als schwarzer Tabellenstrich. Jakob nennt den heutigen Strich
     ausdrücklich „dünn, fein, professionell" — das darf nicht verloren gehen,
     nur weil Blau dazukommt. Jetzt 1 px Vollton in `--tiefe` plus der helle
     Grat darunter: dieselbe Feinheit, aber es ist Blau, und es ist ein
     Schnitt und kein aufgemalter Strich. */
  height: 1px;
  background-color: var(--tiefe);
  background-image: linear-gradient(to bottom,
      rgba(0, 6, 20, .45), rgba(0, 6, 20, 0));
  box-shadow: 0 1px 0 var(--kante-licht);
  pointer-events: none;
}
.ap-kopfleiste__titel { text-align: center; }

/* Der Platz der Marke, oben links. AUSDRÜCKLICH EIN PLATZHALTER: das Logo
   entsteht parallel (`design/exodus/logo/`) und gehört einem anderen Agenten.
   Hier steht nur ein sauberer runder Ausschnitt, der die richtige Fläche
   belegt — keine Lamellen, keine Form, keine Behauptung. Wer das Logo
   einsetzt, ersetzt dieses Element und ändert an der Leiste nichts. */
.ap-marke-platz {
  width: 32px; height: 32px;
  border-radius: 50%;
  justify-self: start;
}

.ap-fussleiste {
  --ap-hoehe: 1;
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  justify-items: center;
  gap: 8px;
  height: 88px;
  /* Gleiche Zusage wie bei der Kopfleiste — Herleitung dort. Ohne sie schrumpft
     die Leiste in einer Flex-Spalte auf ihr grösstes Kind (die 72-px-Mulde),
     und der blaue Ring des Sprechknopfs stösst oben und unten an die Leisten-
     kante. */
  flex: none;
  padding: 0 16px;
  background-color: var(--papier);
  background-image: var(--woelbung-erhaben);
  /* HIER LAG DER GRÖBSTE VERSTOSS, und er ist lehrreich: Die Fussleiste warf
     ihren Schatten NACH OBEN (`0 -2px 4px`, `0 -8px 14px`). Bei einer Sonne
     oben links ist das unmöglich — ein erhabenes Bauteil kann nicht nach
     oben werfen. Es war die bequeme Lösung („die Leiste soll sich absetzen"),
     und sie hat für jede Fläche eine zweite, erfundene Lichtquelle unten
     eingeführt. Genau das meint Jakobs „nicht aus derselben Richtung".
     Was stattdessen richtig ist: Die Leiste ist erhaben, also fängt ihre
     OBERE Kante das Licht — der helle Grat bleibt. Ihr Wurf ginge nach unten
     rechts und liegt dort ausserhalb des Bildschirms, ist also unsichtbar.
     Sichtbar bliebe nur die Kontaktverdeckung: das Streulicht kommt in die
     Fuge zwischen Leiste und Papier nicht hinein.

     UND GENAU DIESE FUGE IST AM 02.08.2026 GEFALLEN. Jakob an Station 9:
       „Der untere Balken hat einen SCHATTEN NACH OBEN — das passt wiederum
        nicht, DA MUSS EINE HELLE KANTE HIN."
     Er hat recht, und es ist nachgemessen. Senkrechter Schnitt durch die
     Oberkante der Fussleiste (Helligkeit von 255, y = 0 ist die Oberkante):
         −14: 50   ← der blaue Schnitt (::before)
         −13: 247  ← sein heller Grat
         −12 … −3: rund 220 (Papier)
         −2: 211 · −1: 206   ← DAS WAR DIE FUGE
          0:  247 ·  1: 247  ← die eigene Lichtkante der Leiste
     Über der Lichtkante lag also ein dunkler Streifen, und das Auge liest
     das Paar von oben nach unten: erst dunkel, dann hell — also eine Kante,
     die nach OBEN wirft. Der Beleg dafür, dass die Ausnahme (b) hier nicht
     nur unschön, sondern falsch war: sie hat die Lichtkante, die direkt
     darunter liegt, unlesbar gemacht.
     Jetzt trägt die Leiste dasselbe Kantenpaar wie jeder andere Träger —
     hell innen oben links, dunkel innen unten rechts — und darüber nichts.
     Die Trennung leistet der Schnitt 14 px darüber, wie zuvor auch. */
  box-shadow:
      inset 2px 2px 0 var(--kante-licht),
      inset 7px 7px 10px -7px var(--kante-licht),
      inset -2px -2px 0 var(--kante-dunkel);
}
.ap-fussleiste::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: -14px;
  /* NACHKORRIGIERT nach dem ersten Screenshot: 2 px Tiefe mit einer dunklen
     Innenkante lasen sich über die volle Breite nicht als feiner Schnitt,
     sondern als schwarzer Tabellenstrich. Jakob nennt den heutigen Strich
     ausdrücklich „dünn, fein, professionell" — das darf nicht verloren gehen,
     nur weil Blau dazukommt. Jetzt 1 px Vollton in `--tiefe` plus der helle
     Grat darunter: dieselbe Feinheit, aber es ist Blau, und es ist ein
     Schnitt und kein aufgemalter Strich. */
  height: 1px;
  background-color: var(--tiefe);
  background-image: linear-gradient(to bottom,
      rgba(0, 6, 20, .45), rgba(0, 6, 20, 0));
  box-shadow: 0 1px 0 var(--kante-licht);
  pointer-events: none;
}

.ap-leisten-knopf {
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  color: var(--tinte);
  cursor: pointer;
}
.ap-leisten-knopf:active { box-shadow: var(--praegung-vertieft); }

/* Die Mulde: eine runde Vertiefung, in der der Sprechknopf sitzt. Erst durch
   die Mulde wirkt der Knopf eingelassen statt aufgeklebt.
   GEÄNDERT 01.08.2026 — sie ist jetzt ein echtes LOCH und kein vertieftes
   Papier mehr. Damit steht in der unteren Leiste ein 8 px breiter blauer Ring
   um den Sprechknopf (72 aussen, 56 innen). Das ist die zweite Hälfte von
   Jakobs „man müsste dieses Blau noch dort einbauen" — und es stimmt auch
   inhaltlich: der Sprechknopf sitzt in der Blende, durch die Tzuki hört. */
.ap-mulde {
  --ap-hoehe: -2;
  display: grid;
  place-items: center;
  width: 72px; height: 72px;
  border-radius: 50%;
  background-color: var(--tiefe);
  background-image: var(--loch-korn), var(--loch-schatten), var(--loch-grund);
  background-repeat: repeat, no-repeat, no-repeat, no-repeat;
  box-shadow: var(--loch-innen), var(--loch-kante);
}
/* DER SPRECHKNOPF IST DER VORFÜHRFALL DER EBENEN (siehe Kopf der Datei).
   Er liegt NICHT auf Papier, sondern in einem Loch — und deshalb reicht
   `--praegung-erhaben-hoch` hier nicht: dessen Wurf ist warm (rgba(60,45,30)),
   und ein warmer Schatten auf dunklem Blau ist unsichtbar. Vorher war genau
   das der Zustand: der Knopf hatte gegen die Mulde faktisch keine Unterkante,
   und die ganze Räumlichkeit kam allein aus dem sehr dunklen blauen Ring.
   Das ist Jakobs „bei dem Sprechknopf ist er richtig stark" von der anderen
   Seite gesehen — zu viel Loch, zu wenig Knopf.
   Jetzt: dieselben INNEN-Kanten wie bei jedem Träger (Licht oben links, Fase,
   Gegenkante unten rechts) und ein KALTER Wurf nach unten rechts in die
   Tiefe. Die Kurve ist dieselbe wie beim Papierwurf — 52 % an der Kontakt-
   linie, danach schnell weg (gemessen an `35-speech-button-rest.webp`). */
.ap-sprechknopf {
  --ap-hoehe: 2;
  display: grid;
  place-items: center;
  width: 56px; height: 56px;
  border-radius: 50%;
  background-color: var(--papier);
  background-image: var(--woelbung-erhaben);
  color: var(--tinte);
  cursor: pointer;
  box-shadow:
      inset 2px 2px 0 var(--kante-licht),
      inset 7px 7px 10px -7px var(--kante-licht),
      inset -2px -2px 0 var(--kante-dunkel),
      inset -9px -9px 14px -9px var(--schatten-3),
      1.5px 1.5px 0 rgba(0, 4, 14, .62),
      2px 2px 3px rgba(0, 4, 14, .34),
      4px 4px 6px rgba(0, 4, 14, .16);
  transition: box-shadow .09s ease-out;
}
.ap-sprechknopf:active {
  background-image: var(--woelbung-vertieft);
  box-shadow: var(--praegung-vertieft);
}
.ap-sprechknopf[disabled],
.ap-sprechknopf.ist-gesperrt {
  box-shadow: inset 0 0 0 1px var(--papier-dunkel);
  color: var(--tinte-leicht);
  cursor: not-allowed;
}

/* DIE VIERTE EBENE: das Symbol. Jakob: „und an der nächsten Kante geht es
   wieder hoch" — nach der Mulde (runter) und dem Knopf (hoch) schlägt das
   Vorzeichen ein drittes Mal um. Ein Symbol auf Papier ist EINGEPRÄGT, nicht
   aufgeklebt: die Rille liegt oben links im Schatten und fängt unten rechts
   das Licht. Genau zwei Halbpixel, mehr verträgt eine 1,6 px dünne Linie
   nicht — dicker gesetzt wird daraus ein Doppelstrich statt einer Kerbe.

   NUR EINE LIPPE, KEIN GEGENSCHATTEN — und das ist gemessen, nicht gespart.
   Erster Versuch waren zwei Lagen (helle Lippe unten rechts, dunkler Saum
   oben links); im Screenshot bei sechsfacher Vergrösserung las sich der
   dunkle Saum als zweiter, versetzter Strich statt als Kerbe. Am
   freigegebenen Bild `32-logo-embossed.webp` (die geprägte Marke) ist es
   genauso: senkrechter Schnitt durch die obere Linie, Papier 220 von 255 —
   die Werte steigen auf 247 und fallen dann auf 225 zurück. Ein Ausschlag
   von +27 nach oben, keiner nach unten. Eine geprägte Linie in diesem
   Material zeigt die Lippe und praktisch keinen Gegenschatten.

   Der Selektor greift AUCH ohne Klasse (`.ap-sprechknopf > svg`), damit die
   bestehenden Reise-Bildschirme die Ebene mitbekommen, ohne dass jede Datei
   angefasst werden muss. Für neuen Code ist `.ap-symbol` die Klasse — nur
   sie ist für das Gate lesbar. */
.ap-symbol,
.ap-sprechknopf > svg,
.ap-leisten-knopf > svg {
  --ap-hoehe: -1;
  filter: drop-shadow(0.6px 0.6px 0.4px var(--kante-licht));
}
/* Im Ausschnitt gibt es kein Papier, in das man etwas prägen könnte — dort
   ist das Symbol ein aufliegender Lichtstrich und wirft nach unten rechts. */
.ap-loch .ap-symbol,
.ap-tiefe .ap-symbol {
  --ap-hoehe: 1;
  filter: drop-shadow(0.5px 0.5px 0.5px rgba(0, 4, 14, .55));
}

/* Fixierte Fassung — nur dort verwenden, wo der Inhalt genug Polster hat, um
   unter der Leiste hervorzukommen (designcheck Regel 6). */
.ap-kopfleiste--fixiert {
  position: fixed; top: 0; left: 0; right: 0; z-index: 2;
}
.ap-fussleiste--fixiert {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 2;
}

/* =========================================================================
   9 — Der Profilkreis
   ========================================================================= */
.ap-profil {
  --ap-hoehe: -1;
  position: relative;
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  background-color: var(--papier);
  background-image: var(--woelbung-vertieft);
  color: var(--tinte);
  cursor: pointer;
  box-shadow: var(--praegung-vertieft);
}
.ap-profil:active { box-shadow: var(--praegung-vertieft-tief); }
/* Der Signalpunkt am Rand ist ein kleiner Durchbruch, kein aufgesetzter
   Klecks — deshalb Tiefe mit Innenschatten, nicht einfach Blau. */
.ap-profil__signal {
  position: absolute;
  top: 0; right: 0;
  width: 10px; height: 10px;
  border-radius: 50%;
  /* Material kommt aus dem gemeinsamen Satz in §3 — vorher stand hier eine
     eigene, schwächere Fassung, und genau die sah aus wie ein blauer Klecks. */
}

/* =========================================================================
   10 — Der Trenner: eine Rille im Papier
   Eine Linie wäre aufgemalt. Zwei Linien — dunkel oben, hell unten — sind
   eine Kerbe, in die Licht von oben links fällt.

   NACHGEZOGEN 01.08.2026: Die Kerbe war 1 px dunkel plus 1 px hell aus den
   Flächentönen und damit fast unsichtbar (1,17:1 bzw. 1,08:1 gegen das
   Papier). Jetzt derselbe helle Grat wie an jeder anderen Schnittkante.
   Wer eine Trennung mit BLAU will, nimmt `.ap-schnitt` — das ist ein Loch,
   keine Kerbe, und trägt entsprechend mehr Gewicht. */
.ap-rille {
  height: 2px;
  border: 0;
  background-image: linear-gradient(var(--schatten-2) 0 1px, var(--kante-licht) 1px 2px);
}

/* =========================================================================
   11 — Die Blende

   11a — DER VEKTOR (`design/exodus/blende.svg`) IST DIE BLENDE.
   Wer eine Blende braucht, nimmt ihn. Die Herleitung, die Bewegungsgrammatik
   und die gemessenen Grenzen stehen in `design/exodus/blende.md`.

   Der Vektor bringt seine eigene Gestalt und seine eigenen Zustände mit; er
   wird INLINE ins HTML gesetzt (ein `<img src="blende.svg">` liesse sich von
   aussen nicht in einen Zustand versetzen). Hier stehen deshalb nur die zwei
   Sachen, die er NICHT mitbringen kann, weil sie von aussen kommen: seine
   Grösse und das Atmen des Lichtpunkts. Nichts davon wiederholt einen Wert
   aus der SVG.

   WICHTIG — die Zustandsklasse gehört an das `<svg>` SELBST, nicht an eine
   Hülle darum. Gemessen am 01.08.2026: eine Hülle mit
   `class="ap-blende-svg ap-blende-svg--offen"` (so steht es im Einbett-
   Beispiel von `blende.md`) bleibt wirkungslos — die SVG setzt `--ap-iris`
   auf sich selbst, und ein direkt gesetzter Wert schlägt jeden geerbten.
   Die Hülle unten trägt deshalb NUR die Grösse.
   ========================================================================= */
.ap-blende-vektor {
  display: block;
  width: var(--ap-blende-groesse, 96px);
  height: var(--ap-blende-groesse, 96px);
}
.ap-blende-vektor--klein { --ap-blende-groesse: 48px; }
.ap-blende-vektor--gross { --ap-blende-groesse: 200px; }

/* Der Lichtpunkt des Vektors wird vollständig in §4 bzw. §4b eingestellt —
   flach als Standard, leuchtend nur unter `.ap-leuchtend`. Hier stand bis zum
   02.08.2026 ein zweiter Satz Regeln für denselben Punkt (Atmen und heisser
   Kern). Zwei Orte für dieselbe Frage sind in diesem Projekt schon dreimal
   die Fehlerquelle gewesen; sie sind deshalb dorthin gezogen und nicht
   verdoppelt worden. */

/* =========================================================================
   11b — ÜBERHOLT: die Blende aus drei CSS-Quadraten (`.ap-blende`)
   Bauform: Die Lamellen sind grosse Quadrate, deren UNTERE Kante die
   Schneide ist. Drei davon, um 120° versetzt und um `--ap-oeffnung` vom
   Mittelpunkt weggeschoben, lassen genau ein gedrehtes Dreieck offen.

   BEFUND 01.08.2026 — DER GESCHLOSSENE ZUSTAND LAS SICH NICHT ALS BLENDE.
   Gemeldet beim Bau der Referenzreise, danach selbst nachgestellt und
   fotografiert. Die Diagnose der Meldung war „ein Sektor bleibt unbedeckt";
   das stimmte NICHT — der Ausschnitt ist bei `--ap-oeffnung: 0` vollständig
   zu, es kam kein Blau durch. Der Fehler war ein anderer und lag tiefer:

   Die Lamellen sind Quadrate von 1,7-facher Ringgrösse. Bei geschlossener
   Blende laufen ihre Schneiden durch den Mittelpunkt, und weil jedes Quadrat
   weit über den Ring hinausragt, verdeckt das oberste die Schneiden der
   beiden anderen. Sichtbar blieb EINE lange Sehne quer durch den Kreis —
   ein angeschnittener Kuchen, kein Windrad. Eine echte geschlossene Iris
   zeigt DREI kurze Kanten in Rotationssymmetrie.

   Gegenprobe gemacht, damit die Ursache nicht geraten war: `--ap-drehung: 0`
   und ein negativer Überlappungswert änderten beide nichts. Es lag an der
   Grösse der Lamelle, nicht an Drehung oder Deckung — mit `overflow: hidden`
   allein war das nicht zu lösen.

   ENTSCHEIDUNG: Hier wurde nicht nachgebessert, und dieses Bauteil ist seit
   dem 01.08.2026 ÜBERHOLT. `design/exodus/blende.svg` löst dieselbe Aufgabe
   richtig (Schnittmenge dreier Kreisscheiben, ein Parameter, geschlossen ein
   sauberes Windrad) und ist ausserdem skalierbar. Die Referenzreise ist am
   01.08.2026 vollständig auf den Vektor umgestellt.

   WARUM ES TROTZDEM NOCH HIER STEHT: `musterbogen.html` und
   `beispiel-morgen.html` zeigen es noch — der Musterbogen ausdrücklich als
   Beleg des Befunds. Ob das Bauteil ganz gelöscht wird, entscheidet Jakob;
   es ist das Namensgebende des ganzen Designsystems.
   IN NEUEM CODE NICHT MEHR VERWENDEN.
   ========================================================================= */
.ap-blende {
  --ap-hoehe: -2;
  --ap-koerper: 1;   /* die Iris ist 96 px gross und traegt die Flaeche */
  --ap-blende-groesse: 96px;
  --ap-lamelle: calc(var(--ap-blende-groesse) * 1.7);
  --ap-oeffnung: calc(var(--ap-blende-groesse) * 0.13);
  --ap-drehung: 0deg;

  position: relative;
  width: var(--ap-blende-groesse);
  height: var(--ap-blende-groesse);
  border-radius: 50%;
  overflow: hidden;
  /* Material kommt aus dem gemeinsamen Satz in §3. */
}

.ap-blende__lamelle {
  position: absolute;
  left: 50%; top: 50%;
  width: var(--ap-lamelle);
  height: var(--ap-lamelle);
  background-color: var(--papier);
  /* KEINE Wölbung auf der Lamelle. Der Verlauf bezieht sich auf den ganzen,
     weit über den Ring hinausragenden Lamellenkasten — sichtbar ist davon nur
     ein Ausschnitt, und der wirkte wie gebürstetes Metall statt wie Papier.
     Ein einzelner heller Streifen ENTLANG der Schneide leistet dasselbe,
     ohne diesen Fehler. */
  background-image: linear-gradient(to top,
      color-mix(in srgb, var(--papier-hell) 80%, transparent) 0,
      transparent 14px);
  /* Die Schneide fängt Licht (heller Grat) und wirft ihren Schatten. Der
     Schatten braucht zwei Lagen, weil er auf ZWEI Materialien fällt: warm auf
     die nächste Lamelle (Papier), kalt in den Ausschnitt (Tiefe). */
  /* Versatz nachgezogen 01.08.2026 — auch dieses überholte Bauteil darf die
     eine Sonne nicht verletzen, es steht noch auf dem Musterbogen. */
  box-shadow: 1px 1px 0 var(--papier-hell),
              2px 2px 4px rgba(60, 45, 30, .45),
              5px 6px 12px rgba(0, 8, 24, .38);
  /* Die abgerundete Führungsecke macht aus dem Dreieck die gebogene
     Blendenform aus 05-health. ZURÜCKGENOMMEN von 78%/62%: bei so grossem
     Radius frisst die Rundung die ganze Schneide, und aus der Iris wird ein
     Klecks. Der Radius darf die Kante nur anfasen. */
  border-bottom-left-radius: 24% 16%;
  transform:
      translate(-50%, -50%)
      rotate(calc(var(--ap-drehung) + var(--i) * 120deg))
      translateY(calc(-1 * (var(--ap-oeffnung) + var(--ap-lamelle) / 2)));
}
.ap-blende__lamelle:nth-child(1) { --i: 0; }
.ap-blende__lamelle:nth-child(2) { --i: 1; }
.ap-blende__lamelle:nth-child(3) { --i: 2; }

.ap-blende--zu    { --ap-oeffnung: 0px; --ap-drehung: -38deg; }
.ap-blende--offen { --ap-oeffnung: calc(var(--ap-blende-groesse) * 0.22); --ap-drehung: 10deg; }

/* Ladezustand: öffnet und schliesst. Kein kreisender Kringel — die Blende
   sagt „ich sehe gerade hin", was hier die ehrlichere Aussage ist. */
.ap-blende--laden {
  animation: ap-blende-laden 2.6s cubic-bezier(.4, 0, .3, 1) infinite;
}
@keyframes ap-blende-laden {
  0%, 100% { --ap-oeffnung: 0px; --ap-drehung: -38deg; }
  50%      { --ap-oeffnung: calc(var(--ap-blende-groesse) * 0.22); --ap-drehung: 10deg; }
}

.ap-blende--klein { --ap-blende-groesse: 48px; }
.ap-blende--gross { --ap-blende-groesse: 200px; }

/* Die Blende als Fassung für einen Wert (05-health): der Text liegt IN der
   Tiefe, also über den Lamellen. */
.ap-blende__inhalt {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  color: var(--tinte-hell);
}

/* =========================================================================
   12 — Schaufenster-Zustände
   :active und :focus-visible lassen sich nicht fotografieren. Damit der
   Musterbogen sie trotzdem NEBENEINANDER zeigt, gibt es zu jedem Zustand eine
   Klasse, die exakt dieselben Regeln setzt. Sie gehören in die Bibliothek und
   nicht in den Musterbogen — zwei Definitionen desselben Zustands wären die
   zweite Liste, und dann driftet die eine von der anderen weg.
   ========================================================================= */
/* NACHGEZOGEN 01.08.2026, ABENDS — hier stand ein echter Fehler, und er ist
   genau der, vor dem der Kopf dieses Abschnitts warnt. `:active` tauscht
   Schatten UND Wölbung; die Schaufenster-Klassen tauschten nur den Schatten.
   Ein gedrückter Knopf hatte damit die Vertiefung in den Kanten und die
   Erhebung in der Fläche — zwei Lichtquellen an einem Bauteil. Aufgefallen
   ist es beim Nachmessen von `reise/02-hoert-zu.html`: dort steht der
   Sprechknopf auf `ist-gedrueckt`, und seine Fläche wurde nach oben links
   heller, während seine Kante dort dunkel war. */
.ap-knopf.ist-gedrueckt        { background-image: var(--woelbung-vertieft);
                                 box-shadow: var(--praegung-vertieft); transform: translateY(1px); }
.ap-knopf--haupt.ist-gedrueckt { background-image: var(--woelbung-vertieft);
                                 box-shadow: var(--praegung-vertieft-tief); transform: translateY(2px); }
.ap-zeile.ist-gedrueckt        { box-shadow: var(--praegung-vertieft); border-radius: 16px; }
.ap-sprechknopf.ist-gedrueckt,
.ap-profil.ist-gedrueckt       { background-image: var(--woelbung-vertieft);
                                 box-shadow: var(--praegung-vertieft); }
.zeigt-fokus                   { outline: 2px solid var(--tinte); outline-offset: 2px; }

/* =========================================================================
   13 — Bewegung ist optional, Lesbarkeit nicht
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  /* Der flache Punkt bewegt sich ohnehin nicht mehr; abzuschalten ist nur
     noch, was die Ausnahme `.ap-leuchtend` in Gang setzt. */
  .ap-leuchtend .ap-punkt--atmend,
  .ap-punkt--leuchtend.ap-punkt--atmend { animation: none; opacity: 1; box-shadow: var(--punkt-glanz); }
  /* Die Warnung verliert ihr Schlagen, aber NICHT ihre Grösse — die Grösse
     ist das eigentliche zweite Merkmal und darf nie wegfallen. */
  .ap-punkt--warnung { animation: none; opacity: 1; }
  .ap-leuchtend .ap-punkt--warnung,
  .ap-punkt--leuchtend.ap-punkt--warnung { animation: none; box-shadow: var(--punkt-glanz); }
  /* Derselbe Punkt, nur im Vektor. Der Vektor schaltet in seiner eigenen
     Datei den Dauerlauf der Lamellen ab; das Atmen wird hier gesetzt, also
     muss es auch hier abgeschaltet werden. */
  .ap-leuchtend .ap-blende-svg--atmet .ap-blende-svg__punkt { animation: none; }
  .ap-blende--laden {
    animation: none;
    --ap-oeffnung: 24px;
    --ap-drehung: -8deg;
  }
  .ap-knopf, .ap-sprechknopf { transition: none; }
}

/* Die Papiertextur als Regel statt als Variable — siehe die Falle oben.
   Wer eine Fläche mit echtem Papier belegen will, nimmt DIESE Klasse; sie
   funktioniert auch aus Unterordnern, weil der Pfad hier steht. */
.ap-papier {
  background-color: var(--papier);
  background-image: url("assets/papier.webp");
  background-size: var(--papier-kachel, cover);
  background-repeat: repeat;
}
.ap-papier--fein { background-image: url("assets/papier-fein.webp"); }
