/* ════════════════════════════════════════════════════════════════════════════════════════════
   MELOGNITE — GEMEINSAME BEDIEN- UND ZUGAENGLICHKEITSSCHICHT (CSS)   Stand 2026-07-30
   Eine Datei fuer ALLE Genre-Apps. Gegenstueck: /shared/melognite-ux.js
   Vorbild ist der bereits bestehende /shared/legal-footer.js — dasselbe Muster: eine zentrale
   Quelle statt fuenf handgepatchte Kopien. Damit gilt jede Verbesserung sofort in jedem Genre
   und auch im siebten, das es noch nicht gibt.

   ALLE Regeln sind ADDITIV und greifen nur dort, wo etwas fehlt. Kein Layout, keine Farbe, keine
   Klangeinstellung wird veraendert. Notausgang: ?ux=0 (siehe .js) entfernt die Klasse .mgn-ux
   vom <html>-Element, wodurch jede Regel hier wirkungslos wird.

   GEMESSENE BEFUNDE, die diese Datei behebt (a11y_probe.js gegen die LIVE-App /reggae/):
     · 23 von 71 klickbaren Elementen sind per Tastatur NICHT erreichbar — darunter die vier
       Stil-Reiter (div.tab.tab-roots/ska/dancehall/dub), also das wichtigste Kreativ-Bedienelement
       der Seite  → WCAG 2.2 / 2.1.1 Tastatur (Stufe A)
     · 23 Tippflaechen kleiner als 24x24 CSS-Pixel (z. B. 36x18, 34x19, 21px hohe Fusszeilen-Links)
       → WCAG 2.2 / 2.5.8 Zielgroesse Minimum (Stufe AA)
     · outline:none an mehreren Knoepfen, nur EINE :focus-visible-Regel im ganzen Dokument
       → WCAG 2.2 / 2.4.7 Fokus sichtbar (Stufe AA) und 2.4.13 Fokus-Erscheinungsbild
     · 2 endlos laufende Animationen, nur 2 Regeln fuer prefers-reduced-motion
       → WCAG 2.2 / 2.3.3 Animation aus Interaktionen
     · 0 Sprunglinks, 0 Live-Regionen (Zustandsaenderungen werden nicht angesagt)
   ════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── 1) SICHTBARER TASTATURFOKUS ─────────────────────────────────────────────────────────────
   Die Apps setzen an einigen Stellen `outline:none`, ohne einen Ersatz anzubieten. Wer mit der
   Tastatur bedient, sieht dann nicht, wo er ist. Zwei Ringe uebereinander (dunkel + hell) sind
   auf JEDEM Untergrund sichtbar — die Genre-Skins reichen von Beton-Anthrazit bis Pergament,
   eine einzelne Farbe kann das nicht leisten. :focus-visible trifft nur echte Tastaturnutzung,
   Mausklicks bleiben unveraendert. */
/* ⚠ 10.08.: `:focus-visible` mit Universalselektor trifft auch <body>. Der Splash wird beim
   Schliessen aus dem DOM ENTFERNT -- der Fokus faellt auf <body>, und der 3-px-Ring wurde zu
   einem gelben Rechteck um die ganze Seite; beim Scrollen lief dessen Unterkante als Balken
   durchs Bild (Eigentuemer-Screenshot). Ein Fokusring gehoert auf BEDIENELEMENTE, nie auf
   das Dokument -- er soll zeigen, WO man ist, und "ueberall" ist keine Antwort. */
html.mgn-ux :focus-visible:not(body):not(html) {
  outline: 3px solid #ffd23f !important;
  outline-offset: 2px !important;
  box-shadow: 0 0 0 6px rgba(0, 0, 0, .55) !important;
  border-radius: 4px;
}
/* Elemente, die den Ring per outline:none unterdruecken, bekommen ihn trotzdem. */
html.mgn-ux button:focus-visible,
html.mgn-ux [role="button"]:focus-visible,
html.mgn-ux [role="tab"]:focus-visible,
html.mgn-ux a:focus-visible,
html.mgn-ux input:focus-visible,
html.mgn-ux select:focus-visible,
html.mgn-ux [tabindex]:focus-visible {
  outline-style: solid !important;
}

