/* GRID.Whisper – Rollen, Rahmen und die geteilten Bauteile.
   Wird von BEIDEN Seiten geladen: Startseite (landing.css) und App (styles.css).

   ============================================================================
   TOMORIS.Design 3.0.0 – DAS PAKET FUEHRT, DIESE DATEI ZIEHT NACH
   ============================================================================
   Bis zur Fundament-Etappe galt "optisch aendert sich nichts", und diese Datei
   trug ihre 14 Farbwerte selbst. Das ist vorbei. Ab 3.0.0 stehen hier keine
   Farbwerte mehr, sondern Zuordnungen: eine Rolle dieses Produkts auf eine Rolle
   des Pakets. Wer einen Ton aendern will, aendert ihn im Paket.

   WARUM ES ERST JETZT GEHT. Bis 2.0.0 verteilte das Paket seine Palette
   ausschliesslich ueber [data-theme]. Whisper setzt dieses Attribut wegen der
   strengen CSP (script-src 'self', kein Inline-Schnipsel im <head>) erst in
   js/theme.js, also nach dem ersten Bild. GEMESSEN am 04.08.2026 mit
   abgeschaltetem JavaScript: zog man die 14 Werte ans Paket, loeste --grund NICHT
   MEHR AUF, der Koerper fiel auf rgba(0,0,0,0) und die Seite verlor ihren Grund.
   3.0.0 traegt den Rueckfall ueber prefers-color-scheme – dieselbe Bauform, die
   diese Datei zuvor selbst fuehrte. Damit ist der einzige offene Kern aus
   docs/token-luecken.md geschlossen.

   UND DER TEIL, DEN MAN NICHT UEBERSEHEN DARF: die acht Vergleichsbilder jener
   Probe waren BYTEWEISE IDENTISCH. Mit JavaScript an setzte theme.js das Attribut,
   die Variablen loesten auf, die Werte waren dieselben. Ein reiner Bildvergleich
   haette die kaputte Fassung durchgewunken. Deshalb misst der Abnahmelauf dieser
   Etappe weiterhin den ERSTEN Frame ohne JavaScript mit.

   KEIN ERSATZWERT, an keiner Stelle. Kommt das Paket nicht an, hat die Seite
   keinen Grund, keinen Text und keine Kanten – sichtbar, nicht still. Ein zweiter
   Farbsatz hier waere eine zweite Wahrheit, die beim naechsten Paketsprung
   lautlos veraltet. Gedeckt ist der Fall an drei Stellen, die alle hart
   abbrechen: der Bau-Riegel in der csproj, der Rauchtest mit --erwarte-tokens
   und pruefe/kontrast.mjs.

   NUR DIE TOKENSCHICHT. 3.0.0 liefert drei Dateien; die beiden freiwilligen
   (tomoris-base.css und tomoris-components.css) sind bewusst NICHT eingebunden
   und kommen auch nicht ins Bauergebnis. Ihre Regeln liegen samt und sonders in
   @layer, diese Datei liegt in keiner – und eine ungelayerte Regel schlaegt jede
   Layer-Regel, unabhaengig von der Spezifitaet. Sie waeren also wirkungslos.
   Tabelle Regel fuer Regel in docs/token-luecken.md, Abschnitt 4.

   ============================================================================
   VIER REGELN, die diese Datei traegt
   ============================================================================
   1. DAS EINGABEFELD IST DER HELD. Es steht ganz oben, ohne Vorspann.

   2. DIE FARBE ERKLAERT DAS PRODUKT. Es gibt genau ZWEI Bedeutungsfarben:
        --aktion / --blau-text       BLAU   = verlaesst den Browser, geht an unseren Server
        --schluessel / --orange-text ORANGE = bleibt bei dir, verlaesst den Browser nie
      Das gilt ausnahmslos. Ein oranges Element, das nichts mit dem Schluessel zu tun
      hat, ist ein Fehler. Damit erklaert sich Zero-Knowledge ohne einen Werbesatz.
      FOLGE FUER DIE WERKBANK: ihre Kante ist NEUTRAL (--werkbank-kante) und nicht
      blau. Ein blauer Rahmen um das ganze Werkzeug waere eine Aussage ueber den
      Schluessel – und zwar eine falsche.
      Die Zustandsfarben (in Ordnung, Aufmerksamkeit, kritisch …) sind KEINE dritte
      Bedeutungsfarbe: sie stehen ausschliesslich in der Zustandsmarke und nirgends
      sonst, und sie sagen etwas ueber die Lage und nichts ueber den Weg der Daten.

   3. LINIEN STATT KAESTEN – MIT GENAU ZWEI AUSNAHMEN, und beide sind Auftrag.
      Trennung laeuft weiter ueber 1px-Linien und 2px-Seitenakzente, Rundung an einer
      bedeutungstragenden Akzentkante bleibt 0. Kasten ist die WERKBANK (hier ist das
      Werkzeug) und die BELEGSPALTE (hier steht, was die Zusage traegt).

   4. MONOSPACE NUR FUER TECHNIK: Link, Kennzeichnungen, Merkmalzeilen, Restzeit,
      der Secret-Inhalt selbst. NIEMALS mit negativer Laufweite – eine
      Festbreitenschrift ist auf ihren festen Vorschub gezeichnet, negatives
      letter-spacing drueckt die Zeichen ineinander.

   ============================================================================
   BEWEGUNG – sparsam, ueberall gleich, und ueberall abschaltbar
   ============================================================================
   Zwei Taktzeiten, beide aus dem Paket: --tm-dur-fast (160ms) fuer alles, was auf
   einen Zeigerwechsel antwortet, --tm-dur-slow (320ms) fuer den Aufbau einer
   Flaeche. Dazwischen gibt es nichts. Hover hebt um genau 1px – an jedem Element,
   das sich heben darf, mit demselben Wert.

   EINE EINZIGE DAUERSCHLEIFE: der Statuspunkt der Zustandsmarke "laedt". Alles
   andere laeuft einmal und hoert auf. Der Hauptknopf bekommt beim Erscheinen genau
   einen Glanz, nicht wiederkehrend.

   prefers-reduced-motion schaltet Ueberblendungen, Bewegungen und Schleifen ab –
   Deckkraftwechsel bleiben, weil sie den Aufbau lesbar halten, ohne etwas zu
   bewegen.

   ============================================================================
   KONTRAST – gerechnet, nicht geschaetzt (WCAG 2.1)
   ============================================================================
   Die Zahlen stehen nicht in dieser Datei. Sie koennen es seit 3.0.0 auch gar
   nicht mehr: hier steht keine Farbe, nur eine Zuordnung.

   Gerechnet wird in pruefe/kontrast.mjs, und zwar aus BEIDEN Quellen zusammen –
   der Zuordnung aus dieser Datei und den Werten aus dem ausgelieferten Paket.
   Deshalb laeuft das Skript gegen das Bauergebnis und nicht gegen frontend/,
   genau wie der zweite Rauchtest. tests/kontrast.test.js bleibt daneben stehen
   und prueft, was ohne Paket pruefbar ist: dass jede Rolle eine Zuordnung hat und
   dass ausser den vier begruendeten Ausnahmen kein Hexwert in dieser Datei steht.

   DREI UNTERGRUENDE, nicht zwei: Grundflaeche, WERKBANK und Feldflaeche. Die
   Werkbank ist beim Nachrechnen der teuerste Fall – sie liegt zwischen den beiden
   anderen, und ein Ton, der auf Grund und Feld reicht, kann auf ihr durchfallen.
   Seit dieser Etappe kommt die BUEHNE als vierter dazu.

   KNOPFFUELLUNG UND TEXTAKZENT SIND ZWEI VERSCHIEDENE ROLLEN. Das ist keine
   Feinheit, sondern ein Fehler, der in diesem Produkt schon zweimal dastand: eine
   zur Lesbarkeit aufgehellte Akzentfarbe ergibt als Fuellung weisse Schrift auf
   Hellblau, gemessen 2.16:1. Deshalb:
     --aktion    = FLAECHE, auf der --aktion-schrift steht
     --blau-text = alles, was AUF einer Flaeche liegt: Schrift UND Akzentkanten
   Das Paket fuehrt beide getrennt (--tm-accent und --tm-accent-text) und deckt die
   Trennung mit einer eigenen Negativkontrolle in tests/kontrast.test.js.

   HELL UND DUNKEL kommen aus dem Paket und sind dort gleichwertig ausgeschrieben.
   Die Voreinstellung folgt dem System; der Umschalter setzt data-theme auf <html>
   und merkt sich die Wahl. Ein festes data-theme steht NICHT im Dokument – siehe
   MINT-3166.

   Bekannte Einschraenkung, bewusst so: die CSP verbietet Inline-JavaScript.
   Die gespeicherte Wahl greift deshalb erst nach dem Laden von /js/theme.js – wer
   die Systemvorgabe ueberstimmt hat, sieht beim ersten Bild einen kurzen Umschlag.
   Bei einem Zero-Knowledge-Produkt ist die strenge CSP mehr wert als ein
   Aufblitzen. Das ist kein offener Punkt. */

