/* ════════════════════════════════════════════════════════════════════════
   sai-effects.css — Zustandsebene: Fokus, Markierung, Hover, Kontextmenue
   ────────────────────────────────────────────────────────────────────────
   EINE Ebene ueber den bestehenden Stilen. Sie erfindet KEINE Farbe: jeder
   Wert hier ist ein var() auf ein Token, das die jeweilige Flaeche schon
   definiert — `static/app/app.css` (--app-*) fuer die App-Schale,
   `static/css/sai-landing.css` (--gruen/--tinte/--linie/--papier) fuer die
   Startseite. Die Datei laeuft auf beiden, ohne dass eine der beiden ihre
   Tokens umbenennen muss.

   WARUM SIE UNTER /static/app/ LIEGT, obwohl sie auch die Startseite bedient:
   Das Auth-Gate in `web_ui.py` gibt anonym nur eine exakte Allowlist frei
   (`_PUBLIC_ASSET_EXACT`) plus die Praefixe `_PUBLIC_ASSET_PREFIXES`, und
   `/static/app/` ist einer dieser Praefixe. Eine Datei unter
   `/static/css/` waere ohne zusaetzlichen Eintrag in `web_ui.py` anonym 404
   — genau der Fehler, den `sai-landing.css` in ihrem Kopfkommentar
   dokumentiert. `web_ui.py` wird hier bewusst nicht angefasst.

   ZWEITONRING, UND ZWAR GEMESSEN, NICHT GERATEN:
   Es gibt in diesem Farbsystem KEINE einzelne Farbe, die auf allen zwoelf
   gemessenen Flaechen 3:1 erreicht (Beweis: tests/test_brand_contrast.py,
   Abschnitt "Fokusring"). Der bisherige Ring der App, `outline: 3px solid
   #d8a23c` in app.css, liegt auf weissem Grund bei 2.29:1 und verfehlt
   WCAG 2.2 SC 1.4.11 auf der eigenen Hauptflaeche.
   Deshalb hat der Ring hier zwei Toene: einen dunklen Kern, der auf allen
   hellen Flaechen traegt, und einen hellen Hof, der auf allen dunklen und
   auf den gruenen Knopfflaechen traegt. Auf jeder Flaeche erreicht
   mindestens einer der beiden >= 3:1, und Kern gegen Hof sind 10.35:1,
   der Ring ist also auch gegen sich selbst sichtbar.

   FOKUS NUR UEBER :focus-visible — nicht ueber :focus. Sonst leuchtet der
   Ring bei jedem Mausklick auf, und Nutzer lernen ihn zu ignorieren.
   ════════════════════════════════════════════════════════════════════════ */

:root {
  /* Kern des Fokusrings: dunkelgruen. App -> --app-green-dark, Startseite
     -> --gruen-tief. Die Kette greift, weil das jeweils andere Token auf
     der jeweiligen Seite schlicht nicht definiert ist. */
  --fx-ring:      var(--app-green-dark, var(--gruen-tief));
  /* Hof: die hellste Flaeche der Seite. Auf beiden Seiten Weiss. */
  --fx-ring-halo: var(--app-surface, var(--papier));
  /* Markenakzent fuer Markierung und Hover. */
  --fx-accent:    var(--app-green, var(--gruen));
  --fx-ink:       var(--app-ink, var(--tinte));
  --fx-line:      var(--app-line, var(--linie));

  /* Abgeleitete Toenungen. color-mix erzeugt keine neue Marke, es mischt
     das vorhandene Token mit Transparenz. */
  --fx-glow:      color-mix(in srgb, var(--fx-accent) 34%, transparent);
  --fx-wash:      color-mix(in srgb, var(--fx-accent) 8%, transparent);
  --fx-wash-firm: color-mix(in srgb, var(--fx-accent) 15%, transparent);
  --fx-edge:      color-mix(in srgb, var(--fx-accent) 42%, transparent);
  --fx-shade:     color-mix(in srgb, var(--fx-ink) 14%, transparent);
  --fx-shade-soft:color-mix(in srgb, var(--fx-ink) 8%, transparent);

  /* Geometrie. SC 2.4.13 verlangt eine Mindestflaeche; 3 px Ring mit 2 px
     Abstand liegt darueber und bleibt ruhig. */
  --fx-ring-w:   3px;
  --fx-ring-gap: 2px;
  --fx-halo-w:   7px;

  --fx-fast: 130ms;
  --fx-slow: 220ms;
  --fx-ease: cubic-bezier(.2, .7, .3, 1);
}