/* ── 2) DOPPELTIPP-ZOOM GEZIELT UNTERBINDEN ──────────────────────────────────────────────────
   Der Kopfbereich sperrte bisher JEDES Zoomen (`user-scalable=no`) — ein Verstoss gegen 1.4.4,
   der Sehbehinderten das Aufziehen verwehrt. Nach dem Entsperren darf ein schnelles Doppeltippen
   auf Transport-Knoepfe (Play/Stop/Forge) aber nicht mehr die Seite zoomen. `touch-action:
   manipulation` erlaubt weiterhin das Kneifen-Zoomen der SEITE und nimmt nur dem EINZELNEN
   Bedienelement die Doppeltipp-Geste. Genau das gewuenschte Verhalten. */
html.mgn-ux button,
html.mgn-ux [role="button"],
html.mgn-ux [role="tab"],
html.mgn-ux .tab,
html.mgn-ux input[type="range"],
html.mgn-ux .knob,
html.mgn-ux .seg,
html.mgn-ux .obtn {
  touch-action: manipulation;
}

/* ── 3) TIPPFLAECHEN VERGROESSERN, OHNE DAS LAYOUT ANZUFASSEN ────────────────────────────────
   Gemessen: 23 Bedienelemente unter 24x24 px. Groesser machen wuerde jedes Genre-Layout
   verschieben (die Apps sind handgesetzt). Stattdessen ein unsichtbares Pseudo-Element, das die
   TREFFERFLAECHE auf mindestens 24x24 aufzieht: es liegt ausserhalb des Textflusses, veraendert
   also keine Position und keine Groesse — nur die Flaeche, die der Finger treffen darf.
   (Vorgehen nach WCAG-2.2-Technik "Zielgroesse durch Abstand/erweiterte Trefferflaeche".) */
/* ⚠ NICHT auf schwachen Geraeten (html.fxlite): rund 35 zusaetzliche Pseudo-Elemente mit eigenem
   Positionierungskontext sind zwar unsichtbar, kosten den Compositor beim Scrollen aber Arbeit —
   und auf dem 2-Kern-Zielgeraet streitet der Compositor mit dem Audio-Dienst um dieselben Kerne.
   Der Nutzen (groessere Trefferflaechen) betrifft vor allem Fingerbedienung; die schwache
   Geraeteklasse hier ist ein Laptop mit Maus, das Telefon (9 Threads) bekommt die Erweiterung.
   Sauberer Handel: Zugaenglichkeit dort, wo Rechenleistung uebrig ist — Ton zuerst, wo sie fehlt. */
html.mgn-ux:not(.fxlite) .mgn-hit {
  position: relative;
}
html.mgn-ux:not(.fxlite) .mgn-hit::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: max(100%, 24px);
  height: max(100%, 24px);
  transform: translate(-50%, -50%);
  /* nur Trefferflaeche — unsichtbar und ohne eigene Wirkung */
}

/* ── 4) BEWEGUNG RESPEKTIEREN ────────────────────────────────────────────────────────────────
   Es laufen Endlos-Animationen (Puls, Funkeln, Leuchtlauf). Wer im Betriebssystem "Bewegung
   reduzieren" gewaehlt hat, tut das oft wegen Schwindel oder Migraene — dann muss das Produkt
   still sein. Zusaetzlicher Nebeneffekt auf dem Zielgeraet: dauerhaft laufende Animationen
   kosten den Compositor Arbeit, der sich dort mit dem Audio-Dienst zwei Kerne teilt. */