/* ==========================================================================
   DIE ZUORDNUNG. Links die Rolle dieses Produkts, rechts die Rolle des Pakets.

   FORMAT NICHT VERAENDERN: tests/kontrast.test.js und pruefe/kontrast.mjs lesen
   genau diesen Block und erwarten je Zeile "  --name: var(--tm-name);". Wer hier
   einen Hexwert eintraegt, faellt aus der Pruefung heraus – und zwar NICHT still:
   der Test besteht auf einer Mindestzahl gelesener Zuordnungen und verbietet
   Hexwerte ausserhalb der vier begruendeten Ausnahmen.
   ========================================================================== */

:root {
  /* --- Flaechen, von aussen nach innen ---------------------------------- */
  --grund: var(--tm-bg);
  --werkbank: var(--tm-surface);
  --feld: var(--tm-field);
  /* Die Belegspalten liegen auf DERSELBEN Flaeche wie die Werkbank, und das ist
     gemessen und nicht bequem: auf --tm-surface-3 faellt die Kennzeichnung im
     Dunkelmodus auf 4.21:1 und damit unter AA (--tm-text-4 #8b98b4 auf #2a3550,
     gerechnet am 04.08.2026). Auf --tm-surface sind es 4.96:1. Unterschieden
     werden Werkbank und Beleg deshalb ueber Kante und Tiefe: die Werkbank traegt
     --werkbank-kante und den vollen Schatten, der Beleg eine Haarlinie und den
     flachen. */
  --beleg: var(--tm-surface);

  /* --- Kanten ------------------------------------------------------------ */
  --linie: var(--tm-border);
  --feldrand: var(--tm-border-strong);
  --werkbank-kante: var(--tm-border-elevated);

  /* --- Blau: verlaesst den Browser --------------------------------------- */
  --aktion: var(--tm-accent);
  --aktion-tief: var(--tm-accent-hover);
  --aktion-schrift: var(--tm-accent-ink);
  --aktion-hauch: var(--tm-accent-soft);
  --blau-text: var(--tm-accent-text);

  /* --- Orange: bleibt beim Nutzer ---------------------------------------- */
  --schluessel: var(--tm-accent-2);
  --schluessel-schrift: var(--tm-accent-2-ink);
  --orange-text: var(--tm-accent-2-text);

  /* --- Vier Textstufen ---------------------------------------------------
     ACHTUNG BEIM HELLMODUS: --tm-text-3 und --tm-text-4 tragen dort denselben
     Wert. "Dimmer" heisst im Hellen heller, und die dritte Stufe sitzt bereits
     auf der AA-Grenze; eine vierte Farbstufe waere unter 4.5:1 gefallen. Wer
     hier eine weitere Abstufung braucht, nimmt GROESSE oder GEWICHT, nicht
     Farbe – .klein und .kennz machen genau das. Im Dunkelmodus sind es vier
     echte Stufen. */
  --ueberschrift: var(--tm-text-1);
  --fliesstext: var(--tm-text-2);
  --nebentext: var(--tm-text-3);
  --kennzeichnung: var(--tm-text-4);

  /* --- Die Buehne: dunkle Flaeche im hellen Produkt -----------------------
     NICHT --tm-text-1 dafuer nehmen. Das ist eine Textfarbe; sie kippt im
     Dunkelmodus ins Helle, und der Sicherheitsabschnitt waere dort weiss auf
     weiss. Genau dieser Fehler ist am 04.08.2026 in drei Diensten aufgetreten
     und der Grund, warum das Paket --tm-stage ueberhaupt fuehrt. */
  --buehne: var(--tm-stage);
  --buehne-tief: var(--tm-stage-2);
  --buehne-text: var(--tm-stage-ink);
  --buehne-fliess: var(--tm-stage-text-2);
  --buehne-leise: var(--tm-stage-text-3);
  --buehne-akzent: var(--tm-stage-accent);
}

