/* ============================================================
   LIQUID GLASS — kanonische Quelle
   ============================================================
   Diese Datei ist das Original. Die drei Frontends tragen KOPIEN:

     Goose Agent/Frontend/src/liquid-glass.css
     Goose Agent/Database-Frontend/src/liquid-glass.css
     Website/Datei/liquid-glass.css

   Nicht in der Kopie arbeiten. Aenderungen hier, dann
   `DesignSystem/sync-liquid-glass.sh`. Das Skript bricht ab, wenn
   eine Kopie abgewichen ist — drei handgepflegte Kopien driften
   sonst still auseinander, dieselbe Lehre wie bei den drei
   Zugehoerigkeitslisten im Korpus.

   WAS DAS IST. Apples Materialsprache seit WWDC 2025 (iOS/macOS 26),
   nicht das Frosted Glass von 2013. Der Unterschied ist Lichtbrechung:
   ein Liquid-Glass-Element BRICHT den Hintergrund an seiner Kante wie
   eine Linse, statt ihn nur zu verwischen. `backdrop-filter: blur()`
   allein ist Milchglas und sieht flach aus.

   DREI SIGNATUREN, in dieser Datei umgesetzt:
     1 Lensing   — Kante bricht den Hintergrund (.lg)
     2 Flex      — Material gibt unter Druck nach (.lg-flex)
     3 Shrink    — Chrome zieht sich beim Scrollen zusammen (.lg-shrink)

   WAS NICHT GEHT. Apples Specular-Highlight folgt der Gerätelage
   (Gyroskop, Metal-Shader, jeder Frame neu). Im Browser gibt es
   dafuer keinen Weg ohne WebGL-Canvas hinter jeder Flaeche. Die
   Kante traegt hier stattdessen ein statisches Glanzlicht oben.
   Das ist bewusst eine Naeherung, keine vergessene Zeile.

   GRENZE. Glas traegt nur, was SCHWEBT: Navigation, Leisten,
   Popover, Sheets, Pillen. Inhaltsflaechen (Karten, Tabellen,
   Zitate) bleiben blickdicht und schattenlos — so steht es in
   Referenz/DESIGN.md, und zwei uebereinandergelegte lichte
   Glasflaechen sind unlesbar (apple-design-Skill Kapitel 12).
   ============================================================ */