@media (prefers-reduced-motion: reduce) {
  html.mgn-ux *,
  html.mgn-ux *::before,
  html.mgn-ux *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── 4b) DER INTRO-LICHTSWEEP DARF NICHT REPAINTEN ──────────────────────────────────────────
   BEFUND (Audit + selbst nachgeprueft, in ALLEN fuenf Apps identisch):
     .tabs.sweep::before  —  volle Breite ueber die Stil-Reiter, mix-blend-mode:overlay,
     animation: tabsweep 1.7s ease-in-out 2  →  3,4 Sekunden lang, und die Animation bewegt
     `background-position`. Das ist die eine Eigenschaft, die der Compositor NICHT uebernehmen
     kann: jeder Frame ist ein echtes Neuzeichnen der Reiterleiste, zusaetzlich mit
     Mischmodus. Ausgeloest wird sie 420 ms nach dem Start — also genau, waehrend die letzten
     Samples dekodieren und der Nutzer nach Play greift.
   Es ist dieselbe Wirkungsklasse, die t031b als Ursache des Scroll-Ruckelns nachgewiesen hat
   (background-attachment/Mischmodus/Vollbild-Filter) — sie hat den Fix nur ueberlebt, weil sie
   an einem anderen Element haengt.

   BEHANDLUNG: Der Effekt wird dort abgeschaltet, wo er schadet — und bleibt dort unangetastet,
   wo Rechenleistung uebrig ist (dieselbe Linie wie t031d: volle Optik auf starken Geraeten,
   sparsam auf schwachen). Auf der Maschine, auf der die Wiedergabe ohnehin am Limit laeuft, ist
   ein 3,4-Sekunden-Zierlauf im Moment des Startens nicht vertretbar; dort zaehlt der erste Ton.

   VERWORFENER VERSUCH (gemessen, nicht ausgeliefert): dieselbe Bewegung ueber
   `transform:translateX()` statt `background-position`, um sie compositor-faehig und damit auf
   ALLEN Geraeten billig zu machen. Die Umrechnung der Wegstrecke war richtig (−2,45 bis +1,05
   Elementbreiten), die Laufrichtung nach einer Korrektur ebenfalls — aber die Optik blieb
   abweichend (Bildvergleich am festgehaltenen Animationszeitpunkt: SSIM 0,74 statt ~1,0).
   URSACHE: Die Vorlage ist genau so breit wie die Reiterleiste und BESCHNEIDET den 240 % breiten
   Farbverlauf. Die transform-Fassung muss das Element selbst auf 240 % aufziehen, wodurch der
   Verlauf unbeschnitten erscheint und ueber die Leiste hinausragt. Gleiche Optik waere nur mit
   einem zusaetzlichen Element (Beschneidungsrahmen) zu erreichen — ein Eingriff in die
   Genre-Struktur, der fuer einen Zierlauf auf leistungsfaehiger Hardware nicht zu rechtfertigen
   ist. MERKSATZ: background-position laesst sich nur dann in transform uebersetzen, wenn das
   Element den Verlauf NICHT beschneidet. */
/* ⭐ 10.08. — EIGENTUEMER-ENTSCHEIDUNG: der Effekt kommt zurueck, auch auf schwachen
   Geraeten. Vorgelegt wurde die Messung oben samt Empfehlung, ihn ausgeschaltet zu
   lassen; der Eigentuemer hat anders entschieden und zugleich die Laufzeit HALBIERT
   (einmalig statt zweimal, 1,7 s statt 3,4 s) -- damit sinkt genau die Belastung, um
   die es in der Notiz ging. Die Sperre ist deshalb aufgehoben.
   ⚠ Sie allein aufzuheben genuegt NICHT: die calm/flat-Regel in melognite-profile.css
     killt zusaetzlich jede Animation auf *::before. Beide Stellen gehoeren zusammen. */
/* (aufgehoben 10.08.) html.fxlite .tabs.sweep::before { display: none !important; } */

/* ── 4c) WAEHREND DES ZOOMENS: SPARSAME OPTIK ────────────────────────────────────────────────
   USER-BEFUND 2026-07-30: Seit die Zoom-Sperre entfernt ist (WCAG 1.4.4), erzeugt das Aufziehen
   leichte Glitches — beim Kneifen-Zoom rastert der Browser die Seite neu, und die teuren
   Zierschichten (Mischmodi, Vollbild-Verlaeufe, fixierte Hintergruende) muessen dabei jedes Mal
   mitgerechnet werden. Zoom bleibt erlaubt; solange gezoomt ist, greift dieselbe Sparfassung wie
   auf schwachen Geraeten. Das JS setzt .mgn-zoom, wenn visualViewport.scale > 1,05. */
