:root {
  --bg: #f6f7f9; --panel: #fff; --ink: #16191d; --muted: #656d78;
  --line: #dfe3e8; --accent: #2563eb; --accent-ink: #fff;
  --ok: #0f7b40; --ok-bg: #e6f4ec; --warn: #92510b; --warn-bg: #fdf3e3;
  --err: #b3261e; --err-bg: #fdeceb; --code-bg: #f1f3f5;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #14171a; --panel: #1c2025; --ink: #e8eaed; --muted: #9aa3ad;
    --line: #2c323a; --accent: #4d86f7; --accent-ink: #0d1117;
    --ok: #5cc98d; --ok-bg: #16301f; --warn: #e0a75e; --warn-bg: #332711;
    --err: #f2857c; --err-bg: #3a1a18; --code-bg: #23282e;
  }
}
* { box-sizing: border-box; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font: 15px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
a { color: var(--accent); }
header.top {
  background: var(--panel); border-bottom: 1px solid var(--line);
  padding: 0 14px; display: flex; align-items: center; gap: 12px;
  position: sticky; top: 0; z-index: 10;
}
header.top .brand { font-weight: 650; padding: 9px 0; letter-spacing: -.01em; }
header.top nav { display: flex; gap: 4px; flex: 1; flex-wrap: wrap; }
header.top nav a {
  padding: 9px 9px; text-decoration: none; color: var(--muted);
  border-bottom: 2px solid transparent; font-weight: 500; font-size: 14px;
}
header.top nav a:hover { color: var(--ink); }
header.top nav a.active { color: var(--ink); border-bottom-color: var(--accent); }
header.top .who { color: var(--muted); font-size: 13px; }
/* Alle Seiten sind gleich breit. Vorher nutzten nur die Listenseiten den
   Bildschirm aus und die Formularseiten blieben schmal - der Gedanke dahinter
   war richtig (lange Textzeilen lesen sich schlecht), das Ergebnis aber
   unruhig: Beim Wechsel zwischen zwei Seiten sprang die Breite.

   Der ursprüngliche Zweck bleibt trotzdem erhalten, nur an der richtigen
   Stelle: Erklärtexte werden unten einzeln begrenzt, Tabellen nicht. */
main {
  max-width: min(99vw, 2400px);
  margin: 0 auto;
  padding: 14px 12px 28px;
}
/* Fließtext bleibt lesbar begrenzt, auch auf einem breiten Bildschirm. */
main .panel > p.hint,
main .panel > .flash { max-width: 105ch; }
h1 { font-size: 19px; margin: 0 0 2px; letter-spacing: -.02em; }
h2 { font-size: 15px; margin: 0 0 8px; }
.sub { color: var(--muted); margin: 0 0 12px; font-size: 13px; }
.panel {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 8px; padding: 12px 14px; margin-bottom: 10px;
}
.grid { display: grid; gap: 8px; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
.stat .k { color: var(--muted); font-size: 12px; }
.stat .v { font-size: 20px; font-weight: 600; margin-top: 0; letter-spacing: -.02em; }
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th { text-align: left; color: var(--muted); font-weight: 600; font-size: 12px;
     text-transform: uppercase; letter-spacing: .04em; padding: 0 10px 8px; }
td { padding: 10px; border-top: 1px solid var(--line); vertical-align: middle; }
.scroll { overflow-x: auto; }
code, pre, .mono { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; }
pre {
  background: var(--code-bg); border: 1px solid var(--line); border-radius: 8px;
  padding: 12px 14px; overflow-x: auto; font-size: 13px; margin: 0;
}
.codebox { display: flex; gap: 8px; align-items: stretch; margin-bottom: 10px; }
.codebox pre { flex: 1; white-space: pre-wrap; word-break: break-all; }
label { display: block; font-weight: 550; margin: 0 0 5px; font-size: 14px; }
.hint { color: var(--muted); font-size: 13px; margin: 4px 0 0; }
/* Eingabefelder. `input:not([type])` gehört dazu: Ein <input> ohne
   type-Attribut verhält sich wie type="text", wird von `input[type=text]`
   aber NICHT getroffen. Solche Felder standen ungestaltet zwischen den
   anderen — schmaler, ohne Rundung, auf anderer Höhe. Vier Stück waren es;
   der Selektor sorgt dafür, dass es kein fünftes gibt.

   `search`, `email`, `tel` und `url` sind gleich mit aufgenommen, damit die
   Frage nicht beim nächsten Feldtyp wiederkommt. */
input:not([type]),
input[type=text], input[type=password], input[type=number],
input[type=search], input[type=email], input[type=tel], input[type=url],
select, textarea {
  width: 100%; padding: 9px 11px; border: 1px solid var(--line); border-radius: 7px;
  background: var(--bg); color: var(--ink); font: inherit;
}
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent);
}
.field { margin-bottom: 11px; }
.row { display: grid; gap: 14px; grid-template-columns: 1fr 1fr; }
@media (max-width: 620px) { .row { grid-template-columns: 1fr; } }
button, .btn {
  padding: 9px 15px; border-radius: 7px; border: 1px solid var(--line);
  background: var(--panel); color: var(--ink); font: inherit; font-weight: 550;
  cursor: pointer; text-decoration: none; display: inline-block;
}
button:hover, .btn:hover { border-color: var(--accent); }
.btn-primary { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.btn-danger { color: var(--err); }
.btn-sm { padding: 3px 8px; font-size: 12px; }
.actions { display: flex; gap: 7px; align-items: center; flex-wrap: wrap; margin-top: 11px; }

/* Knöpfe, die nebeneinander stehen, sind gleich groß. Ein kleiner neben einem
   großen sieht aus wie ein Versehen - und war meistens auch eins: Irgendwo
   wurde btn-sm gesetzt, weil der Knopf allein in einer Tabellenzelle stand,
   und später zog jemand einen normalen daneben. Diese Regel macht die Frage
   gegenstandslos. */
.actions .btn-sm, .actions button.btn-sm { padding: 9px 15px; font-size: inherit; }

/* ---------------------------------------------------------------------
   Eine Zeile aus mehreren Eingabefeldern nebeneinander.

   Vorher war jede solche Zeile aus Inline-Angaben zusammengestückelt, und
   entsprechend sah sie aus: Beschriftungen auf drei Höhen, Felder, die um
   ein paar Pixel versetzt sitzen. Die Ursache ist immer dieselbe - eine
   einzeilige Beschriftung neben einer zweizeiligen verschiebt alles darunter.

   Deshalb: feste Höhe für die Beschriftung, Felder oben ausgerichtet, und
   ein eigener Platzhalter für Knöpfe, damit sie auf der Höhe der Eingaben
   sitzen statt auf der der Beschriftung.
   --------------------------------------------------------------------- */
.formzeile {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 12px;
  align-items: flex-start;
}
.formzeile .field { margin: 0; min-width: 0; }
.formzeile .field > label {
  display: block;
  min-height: 19px;        /* eine Zeile - auch wenn die Beschriftung fehlt */
  line-height: 19px;
  white-space: nowrap;
}
/* Trägt einen Knopf auf Eingabehöhe: die leere Beschriftung schafft den
   Abstand, den die anderen Felder von ihrer echten bekommen. */
.formzeile .field.knopf > label { visibility: hidden; }
.formzeile .field.knopf > button,
.formzeile .field.knopf > .btn { width: 100%; }
/* Ein Ankreuzfeld, das wie ein Eingabefeld aussieht - damit es in einer
   Zeile aus Auswahllisten nicht wie hineingerutscht wirkt. */
.kaestchen {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  padding: 0 11px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--bg);
  white-space: nowrap;
  cursor: pointer;
  font-weight: 400;
}
.kaestchen input { width: auto; margin: 0; }
.formzeile .hinweis-unten {
  flex-basis: 100%;
  margin: 2px 0 0;
}
@media (max-width: 700px) {
  .formzeile .field { flex: 1 1 100%; }
}
.flash { padding: 8px 11px; border-radius: 7px; margin-bottom: 10px; font-size: 13px; }
.flash.ok { background: var(--ok-bg); color: var(--ok); }
.flash.err { background: var(--err-bg); color: var(--err); }
.flash.warn { background: var(--warn-bg); color: var(--warn); }
.tag {
  display: inline-block; padding: 2px 8px; border-radius: 20px;
  font-size: 12px; font-weight: 600;
}
.tag.on { background: var(--ok-bg); color: var(--ok); }
.tag.off { background: var(--code-bg); color: var(--muted); }
.tag.warn { background: var(--warn-bg); color: var(--warn); }
.tag.err { background: var(--err-bg); color: var(--err); }
.auth { max-width: 400px; margin: 9vh auto; }
.muted { color: var(--muted); }
.nowrap { white-space: nowrap; }
.stepnum {
  display: inline-flex; width: 22px; height: 22px; border-radius: 50%;
  background: var(--accent); color: var(--accent-ink); align-items: center;
  justify-content: center; font-size: 13px; font-weight: 700; margin-right: 8px;
}
ol.steps { list-style: none; padding: 0; margin: 0; }
ol.steps > li { margin-bottom: 22px; }