:root {
  /* ---- refero „Apple iPhone Duo“: Geometrie ----------------------
     https://styles.refero.design/style/a73148b9-449b-42cd-9f38-86ef694f500e
     Basis 4px. Die Radien sind ROLLEN, keine Groessen: --r-card gilt
     fuer Karten und Bildflaechen, nicht fuer jeden Knopf. Eine
     Chat-Blase mit 28px Radius liest als Pille, nicht als Karte. */
  --lg-unit: 4px;
  --r-card: 28px;
  --r-nav: 20px;
  --r-pill: 36px;
  --r-link: 10px;
  --r-control: 9999px;
  --gap-element: 20px;
  --pad-card: 28px;
  --gap-section: 90px;

  /* ---- refero: Typo ---------------------------------------------
     Tracking ist GROESSENABHAENGIG, nie ein Wert fuer alle Groessen:
     grosse Schrift braucht negatives Tracking, kleine positives
     (apple-design-Skill Kapitel 15). Wer `letter-spacing` global
     setzt, hat es an einer der beiden Stellen falsch. */
  --t-hero-size: clamp(2.5rem, 6vw, 80px);
  --t-hero-lh: 1.05;
  --t-hero-track: -1.2px;
  --t-heading-size: clamp(1.75rem, 3.5vw, 40px);
  --t-heading-lh: 1;
  --t-heading-track: 0px;
  --t-kicker-track: 0.231px;
  --t-body-size: 17px;
  --t-body-lh: 1.47;
  --t-body-track: -0.374px;
  --t-compact-track: -0.12px;

  /* ---- Material --------------------------------------------------
     Zwei Varianten wie bei Apple: Regular ist der Normalfall und
     adaptiert; Clear ist durchsichtiger und DARF NUR ueber Medien
     stehen, weil Text darauf sonst reisst. */
  /* 0,72, nicht 0,62. Gemessen an der Navigationsleiste ueber allen
     fuenf Inhaltsseiten, alle 200px, drei Streifen je Stand: bei 0,62
     fiel goose.html an einer Stelle (y=2200) auf 4,43:1 fuer die
     Navigationslinks -- unter der Schwelle, auf genau EINEM Stand von
     ueber hundert. Glas wird ueber dunklem Inhalt dunkel, und die
     Leiste steht ueber allem. Mehr Deckkraft heisst weniger Durchsicht;
     das ist der Preis, und er ist nicht verhandelbar. */
  /* Die Deckung des Glases -- die EINE Stellgroesse, an der alles
     haengt. Sie steht als eigene Zahl da und nicht als fertiges
     rgba(), damit die Darstellungseinstellung sie zur Laufzeit
     umsetzen kann, ohne jede Flaeche einzeln anzufassen.
     0,5 statt 0,72: naeher an Apples Vorlage, wo das Glas den Grund
     deutlich durchlaesst und erst die Lichtkante den Koerper
     definiert. */
  --lg-deckung: 0.5;
  --lg-tint: rgba(255, 255, 255, var(--lg-deckung));
  /* Das duenne Glas behaelt sein Verhaeltnis zum dicken (0,28 zu
     0,72), damit der Regler beide zugleich mitnimmt. */
  --lg-tint-clear: rgba(255, 255, 255, calc(var(--lg-deckung) * 0.39));
  --lg-blur: 20px;
  --lg-saturate: 180%;
  /* Das Glanzlicht der Kante. Oben hell (Licht faellt von oben),
     unten ein schwacher Rueckwurf — das ist, was eine Glaskante von
     einem 1px-Rahmen unterscheidet. */
  /* Die Lichtkante haengt bewusst NICHT an --lg-deckung. Je duenner
     das Glas, desto mehr traegt sie allein den Koerper -- genau das
     macht Apples Vorlage: die Flaeche laesst den Grund durch, die
     Kante sagt, wo das Ding aufhoert. Zoege man sie mit herunter,
     loeste sich das Element bei niedriger Deckung ganz auf. */
  --lg-edge-top: rgba(255, 255, 255, 0.92);
  --lg-edge-bottom: rgba(255, 255, 255, 0.28);
  --lg-edge-line: rgba(255, 255, 255, 0.55);
  /* Koernung gegen Baenderung. Sehr schwache Verlaeufe -- und die
     Farbwolken im Grund sind mit 6 bis 8 Prozent Deckkraft genau das --
     zeigen in 8 Bit sichtbare Ringe: zwischen zwei benachbarten
     Farbwerten liegt schlicht keine Zwischenstufe. Ein feines Rauschen
     darueber verteilt den Sprung auf die Flaeche, statt ihn als Kante
     stehen zu lassen. Das ist derselbe Trick wie Dithering im Druck.

     Als gekachelte 140px-Fliese, nicht als fensterfuellendes Bild: so
     rastert der Browser sie einmal. Eingesetzt wird sie mit
     `background-blend-mode: overlay`. Nicht soft-light: das wirkt auf
     einer fast weissen Flaeche praktisch nicht, und genau dort standen
     die Ringe der Anmeldeseite nach dem ersten Versuch noch. */
  --lg-koernung: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22140%22%20height%3D%22140%22%3E%3Cfilter%20id%3D%22k%22%3E%3CfeTurbulence%20type%3D%22fractalNoise%22%20baseFrequency%3D%220.9%22%20numOctaves%3D%223%22%20stitchTiles%3D%22stitch%22%2F%3E%3CfeColorMatrix%20type%3D%22saturate%22%20values%3D%220%22%2F%3E%3CfeComponentTransfer%3E%3CfeFuncR%20type%3D%22linear%22%20slope%3D%220.14%22%20intercept%3D%220.43%22%2F%3E%3CfeFuncG%20type%3D%22linear%22%20slope%3D%220.14%22%20intercept%3D%220.43%22%2F%3E%3CfeFuncB%20type%3D%22linear%22%20slope%3D%220.14%22%20intercept%3D%220.43%22%2F%3E%3C%2FfeComponentTransfer%3E%3C%2Ffilter%3E%3Crect%20width%3D%22140%22%20height%3D%22140%22%20filter%3D%22url%28%23k%29%22%2F%3E%3C%2Fsvg%3E");
  --lg-shadow: 0 8px 28px rgba(0, 0, 0, 0.12);
  --lg-shadow-big: 0 20px 60px rgba(0, 0, 0, 0.16);

  /* ---- Bewegung --------------------------------------------------
     Springs, keine festen Dauern. CSS kann keine echten Springs, aber
     `linear()` bildet die Kurve ab. Zwei Kurven reichen:
       --ease-glass  kritisch gedaempft (Daempfungsgrad 1,0), Maximum
                     exakt 1,0 -- kein Ueberschwingen
       --ease-flex   Daempfungsgrad 0,69, Maximum 1,0527 -- 5,3 Prozent
                     Ueberschwingen, NUR wo eine Geste Schwung
                     mitgebracht hat
     Ueberschwingen auf einem Menue, das nur eingeblendet wurde, ist
     falsch; auf etwas, das man geworfen hat, richtig.

     BEIDE KURVEN WAREN FALSCH GESTUETZT. Bis 2026-09-22 trug
     --ease-glass Stuetzstellen bis 1,0678 -- also MEHR Ueberschwingen
     als --ease-flex mit 1,0479, bei der Beschriftung "kein
     Ueberschwingen". Aufgefallen ist es erst beim Messen MITTEN in
     der Bewegung: die Seitenleiste stand bei -277,2px, obwohl ihr
     Ziel -272px war, und die Ansicht daneben rutschte 5px zu weit
     nach links. Am Standbild davor und danach ist so etwas
     unsichtbar.

     Die Werte hier sind jetzt aus der Federgleichung gerechnet, nicht
     abgeschrieben:
       kritisch      x(t) = 1 - (1 + wt)·e^(-wt)
       unterdaempft  x(t) = 1 - e^(-zwt)·(cos(w_d·t) + (zw/w_d)·sin(w_d·t))
     mit w = 2p/0,4s (Apples "response" 0,4). Wer sie aendert, rechnet
     neu und prueft das Maximum. */
  --ease-glass: linear(
    0, 0.0252 3.8%, 0.0864 7.7%, 0.1668 11.5%, 0.2554 15.4%, 0.3451 19.2%,
    0.4312 23.1%, 0.5111 26.9%, 0.5836 30.8%, 0.6481 34.6%, 0.7047 38.5%,
    0.7539 42.3%, 0.7962 46.2%, 0.8323 50%, 0.863 53.8%, 0.8888 57.7%,
    0.9105 61.5%, 0.9287 65.4%, 0.9438 69.2%, 0.9563 73.1%, 0.9667 76.9%,
    0.9753 80.8%, 0.9823 84.6%, 0.9882 88.5%, 0.9929 92.3%, 0.9968 96.2%, 1
  );
  --ease-flex: linear(
    0, 0.0473 3.8%, 0.1611 7.7%, 0.3068 11.5%, 0.46 15.4%, 0.6045 19.2%,
    0.7307 23.1%, 0.8344 26.9%, 0.9147 30.8%, 0.9731 34.6%, 1.0127 38.5%,
    1.0368 42.3%, 1.049 46.2%, 1.0527 50%, 1.0506 53.8%, 1.045 57.7%,
    1.0378 61.5%, 1.0301 65.4%, 1.0229 69.2%, 1.0165 73.1%, 1.0112 76.9%,
    1.0071 80.8%, 1.0041 84.6%, 1.0021 88.5%, 1.0008 92.3%, 1.0002 96.2%, 1
  );
  --dur-glass: 400ms;
  --dur-press: 120ms;
}