:root {
  /* --- Masse aus dem Paket -----------------------------------------------
     Beide haengen an data-app und NICHT an data-theme – das ist der Grund,
     warum sie schon seit 2.0.0 beziehbar sind. Unter 1.0.1 hing dieselbe
     Ueberschreibung zusaetzlich am Modus; --tm-radius-button loeste im ersten
     Bild auf 12px auf und sprang danach auf 10px. Gemessen am 04.08.2026. */
  --radius: var(--tm-radius-button);
  --radius-karte: var(--tm-radius-card);

  /* --- Takt und Verlauf, ebenfalls aus dem Paket -------------------------
     160ms fuer die Antwort auf einen Zeiger, 320ms fuer den Aufbau einer
     Flaeche. Zwei Zeiten, keine dritte. */
  --takt-schnell: var(--tm-dur-fast);
  --takt-ruhig: var(--tm-dur-slow);
  --verlauf: var(--tm-ease);

  /* --- Tiefe --------------------------------------------------------------
     Zwei Stufen. --tm-shadow-overlay und --tm-scrim bleiben ungenutzt: dieses
     Produkt hat keine ueberlagerte Ebene, und ein Token zu benutzen, weil es da
     ist, ist kein Grund. */
  --tiefe-flach: var(--tm-shadow-sm);
  --tiefe: var(--tm-shadow);

  /* --- Schrift ------------------------------------------------------------
     NICHT --tm-font. Das Paket fuehrt Nunito Sans, liefert die Schrift aber
     nicht mit (kein @font-face), und font-src 'self' verbietet ein CDN. Ein
     Schrifttausch ins Leere kostet Zeilenhoehe und Umbruch, ohne dass das Bild
     verdaechtig aussieht – der GRID-DarkWatch-Lauf hat am 04.08.2026 gemessen,
     wie eine Zeile dabei von 175,8 auf 165,0 px schrumpft. Eigener Vorgang beim
     Paket, hier bewusst offen. */
  --font: "Segoe UI", system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
  --mono: "Cascadia Mono", ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;

  /* ZWEI BREITEN, nicht eine. --seite ist der Rahmen (Kopf, Fuss, Werkbank, die
     drei Belege), --lesespalte die Zeile. Eine einzige Breite kann nur eines von
     beiden richtig machen: 760px war als Rahmen zu eng, 1180px waere als
     Textzeile mit rund 140 Zeichen unlesbar. Beide haben im Paket kein
     Gegenstueck, und das ist richtig so – Seitenbreiten sind Sache der
     Anwendung, genau wie die Abstaende (die 3.0.0 gar nicht mehr fuehrt). */
  --seite: 1180px;
  --lesespalte: 78ch;

  /* Der Seitenrand. Steht als eigenes Token da, weil er an zwei Sorten Element
     unterschiedlich angreift: Kopfzeile, Fusszeile und Textabschnitte tragen ihn als
     INNENabstand, die Werkbank als AUSSENabstand – sie hat ja eine sichtbare Kante,
     und die soll mit dem Text der Kopfzeile fluchten und nicht mit deren Aussenkante.
     Solange derselbe Wert an beiden Stellen steht, stimmt die Flucht von selbst. */
  --rand: clamp(1rem, 4vw, 1.5rem);
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--grund);
  color: var(--fliesstext);
  font-family: var(--font);
  font-size: var(--tm-size-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

::selection {
  background: var(--aktion);
  color: var(--aktion-schrift);
}

/* Der Fokusring liegt AUF einer Flaeche und traegt deshalb --blau-text, nicht die
   Knopffuellung. Auf dem weichen Grund erreicht die Fuellung keine 3:1 mehr; ein
   Fokusring, den man nicht sieht, ist die Tastaturbedienung. Rundung 0, wie an
   jeder bedeutungstragenden Kante. */
:focus-visible {
  outline: 2px solid var(--blau-text);
  outline-offset: 2px;
}

/* ==========================================================================
   BEWEGUNG ABSCHALTEN
   ==========================================================================
   Der Riegel steht hier oben und nicht am Ende: er soll jede Regel erwischen,
   die darunter noch dazukommt. Deckkraft bleibt erlaubt – sie bewegt nichts.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-property: opacity !important;
    transition-duration: var(--takt-schnell) !important;
    animation: none !important;
    scroll-behavior: auto !important;
  }

  /* Der Hebe-Effekt haengt an transform und waere sonst das Einzige, was die
     Zeile darueber nicht erreicht: transition aus, Sprung bleibt. Ein Pixel ohne
     Ueberblendung ist kein sanfter Effekt, sondern ein Zucken – also weg damit.
     Die Liste muss vollstaendig sein: jede Regel mit einem Hover-transform
     gehoert hier hinein, sonst zuckt genau die eine. */
  .hebt:hover,
  .hebt:focus-visible,
  .knopf-gefuellt:hover:not(:disabled),
  .knopf-umriss:hover,
  .beleg:hover {
    transform: none !important;
  }
}

/* Ein Element, das sich beim Zeigen hebt. EINE Klasse, EIN Wert – damit die
   Bewegung ueberall dieselbe ist und niemand an einer Stelle 2px nimmt. */
.hebt {
  transition: transform var(--takt-schnell) var(--verlauf),
    box-shadow var(--takt-schnell) var(--verlauf),
    border-color var(--takt-schnell) var(--verlauf);
}

.hebt:hover,
.hebt:focus-visible {
  transform: translateY(-1px);
}