/* Passwortfelder mit Sichtbarkeits-Umschalter */
.pw-wrap { position: relative; display: block; }
.pw-wrap > input { padding-right: 84px; }
.pw-toggle {
  position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
  padding: 4px 9px; font-size: 12px; line-height: 1.4; border-radius: 5px;
  border: 1px solid var(--line); background: var(--panel); color: var(--muted);
  cursor: pointer; font-family: inherit; font-weight: 500;
}
.pw-toggle:hover { color: var(--ink); border-color: var(--accent); }
.pw-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Kopierfeld im Stil einer Eingabezeile, mit Symbol rechts */
.copyrow { display: flex; align-items: stretch; gap: 0; margin-bottom: 8px; }
.copyrow > .val {
  flex: 1; min-width: 0; padding: 9px 11px; border: 1px solid var(--line);
  border-right: none; border-radius: 7px 0 0 7px; background: var(--bg);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 13px; overflow-x: auto; white-space: nowrap; line-height: 1.5;
}
.copyrow > .cbtn {
  display: flex; align-items: center; justify-content: center; width: 40px;
  border: 1px solid var(--line); border-radius: 0 7px 7px 0;
  background: var(--panel); color: var(--muted); cursor: pointer; padding: 0;
}
.copyrow > .cbtn:hover { color: var(--accent); border-color: var(--accent); }
.copyrow > .cbtn svg { width: 16px; height: 16px; }
.copyrow > .cbtn.done { color: var(--ok); }
.codegroup { margin-bottom: 20px; }
.codegroup > h3 {
  font-size: 13px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); margin: 0 0 10px; font-weight: 600;
}
.codelabel { font-size: 13px; font-weight: 550; margin: 0 0 3px; }