/* ── 1. Fokus: der Randglow ──────────────────────────────────────────────
   Reihenfolge im box-shadow ist Absicht: der Hof steht vorn und wird also
   ueber dem Schein gezeichnet; der Schein tritt erst ausserhalb des Hofs
   hervor. Der Hof fuellt zugleich den 2-px-Spalt zwischen Element und
   outline, der Kern liegt damit zwischen zwei hellen Flaechen.
   Die Elementliste steht ausgeschrieben (Spezifitaet 0,1,1) statt in
   :where() (0,1,0), damit die Regel unabhaengig von der Ladereihenfolge
   ueber der bestehenden :focus-visible-Regel in app.css liegt. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
details:focus-visible,
dialog:focus-visible,
[tabindex]:focus-visible,
[role="button"]:focus-visible,
[role="menuitem"]:focus-visible,
[contenteditable]:focus-visible,
:focus-visible {
  /* Einzeleigenschaften statt der Kurzform `outline:`. Eine Kurzform mit
     var() wird zu einem "pending substitution value": schlaegt EIN Teil fehl,
     faellt die GANZE Kurzform auf ihre Anfangswerte zurueck — und der
     Anfangswert von outline-style ist `none`, der Ring waere weg. Als
     Einzeleigenschaften kann jeder Teil unabhaengig scheitern, und
     outline-style: solid steht ohne var() da, kann also gar nicht scheitern. */
  outline-width: var(--fx-ring-w);
  outline-style: solid;
  outline-color: var(--fx-ring);
  outline-offset: var(--fx-ring-gap);
  box-shadow:
    0 0 0 var(--fx-halo-w) var(--fx-ring-halo),
    0 0 20px 3px var(--fx-glow);
}

/* Das Eingabefeld des Chats ist der wichtigste Tastaturhalt im Kundenpfad und
   braucht einen eigenen, spezifischeren Eintrag. GEMESSEN 2026-08-12:
   `app.css` setzt `.chat-composer textarea { outline: 0 }` mit Spezifitaet
   (0,1,1) — genau so spezifisch wie `textarea:focus-visible`. Bei Gleichstand
   entscheidet allein die Ladereihenfolge der Stylesheets, und das ist zu
   duenn fuer das Feld, in das der Kunde schreibt. (0,1,2) entscheidet es
   unabhaengig von der Reihenfolge. */
.chat-composer textarea:focus-visible,
.chat-composer input:focus-visible {
  outline-width: var(--fx-ring-w);
  outline-style: solid;
  outline-color: var(--fx-ring);
  outline-offset: var(--fx-ring-gap);
  box-shadow:
    0 0 0 var(--fx-halo-w) var(--fx-ring-halo),
    0 0 20px 3px var(--fx-glow);
}

/* Der Recherche-Schalter war beim Pixel-Abnahmetest 2026-08-12 der EINZIGE
   Tastaturhalt im Kundenpfad ohne wahrnehmbaren Ring. Gemessen, nicht
   hergeleitet: `app.css` setzt `.research-toggle input:focus-visible`
   (Spezifitaet 0,2,1) auf `rgba(14,107,67,.25)`. Das schlaegt
   `input:focus-visible` (0,1,1) aus dieser Ebene, und 25 % Deckkraft ergeben
   auf der weissen Karte gemalte 1,47:1 — unter der WCAG-2.2-Schwelle von
   3:1 (SC 1.4.11). Der weisse Hof half dort nicht, weil er auf Weiss liegt.
   Dieselbe Spezifitaet (0,2,1) plus spaetere Ladereihenfolge stellt den
   deckenden Ring wieder her, OHNE app.css anzufassen. */