/* Der Aufbau einer Flaeche. Laeuft EINMAL, 320ms, und danach nie wieder. */
@keyframes taucht-auf {
  from {
    opacity: 0;
    transform: translateY(4px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

.baut-auf {
  animation: taucht-auf var(--takt-ruhig) var(--verlauf) both;
}

/* --------------------------------------------------------------------------
   Kennzeichnung – die wiederkehrende Auszeichnung fuer Maschinensprache.
   VERSALIEN gibt es NUR hier; im Fliesstext gilt Sentence case.
   Groesse und Laufweite kommen aus dem Paket (--tm-size-eyebrow,
   --tm-track-eyebrow). Laufweite positiv: eine Festbreitenschrift vertraegt
   kein negatives Sperren.
   -------------------------------------------------------------------------- */

.kennz {
  display: block;
  font-family: var(--mono);
  font-size: var(--tm-size-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tm-track-eyebrow);
  text-transform: uppercase;
  color: var(--kennzeichnung);
  margin: 0 0 0.7rem;
}

.kennz-blau {
  color: var(--blau-text);
}

.kennz-orange {
  color: var(--orange-text);
}

/* ==========================================================================
   DIE ZUSTANDSMARKE – sieben Zustaende, ein Bauteil
   ==========================================================================
   Ein leerer Fleck ist kein Zustand, sondern ein vergessener. Deshalb gibt es
   fuer jeden der sieben Faelle eine gebaute Marke, auch fuer die selten
   sichtbaren.

   DIE FARBE IST NIE DAS EINZIGE MERKMAL. Jede Marke traegt ausserdem ein Zeichen
   und einen Text; zwei Marken teilen sich absichtlich eine Farbe (kein Zugriff
   und nicht angebunden liegen beide auf --tm-unknown-*), und getrennt werden sie
   ueber Zeichen, Text und die Kantenform – gestrichelt heisst "von hier aus nicht
   feststellbar". Wer die Zustaende nur an der Farbe unterscheidet, hat sie fuer
   jeden Vierzehnten unter uns gar nicht unterschieden.

   GETOENTE FLAECHEN, nicht volle. --tm-*-fill ist im Dunkelmodus durchscheinend
   (rgba mit 12–14 % Deckung) und mischt sich mit dem Untergrund. pruefe/kontrast.mjs
   rechnet deshalb NICHT --tm-ok-ink gegen --tm-ok-fill, sondern gegen die
   Mischung aus Fuellung UND Untergrund – die Fuellung allein waere ein Wert, den
   es auf dem Bildschirm nie gibt.

   KEIN ROT AUF DEM BILDSCHIRM NACH DEM ABRUF. Dort ist nichts kaputt, die
   Nachricht hat ihren Zweck erfuellt – die Marke dort ist "in Ordnung".
   ========================================================================== */

.marke {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.28rem 0.7rem 0.28rem 0.55rem;
  border-radius: var(--tm-radius-pill);
  border: 1px solid transparent;
  font-family: var(--mono);
  font-size: var(--tm-size-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tm-track-eyebrow);
  text-transform: uppercase;
  white-space: nowrap;
}

/* Das Zeichen. Ein Punkt, ein Ring, ein Balken – gezeichnet, nicht getippt,
   damit keine Schriftart daraus ein Kaestchen macht. */
.marke-zeichen {
  width: 9px;
  height: 9px;
  flex: none;
  border-radius: 50%;
  background: currentColor;
}

.marke-ok {
  background: var(--tm-ok-fill);
  color: var(--tm-ok-ink);
  border-color: var(--tm-ok);
}

.marke-warnung {
  background: var(--tm-warn-fill);
  color: var(--tm-warn-ink);
  border-color: var(--tm-warn);
}

.marke-kritisch {
  background: var(--tm-crit-fill);
  color: var(--tm-crit-ink);
  border-color: var(--tm-crit);
}

.marke-laedt {
  background: var(--tm-info-fill);
  color: var(--tm-info-ink);
  border-color: var(--tm-info);
}

/* Die drei Grautoene. Sie teilen sich die Farbe und trennen sich ueber die
   Kante: durchgezogen heisst "so ist es", gestrichelt heisst "von hier aus
   nicht feststellbar". */
.marke-leer,
.marke-kein-zugriff,
.marke-nicht-angebunden {
  color: var(--tm-unknown-ink);
  border-color: var(--tm-unknown);
}

.marke-leer {
  background: none;
  border-style: dashed;
}

.marke-kein-zugriff {
  background: var(--tm-unknown-fill);
}

.marke-nicht-angebunden {
  background: var(--tm-unknown-fill);
  border-style: dashed;
}

/* Der Ring statt des Punktes: bei "kein Zugriff" ist nichts erloschen, es ist
   nur verschlossen. */
.marke-kein-zugriff .marke-zeichen {
  background: none;
  border: 2px solid currentColor;
}

.marke-leer .marke-zeichen {
  background: none;
  border: 1px dashed currentColor;
}

.marke-nicht-angebunden .marke-zeichen {
  background: none;
  border: 1px dashed currentColor;
}

/* DIE EINZIGE DAUERSCHLEIFE DER SEITE. Sie sagt "es laeuft noch", und dafuer
   muss sie laufen. Alles andere haelt an. */
@keyframes puls {
  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.35;
  }
}

.marke-laedt .marke-zeichen {
  animation: puls 1.2s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .marke-laedt .marke-zeichen {
    animation: none !important;
    opacity: 0.7;
  }
}

/* Die Marke steht ueber der Schlagzeile und ersetzt dort die Kennzeichnung.
   Ein eigener Abstand, damit sie nicht an der Ueberschrift klebt. */
.markenzeile {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  flex-wrap: wrap;
  margin: 0 0 0.9rem;
}

.markenzeile .kennz {
  margin: 0;
}

/* --------------------------------------------------------------------------
   Kopfzeile. Grundflaeche, unten eine Haarlinie, sonst nichts.
   -------------------------------------------------------------------------- */

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  /* width: 100% ist NICHT redundant neben max-width. app.html macht den <body> zu einem
     Flex-Container (Spalte, damit die Fusszeile unten bleibt); dort unterdrueckt das
     margin-inline: auto das Strecken auf der Querachse, und der Kopf schrumpft auf
     Inhaltsbreite. Im Bild vom 03.08.2026 war die Kopfzeile der Abrufseite dadurch
     510 statt 760 px breit und sass eingerueckt ueber ihrem eigenen Inhalt. Auf der
     Startseite fiel es nicht auf, weil deren <body> kein Flex-Container ist – ein
     Fehler, den nur die App zeigt und kein Test findet. */
  width: 100%;
  max-width: var(--seite);
  margin-inline: auto;
  padding: 1.1rem var(--rand) 1rem;
  border-bottom: 1px solid var(--linie);
}

.brand {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  text-decoration: none;
  flex-wrap: wrap;
}

.brand-mark {
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: 0.01em;
  color: var(--ueberschrift);
}

/* Der Punkt ist BLAU, nicht orange: Orange gehoert dem Schluessel und sonst
   niemandem. Ein oranger Markenpunkt waere genau die Verwaesserung, die den
   Farbcode unlesbar macht. */
.brand-dot {
  color: var(--blau-text);
}

.brand-tagline {
  font-family: var(--mono);
  font-size: var(--tm-size-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tm-track-eyebrow);
  text-transform: uppercase;
  color: var(--kennzeichnung);
}

.site-nav {
  display: flex;
  align-items: center;
  gap: 1.1rem;
}

.nav-link {
  color: var(--fliesstext);
  text-decoration: none;
  font-size: 0.86rem;
  border-bottom: 1px solid transparent;
  padding-bottom: 1px;
  transition: color var(--takt-schnell) var(--verlauf),
    border-color var(--takt-schnell) var(--verlauf);
}

.nav-link:hover,
.nav-link.is-active {
  color: var(--ueberschrift);
  border-bottom-color: var(--linie);
}

/* Beide Umschalter: kein Knopfaussehen. Sie sind Werkzeug, nicht Aufforderung –
   der einzige gefuellte Knopf der Seite ist "Link erzeugen". */
.lang-toggle,
.theme-toggle {
  background: none;
  border: 0;
  color: var(--kennzeichnung);
  font-family: var(--mono);
  font-size: var(--tm-size-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tm-track-eyebrow);
  text-transform: uppercase;
  cursor: pointer;
  padding: 0.2rem 0;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  transition: color var(--takt-schnell) var(--verlauf);
}

.lang-toggle:hover,
.theme-toggle:hover {
  color: var(--ueberschrift);
}

.theme-toggle svg {
  width: 12px;
  height: 12px;
  flex: none;
}

/* --------------------------------------------------------------------------
   Fusszeile – eine Zeile Kennzeichnung, mehr braucht sie nicht.
   -------------------------------------------------------------------------- */

.site-footer {
  /* siehe .site-header: ohne width: 100% schrumpft die Fusszeile im Flex-Body der App */
  width: 100%;
  max-width: var(--seite);
  margin: 4rem auto 0;
  padding: 1.4rem var(--rand) 3rem;
  border-top: 1px solid var(--linie);
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.4rem;
  align-items: baseline;
}

.footer-brand {
  font-family: var(--mono);
  font-size: var(--tm-size-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tm-track-eyebrow);
  text-transform: uppercase;
  color: var(--kennzeichnung);
  margin: 0;
  flex: 1 1 auto;
}

.footer-legal {
  margin: 0;
  font-size: 0.8rem;
}

.footer-legal a {
  color: var(--fliesstext);
  text-decoration: none;
  border-bottom: 1px solid var(--linie);
  transition: color var(--takt-schnell) var(--verlauf),
    border-color var(--takt-schnell) var(--verlauf);
}

.footer-legal a:hover {
  color: var(--ueberschrift);
  border-bottom-color: var(--feldrand);
}

.footer-legal span {
  margin: 0 0.45rem;
  color: var(--feldrand);
}

.skip-link {
  position: absolute;
  left: -9999px;
}

.skip-link:focus {
  left: 1rem;
  top: 1rem;
  background: var(--aktion);
  color: var(--aktion-schrift);
  padding: 0.5rem 0.9rem;
  z-index: 20;
}

@media (max-width: 640px) {
  .brand-tagline {
    display: none;
  }

  .site-nav {
    gap: 0.9rem;
  }
}

/* ==========================================================================
   DIE WERKBANK – der abgesetzte Funktionsbereich
   ==========================================================================
   Das Werkzeug traegt eine eigene Flaeche, eine eigene Kante und einen eigenen
   Innenabstand; alles darunter liegt auf der blanken Grundflaeche.

   WORAN DIE ABHEBUNG HAENGT – gemessen, nicht gehofft: die Fuellung allein macht
   nur rund 1.2:1 gegen den Grund. Das ist zu wenig, um auf einen Blick zu wirken.
   Die KANTE traegt es: --werkbank-kante liegt ueber der 3:1 aus WCAG 1.4.11.
   pruefe/kontrast.mjs rechnet beides nach.

   SEIT DIESER ETAPPE KOMMT TIEFE DAZU, und zwar als Zugabe und nicht als Ersatz.
   Ein Schatten ist kein Kontrast: er verschwindet auf jedem Bildschirm mit
   erhoehtem Kontrastmodus, und im Dunkelmodus ist er ohnehin kaum sichtbar. Die
   Kante bleibt deshalb, wo sie war.

   ZWEI SPALTEN AB 980px: links wird eingegeben, rechts entsteht der Link. Ein
   Eingabefeld auf 1100px zu ziehen waere die duemmste Art, Breite zu verbrauchen.
   Darunter gestapelt.
   ========================================================================== */

.werkbank {
  /* Zwei Grenzen, und beide werden gebraucht: die Breite haelt den Aussenabstand ein
     (damit die Kante auf schmalen Geraeten nicht am Bildschirmrand klebt), die
     Hoechstbreite bringt die Kante auf die Textflucht der Kopfzeile. Nur eine von
     beiden reicht nicht – mit der Hoechstbreite allein beruehrt der Kasten unter
     1180px die Raender, mit der Breite allein sitzt er ueber 1180px zu weit aussen. */
  width: calc(100% - 2 * var(--rand));
  max-width: calc(var(--seite) - 2 * var(--rand));
  margin: 2rem auto 0;
  background: var(--werkbank);
  border: 1px solid var(--werkbank-kante);
  border-radius: var(--radius-karte);
  box-shadow: var(--tiefe);
  padding: 1.8rem clamp(1.1rem, 3vw, 2rem);
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: 2.4rem;
  align-items: start;
}

/* Die Ansichten des EMPFAENGERS haben nur eine Haelfte – dort entsteht nichts
   parallel, dort wird geoeffnet. Sie bekommen dieselbe Flaeche und dieselbe Kante,
   damit "hier ist das Werkzeug" auf allen Ansichten dasselbe Zeichen ist, aber eine
   Spalte und Lesebreite. Die Zustandsansicht (abgelaufen, verbraucht) bekommt sie
   ausdruecklich NICHT: sie ist kein Werkzeug, sondern eine Auskunft. */
.werkbank-einspaltig {
  grid-template-columns: 1fr;
  max-width: var(--lesespalte);
}

/* Die senkrechte Fuge zwischen Eingeben und Entstehen. Eine Linie, kein Rahmen –
   die beiden Haelften sind EIN Werkzeug und nicht zwei Kaesten. */
.werkbank-ergebnis {
  /* Dieselbe Farbe wie die Aussenkante der Werkbank, und aus demselben Grund: --linie
     und --feldrand sind auf die GRUNDflaeche gezeichnet und verschwinden auf der
     helleren Werkbank fast vollstaendig (gemessen 1.2:1 bzw. 1.5:1). Eine Fuge, die
     man gerade so ahnt, sieht nach Versehen aus – entweder sie ist da oder sie ist
     weg. --werkbank-kante ist da. */
  border-left: 1px solid var(--werkbank-kante);
  padding-left: 2.4rem;
}

/* Innerhalb der Werkbank ist eine Stufe eine Rasterzelle: keine eigene Breite,
   keine eigene Zentrierung, kein eigener Aussenabstand. Ohne diese Zeile schoebe
   sich das margin-inline: auto der Stufe gegen das Raster und beide Haelften
   saessen eingerueckt in ihrer eigenen Spalte. */
.werkbank .stufe {
  max-width: none;
  margin-inline: 0;
  padding: 0;
}

@media (max-width: 980px) {
  .werkbank {
    grid-template-columns: 1fr;
    gap: 1.8rem;
  }

  .werkbank-ergebnis {
    border-left: 0;
    border-top: 1px solid var(--werkbank-kante);
    padding-left: 0;
    padding-top: 1.8rem;
  }
}

/* ==========================================================================
   DAS FORMULAR UND DIE LINK-ANATOMIE
   Steht hier und nicht in landing.css oder styles.css, weil BEIDE Seiten es
   zeigen: die oeffentliche Startseite und /app. Das Markup dazu kommt aus
   js/erstellen.js, ebenfalls einmal fuer beide.
   ========================================================================== */

.stufe {
  max-width: var(--seite);
  margin-inline: auto;
  padding: 2.2rem var(--rand) 0;
}

.trenner {
  max-width: var(--seite);
  margin: 2.4rem auto 0;
  border: 0;
  border-top: 1px solid var(--linie);
}

/* Schlagzeile: Hausschrift, 29px, Gewicht 500, leicht negativ gesperrt.
   Negative Laufweite ist bei einer PROPORTIONALEN Schrift richtig und bei einer
   Festbreitenschrift falsch – deshalb steht sie hier und nirgends bei .mono. */
.schlagzeile {
  font-size: 29px;
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.25;
  color: var(--ueberschrift);
  margin: 0 0 0.5rem;
}

.satz {
  margin: 0 0 1.4rem;
  max-width: 60ch;
}

/* Die vierte Textstufe wird hier ueber GROESSE gemacht und nicht ueber Farbe:
   im Hellmodus faellt --tm-text-3 mit --tm-text-4 zusammen, eine Farbstufe gaebe
   es dort also gar nicht. --nebentext ist trotzdem richtig – im Dunkelmodus ist
   es eine echte Stufe, und die Regel muss den Modus nicht unterscheiden. */
.klein {
  font-size: 0.8rem;
  color: var(--nebentext);
  margin: 0.5rem 0 0;
}

/* --- Das Heldenfeld ------------------------------------------------------
   Der 2px-Seitenakzent ist nicht Zierde: er ist das Element, ueber das dieses Feld
   die 3:1 aus WCAG 1.4.11 erreicht. Er traegt --blau-text und NICHT --aktion –
   die Knopffuellung bliebe auf der Feldflaeche darunter. Rundung an der
   Akzentkante: 0. */
.held {
  display: block;
  width: 100%;
  height: 168px;
  resize: vertical;
  background: var(--feld);
  color: var(--ueberschrift);
  border: 1px solid var(--feldrand);
  border-left: 2px solid var(--blau-text);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: 0.85rem 1rem;
  font-family: var(--mono);
  font-size: 14px;
  line-height: 1.55;
  letter-spacing: 0;
  transition: border-color var(--takt-schnell) var(--verlauf),
    box-shadow var(--takt-schnell) var(--verlauf);
}

.held:hover:not(:disabled) {
  border-color: var(--werkbank-kante);
  border-left-color: var(--blau-text);
}

.held::placeholder {
  color: var(--kennzeichnung);
}

.held:disabled {
  opacity: 0.55;
}

/* --- Die Aktionszeile: Abrufe, Lebensdauer, Knopf ------------------------ */

.aktionszeile {
  display: flex;
  gap: 0.9rem;
  align-items: flex-end;
  margin-top: 0.9rem;
  flex-wrap: wrap;
}

.wahl {
  display: block;
  flex: 0 0 auto;
}

.wahl .kennz {
  margin-bottom: 0.35rem;
}

.wahl select {
  height: 44px;
  background: var(--feld);
  color: var(--ueberschrift);
  border: 1px solid var(--feldrand);
  border-radius: var(--radius);
  padding: 0 0.7rem;
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: 0;
  cursor: pointer;
  transition: border-color var(--takt-schnell) var(--verlauf);
}

.wahl select:hover {
  border-color: var(--werkbank-kante);
}

/* Der Knopf nimmt den ganzen Rest der Breite. Er ist der EINZIGE gefuellte
   Knopf dieser Seite – wo alles gleich laut ruft, hoert man nichts. */
.knopf-rest {
  flex: 1 1 200px;
}

.knopf {
  height: 44px;
  padding: 0 1.2rem;
  border-radius: var(--radius);
  font-family: var(--font);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background var(--takt-schnell) var(--verlauf),
    border-color var(--takt-schnell) var(--verlauf),
    color var(--takt-schnell) var(--verlauf),
    transform var(--takt-schnell) var(--verlauf),
    box-shadow var(--takt-schnell) var(--verlauf);
}

/* Gefuellter Knopf: Flaeche --aktion, Schrift --aktion-schrift (das Paket fuehrt
   sie als --tm-accent-ink). NICHT --blau-text als Flaeche nehmen – das ergaebe
   2.52:1 und ist der Fehler, den dieses Produkt zweimal hatte. */
.knopf-gefuellt {
  position: relative;
  overflow: hidden;
  background: var(--aktion);
  color: var(--aktion-schrift);
}

.knopf-gefuellt:hover:not(:disabled) {
  background: var(--aktion-tief);
  transform: translateY(-1px);
  box-shadow: var(--tiefe-flach);
}

.knopf-gefuellt:active:not(:disabled) {
  transform: none;
}

.knopf-gefuellt:disabled {
  opacity: 0.5;
  cursor: default;
}

/* DER EINMALIGE GLANZ. Er laeuft genau einmal, wenn der Knopf erscheint, und
   danach nie wieder – kein Blinken, keine Schleife, keine Aufforderung im
   Sekundentakt. Er sagt "das hier ist der Knopf" und tritt dann zurueck.

   NUR AM HAUPTKNOPF, deshalb eine eigene Klasse und nicht .knopf-gefuellt. Auf
   dem Ergebnisbildschirm stehen zwei gefuellte Knoepfe nebeneinander (Kopieren
   und der QR-Code); glaenzten beide, glaenzte keiner. Vergeben wird die Klasse an
   genau eine Stelle je Ansicht: "Link erzeugen" beim Absender, "Jetzt oeffnen"
   beim Empfaenger.

   Ein ::after statt eines zweiten Elements: es gibt keinen Grund, dem Markup
   dafuer ein Kind zu geben, und ein Pseudoelement kann kein Tabstopp werden. */
@keyframes glanz {
  from {
    transform: translateX(-120%) skewX(-18deg);
  }

  to {
    transform: translateX(320%) skewX(-18deg);
  }
}

.knopf-glanz::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 28%;
  background: var(--aktion-schrift);
  opacity: 0.18;
  pointer-events: none;
  transform: translateX(-120%) skewX(-18deg);
  animation: glanz 900ms var(--verlauf) 240ms 1 both;
}