td.actions-cell { white-space: nowrap; }
td.actions-cell form { display: inline; margin: 0; }
/* Die Knopfreihe je Zeile ist der breiteste Teil der Bot-Liste. Eng gesetzt
   passt die Tabelle auch auf einen kleineren Bildschirm ohne Querlauf. */
td.actions-cell .btn-sm, td.actions-cell button { margin-left: 2px; }
table { font-size: 13px; }
/* Zweizeilige Zellen kompakt halten */
table .sub2 { font-size: 12px; color: var(--muted); line-height: 1.35; }
table td, table th { padding: 6px 8px; }

/* Sicherheitsnetz: Ein Symbol in einem Knopf darf nie den Platz sprengen,
   auch wenn eine spätere Regel fehlt oder eine alte Fassung zwischengespeichert
   ist. */
button svg, .btn svg { width: 1em; height: 1em; vertical-align: -.125em; }

/* Erklaerung beim Darueberfahren. Als freies Element am <body>, nicht im
   <th>: die Tabelle steckt in einem Kasten mit overflow-x, der ein
   absolut positioniertes Kind abschneiden wuerde. */
[data-tip] { cursor: help; }
th[data-tip], h2[data-tip] {
  text-decoration: underline dotted; text-underline-offset: 3px;
  text-decoration-color: var(--line);
}
th[data-tip]:hover, h2[data-tip]:hover {
  text-decoration-color: var(--accent); color: var(--accent);
}
.tip {
  position: fixed; z-index: 60; left: -9999px; top: 0; display: none;
  max-width: 360px; padding: 10px 12px;
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .16);
  /* Der Spaltenkopf ist versal und gesperrt - das darf nicht durchschlagen. */
  font: 400 13px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  text-transform: none; letter-spacing: 0; text-align: left;
  white-space: normal; pointer-events: none;
}
.tip b { display: block; margin-bottom: 3px; font-size: 12px;
         text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }

/* Ein gesperrter Knopf muss auch gesperrt aussehen, sonst klickt man ins
   Leere und haelt es fuer einen Fehler. */
button:disabled, .btn:disabled {
  opacity: .45; cursor: not-allowed;
}