@media (prefers-color-scheme: dark) {
  :root {
    --lg-deckung: 0.46;
    --lg-tint: rgba(40, 40, 42, var(--lg-deckung));
    --lg-tint-clear: rgba(20, 20, 22, calc(var(--lg-deckung) * 0.52));
    --lg-edge-top: rgba(255, 255, 255, 0.28);
    --lg-edge-bottom: rgba(255, 255, 255, 0.06);
    --lg-edge-line: rgba(255, 255, 255, 0.16);
    --lg-shadow: 0 8px 28px rgba(0, 0, 0, 0.5);
    --lg-shadow-big: 0 20px 60px rgba(0, 0, 0, 0.6);
  }
}

/* ============================================================
   1 · DAS MATERIAL
   ============================================================ */

.lg {
  position: relative;
  background: var(--lg-tint);
  -webkit-backdrop-filter: blur(var(--lg-blur)) saturate(var(--lg-saturate));
  backdrop-filter: blur(var(--lg-blur)) saturate(var(--lg-saturate));
  /* Kein `border`, sondern ein inset-Schatten: ein Rahmen sitzt AUF der
     Kante und schneidet sie ab, das Glanzlicht gehoert IN sie hinein. */
  box-shadow:
    inset 0 1px 0 var(--lg-edge-top),
    inset 0 -1px 0 var(--lg-edge-bottom),
    inset 0 0 0 1px var(--lg-edge-line),
    var(--lg-shadow);
  border-radius: var(--r-nav);
}