@media (prefers-reduced-motion: reduce) {
  .knopf-glanz::after {
    display: none;
  }
}

/* Umrissknopf: Schrift in der NORMALEN Textfarbe, nie in --aktion-schrift. Ein
   weisser Text auf einer weissen Flaeche ist einer der zwei Fehler, die frueher
   erst im Screenshot aufgefallen sind. */
.knopf-umriss {
  background: none;
  color: var(--ueberschrift);
  border-color: var(--feldrand);
}

.knopf-umriss:hover {
  border-color: var(--blau-text);
  color: var(--blau-text);
  transform: translateY(-1px);
}

.knopf-text {
  background: none;
  border: 0;
  color: var(--blau-text);
  height: auto;
  padding: 0;
  font-size: 0.82rem;
  text-decoration: underline;
}

.knopf.is-copied {
  border-color: var(--blau-text);
}

/* --- Passphrase: vorhanden, aber leise ----------------------------------- */

.nebensache {
  margin-top: 1rem;
  font-size: 0.86rem;
}

.nebensache > summary {
  cursor: pointer;
  color: var(--nebentext);
  list-style: none;
  transition: color var(--takt-schnell) var(--verlauf);
}

.nebensache > summary::before {
  content: "+ ";
  font-family: var(--mono);
}

.nebensache[open] > summary::before {
  content: "− ";
}