/* Wirkt gesperrt, ist es aber technisch nicht: Ein echtes `disabled`
   verschluckt Mausereignisse, dann erscheint kein Hinweis und der Benutzer
   sieht nur einen durchgestrichenen Kreis ohne Erklaerung. */
.gesperrt {
  opacity: .5; cursor: help; border-style: dashed;
}
.gesperrt:hover { opacity: .75; }

/* Umschalter: Der aktuelle Zustand ist ausgefüllt, die Alternative bleibt ein
   normaler Knopf. Vorher trug der aktuelle die Klasse .gesperrt - halb
   durchsichtig und gestrichelt. Die heisst sonst "geht nicht", und
   entsprechend las man sie: als waere die Option verschwunden. */
.umschalter { display: flex; gap: 0; flex-wrap: wrap; }
.umschalter .btn {
  border-radius: 0;
  margin: 0;
  border-right-width: 0;
}
.umschalter .btn:first-child { border-radius: 7px 0 0 7px; }
.umschalter .btn:last-child { border-radius: 0 7px 7px 0; border-right-width: 1px; }
.umschalter .btn.aktiv {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-weight: 600;
  cursor: default;
}

/* Aufklappbarer Ablauf je Bot. Der Name ist ein Schalter, kein Link - ein
   Link fuehrte frueher dorthin, wo ohnehin schon ein Knopf hinfuehrt. */
button.ausklapp {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; color: var(--accent); cursor: pointer; text-align: left;
}
button.ausklapp:hover strong { text-decoration: underline; }
button.ausklapp .pfeil {
  display: inline-block; transition: transform .12s ease; font-size: 11px;
  color: var(--muted);
}
button.ausklapp[aria-expanded="true"] .pfeil { transform: rotate(90deg); }

/* Stillgelegtes Boersenkonto. Es behaelt seine Zugangsdaten, fuehrt aber
   keine Order mehr aus - das muss man auf einen Blick sehen, sonst sucht man
   den Fehler an der Boerse statt hier. Die Knoepfe bleiben voll sichtbar,
   sonst kaeme man an "Aktivieren" schlecht heran. */
tr.stillgelegt > td { opacity: .45; }
tr.stillgelegt > td.nowrap:last-child,
tr.stillgelegt > td:last-child { opacity: 1; }
tr.stillgelegt > td:last-child form,
tr.stillgelegt > td:last-child a { opacity: 1; }

/* Betriebszustand in der Kopfleiste. Er stand frueher als breiter Balken
   ueber jeder Seite und kostete dort Platz, den die Tabellen brauchen. */
.zustand {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 12px; font-weight: 600; cursor: help; white-space: nowrap;
}
.zustand.on   { background: var(--ok-bg);   color: var(--ok); }
.zustand.warn { background: var(--warn-bg); color: var(--warn); }
.zustand.err  { background: var(--err-bg);  color: var(--err); }

/* Kennzahlenkarten kompakter: Die Zahl zaehlt, nicht der Rahmen. */
.panel.stat { padding: 9px 11px; }

/* Der Abstand unter der letzten Tabelle einer Tafel war doppelt gesetzt. */
.panel > .scroll:last-child table { margin-bottom: 0; }

/* ---------------------------------------------------------------------
   Tabellenkopf, der beim Rollen stehen bleibt.

   Bei 103 Börsen und zwölf Spalten ist eine Zeile ohne sichtbaren Kopf nur
   noch eine Reihe von Zahlen: Man weiß nicht mehr, ob 0,1 % die Maker- oder
   die Taker-Gebühr ist.

   Zwei Dinge sind daran nicht offensichtlich:

   1. Der Kasten mit `overflow-x` muss weg. Steht auf einem Element nur
      `overflow-x: auto`, rechnet der Browser `overflow-y` auf `auto` hoch —
      damit wird der Kasten zum Rollbereich, und ein klebender Kopf darin
      klebt am Kasten statt am Fenster. Der Kasten rollt aber nie senkrecht,
      also klebt der Kopf nirgends. Gemessen: Der Kopf lief auf -2322 px
      davon, blieb also einfach mit nach oben weg.

      Deshalb rollt hier die Seite selbst. Preis: Ist das Fenster schmaler
      als die Tabelle (gemessen 1210 px), bekommt die Seite einen
      Querbalken statt der Kasten. Dafür klebt der Kopf in jeder Breite.

   2. Der Abstand nach oben ist keine feste Zahl. Die Navigationsleiste
      klebt selbst schon oben und ist bei schmalem Fenster doppelt so hoch,
      weil die Links umbrechen (gemessen: 42 px gegen 87 px). Ihre Höhe
      steht in --kopfhoehe; base.html misst sie und schreibt sie fort.

   Die Trennlinie ist ein inneres Schlagschatten-Rechteck, kein Rahmen:
   Bei `border-collapse: collapse` gehören Rahmen der Tabelle, nicht der
   Zelle — sie bleiben beim Kleben zurück.
   --------------------------------------------------------------------- */