/* Grosse Flaechen lesen als dickeres Glas: staerkerer Blur, tieferer
   Schatten, staerkere Brechung (apple-design-Skill Kapitel 12). */
.lg-thick {
  --lg-blur: 32px;
  box-shadow:
    inset 0 1px 0 var(--lg-edge-top),
    inset 0 -1px 0 var(--lg-edge-bottom),
    inset 0 0 0 1px var(--lg-edge-line),
    var(--lg-shadow-big);
}

/* Clear: nur ueber Bild/Video, und nur MIT dem Verdunkler darunter.
   Ohne ihn faellt der Text durch — Apple hat in den 26er-Betas aus
   genau diesem Grund nachbessern muessen. */
.lg-clear {
  --lg-tint: var(--lg-tint-clear);
  --lg-blur: 12px;
}
.lg-clear::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(rgba(0, 0, 0, 0.28), rgba(0, 0, 0, 0.42));
  pointer-events: none;
  z-index: -1;
}

/* ---- Lensing ----------------------------------------------------
   Die eigentliche Lichtbrechung. `feDisplacementMap` verschiebt jeden
   Bildpunkt des Hintergrunds um den Betrag, den die Karte an dieser
   Stelle vorgibt: R steuert x, G steuert y, 128 heisst „nicht
   verschieben". Die Karte ist an den Raendern hell bzw. dunkel und in
   der Mitte neutral — also bricht nur die Kante, wie bei echtem Glas.

   Steht hinter @supports, weil `url()` in `backdrop-filter` nicht
   ueberall geht (Safari kann es nicht). Faellt es aus, bleibt die
   Flaeche Milchglas mit Glanzkante — schlechter, aber nicht kaputt.

   NACH url(#lg-lens) DARF NICHTS MEHR STEHEN. Chrome wendet die
   Filterfunktionen hinter einem SVG-Filter nicht mehr an, ohne das
   irgendwo zu melden. `url(#lg-lens) blur(20px)` sah aus wie beides
   und war weder noch: der Hintergrund blieb scharf lesbar, und die
   Flaeche verlor zugleich ihre Rundung. Der Weichzeichner sitzt
   deshalb IM Filter (feGaussianBlur vor feDisplacementMap, s.
   liquid-glass.js) -- und aus demselben Grund steuert --lg-blur nur
   noch den Fall OHNE Linse. saturate() bleibt hier stehen, weil es
   ohnehin nur den Fall ohne Linse betrifft. */