.nebensache > summary:hover {
  color: var(--ueberschrift);
}

.nebensache input {
  display: block;
  width: 100%;
  max-width: 340px;
  margin-top: 0.7rem;
  height: 40px;
  background: var(--feld);
  color: var(--ueberschrift);
  border: 1px solid var(--feldrand);
  border-radius: var(--radius);
  padding: 0 0.8rem;
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: 0;
}

/* ==========================================================================
   DIE LINK-ANATOMIE – das Leitmotiv, und deshalb gross
   ==========================================================================
   Blau geht an den Server, Orange bleibt beim Nutzer. Das ist die ganze
   Erklaerung von Zero-Knowledge, und sie steht nicht in einem Satz, sondern im
   Gegenstand selbst: im Link, den der Nutzer gleich verschickt.

   DREI DINGE MACHEN SIE GROSS, und keines davon ist ein Kasten:
     1. der Schriftgrad – 19px Festbreite statt 15, mit Luft in der Zeile
     2. die zweifarbige UNTERSTREICHUNG, 2px, je Haelfte in ihrer Farbe. Sie
        ueberlebt den Zeilenumbruch, weil sie am Inline-Element haengt und nicht
        an einer gezeichneten Klammer. Eine Klammer ueber dem Text waere bei jedem
        Umbruch falsch – und dieser Link bricht immer um.
     3. die beiden Erklaerkaesten darunter, jeder in der getoenten Flaeche seiner
        Farbe. Sie stehen fuer die zwei Haelften, nicht daneben.

   DER SCHLUESSEL IST HIER ECHT. Die Vorschau zeigt genau den Schluessel, mit dem
   gleich verschluesselt wird (js/erstellen.js) – gekuerzt, damit ein Blick ueber
   die Schulter nicht den ganzen mitnimmt. Eine nachgebaute Zeichenfolge waere
   eine zweite Wahrheit ueber den Schluessel und haette hier nichts verloren.

   WAS HIER NICHT STEHT UND NIE STEHEN DARF: der Klartext des Secrets. Weder als
   Vorschau, noch ausgegraut, noch im DOM. Ein Linkvorschaudienst im Postfach
   wuerde ihn sonst verbrauchen, bevor der Empfaenger ihn sieht.
   ========================================================================== */

