/* ==========================================================================
   neumann-tim.com - Kontakt
   Ein Stylesheet fuer alle Seiten. Keine Inline-Styles, keine externen
   Ressourcen: dadurch kommt die Content-Security-Policy ohne 'unsafe-inline'
   und ohne Fremd-Hosts aus.
   ========================================================================== */

/* ---------- Tokens: Hell ist die Basis, Dunkel ueberschreibt nur Farben ---- */
:root {
  color-scheme: light dark;

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text", "Segoe UI",
          Roboto, Inter, system-ui, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 20px;
  --r-xl: 26px;

  --ease: cubic-bezier(.2, .8, .2, 1);
  --dur: .32s;

  --bg: #f5f5f3;
  --bg-2: #ececeb;
  --surface: #ffffff;
  --field: #fbfbfa;
  --field-focus: #ffffff;

  --ink: #16181a;
  --ink-2: #4c5257;
  --ink-3: #838a91;

  --line: rgba(20, 24, 28, .11);
  --line-2: rgba(20, 24, 28, .2);

  --accent: #2f6f5c;
  --accent-hover: #275e4e;
  --accent-ink: #ffffff;
  --accent-soft: rgba(47, 111, 92, .12);
  --accent-glow: rgba(47, 111, 92, .16);

  --ok: #1c7a4f;
  --ok-soft: rgba(28, 122, 79, .12);
  --err: #b3261e;
  --err-soft: rgba(179, 38, 30, .1);

  --shadow-1: 0 1px 2px rgba(16, 20, 24, .05), 0 6px 16px -10px rgba(16, 20, 24, .18);
  --shadow-2: 0 1px 2px rgba(16, 20, 24, .04), 0 32px 64px -32px rgba(16, 20, 24, .3);

  --aurora-1: rgba(47, 111, 92, .16);
  --aurora-2: rgba(120, 150, 200, .12);

  /* Deckkraft des Punktfelds im Hintergrund. Auf hellem Grund wirken dunkle
     Punkte deutlich staerker als helle auf dunklem, deshalb hier gedaempft. */
  --dot-strength: .7;

  /* Maskottchen. Warmes Braun als Gegengewicht zum kuehlen Gruen. */
  --bear:       #a87f5d;
  --bear-shade: #8c6746;
  --bear-snout: #ddc3aa;
  --bear-ink:   #2a2018;
}

/* Dunkle Palette. Doppelt notiert, damit sowohl die Systemeinstellung als
   auch der manuelle Schalter greifen - und der Schalter in beide Richtungen
   gewinnt. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0a0b0c;
    --bg-2: #131517;
    --surface: #151719;
    --field: #1b1e21;
    --field-focus: #202427;

    --ink: #f0f1f2;
    --ink-2: #aeb4ba;
    --ink-3: #7b828a;

    --line: rgba(255, 255, 255, .1);
    --line-2: rgba(255, 255, 255, .2);

    --accent: #7cc4a8;
    --accent-hover: #93d3ba;
    --accent-ink: #06211a;
    --accent-soft: rgba(124, 196, 168, .14);
    --accent-glow: rgba(124, 196, 168, .2);

    --ok: #6ed6a4;
    --ok-soft: rgba(110, 214, 164, .14);
    --err: #ff8a90;
    --err-soft: rgba(255, 138, 144, .12);

    --shadow-1: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px -12px rgba(0, 0, 0, .6);
    --shadow-2: 0 1px 2px rgba(0, 0, 0, .4), 0 40px 80px -40px rgba(0, 0, 0, .8);

    --aurora-1: rgba(124, 196, 168, .13);
    --aurora-2: rgba(96, 130, 190, .1);

    --dot-strength: 1;

    --bear:       #b98a63;
    --bear-shade: #9a7150;
    --bear-snout: #e3ceb6;
    --bear-ink:   #241b14;
  }
}

:root[data-theme="dark"] {
  --bg: #0a0b0c;
  --bg-2: #131517;
  --surface: #151719;
  --field: #1b1e21;
  --field-focus: #202427;

  --ink: #f0f1f2;
  --ink-2: #aeb4ba;
  --ink-3: #7b828a;

  --line: rgba(255, 255, 255, .1);
  --line-2: rgba(255, 255, 255, .2);

  --accent: #7cc4a8;
  --accent-hover: #93d3ba;
  --accent-ink: #06211a;
  --accent-soft: rgba(124, 196, 168, .14);
  --accent-glow: rgba(124, 196, 168, .2);

  --ok: #6ed6a4;
  --ok-soft: rgba(110, 214, 164, .14);
  --err: #ff8a90;
  --err-soft: rgba(255, 138, 144, .12);

  --shadow-1: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px -12px rgba(0, 0, 0, .6);
  --shadow-2: 0 1px 2px rgba(0, 0, 0, .4), 0 40px 80px -40px rgba(0, 0, 0, .8);

  --aurora-1: rgba(124, 196, 168, .13);
  --aurora-2: rgba(96, 130, 190, .1);

  --dot-strength: 1;

  --bear:       #b98a63;
  --bear-shade: #9a7150;
  --bear-snout: #e3ceb6;
  --bear-ink:   #241b14;
}

:root[data-theme="dark"] { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

/* Das hidden-Attribut zuverlaessig durchsetzen. Die Regel [hidden]{display:none}
   stammt aus dem Browser-Stylesheet, und jede Autorenregel schlaegt sie -
   "form { display: flex }" liess das versteckte Formular sichtbar bleiben.
   Deshalb hier einmal zentral und mit !important. */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Android legt beim Antippen sonst ein graues Rechteck ueber Knoepfe und
     Links. Eigene :active- und :focus-Zustaende gibt es ohnehin. */
  -webkit-tap-highlight-color: transparent;
}