@supports (backdrop-filter: url(#lg-lens)) {
  .lg-lens {
    -webkit-backdrop-filter: url(#lg-lens) saturate(var(--lg-saturate));
    backdrop-filter: url(#lg-lens) saturate(var(--lg-saturate));
  }
  /* Fuer lange Kapseln -- Eingabefelder, Pillen-Knoepfe. Die Karte wird
     auf Elementgroesse gestreckt; eine quadratische Karte auf 14:1
     gezogen stauchte die Rundung zu einem Strich und liesse die
     Oberkante fast waagerecht brechen. Diese Karte ist 12:1 gerechnet.
     Ab etwa 4:1 lohnt der Wechsel, darunter genuegt .lg-lens. */
  .lg-lens-pille {
    -webkit-backdrop-filter: url(#lg-lens-pille) saturate(var(--lg-saturate));
    backdrop-filter: url(#lg-lens-pille) saturate(var(--lg-saturate));
  }
}

/* ============================================================
   2 · FLEX — das Material gibt unter Druck nach
   ============================================================
   Nicht `scale(0.97)`. Glas staucht sich, und es federt zurueck: das
   Zurueckfedern traegt --ease-flex, das Nachgeben nicht. Rueckmeldung
   kommt auf pointer-down, nie erst auf den Release (Kapitel 1). */
.lg-flex {
  transition:
    transform var(--dur-glass) var(--ease-flex),
    box-shadow var(--dur-glass) var(--ease-glass);
}
.lg-flex:active,
.lg-flex[data-pressed="true"] {
  transform: scale(0.965);
  transition-duration: var(--dur-press);
  transition-timing-function: ease-out;
}

/* ============================================================
   3 · SHRINK — Chrome zieht sich beim Scrollen zusammen
   ============================================================
   Die Leiste verschwindet nicht und faded nicht, sie ZIEHT SICH
   ZUSAMMEN und kommt beim Zurueckscrollen wieder heraus. Das Flag
   setzt der Scroll-Handler (liquid-glass.js). */
.lg-shrink {
  transition:
    padding var(--dur-glass) var(--ease-glass),
    transform var(--dur-glass) var(--ease-glass),
    border-radius var(--dur-glass) var(--ease-glass);
  transform-origin: top center;
}
[data-scrolled="true"] .lg-shrink,
.lg-shrink[data-scrolled="true"] {
  padding-block: calc(var(--lg-unit) * 1.5);
  border-radius: var(--r-pill);
}

/* ============================================================
   4 · MATERIALISIEREN statt einblenden
   ============================================================
   Eine Glasflaeche, die nur ihre Deckkraft hochzieht, liest wie ein
   Bild. Eine, die gleichzeitig Blur und Groesse aufzieht, liest wie
   Material, das ankommt. Der Ursprung ist der AUSLOESER, nicht die
   Mitte — sonst geht die raeumliche Beziehung zwischen Knopf und
   Inhalt verloren (Kapitel 7). transform-origin setzt der Aufrufer. */
@keyframes lg-materialize {
  from {
    opacity: 0;
    transform: scale(0.92);
    -webkit-backdrop-filter: blur(0) saturate(100%);
    backdrop-filter: blur(0) saturate(100%);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}
.lg-materialize {
  animation: lg-materialize var(--dur-glass) var(--ease-glass);
}

/* ============================================================
   5 · ZUGAENGLICHKEIT — nicht optional
   ============================================================ */

/* Blickdicht statt frostig. Glas ist hier ein Effekt, kein Traeger von
   Bedeutung: es faellt ersatzlos weg, ohne dass etwas fehlt. */
@media (prefers-reduced-transparency: reduce) {
  .lg,
  .lg-thick,
  .lg-clear {
    background: Canvas;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    box-shadow:
      inset 0 0 0 1px rgba(128, 128, 128, 0.4),
      var(--lg-shadow);
  }
  .lg-clear::before {
    display: none;
  }
}

/* Hoher Kontrast: definierte Kante statt Glanzlicht. */
@media (prefers-contrast: more) {
  .lg,
  .lg-thick,
  .lg-clear {
    background: Canvas;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    box-shadow: inset 0 0 0 2px CanvasText;
  }
}

/* Reduzierte Bewegung heisst nicht „keine Rueckmeldung", sondern eine
   Rueckmeldung ohne Ortswechsel: Ueberblendung statt Federn, und der
   Druck bleibt spuerbar — nur ohne Verformung (Kapitel 14). */
@media (prefers-reduced-motion: reduce) {
  .lg-flex,
  .lg-shrink {
    transition-duration: 1ms;
  }
  .lg-flex:active,
  .lg-flex[data-pressed="true"] {
    transform: none;
    filter: brightness(0.94);
  }
  .lg-materialize {
    animation: none;
  }
}

/* ---- Morphing ------------------------------------------------------
   Gegenstueck zu glasWechsel() in liquid-glass.js. Zwei Elemente
   tragen NACHEINANDER denselben Namen -- nie gleichzeitig, sonst
   verwirft der Browser den Uebergang stillschweigend. Also: der Knopf
   traegt .lg-morph, solange zu ist; die Flaeche traegt ihn, solange
   auf ist.

   Die Geometrie wandert auf der Federkurve ueber --dur-glass; der
   INHALT kreuzblendet in 140ms. Zwei verschiedene Dauern mit Absicht:
   ein hochskaliertes Symbol, das 400ms lang sichtbar bleibt, liest als
   Fehler. Frueh blenden, lang morphen -- dann liest es als Form, die
   sich oeffnet. */
/* Drei Steckplaetze, keine drei Bedeutungen. Ein Name darf im selben
   Augenblick nur an EINEM Element haengen -- sonst verwirft der Browser
   den Uebergang stillschweigend. Zwei Paare koennen aber gleichzeitig
   unterwegs sein (Menue schliesst sich, waehrend die Ansicht wechselt),
   und dann brauchen sie verschiedene Namen. Wer ein viertes Paar
   braucht, haengt hier einen Steckplatz an. */
.lg-morph {
  view-transition-name: lg-morph;
}
.lg-morph-b {
  view-transition-name: lg-morph-b;
}
.lg-morph-c {
  view-transition-name: lg-morph-c;
}
.lg-morph-d {
  view-transition-name: lg-morph-d;
}
::view-transition-group(lg-morph),
::view-transition-group(lg-morph-b),
::view-transition-group(lg-morph-c),
::view-transition-group(lg-morph-d) {
  animation-duration: var(--dur-glass);
  animation-timing-function: var(--ease-glass);
}
::view-transition-old(lg-morph),
::view-transition-new(lg-morph),
::view-transition-old(lg-morph-b),
::view-transition-new(lg-morph-b),
::view-transition-old(lg-morph-c),
::view-transition-new(lg-morph-c),
::view-transition-old(lg-morph-d),
::view-transition-new(lg-morph-d) {
  animation-duration: 140ms;
  /* Die Momentaufnahme in NATUERLICHER Groesse, oben links verankert.
     Die Vorgabe (`object-fit: contain` mit Zentrierung) zerrt das alte
     Bild auf die neue Kastengroesse und schneidet den Inhalt mittig an
     -- gemessen stand dann "ument anhaengen" da, das Wort begann
     ausserhalb. Verankert waechst der Kasten stattdessen ueber dem
     stehenden Inhalt auf, und der Text kommt hervor, statt zu wandern. */
  width: 100%;
  height: 100%;
  object-fit: none;
  object-position: top left;
  overflow: clip;
}

@media (prefers-reduced-motion: reduce) {
  /* glasWechsel() startet dann gar keinen Uebergang. Der Name bleibt
     trotzdem stehen, falls ihn ein anderer Weg ausloest. */
  ::view-transition-group(lg-morph),
  ::view-transition-group(lg-morph-b),
  ::view-transition-group(lg-morph-c),
  ::view-transition-group(lg-morph-d) {
    animation-duration: 1ms;
  }
}