html.mgn-zoom body { background-attachment: scroll !important; }
html.mgn-zoom body::before { filter: none !important; }
html.mgn-zoom body::before,
html.mgn-zoom body::after { mix-blend-mode: normal !important; }
html.mgn-zoom .tabs.sweep::before { display: none !important; }

/* ── 5) SPRUNGLINK ───────────────────────────────────────────────────────────────────────────
   Ohne ihn muss man sich mit der Tastatur bei JEDEM Aufruf durch Splash, Kopfzeile und
   Fusszeilen-Links tabben, bevor das Instrument erreichbar ist (gemessen: 19 Stationen bis zum
   Forge-Knopf, 20 bis Play). Der Link ist unsichtbar, bis er den Fokus erhaelt. */
html.mgn-ux .mgn-skip {
  position: fixed;
  left: 8px;
  top: -100px;
  z-index: 100000;
  padding: 10px 16px;
  background: #ffd23f;
  color: #1a1510;
  font: 600 14px/1.2 system-ui, sans-serif;
  border-radius: 0 0 8px 8px;
  text-decoration: none;
  transition: top .12s ease;
}
html.mgn-ux .mgn-skip:focus {
  top: 0;
}

/* ── 6) DIALOG-ABDUNKELUNG FUER OVERLAYS ─────────────────────────────────────────────────────
   Der Splash traegt weder role="dialog" noch einen Namen; der Tastaturfokus lief nach drei
   Stationen HINTER das Overlay in die verdeckte Seite. Das .js ergaenzt Rolle, Name und
   Fokusfalle; hier nur die Zusicherung, dass der als modal markierte Bereich auch optisch
   ueber allem liegt. */
html.mgn-ux [data-mgn-modal="1"] {
  z-index: 99990;
}

/* ── 8) HINHALTEBANNER VOR DEM ERSTEN TON ────────────────────────────────────────────────────
   Nach dem Play-Klick vergehen bis zu acht Sekunden, in denen NICHTS zu sehen ist: erst laedt die
   App Samples, danach wartet `RSF_AUDIO.play()` darauf, dass die Kontext-Uhr einschwingt (die
   Schranke steigt erst aus, wenn die Abweichung zur Wanduhr unter 50 ms faellt). Der Lade-Spinner
   am Knopf wird eine Zeile VOR dieser zweiten Wartestrecke abgeschaltet — und in reggae,
   reggae-ux und techno-var ist er ohnehin tot, weil die Foto-Knopf-Regel
   `#play .ic{display:none !important}` die Spinner-Regel in der Kaskade schlaegt.

   ⚠⚠ DIESE FLAECHE DARF NICHTS KOSTEN. Das Ausstiegskriterium der Wartestrecke ist eine
   Driftmessung in 150-ms-Fenstern, auf denselben zwei Kernen, auf denen der Compositor mit dem
   Audio-Dienst konkurriert. t031b hat nachgewiesen, dass Mischmodi, Vollbild-Verlaeufe und
   fixierte Hintergruende hier den Ton stehlen. Ein animierter Banner koennte die Drift ueber der
   Schwelle halten und die Wartezeit damit SELBST auf die vollen acht Sekunden treiben.
   Erlaubt ist deshalb ausschliesslich ein einmaliges opacity-Einblenden (reine Compositor-Arbeit,
   kein Neuzeichnen). Kein backdrop-filter, kein mix-blend-mode, kein box-shadow-Puls
   (die vorhandene `rsfpulse`-Animation animiert box-shadow = Paint und kommt hier NICHT infrage).

   Skin-frei: die fuenf Genre-Oberflaechen reichen von Beton-Anthrazit bis Pergament, deshalb
   werden Hintergrund, Textfarbe, Schrift und Rahmen ausdruecklich gesetzt statt geerbt.
   `pointer-events:none` — die Flaeche informiert und darf niemals einen Klick abfangen.
   Position oben mittig: unten links sitzt in drei Apps die gruene Diagnoseleiste, unten rechts
   die Build-Plakette; der Sprunglink liegt mit 100000 darueber. */
