/*
 * Marktkompass — Oberfläche.
 *
 * Leitgedanke aus §18.1: ruhig, klar, seriös. Keine Casino-Optik, keine
 * Reizüberflutung. Grün und Rot kommen vor, aber gedämpft und nie als einziger
 * Träger einer Information — daneben steht immer ein Vorzeichen oder ein Wort.
 *
 * Die Ordnung der Seite entsteht durch drei Mittel, in dieser Reihenfolge:
 * Abstand, Schriftgröße, Farbe. Rahmen kommen zuletzt. Deshalb tragen Karten
 * hier einen sehr weichen Schatten statt eines Strichs — der Blick soll
 * Gruppen erkennen, ohne dass ihn ein Gitter dabei anleiten muss.
 *
 * Alle Maße kommen aus Klassen, nie aus style-Attributen: die
 * Content-Security-Policy verbietet Inline-Stile, und das soll sie auch.
 */

/* --- Festwerte ----------------------------------------------------------- */

/*
 * Dunkel ist der Grundfall, hell die Abweichung. Das ist keine Mode: die
 * Anwendung besteht aus Kursflächen, Kerzen und farbcodierten Zahlen, und die
 * stehen auf dunklem Grund ruhiger. Grün und Rot brauchen dort weniger
 * Sättigung, um sich zu unterscheiden, und ein Diagramm hört auf, ein weißes
 * Loch in der Seite zu sein.
 *
 * Jede Farbe steht einmal, als `light-dark(hell, dunkel)`. Vorher gab es zwei
 * Blöcke — einen für dunkel, einen in einer Medienabfrage für hell —, und ein
 * Wert, den man nur im ersten änderte, fiel niemandem auf, der sein Gerät auf
 * dunkel gestellt hatte. Jetzt kann das nicht mehr passieren, und der
 * Umschalter im Konto-Menü braucht keine dritte Kopie: er setzt nur
 * `color-scheme` um, und `light-dark()` folgt.
 *
 * `light-dark()` gilt ab Chrome 123, Safari 17.5 und Firefox 120 (alle 2023/24).
 * Ein älterer Browser bekäme eine Seite ohne Farben — dagegen steht der
 * Notblock unter den Festwerten.
 */