body {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.55;
  letter-spacing: -.011em;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           env(safe-area-inset-bottom) env(safe-area-inset-left);
}

svg { display: block; }
a { color: var(--accent); text-underline-offset: .18em; text-decoration-thickness: 1px; }
a:hover { color: var(--accent-hover); }

::selection { background: var(--accent-soft); color: var(--ink); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 6px;
}

/* ---------- Hintergrund ---------- */
.aurora {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(52% 42% at 50% -6%, var(--aurora-1), transparent 68%),
    radial-gradient(38% 34% at 92% 8%, var(--aurora-2), transparent 70%),
    linear-gradient(180deg, var(--bg) 30%, var(--bg-2));
}

/* Punktfeld ueber dem Verlauf. Liegt fest im Sichtfenster, nimmt keine
   Zeigerereignisse an und bleibt hinter allem Inhalt. Ohne JavaScript bleibt
   die Flaeche leer und der Verlauf darunter steht fuer sich - deshalb traegt
   der Verlauf weiterhin die Grundstimmung und nicht das Canvas. */
.backdrop {
  position: fixed;
  inset: 0;
  z-index: 0;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* ---------- Skiplink ---------- */
.skiplink {
  position: absolute;
  top: .6rem;
  left: 50%;
  z-index: 100;
  transform: translate(-50%, -220%);
  padding: .65rem 1.1rem;
  border-radius: var(--r-sm);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: .85rem;
  font-weight: 600;
  text-decoration: none;
  transition: transform .2s var(--ease);
}
.skiplink:focus-visible { transform: translate(-50%, 0); color: var(--accent-ink); }

/* ---------- Kopfzeile ---------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  height: 56px;
  padding: 0 clamp(1rem, 4vw, 1.75rem);
  border-bottom: 1px solid transparent;
  transition: border-color .25s var(--ease), background .25s var(--ease);
}
.topbar.is-stuck {
  border-bottom-color: var(--line);
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
}

.wordmark {
  /* Gleicher Grund wie in der Fusszeile: 22 Pixel Zeilenhoehe sind als
     Trefferflaeche zu wenig. */
  padding: .3rem 0;
  font-size: .9rem;
  font-weight: 500;
  color: var(--ink-3);
  text-decoration: none;
  letter-spacing: -.015em;
  white-space: nowrap;
}
.wordmark b { color: var(--ink); font-weight: 650; }
.wordmark:hover { color: var(--ink-2); }

.icon-btn {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  flex: none;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
  transition: background .2s var(--ease), color .2s var(--ease), border-color .2s var(--ease);
}
.icon-btn:hover { background: var(--surface); color: var(--ink); border-color: var(--line-2); }
.icon-btn svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }

/* Nur das jeweils passende Symbol zeigen. */
.icon-btn .i-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .icon-btn .i-sun { display: none; }
  :root:not([data-theme="light"]) .icon-btn .i-moon { display: block; }
}
:root[data-theme="dark"] .icon-btn .i-sun { display: none; }
:root[data-theme="dark"] .icon-btn .i-moon { display: block; }
:root[data-theme="light"] .icon-btn .i-sun { display: block; }
:root[data-theme="light"] .icon-btn .i-moon { display: none; }

/* ---------- Layout ---------- */
.wrap {
  position: relative;
  z-index: 1;
  flex: 1;
  width: 100%;
  max-width: 33rem;
  margin: 0 auto;
  padding: clamp(2rem, 7vh, 4.5rem) clamp(1.1rem, 4vw, 1.75rem) 3rem;
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
}
.wrap.wide { max-width: 44rem; }

/* ---------- Einleitung ---------- */
.intro { text-align: center; }

h1 {
  font-size: clamp(1.95rem, 6.5vw, 2.6rem);
  font-weight: 640;
  line-height: 1.1;
  letter-spacing: -.033em;
  text-wrap: balance;
}
.lede {
  margin: .8rem auto 0;
  max-width: 30rem;
  font-size: .96rem;
  color: var(--ink-2);
  text-wrap: pretty;
}