.anatomie {
  margin: 0 0 1.2rem;
}

.linkvorschau {
  font-family: var(--mono);
  font-size: 19px;
  letter-spacing: 0;
  line-height: 1.85;
  margin: 0 0 1rem;
  word-break: break-all;
}

/* BLAU = verlaesst den Browser. ORANGE = bleibt hier. Nur diese zwei.
   Die Unterstreichung ist 2px und liegt 3px tiefer als die Grundlinie: dichter
   dran schneidet sie die Unterlaengen an, weiter weg loest sie sich vom Wort. */
.teil-server,
.teil-key {
  border-bottom: 2px solid;
  padding-bottom: 3px;
}

.teil-server {
  color: var(--blau-text);
  border-bottom-color: var(--blau-text);
}

.teil-key {
  color: var(--orange-text);
  border-bottom-color: var(--schluessel);
  font-weight: 600;
}

/* Vor dem ersten Zeichen steht ein Platzhalter. Er ist NICHT eingefaerbt –
   sonst behauptete die Farbe eine Aufteilung, die es noch gar nicht gibt. */
.linkvorschau.ist-leer {
  color: var(--kennzeichnung);
}

.linkvorschau.ist-leer .teil-server,
.linkvorschau.ist-leer .teil-key {
  color: inherit;
  border-bottom-color: var(--linie);
  font-weight: inherit;
}

/* Bewusst KEIN Flex-Container: der QR-Code darin wurde als Flex-Kind mit
   flex-basis: 100% ueber die ganze Spalte gezogen und stand als leerer weisser Balken
   im Bild. Gestapelte Bloecke, und nur die Knopfzeile darin ist Flex. */
.linkaktionen {
  margin: 0 0 1.5rem;
}

.knopfzeile {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  align-items: center;
}

.linkaktionen .qr {
  margin-top: 0.9rem;
}

/* Der QR-Code bleibt WEISS mit dunklen Modulen, auch im dunklen Fall: Lesegeraete
   erkennen ihn ueber den Hell-Dunkel-Kontrast, invertiert lesen ihn viele Kameras
   nicht. Funktionsbedingung, kein Stilbruch – und deshalb einer der vier
   Hexwerte, die diese Datei ausdruecklich behaelt. */
.qr {
  background: #fff;
  padding: 10px;
  width: max-content;
  border-radius: var(--radius);
}

.qr svg {
  display: block;
  width: 148px;
  height: 148px;
}

.loeschmarke {
  border-left: 2px solid var(--linie);
  border-radius: 0;
  padding-left: 0.9rem;
  margin-top: 1.1rem;
}

.loeschmarke code {
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: 0;
  color: var(--ueberschrift);
  margin-right: 0.6rem;
}

/* --- Die zwei Erklaerspalten ---------------------------------------------
   Seit dieser Etappe getoente Flaechen statt blosser Seitenakzente: sie gehoeren
   zur Anatomie darueber und sollen als deren zwei Haelften lesbar sein, nicht als
   zwei weitere Absaetze. Die Kante bleibt trotzdem – die Toenung ist schwach
   (im Dunkelmodus durchscheinend), und ein Bereich, der nur ueber eine 1.1:1
   starke Fuellung existiert, existiert auf einem hellen Bildschirm im Sonnenlicht
   nicht mehr.
   -------------------------------------------------------------------------- */

.deutung {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-bottom: 0.4rem;
}

/* In der rechten Werkbankhaelfte stehen die beiden Erklaerspalten UNTEREINANDER.
   Nebeneinander waeren sie dort rund 25 Zeichen breit – zwei Saeulen aus Silben. */
.werkbank .deutung {
  grid-template-columns: 1fr;
  gap: 0.8rem;
}

.deutung-blau,
.deutung-orange {
  border-left: 2px solid;
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: 0.7rem 0.9rem;
}

.deutung-blau {
  border-left-color: var(--blau-text);
  background: var(--aktion-hauch);
}