.scroll.klebkopf { overflow: visible; }
.klebkopf thead th {
  position: sticky;
  top: var(--kopfhoehe, 42px);
  /* Unter der Navigationsleiste (10), über den Zeilen, unter dem
     Hinweisfähnchen (60). */
  z-index: 5;
  background: var(--panel);
  box-shadow: inset 0 -1px 0 var(--line);
  padding-top: 9px; padding-bottom: 9px;
}

/* ---------------------------------------------------------------------
   Anleitung zum Einrichten einer App, mitten im Anmeldeablauf.

   Sie muss sichtbar sein, ohne den Ablauf zu verstopfen: Wer die App schon
   hat, klappt sie mit einem Klick zu; wer sie nicht hat, kommt ohne sie
   nicht weiter - und merkt das sonst erst, wenn der Bestätigungscode
   ausbleibt. Deshalb offen als Vorgabe, nicht zugeklappt.
   --------------------------------------------------------------------- */
.einrichtung {
  border: 1px solid var(--line); border-radius: 8px;
  margin: 0 0 11px; background: var(--bg);
}
.einrichtung > summary {
  cursor: pointer; padding: 9px 12px; font-weight: 550; font-size: 14px;
  list-style-position: inside;
}
.einrichtung > summary:hover { color: var(--accent); }
.einrichtung-inhalt { padding: 0 12px 10px; }

/* Nummerierte Schritte. Der Abstand trennt sie deutlicher als die Ziffer
   allein - bei drei Schritten mit Bildern verschwimmt es sonst. */
ol.schritte { margin: 0; padding-left: 20px; }
ol.schritte > li { margin-bottom: 12px; font-size: 13px; line-height: 1.5; }
ol.schritte > li:last-child { margin-bottom: 0; }

/* Bezugsquellen mit QR-Code nebeneinander.

   Keine festen Pixelbreiten: Die drei Quellen teilen sich den Platz, der da
   ist. Ein fester Wert war schon zweimal falsch - der Anmeldekasten hat
   innen 368 px, nach dem Einzug der nummerierten Liste bleiben davon 324.
   Solche Rechnungen veralten beim nächsten Layoutwechsel; `flex: 1 1 0`
   nicht.

   Der QR-Code darf dabei nicht beliebig klein werden, deshalb die
   Obergrenze - 92 px genügen zum Abfotografieren, die Codes tragen
   mittlere Fehlerkorrektur. */
.appquellen {
  display: flex; gap: 8px; flex-wrap: wrap;
  padding: 8px 0 2px; align-items: flex-start;
}
.appquelle {
  text-align: center; flex: 1 1 0; min-width: 84px; max-width: 120px;
}
.appquelle svg { width: 100%; height: auto; max-width: 92px; }
.appquelle a {
  display: block; font-size: 10.5px; margin-top: 4px; line-height: 1.3;
  hyphens: auto;
}

/* Eine Zeile aus Code und Knopf - Adresse oder Themenname zum Kopieren.

   Der Code bekommt IMMER die ganze Zeile, der Knopf sitzt darunter. Mit dem
   Knopf daneben blieben nur 246 px, und `https://ntfy.130-61-152-44.sslip.io`
   brach mitten im Wort um ("ssli / p.io") - lesbar, aber es sieht nach Fehler
   aus, und wer eine Adresse abtippt, stolpert darüber. Über die volle Breite
   von 324 px passt sie in eine Zeile. */
.codezeile {
  display: flex; gap: 6px; align-items: stretch;
  margin: 6px 0; flex-wrap: wrap;
}
.codezeile > code {
  flex: 1 1 100%; min-width: 0; padding: 6px 9px; font-size: 12px;
  background: var(--code-bg); border: 1px solid var(--line);
  border-radius: 7px; word-break: break-all; display: flex;
  align-items: center;
}
.codezeile > button { flex: 0 0 auto; }