.research-toggle input:focus-visible {
  outline-width: var(--fx-ring-w);
  outline-style: solid;
  outline-color: var(--fx-ring);
  outline-offset: var(--fx-ring-gap);
  box-shadow:
    0 0 0 var(--fx-halo-w) var(--fx-ring-halo),
    0 0 20px 3px var(--fx-glow);
}

/* Der Sprunglink ist der erste Tabstopp der Seite und darf nicht am
   Bildschirmrand abgeschnitten werden, wenn der Ring dazukommt. */
.skip-link:focus-visible,
.skip:focus-visible { outline-offset: var(--fx-ring-gap); }

/* Programmatischer Fokus auf Landmarken (`<main tabindex="-1">` nach dem
   Sprunglink) soll die Seite nicht einrahmen — dort genuegt der Sprung. */
main:focus-visible,
[role="log"]:focus-visible {
  outline-width: var(--fx-ring-w);
  outline-style: solid;
  outline-color: var(--fx-ring);
  /* Nach innen, damit der Ring einer randlosen Flaeche nicht aus dem
     Fensterausschnitt faellt. */
  outline-offset: calc(var(--fx-ring-gap) * -1 - var(--fx-ring-w));
  box-shadow: none;
}

/* Windows-Kontrastmodus setzt eigene Systemfarben. Dann weicht die Marke,
   sonst gewinnt sie gegen die Systemfarbe und der Ring verschwindet. */
@media (forced-colors: active) {
  a:focus-visible,
  button:focus-visible,
  input:focus-visible,
  select:focus-visible,
  textarea:focus-visible,
  summary:focus-visible,
  [tabindex]:focus-visible,
  :focus-visible {
    outline: 3px solid Highlight;
    outline-offset: 2px;
    box-shadow: none;
  }
}

/* ── 2. Markierung ───────────────────────────────────────────────────────
   Auswahlgrund = Markengruen, Auswahltext = Weiss. Gemessen 6.56:1 in der
   App (--app-green #0e6b43) und 5.32:1 auf der Startseite (--gruen
   #1f7a4d), beide ueber AA fuer Fliesstext. Der Grund hebt sich zugleich
   mit 6.56:1 bzw. 5.32:1 von der weissen Seite ab, die Markierung ist also
   auch als Flaeche erkennbar. */
::selection {
  background: var(--fx-accent);
  color: var(--fx-ring-halo);
  text-shadow: none;
}

/* Ein per Link angesprungener Abschnitt wird kurz markiert, damit klar ist,
   wo man gelandet ist. */
:target {
  scroll-margin-top: 84px;
}

/* Die vom Kontextmenue angefasste Nachricht bleibt sichtbar markiert,
   solange das Menue offen ist. Das ist der Tastatur-Ersatz fuer "worauf
   habe ich gerade rechtsgeklickt". */
[data-fx-marked] {
  position: relative;
  border-radius: 14px;
  background: var(--fx-wash);
  box-shadow: 0 0 0 2px var(--fx-edge);
}

/* ── 3. Ruhige Hover- und Aktiv-Zustaende ────────────────────────────────
   Regel: Hover bewegt hoechstens 1 px und aendert hoechstens eine Flaeche.
   Kein Skalieren, kein Farbwechsel der Schrift. */
.button,
.knopf,
.icon-button,
.composer-button,
.icon-label-button {
  transition:
    background-color var(--fx-fast) var(--fx-ease),
    border-color     var(--fx-fast) var(--fx-ease),
    box-shadow       var(--fx-fast) var(--fx-ease),
    transform        var(--fx-fast) var(--fx-ease);
}
.button:hover,
.knopf:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 16px var(--fx-shade);
}
.button:active,
.knopf:active,
.icon-button:active,
.composer-button:active {
  transform: translateY(0);
  box-shadow: none;
}
.icon-button:hover,
.composer-button:hover,
.icon-label-button:hover {
  background: var(--fx-wash-firm);
}