/* AUF DER GETOENTEN FLAECHE TRAEGT DIE KENNZEICHNUNG DEN AKZENTTON, nicht die
   Standardfarbe. Das ist gemessen und nicht Geschmack: --kennzeichnung erreicht
   auf dem blauen Hauch ueber der Werkbank im Dunkelmodus 4.23:1 und faellt damit
   unter AA, --blau-text erreicht 5.68:1. Heute steht dort ohnehin .kennz-blau;
   diese Regel sorgt dafuer, dass auch eine kuenftige Zeile ohne den Zusatz
   richtig herauskommt, statt lautlos knapp durchzufallen. */
.deutung-blau .kennz {
  color: var(--blau-text);
}

/* Die orange Toenung baut das Paket nicht als eigenes Token – --tm-accent-2-soft
   gibt es nicht. Sie hier zu erfinden hiesse, einen Wert zu setzen, den niemand
   nachrechnet. Stattdessen die Feldflaeche: sie hebt sich von der Werkbank ab,
   ist in beiden Modi definiert und gemessen, und die Bedeutung traegt ohnehin die
   Kante. Als Wunsch ans Paket vermerkt, nicht als Notloesung eingebaut. */
.deutung-orange {
  border-left-color: var(--schluessel);
  background: var(--feld);
}

.deutung p {
  margin: 0;
  font-size: 0.88rem;
}

/* ==========================================================================
   DER ABLAUFRING
   ==========================================================================
   Er sitzt um den Hauptknopf der Abrufseite und sagt, wie viel Zeit dieses Secret
   noch hat. Die Restzeit steht in Festbreite daneben – sie ist eine Zahl, die man
   ablesen und vergleichen koennen muss, und dafuer duerfen die Ziffern nicht
   tanzen.

   ER ERFINDET KEINEN NENNER. Das ist der Punkt, an dem so etwas normalerweise
   unehrlich wird: die API liefert expiresAt, aber NICHT, wie lang die Lebensdauer
   ursprunglich war (das steht nur beim Absender). Ein Ring, der "noch 40 Prozent"
   zeigt, muesste sich diese 100 Prozent also ausdenken.

   Deshalb dreht er sich in der LETZTEN STUNDE, und nur dort. Ueber einer Stunde
   ist er voll und die Zahl daneben nennt die Restzeit im Klartext. Unter einer
   Stunde leert er sich – 60 Minuten sind ein Nenner, den niemand erfinden muss,
   und es ist genau der Zeitraum, in dem die Restzeit ueberhaupt eine Handlung
   ausloest.

   GEZEICHNET ALS SVG, nicht als CSS-Verlauf. Die CSP verbietet Inline-Stile
   (style-src 'self'); ein Fortschritt, den JavaScript setzt, muesste sonst ueber
   ein style-Attribut laufen. stroke-dasharray und stroke-dashoffset sind
   SVG-Praesentationsattribute und kein CSS – sie sind erlaubt, und der Rauchtest
   faehrt gegen dieselbe strenge Richtlinie wie der Betrieb.
   ========================================================================== */

.ablauf {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  margin: 0 0 1rem;
}

.ablauf-ring {
  width: 44px;
  height: 44px;
  flex: none;
  display: block;
}

/* Die Spur, auf der der Zeiger laeuft. Sie muss sichtbar sein, sonst sieht ein
   voller Ring aus wie ein gezeichneter Kreis ohne Bedeutung – und ein voller Ring
   ist der Normalfall.

   --werkbank-kante UND NICHT --feldrand, und das steht hier, weil der erste
   Anlauf --feldrand nahm und der Kontrastlauf ihn zerlegt hat: 1.48:1 hell und
   1.58:1 dunkel gegen die Werkbank. Die Feldkante ist auf die GRUNDflaeche
   gezeichnet; auf der helleren Werkbank verschwindet sie fast vollstaendig –
   derselbe Befund, der weiter oben schon die senkrechte Fuge betrifft. */
.ablauf-spur {
  fill: none;
  stroke: var(--werkbank-kante);
  stroke-width: 3;
}

.ablauf-zeiger {
  fill: none;
  stroke: var(--blau-text);
  stroke-width: 3;
  stroke-linecap: round;
  transition: stroke-dashoffset var(--takt-ruhig) linear;
}

/* Unter fuenf Minuten wechselt der Zeiger auf die Schluesselfarbe. Das ist KEIN
   Alarm und kein Rot – es ist dieselbe Farbe, die auf dieser Seite ohnehin sagt
   "das hier betrifft dich unmittelbar". */
.ablauf.ist-knapp .ablauf-zeiger {
  stroke: var(--schluessel);
}

.ablauf-zeit {
  font-family: var(--mono);
  font-size: 15px;
  letter-spacing: 0;
  color: var(--ueberschrift);
  font-variant-numeric: tabular-nums;
}

.ablauf-was {
  display: block;
  font-family: var(--mono);
  font-size: var(--tm-size-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tm-track-eyebrow);
  text-transform: uppercase;
  color: var(--kennzeichnung);
}

@media (prefers-reduced-motion: reduce) {
  .ablauf-zeiger {
    transition: none !important;
  }
}

/* --- Meldungen ------------------------------------------------------------ */

.meldung {
  margin-top: 1rem;
  padding: 0.7rem 0 0.7rem 0.9rem;
  border-left: 2px solid var(--feldrand);
  border-radius: 0;
  font-size: 0.9rem;
  color: var(--ueberschrift);
}

/* Kein Rot: eine abgelaufene Frist ist kein Fehler des Lesers, und ein leeres
   Feld auch nicht. Die Meldung faellt ueber die Linie auf, nicht ueber Alarm. */
.meldung-warn {
  border-left-color: var(--schluessel);
}

/* --- Die Notbremse -------------------------------------------------------
   Der Bildschirm, den js/notbremse.js zeichnet, wenn der Container leer geblieben
   ist. Er benutzt bewusst NUR Klassen, die es hier ohnehin gibt (.stufe, .kennz,
   .schlagzeile, .satz, .meldung, .klein) – kommt auch dieses Stylesheet nicht an,
   steht der Text unformatiert und trotzdem lesbar da.

   KEIN ROT und KEIN Warnsymbol, aus demselben Grund wie bei der Zustandsansicht:
   der Besucher hat nichts falsch gemacht. */
.notbremse {
  max-width: var(--lesespalte);
}

.notbremse .notbremse-grund {
  display: block;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0;
  color: var(--ueberschrift);
  word-break: break-all;
}

@media (max-width: 640px) {
  .schlagzeile {
    font-size: 25px;
  }

  .linkvorschau {
    font-size: 16px;
  }

  .deutung {
    grid-template-columns: 1fr;
    gap: 0.8rem;
  }

  .aktionszeile {
    gap: 0.6rem;
  }

  .wahl {
    flex: 1 1 45%;
  }

  .wahl select {
    width: 100%;
  }
}