/* ---------- Karte ---------- */
.card {
  position: relative;
  /* Luft nach oben fuer das Maskottchen, das hinter der Oberkante hervorkommt.
     Ohne sie ragt es in die Ueberschrift. Der Abstand steht hier und nicht am
     Zwischenraum des Layouts, weil nur diese Seite eine Karte hat. */
  margin-top: 2.6rem;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  padding: clamp(1.35rem, 5vw, 2rem);
}

/* ---------- Maskottchen ---------- */

/* Der Ausschnitt sitzt direkt ueber der Karte und schneidet unten ab. Der
   Baer wird darin von unten hochgefahren - dadurch wirkt es, als lugte er
   hinter der Karte hervor, ohne dass es dafuer eine zweite Ebene braucht.
   Er liegt bewusst rechts: mittig wuerde er in die Ueberschrift ragen. */
.peek {
  position: absolute;
  right: 1.9rem;
  bottom: 100%;
  width: 92px;
  height: 68px;
  overflow: hidden;
  pointer-events: none;
}

.peek .bear {
  width: 100%;
  height: auto;
  transform: translateY(100%);
  transition: transform .5s var(--ease);
}
/* Weit genug hoch, dass Nase und Mund mitkommen - nur mit Augen wirkte er
   wie abgeschnitten statt wie hervorlugend. */
.peek.is-up .bear { transform: translateY(6%); }

/* Ohne JavaScript bleibt die Klasse aus und der Ausschnitt leer - der Baer
   ist dann schlicht nicht da, nichts bricht. */

.bear-fur   { fill: var(--bear); }
.bear-ear   { fill: var(--bear); }
.bear-ear-in { fill: var(--bear-shade); }
.bear-snout { fill: var(--bear-snout); }
.bear-nose  { fill: var(--bear-ink); }
.bear-paw   { fill: var(--bear); stroke: var(--bear-shade); stroke-width: 1.5; }
.bear-eye   { fill: #fdfaf5; }
.bear-pupil { fill: var(--bear-ink); }
.bear-mouth {
  fill: none;
  stroke: var(--bear-ink);
  stroke-width: 2.2;
  stroke-linecap: round;
}

/* Kopf und Pupillen werden per Skript gesetzt; die Uebergaenge hier machen
   daraus eine weiche Bewegung statt eines Sprungs je Ereignis.
   Der Kopf dreht um den Hals, nicht um seine Mitte - sonst rutscht er beim
   Neigen seitlich vom Koerper. */
.bear-head  { transition: transform .25s var(--ease); transform-origin: 60px 92px; }
.bear-pupil { transition: transform .12s linear; }
.bear-paws  { transition: transform .35s var(--ease); }

/* Freude nach erfolgreichem Versand: zweimal kurz hochschnellen. */
.peek.is-cheer .bear-body { animation: bear-hop .45s var(--ease) 2; }
@keyframes bear-hop {
  0%, 100% { transform: translateY(0); }
  40%      { transform: translateY(-7px); }
}

/* Bestaetigter Regler: einmal zwinkern und zufrieden nicken. Das Zwinkern
   drueckt nur das rechte Auge zu - beide waeren ein Blinzeln. */
.bear-eye-r { transition: transform .1s var(--ease); transform-origin: 77px 55px; }
.peek.is-winking .bear-eye-r { transform: scaleY(.08); }

.bear-head-anim { transform-origin: 60px 92px; }
.peek.is-nodding .bear-head-anim { animation: bear-nod .4s var(--ease) 2; }
@keyframes bear-nod {
  0%, 100% { transform: translateY(0) rotate(0); }
  50%      { transform: translateY(3px) rotate(3deg); }
}

/* Winken nach dem Versand: die rechte Pfote faehrt neben den Kopf und
   schwenkt. Sie dreht um ihr unteres Ende, damit die Bewegung aus dem Arm
   kommt und nicht aus der Mitte der Pfote. */
.bear-paw-r { transform-origin: 84px 164px; }
.peek.is-waving .bear-paw-r { animation: bear-wave .6s var(--ease) 3; }
@keyframes bear-wave {
  /* Auch nach rechts versetzt: senkrecht hochgefahren laege die Pfote mitten
     auf der Wange statt neben dem Kopf. */
  0%, 100% { transform: translate(11px, -72px) rotate(-14deg); }
  50%      { transform: translate(15px, -79px) rotate(16deg); }
}

/* Blinzeln und Augenzuhalten: die Lider sind die Augen selbst, flach
   gedrueckt um ihre eigene Mitte. */
.bear-eyes { transition: transform .09s var(--ease); transform-origin: 60px 55px; }
.peek.is-blinking .bear-eyes { transform: scaleY(.1); }
/* Von y=150 auf Augenhoehe y=55 - die Pfoten liegen im SVG hinter dem Kopf
   und werden zuletzt gezeichnet, decken die Augen also wirklich ab. */
.peek.is-shy .bear-paws { transform: translateY(-95px); }

form { display: flex; flex-direction: column; gap: .8rem; }

/* ---------- Felder mit schwebendem Label ---------- */
.field { position: relative; }

.field input,
.field textarea {
  width: 100%;
  font: inherit;
  font-size: 1rem;              /* 16px verhindert das Zoomen auf iOS */
  color: var(--ink);
  background: var(--field);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 1.6rem .95rem .62rem;
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease), background .18s var(--ease);
}
.field textarea {
  min-height: 9.5rem;
  max-height: 22rem;
  padding-top: 1.75rem;
  line-height: 1.6;
  /* Kein Anfasser: das Feld waechst selbst mit dem Text (siehe app.js). Der
     native Anfasser sass ausserdem auf dem Rollbalken und sah ramponiert aus. */
  resize: none;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--line-2) transparent;
}