/* RUECKFALL-STELLUNG, wenn kein Graph da ist (z. B. Startseite): oben mittig am Bildschirm.
   Die Regel fuer die Grundstellung ueber dem Graphen steht ABSICHTLICH danach — beide haben
   dieselbe Gewichtung, es gewinnt die spaetere. */
html.mgn-ux .mgn-wait {
  position: fixed;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 99500;
  max-width: min(92vw, 420px);
  padding: 10px 16px;
  border-radius: 10px;
  border: 1px solid rgba(255, 210, 63, .45);
  background: #16130f;
  color: #f3ede1;
  font-family: system-ui, -apple-system, sans-serif;
  text-align: center;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  /* ABSICHT, nicht Versehen: nur `opacity` wird ueberblendet, `visibility` nicht. Der Banner
     blendet also EIN und faellt beim Ausblenden hart weg. Das ist gewollt — das Ausblenden
     faellt mit dem ersten Ton zusammen, und genau dort soll keine einzige Zeichenarbeit mehr
     anfallen. Wer hier eine zweite Transition „nachruestet", macht es schlechter. */
  transition: opacity .15s linear;
}
html.mgn-ux .mgn-wait.on {
  opacity: 1;
  visibility: visible;
}
html.mgn-ux .mgn-wait b {
  display: block;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.25;
  color: #ffd23f;
}
html.mgn-ux .mgn-wait span {
  display: block;
  margin-top: 3px;
  font-size: 11.5px;
  line-height: 1.35;
  color: #cfc7b8;
}

/* GRUNDSTELLUNG: ueber dem Graphen (Wunsch des Eigentuemers 2026-07-31). `.scopewrap` traegt in
   allen fuenf Genres wortgleich `position:relative;display:block` und beherbergt bereits den
   Fortschritts-Cursor — die Flaeche legt sich also ohne Messung und ohne Aenderung am Wirt
   darueber. Der Graph ist genau die Stelle, auf die der Nutzer nach dem Play-Klick ohnehin
   schaut, und die Kontur dahinter ist waehrend der Wartezeit noch die des VORIGEN Songs.
   Muss NACH der Rueckfall-Regel stehen (gleiche Gewichtung, die spaetere gewinnt). */
html.mgn-ux .mgn-wait-graph {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 40;               /* ueber der Kontur, unter dem Splash */
  /* FESTE Breite statt max-width: ein absolut positioniertes Element ohne Breitenangabe
     schrumpft auf den Inhalt, und die Ueberschrift brach dadurch mitten in der Wendung um
     („Building your / song…"). Mit einer berechenbaren Breite steht sie in einer Zeile. */
  width: min(92%, 320px);
}

/* ── 9) EREIGNIS-MITSCHRIFT (?evlog=1) ───────────────────────────────────────────────────────
   Diagnosewerkzeug fuer das echte Geraet: zeigt, welche Ereignisse beim Herunterziehen der
   Benachrichtigungsleiste tatsaechlich feuern. Ohne den Parameter wird sie nie erzeugt.
   Bewusst unten links, weil dort in drei Apps ohnehin schon die Diagnoseleiste sitzt. */
html.mgn-ux .mgn-evlog {
  position: fixed;
  left: 4px;
  bottom: 4px;
  z-index: 99400;
  max-width: 96vw;
  max-height: 46vh;
  overflow: auto;
  padding: 6px 8px;
  border-radius: 6px;
  background: rgba(8, 8, 8, .92);
  color: #9ef39e;
  font: 11px/1.35 ui-monospace, monospace;
  white-space: pre;
  pointer-events: none;
}

/* ── 7) LIVE-REGION ─────────────────────────────────────────────────────────────────────────
   Zustandsaenderungen (Wiedergabe, neuer Song, gesperrte Funktion) wurden bisher NICHT
   angesagt — gemessen: 0 Live-Regionen. Die Region traegt Text nur fuer Hilfsmittel; sie darf
   nicht per display:none verborgen werden, sonst lesen Screenreader sie nicht. */
html.mgn-ux .mgn-live {
  position: absolute !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
  margin: -1px;
  padding: 0;
}
