/* ============================================================
   Schriften — selbst gehostet, nicht ueber Googles CDN
   Die Seite lief in der Systemschrift: auf einem Mac SF, auf Windows
   Segoe, auf Android Roboto. Drei verschiedene Marken auf derselben
   Seite, und keine davon unsere. Instrument Sans traegt jetzt die
   Stimme, JetBrains Mono die Codes — dort, wo der Zugangscode SELBST
   das Produkt ist, verdient er eine Schrift, die das zeigt.

   Selbst gehostet, weil eine Einbindung ueber fonts.googleapis.com die
   IP jedes Besuchers an Google sendet. Bei einer Seite mit Impressum
   und deutschen Kunden ist das kein Detail, sondern abmahnfaehig
   (LG Muenchen I, 3 O 17493/20). Beide Familien sind variabel,
   zusammen 82 KB, mit font-display: swap.
   ============================================================ */
@font-face {
  font-family: "Instrument Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/instrument-sans-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Instrument Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/instrument-sans-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/jetbrains-mono-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/jetbrains-mono-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ============================================================
   Symbolarity — Marken-Fundament

   Die Seite ist schwarzweiss wie das Logo. Keine Markenfarbe —
   die Hierarchie laeuft ueber HELLIGKEIT, und genau dadurch faellt
   jede Farbe auf, die doch auftaucht. Farbe ist hier kein Schmuck
   mehr, sondern eine Aussage.

   Rollen, streng getrennt:
     Weiss     = Marke UND Aufmerksamkeit. Etiketten, Links, Fokus,
                 Logo, Kaufknopf, das Band der Schluesselkarte, der
                 Vertrauenskasten.
     Grau      = alles Untergeordnete. Drei Stufen, mehr nicht.
     Silber    = --silber, der Verlauf des Logos. Nur dort, wo
                 Material gemeint ist: Hero-Zeile, Chip der Karte.
     Gruen     = bezahlt. Rot = fehlgeschlagen. Sonst nirgends.
     Produkt   = nur die kleinen Produktzeichen.

   Kein Violett, kein Leuchtschatten, kein Verlauf im Fliesstext.
   Tiefe entsteht ueber hellere Flaechen, nicht ueber schwarze
   Schatten.

   Weisse Flaeche heisst SCHWARZE Schrift (var(--bg)) — nicht #fff.
   Und filter: brightness() ueber 1 tut auf Weiss nichts: ein Hover
   auf einer weissen Flaeche muss abdunkeln.
   ============================================================ */

:root {
  /* ---- Grund: die Kachel des Logos ----
     #0a0a0b ist exakt der Grund des Favicons. Die Seite steht damit auf
     demselben Schwarz, auf dem der Funke sitzt. */
  --bg: #0a0a0b;
  --bg-1: #131315;
  --bg-2: #1c1c1f;
  --line: rgba(255, 255, 255, 0.1);
  --line-2: rgba(255, 255, 255, 0.18);
  --text: #f4f4f5;
  --muted: #a3a3a6;
  --faint: #86868a;

  /* ---- Die Marke ist Weiss ----
     Kein Farbton, nur Helligkeit. 20,4:1 auf dem Grund — mehr Kontrast
     gibt es nicht. Hierarchie entsteht ueber WERT statt Farbe: Weiss
     traegt, Grau ordnet sich unter, und wenn irgendwo Farbe auftaucht,
     bedeutet sie etwas. */
  --brand: #ffffff;
  --brand-dim: rgba(255, 255, 255, 0.1);
  --brand-tief: #8e8e92;

  /* Der Verlauf des Logos, Zeichen fuer Zeichen: dieselben Werte wie im
     Favicon. Traegt die Hero-Zeile und den Code auf der Karte. */
  --silber: linear-gradient(168deg, #8e8e8e 0%, #ffffff 46%, #7a7a7a 100%);

  /* ---- Farbe bedeutet etwas ----
     Diese drei sind die EINZIGEN Farbtoene der Marke. Sie stehen nie
     dekorativ, immer als Zustand. */
  --ok: #4ec97f;      /* bezahlt, verfuegbar */
  --bad: #ff6b6b;     /* fehlgeschlagen */
  --warn: #ffffff;    /* wartend ist weder gut noch schlecht: neutral */

  /* Produktfarben — fremde Marken auf kleinen Zeichen, sonst nirgends.
     Abgeleitet aus den eBay-Thumbnails (Thumbnails/), damit Karte und
     Angebotsbild dasselbe Produkt behaupten: die gruene Eule, das blaue
     MAX, das violette Nitro-Neon. Alle drei sind auf ~4,3:1 gegen ihren
     eigenen Kartenlack getrimmt — gleich laut, damit keine Karte
     vorlaut wird, und ueber den 3:1 fuer Grafikelemente. Wer einen Ton
     nachzieht, muss den Kontrast neu messen: die Zeichen sind
     1,6px-Striche, da traegt Helligkeit alles. */
  --nitro: #d75eff;
  --duo: #47ab00;
  --max: #6190ff;
  --yt: #cc2b3d;

  /* Die Karte: schwarzer Lack wie die Logokachel, Code in Silber. */
  --lack: #191919;
  --lack-tief: #0d0d0e;
  --holo: linear-gradient(135deg, #4a4a4a, #ffffff 52%, #3a3a3a);

  /* ---- Hoehenstufen ----
     Schwarze Schatten sind auf dunklem Grund unsichtbar. Hoehe entsteht
     ueber hellere Flaechen plus eine beleuchtete Oberkante. */
  --e0: #0a0a0b;
  --e1: #131315;
  --e2: #1c1c1f;
  --e3: #26262a;
  --kante: inset 0 1px 0 rgba(255, 255, 255, 0.07);
  --kante-stark: inset 0 1px 0 rgba(255, 255, 255, 0.11);
  --tiefe: 0 18px 40px -28px rgba(0, 0, 0, 0.9);

  /* ---- Groessen ---- Modulare Skala, Verhaeltnis 1,25, Basis 16px. */
  --t-xs: 0.78rem;
  --t-sm: 0.875rem;
  --t-md: 1rem;
  --t-lg: 1.25rem;
  --t-xl: clamp(1.4rem, 1.1rem + 1.1vw, 1.563rem);
  --t-2xl: clamp(1.7rem, 1.2rem + 2vw, 1.953rem);
  --t-3xl: clamp(2rem, 1.3rem + 3vw, 2.441rem);
  --t-4xl: clamp(2.4rem, 1.4rem + 4.4vw, 3.052rem);

  /* ---- Abstaende ---- Vielfache von 4px. */
  --s-1: 4px;  --s-2: 8px;   --s-3: 12px; --s-4: 16px;
  --s-5: 24px; --s-6: 32px;  --s-7: 48px; --s-8: 64px;
  --s-9: 96px;

  --r: 10px;
  --maxw: 1120px;
  --sans: "Instrument Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo, "Cascadia Mono", monospace;
}

::selection { background: rgba(255, 255, 255, 0.22); color: #fff; }

/* ---- Scrollbar ----
   Die Systemleiste war das einzige helle Element, das nicht aus dieser
   Palette kam. Schmal, dunkel, ohne eigene Flaeche — Werkzeug, kein
   Schmuck. */
/* color-scheme sagt dem Browser, dass diese Seite dunkel IST. Ohne die
   Zeile rendert er alle NATIVEN Bedienelemente hell — auf /kauf/ war die
   Widerrufs-Checkbox dadurch ein weisses Kaestchen auf schwarzem Grund,
   und zwar auf der Seite, die Geld annimmt. Betrifft ausserdem
   Text-Cursor, Auswahlfarben und die Standard-Scrollbar.
   Gefunden am 06.09.2026 beim Audit gegen die Web Interface Guidelines. */
html { color-scheme: dark; scrollbar-width: thin; scrollbar-color: #2c2c30 transparent; }
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: #26262a; border-radius: 8px;
  border: 3px solid var(--bg);
}
::-webkit-scrollbar-thumb:hover { background: #35353a; }

/* ---- Filmkorn ----
   Nimmt den dunklen Flaechen das Plastikhafte. Statisch, deshalb
   absichtlich nicht unter prefers-reduced-motion. */
body::after {
  content: ""; position: fixed; inset: 0; z-index: 60;
  pointer-events: none; opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
}

/* ---- Tippen ----
   Ohne touch-action wartet mobiles Safari/Chrome nach jedem Tipp rund
   300 ms ab, ob ein zweiter folgt (Doppeltipp-Zoom). Auf einer Seite,
   deren Hauptbedienung Kacheln und Knoepfe sind, fuehlt sich das
   traege an, ohne dass man sagen koennte warum. `manipulation` laesst
   Kneifzoom und Scrollen unangetastet — nur der Doppeltipp-Zoom auf
   genau diesen Elementen faellt weg, und der ist dort nutzlos.
   Ergaenzt am 07.09.2026; beim Audit am 06.09. uebersehen. */
a, button, summary, label, select, [role="button"], input:not([type="text"]):not([type="email"]) {
  touch-action: manipulation;
}

/* ---- Fokus ----
   Vorher gab es auf der ganzen Seite KEINE Fokus-Markierung: Wer mit der
   Tastatur navigiert, sah nicht, wo er steht — auf einer Seite, die zur
   Kasse fuehrt. :focus-visible trifft nur echte Tastaturnutzung, Mausklicks
   bekommen keinen Ring. */
:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
  border-radius: 4px;
}
/* Auf dem hellen Knopf waere der helle Ring unsichtbar. */
.btn-primary:focus-visible,
.cta-buy:focus-visible {
  outline-color: var(--text);
}

/* ---- Sprunglink ----
   Erstes Tab-Ziel der Seite: ueberspringt Kopfzeile und Navigation.
   Sichtbar erst, wenn er den Fokus hat. */
.sprunglink {
  position: absolute; left: var(--s-4); top: var(--s-4); z-index: 100;
  transform: translateY(-200%);
  background: var(--brand); color: var(--bg);
  padding: 10px 16px; border-radius: 8px;
  font-size: var(--t-sm); font-weight: 600;
  transition: transform 0.16s ease;
}
.sprunglink:focus { transform: translateY(0); }

/* ---- Aufklappmenue (schmale Bildschirme) ----
   Unter 900px verschwand die Navigation bisher ERSATZLOS — auf dem Handy
   gab es keinen Weg zu Ablauf oder FAQ. */
.menue-knopf {
  display: none;
  background: none; border: 1px solid var(--line-2); border-radius: 8px;
  color: var(--text); cursor: pointer;
  width: 40px; height: 38px; padding: 0;
  align-items: center; justify-content: center;
}
.menue-knopf svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.menue-knopf .schliessen { display: none; }
.menue-knopf[aria-expanded="true"] .oeffnen { display: none; }
.menue-knopf[aria-expanded="true"] .schliessen { display: block; }

@media (max-width: 900px) {
  .menue-knopf { display: inline-flex; }
}

/* ---- Mono-Etikett ---- */
.eyebrow {
  display: block;
  font-family: var(--mono); font-size: 0.68rem; font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--brand); margin-bottom: 12px;
}

/* ---- Einblenden beim Scrollen ----
   An .js gebunden: Ohne JavaScript wird gar nichts erst versteckt,
   sonst bliebe der Seiteninhalt unsichtbar, wenn das Skript nicht
   laedt. Beide Sichtbar-Klassen (.visible und .in) werden bedient,
   weil die Seiten historisch verschiedene benutzen. */
.js .reveal {
  opacity: 0; transform: translateY(14px);
  transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
.js .reveal.visible, .js .reveal.in { opacity: 1; transform: translateY(0); }
/* ---- Wortweises Einblenden ----
   Der Text baut sich Wort fuer Wort auf, leicht unscharf und von unten.
   Warum das traegt und Dauergeflacker nicht: es passiert EINMAL, beim
   Ankommen, und es folgt der Leserichtung — man liest schon, waehrend es
   noch entsteht. js/motion.js zerlegt die Textknoten und setzt --i.
   Ohne JS und bei prefers-reduced-motion wird gar nicht erst zerlegt. */
.js [data-wortfade] .wort {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.4em);
  filter: blur(5px);
  transition:
    opacity 0.5s ease,
    transform 0.55s cubic-bezier(0.22, 1, 0.36, 1),
    filter 0.5s ease;
  transition-delay: calc(var(--i, 0) * 36ms);
}
.js [data-wortfade].in .wort,
.js [data-wortfade].visible .wort {
  opacity: 1; transform: none; filter: blur(0);
}

/* ---- Zeilen kommen nacheinander ----
   Eine Liste, die auf einen Schlag da ist, wirkt wie ein Sprung. Kaskade
   ueber --i: 70ms Versatz, die Reihenfolge macht das Lesen mit. */
.js [data-staffel] > * {
  opacity: 0; transform: translateY(12px);
  transition:
    opacity 0.55s ease,
    transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.js [data-staffel].in > *,
.js [data-staffel].visible > * { opacity: 1; transform: none; }

/* Die Schrittnummer zuendet, wenn ihre Zeile ankommt — ein Lichtpunkt
   pro Schritt, genau einmal. */
.js [data-staffel].in .schritt-n {
  animation: markeAn 0.75s cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: calc(var(--i, 0) * 70ms + 0.12s);
}
@keyframes markeAn {
  0%   { border-color: var(--brand); box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.4); }
  100% { border-color: var(--line-2); box-shadow: 0 0 0 9px rgba(255, 255, 255, 0); }
}

.delay-1, .d1 { transition-delay: 0.08s; }
.delay-2, .d2 { transition-delay: 0.16s; }
.delay-3, .d3 { transition-delay: 0.24s; }
.d4 { transition-delay: 0.32s; }

/* ---- Logo-Mark: der Funke auf Holo ----
   Dasselbe Zeichen wie im Favicon — das Logo der Marke, nicht ein
   Buchstabe, der so tut. */
/* Der Funke steht fuer sich — kein Kasten, kein Verlauf darunter. */
.brand-mark {
  width: 20px; height: 20px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
}
/* Der Funke bleibt schwarzweiss — dasselbe Zeichen wie im Browsertab.
   Weiss ist die Signalfarbe; das Logo ist kein Signal, es ist der Absender. */
.brand-mark svg { width: 20px; height: 20px; fill: var(--text); display: block; }

/* ---- Der Funke blinkt ----
   Alle 7 Sekunden eine Vierteldrehung mit einem kurzen Aufblitzen in der
   Mitte. Zwei Dinge machen das moeglich, ohne dass es stoert:

   Das Zeichen ist VIERZAEHLIG symmetrisch — nach 90 Grad steht es exakt
   wie vorher. Die Schleife kann also endlos laufen und springt trotzdem
   nie; es gibt keinen Punkt, an dem etwas zurueckschnappt.

   Und sechs der sieben Sekunden steht es still. Eine Bewegung, die
   dauernd laeuft, wird nach zwei Minuten zur Tapete und danach zum
   Aergernis — der Wert liegt gerade darin, dass man sie fast verpasst. */
@keyframes funkeDreht {
  0%, 86% { transform: rotate(0deg)  scale(1); }
  93%     { transform: rotate(52deg) scale(1.16); }
  100%    { transform: rotate(90deg) scale(1); }
}
.brand-mark svg {
  animation: funkeDreht 7s cubic-bezier(0.5, 0, 0.2, 1) infinite;
  transform-origin: 50% 50%;
  will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
  .brand-mark svg { animation: none; }
}

/* ---- Bestell-Banner ----
   Erscheint auf den Marketing-Seiten, wenn im Browser eine offene oder
   bezahlte Bestellung liegt (js/shop.js). Der kleine Laden merkt sich
   seine Kunden — auch nach dem Raustabben. */
.shop-banner {
  position: relative; z-index: 5;
  border-bottom: 1px solid var(--line);
  box-shadow: var(--kante);
  background: rgba(255, 255, 255, 0.06);
}
.shop-banner-inner {
  max-width: var(--maxw); margin: 0 auto;
  padding: 10px 24px;
  display: flex; align-items: center; gap: 10px;
  font-size: 0.85rem; color: var(--muted);
}
.shop-banner-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--warn); flex: none;
}
.shop-banner-dot.is-paid { background: var(--ok); }
.shop-banner-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.shop-banner-link { color: var(--brand); font-weight: 600; white-space: nowrap; }
.shop-banner-close {
  margin-left: auto; background: none; border: 0;
  color: var(--faint); font-size: 1.05rem; cursor: pointer; padding: 4px 6px;
}
.shop-banner-close:hover { color: var(--text); }



/* ---- Lesefortschritt ----
   Sitzt als Haarlinie unten an der Kopfzeile und zeigt, wie weit man
   ist. Zustand, kein Zierstrich. */
.fortschritt {
  position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
  background: var(--brand);
  transform: scaleX(0); transform-origin: 0 50%;
  will-change: transform; pointer-events: none;
}

/* ---- Knopf-Physik ----
   Knoepfe geben beim Druecken nach und federn zurueck. Rueckmeldung auf
   eine Eingabe — der Nutzer erfaehrt, dass er getroffen hat. */
.press-fx { transition: transform 0.13s cubic-bezier(0.22, 1, 0.36, 1); }
.press-fx:active { transform: scale(0.97); }

/* ---- Kopieren-Bestaetigung ----
   Beantwortet die Frage "hat's geklappt?" — die befriedigendste Sorte
   Animation, weil sie auf eine Handlung antwortet. */
[data-copy] { cursor: pointer; position: relative; }
[data-copy]::after {
  content: "Kopiert";
  position: absolute; left: 50%; top: -6px;
  transform: translate(-50%, 0) scale(0.9);
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bg); background: var(--brand);
  padding: 3px 8px; border-radius: 5px;
  opacity: 0; pointer-events: none;
}
[data-copy].kopiert::after { animation: kopiert 1.4s cubic-bezier(0.22, 1, 0.36, 1) both; }
@keyframes kopiert {
  0%   { opacity: 0; transform: translate(-50%, 4px) scale(0.9); }
  18%  { opacity: 1; transform: translate(-50%, -12px) scale(1); }
  78%  { opacity: 1; transform: translate(-50%, -12px) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -18px) scale(0.96); }
}
[data-copy].kopiert { color: var(--brand); }

@media (prefers-reduced-motion: reduce) {
  .press-fx { transition: none; }
  .press-fx:active { transform: none; }
  [data-copy].kopiert::after { animation: none; opacity: 1; transform: translate(-50%, -12px); }
}

@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .js [data-wortfade] .wort,
  .js [data-staffel] > * {
    opacity: 1; transform: none; filter: none; transition: none;
  }
  .js [data-staffel].in .schritt-n { animation: none; }
}