/* Schlanker Rollbalken statt des klobigen Systembalkens mit Pfeiltasten. */
.field textarea::-webkit-scrollbar { width: 10px; }
.field textarea::-webkit-scrollbar-track { background: transparent; }
.field textarea::-webkit-scrollbar-thumb {
  background: var(--line-2);
  border-radius: 99px;
  /* Rand in Feldfarbe laesst den Griff schmaler wirken, ohne die Trefferflaeche
     zu verkleinern. */
  border: 3px solid var(--field);
}
.field textarea:focus::-webkit-scrollbar-thumb { border-color: var(--field-focus); }
.field textarea::-webkit-scrollbar-thumb:hover { background: var(--ink-3); }

/* Der gescrollte Text lief bisher unter dem schwebenden Label hindurch und
   ueberlagerte es. Dieser Streifen in Feldfarbe deckt den Bereich ab; Label
   und Zaehler liegen darueber. */
.field--area::before {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  right: 2px;
  /* Genau so hoch wie der obere Innenabstand des Feldes: der Streifen endet
     dort, wo die erste Textzeile beginnt. Ein weicher Verlauf stattdessen
     liess den weggescrollten Text als Schemen hinter dem Label stehen. */
  height: 1.95rem;
  border-radius: var(--r-md) var(--r-md) 0 0;
  background: var(--field);
  pointer-events: none;
  /* Ohne eigenen z-index malt der Browser den Feldinhalt darueber. */
  z-index: 1;
  transition: background .18s var(--ease);
}
.field--area:focus-within::before { background: var(--field-focus); }
.field--area label,
.field--area .counter { z-index: 2; }

.field label {
  position: absolute;
  top: .52rem;
  left: .98rem;
  font-size: .715rem;
  font-weight: 550;
  color: var(--ink-3);
  letter-spacing: .005em;
  pointer-events: none;
  transform-origin: left top;
  transition: transform .18s var(--ease), color .18s var(--ease);
}
/* Leeres, unfokussiertes Feld: Label sitzt gross in der Feldmitte. */
.field input:placeholder-shown:not(:focus) ~ label,
.field textarea:placeholder-shown:not(:focus) ~ label {
  transform: translateY(.6rem) scale(1.31);
  color: var(--ink-3);
}
.field textarea:placeholder-shown:not(:focus) ~ label {
  transform: translateY(.62rem) scale(1.31);
}

.field input:hover,
.field textarea:hover { border-color: var(--line-2); }

.field input:focus,
.field textarea:focus {
  outline: none;
  background: var(--field-focus);
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-glow);
}
.field:focus-within label { color: var(--accent); }

.field.is-invalid input,
.field.is-invalid textarea {
  border-color: var(--err);
  box-shadow: 0 0 0 3px var(--err-soft);
}
.field.is-invalid label,
.field.is-invalid:focus-within label { color: var(--err); }

.counter {
  position: absolute;
  top: .55rem;
  right: .95rem;
  font-family: var(--mono);
  font-size: .68rem;
  color: var(--ink-3);
  opacity: 0;
  transition: opacity .2s var(--ease), color .2s var(--ease);
  pointer-events: none;
}
.field:focus-within .counter,
.counter.is-visible { opacity: 1; }
.counter.is-near { color: var(--err); }

.msg {
  display: flex;
  align-items: center;
  gap: .35rem;
  margin: .38rem 0 0 .2rem;
  font-size: .78rem;
  color: var(--err);
}
.msg svg { width: 13px; height: 13px; flex: none; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* Honeypots: fuer Menschen und Screenreader unerreichbar, fuer Bots sichtbar. */
.hp {
  position: absolute !important;
  left: -9999px !important;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- Slider-Captcha ---------- */
.slider {
  position: relative;
  height: 54px;
  margin-top: .15rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--field);
  overflow: hidden;
  /* Nur die waagerechte Geste abfangen. Mit "none" verschluckte der Regler
     auch das senkrechte Wischen - wer auf dem Handy mit dem Finger genau
     hier ansetzte, um die Seite zu scrollen, kam nicht vom Fleck. */
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
  cursor: default;
}
.slider[aria-disabled="true"] { opacity: .6; }

/* Gleiche Einrückung und Rundung wie der Knopf: in Ruhestellung liegt der
   Balken exakt unter ihm und ist dadurch unsichtbar. Vorher lief er über die
   volle Höhe ab Position 0 und schaute oben, unten und links um den Knopf
   herum – das ergab den sichtbaren Kasten am linken Rand. */
.slider-fill {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 4px;
  width: 0;
  border-radius: 10px;
  background: linear-gradient(90deg, var(--accent-soft), var(--accent-glow));
}

.slider-text {
  position: absolute;
  inset: 0 .8rem 0 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  font-size: .855rem;
  color: var(--ink-3);
  pointer-events: none;
  transition: opacity .2s var(--ease);
}
.slider-text svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }

.slider-done {
  color: var(--ok);
  font-weight: 600;
  opacity: 0;
}
.slider.is-done .slider-hint { opacity: 0; }
.slider.is-done .slider-done { opacity: 1; }
.slider.is-done { border-color: color-mix(in srgb, var(--ok) 45%, transparent); }
.slider.is-done .slider-fill { width: calc(100% - 8px) !important; }

.slider-knob {
  position: absolute;
  top: 4px;
  left: 4px;
  width: 46px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  background: var(--accent);
  color: var(--accent-ink);
  box-shadow: var(--shadow-1);
  cursor: grab;
  will-change: transform;
}
.slider-knob:active { cursor: grabbing; }
.slider.is-done .slider-knob { background: var(--ok); cursor: default; }
.slider-knob svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }

/* Nur beim Zurueckschnappen animieren, waehrend des Ziehens nie. */
.slider.is-animating .slider-knob,
.slider.is-animating .slider-fill { transition: transform .3s var(--ease), width .3s var(--ease); }

.slider.is-loading .slider-hint { opacity: .6; }
.slider.is-loading::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, var(--accent-soft), transparent);
  animation: shimmer 1.4s linear infinite;
  pointer-events: none;
}
@keyframes shimmer {
  from { transform: translateX(-100%); }
  to { transform: translateX(100%); }
}

/* ---------- Turnstile ----------
   Alternative zum Regler. Solange das Widget nicht geladen ist, steht hier
   ein Platzhalter im Look des Reglers. Er reserviert genau die Hoehe, die
   das Widget spaeter braucht (65 px bei "flexible", 140 px bei "compact"),
   damit beim Einsetzen nichts springt. Sobald das Widget steht, verliert
   der Kasten Rahmen und Flaeche - das iframe bringt beides selbst mit, und
   zwei ineinanderliegende Rahmen saehen nach Fehler aus. */
.turnstile {
  position: relative;
  min-height: 65px;
  margin-top: .15rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--field);
  overflow: hidden;
}
.turnstile.is-compact { min-height: 140px; }

/* Das Widget sitzt in einem geschlossenen Shadow Root im Container und
   setzt seine Masse per Skript. Mehr als die Breite zu begrenzen ist hier
   weder moeglich noch noetig. */
.turnstile-widget { max-width: 100%; }
.turnstile-widget iframe { max-width: 100%; }

.turnstile-note {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .3rem;
  padding: .55rem 1rem;
  font-size: .82rem;
  line-height: 1.45;
  text-align: center;
  color: var(--ink-3);
  pointer-events: none;
}
.turnstile-note a,
.turnstile-note button { pointer-events: auto; }
.turnstile-alt { font-size: .76rem; }
.turnstile-alt a { color: var(--ink-2); }

.turnstile-retry {
  font: inherit;
  font-size: .78rem;
  font-weight: 600;
  color: var(--accent);
  background: none;
  border: 0;
  border-radius: 6px;
  padding: .15rem .4rem;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.turnstile-retry:hover { color: var(--accent-hover); }
.turnstile-retry:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Gerendert: nur noch das Widget, die Notiz tritt zurueck. */
.turnstile.is-rendered {
  border-color: transparent;
  background: transparent;
  overflow: visible;
}
.turnstile.is-rendered:not(.is-error) .turnstile-note { display: none; }

.turnstile.is-loading::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, var(--accent-soft), transparent);
  animation: shimmer 1.4s linear infinite;
  pointer-events: none;
}

/* Fehler: Hinweis und "Erneut versuchen" im Kasten. Laeuft das Widget noch
   (automatische Wiederholung von Turnstile), steht die Meldung darunter
   statt darueber - sonst verdeckte sie genau das, was gerade passiert. */
.turnstile.is-error {
  border-color: color-mix(in srgb, var(--err) 40%, transparent);
  background: var(--err-soft);
}
.turnstile.is-error .turnstile-text { color: var(--err); font-weight: 500; }
.turnstile.is-error.is-rendered {
  border-color: transparent;
  background: transparent;
}
.turnstile.is-error.is-rendered .turnstile-note {
  position: static;
  padding: .5rem .2rem 0;
}