:root {
  color-scheme: dark light;

  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, monospace;

  /*
   * Flächen. Der dunkle Grund ist ein tiefes Marineblau, die Karten darüber
   * heben sich in drei knappen Stufen ab. Reines Schwarz wäre härter, als es
   * sein muss: auf ihm wirkt jeder Rahmen wie ein Schnitt.
   *
   * Der Blauton ist gewollt und nicht nur Geschmack — er stammt aus dem
   * Gegenstand. Kursflächen, Kerzen und der Akzent liegen ohnehin im blauen
   * Bereich; ein neutralgrauer Grund darunter ließ sie wie aufgeklebt wirken.
   * Die Sättigung bleibt trotzdem verhalten: Ein leuchtendes Blau, wie es
   * Handelsoberflächen gern tragen, liest sich nach zwei Stunden nicht mehr,
   * und diese Anwendung wird gelesen und nicht angestarrt.
   *
   * Hell bleibt hell. Ein kühler Stich in den hellen Flächen hätte die
   * gedämpften Grüntöne ins Graue gezogen, und dort trägt Farbe Bedeutung.
   */
  --bg: light-dark(#f2f5f8, #060e18);
  --surface: light-dark(#ffffff, #101a28);
  --surface-2: light-dark(#eaeff4, #172435);
  --surface-3: light-dark(#dfe6ed, #223145);

  --border: light-dark(#dde3ea, #212e3f);
  --border-strong: light-dark(#bcc6d1, #4b5f7c);

  --text: light-dark(#0e1319, #e6ecf5);
  --text-muted: light-dark(#525c69, #94a3b8);
  --text-faint: light-dark(#7e8895, #68788d);

  /*
   * Der Akzent zieht mit: satter als vorher und im Hellen eine Spur tiefer.
   * Beide Fassungen bleiben über dem geforderten Kontrast — im Dunkeln 7,4:1
   * auf der Kartenfläche, im Hellen 6,5:1 auf Weiß.
   */
  --accent: light-dark(#0a5fa8, #46adf7);
  --accent-strong: light-dark(#084a80, #7fc4ff);
  --accent-soft: light-dark(#e3eff9, #0e2740);
  --accent-line: light-dark(#a3c8ea, #2a5480);

  /*
   * Schriftfarbe auf der Akzentfläche. Sie muss mitkippen: auf dem hellen Blau
   * des Dunkelmodus wäre Weiß mit 2,5:1 unlesbar, auf dem tiefen Blau des
   * Hellmodus wäre Schwarz mit 3,2:1 dasselbe Problem andersherum. Ein fester
   * Wert wäre in genau einem der beiden Fälle falsch.
   */
  --on-accent: light-dark(#ffffff, #05090f);

  /*
   * Grün und Rot sind die einzigen Farben, die in dieser Anwendung etwas
   * bedeuten dürfen. Sie stammen aus der Kursdarstellung und gelten überall
   * gleich: steigend, fallend. Kein drittes Blau, das auch irgendwie freundlich
   * aussieht.
   */
  --up: light-dark(#12784c, #35c07d);
  --up-soft: light-dark(#e4f2ea, #10291d);
  --down: light-dark(#c0352d, #f0605a);
  --down-soft: light-dark(#fbeae9, #2c1719);
  --warn: light-dark(#8a6212, #e0b055);
  --warn-soft: light-dark(#fdf4e3, #2a2214);

  /*
   * Abstandsskala. Sieben Stufen reichen für die ganze Anwendung; wer eine
   * achte braucht, hat meist ein Gliederungsproblem und kein Platzproblem.
   */
  --s1: 0.25rem;
  --s2: 0.5rem;
  --s3: 0.75rem;
  --s4: 1rem;
  --s5: 1.5rem;
  --s6: 2rem;
  --s7: 3rem;

  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 14px;
  --radius-pill: 999px;

  /*
   * Ein Schatten ist keine Farbe, sondern eine Liste aus Maßen und einer Farbe.
   * `light-dark()` kann nur die Farbe, deshalb steckt sie in einer eigenen
   * Größe. Im Dunkeln braucht der Schatten deutlich mehr Deckkraft, um
   * überhaupt zu wirken; im Hellen wenig, sonst wird die Karte schmutzig.
   */
  --shadow-1: light-dark(rgba(15, 23, 34, 0.05), rgba(0, 0, 0, 0.35));
  --shadow-2: light-dark(rgba(15, 23, 34, 0.07), rgba(0, 0, 0, 0.45));
  --shadow-3: light-dark(rgba(15, 23, 34, 0.04), rgba(0, 0, 0, 0.3));
  --shadow-4: light-dark(rgba(15, 23, 34, 0.11), rgba(0, 0, 0, 0.55));

  --shadow-sm: 0 1px 2px var(--shadow-1);
  --shadow: 0 1px 3px var(--shadow-2), 0 1px 2px var(--shadow-3);
  --shadow-lg: 0 10px 30px var(--shadow-4), 0 2px 6px var(--shadow-1);

  --page: 78rem;
  --measure: 62ch;
}

/*
 * Auf breiten Bildschirmen darf die Anwendung mehr Fläche nehmen.
 *
 * Möglich ist das nur, weil Breite und Zeilenlänge hier zwei verschiedene Maße
 * sind: `--page` deckelt die Seite, `--measure` den Fließtext. Wo beides
 * dasselbe Maß ist, muss eine Seite schmal bleiben, sonst laufen Absätze über
 * die halbe Wand. Hier gewinnen die Raster — Kennzahlen, Tabellen, Diagramme,
 * die zweispaltige Aufteilung —, während jeder Absatz bei seinen 62 Zeichen
 * bleibt.
 *
 * Die Seite wächst mit dem Fenster, bis 100 rem erreicht sind; darüber wächst
 * nur noch der Rand. Ein fester Randabzug statt fester Stufen, weil Stufen
 * genau zwischen zwei Schwellen den Platz verschenken, den es gerade gibt —
 * ein Fenster mit 1500 Pixeln bekäme sonst dasselbe wie eines mit 1250.
 *
 * Die Regel greift erst ab 90 rem, und das ist der Punkt, auf den es ankommt:
 * `100vw` kennt keine Bildlaufleiste. Auf schmalen Geräten, wo die Seite ohnehin
 * die volle Breite nimmt, würde der Abzug den Inhalt zusätzlich einschnüren.
 */
@media (min-width: 90rem) {
  :root { --page: min(100rem, 100vw - 8rem); }
}

/*
 * Die Wahl des Nutzers. Sie greift in genau einer Eigenschaft, weil alle Farben
 * über `light-dark()` daran hängen — deshalb steht hier keine einzige Farbe.
 *
 * Ohne Klasse bleibt es bei `dark light` von oben, und das Gerät entscheidet.
 * Die Klasse setzt `Kernel` aus dem Cookie, siehe `Presentation\Theme`.
 */
:root.thema-hell   { color-scheme: light; }
:root.thema-dunkel { color-scheme: dark; }

/*
 * Notnagel für Browser ohne `light-dark()`. Ohne ihn wären dort sämtliche
 * Farbgrößen ungültig und die Seite bestünde aus schwarzer Schrift auf weißem
 * Grund mit unsichtbaren Rändern. Hier steht deshalb einmal die dunkle
 * Palette — sie ist der Grundfall, und ein alter Browser bekommt sie fest.
 */
@supports not (color: light-dark(#000, #fff)) {
  :root {
    --bg: #060e18;
    --surface: #101a28;
    --surface-2: #172435;
    --surface-3: #223145;
    --border: #212e3f;
    --border-strong: #4b5f7c;
    --text: #e6ecf5;
    --text-muted: #94a3b8;
    --text-faint: #68788d;
    --accent: #46adf7;
    --accent-strong: #7fc4ff;
    --accent-soft: #0e2740;
    --accent-line: #2a5480;
    --on-accent: #05090f;
    --up: #35c07d;
    --up-soft: #10291d;
    --down: #f0605a;
    --down-soft: #2c1719;
    --warn: #e0b055;
    --warn-soft: #2a2214;
    --shadow-1: rgba(0, 0, 0, 0.35);
    --shadow-2: rgba(0, 0, 0, 0.45);
    --shadow-3: rgba(0, 0, 0, 0.3);
    --shadow-4: rgba(0, 0, 0, 0.55);
  }
}

/* --- Grundlagen ---------------------------------------------------------- */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;

  /* Nachrichtentitel und Adressen enthalten Zeichenketten ohne Leerzeichen.
     Auf einem breiten Bildschirm fällt das nie auf, auf einem Telefon schiebt
     ein einziges solches Wort die ganze Seite zur Seite. */
  overflow-wrap: break-word;
}

h1, h2, h3, h4 {
  margin: 0;
  line-height: 1.25;
  font-weight: 600;
  letter-spacing: -0.011em;
}

h1 {
  font-size: clamp(1.6rem, 1.35rem + 0.9vw, 2rem);
  font-weight: 650;
  letter-spacing: -0.021em;
}

h2 { font-size: 1.2rem; }
h3 { font-size: 1rem; }
h4 { font-size: 0.92rem; color: var(--text-muted); }

p { margin: 0 0 var(--s3); }
p:last-child { margin-bottom: 0; }

a {
  color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: var(--accent-line);
  transition: text-decoration-color 120ms ease, color 120ms ease;
}

a:hover {
  color: var(--accent-strong);
  text-decoration-color: currentColor;
}

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

hr {
  border: none;
  border-top: 1px solid var(--border);
  margin: var(--s5) 0;
}

/* --- Hilfsklassen -------------------------------------------------------- */

.lead {
  max-width: var(--measure);
  color: var(--text-muted);
  font-size: 1.02rem;
}

/* Der eine Satz, um den es auf der Seite geht. */
.statement {
  max-width: var(--measure);
  font-size: 1.15rem;
  line-height: 1.5;
}

.muted { color: var(--text-muted); }
.faint { color: var(--text-faint); font-size: 0.88rem; }
.mono { font-family: var(--font-mono); font-size: 0.9em; }
.nowrap { white-space: nowrap; }
.prose { max-width: var(--measure); }

.num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

.positiv { color: var(--up); }
.negativ { color: var(--down); }
.neutral { color: var(--text-muted); }

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

.skip {
  position: absolute;
  left: -999px;
  z-index: 20;
  background: var(--surface);
  color: var(--text);
  padding: var(--s3) var(--s4);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  text-decoration: none;
}

.skip:focus { left: var(--s3); top: var(--s3); }

/*
 * Erklärbarer Fachbegriff im Text (§5.10). Die Markierung bleibt bewusst
 * schwach: sie soll den Satz lesbar lassen und nicht wie ein Verweis wirken,
 * dem man folgen muss.
 */
.term {
  color: inherit;
  text-decoration: underline dotted var(--text-faint);
  text-underline-offset: 0.22em;
  cursor: help;
}

.term:hover,
.term:focus-visible {
  color: var(--accent);
  text-decoration-style: solid;
}

/* --- Infoblase ----------------------------------------------------------- */

/*
 * Die Erklärung zum markierten Begriff. Sie stand früher im `title`-Attribut;
 * der Kasten des Browsers erscheint erst nach etwa einer Sekunde, lässt sich
 * nicht gestalten und ist mit der Tastatur gar nicht erreichbar.
 *
 * Sichtbar wird die Blase über `:hover` und `:focus-within` — kein Skript, die
 * Content-Security-Policy bleibt unangetastet. `:focus-within` ist der Teil,
 * der für die Tastatur zählt: der Auslöser ist ein Verweis, und sobald er den
 * Fokus hat, steht die Erklärung da.
 *
 * `visibility` statt `display`: nur so lässt sich der Übergang zeichnen, und
 * die Blase bleibt für `aria-describedby` lesbar, während sie im Barrierebaum
 * nicht doppelt auftaucht.
 *
 * Eine Grenze, die man kennen muss: Ein Vorfahr mit `overflow` schneidet die
 * Blase ab. In `.table-scroll` gehört deshalb keine — die Beschriftung erklärt
 * man dort über der Tabelle, nicht in ihrem Kopf.
 */
.tip {
  position: relative;
}

.tip__body {
  position: absolute;
  top: calc(100% + 0.45rem);

  /* Mittig unter dem Wort statt linksbündig. Das ist nicht Geschmack: eine
     linksbündige Blase ragt am rechten Rand um ihre volle Breite hinaus, eine
     mittige nur um die Hälfte. Zusammen mit der schmalen Breite bleibt sie auf
     einem breiten Bildschirm damit zuverlässig im Bild. */
  left: 50%;
  translate: -50%;
  z-index: 20;

  /* Erst nach Inhalt, dann gedeckelt: ein Halbsatz soll keine Blase über die
     halbe Seite aufziehen, ein langer Satz nicht in einer Spalte kleben. */
  width: max-content;
  max-width: min(20rem, calc(100vw - 2rem));

  padding: var(--s3) var(--s4);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);

  color: var(--text);
  font-family: var(--font-body);
  font-size: 0.86rem;
  font-weight: 400;
  font-style: normal;
  line-height: 1.5;
  letter-spacing: normal;
  text-align: left;
  text-transform: none;
  white-space: normal;

  opacity: 0;
  visibility: hidden;
  transition: opacity 120ms ease, visibility 120ms;
}

.tip:hover > .tip__body,
.tip:focus-within > .tip__body {
  opacity: 1;
  visibility: visible;
}

/* Steht der Auslöser ohnehin am rechten Rand — etwa ein Etikett im Seitenkopf
   —, ist die Mitte der falsche Bezug. Dann klebt die Blase rechts. */
.tip--end > .tip__body {
  left: auto;
  right: 0;
  translate: none;
}

/* Mehr als ein Satz: eine Aufstellung, etwa die Handelszeiten aller Börsen. */
.tip__body--wide {
  max-width: min(28rem, calc(100vw - 2rem));
}

.tip__list {
  display: grid;
  gap: var(--s2);
}

.tip__row {
  display: grid;
  gap: 0.1rem;
}

.tip__place {
  font-weight: 600;
}

.tip__when {
  color: var(--text-muted);
}

/*
 * Auf einem Telefon gibt es keine Blase am Wort, die aufgeht.
 *
 * Der Grund ist Arithmetik, nicht Geschmack: Eine Blase von 20rem passt auf
 * 390 Pixel Breite nur, wenn das Wort ziemlich genau in der Mitte steht. Sonst
 * ragt sie hinaus — bei der Messung waren es 119 Pixel. Deshalb liegt sie hier
 * als Leiste am unteren Rand: immer vollständig, immer an derselben Stelle,
 * und nah am Daumen. Die Berührung des Begriffs setzt den Fokus und lässt sie
 * aufgehen; der zweite Antipper folgt dem Verweis zur ganzen Erklärung.
 */
@media (max-width: 48rem) {
  .tip__body,
  .tip--end > .tip__body {
    position: fixed;
    top: auto;
    left: var(--s3);
    right: var(--s3);
    bottom: var(--s3);
    translate: none;
    width: auto;
    max-width: none;
  }
}

/* --- Kopfzeile ----------------------------------------------------------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.topbar__inner {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--s3) var(--s5);
  display: flex;
  align-items: center;
  gap: var(--s4);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-weight: 660;
  font-size: 1.05rem;
  color: var(--text);
  text-decoration: none;
  letter-spacing: -0.032em;
  white-space: nowrap;
}

/*
 * Das Bildzeichen (siehe `partials/mark.php`): Docht über die volle Höhe,
 * darauf ein Körper aus zwei Hälften. Die Nordhälfte trägt die volle Farbe,
 * die Südhälfte bleibt zurück — so kippt die Figur je nach Blick zur Kerze
 * oder zur Kompassnadel.
 */
.mark {
  width: 1.35rem;
  height: 1.35rem;
  flex: none;
}

/* Das Kompassgehäuse. Bewusst sehr blass: ein kräftiger Ring machte aus dem
   Zeichen ein Zifferblatt und nähme der Kerzenlesart den Halt. */
.mark__ring {
  fill: none;
  stroke: var(--accent);
  stroke-width: 0.9;
  opacity: 0.2;
}

/* Docht und zugleich Nord-Süd-Achse der Nadel. Dünn und mit geradem Ende:
   ein runder, dicker Strich sähe aus wie ein Stab, auf dem etwas steckt —
   und die Kerze wäre weg. */
.mark__wick {
  stroke: var(--accent);
  stroke-width: 1.1;
  opacity: 0.45;
}

/* Die Nadel ist je Hälfte in zwei Facetten geteilt, die sich am Mittelgrat
   treffen. Die linke steht voll, die rechte (`--edge`) zurückgenommen — das
   liest sich als einfallendes Licht und gibt der flachen Fläche Tiefe. */
.mark__facet { fill: var(--accent); }
.mark__facet--edge { opacity: 0.6; }

/* Nord voll, Süd zurückgenommen. Die Deckkraft steht an der Hälfte, damit sich
   das Verhältnis der beiden Facetten in beiden Hälften gleich wiederholt. */
.mark__north { opacity: 1; }
.mark__south { opacity: 0.32; }

/* Drehpunkt der Nadel; deckt zugleich den Treffpunkt der vier Facetten. */
.mark__hub { fill: var(--accent); }

/* Im Kopf der Anwendung sitzt das Zeichen neben dem Schriftzug und bekommt
   beim Überfahren dieselbe Aufhellung wie dieser. */
.brand:hover .mark__wick { opacity: 0.62; }
.brand:hover .mark__south { opacity: 0.5; }
.brand:hover .mark__ring { opacity: 0.34; }

.search {
  display: flex;
  align-items: center;
  gap: var(--s2);
  margin-left: auto;
  min-width: 0;
}

/*
 * Die Suche ist ein Angebot, keine Aufgabe.
 *
 * Sie stand als breites Feld mit umrandeter Schaltfläche daneben im Kopf und
 * zog damit mehr Blick auf sich als die Navigation darunter — dabei sucht man
 * hier gelegentlich, während man ständig navigiert. Deshalb schmaler, flacher,
 * mit runden Enden und ohne zweiten Kasten daneben. Beim Hineinklicken wächst
 * das Feld auf die alte Breite: Zurückhaltung gilt dem Ruhezustand, nicht dem
 * Tippen.
 *
 * Zwei Feinheiten, die beide nicht ins Auge springen:
 *
 * Der Selektor nennt den Feldtyp mit, weil die allgemeine Formularregel weiter
 * unten `input[type="search"]` anspricht — gleiche Spezifität, spätere Stelle,
 * also gewänne sie. Ein schlichtes `.search input` sähe hier richtig aus und
 * bliebe bei Polsterung, Radius und Grundfarbe wirkungslos.
 *
 * Feste Breite statt `max-width`, weil in einem Flex-Verbund nicht die
 * Höchstbreite die Größe bestimmt, sondern der zugeteilte Platz. Beim Fokus
 * wäre ein `max-width` eine Regel, die nichts tut. Schrumpfen darf das Feld
 * weiterhin, dafür genügt der Standardwert von `flex-shrink`.
 */
.search input[type="search"] {
  width: 13rem;
  min-width: 0;
  padding: 0.3rem var(--s3);
  font-size: 0.9rem;
  line-height: 1.45;
  background: var(--surface-2);
  border-color: transparent;
  border-radius: var(--radius-pill);
  transition: width 140ms ease, background 120ms ease, border-color 120ms ease;
}

.search input::placeholder { color: var(--text-faint); }

/* Der weiche Schein aus der Grundregel bleibt: Zurückhaltung gilt dem
   Ruhezustand, eine erkennbare Fokusanzeige ist nicht verhandelbar. */
.search input[type="search"]:focus {
  width: 18rem;
  background: var(--surface);
  border-color: var(--border-strong);
}

/*
 * Rahmen und Grundfarbe der Schaltfläche kommen aus `quiet` im Markup — zwei
 * umrandete Kästen nebeneinander waren der Grund, warum die Zeile so schwer
 * wirkte.
 *
 * Statt des Wortes „Suchen" trägt sie eine Lupe und wird damit quadratisch. Die
 * Polsterung aus `small` ist dafür seitlich zu weit: Sie ist für Text gemacht,
 * der breiter als hoch ist, und ergäbe hier ein liegendes Rechteck um ein
 * rundes Sinnbild.
 *
 * Das Maß folgt der Höhe des Feldes daneben. Es liegt unter den 44 Pixeln, die
 * für eine Fingerfläche empfohlen sind — hier ist das vertretbar, weil der
 * Knopf nicht der Weg zum Ziel ist, sondern die zweite Möglichkeit: Die
 * Eingabetaste im Feld schickt dasselbe Formular ab.
 */
.search__go {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  /* Rund wie das Feld daneben. Die Hover-Fläche aus `quiet` ist das einzige,
     was von diesem Knopf sichtbar wird — als Rechteck stünde sie neben einem
     Feld mit runden Enden. */
  border-radius: var(--radius-pill);
}

/*
 * Größer als die Sinnbilder des Umschalters, obwohl beide dieselbe Aufgabe
 * haben. Der Grund steht nicht hier, sondern im Markup: Jene sitzen zu dritt in
 * einer Gruppe und stützen sich gegenseitig, diese Lupe steht allein neben
 * einem Feld voller Text. Bei gleichem Maß verschwand sie darin.
 */
.search__icon {
  width: 1.75rem;
  height: 1.75rem;
  display: block;
}

/* --- Konto-Menü ---------------------------------------------------------- */

/*
 * Aufklappbar ohne Skript: <details> kann das von Haus aus. Das Menü schließt
 * dadurch nicht beim Klick daneben — dafür funktioniert es ohne eine einzige
 * Zeile JavaScript, und die CSP bleibt streng.
 */
.menu { position: relative; flex: none; }

.menu > summary {
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding: 0.32rem 0.55rem 0.32rem 0.32rem;
  border-radius: var(--radius-pill);
  cursor: pointer;
  list-style: none;
  color: var(--text-muted);
  font-size: 0.9rem;
  white-space: nowrap;
  transition: background 120ms ease;
}

.menu > summary::-webkit-details-marker { display: none; }
.menu > summary::marker { content: ""; }
.menu > summary:hover { background: var(--surface-2); color: var(--text); }
.menu[open] > summary { background: var(--surface-2); color: var(--text); }

/* Initial des Namens als Ersatz für ein Profilbild. */
.menu__avatar {
  width: 1.7rem;
  height: 1.7rem;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  display: grid;
  place-items: center;
  font-size: 0.8rem;
  font-weight: 600;
  flex: none;
}

.menu__panel {
  position: absolute;
  right: 0;
  top: calc(100% + var(--s2));
  min-width: 14rem;
  padding: var(--s2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}

.menu__panel a,
.menu__panel button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.45rem var(--s3);
  border-radius: var(--radius-sm);
  color: var(--text);
  background: none;
  border: none;
  font: inherit;
  font-weight: 400;
  text-decoration: none;
  cursor: pointer;
}

.menu__panel a:hover,
.menu__panel button:hover {
  background: var(--surface-2);
  color: var(--text);
  filter: none;
}

.menu__name {
  padding: var(--s2) var(--s3) var(--s1);
  font-size: 0.85rem;
  color: var(--text-faint);
  line-height: 1.35;
}

.menu__sep {
  height: 1px;
  background: var(--border);
  margin: var(--s2) 0;
}

/* --- Hauptnavigation ----------------------------------------------------- */

.mainnav {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  scrollbar-width: none;
}

.mainnav::-webkit-scrollbar { display: none; }

.mainnav ul {
  max-width: var(--page);
  margin: 0 auto;
  padding: 0 var(--s5);
  display: flex;
  gap: var(--s1);
  list-style: none;
}

.mainnav a {
  display: block;
  padding: var(--s3) var(--s3) calc(var(--s3) - 2px);
  color: var(--text-muted);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  font-size: 0.94rem;
  transition: color 120ms ease, border-color 120ms ease;
}

.mainnav a:hover { color: var(--text); }

.mainnav a[aria-current="page"] {
  color: var(--accent);
  border-bottom-color: var(--accent);
  font-weight: 550;
}

/* --- Seitenaufbau -------------------------------------------------------- */

.wrap {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--s6) var(--s5) var(--s7);
}

/*
 * Abstand entsteht aus der Reihenfolge, nicht aus Klassen an jedem Element.
 * Zwei Regeln genügen für die ganze Anwendung: Abschnitte einer Seite atmen
 * weit, Bausteine innerhalb einer Karte enger. Überschriften brauchen deshalb
 * keinen eigenen Außenabstand mehr — das war früher die Quelle jeder
 * ungleichen Lücke.
 */
main.wrap > * + * { margin-top: var(--s5); }
.card > * + * { margin-top: var(--s4); }

/* Titelzeile: Überschrift links, Aktionen rechts, Erklärung darunter. */
.page-head { margin-bottom: var(--s5); }

.page-head__row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s4);
  flex-wrap: wrap;
}

.page-head__actions {
  display: flex;
  gap: var(--s2);
  align-items: center;
  flex-wrap: wrap;
}

.page-head p { margin-top: var(--s2); }

.stack > * + * { margin-top: var(--s3); }
.stack--wide > * + * { margin-top: var(--s5); }

.row {
  display: flex;
  gap: var(--s3);
  flex-wrap: wrap;
  align-items: center;
}

/*
 * Eingabefelder sind standardmäßig so breit wie ihr Feld. Steht eines direkt
 * in einer Zeile neben einer Schaltfläche, wäre das falsch: es drängt die
 * Schaltfläche in die nächste Zeile und der Zusammenhang zerfällt.
 */
.row > input,
.row > select {
  width: auto;
  min-width: 12rem;
}

.row--tight { gap: var(--s2); }
.row--end { justify-content: flex-end; }
.row--between { justify-content: space-between; }

/*
 * `min(…, 100%)` statt einer festen Mindestbreite: ohne das erzwingt
 * `auto-fit` die Spaltenbreite auch dann, wenn der Bildschirm schmaler ist —
 * die Karte ragt aus dem Bild und die ganze Seite lässt sich seitlich
 * schieben. Auf dem Telefon ist genau das der häufigste Layoutfehler.
 */
.grid {
  display: grid;
  gap: var(--s4);
  grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
}

.grid--halves { grid-template-columns: repeat(auto-fit, minmax(min(23rem, 100%), 1fr)); }
.grid--thirds { grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr)); }

/*
 * Zwei Spalten mit fester Gewichtung: links das Wesentliche, rechts der
 * Zusammenhang. Unter 62rem stapeln sie, damit auf dem Telefon nichts
 * gequetscht wird.
 */
.split {
  display: grid;
  gap: var(--s4);
  grid-template-columns: minmax(0, 1.65fr) minmax(0, 1fr);
  align-items: start;
}

@media (max-width: 62rem) {
  .split { grid-template-columns: 1fr; }
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--s5);
}

.card--flat { box-shadow: none; }
.card--quiet { background: var(--surface-2); border-color: transparent; box-shadow: none; }
.card--accent { background: var(--accent-soft); border-color: var(--accent-line); box-shadow: none; }
.card--narrow { max-width: 25rem; width: 100%; }
.card--tight { padding: var(--s4); }

/*
 * Kartenkopf. Die Überschrift trägt keine eigene Linie — der Abstand zum
 * Inhalt reicht, und eine Linie weniger ist eine Linie weniger.
 */
.card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s4);
  flex-wrap: wrap;
}

.card__head h2,
.card__head h3 { margin: 0; }

.card__more {
  font-size: 0.88rem;
  white-space: nowrap;
}

/* Mehrere Umschalter im Kartenkopf. Sie brechen gemeinsam um, damit auf dem
   Telefon nicht einer oben und einer unten steht. */
.card__controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

.card > h2:first-child,
.card > h3:first-child { margin-bottom: var(--s4); }

/* Karte, die eine ganze Zeile im Raster füllt. */
.span-all { grid-column: 1 / -1; }

.centered {
  min-height: 100vh;
  display: grid;
  place-items: center;
  align-content: center;
  gap: var(--s4);
  padding: var(--s5);
}

/* --- Kennzahlen ---------------------------------------------------------- */

/*
 * Die wichtigste Zahl der Anwendung ist der Depotwert. Sie bekommt deshalb
 * eine eigene Größe, die sonst nirgends vorkommt — daran erkennt der Blick
 * beim Öffnen der Seite sofort, wo er anfangen soll.
 */
.headline-figure {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
}

.headline-figure__label {
  font-size: 0.88rem;
  color: var(--text-muted);
}

.headline-figure__value {
  font-size: clamp(2rem, 1.5rem + 2vw, 2.9rem);
  font-weight: 650;
  line-height: 1.1;
  letter-spacing: -0.025em;
  font-variant-numeric: tabular-nums;
}

.headline-figure__unit {
  font-size: 0.5em;
  font-weight: 500;
  color: var(--text-muted);
  letter-spacing: 0;
}

.headline-figure__note {
  color: var(--text-muted);
  font-size: 0.92rem;
}

/*
 * Kopf einer Seite mit einer führenden Zahl: eine große Angabe, daneben die
 * Kennzahlen, die sie einordnen. Die Aufteilung ist bewusst ungleich — gleich
 * große Kacheln würden vier gleich wichtige Zahlen behaupten, und das stimmt
 * nicht. Auf der Übersicht steht dafür `.hero`, weil dort noch ein Diagramm
 * dazukommt.
 */
.overview-head {
  display: grid;
  gap: var(--s5);
  grid-template-columns: minmax(min(11rem, 100%), auto) 1fr;
  align-items: center;
}

@media (max-width: 52rem) {
  .overview-head { grid-template-columns: 1fr; gap: var(--s4); }
}

.metrics {
  display: grid;
  gap: var(--s4) var(--s5);
  grid-template-columns: repeat(auto-fit, minmax(min(10rem, 100%), 1fr));
}

.metric {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.metric__label {
  font-size: 0.82rem;
  color: var(--text-muted);
}

.metric__value {
  font-size: 1.4rem;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
}

/* Für Werte, die Text statt Zahl sind — 1.4rem wirkt dort wie Geschrei. */
.metric__value--small {
  font-size: 1.1rem;
  font-weight: 550;
}

.metric__note {
  font-size: 0.84rem;
  color: var(--text-faint);
  line-height: 1.45;
}

/* Kennzahlen nebeneinander, durch feine Linien getrennt statt durch Kästen. */
.metrics--ruled .metric + .metric {
  padding-left: var(--s5);
  border-left: 1px solid var(--border);
}

@media (max-width: 44rem) {
  .metrics--ruled .metric + .metric {
    padding-left: 0;
    border-left: none;
  }
}

/* --- Übersicht ----------------------------------------------------------- */

/*
 * Der Kopf der Übersicht trägt zwei Dinge nebeneinander, die vorher zwei Karten
 * untereinander waren: den Depotwert und seinen Verlauf. Eine Zahl ohne Kurve
 * sagt nicht, ob sie gut ist, und eine Kurve einen Bildschirm tiefer wird
 * dafür nicht mehr angesehen.
 *
 * Die Spalten sind ungleich, aber beide wachsen mit: Das Diagramm hat ein festes
 * Seitenverhältnis von drei zu eins, und wenn nur es den zusätzlichen Platz
 * bekommt, wächst mit der Breite auch die Höhe der ganzen Karte. Bei einer fest
 * gedeckelten linken Spalte von 20 rem stand die Zahl dann in einer Karte von
 * einem halben Tausend Punkten Höhe und hatte gut die Hälfte davon als Leerraum
 * um sich. Deshalb Anteile statt einer Obergrenze.
 *
 * Unter 64 rem stehen sie übereinander — nebeneinander bliebe für das Diagramm
 * eine Handbreit, und darin ist ein halbes Jahr Verlauf nicht mehr zu
 * unterscheiden.
 */
.hero {
  display: grid;
  gap: var(--s5);
  grid-template-columns: minmax(min(16rem, 100%), 1fr) minmax(0, 1.3fr);
  align-items: stretch;
}

@media (max-width: 64rem) {
  .hero { grid-template-columns: 1fr; }
}

/*
 * Der Block links füllt die Höhe des Diagramms: die große Zahl oben, darunter
 * die Aufstellung, deren Zeilen sich den Rest teilen. Zentriert stand beides als
 * Klumpen in der Mitte mit gleich viel Nichts darüber wie darunter; mit einem
 * Abstand am Ende (`space-between`) klaffte das Nichts dann in der Mitte.
 */
.hero__figure {
  display: flex;
  flex-direction: column;
  gap: var(--s4);
  min-width: 0;
}

.hero__lead {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
}

.hero__badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

/*
 * Beschriftung links, Zahl rechts, eine Linie dazwischen — dieselbe Ordnung wie
 * in einer Abrechnung. Die Linie steht oben und nicht unten, damit die letzte
 * Zeile nicht doppelt abgegrenzt wird, wo darunter schon der Kartenrand kommt.
 */
.hero__facts {
  display: grid;
  grid-auto-rows: 1fr;
  flex: 1;
  margin: 0;
}

.hero__facts > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  padding: var(--s2) 0;
  border-top: 1px solid var(--border);
}

.hero__facts dt {
  color: var(--text-muted);
  font-size: 0.9rem;
}

.hero__facts dd {
  margin: 0;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.hero__facts .faint { font-size: 0.82rem; }

/*
 * Gestapelt ist die Spalte so breit wie die Seite, und drei Zeilen mit je zwei
 * Wörtern und viel Nichts dazwischen sähen dort aus wie ein Fehler. Nebeneinander
 * haben sie dieselbe Form wie das Kennzahlenband der übrigen Seiten.
 */
@media (max-width: 64rem) {
  .hero__facts {
    grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr));
    grid-auto-rows: auto;
    flex: 0 1 auto;
    column-gap: var(--s5);
  }
}

.hero__chart { min-width: 0; }

.hero__more {
  margin: var(--s2) 0 0;
  font-size: 0.85rem;
  color: var(--text-faint);
}

/* Über die ganze Breite, damit die Warnung nicht neben der Zahl klemmt. */
.hero__warning { grid-column: 1 / -1; }

/*
 * Ein Etikett mit zwei Zeilen: Prozentwert oben, absoluter Betrag darunter. Der
 * Prozentwert allein sagt nichts über die Größenordnung, der Betrag allein
 * nichts über das Gewicht — zusammen sind sie eine Aussage.
 *
 * Der Rand trägt die Farbe, die Fläche bleibt gedämpft. Eine satte grüne Fläche
 * neben dem Depotwert liest sich wie eine Auszeichnung; hier steht nur, was
 * gemessen wurde.
 */
.chip {
  display: inline-flex;
  flex-direction: column;
  gap: 0.05rem;
  padding: 0.3rem var(--s3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: 0.92rem;
  font-weight: 550;
  font-variant-numeric: tabular-nums;
  line-height: 1.25;
}

.chip__sub {
  font-size: 0.78rem;
  font-weight: 400;
  color: var(--text-faint);
}

.chip--positiv { color: var(--up); border-color: color-mix(in oklab, var(--up) 45%, var(--border)); }
.chip--negativ { color: var(--down); border-color: color-mix(in oklab, var(--down) 45%, var(--border)); }
.chip--neutral { color: var(--text-muted); }

/*
 * Schnellzugriff: die sechs Wege, die von hier aus genommen werden. Vorher
 * standen zwei davon als Schaltflächen im Seitenkopf — dort übersieht man sie,
 * und die anderen vier fehlten ganz.
 *
 * Die Notiz unter der Beschriftung ist der eigentliche Zweck: Sie sagt, ob sich
 * der Klick lohnt, bevor man ihn tut.
 */
.shortcuts {
  display: grid;
  gap: var(--s3);
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-top: var(--s5);
}

/*
 * Feste Spaltenzahlen statt `auto-fit`: Sechs Kacheln füllen bei automatischer
 * Verteilung eine Zeile mit fünf und lassen eine allein stehen, und die sieht
 * dann aus wie vergessen. Drei mal zwei und zwei mal drei gehen immer auf.
 */
@media (min-width: 92rem) {
  .shortcuts { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}

@media (max-width: 52rem) {
  .shortcuts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/*
 * Auf dem Telefon eine Spalte. Zu zweit nebeneinander bleiben rund 150 Punkte
 * je Kachel, und dort passt weder „Order aufgeben" in eine Zeile noch die
 * Notiz darunter — beides brach mitten im Wort um.
 */
@media (max-width: 34rem) {
  .shortcuts { grid-template-columns: minmax(0, 1fr); }
}

.shortcut {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--text);
  text-decoration: none;
  transition: border-color 140ms ease, transform 140ms ease, background 140ms ease;
}

.shortcut:hover,
.shortcut:focus-visible {
  border-color: var(--accent);
  background: var(--surface-2);
  transform: translateY(-1px);
  text-decoration: none;
}

.shortcut__icon {
  display: inline-flex;
  flex: none;
  color: var(--accent);
}

.shortcut__icon svg {
  width: 1.35rem;
  height: 1.35rem;
  display: block;
}

.shortcut__body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/*
 * `overflow-wrap: normal` gegen die allgemeine Regel weiter oben: sechs Kacheln
 * nebeneinander sind schmal, und mitten im Wort getrenntes „Empfehlung-en"
 * liest sich wie ein Fehler. Lieber läuft der Text über den Rand hinaus, dann
 * fällt es beim Bauen auf.
 */
.shortcut__label {
  font-weight: 550;
  overflow-wrap: normal;
}

.shortcut__note {
  font-size: 0.82rem;
  color: var(--text-faint);
  overflow-wrap: normal;
}

/*
 * Die Zahl am Ziel steht nur da, wo es etwas zu entscheiden gibt. Eine „0"
 * neben „Märkte" behauptete eine Menge, die es dort nicht gibt.
 */
.shortcut__count {
  margin-left: auto;
  flex: none;
  min-width: 1.6rem;
  padding: 0.1rem 0.4rem;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 0.82rem;
  font-weight: 600;
  text-align: center;
}

/*
 * Eine Empfehlung in vier Zeilen: Aktion und Wert, Name, Erwartung, Konfidenz.
 * Vorher stand alles in einer Zeile mit Etiketten dazwischen — auf dem Telefon
 * brach sie an beliebiger Stelle um, und die Konfidenz landete unter dem Namen,
 * als gehörte sie dazu.
 */
.decisions { list-style: none; margin: 0; padding: 0; }

.decision {
  display: grid;
  gap: var(--s1) var(--s3);
  padding: var(--s4) 0;
  border-bottom: 1px solid var(--border);
  grid-template-columns: minmax(0, 1fr) minmax(0, auto);
  align-items: baseline;
}

.decision:first-child { padding-top: 0; }
.decision:last-child { border-bottom: none; padding-bottom: 0; }

.decision__head {
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex-wrap: wrap;
  min-width: 0;
}

.decision__title {
  font-weight: 600;
  font-size: 1.02rem;
}

.decision__meta {
  grid-column: 1;
  color: var(--text-faint);
  font-size: 0.85rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

.decision__outlook {
  grid-column: 1;
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex-wrap: wrap;
  margin-top: var(--s1);
}

.decision__horizon {
  color: var(--text-muted);
  font-size: 0.85rem;
}

/*
 * Die Konfidenz steht rechts und über beide unteren Zeilen. Sie ist die Zahl,
 * an der zwei Empfehlungen verglichen werden — in der Zeile mitlaufend wäre sie
 * eine Angabe unter vielen.
 */
.decision__confidence {
  grid-column: 2;
  grid-row: 2 / span 2;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.25rem;
  justify-self: end;
  width: min(9rem, 40vw);
}

.decision__confidence .bar { width: 100%; }

.decision__value {
  font-size: 0.82rem;
  color: var(--text-muted);
}

/* Gebuchtes tritt zurück, verschwindet aber nicht: die Empfehlung gilt weiter. */
.decision--booked { opacity: 0.72; }

@media (max-width: 40rem) {
  .decision { grid-template-columns: minmax(0, 1fr); }

  .decision__confidence {
    grid-column: 1;
    grid-row: auto;
    align-items: stretch;
    justify-self: stretch;
    width: 100%;
    margin-top: var(--s2);
  }

  .decision__value { text-align: right; }
}

/* Schmaler als der Balken in der Order-Vorschau: hier steht er in einer Zeile. */
.bar--slim { height: 0.3rem; }

/*
 * Positionen mit ihrem eigenen Verlauf. Der Streifen beantwortet die Frage, die
 * ein Prozentwert offen lässt: ob es stetig aufwärts ging oder einmal gesprungen
 * ist und seitdem steht.
 */
.holdings { list-style: none; margin: 0; padding: 0; }

.holding {
  display: grid;
  gap: var(--s2) var(--s4);
  grid-template-columns: minmax(7rem, 1.1fr) minmax(5rem, 0.9fr) minmax(6rem, auto) minmax(6rem, auto);
  align-items: center;
  padding: var(--s4) 0;
  border-bottom: 1px solid var(--border);
}

.holding:first-child { padding-top: 0; }
.holding:last-child { border-bottom: none; }

.holding__name {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.holding__name a { font-weight: 600; }

.holding__full {
  font-size: 0.8rem;
  color: var(--text-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.holding__trend {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.holding__figures,
.holding__result {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  text-align: right;
  min-width: 0;
}

.holding__value,
.holding__total {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.holding__share,
.holding__span {
  font-size: 0.78rem;
  color: var(--text-faint);
}

.holding__outlook {
  grid-column: 2 / -1;
  justify-self: end;
}

.holding__outlook:empty { display: none; }

@media (max-width: 52rem) {
  .holding {
    grid-template-columns: minmax(0, 1fr) minmax(0, auto);
    align-items: start;
  }

  /* Der Streifen läuft unter Name und Zahlen über die ganze Breite. */
  .holding__trend { grid-column: 1 / -1; order: 3; }
  .holding__figures { text-align: left; }
  .holding__result { grid-column: 2; grid-row: 1; }
  .holding__outlook { grid-column: 1 / -1; order: 4; justify-self: start; }
}

/*
 * Kleiner Kursverlauf. Die Fläche darunter ist gedämpft, die Linie trägt die
 * Farbe — umgekehrt zöge ein Streifen von fünf Zentimetern mehr Aufmerksamkeit
 * als der Depotwert darüber.
 */
.trend {
  display: block;
  width: 100%;
  height: 2.4rem;
  overflow: visible;
}

.trend__line { stroke-width: 1.8; stroke-linejoin: round; stroke-linecap: round; }

.trend--positiv .trend__line { stroke: var(--up); }
.trend--negativ .trend__line { stroke: var(--down); }
.trend--neutral .trend__line,
.trend--accent .trend__line { stroke: var(--accent); }

.trend__area { opacity: 0.55; }
.trend--positiv .trend__area { fill: var(--up-soft); }
.trend--negativ .trend__area { fill: var(--down-soft); }
.trend--neutral .trend__area,
.trend--accent .trend__area { fill: var(--accent-soft); }

/*
 * Der Ticker in der Randspalte der Übersicht.
 *
 * Dieselben Zeilen wie auf der Ereignisseite, aber zweizeilig: Zeit und Symbol
 * oben, der Titel darunter über die ganze Breite. Drei Spalten in einer Spalte
 * von zwanzig Zeichen ließen vom Titel ein Wortband übrig — es ist dieselbe
 * Aufteilung, die dort auf dem Telefon greift.
 */
.ticker--compact {
  padding: var(--s4);
  margin-bottom: 0;
}

.ticker--compact .ticker__head { margin-bottom: var(--s2); }

.ticker--compact .items > li {
  grid-template-columns: 3.2rem minmax(0, 1fr);
  gap: var(--s1) var(--s3);
}

.ticker--compact .ticker__line { grid-column: 1 / -1; }

/* Ein leerer Bereich in einer Karte, die schon einen Rahmen hat. */
.empty--flat { border: none; background: none; padding: 0; }

/*
 * Bewegung beim Aufbau.
 *
 * Einmalig und kurz: Die Seite soll sich setzen, nicht arbeiten. Eine dauerhaft
 * bewegte Fläche zieht den Blick von den Zahlen ab, und genau die sollen hier
 * gelesen werden.
 *
 * Die Staffelung kommt aus `:nth-child` und nicht aus einer Variablen am
 * Element: `style-src` erfasst auch `style`-Attribute, der sonst übliche Weg
 * scheidet damit aus. Sie zählt je Elternelement neu — in der zweispaltigen
 * Aufteilung laufen beide Spalten deshalb gleichzeitig ein, was gewollt ist.
 */
.reveal { animation: reveal 380ms cubic-bezier(0.22, 0.61, 0.36, 1) both; }

.reveal:nth-child(2) { animation-delay: 60ms; }
.reveal:nth-child(3) { animation-delay: 120ms; }
.reveal:nth-child(4) { animation-delay: 180ms; }

/*
 * Der zweispaltige Teil beginnt, wo der Hauptstrang aufhört. Die Zahlen sind
 * ausgeschrieben und nicht gerechnet — CSS kann Verzögerungen nicht addieren,
 * und eine Variable am Element scheidet wegen `style-src` aus.
 */
.split .stack--wide > .reveal:nth-child(1) { animation-delay: 200ms; }
.split .stack--wide > .reveal:nth-child(2) { animation-delay: 260ms; }
.split .stack--wide > .reveal:nth-child(3) { animation-delay: 320ms; }

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

/*
 * Das Diagramm im Kopf wischt von links auf. Nicht die Linie allein: Achsen,
 * Raster und Fläche gehören zum selben Bild, und eine Linie, die vor leerem
 * Raster entlangläuft, sieht nach Ladevorgang aus statt nach Aufbau.
 */
.hero__chart .chart__canvas { animation: chart-wipe 900ms ease-out 160ms both; }

@keyframes chart-wipe {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

/*
 * Die kleinen Verläufe wischen von links auf, mit derselben Bewegung wie das
 * Diagramm im Kopf.
 *
 * Vorher zeichnete sich die Linie über ein wanderndes `stroke-dasharray` nach,
 * und das ging hier nicht auf: Der Pfad trägt `vector-effect="non-scaling-stroke"`,
 * damit `preserveAspectRatio="none"` ihn nicht mitverzerrt. Damit rechnet der
 * Browser aber auch das Strichmuster in Bildschirmpunkten statt in den 100
 * Einheiten, auf die `pathLength` den Pfad normiert. Aus „hundert Einheiten
 * Strich" wurden hundert Punkte Strich und hundert Punkte Lücke — die fertige
 * Linie hatte zwei Löcher und sah aus, als fehlten Kurse. Ein Wisch über das
 * ganze Bild hat das Problem nicht und nimmt die Fläche gleich mit.
 */
.trend { animation: trend-wipe 700ms ease-out 220ms both; }

/*
 * Senkrecht schneidet der Endzustand großzügig frei, waagerecht nur knapp.
 * Grund ist derselbe wie beim Kurshintergrund (siehe `wp-draw`): Die Linie
 * trägt `non-scaling-stroke` und ragt damit über die Zeichenfläche hinaus, aber
 * der waagerechte Wert ist zugleich die Strecke der Bewegung.
 */
@keyframes trend-wipe {
  from { clip-path: inset(-30% 100% -30% 0); }
  to   { clip-path: inset(-30% -3% -30% 0); }
}

@media (prefers-reduced-motion: reduce) {
  .reveal,
  .hero__chart .chart__canvas,
  .trend {
    animation: none;
  }

  .shortcut { transition: none; }
}

/* --- Tabellen ------------------------------------------------------------ */

.table-scroll {
  overflow-x: auto;
  margin: 0 calc(var(--s5) * -1);
  padding: 0 var(--s5);
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.94rem;
}

caption {
  text-align: left;
  color: var(--text-muted);
  padding-bottom: var(--s2);
  font-size: 0.88rem;
}

th, td {
  text-align: left;
  padding: var(--s3);
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

th {
  font-weight: 550;
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text-faint);
  border-bottom-color: var(--border-strong);
  white-space: nowrap;
  padding-top: 0;
}

td.num, th.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

tbody tr:last-child td { border-bottom: none; }

tbody tr { transition: background 100ms ease; }
tbody tr:hover { background: var(--surface-2); }

/* Erste Spalte trägt meist den Namen — sie darf etwas kräftiger sein. */
.table--titled td:first-child { font-weight: 500; }

.table--compact th,
.table--compact td { padding: var(--s2) var(--s3); }

/* Zwischenüberschrift, wenn eine Karte mehrere Tabellen trägt. */
.group__title {
  display: flex;
  align-items: baseline;
  gap: var(--s2);
  margin: var(--s5) 0 var(--s3);
}

.group__title:first-of-type { margin-top: 0; }

.group__count {
  font-weight: 400;
  font-size: 0.85rem;
  color: var(--text-faint);
}

/* --- Listen -------------------------------------------------------------- */

.items {
  list-style: none;
  margin: 0;
  padding: 0;
}

.items > li {
  padding: var(--s3) 0;
  border-bottom: 1px solid var(--border);
}

.items > li:first-child { padding-top: 0; }
.items > li:last-child { padding-bottom: 0; border-bottom: none; }

.item__title {
  font-weight: 500;
  line-height: 1.4;
}

.item__title a { color: var(--text); text-decoration-color: var(--border-strong); }
.item__title a:hover { color: var(--accent); }

.item__text {
  margin: var(--s2) 0 0;
  color: var(--text-muted);
  max-width: var(--measure);
}

.item__meta {
  display: block;
  font-size: 0.85rem;
  color: var(--text-faint);
  margin-top: 0.15rem;
}

.items > li > .row { margin-top: var(--s2); }
.items > li > .item__text + .item__meta { margin-top: var(--s2); }

/*
 * Anklickbare Zeile mit Fläche. Für Listen, in denen der ganze Eintrag ein
 * Ziel ist — das trifft sich auf dem Telefon deutlich besser als ein Wort.
 */
.tiles {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s2);
}

.tile {
  display: block;
  padding: var(--s3) var(--s4);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: inherit;
  text-decoration: none;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}

.tile:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow);
  color: inherit;
}

.tile__title { font-weight: 550; }
.tile__meta { font-size: 0.85rem; color: var(--text-faint); }

/* --- Formulare ----------------------------------------------------------- */

label {
  display: block;
  font-size: 0.88rem;
  font-weight: 500;
  color: var(--text);
  margin-bottom: var(--s1);
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="search"],
input[type="number"],
input[type="date"],
select,
textarea {
  width: 100%;
  padding: 0.5rem var(--s3);
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  transition: border-color 120ms ease, box-shadow 120ms ease;
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

input::placeholder { color: var(--text-faint); }

textarea { min-height: 6rem; resize: vertical; }

.field { margin-bottom: var(--s4); }
.field--inline { display: flex; gap: var(--s2); align-items: flex-end; }

.field__hint {
  font-size: 0.83rem;
  color: var(--text-faint);
  margin-top: var(--s1);
  line-height: 1.45;
}

fieldset {
  border: none;
  padding: 0;
  margin: 0 0 var(--s5);
}

legend {
  padding: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--s3);
}

/* --- Schaltflächen ------------------------------------------------------- */

button,
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  padding: 0.5rem var(--s4);
  font: inherit;
  font-weight: 550;
  font-size: 0.94rem;
  color: var(--on-accent);
  background: var(--accent);
  border: 1px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition: background 120ms ease, border-color 120ms ease;
}

button:hover,
.button:hover {
  background: var(--accent-strong);
  color: var(--on-accent);
}

button.secondary,
.button.secondary {
  background: var(--surface);
  color: var(--text);
  border-color: var(--border-strong);
}

button.secondary:hover,
.button.secondary:hover {
  background: var(--surface-2);
  color: var(--text);
}

button.quiet,
.button.quiet {
  background: none;
  color: var(--text-muted);
  border-color: transparent;
}

button.quiet:hover,
.button.quiet:hover {
  background: var(--surface-2);
  color: var(--text);
}

button.link {
  background: none;
  border: none;
  color: var(--accent);
  padding: 0;
  text-decoration: underline;
  text-underline-offset: 0.18em;
  font-weight: 400;
}

button.link:hover {
  background: none;
  color: var(--accent-strong);
}

button.small,
.button.small {
  padding: 0.3rem var(--s3);
  font-size: 0.86rem;
}

button:disabled,
.button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* --- Filterleiste -------------------------------------------------------- */

/*
 * Eine Reihe von Ansichten desselben Bestands. Sie sieht aus wie ein Schalter,
 * ist aber eine Reihe von Verweisen — jede Ansicht hat damit eine eigene
 * Adresse und lässt sich als Lesezeichen ablegen.
 */
.segmented {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--s1);
  padding: var(--s1);
  background: var(--surface-2);
  border-radius: var(--radius-pill);
}

.segmented a {
  padding: 0.32rem var(--s3);
  border-radius: var(--radius-pill);
  font-size: 0.88rem;
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
  transition: background 120ms ease, color 120ms ease;
}

.segmented a:hover { color: var(--text); }

/*
 * Der Umschalter zwischen Kerze und Linie sieht aus wie seine Nachbarn, ist
 * aber eine Gruppe von Optionsfeldern. Der Grund steht in der Vorlage: Ein
 * Verweis holt die Seite, und die Seite fängt oben an.
 *
 * Die Beschriftungen tragen deshalb dieselben Werte wie die Verweise darüber.
 * Zusammengefasst sind sie nicht — ein `a, label`-Selektor spräche auch die
 * Beschriftungen der Formularfelder an, und dort gilt anderes.
 */
.chartswitch__tabs label {
  padding: 0.32rem var(--s3);
  border-radius: var(--radius-pill);
  font-size: 0.88rem;
  color: var(--text-muted);
  white-space: nowrap;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}

.chartswitch__tabs label:hover { color: var(--text); }

/*
 * Das Feld liegt versteckt hinter seiner Beschriftung und kann den Fokusring
 * nicht selbst zeigen. Ohne diese Regel bedient man die Gruppe mit der Tastatur
 * blind: Die Auswahl wandert, sichtbar ist davon nichts.
 */
.chartswitch__radio:focus-visible + label {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.chartswitch__radio:checked + label,
.segmented a[aria-current="true"] {
  background: var(--surface);
  color: var(--text);
  font-weight: 550;
  box-shadow: var(--shadow-sm);
}

/*
 * Beide Zeichnungen stehen im Dokument, sichtbar ist eine.
 *
 * Zwei Ebenen, und die Reihenfolge ist Absicht: Zuerst entscheidet `is-active`,
 * was der Server gewählt hat — das gilt auch dort, wo `:has()` fehlt. Danach
 * überschreiben die `:has()`-Regeln mit dem, was der Nutzer angeklickt hat. Sie
 * stehen später und sind spezifischer, gewinnen also in beiden Hinsichten.
 *
 * Ohne `:has()` (vor Chrome 105, Safari 15.4, Firefox 121) bleibt der Stand aus
 * der Adresse stehen und die Beschriftungen tun nichts. Das ist der Zustand von
 * vorher, nur ohne Neuladen — kein Ausfall, nur kein Gewinn.
 */
.chartswitch__pane { display: none; }
.chartswitch__pane.is-active { display: block; }

.chartswitch:has(#darstellung-kerzen:checked) .chartswitch__pane--kerzen,
.chartswitch:has(#darstellung-linie:checked) .chartswitch__pane--linie {
  display: block;
}

.chartswitch:has(#darstellung-kerzen:checked) .chartswitch__pane--linie,
.chartswitch:has(#darstellung-linie:checked) .chartswitch__pane--kerzen {
  display: none;
}

/* --- Umschalter für hell und dunkel -------------------------------------- */

/*
 * Sieht aus wie die Segmentgruppe darüber, ist aber ein Formular: die Wahl wird
 * abgeschickt und nicht verlinkt. Deshalb kann sie sich die Regeln nicht
 * teilen — Verweise und Knöpfe erben Unterschiedliches.
 */
.themeswitch {
  padding: var(--s1) var(--s3) var(--s2);
}

/* Beschriftung links, aktuelle Wahl rechts — zusammen eine Zeile über der Gruppe. */
.themeswitch__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s2);
  padding-bottom: var(--s1);
  font-size: 0.85rem;
}

.themeswitch__label { color: var(--text-faint); }

/*
 * Die gewählte Darstellung im Klartext. Sie ersetzt die weggefallene
 * Beschriftung der Knöpfe: Ein halb gefüllter Kreis sagt niemandem
 * „automatisch", und der Zustand soll ablesbar sein, ohne ein Sinnbild zu
 * deuten.
 */
.themeswitch__current {
  color: var(--text);
  font-weight: 550;
}

.themeswitch__group {
  display: flex;
  gap: var(--s1);
  padding: var(--s1);
  background: var(--surface-2);
  border-radius: var(--radius-pill);
}

/*
 * Die Menütafel macht aus jedem Knopf eine linksbündige Zeile über die ganze
 * Breite. Hier stehen drei nebeneinander, deshalb wird das zurückgenommen.
 *
 * Alle drei sind gleich breit, weil sie dasselbe tragen: ein Sinnbild fester
 * Größe. Mit Beschriftung ging das nicht auf — „Automatisch" braucht mehr als
 * doppelt so viel Platz wie „Hell", und bei gleicher Verteilung stand der Text
 * über seine Hervorhebung hinaus.
 */
.menu__panel .themeswitch__option,
.themeswitch__option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 1;
  width: auto;
  min-width: 0;
  padding: 0.36rem var(--s2);
  border: none;
  border-radius: var(--radius-pill);
  background: none;
  color: var(--text-muted);
  font: inherit;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}

.themeswitch__icon {
  width: 1.05rem;
  height: 1.05rem;
  display: block;
}

.menu__panel .themeswitch__option:hover,
.themeswitch__option:hover {
  background: none;
  color: var(--text);
  filter: none;
}

.menu__panel .themeswitch__option.is-active,
.themeswitch__option.is-active {
  background: var(--surface);
  color: var(--accent);
  box-shadow: var(--shadow-sm);
}

/*
 * Die kompakte Fassung für Kopf- und Fußzeilen. Sie ist nicht nur enger,
 * sondern deutlich leiser: keine getönte Trägerfläche, keine Beschriftung,
 * keine Hervorhebung mit Fläche und Schatten. Drei Sinnbilder, von denen eines
 * dunkler ist.
 *
 * Der Grund steht in der Vorlage: Auf der Anmeldeseite und im Kopf der
 * Produktseite ist die Darstellung eine Nebensache neben dem, weswegen jemand
 * da ist. In voller Ausführung war der Umschalter dort das Auffälligste im
 * Bild — eine getönte Pille mit drei Feldern zieht mehr Blick als ein
 * Anmeldeformular.
 */
.themeswitch--compact {
  display: flex;
  align-items: center;
  padding: 0;
}

/*
 * Der Kopf trägt hier nur noch das versteckte Wort „Darstellung". Das liegt
 * absolut und braucht keinen Platz — seine Polsterung aus der vollen Fassung
 * schöbe die Knöpfe trotzdem um ein paar Pixel nach unten.
 */
.themeswitch--compact .themeswitch__head { padding-bottom: 0; }

.themeswitch--compact .themeswitch__group {
  gap: 0;
  padding: 0;
  background: none;
}

.themeswitch--compact .themeswitch__option {
  flex: 0 0 auto;
  padding: 0.34rem 0.42rem;
  color: var(--text-faint);
}

.themeswitch--compact .themeswitch__icon {
  width: 0.95rem;
  height: 0.95rem;
}

/*
 * Die geltende Wahl trägt Farbe, sonst nichts. Fläche und Schatten wie in der
 * vollen Fassung machten aus dem Trio wieder eine Schaltergruppe; hier soll man
 * es erst bemerken, wenn man es sucht.
 */
.themeswitch--compact .themeswitch__option.is-active {
  background: none;
  box-shadow: none;
  color: var(--text);
}

.themeswitch--compact .themeswitch__option:hover { color: var(--text); }

/*
 * Auf der Anmeldeseite steht der Umschalter im Fuß, über dem Rechtshinweis. Der
 * Fuß ist dort mittig gesetzt, der Umschalter aber ein Block mit eigener
 * Breite — ohne `justify-content` stünde er linksbündig unter einer zentrierten
 * Zeile.
 */
.footer--plain .themeswitch--compact {
  justify-content: center;
  margin-bottom: var(--s2);
}

/* --- Hinweise ------------------------------------------------------------ */

.notice {
  display: flex;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  margin-bottom: var(--s5);
  box-shadow: var(--shadow-sm);
}

.notice--ok      { background: var(--up-soft); border-color: transparent; }
.notice--fehler  { background: var(--down-soft); border-color: transparent; }
.notice--hinweis { background: var(--warn-soft); border-color: transparent; }

.alert {
  border-left: 3px solid var(--border-strong);
  padding: var(--s3) var(--s4);
  background: var(--surface-2);
  border-radius: 0 var(--radius) var(--radius) 0;
}

.alert--warn  { border-left-color: var(--warn); background: var(--warn-soft); }
.alert--error { border-left-color: var(--down); background: var(--down-soft); }
.alert--ok    { border-left-color: var(--up); background: var(--up-soft); }

.alert > * + * { margin-top: var(--s2); }
.alert ul { margin: 0; padding-left: 1.2rem; }

/*
 * Leerzustand. Er sagt, was fehlt und was es füllen würde — ein leerer
 * Kasten mit „keine Daten" hilft niemandem weiter.
 */
.empty {
  color: var(--text-muted);
  padding: var(--s6) var(--s4);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  text-align: center;
  font-size: 0.94rem;
}

.empty strong { color: var(--text); font-weight: 550; }
.empty p { margin: 0; }
.empty p + p { margin-top: var(--s2); }

/* --- Etiketten ----------------------------------------------------------- */

/*
 * Farbe und Grund stehen in eigenen Merkmalen, nicht direkt in der Regel. Das
 * kostet zwei Zeilen und spart sie an anderer Stelle: Ein Etikett, das als
 * Schaltfläche gebaut ist (siehe `.tag--asks`), erbt sonst beim Zeigen die
 * Akzentfarbe aller Schaltflächen und verliert seine eigene.
 */
.tag {
  --tag-bg: var(--surface-2);
  --tag-fg: var(--text-muted);

  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.12rem 0.5rem;
  font-size: 0.78rem;
  font-weight: 500;
  line-height: 1.5;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  color: var(--tag-fg);
  background: var(--tag-bg);
  white-space: nowrap;
}

.tag--strong { --tag-fg: var(--accent); --tag-bg: var(--accent-soft); }
.tag--warn   { --tag-fg: var(--warn);   --tag-bg: var(--warn-soft); }
.tag--down   { --tag-fg: var(--down);   --tag-bg: var(--down-soft); }
.tag--up     { --tag-fg: var(--up);     --tag-bg: var(--up-soft); }
.tag--plain  { --tag-bg: none; border-color: var(--border); }

/*
 * Etikett, das eine Erklärung bereithält. Als Schaltfläche gebaut, damit es
 * die Tastatur erreicht — die Schaltflächengestalt muss deshalb wieder
 * abgeräumt werden. Die gepunktete Linie ist dieselbe wie am Fachbegriff im
 * Text: gleiche Zusage, gleiches Zeichen.
 */
.tag--asks {
  font-family: inherit;
  letter-spacing: normal;
  text-transform: none;
  text-decoration: underline dotted currentColor;
  text-underline-offset: 0.22em;
  cursor: help;
}

.tag--asks:hover,
.tag--asks:focus-visible {
  color: var(--tag-fg);
  background: var(--tag-bg);
  text-decoration-style: solid;
}

/* Punkt vor dem Wort: trägt die Farbe, ohne dass sie den Text einfärbt. */
.dot {
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

/* --- Balken -------------------------------------------------------------- */

.bar {
  height: 0.4rem;
  background: var(--surface-2);
  border-radius: var(--radius-pill);
  overflow: hidden;
}

.bar__fill {
  height: 100%;
  background: var(--accent);
  border-radius: var(--radius-pill);
}

.bar--up .bar__fill { background: var(--up); }
.bar--down .bar__fill { background: var(--down); }

/*
 * Breiten und Höhen kommen aus festen Klassen, nicht aus style-Attributen:
 * die Content-Security-Policy verbietet Inline-Stile. Fünf-Prozent-Schritte
 * sind für eine Balkenanzeige genau genug.
 */
.w0   { width: 0; }
.w5   { width: 5%; }
.w10  { width: 10%; }
.w15  { width: 15%; }
.w20  { width: 20%; }
.w25  { width: 25%; }
.w30  { width: 30%; }
.w35  { width: 35%; }
.w40  { width: 40%; }
.w45  { width: 45%; }
.w50  { width: 50%; }
.w55  { width: 55%; }
.w60  { width: 60%; }
.w65  { width: 65%; }
.w70  { width: 70%; }
.w75  { width: 75%; }
.w80  { width: 80%; }
.w85  { width: 85%; }
.w90  { width: 90%; }
.w95  { width: 95%; }
.w100 { width: 100%; }

.h5   { height: 5%; }
.h10  { height: 10%; }
.h15  { height: 15%; }
.h20  { height: 20%; }
.h25  { height: 25%; }
.h30  { height: 30%; }
.h35  { height: 35%; }
.h40  { height: 40%; }
.h45  { height: 45%; }
.h50  { height: 50%; }
.h55  { height: 55%; }
.h60  { height: 60%; }
.h65  { height: 65%; }
.h70  { height: 70%; }
.h75  { height: 75%; }
.h80  { height: 80%; }
.h85  { height: 85%; }
.h90  { height: 90%; }
.h95  { height: 95%; }
.h100 { height: 100%; }

/* --- Angabenlisten ------------------------------------------------------- */

.facts { margin: 0; }

.facts > div {
  display: grid;
  grid-template-columns: minmax(8rem, 13rem) 1fr;
  gap: var(--s2) var(--s4);
  padding: var(--s3) 0;
  border-bottom: 1px solid var(--border);
}

.facts > div:first-child { padding-top: 0; }
.facts > div:last-child { border-bottom: none; padding-bottom: 0; }

.facts dt { color: var(--text-muted); font-size: 0.9rem; }
.facts dd { margin: 0; }

@media (max-width: 34rem) {
  .facts > div { grid-template-columns: 1fr; gap: 0.1rem; }
}

/* --- Aufklappbare Abschnitte --------------------------------------------- */

/*
 * Der Kern der Entlastung: das Wesentliche steht offen, die Belege stecken
 * darunter. <details> kann das ohne Skript, behält den Inhalt im Dokument
 * (Suchfunktion, Vorlesen, Drucken finden ihn) und ist über die Tastatur
 * bedienbar. Nichts verschwindet — es tritt nur einen Schritt zurück.
 */
.disclose {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

.disclose + .disclose { margin-top: var(--s2); }

.disclose > summary {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  cursor: pointer;
  list-style: none;
  font-weight: 550;
  font-size: 0.95rem;
  transition: background 120ms ease;
}

.disclose > summary::-webkit-details-marker { display: none; }
.disclose > summary::marker { content: ""; }
.disclose > summary:hover { background: var(--surface-2); }

/* Pfeil, der sich beim Öffnen dreht. Kein Bild, nur zwei Kanten. */
.disclose > summary::before {
  content: "";
  width: 0.42rem;
  height: 0.42rem;
  border-right: 2px solid var(--text-faint);
  border-bottom: 2px solid var(--text-faint);
  transform: rotate(-45deg);
  transition: transform 150ms ease;
  flex: none;
  margin-left: 0.15rem;
}

.disclose[open] > summary::before { transform: rotate(45deg); }

.disclose__count {
  margin-left: auto;
  font-weight: 400;
  font-size: 0.85rem;
  color: var(--text-faint);
}

.disclose__body {
  padding: var(--s2) var(--s4) var(--s4);
  border-top: 1px solid var(--border);
}

.disclose[open] > summary { background: var(--surface-2); }

/*
 * Nebensache neben einer Umschaltung: kein Kasten über die ganze Breite,
 * sondern ein unauffälliger Schalter, der erst beim Öffnen Platz nimmt.
 */
.disclose--inline {
  position: relative;
  border: none;
  background: none;
  overflow: visible;
}

.disclose--inline > summary {
  padding: 0.3rem 0;
  font-weight: 400;
  font-size: 0.88rem;
  color: var(--text-muted);
}

.disclose--inline > summary:hover,
.disclose--inline[open] > summary {
  background: none;
  color: var(--text);
}

.disclose--inline > .disclose__body {
  position: absolute;
  right: 0;
  z-index: 20;
  margin-top: var(--s2);
  padding: var(--s3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}

@media (prefers-reduced-motion: reduce) {
  .disclose > summary::before { transition: none; }
  html { scroll-behavior: auto; }
  * { transition: none !important; }
}

/* --- Kursverlauf --------------------------------------------------------- */

/*
 * Sparkline aus reinem CSS: ein Balken je Tagesstand. Keine Bibliothek, kein
 * Skript, keine Datei — und auf einem Kursverlauf über wenige Wochen liest
 * sich das genauso gut wie eine Linie.
 */
.spark {
  display: flex;
  align-items: flex-end;
  gap: 1px;
  height: 5rem;
  padding: var(--s1) 0;
}

.spark__bar {
  flex: 1 1 0;
  min-width: 1px;
  background: var(--accent-soft);
  border-top: 2px solid var(--accent);
  border-radius: 1px 1px 0 0;
}

/* --- Diagramm ------------------------------------------------------------ */

/*
 * Die Geometrie kommt aus Presentation\Chart, das Aussehen ausschließlich von
 * hier. Grund ist nicht Ordnungsliebe: Farben im Markup wären style-Attribute
 * (von der CSP verboten) oder feste Werte (im Dunkelmodus falsch).
 *
 * Zurückhaltung ist Absicht. Ein Kursverlauf soll ablesbar sein, nicht
 * aufregend — deshalb dünne Linien, ein blasses Gitter und eine Füllung, die
 * kaum mehr ist als ein Hauch.
 */
.chart {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s2);
}

.chart__canvas {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.chart__grid line {
  stroke: var(--border);
  stroke-width: 1;
}

.chart__line {
  fill: none;
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.chart__line--accent  { stroke: var(--accent); }
.chart__line--up      { stroke: var(--up); }
.chart__line--down    { stroke: var(--down); }

/* Der Vergleichswert tritt zurück: gestrichelt, dünn, gedämpft. Er ist Maßstab,
   nicht Gegenstand. */
.chart__line--compare {
  stroke: var(--text-faint);
  stroke-width: 1.5;
  stroke-dasharray: 5 4;
}

.chart__area--accent { fill: var(--accent-soft); }
.chart__area--up     { fill: var(--up-soft); }
.chart__area--down   { fill: var(--down-soft); }

/* Der Erwartungsbereich ist bewusst durchscheinend: eine satte Fläche würde
   Gewissheit behaupten, wo eine Spanne gemeint ist. */
.chart__band          { opacity: 0.5; }
.chart__band--accent  { fill: var(--accent-soft); }
.chart__band--up      { fill: var(--up-soft); }
.chart__band--down    { fill: var(--down-soft); }

.chart__divider {
  stroke: var(--border-strong);
  stroke-width: 1;
  stroke-dasharray: 3 3;
}

/* --- Kerzen ------------------------------------------------------------- */

/*
 * Docht und Körper tragen dieselbe Farbe. Die verbreitete Variante mit hohlem
 * Körper für steigende Kerzen stammt aus dem Schwarzweißdruck; auf einem
 * Bildschirm mit Dunkelmodus kostet sie nur Kontrast.
 *
 * Die Farbe folgt der klassischen Lesart: Schlusskurs über Eröffnung ist
 * aufwärts. Nicht der Vergleich zum Vortag — das wäre eine andere Aussage.
 */
.chart__wick { stroke-width: 1; }

.chart__candle--up   .chart__wick { stroke: var(--up); }
.chart__candle--down .chart__wick { stroke: var(--down); }
.chart__candle--flat .chart__wick { stroke: var(--text-faint); }

.chart__candle--up   .chart__body { fill: var(--up); }
.chart__candle--down .chart__body { fill: var(--down); }
.chart__candle--flat .chart__body { fill: var(--text-faint); }

/*
 * Das Volumen ist Begleitinformation, kein zweiter Kurs. Es tritt deshalb
 * deutlich zurück — sonst zöge die Fläche unten den Blick von der Kursbewegung
 * ab, um die es geht.
 */
.chart__volume-bar { opacity: 0.45; }

.chart__volume-bar--up   { fill: var(--up); }
.chart__volume-bar--down { fill: var(--down); }
.chart__volume-bar--flat { fill: var(--text-faint); }

/* Ohne Grundlinie ließe sich die Höhe eines Balkens nicht einordnen. */
.chart__baseline {
  stroke: var(--border);
  stroke-width: 1;
}

.chart__point       { stroke: var(--surface); stroke-width: 2; }
.chart__point--accent { fill: var(--accent); }
.chart__point--up     { fill: var(--up); }
.chart__point--down   { fill: var(--down); }

.chart__tick {
  fill: var(--text-faint);
  font-family: var(--font-body);
  font-size: 11px;
}

.chart__tick--value  { text-anchor: end; }
.chart__tick--start  { text-anchor: start; }
.chart__tick--middle { text-anchor: middle; }
.chart__tick--end    { text-anchor: end; }

/* Die Wertmarke über der Linie wird erst auf schmalen Bildschirmen gebraucht.
   Siehe die Begründung in views/partials/chart.php. */
.chart__tick--above {
  display: none;

  /*
   * Diese Marke steht nicht am Rand, sondern in der Zeichenfläche — und damit
   * dort, wo auch Kerzen stehen. Ohne Freistellung schneidet der erste Docht
   * mitten durch die Zahl, und eine 95,00 mit einem roten Strich darin sieht
   * aus wie ein Fehler in den Daten. Die Kontur in Hintergrundfarbe liegt
   * dank `paint-order` unter der Schrift und legt sie frei.
   */
  paint-order: stroke fill;
  stroke: var(--surface);
  stroke-width: 4px;
  stroke-linejoin: round;
}

.chart__caption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s2) var(--s4);
  color: var(--text-muted);
  font-size: 0.85rem;
}

.chart__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
}

/* Der Punkt vor dem Namen trägt die Farbe der zugehörigen Linie. */
.chart__key {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  color: var(--text);
}

.chart__key::before {
  content: "";
  width: 0.7rem;
  height: 0.2rem;
  border-radius: var(--radius-pill);
  background: var(--accent);
}

.chart__key--up::before      { background: var(--up); }
.chart__key--down::before    { background: var(--down); }
.chart__key--compare::before { background: var(--text-faint); }

/* Kerzen und Volumen sind Flächen, keine Linien — der Schlüssel zeigt das. */
.chart__key--candle-up::before,
.chart__key--candle-down::before,
.chart__key--volume::before {
  width: 0.4rem;
  height: 0.8rem;
  border-radius: 1px;
}

.chart__key--candle-up::before   { background: var(--up); }
.chart__key--candle-down::before { background: var(--down); }
.chart__key--volume::before      { background: var(--text-faint); opacity: 0.45; }

.chart__note { color: var(--text-faint); }

/* --- Was aus einer Empfehlung folgt -------------------------------------- */

/*
 * Die erste Karte einer Empfehlung beantwortet eine einzige Frage: was ist zu
 * tun. Sie steht deshalb vor der Begründung und trägt dieselbe Akzentkante wie
 * die Order-Vorschau — beides sind Stellen, an denen etwas entschieden wird.
 */
.decide { border-left: 3px solid var(--accent); }

.todo__do {
  margin: 0;
  font-size: 1.15rem;
  line-height: 1.45;
  font-weight: 500;
  max-width: var(--measure);
}

.todo__note {
  margin: var(--s2) 0 0;
  color: var(--text-muted);
  font-size: 0.92rem;
  line-height: 1.5;
  max-width: var(--measure);
}

/*
 * Was der Klick auslösen würde, in Zahlen.
 *
 * Sie stehen zwischen Satz und Knopf, weil der Knopf ohne sie eine Zumutung
 * wäre: gebucht wird sofort, also muss vorher lesbar sein, wie viele Anteile zu
 * welchem Kurs den Besitzer wechseln und was das kostet. Etwas größer als eine
 * Fußnote und in der Textfarbe — es ist die Rechnung, nicht ihr Kleingedrucktes.
 */
.todo__figures {
  margin: var(--s2) 0 0;
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--text-muted);
  max-width: var(--measure);
}

.todo__figures strong {
  color: var(--text);
  font-weight: 600;
}

/* Die Kostenquote ist der Nebensatz zur Rechnung: sie erklärt, welche Hürde der
   Kurs nehmen muss, drängt sich aber nicht vor die Stückzahl. */
.todo__cost { color: var(--text-faint); }

/* Eine Rechnung, die nicht aufgeht, gehört an den Vorschlag — nicht hinter den
   Knopf, den es dann ohnehin nicht gibt. */
.todo__note--warn { color: var(--down); }

.todo__go {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2) var(--s3);
  margin: var(--s4) 0 0;
}

.todo__hint {
  font-size: 0.85rem;
  color: var(--text-faint);
}

/* Als eigene Zeile unter dem Knopf, nicht als Wort daneben. */
p.todo__hint {
  margin: var(--s2) 0 0;
  max-width: var(--measure);
}

/*
 * Ist der Vorschlag schon gebucht, tritt er zurück und die Buchung nach vorn.
 * Der Satz bleibt trotzdem stehen — ohne ihn wüsste man nicht mehr, worauf sich
 * die Buchung bezieht.
 */
.todo--done .todo__do {
  color: var(--text-muted);
  font-weight: 400;
}

.todo__done {
  display: flex;
  gap: var(--s2);
  margin: var(--s2) 0 0;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--text);
  max-width: var(--measure);
}

.todo__done::before {
  content: "";
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  margin-top: 0.45em;
  border-radius: 50%;
  background: var(--up);
}

/* Ein zweiter Kauf bleibt möglich, drängt sich aber nicht auf. */
.todo__again {
  font-size: 0.85rem;
  color: var(--text-faint);
}

/* Ein Formular mit einem einzigen Knopf soll die Zeile nicht umbrechen. */
.inline-form { display: inline; }

/*
 * In der Liste steht derselbe Satz kleiner und ohne Herleitung: dort trägt ihn
 * schon die Überschrift der Zeile, und zwanzig Erklärungen untereinander liest
 * niemand.
 */
.todo--compact { margin-top: var(--s2); }

.todo--compact .todo__do {
  font-size: 1rem;
  font-weight: 400;
  color: var(--text-muted);
}

.todo--compact .todo__go { margin-top: var(--s3); }

/* Einträge, in denen ein Knopf sitzt, brauchen mehr Luft als eine Textzeile. */
.items--roomy > li { padding: var(--s4) 0; }
.items--roomy > li:first-child { padding-top: 0; }
.items--roomy > li:last-child { padding-bottom: 0; }

/* --- Kurs und laufende Rechnung im Orderformular ------------------------- */

/*
 * Sitzt zwischen den Eingabefeldern und dem Knopf und wächst beim Tippen von
 * einer Zeile auf einen kleinen Block. Deshalb eine Mindesthöhe: ohne sie
 * springt der Knopf darunter bei der ersten eingegebenen Ziffer weg.
 */
.figures {
  min-height: 3.4rem;
  padding: var(--s3) var(--s4);
  margin-bottom: var(--s4);
  background: var(--surface-2);
  border-radius: var(--radius);
}

.figures__idle {
  margin: 0;
  color: var(--text-faint);
  font-size: 0.88rem;
  line-height: 1.5;
}

.figures__quote {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s2) var(--s3);
}

/* Der Kurs ist die Zahl, wegen der jemand hersieht — entsprechend groß. */
.figures__price {
  font-size: 1.24rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}

.figures__price .faint { font-size: 0.72em; font-weight: 400; }

.figures__change {
  font-size: 0.92rem;
  font-weight: 550;
  font-variant-numeric: tabular-nums;
}

.figures__at {
  margin-left: auto;
  color: var(--text-faint);
  font-size: 0.82rem;
}

/*
 * Die Rechnung als Beschriftung-Wert-Paare. Die Trennlinie oben grenzt sie vom
 * Kurs ab: der Kurs kommt vom Markt, alles darunter ist gerechnet.
 */
/*
 * Der Abstand zwischen Beschriftung und Zahl steckt im Innenabstand der Zahl,
 * nicht in `column-gap`. Sonst risse die Linie über der Summe genau in der
 * Lücke zwischen den Spalten auf und sähe aus wie zwei Striche.
 */
.figures__calc {
  display: grid;
  grid-template-columns: 1fr auto;
  row-gap: var(--s1);
  margin: var(--s3) 0 0;
  padding-top: var(--s3);
  border-top: 1px solid var(--border);
  font-size: 0.9rem;
}

.figures__calc > div {
  display: contents;
}

.figures__calc dt {
  color: var(--text-muted);
}

.figures__calc dd {
  margin: 0;
  padding-left: var(--s3);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Die Summe ist das Ergebnis und trägt entsprechend Gewicht. */
.figures__sum dt,
.figures__sum dd {
  padding-top: var(--s1);
  border-top: 1px solid var(--border);
  font-weight: 600;
  color: var(--text);
}

.figures__note {
  margin: var(--s2) 0 0;
  color: var(--text-faint);
  font-size: 0.8rem;
  line-height: 1.45;
}

/*
 * Ein gesperrter Auftrag ist hier kein Alarm, sondern eine Auskunft beim Tippen
 * — etwa dass das Guthaben nicht reicht. Deshalb ein Hinweis in Warnfarbe statt
 * eines Kastens über die ganze Breite.
 */
.figures__blocked {
  margin: var(--s3) 0 0;
  padding-top: var(--s3);
  border-top: 1px solid var(--border);
  color: var(--warn);
  font-size: 0.88rem;
  line-height: 1.45;
}

/* --- Order-Vorschau ------------------------------------------------------ */

/* Die Vorschau steht bewusst abgesetzt: sie ist ein Zwischenschritt, kein
   Ergebnis. Der Akzentrand macht sichtbar, dass hier noch nichts gebucht ist. */
.preview {
  border-left: 3px solid var(--accent);
  scroll-margin-top: var(--s6);
}

.preview__lead {
  font-size: 1.05rem;
  line-height: 1.5;
}

/* Woher der Auftrag kommt. Steht über der Rechnung, weil es die Rechnung
   einordnet — hinterher gelesen wäre es eine Fußnote. */
.preview__from {
  margin: calc(var(--s3) * -1) 0 var(--s4);
  padding: var(--s3) var(--s4);
  background: var(--accent-soft);
  border-radius: var(--radius);
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--text-muted);
  max-width: var(--measure);
}

.preview__title {
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 600;
}

.preview__confirm {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
  align-items: center;
}

.shifts {
  list-style: none;
  padding: 0;
  display: grid;
  gap: var(--s4);
}

.shift {
  display: grid;
  gap: var(--s2);
  padding-bottom: var(--s4);
  border-bottom: 1px solid var(--border);
}

.shift:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

.shift__label {
  color: var(--text-muted);
  font-size: 0.9rem;
}

.shift__values {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--s2);
  font-variant-numeric: tabular-nums;
}

.shift__before {
  color: var(--text-faint);
}

.shift__arrow {
  color: var(--text-faint);
}

.shift__after {
  font-weight: 600;
  font-size: 1.1rem;
}

.shift__after--over { color: var(--down); }

.shift__note {
  color: var(--text-faint);
  font-size: 0.85rem;
}

/* Der Balken: heller Streifen ist der Stand heute, der kräftige der Stand
   nach der Order, der senkrechte Strich die Grenze. */
/* Ueber die volle Kartenbreite gezogen wirkt ein Balken wie eine Trennlinie
   und nicht mehr wie eine Menge. Deshalb die Begrenzung. */
.gauge {
  width: 100%;
  max-width: 22rem;
  height: 20px;
  overflow: visible;
}

.gauge__track  { fill: var(--surface-3); }
.gauge__before { fill: var(--text-faint); }
.gauge__after  { fill: var(--accent); }
.gauge__after--over { fill: var(--down); }

.gauge__limit {
  stroke: var(--text);
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
}

/* --- Fußzeile ------------------------------------------------------------ */

.footer {
  border-top: 1px solid var(--border);
  color: var(--text-faint);
  font-size: 0.85rem;
  padding-top: var(--s5);
  padding-bottom: var(--s6);
}

.footer p { margin: 0 0 var(--s1); max-width: var(--measure); }
.footer--plain { border: none; text-align: center; }

/* --- Anmeldung ----------------------------------------------------------- */

.card__brand {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-size: 1.3rem;
  font-weight: 660;
  letter-spacing: -0.032em;
  margin-bottom: var(--s5);
}

.card__brand .mark { width: 1.6rem; height: 1.6rem; }

/* --- Kurshintergrund ------------------------------------------------------ */

/*
 * Ein Kursverlauf, der sich einmal aufbaut und dann stehen bleibt: erst das
 * Raster, dann Kerzen und Umsatzbalken von links nach rechts, zuletzt die
 * beiden Durchschnitte — nach rund zweieinhalb Sekunden ist Ruhe.
 *
 * Keine Schleife, und nichts, was blinkt oder pulsiert. Eine Fläche, die
 * dauerhaft arbeitet, zieht den Blick vom Inhalt ab; das Ziel dieser Seiten ist
 * die Anmeldung und die Erklärung des Produkts, nicht der Hintergrund.
 *
 * Die Deckkraft steht in den Farben selbst statt in `opacity`, weil sie sich
 * dann je Element unterscheiden kann und weil `light-dark()` nur Farben kennt,
 * keine Zahlen.
 */

.wallpaper {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

/*
 * Das Band sitzt unten und füllt die volle Breite. Die Höhe folgt aus dem
 * Seitenverhältnis der Zeichenfläche, damit nichts beschnitten wird.
 */
.wallpaper__chart {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: block;
  width: 100%;
  height: auto;
  z-index: 1;
}

/*
 * Auf Fingerbreite ergäbe die volle Reihe ein Band von gut drei Zentimetern
 * Höhe mit Kerzen von wenigen Pixeln — das liest sich nicht als Kursverlauf,
 * sondern als Störung. Eine gesetzte Höhe zwingt `slice` zum seitlichen
 * Beschnitt: weniger Kerzen, dafür in erkennbarer Größe.
 */
@media (max-width: 40rem) {
  .wallpaper__chart { height: 13rem; }
}

/*
 * Hilfslinien über die ganze Fläche, nicht nur unter dem Band. Als Verlauf
 * statt als Linien im SVG, weil sie so unabhängig von dessen Geometrie über
 * die volle Höhe laufen.
 *
 * Senkrecht enger als waagerecht: Auf einer Kursfläche steht die Zeit dichter
 * als der Preis, und ein quadratisches Netz sähe aus wie Millimeterpapier. Die
 * senkrechten Linien sind zusätzlich schwächer — sie sollen die Fläche
 * gliedern, nicht mit den Kerzen um Aufmerksamkeit ringen.
 */
.wp-grid {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image:
    repeating-linear-gradient(
      to bottom,
      color-mix(in srgb, var(--border-strong) 70%, transparent) 0 1px,
      transparent 1px 7rem
    ),
    repeating-linear-gradient(
      to right,
      color-mix(in srgb, var(--border-strong) 42%, transparent) 0 1px,
      transparent 1px 4.5rem
    );
}

/*
 * Ein Schleier hinter Karte und Fußzeile. Die Karte deckt selbst, aber die
 * Fußzeile steht ohne eigene Fläche direkt auf dem Bild; ohne diesen Verlauf
 * liefe ihr Text über Kerzenkanten.
 */
.wallpaper::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background:
    radial-gradient(
      ellipse 40% 58% at 50% 48%,
      var(--bg) 0%,
      color-mix(in srgb, var(--bg) 88%, transparent) 44%,
      color-mix(in srgb, var(--bg) 42%, transparent) 70%,
      transparent 90%
    );
}

/* Inhalt vor den Hintergrund, sonst verschluckt ihn das Bild. */
.centered--staged > main,
.centered--staged > footer {
  position: relative;
  z-index: 1;
}

/* Auf gemustertem Grund braucht die Karte eine deutlichere Kante als sonst. */
.centered--staged > .card { box-shadow: var(--shadow-lg); }

/*
 * Die Fußzeile steht ohne eigene Fläche über dem Band. Der sonst genügend
 * zurückgenommene Ton reicht dort nicht mehr.
 */
.centered--staged > .footer { color: var(--text-muted); }

.wp-candle__wick {
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

.wp-candle--up .wp-candle__wick { stroke: color-mix(in srgb, var(--up) 62%, transparent); }
.wp-candle--up .wp-candle__body { fill: color-mix(in srgb, var(--up) 46%, transparent); }
.wp-candle--down .wp-candle__wick { stroke: color-mix(in srgb, var(--down) 62%, transparent); }
.wp-candle--down .wp-candle__body { fill: color-mix(in srgb, var(--down) 46%, transparent); }

/*
 * Die Umsatzspur bleibt deutlich blasser als die Kerzen darüber. Sie ist die
 * Nebenangabe: Wer auf das Bild sieht, soll den Verlauf lesen und den Umsatz
 * erst danach bemerken. Gleich kräftig gefärbt entstünden zwei Reihen, die um
 * denselben Blick werben.
 */
.wp-bar--up   { fill: color-mix(in srgb, var(--up) 26%, transparent); }
.wp-bar--down { fill: color-mix(in srgb, var(--down) 26%, transparent); }

/*
 * Die Durchschnitte liegen über allem. Der kurze trägt den Akzent und ist die
 * eine Linie, der das Auge folgt; der lange läuft dünner und in gedämpftem Ton
 * darunter, weil zwei gleich starke Linien nur ein Geflecht ergäben.
 *
 * Keine Strichelung für den langen: Der Aufbau zieht beide Linien über
 * `stroke-dasharray`, und ein zweites Strichmuster auf derselben Eigenschaft
 * ginge nicht — es bliebe eine der beiden Wirkungen auf der Strecke.
 */
.wp-ma {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

.wp-ma--fast {
  stroke: color-mix(in srgb, var(--accent) 82%, transparent);
  stroke-width: 2.5;
}

.wp-ma--slow {
  stroke: color-mix(in srgb, var(--text-muted) 52%, transparent);
  stroke-width: 1.8;
}

@keyframes wp-settle {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes wp-rise {
  from { opacity: 0; transform: scaleY(0.06); }
  to   { opacity: 1; transform: scaleY(1); }
}

/*
 * Waagerecht endet der Schnitt knapp hinter der Kante, senkrecht weit davor.
 * Das ist kein Zahlendreher: Bezug ist die Umrissbox des Linienzugs, und die
 * kennt die Strichbreite nicht — bündig geschnitten fehlte oben und unten eine
 * halbe Strichbreite. Waagerecht darf der Wert trotzdem nicht groß sein, weil
 * er die Strecke der Bewegung ist: Bei -40 % stand die Linie nach zwei Dritteln
 * der Laufzeit fertig da und der Rest der Zeit verging, ohne dass sich etwas
 * bewegte.
 */
@keyframes wp-draw {
  from { clip-path: inset(-30% 100% -30% 0); }
  to   { clip-path: inset(-30% -1% -30% 0); }
}

.wp-grid { animation: wp-settle 700ms ease both; }

/*
 * `fill-box` bezieht den Ursprung auf das Element selbst. Ohne das säße er im
 * Nullpunkt der Zeichenfläche, und alles würde vom linken Rand her aufgezogen
 * statt an seinem Platz zu wachsen.
 *
 * Die Kerze wächst aus ihrer Mitte, der Umsatzbalken vom Boden: Ein Balken, der
 * an einer Grundlinie steht, wächst nach oben. Aus der Mitte gedehnt sähe es
 * aus, als rutschte die Grundlinie mit.
 */
.wp-candle,
.wp-bar {
  transform-box: fill-box;
  animation: wp-rise 620ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

.wp-candle { transform-origin: center; }
.wp-bar    { transform-origin: bottom; }

/*
 * Die Verzögerung steht hier und nicht am Element: `style`-Attribute fallen
 * unter `style-src` und werden von der Content-Security-Policy verworfen.
 * Damit scheidet auch der übliche Weg über eine Variable am Element aus.
 *
 * Eine Reihe für zwei Spuren: Kerze und Umsatzbalken desselben Tages tragen
 * beide `wp-tick` und stehen in ihrer Gruppe an derselben Stelle, weil
 * `:nth-child` je Elternelement von vorn zählt. Zwei getrennte Reihen mit je
 * vierzig Zeilen müssten von Hand gleich gehalten werden, und ein Versatz
 * zwischen Kerze und ihrem Umsatz fiele als Zucken auf.
 *
 * Der Abstand von 30 ms ist an die Länge der Reihe gebunden, nicht umgekehrt:
 * Er hält den Einlauf bei rund 1,5 Sekunden, sodass die letzte Kerze etwa dann
 * steht, wenn die Linien durchgezogen sind. Mit dem doppelten Abstand liefe der
 * Aufbau über drei Sekunden, und aus einem Bild, das sich setzt, würde eine
 * Vorführung.
 */
.wp-tick:nth-child(1)  { animation-delay: 0.34s; }
.wp-tick:nth-child(2)  { animation-delay: 0.37s; }
.wp-tick:nth-child(3)  { animation-delay: 0.40s; }
.wp-tick:nth-child(4)  { animation-delay: 0.43s; }
.wp-tick:nth-child(5)  { animation-delay: 0.46s; }
.wp-tick:nth-child(6)  { animation-delay: 0.49s; }
.wp-tick:nth-child(7)  { animation-delay: 0.52s; }
.wp-tick:nth-child(8)  { animation-delay: 0.55s; }
.wp-tick:nth-child(9)  { animation-delay: 0.58s; }
.wp-tick:nth-child(10) { animation-delay: 0.61s; }
.wp-tick:nth-child(11) { animation-delay: 0.64s; }
.wp-tick:nth-child(12) { animation-delay: 0.67s; }
.wp-tick:nth-child(13) { animation-delay: 0.70s; }
.wp-tick:nth-child(14) { animation-delay: 0.73s; }
.wp-tick:nth-child(15) { animation-delay: 0.76s; }
.wp-tick:nth-child(16) { animation-delay: 0.79s; }
.wp-tick:nth-child(17) { animation-delay: 0.82s; }
.wp-tick:nth-child(18) { animation-delay: 0.85s; }
.wp-tick:nth-child(19) { animation-delay: 0.88s; }
.wp-tick:nth-child(20) { animation-delay: 0.91s; }
.wp-tick:nth-child(21) { animation-delay: 0.94s; }
.wp-tick:nth-child(22) { animation-delay: 0.97s; }
.wp-tick:nth-child(23) { animation-delay: 1.00s; }
.wp-tick:nth-child(24) { animation-delay: 1.03s; }
.wp-tick:nth-child(25) { animation-delay: 1.06s; }
.wp-tick:nth-child(26) { animation-delay: 1.09s; }
.wp-tick:nth-child(27) { animation-delay: 1.12s; }
.wp-tick:nth-child(28) { animation-delay: 1.15s; }
.wp-tick:nth-child(29) { animation-delay: 1.18s; }
.wp-tick:nth-child(30) { animation-delay: 1.21s; }
.wp-tick:nth-child(31) { animation-delay: 1.24s; }
.wp-tick:nth-child(32) { animation-delay: 1.27s; }
.wp-tick:nth-child(33) { animation-delay: 1.30s; }
.wp-tick:nth-child(34) { animation-delay: 1.33s; }
.wp-tick:nth-child(35) { animation-delay: 1.36s; }
.wp-tick:nth-child(36) { animation-delay: 1.39s; }
.wp-tick:nth-child(37) { animation-delay: 1.42s; }
.wp-tick:nth-child(38) { animation-delay: 1.45s; }
.wp-tick:nth-child(39) { animation-delay: 1.48s; }
.wp-tick:nth-child(40) { animation-delay: 1.51s; }

/*
 * Die Linien ziehen mit, während die Kerzen noch einlaufen — hintereinander
 * gesetzt wäre der Aufbau vier Sekunden lang. Der lange Durchschnitt startet
 * eine Spur später, damit die beiden nicht als ein Strich wahrgenommen werden.
 */
/*
 * Aufgedeckt von links statt nachgezeichnet.
 *
 * Hier stand ein wanderndes `stroke-dasharray` auf einem `pathLength="1"`, und
 * das lief ins Leere: Die Linien tragen `non-scaling-stroke`, worauf der
 * Browser das Strichmuster in Bildschirmpunkten rechnet statt in der normierten
 * Einheit. Aus dem Muster wurde „ein Punkt Strich, ein Punkt Lücke" — sichtbar
 * war das nicht, weil die runden Strichenden die Lücken wieder schließen, aber
 * der Versatz wanderte damit um genau einen Punkt und die Linien erschienen
 * schlagartig. Derselbe Fehler schnitt in die Verlaufsstreifen der Übersicht
 * zwei Löcher, dort mit hundert Punkten Abstand.
 */
.wp-ma { animation: wp-draw 1300ms cubic-bezier(0.32, 0.5, 0.2, 1) both; }

.wp-ma--fast { animation-delay: 0.86s; }
.wp-ma--slow { animation-delay: 1.06s; }

/*
 * Wer Bewegung abbestellt hat, bekommt das fertige Bild statt seines Aufbaus —
 * nicht eine leere Fläche.
 */
@media (prefers-reduced-motion: reduce) {
  .wp-grid,
  .wp-candle,
  .wp-bar,
  .wp-ma { animation: none; }
}

/* --- Ticker der Ereignisseite -------------------------------------------- */

/*
 * Der Ticker zeigt den Zufluss, die Liste darunter die Chronologie. Damit der
 * Unterschied nicht nur in der Überschrift steht, sitzt er als eigene Karte
 * über den Filtern und bekommt eine ruhige Tönung statt der weißen Fläche.
 */
.ticker {
  background: var(--surface-2);
  border-color: transparent;
  box-shadow: none;
  margin-bottom: var(--s5);
}

.ticker__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s2) var(--s3);
  margin-bottom: var(--s3);
}

.ticker__head h2 {
  margin: 0;
  font-size: 1rem;
  font-weight: 550;
}

/*
 * Die Statuszeile ist bewusst leise. Sie beantwortet nur die eine Frage, die
 * ein sich selbst aktualisierender Bereich sonst offen lässt: läuft das noch.
 * Ohne JavaScript bleibt sie über `hidden` weg — eine tote Zeile wäre
 * schlechter als keine.
 */
.ticker__state {
  margin: 0;
  color: var(--text-faint);
  font-size: 0.84rem;
}

.ticker__note {
  margin: var(--s3) 0 0;
  font-size: 0.84rem;
  max-width: var(--measure);
}

/*
 * Eine Zeile je Eingang: Uhrzeit, Symbol, Titel. Die ausführliche Fassung mit
 * Quellenlage und Einpreisung steht direkt darunter in der Liste — hätte der
 * Ticker sie auch, stünde derselbe Eintrag zweimal in voller Länge auf dem
 * Bildschirm, und der Unterschied zwischen Zufluss und Chronologie ginge
 * vollends unter.
 *
 * Feste Spalten für Zeit und Symbol, damit die Titel auf einer Kante beginnen.
 * Das macht aus der Aufzählung eine Spalte, die sich überfliegen lässt.
 */
.ticker .items > li {
  display: grid;
  grid-template-columns: 3.2rem 5.5rem 1fr;
  align-items: baseline;
  gap: var(--s3);
  padding: var(--s2) 0;
}

.ticker__time {
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  font-size: 0.84rem;
  white-space: nowrap;
}

/* Bleibt als leere Spalte stehen, wenn kein Symbol zugeordnet ist. */
.ticker__symbol {
  min-width: 0;
  overflow: hidden;
}

.ticker__symbol .tag {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ticker__line {
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s2);
  line-height: 1.45;
}

/*
 * Dieselbe ruhige Färbung wie in der Liste darunter: sechs blaue Blöcke
 * übereinander lesen sich als Werbefläche, nicht als Nachrichtenlage.
 */
.ticker__line a {
  color: var(--text);
  text-decoration-color: var(--border-strong);
  font-weight: 450;
}

.ticker__line a:hover { color: var(--accent); }

@media (max-width: 40rem) {
  /*
   * Auf dem Telefon reicht die Breite nicht für drei Spalten — der Titel bliebe
   * ein Wortband. Zeit und Symbol rücken deshalb über den Titel.
   */
  .ticker .items > li {
    grid-template-columns: 3.2rem 1fr;
    gap: var(--s1) var(--s3);
  }

  .ticker__line { grid-column: 1 / -1; }
}

/*
 * Einlauf eines nachgeladenen Eintrags: kurz getönt, dann zurück in die Ruhe.
 * Die Tönung klingt ab, statt zu bleiben — sonst sammelte sich über eine
 * längere Sitzung eine Liste aus lauter hervorgehobenen Zeilen an, und die
 * Hervorhebung sagte nichts mehr aus.
 */
@keyframes ticker-einlauf {
  from {
    opacity: 0;
    transform: translateY(-0.4rem);
    background-color: var(--accent-soft);
  }

  40% {
    opacity: 1;
    transform: none;
    background-color: var(--accent-soft);
  }

  to {
    opacity: 1;
    transform: none;
    background-color: transparent;
  }
}

.ticker__item--neu {
  animation: ticker-einlauf 2.4s ease-out both;
}

/*
 * Ohne Bewegung erscheint der Eintrag einfach — sichtbar und vollständig. Die
 * Regel muss nach der Animation stehen, sonst gewinnt die spätere Deklaration
 * und der Eintrag bliebe auf der Anfangsstufe der Bildfolge hängen: unsichtbar.
 */
@media (prefers-reduced-motion: reduce) {
  .ticker__item--neu {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

/* --- Kleine Bildschirme -------------------------------------------------- */

@media (max-width: 48rem) {
  .wrap { padding: var(--s5) var(--s4) var(--s6); }
  .topbar__inner { padding: var(--s3) var(--s4); }
  .mainnav ul { padding: 0 var(--s4); }
  .card { padding: var(--s4); }
  .table-scroll { margin: 0 calc(var(--s4) * -1); padding: 0 var(--s4); }

  /*
   * Was mit dem Finger getroffen werden muss, ist mindestens 44 Punkte hoch.
   * Mit der Maus reicht die Fläche des Textes, mit dem Daumen nicht — und
   * daneben zu treffen kostet hier eine Order.
   */
  button,
  .button,
  .mainnav a,
  .segmented a,
  .menu__panel a,
  .menu__panel button {
    min-height: 2.75rem;
  }

  button,
  .button { padding: 0.6rem var(--s4); }

  .mainnav a { padding: 0.85rem var(--s3) calc(0.85rem - 2px); }

  .segmented a {
    display: inline-flex;
    align-items: center;
    padding: 0.4rem var(--s4);
  }

  .disclose > summary { padding-top: var(--s4); padding-bottom: var(--s4); }

  /* Unter 16 Punkten Schriftgröße zoomt Safari beim Hineintippen in ein Feld
     die ganze Seite heran und springt nicht wieder zurück. */
  input,
  select,
  textarea {
    font-size: 1rem;
    padding: 0.6rem var(--s3);
  }

  /* Das Suchfeld setzt seine Schriftgröße oben mit höherer Spezifität und
     nähme den Schutz sonst mit. Hier gilt er wieder. */
  .search input[type="search"] {
    font-size: 1rem;
    padding: 0.5rem var(--s3);
  }

  /* Eine Schaltfläche allein in einer Zeile nimmt die volle Breite: auf dem
     Telefon ist sie damit sicher zu treffen, ohne dass die Zeile bricht. */
  .preview__confirm > button,
  .preview__confirm > .button { flex: 1 1 10rem; }

  .page-head__actions { width: 100%; }
  .page-head__actions > * { flex: 1 1 auto; }
}

/*
 * Ab hier wird aus jeder breiten Datentabelle eine Liste von Karten.
 *
 * Der Grund ist einfach: acht Spalten passen auf ein Telefon nicht, und
 * seitliches Schieben versteckt genau die Spalten, wegen derer man die Tabelle
 * aufgemacht hat. Weggelassen wird nichts — jede Zelle behält ihren Wert, die
 * Spaltenüberschrift wandert über `data-label` neben den Wert. Wer eine
 * Tabelle so auszeichnet, muss deshalb jede Zelle beschriften.
 *
 * Die erste Zelle ist in allen Tabellen der Anwendung das, was die Zeile
 * benennt — Symbol, Datum, Bezeichnung. Sie wird deshalb zur Überschrift der
 * Karte und bekommt keine Beschriftung davor.
 */
@media (max-width: 44rem) {
  /*
   * Die Kopfzeile wird versteckt, nicht entfernt: als `display: none` wäre sie
   * auch für die Sprachausgabe weg. `display: block` ist dabei nicht
   * kosmetisch — eine Zeilengruppe ignoriert `overflow: hidden`, und die
   * breiten Kopfzellen schöben die Seite weiter seitlich heraus.
   */
  .table--cards thead {
    display: block;
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .table--cards,
  .table--cards tbody,
  .table--cards tr,
  .table--cards td { display: block; }

  .table--cards tr {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--s3) var(--s4) var(--s4);
    background: var(--surface-2);
  }

  .table--cards tr + tr { margin-top: var(--s3); }

  /*
   * Die Beschriftung liegt absolut, der Wert fließt im rechten Bereich. Das
   * ist der entscheidende Unterschied zu einer Flex-Zeile: eine Zelle enthält
   * oft mehr als eine Zahl — Währungskürzel, Prozentwert, eine Erläuterung.
   * Nebeneinander in einer Flex-Zeile würden die auseinandergezogen; so
   * stapeln sie sich unter dem Wert, wo sie hingehören.
   */
  .table--cards td {
    position: relative;
    padding: 0.35rem 0 0.35rem 42%;
    border: none;
    text-align: right;
  }

  .table--cards td::before {
    content: attr(data-label);
    position: absolute;
    left: 0;
    top: 0.35rem;
    width: 40%;
    color: var(--text-muted);
    font-size: 0.84rem;
    line-height: 1.5;
    text-align: left;
  }

  /* Eine Zelle ohne Beschriftung ist nicht ausgezeichnet worden. Sie soll
     trotzdem lesbar bleiben und nicht mit leerem Vorspann dastehen. */
  .table--cards td:not([data-label]) {
    padding-left: 0;
    text-align: left;
  }

  .table--cards td:not([data-label])::before { content: none; }

  .table--cards td:first-child {
    font-weight: 600;
    font-size: 1.02rem;
    padding: 0 0 var(--s3);
    margin-bottom: var(--s2);
    border-bottom: 1px solid var(--border);
    text-align: left;
  }

  .table--cards td:first-child::before { content: none; }
  .table--cards td:last-child { padding-bottom: 0; }

  /*
   * Zusatzangaben gehören unter den Wert, nicht neben ihn. Und sie dürfen
   * umbrechen: in der Tabelle hält `nowrap` die Spalte zusammen, in der Karte
   * schiebt derselbe Umbruchschutz einen Halbsatz wie „Kurs 0,62 EUR, Währung
   * 0,00 EUR" über den Bildrand hinaus. Die Zahl darüber bleibt geschützt.
   */
  .table--cards td > div {
    display: block;
    white-space: normal;
  }

  .table--cards tfoot tr { background: var(--surface-3); }
  .table--cards + .faint { margin-top: var(--s3); }

  /* In der Karte gibt es keinen Grund mehr, waagerecht zu schieben. */
  .table-scroll:has(.table--cards) {
    overflow-x: visible;
    margin: 0;
    padding: 0;
  }

  /*
   * Das SVG schrumpft auf etwa die halbe Nutzergröße. Damit die Beschriftung
   * lesbar bleibt, wird sie in Nutzereinheiten verdoppelt — nach der
   * Skalierung entspricht das wieder der Größe auf dem Bildschirm.
   */
  .chart__tick { font-size: 21px; }
  .chart__tick--value { display: none; }
  .chart__tick--above { display: block; text-anchor: start; }
  .chart__tick--dense { display: none; }

  .chart__point { r: 5; }

  /*
   * Der Docht hat feste Strichstärke und schrumpft deshalb nicht mit. Auf dem
   * Telefon ist der Körper daneben nur noch halb so breit — ein Docht von
   * einem Pixel wirkt dort dünn und flackert beim Scrollen.
   */
  .chart__wick { stroke-width: 1.5; }
}

/*
 * Sechs Bereiche passen nicht nebeneinander auf ein Telefon. Sie waagerecht
 * schiebbar zu lassen wäre die bequemere Lösung, versteckt aber die Hälfte der
 * Anwendung hinter einer Geste, die niemand sieht. Also zwei Zeilen: etwas
 * mehr Höhe, dafür ist alles sichtbar.
 */
@media (max-width: 40rem) {
  .mainnav { overflow-x: visible; }

  .mainnav ul {
    flex-wrap: wrap;
    gap: 0 var(--s2);
  }

  .mainnav a { padding: 0.65rem var(--s2) calc(0.65rem - 2px); }
}

@media (max-width: 34rem) {
  /* Auch im Fokus: hier ist der Platz ohnehin knapp, und 18rem waeren auf
     einem schmalen Telefon weniger als die volle Breite. */
  .search input[type="search"],
  .search input[type="search"]:focus { width: 100%; }

  /* Nur der Schriftzug weicht, das Zeichen bleibt: sonst führt kein sichtbarer
     Weg mehr zurück zur Übersicht. */
  .brand span { display: none; }

  /* Auf dem Telefon löst die Eingabetaste die Suche aus; die Tastatur zeigt
     dafür eine eigene Taste. Die Schaltfläche daneben kostet nur Platz. */
  .search button { display: none; }
}

/* --- Druck --------------------------------------------------------------- */

@media print {
  .topbar, .mainnav, .skip, .segmented, form { display: none; }
  body { background: #fff; }
  .card { border-color: #999; box-shadow: none; break-inside: avoid; }
  .disclose[open] > summary { background: none; }
  .disclose__body { display: block !important; }
}