/* Karten und Listenzeilen: die Kante uebernimmt, nicht die Flaeche. */
.list-row,
.list-card,
.quick-card,
.menu-card,
.document-row,
.file-tile,
.account-card,
.passkey-row,
.result-artifact,
.feld,
.tarif {
  transition:
    background-color var(--fx-slow) var(--fx-ease),
    border-color     var(--fx-slow) var(--fx-ease),
    box-shadow       var(--fx-slow) var(--fx-ease);
}
.list-row:hover,
.list-card:hover,
.quick-card:hover,
.menu-card:hover,
.document-row:hover,
.file-tile:hover,
.account-card:hover,
.passkey-row:hover,
.result-artifact:hover,
.feld:hover,
.tarif:hover {
  border-color: var(--fx-edge);
  box-shadow: 0 10px 24px var(--fx-shade-soft);
}

/* Navigation: die aktive Seite behaelt ihre Markierung, Hover legt nur
   eine Waesche darunter. */
.app-nav a { transition: background-color var(--fx-fast) var(--fx-ease); }
.app-nav a:hover { background: var(--fx-wash); }
.kopf nav a { transition: color var(--fx-fast) var(--fx-ease); }

/* Aufklappbare Bloecke der Startseite. */
details summary { transition: color var(--fx-fast) var(--fx-ease); }
details:hover > summary { color: var(--fx-accent); }

/* ── 4. Kontextmenue (Rechtsklick) ───────────────────────────────────────
   PROGRESSIVE ERWEITERUNG. Ohne JavaScript existiert `.fx-menu` gar nicht
   im Dokument: das Element wird ausschliesslich von sai-effects.js erzeugt,
   die Vorlagen enthalten kein Menue-Markup. Ohne JS bleibt damit das
   Browser-Menue unveraendert, weil niemand preventDefault aufruft.
   Der Attributschalter `[data-fx-menu="ready"]` am <html> wird ebenfalls
   erst von JS gesetzt und ist die zweite Sperre. */
.fx-menu {
  position: fixed;
  z-index: 900;
  top: 0;
  left: 0;
  min-width: 208px;
  max-width: min(280px, calc(100vw - 24px));
  margin: 0;
  padding: 6px;
  transform: translate(var(--fx-menu-x, 0), var(--fx-menu-y, 0));
  border: 1px solid var(--fx-line);
  border-radius: 14px;
  background: var(--fx-ring-halo);
  box-shadow:
    0 18px 44px var(--fx-shade),
    0 0 0 1px var(--fx-shade-soft);
  list-style: none;
}
.fx-menu[hidden] { display: none; }
html:not([data-fx-menu="ready"]) .fx-menu { display: none; }

.fx-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 44px;      /* Zielgroesse, SC 2.5.8 */
  padding: 0 12px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--fx-ink);
  font: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}
.fx-menu-item:hover:not([disabled]) { background: var(--fx-wash-firm); }
.fx-menu-item[disabled] { opacity: .45; cursor: default; }
.fx-menu-hint {
  padding: 6px 12px 2px;
  color: var(--fx-ink);
  font-size: 11px;
  opacity: .6;
}

/* Die Chatflaeche bekommt einen Tabstopp und eine sichtbare Marke, damit
   das Menue auch ohne Maus erreichbar ist. */
[data-fx-menu="ready"] #chat-messages { scroll-margin-top: 12px; }

/* ── 5. Bewegung ist optional ────────────────────────────────────────────
   Wer Bewegung abbestellt hat, bekommt dieselben Zustaende ohne Uebergang
   und ohne Versatz. Der Fokusring bleibt vollstaendig erhalten — er ist
   keine Animation, sondern Information. */
@media (prefers-reduced-motion: reduce) {
  .button,
  .knopf,
  .icon-button,
  .composer-button,
  .icon-label-button,
  .list-row,
  .list-card,
  .quick-card,
  .menu-card,
  .document-row,
  .file-tile,
  .account-card,
  .passkey-row,
  .result-artifact,
  .feld,
  .tarif,
  .app-nav a,
  .kopf nav a,
  details summary {
    transition: none;
  }
  .button:hover,
  .knopf:hover,
  .button:active,
  .knopf:active {
    transform: none;
  }
  .fx-menu { box-shadow: 0 0 0 1px var(--fx-shade); }
}

/* Wer mehr Kontrast angefordert hat, bekommt einen breiteren Ring. */
@media (prefers-contrast: more) {
  :root {
    --fx-ring-w: 4px;
    --fx-halo-w: 8px;
  }
}