/* ---------- Buttons ---------- */
.btn {
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  width: 100%;
  min-height: 50px;
  margin-top: .3rem;
  padding: .85rem 1.2rem;
  font: inherit;
  font-size: .95rem;
  font-weight: 600;
  letter-spacing: -.008em;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  background: var(--accent);
  color: var(--accent-ink);
  cursor: pointer;
  transition: background .18s var(--ease), transform .12s var(--ease), opacity .18s var(--ease);
}
.btn:hover { background: var(--accent-hover); }
.btn:active { transform: scale(.985); }
.btn[disabled] { opacity: .5; cursor: not-allowed; transform: none; }
.btn svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }

.btn.ghost {
  background: transparent;
  color: var(--ink-2);
  border-color: var(--line);
}
.btn.ghost:hover { background: var(--field); color: var(--ink); border-color: var(--line-2); }

.btn .spinner { display: none; }
.btn.is-busy .spinner { display: block; }
.btn.is-busy .btn-icon { display: none; }

.spinner {
  width: 15px;
  height: 15px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin .6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- Statuszeile ---------- */
.status {
  margin-top: .1rem;
  font-size: .83rem;
  font-weight: 500;
  text-align: center;
  color: var(--ink-2);
}
.status:empty { display: none; }
.status.is-err { color: var(--err); }
.status.is-ok { color: var(--ok); }

.fineprint {
  margin-top: .3rem;
  font-size: .74rem;
  line-height: 1.5;
  color: var(--ink-3);
  text-align: center;
}
.fineprint a { color: var(--ink-2); }

/* ---------- Bestaetigung nach dem Senden ---------- */
.sent {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: .55rem;
  padding: 1.4rem .5rem .6rem;
  animation: rise .5s var(--ease) both;
}
.sent-badge {
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  margin-bottom: .5rem;
  border-radius: 50%;
  background: var(--ok-soft);
  color: var(--ok);
}
.sent-badge svg { width: 26px; height: 26px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.sent-badge path {
  stroke-dasharray: 26;
  stroke-dashoffset: 26;
  animation: draw .5s var(--ease) .15s forwards;
}
@keyframes draw { to { stroke-dashoffset: 0; } }
.sent h2 { font-size: 1.15rem; font-weight: 620; letter-spacing: -.02em; }
.sent p { font-size: .9rem; color: var(--ink-2); max-width: 24rem; }
.sent .btn { width: auto; margin-top: 1rem; }

@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

/* ---------- Fusszeile ---------- */
.foot {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: .55rem;
  padding: 1.2rem 1.2rem 2rem;
  font-size: .755rem;
  color: var(--ink-3);
}
/* Innenabstand nur fuer die Trefferflaeche: die Zeile ist 19 Pixel hoch und
   liegt damit unter dem Mindestmass von 24. Sichtbar aendert sich nichts. */
.foot a { color: var(--ink-3); text-decoration: none; padding: .35rem .2rem; }
.foot a:hover { color: var(--ink); text-decoration: underline; }
.foot span { opacity: .45; }

/* ---------- Fliesstext (Impressum, Datenschutz, 404) ---------- */
.prose {
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--surface);
  box-shadow: var(--shadow-1);
  padding: clamp(1.5rem, 5vw, 2.4rem);
  font-size: .91rem;
  line-height: 1.68;
  color: var(--ink-2);
}
.prose h1 { font-size: clamp(1.5rem, 4.5vw, 1.9rem); color: var(--ink); margin-bottom: 1.4rem; }
.prose h2 {
  margin: 1.9rem 0 .5rem;
  font-size: .96rem;
  font-weight: 620;
  letter-spacing: -.012em;
  color: var(--ink);
}
/* Nur wenn die Überschrift unmittelbar auf den Titel folgt. Mit
   :first-of-type verlor sie ihren Abstand auch dann, wenn ein Absatz
   dazwischenstand - die Überschrift klebte dann am Text darüber. */
/* Sprungziele (z. B. #turnstile aus dem Formular) nicht unter der
   fixierten Kopfzeile verstecken. */
.prose h2[id] { scroll-margin-top: 5.5rem; }
.prose h1 + h2 { margin-top: 0; }
.prose p + p { margin-top: .75rem; }
.prose ul { margin: .5rem 0 .5rem 1.15rem; }
.prose li { margin-bottom: .3rem; }
/* Eigener Abstand, weil die Regel "p + p" durch ein dazwischenstehendes
   address nicht greift und der Block sonst am Fliesstext klebt. */
.prose address { font-style: normal; margin: .6rem 0; }

/* ---------- E-Mail-Adresse gegen automatisiertes Auslesen ----------
   Hier steht bewusst KEINE Regel. Die Fuellstuecke in der Adresse stecken in
   <template>-Elementen und sind damit schon nach HTML-Standard inert: kein
   Rendering, kein Eintrag im Accessibility-Tree, nichts in der Zwischenablage.
   Das haengt an keinem Stylesheet - faellt diese Datei aus, bleibt die
   angezeigte Adresse trotzdem richtig. Eine CSS-Loesung (display:none) haette
   genau diese Schwaeche gehabt: ohne Stylesheet erschienen die Fuellstuecke
   mitten in der Adresse und das Impressum zeigte eine falsche.

   Warum ueberhaupt sichtbarer Klartext: Das LG Frankfurt a. M. hat am
   05.03.2025 (2-06 O 38/25) entschieden, dass ein mailto-Link allein die
   Adresse nicht "leicht erkennbar und unmittelbar erreichbar" macht. Grafik
   und reine JavaScript-Loesung scheiden aus demselben Grund aus.

   Grenze der Methode: Ein Scraper, der die Seite in einem echten Browser
   rendert und innerText liest, bekommt die Adresse trotzdem. Dagegen hilft
   keine Technik, die sie gleichzeitig lesbar laesst. */
.prose .meta {
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
  font-family: var(--mono);
  font-size: .72rem;
  color: var(--ink-3);
}

.backlink {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: .84rem;
  color: var(--ink-3);
  text-decoration: none;
}
.backlink:hover { color: var(--ink); }
.backlink svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- Ohne JavaScript ---------- */
.noscript {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  padding: 1.1rem 1.3rem;
  font-size: .875rem;
  line-height: 1.6;
  color: var(--ink-2);
  text-align: center;
}

/* ---------- Setup-Seite ----------
   Gleiche Bausteine wie das Formular (Felder, Buttons, Karten); hier nur,
   was es dort nicht gibt: Gruppen, Segmentauswahl, Ampel und Hinweise. */
.setup { gap: 1.25rem; }
.setup .lede { text-align: center; }
.setup-lede { margin-top: -.6rem; }

/* Die Karte des Formulars haelt oben Platz fuer das Maskottchen frei -
   das gibt es hier nicht. */
.setup .card { margin-top: 0; }
.setup-card h2:first-child { margin-top: 0; }

.setup code,
.setup-code {
  font-family: var(--mono);
  font-size: .86em;
  padding: .08rem .32rem;
  border-radius: 6px;
  background: var(--field);
  border: 1px solid var(--line);
  color: var(--ink);
  overflow-wrap: anywhere;
}
.setup-code {
  display: block;
  margin-top: .7rem;
  padding: .8rem 1rem;
  white-space: pre;
  overflow-x: auto;
  line-height: 1.55;
}
.setup-code code { padding: 0; border: 0; background: none; font-size: inherit; }

.setup-steps { margin: .5rem 0 .75rem 1.15rem; }
.setup-steps li { margin-bottom: .35rem; }

.setup-help {
  margin: -.35rem 0 0 .2rem;
  font-size: .78rem;
  line-height: 1.5;
  color: var(--ink-3);
}
.setup-help a { color: var(--ink-2); }

/* Hinweise: Ergebnis einer Pruefung, Warnungen, Fehlerliste. */
.setup-alert {
  border: 1px solid var(--line);
  border-left-width: 3px;
  border-radius: var(--r-md);
  background: var(--surface);
  padding: .8rem 1rem;
  font-size: .86rem;
  line-height: 1.55;
  color: var(--ink-2);
}
.setup-alert ul { margin: .35rem 0 0 1.1rem; }
.setup-alert a { color: inherit; }
.setup-alert.is-ok   { border-left-color: var(--ok); background: color-mix(in srgb, var(--ok-soft) 60%, var(--surface)); }
.setup-alert.is-warn { border-left-color: #b7791f; }
.setup-alert.is-fail { border-left-color: var(--err); background: color-mix(in srgb, var(--err-soft) 70%, var(--surface)); color: var(--ink); }
.setup-inline-btn { width: auto; min-height: 40px; margin-top: .6rem; padding: .5rem .95rem; font-size: .86rem; }

/* Ampel der Systempruefung */
/* Doppelte Klasse: .prose ul ist sonst spezifischer und rueckt die Liste ein. */
.setup-checks.setup-checks {
  list-style: none;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13.5rem, 1fr));
  gap: .55rem 1.2rem;
}
.setup-checks li {
  margin: 0;
  display: grid;
  grid-template-columns: 10px 1fr;
  column-gap: .65rem;
  align-items: baseline;
}
.setup-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--ok);
  transform: translateY(-1px);
}
.setup-checks .is-warn .setup-dot { background: #d69e2e; }
.setup-checks .is-fail .setup-dot { background: var(--err); }
.setup-check-label { color: var(--ink); }
.setup-check-detail { grid-column: 2; font-size: .8rem; color: var(--ink-3); }
.setup-checks .is-fail .setup-check-detail { color: var(--err); }

/* Formular */
.setup-form { display: flex; flex-direction: column; gap: 1.6rem; }
.setup-group {
  display: flex;
  flex-direction: column;
  gap: .8rem;
  border: 0;
  min-width: 0;   /* fieldset waechst sonst mit langen Inhalten ueber den Rand */
}
.setup-group > legend {
  display: flex;
  align-items: center;
  gap: .55rem;
  margin-bottom: .2rem;
  font-size: 1rem;
  font-weight: 620;
  letter-spacing: -.012em;
  color: var(--ink);
}
.setup-step {
  display: inline-grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: .78rem;
  font-weight: 700;
}
.setup-group + .setup-group { padding-top: 1.4rem; border-top: 1px solid var(--line); }

.setup-row { display: grid; grid-template-columns: 1fr 7.5rem; gap: .8rem; align-items: start; }

.setup-area textarea { min-height: 5.5rem; }

/* Segmentauswahl aus echten Radiobuttons */
.setup-choice { border: 0; min-width: 0; display: flex; flex-direction: column; gap: .45rem; }
.setup-choice > legend { font-size: .78rem; font-weight: 550; color: var(--ink-3); margin: 0 0 .45rem .2rem; }
.setup-options { display: flex; flex-wrap: wrap; gap: .45rem; }
.setup-options label { position: relative; cursor: pointer; }
.setup-options input {
  position: absolute;
  opacity: 0;
  inset: 0;
  margin: 0;
  cursor: pointer;
}
.setup-options span {
  display: inline-flex;
  align-items: baseline;
  gap: .35rem;
  min-height: 40px;
  align-items: center;
  padding: .45rem .9rem;
  border: 1px solid var(--line);
  border-radius: 99px;
  background: var(--field);
  font-size: .86rem;
  font-weight: 550;
  color: var(--ink-2);
  transition: border-color .18s var(--ease), background .18s var(--ease), color .18s var(--ease);
}
.setup-options small { font-size: .74rem; font-weight: 450; color: var(--ink-3); }
.setup-options label:hover span { border-color: var(--line-2); }
.setup-options input:checked + span {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--ink);
}
.setup-options input:checked + span small { color: var(--ink-2); }
.setup-options input:focus-visible + span { box-shadow: 0 0 0 3px var(--accent-glow); border-color: var(--accent); }
.setup-choice.is-invalid .setup-options span { border-color: var(--err); }

/* Turnstile-Schluessel nur, wenn Turnstile gewaehlt ist. Ohne :has()-
   Unterstuetzung bleiben sie einfach stehen - kein Schaden. */
.setup-form:has(input[name="captcha_provider"][value="turnstile"]:not(:checked)) .setup-turnstile { display: none; }
.setup-turnstile { display: flex; flex-direction: column; gap: .8rem; }

.setup-check {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .65rem;
  align-items: start;
  font-size: .9rem;
  color: var(--ink);
  cursor: pointer;
}
.setup-check input { width: 18px; height: 18px; margin-top: .15rem; accent-color: var(--accent); }
.setup-check small { display: block; margin-top: .1rem; font-size: .78rem; color: var(--ink-3); }

.setup-actions { display: flex; flex-wrap: wrap; gap: .5rem; }
.setup-actions .setup-inline-btn { margin-top: 0; }

.setup-submit { display: flex; flex-direction: column; gap: .5rem; }
.setup-submit .btn { margin-top: 0; }

.setup-unlock { display: flex; flex-direction: column; gap: .8rem; margin-top: 1.2rem; }
.setup-unlock .setup-help { margin-top: -.45rem; }

/* Vorgabe fuer die Eingabetaste: im Formular vorhanden, aber unsichtbar
   und nicht per Tabulator erreichbar. display:none wuerde manche Browser
   den Knopf als Vorgabe ignorieren lassen. */
.setup-default {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  border: 0;
  padding: 0;
}

@media (max-width: 480px) {
  .setup-row { grid-template-columns: 1fr 5.5rem; }
}

/* ---------- Feinschliff ---------- */
@media (min-width: 1600px) {
  body { font-size: 17px; }
  .wrap { max-width: 36rem; }
}

@media (max-width: 380px) {
  .slider-text { inset: 0 .6rem 0 50px; font-size: .8rem; }
  .slider-knob { width: 42px; }
}

/* Auf Zeigegeraeten ohne Hover keine haengenden Hover-Zustaende. */
@media (hover: none) {
  /* Auf Zeigegeraeten ohne Maus grosszuegiger: 36 Pixel trifft man mit dem
     Finger schlecht. */
  .icon-btn { width: 44px; height: 44px; }
  .btn:hover { background: var(--accent); }
  .btn.ghost:hover { background: transparent; color: var(--ink-2); }
  .icon-btn:hover { background: transparent; color: var(--ink-2); }
  .foot a:hover { color: var(--ink-3); text-decoration: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* Ein Tier, dessen Blick staendig wandert, ist genau die Bewegung, die
     hier unerwuenscht ist. Das Skript startet ohnehin nicht; die Regel
     stellt sicher, dass auch nichts aufblitzt. */
  .peek { display: none; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .sent-badge path { stroke-dashoffset: 0; }
}

@media (prefers-contrast: more) {
  :root { --line: rgba(20, 24, 28, .35); --line-2: rgba(20, 24, 28, .55); --ink-3: #5c6269; }
}

@media print {
  .aurora, .topbar, .foot, .skiplink, .btn { display: none; }
  body { background: #fff; color: #000; }
  .prose, .card { border: none; box-shadow: none; padding: 0; }
}
