/* Serverübersicht — Fassung 2 („warme Tinte und Messing").
 *
 * Löst die Navy/Cyan-Kachelfassung ab. Die Umstellung folgt dem Handoff
 * doku/GUI-Neufassung/README.md; die Variablennamen sind absichtlich
 * dieselben geblieben, damit der Rest der Datei weiterläuft.
 *
 * Drei Regeln, die den Aufbau erklären:
 *  - Abschnitte trennen Haarlinien, keine Kartenstapel. Ein Kasten im Kasten
 *    kostet Platz und sagt nichts.
 *  - Messing trägt ALLE Daten. Salbei, Bernstein und Terrakotta sind
 *    ausschließlich Zustände und werden nie als Schmuckfarbe benutzt.
 *  - Farbe trägt keine Aussage allein — der Text nennt sie ebenfalls.
 */

/* --- Schriften ------------------------------------------------------
 *
 * Von der Platte, NICHT von Google Fonts: Die CSP im Caddy lässt keine
 * fremden Server zu, und offline soll die PWA gleich aussehen.
 *
 * Fehlen die Dateien, greift der Fallback-Stapel und die App bleibt
 * benutzbar — sie sieht dann nur gewöhnlicher aus. Welche Dateien
 * hierhergehören, steht in schriften/LIESMICH.md.
 */
@font-face {
  font-family: "Newsreader"; font-style: normal; font-weight: 300;
  font-display: swap; src: url("schriften/newsreader-300.woff2") format("woff2");
}
@font-face {
  font-family: "Newsreader"; font-style: normal; font-weight: 400;
  font-display: swap; src: url("schriften/newsreader-400.woff2") format("woff2");
}
@font-face {
  font-family: "Instrument Sans"; font-style: normal; font-weight: 400;
  font-display: swap; src: url("schriften/instrument-sans-400.woff2") format("woff2");
}
@font-face {
  font-family: "Instrument Sans"; font-style: normal; font-weight: 500;
  font-display: swap; src: url("schriften/instrument-sans-500.woff2") format("woff2");
}
@font-face {
  font-family: "Instrument Sans"; font-style: normal; font-weight: 600;
  font-display: swap; src: url("schriften/instrument-sans-600.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono"; font-style: normal; font-weight: 400;
  font-display: swap; src: url("schriften/ibm-plex-mono-400.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono"; font-style: normal; font-weight: 500;
  font-display: swap; src: url("schriften/ibm-plex-mono-500.woff2") format("woff2");
}

:root {
  --grund:     oklch(0.175 0.008 65);   /* Seitengrund, warme Tinte */
  --flaeche:   oklch(0.225 0.010 65);   /* aktives Element in der Schiene */
  --rand:      oklch(0.28  0.010 65);   /* Abschnittslinie */
  --rand-fein: oklch(0.255 0.008 65);   /* Zeilenlinie in Listen */
  --spur:      oklch(0.26  0.008 65);   /* Balkenspur */
  --schrift:   oklch(0.94  0.008 85);
  --leise:     oklch(0.64  0.012 80);
  --leiser:    oklch(0.60  0.012 80);   /* Achsen, Fußzeile */
  --messing:   oklch(0.80  0.085 82);   /* Akzent: Kurven, Balken, Marke */
  --gut:       oklch(0.70  0.06 148);   /* running */
  --warn:      oklch(0.74  0.13  62);   /* ab 75 % / ab 80 % Budget */
  --alarm:     oklch(0.62  0.14  25);   /* ab 90 % / über Budget / gestoppt */

  --kurvenflaeche:      oklch(0.80 0.085 82 / .10);
  --kurvenflaeche-fein: oklch(0.80 0.085 82 / .09);

  --warnband-rand:    oklch(0.55 0.10 60);
  --warnband-grund:   oklch(0.28 0.045 60);
  --warnband-schrift: oklch(0.90 0.05 75);

  /* Seit den Themen (25.09.2026) stehen hier auch die Farben, die vorher
     fest in einzelnen Regeln saßen. Sonst hätte ein helles Thema
     ausgerechnet die Gitterlinien und den Kopf am Handy dunkel gelassen. */
  --mittel:           oklch(0.68 0.012 80);   /* Beschriftungen zwischen Schrift und leise */
  --schrift-hover:    oklch(0.78 0.012 80);
  --rand-aktiv:       oklch(0.36 0.030 75);   /* gewählter Servereintrag */
  --rand-gestrichelt: oklch(0.30 0.010 65);   /* „+ Server aufnehmen" */
  --rand-hover:       oklch(0.42 0.02 70);
  --gitter:           oklch(0.27 0.010 65);
  --monatsrest:       oklch(0.235 0.008 65 / .5);
  --sockel:           oklch(0.80 0.085 82 / .16);
  --auswahl:          oklch(0.80 0.085 82 / .25);
  --auf-messing:      oklch(0.20 0.02 75);    /* Schrift auf einem Messingknopf */
  --fehler-grund:     oklch(0.26 0.05 25);
  --fehler-schrift:   oklch(0.88 0.05 30);
  --kopf-grund:       oklch(0.175 0.008 65 / .96);
  --schiene-grund:    transparent;            /* Tinte: Schiene und Inhalt auf einem Grund */
  --marke-strich:     #ffffff;                /* Netz-M: Striche und Knoten */
  --marke-akzent:     #2AB3C6;                /* Netz-M: der cyanfarbene Schenkel */

  --radius: 10px;
  color-scheme: dark;

  --serif: Newsreader, Georgia, "Times New Roman", serif;
  --sans:  "Instrument Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono:  "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ==================== Themen ====================
 *
 * Drei Themen und eine Automatik, gewählt über data-thema am <html>
 * (gesetzt von thema.js, bevor die Seite zeichnet):
 *
 *   tinte  — „Tinte und Messing", die Fassung seit dem 30.08.2026 und die
 *            Voreinstellung. Ihre Werte stehen oben in :root.
 *   hell   — MSolutions hell, wie Kontor und TradeAgent.
 *   dunkel — MSolutions dunkel, ebenso.
 *   system — hell oder dunkel, je nachdem, was das Gerät gerade will.
 *
 * Die Werte für „system" stehen ein zweites Mal da, jeweils in einer
 * Medienabfrage. CSS kennt keine Aliase für Regelblöcke — die Doppelung
 * ist der Preis, und werkzeug/pruefstand/thementest.js vergleicht beide
 * Fassungen Wert für Wert, damit sie nicht auseinanderlaufen.
 *
 * Alle Regeln unterhalb benutzen NUR diese Variablen. Eine Farbe, die fest
 * in einer Regel steht, bleibt in allen Themen gleich — genau das war vor
 * dem Umbau bei der Gitterlinie und dem Kopf am Handy der Fall.
 */
:root[data-thema="hell"] {
  color-scheme: light;
  --grund:     #f2f5f8;
  --flaeche:   #ffffff;
  --schiene-grund: #ffffff;
  --kopf-grund: rgba(255, 255, 255, .96);
  --rand:      #d3dce6;
  --rand-fein: #e4e9f0;
  --spur:      #e1e7ee;
  --gitter:    #e4e9f0;
  --schrift:   #16283f;
  --mittel:    #33455c;
  --leise:     #5a6a7e;
  --leiser:    #5a6a7e;
  --schrift-hover: #16283f;
  /* Der Akzent trägt alle Daten. Reines Cyan #2AB3C6 käme auf Weiß nur auf
     rund 2,4:1 — zu blass für Text UND für einen 3-px-Balken. Deshalb das
     lesbare Cyan aus Kontor, gemessen 5,3:1 auf dem Seitengrund. */
  --messing:   #14707c;
  --auf-messing: #ffffff;
  --gut:       #2f7d4f;
  --warn:      #8a5a12;   /* Bernstein aus dem Gestaltungssystem, kein Gelb */
  --alarm:     #b23a3a;
  --kurvenflaeche:      rgba(20, 112, 124, .10);
  --kurvenflaeche-fein: rgba(20, 112, 124, .08);
  --sockel:    rgba(22, 40, 63, .10);
  --monatsrest: rgba(22, 40, 63, .045);
  --auswahl:   rgba(42, 179, 198, .22);
  --rand-aktiv: rgba(22, 40, 63, .30);
  --rand-gestrichelt: rgba(22, 40, 63, .30);
  --rand-hover: rgba(22, 40, 63, .50);
  --warnband-rand:    #ebd9ae;
  --warnband-grund:   #fdf6e6;
  --warnband-schrift: #5e3d0a;
  --fehler-grund:   #fbeeee;
  --fehler-schrift: #7d2626;
  --marke-strich: #16283f;
  --marke-akzent: #2ab3c6;

  /* Keine Webschriften — das Gestaltungssystem lädt keine fremde Datei,
     und das ist Teil des Versprechens. Die Serif nur für Überschriften und
     die großen Zahlen, immer Gewicht 400. */
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --sans:  system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono:  ui-monospace, SFMono-Regular, "Cascadia Mono", Menlo, Consolas, monospace;
}

:root[data-thema="dunkel"] {
  color-scheme: dark;
  /* Wie Kontor und TradeAgent: eine ruhige Leiter aus fast schwarzen
     Flächen mit kühlem Unterton, keine Navy-Karten. Gesättigtes Blau auf
     Dunkel wirkt billig; die Tiefe kommt aus kleinen Helligkeitsschritten. */
  --grund:     #0a0f17;
  --flaeche:   #121a26;
  --schiene-grund: #0e141e;
  --kopf-grund: rgba(14, 20, 30, .96);
  --rand:      #232d3b;
  --rand-fein: #1a2230;
  --spur:      #1c2633;
  --gitter:    #1a2230;
  --schrift:   #e9eef4;
  --mittel:    #b9c5d3;
  --leise:     #8fa1b6;
  --leiser:    #8195aa;
  --schrift-hover: #e9eef4;
  --messing:   #2ab3c6;   /* Das Marken-Cyan ist auf Dunkel lesbar, rund 8:1 */
  --auf-messing: #04191e;
  --gut:       #6fbf8e;
  --warn:      #d9b25a;
  --alarm:     #e07c7c;
  --kurvenflaeche:      rgba(42, 179, 198, .10);
  --kurvenflaeche-fein: rgba(42, 179, 198, .08);
  --sockel:    rgba(255, 255, 255, .07);
  --monatsrest: rgba(255, 255, 255, .025);
  --auswahl:   rgba(42, 179, 198, .28);
  --rand-aktiv: rgba(42, 179, 198, .40);
  --rand-gestrichelt: rgba(255, 255, 255, .16);
  --rand-hover: rgba(255, 255, 255, .34);
  --warnband-rand:    #5c4a22;
  --warnband-grund:   #1d1a12;
  --warnband-schrift: #ecd9a8;
  --fehler-grund:   #2a1618;
  --fehler-schrift: #f2c4c4;
  --marke-strich: #ffffff;
  --marke-akzent: #2ab3c6;

  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --sans:  system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono:  ui-monospace, SFMono-Regular, "Cascadia Mono", Menlo, Consolas, monospace;
}

/* Automatik — dieselben Werte wie oben, siehe Kopfkommentar. */
@media (prefers-color-scheme: light) {
  :root[data-thema="system"] {
    color-scheme: light;
    --grund:     #f2f5f8;
    --flaeche:   #ffffff;
    --schiene-grund: #ffffff;
    --kopf-grund: rgba(255, 255, 255, .96);
    --rand:      #d3dce6;
    --rand-fein: #e4e9f0;
    --spur:      #e1e7ee;
    --gitter:    #e4e9f0;
    --schrift:   #16283f;
    --mittel:    #33455c;
    --leise:     #5a6a7e;
    --leiser:    #5a6a7e;
    --schrift-hover: #16283f;
    /* Der Akzent trägt alle Daten. Reines Cyan #2AB3C6 käme auf Weiß nur auf
       rund 2,4:1 — zu blass für Text UND für einen 3-px-Balken. Deshalb das
       lesbare Cyan aus Kontor, gemessen 5,3:1 auf dem Seitengrund. */
    --messing:   #14707c;
    --auf-messing: #ffffff;
    --gut:       #2f7d4f;
    --warn:      #8a5a12;   /* Bernstein aus dem Gestaltungssystem, kein Gelb */
    --alarm:     #b23a3a;
    --kurvenflaeche:      rgba(20, 112, 124, .10);
    --kurvenflaeche-fein: rgba(20, 112, 124, .08);
    --sockel:    rgba(22, 40, 63, .10);
    --monatsrest: rgba(22, 40, 63, .045);
    --auswahl:   rgba(42, 179, 198, .22);
    --rand-aktiv: rgba(22, 40, 63, .30);
    --rand-gestrichelt: rgba(22, 40, 63, .30);
    --rand-hover: rgba(22, 40, 63, .50);
    --warnband-rand:    #ebd9ae;
    --warnband-grund:   #fdf6e6;
    --warnband-schrift: #5e3d0a;
    --fehler-grund:   #fbeeee;
    --fehler-schrift: #7d2626;
    --marke-strich: #16283f;
    --marke-akzent: #2ab3c6;

    /* Keine Webschriften — das Gestaltungssystem lädt keine fremde Datei,
       und das ist Teil des Versprechens. Die Serif nur für Überschriften und
       die großen Zahlen, immer Gewicht 400. */
    --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
    --sans:  system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --mono:  ui-monospace, SFMono-Regular, "Cascadia Mono", Menlo, Consolas, monospace;
  }
}
@media (prefers-color-scheme: dark) {
  :root[data-thema="system"] {
    color-scheme: dark;
    /* Wie Kontor und TradeAgent: eine ruhige Leiter aus fast schwarzen
       Flächen mit kühlem Unterton, keine Navy-Karten. Gesättigtes Blau auf
       Dunkel wirkt billig; die Tiefe kommt aus kleinen Helligkeitsschritten. */
    --grund:     #0a0f17;
    --flaeche:   #121a26;
    --schiene-grund: #0e141e;
    --kopf-grund: rgba(14, 20, 30, .96);
    --rand:      #232d3b;
    --rand-fein: #1a2230;
    --spur:      #1c2633;
    --gitter:    #1a2230;
    --schrift:   #e9eef4;
    --mittel:    #b9c5d3;
    --leise:     #8fa1b6;
    --leiser:    #8195aa;
    --schrift-hover: #e9eef4;
    --messing:   #2ab3c6;   /* Das Marken-Cyan ist auf Dunkel lesbar, rund 8:1 */
    --auf-messing: #04191e;
    --gut:       #6fbf8e;
    --warn:      #d9b25a;
    --alarm:     #e07c7c;
    --kurvenflaeche:      rgba(42, 179, 198, .10);
    --kurvenflaeche-fein: rgba(42, 179, 198, .08);
    --sockel:    rgba(255, 255, 255, .07);
    --monatsrest: rgba(255, 255, 255, .025);
    --auswahl:   rgba(42, 179, 198, .28);
    --rand-aktiv: rgba(42, 179, 198, .40);
    --rand-gestrichelt: rgba(255, 255, 255, .16);
    --rand-hover: rgba(255, 255, 255, .34);
    --warnband-rand:    #5c4a22;
    --warnband-grund:   #1d1a12;
    --warnband-schrift: #ecd9a8;
    --fehler-grund:   #2a1618;
    --fehler-schrift: #f2c4c4;
    --marke-strich: #ffffff;
    --marke-akzent: #2ab3c6;

    --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
    --sans:  system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --mono:  ui-monospace, SFMono-Regular, "Cascadia Mono", Menlo, Consolas, monospace;
  }
}

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

body {
  margin: 0;
  background: var(--grund);
  color: var(--schrift);
  font: 400 15px/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
  text-wrap: pretty;
}

::selection { background: var(--auswahl); }

:focus-visible { outline: 2px solid var(--messing); outline-offset: 2px; }

/* Das Netz-M als Symbol: Die Striche nehmen die Farbe des Themas an. */
.netzm { display: block; flex: none; color: var(--marke-strich); }
.anmeldekarte .netzm { margin: 0 auto; }
.symbolablage { position: absolute; width: 0; height: 0; overflow: hidden; }

/* Wiederkehrende Kleinauszeichnung: Mono, gesperrt, versal. */
.rubrik {
  font-family: var(--mono); font-size: .68rem; font-weight: 400;
  letter-spacing: .12em; text-transform: uppercase; color: var(--leise);
}

.veraltet { opacity: .45; }

/* ==================== Grundriss ==================== */

.rahmen { display: flex; flex-wrap: wrap; align-items: flex-start; min-height: 100vh; }

/* ==================== Linke Schiene ==================== */

.schiene {
  flex: 1 1 250px; max-width: 300px; min-width: 250px;
  align-self: stretch;
  display: flex; flex-direction: column; gap: 1.8rem;
  padding: calc(1.6rem + env(safe-area-inset-top)) 1.4rem
           calc(1.6rem + env(safe-area-inset-bottom));
  border-right: 1px solid var(--rand);
  /* Im Tinte-Thema durchsichtig — Schiene und Inhalt auf einem Grund. Die
     MSolutions-Themen setzen die Schiene wie Kontor als eigene Fläche ab. */
  background: var(--schiene-grund);
}

/* Auf dem Handy bricht die Schiene über den Inhalt. Dann ist eine 300 px
   breite Spalte mit Totraum daneben falsch — sie nimmt die volle Breite und
   die Trennlinie wandert nach unten. Das ist die einzige Abweichung vom
   Handoff, und sie betrifft genau das Gerät, um das es ging. */
@media (max-width: 900px) {
  .schiene {
    max-width: none; width: 100%;
    border-right: none; border-bottom: 1px solid var(--rand);
    gap: 1.4rem;
  }
  /* Die Sprungmarken werden hier NICHT umgestellt, sondern ganz am Ende der
     Datei — ihre Grundregeln stehen weiter unten, und eine Medienabfrage
     schlägt keine spätere Regel gleicher Spezifität. Genau daran ist die
     erste Fassung gescheitert. */
}

.marke { display: flex; align-items: center; gap: .7rem; }
.marke .netzm { opacity: .9; }
.marke .namen { display: flex; flex-direction: column; line-height: 1.15; }
.marke .firma { font-size: .94rem; font-weight: 600; letter-spacing: -.01em; }
.marke .sparte { font-size: .68rem; letter-spacing: .09em; }

.schienenblock { display: flex; flex-direction: column; gap: .55rem; }

/* --- Server-Liste --- */
.serverliste { display: flex; flex-direction: column; gap: .4rem; }

.servereintrag {
  display: flex; flex-direction: column; gap: .3rem;
  text-align: left; padding: .7rem .8rem;
  border-radius: var(--radius); cursor: pointer;
  font: inherit; color: inherit;
  background: transparent; border: 1px solid var(--rand);
}
.servereintrag[aria-current="true"] {
  background: var(--flaeche); border-color: var(--rand-aktiv);
}
.servereintrag .kopfzeile { display: flex; align-items: center; gap: .5rem; width: 100%; }
.servereintrag .punkt {
  width: .42rem; height: .42rem; border-radius: 50%; flex: none;
  background: var(--gut);
}
.servereintrag .punkt.weg { background: var(--alarm); }
.servereintrag .name {
  font-weight: 500; font-size: .9rem;
  min-width: 0; overflow-wrap: anywhere;
}
.servereintrag .preis {
  margin-left: auto; flex: none; white-space: nowrap;
  font-family: var(--mono); font-size: .72rem;
  color: var(--mittel); font-variant-numeric: tabular-nums;
}
.servereintrag .meta {
  font-family: var(--mono); font-size: .72rem; color: var(--leise);
  padding-left: .92rem;
}

.serverneu {
  text-align: left; padding: .6rem .8rem; border-radius: var(--radius);
  font: inherit; font-size: .82rem;
  background: none; border: 1px dashed var(--rand-gestrichelt);
  color: var(--leise); cursor: pointer;
}
.serverneu:hover { border-color: var(--rand-hover); color: var(--schrift-hover); }
.serverneu[aria-expanded="true"] { border-style: solid; color: var(--schrift-hover); }

/* Die Begründung steht da, wo der Knopf steht — nicht in einem Tooltip,
   den auf dem Handy niemand zu sehen bekommt. */
.serverneu-grund {
  margin: 0; padding: .1rem 0 .2rem .2rem;
  font-size: .78rem; line-height: 1.5; color: var(--leise);
}
.serverneu-grund[hidden] { display: none; }
.serverneu-grund code { font-family: var(--mono); font-size: .92em; }

/* --- Sprungmarken --- */
.sprungmarken { display: flex; flex-direction: column; gap: .1rem; margin-top: -.6rem; }
.sprungmarken a {
  display: flex; align-items: baseline; gap: .6rem;
  padding: .42rem .8rem; border-radius: 8px;
  font-size: .88rem; color: var(--leise); text-decoration: none;
  border-left: 2px solid transparent;
}
.sprungmarken a:hover { color: var(--schrift); }
.sprungmarken a[aria-current="true"] { color: var(--schrift); border-left-color: var(--messing); }
.sprungmarken .zusatz {
  margin-left: auto; font-family: var(--mono); font-size: .72rem;
  color: var(--leise); font-variant-numeric: tabular-nums;
}
.sprungmarken .zusatz.gut   { color: var(--gut); }
/* Fehlte bis zum 26.09.2026 — „Limits 82 %" setzte die Klasse warn, und
   nichts färbte sie. Aufgefallen beim Einbau der Websites, die dieselbe
   Klasse für Serverfehler benutzen. */
.sprungmarken .zusatz.warn  { color: var(--warn); }
.sprungmarken .zusatz.alarm { color: var(--alarm); }

/* --- Fußblock --- */
.schienenfuss {
  margin-top: auto; display: flex; flex-direction: column; gap: .35rem;
  font-family: var(--mono); font-size: .72rem; color: var(--leise); line-height: 1.6;
}
.schienenfuss .knoepfe { display: flex; align-items: center; gap: 1rem; margin-top: .4rem; }

/* Die Fassung steht klein und ruhig da — man braucht sie selten, aber wenn,
   dann sofort: „Läuft oben wirklich, was ich hochgeladen habe?" */
.schienenfuss #fassung { opacity: .8; }

/* Der Hinweis auf eine neue Fassung stand früher hier im Fußblock — am
   Schreibtisch unten links, am Handy irgendwo hinter dem Inhalt. Er ist
   jetzt ein Punkt in der Lagezeile über dem Inhalt. */

.alslink {
  background: none; border: none; padding: 0;
  color: var(--leiser); font: inherit; text-decoration: underline; cursor: pointer;
}
.alslink:hover, .alslink:focus-visible { color: var(--messing); }

/* Der Anstoß-Knopf. Steht im Kopf von „Budgets je Workspace", weil er
   genau einen Abruf auslöst: den von Anthropic. Neben dem allgemeinen
   Zeitstempel im Fußblock sah er aus, als lüde er alles neu.
   Trefferfläche 44 px, ohne die Zeile aufzublasen. */
.anstoss {
  background: none; border: none; padding: .3rem .1rem;
  min-height: 44px; margin: -.3rem 0;
  color: var(--leiser); font: inherit; font-family: var(--mono);
  font-size: .72rem; cursor: pointer;
  display: inline-flex; align-items: center; gap: .35rem;
}
/* Im Abschnittskopf sitzt er hinter dem Kurzwert, nicht davor — der
   Kurzwert schiebt sich mit margin-left:auto nach rechts, der Knopf folgt. */
.abschnittskopf .anstoss { flex: none; }
.anstoss:hover:not(:disabled) { color: var(--messing); }
.anstoss:disabled { cursor: default; }
.anstoss .zeichen { display: inline-block; font-size: .9rem; }
.anstoss.laeuft { color: var(--messing); }
.anstoss.laeuft .zeichen { animation: dreht 1s linear infinite; }

@keyframes dreht { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes pulst { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }

/* Wer „Bewegung reduzieren" eingestellt hat, bekommt ein Pulsieren statt
   der Drehung. Ganz ohne Rückmeldung dazustehen wäre schlechter. */
@media (prefers-reduced-motion: reduce) {
  .anstoss.laeuft .zeichen { animation: pulst 1.2s ease-in-out infinite; }
  .balken i { transition: none; }
}

/* ==================== Inhaltsspalte ==================== */

.inhalt {
  flex: 1 1 620px; min-width: 0;
  padding: 1.6rem clamp(1.1rem, 3vw, 2.6rem) 3rem;
  display: flex; flex-direction: column; gap: 2.4rem;
}

/* --- Lagezeile ---
   Nennt nur Abweichungen und verschwindet sonst. Sie hat den Rahmen des
   alten Warnbands geerbt, weil er sich bewährt hat: kräftig genug, um
   aufzufallen, ruhig genug, um nicht zu blinken. */
.lage {
  display: flex; flex-direction: column; gap: .45rem;
  padding: .7rem .9rem;
  border: 1px solid var(--warnband-rand); border-radius: var(--radius);
  background: var(--warnband-grund); color: var(--warnband-schrift);
  font-size: .85rem;
}
.lage[hidden] { display: none; }
/* Steht nur ein Hinweis darin (etwa „neue Fassung"), ist das keine
   Störung — dann tritt der Kasten zurück. */
.lage.nur-hinweis {
  border-color: var(--rand); background: var(--flaeche); color: var(--schrift);
}
.lagerubrik {
  font-family: var(--mono); font-size: .72rem; letter-spacing: .1em;
  text-transform: uppercase; opacity: .85;
}
.lageliste { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.lagepunkt {
  display: flex; align-items: baseline; gap: .6rem;
  color: inherit; text-decoration: none;
  /* Trefferfläche: Auf dem Handy ist jeder Punkt ein Sprungziel. */
  padding: .12rem 0; min-height: 24px;
}
a.lagepunkt:hover .lagetext { text-decoration: underline; }
.lagemarke {
  width: .42rem; height: .42rem; border-radius: 50%; flex: none;
  position: relative; top: -.1rem;
}
.lagemarke.alarm   { background: var(--alarm); }
.lagemarke.warn    { background: var(--warn); }
.lagemarke.hinweis { background: var(--messing); }
.lagetext { min-width: 0; }
.lagewohin {
  margin-left: auto; flex: none; white-space: nowrap;
  font-family: var(--mono); font-size: .72rem; opacity: .8;
}

/* --- Abschnitte --- */
.abschnitt { display: flex; flex-direction: column; gap: .9rem; scroll-margin-top: 1rem; }
/* display:flex schlägt das hidden-Attribut — ohne diese Zeile blieb der
   Block „KI nicht eingerichtet" auch dann stehen, wenn die KI eingerichtet
   ist. Ein Fehler, den man erst im Bild sieht, nicht im Code. */
.abschnitt[hidden] { display: none; }

.abschnittskopf {
  display: flex; align-items: baseline; gap: 1rem; flex-wrap: wrap;
  border-bottom: 1px solid var(--rand); padding-bottom: .6rem;
}
.abschnittskopf h2 {
  margin: 0; font-family: var(--serif); font-weight: 400;
  font-size: 1.15rem; letter-spacing: -.01em;
}
/* Der Kurzwert rechts im Abschnittskopf — und im <summary> der Behälter,
   das kein .abschnittskopf ist. Deshalb steht die Farbe NICHT unter dem
   Elternselektor: Sonst bliebe "1 von 9 gestoppt" unauffällig weiß. */
.nebenwert {
  font-family: var(--mono); font-size: .72rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--leise);
}
.nebenwert.gut   { color: var(--gut); }
.nebenwert.warn  { color: var(--warn); }
.nebenwert.alarm { color: var(--alarm); font-weight: 500; }
.abschnittskopf .nebenwert { margin-left: auto; }
/* Ein Knopf im Kopf (Zeitraumwahl, „jetzt abrufen") braucht Luft für den
   Fokusring — mit 2 px verschwand er unter dem Innenabstand des Summary. */
.abschnittskopf button:focus-visible { outline-offset: 3px; }
/* Der zweite Kurzwert (Behältergruppen) hängt sich hinter den ersten und
   darf umbrechen, statt die Zeile zu sprengen. */
.gruppenzeile {
  font-family: var(--mono); font-size: .72rem; color: var(--leise);
  overflow-wrap: anywhere;
}
.abschnittskopf .nebenwert + .gruppenzeile { margin-left: 0; }

.fussnote { margin: 0; font-size: .78rem; color: var(--leise); }
.fussnote code { font-family: var(--mono); font-size: .94em; }

/* --- Kopf: laufender Monat --- */
.monatskopf {
  display: flex; flex-wrap: wrap; gap: 2rem 3rem;
  align-items: flex-end; justify-content: space-between;
}
.monatssumme { display: flex; flex-direction: column; gap: .5rem; }
.monatssumme .rubrik { letter-spacing: .14em; font-size: .7rem; }

/* Monatsumschalter. Die Pfeile sind bewusst gleich groß wie die Rubrik
   daneben und nicht größer: Sie sind eine Zugabe, nicht die Hauptsache.
   Trefferfläche trotzdem 44 px — auf dem Handy trifft man sonst nichts. */
.monatswahl { display: flex; align-items: center; gap: .5rem; }
.pfeilknopf {
  background: none; border: none; padding: 0;
  width: 44px; height: 44px; margin: -14px -14px -14px -12px;
  color: var(--leise); font: inherit; font-size: 1.1rem; line-height: 1;
  cursor: pointer;
}
.monatswahl .pfeilknopf + .rubrik { margin-left: -.2rem; }
.pfeilknopf:last-child { margin: -14px -14px -14px -12px; }
.pfeilknopf:hover:not(:disabled) { color: var(--messing); }
/* Unsichtbar statt stumpf: Deckkraft .3 war am Handy nicht als „geht
   nicht" zu erkennen — man klickte und suchte den Fehler bei sich. Der
   Platz bleibt stehen, damit die Rubrik daneben nicht springt. */
.pfeilknopf:disabled { visibility: hidden; cursor: default; }

/* Punktband: wie viele Monate gibt es, und wo stehe ich? Ohne es war die
   Wischgeste auf dem Handy unsichtbar. */
.monatspunkte { display: inline-flex; align-items: center; gap: .3rem; margin-left: .5rem; }
.monatspunkt {
  width: .3rem; height: .3rem; border-radius: 50%;
  background: var(--spur); flex: none;
}
.monatspunkt.hier { background: var(--messing); }

/* Der Vormonatsvergleich unter der Kursnote. */
.vergleich .warn  { color: var(--warn); }
.vergleich .leise { color: var(--leiser); }

/* Ein abgeschlossener Monat wird gedämpft ausgezeichnet — er ändert sich
   nicht mehr, und das soll man sehen, ohne das Datum zu lesen. */
.monatssumme.vergangen .rubrik { color: var(--messing); }

.kennzahl {
  font-family: var(--serif); font-weight: 300;
  font-size: clamp(3.2rem, 7vw, 4.6rem); line-height: .95;
  letter-spacing: -.02em; font-variant-numeric: tabular-nums;
}
.kennzahl .waehrung {
  font-size: .35em; font-weight: 400; color: var(--mittel); margin-left: .35rem;
}
.kursnote { font-family: var(--mono); font-size: .74rem; color: var(--leise); }

.kostenliste {
  margin: 0; display: grid; grid-template-columns: auto auto;
  gap: .55rem 1.6rem; align-items: baseline; font-size: .88rem;
  flex: 0 1 340px;
}
.kostenliste dt { color: var(--mittel); }
/* Kurzes Label oben, Erklärung als Mono-Beizeile darunter. Vorher stand
   alles in einer Zeile („Server cx23, inkl. Sicherung +20 %") und brach um,
   sobald die Liste unter 340 px kam — die Beträge rutschten dann gegen
   leere Zeilen. */
.kostenliste .unterzeile {
  display: block; font-family: var(--mono); font-size: .7rem;
  color: var(--leise); line-height: 1.4;
}
.kostenliste dd { margin: 0; text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.kostenliste dd.leise { color: var(--leise); }
.kostenliste dd.hervor { color: var(--messing); font-weight: 500; }

/* --- Balken (überall gleich: 3 px) --- */
.balken { height: 3px; border-radius: 2px; background: var(--spur); overflow: hidden; }
.balken i {
  display: block; height: 100%; width: 0;
  background: var(--messing); transition: width .4s;
}
.balken i.warn  { background: var(--warn); }
.balken i.alarm { background: var(--alarm); }

/* --- Budgets je Workspace ---
   Drei Spalten: Name mit Betrag darunter, Balken, Text. Vorher lagen Balken
   und Text in einer gemeinsamen Flexbox, und der Text mit `flex: none`
   schob sich unter rund 700 px Inhaltsbreite rechts aus der Zeile hinaus —
   sichtbar lange bevor die 520-px-Abfrage griff. */
.budgetliste { display: flex; flex-direction: column; }

.budgetzeile {
  display: grid;
  /* Alle drei Spalten in fr, KEINE mit `auto`: Jede Zeile ist ein eigenes
     Raster, und eine auto-Spalte richtet sich nach dem Inhalt IHRER Zeile.
     Die Balken standen dadurch von Zeile zu Zeile um ein paar Pixel
     versetzt — kaum zu benennen, aber unruhig zu lesen. */
  grid-template-columns: minmax(110px, 1.1fr) minmax(140px, 1.6fr) minmax(130px, 1.3fr);
  gap: .4rem 1.2rem; align-items: center;
  padding: .75rem 0; border-bottom: 1px solid var(--rand-fein);
}
.budgetzeile .wskopf {
  display: flex; flex-direction: column; gap: .1rem; min-width: 0;
}
.budgetzeile .wsname { font-size: .92rem; font-weight: 500; }
.budgetzeile.ohne-kosten .wsname,
.budgetzeile.ohne-kosten .wsbetrag { color: var(--leise); }
.budgetzeile .wsbetrag {
  font-family: var(--mono); font-size: .72rem;
  font-variant-numeric: tabular-nums; color: var(--leise);
}
/* Der Balken trägt die Hochrechnung als Marke. Deshalb eine eigene Höhe:
   Die Marke ragt über die 3-px-Spur hinaus und bräuchte sonst Platz, den
   die Zeile nicht hat. */
.budgetzeile .wsbudget {
  position: relative; height: 14px; display: flex; align-items: center;
  min-width: 0;
}
.budgetzeile .wsbudget .balken { width: 100%; }
.budgetzeile .hochmarke {
  position: absolute; top: 0; width: 1px; height: 14px;
  background: var(--leise); transform: translateX(-50%);
}
.budgetzeile .hochmarke::after {
  content: ''; position: absolute; left: 50%; top: -3px;
  width: 5px; height: 5px; border-radius: 50%;
  background: inherit; transform: translateX(-50%);
}
.budgetzeile .hochmarke.warn { background: var(--warn); }

.budgetzeile .keinbudget {
  font-family: var(--mono); font-size: .72rem; color: var(--leiser);
}
/* white-space: normal — der Text darf zweizeilig werden. Genau daran ist
   die alte Fassung gescheitert. */
.budgetzeile .budgettext {
  font-family: var(--mono); font-size: .72rem; text-align: right;
  white-space: normal; line-height: 1.45;
  font-variant-numeric: tabular-nums; color: var(--leise);
}
.budgetzeile .budgettext.warn  { color: var(--warn); }
.budgetzeile .budgettext.alarm { color: var(--alarm); font-weight: 500; }
.budgetzeile .hochtext { display: block; color: var(--leiser); }
.budgetzeile .hochtext.warn  { color: var(--warn); }
.budgetzeile .hochtext.alarm { color: var(--alarm); }

.budgetzeile.zusammen { border-bottom: none; padding: .9rem 0 0; }
.budgetzeile.zusammen .wsname { font-family: var(--serif); font-size: 1rem; font-weight: 400; }

/* Unter 640 px wird aus drei Spalten eine: Name und Betrag, darunter der
   Balken über die volle Breite, darunter der Text linksbündig. Die alte
   Schwelle lag bei 520 px — zu spät, der Überlauf begann früher. */
@media (max-width: 640px) {
  .budgetzeile { grid-template-columns: 1fr; gap: .5rem; }
  .budgetzeile .budgettext { text-align: left; }
}

/* --- Websites ---
   Dieselbe Dreiteilung wie bei den Budgets: Name mit Beizeile, Balken,
   Wert. Alle Spalten in fr, damit die Balken von Zeile zu Zeile auf
   derselben Linie beginnen (siehe .budgetzeile). Der Balken ist relativ
   zur meistbesuchten Domain — er zeigt Verhältnisse, keinen Anschlag,
   und deshalb nie Bernstein oder Terrakotta. */
#webkurve { margin-bottom: .4rem; }
.webliste { display: flex; flex-direction: column; }
.webzeile {
  display: grid;
  grid-template-columns: minmax(150px, 1.4fr) minmax(120px, 1.6fr) minmax(70px, .6fr);
  gap: .4rem 1.2rem; align-items: center;
  padding: .7rem 0; border-bottom: 1px solid var(--rand-fein);
}
.webzeile .webkopf { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.webzeile .webname { font-size: .92rem; font-weight: 500; overflow-wrap: anywhere; }
.webzeile .webunter {
  font-family: var(--mono); font-size: .72rem; color: var(--leise);
  font-variant-numeric: tabular-nums;
}
.webzeile .webunter .alarm { color: var(--alarm); font-weight: 500; }
.webzeile .webwert {
  font-family: var(--mono); font-size: .8rem; text-align: right;
  font-variant-numeric: tabular-nums;
}
/* Eine Domain ohne Zugriff im Zeitraum steht gedämpft da — sie ist eine
   Information, aber keine, die hervorstechen muss. */
.webzeile.ruhig .webname, .webzeile.ruhig .webwert { color: var(--leise); }
/* Zwei Teile in einem Balken: Abrufe (Messing), dahinter die Anfragen der
   Apps gedämpft. Flex statt Block, damit die Teile nebeneinander liegen. */
.webzeile .balken { display: flex; }
.webzeile .balken i { flex: none; }
.webzeile .balken i.app { background: var(--leise); }
.webzeile.sonstige .webname { font-weight: 400; color: var(--leise); }

@media (max-width: 640px) {
  .webzeile { grid-template-columns: 1fr auto; }
  .webzeile .balken { grid-column: 1 / -1; grid-row: 2; }
}

/* Token je Modell — kleine Beigabe unter den Budgets. Nicht im Handoff
   vorgesehen, aber die Zahlen gibt es heute schon; sie wortlos zu
   streichen wäre ein Verlust. Bewusst zurückgenommen dargestellt. */
.modelle {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0 2.4rem;
}
.modelle li {
  display: flex; justify-content: space-between; gap: 1rem;
  padding: .4rem 0; border-bottom: 1px solid var(--rand-fein);
  font-family: var(--mono); font-size: .72rem; color: var(--leise);
  font-variant-numeric: tabular-nums;
}

/* --- Ratenlimits --- */
.limitgruppe + .limitgruppe { margin-top: 1.4rem; }
.limitgruppe .gruppenkopf {
  display: flex; align-items: baseline; gap: .8rem; flex-wrap: wrap;
  margin-bottom: .7rem;
}
.limitgruppe .gruppenkopf .modelle {
  font-family: var(--mono); font-size: .72rem; color: var(--leise);
  overflow-wrap: anywhere;
}

.limitzeile {
  display: grid;
  grid-template-columns: minmax(130px, 1fr) minmax(150px, 2fr) minmax(110px, auto);
  gap: .5rem 1.2rem; align-items: center;
  padding: .6rem 0; border-bottom: 1px solid var(--rand-fein);
}
/* min-width: 0 und Umbruch überall: Ein Maschinenname wie
   „input_tokens_per_minute_cache_aware" hat keine Stelle zum Umbrechen und
   lief sonst in die Balkenspalte hinein. */
.limitzeile .lname { font-size: .9rem; min-width: 0; overflow-wrap: anywhere; }
.limitzeile .lzusatz {
  display: block; font-family: var(--mono); font-size: .72rem;
  color: var(--leise); line-height: 1.4;
}
.limitzeile .lwert {
  font-family: var(--mono); font-size: .74rem; text-align: right;
  white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--leise);
}
.limitzeile .lwert.warn  { color: var(--warn); }
.limitzeile .lwert.alarm { color: var(--alarm); font-weight: 500; }
/* Eine Zeile ohne messbare Auslastung bekommt keinen Balken — eine leere
   Spur behauptete eine Messung von null. */
.limitzeile .keinbalken {
  font-family: var(--mono); font-size: .72rem; color: var(--leise);
}

@media (max-width: 520px) {
  .limitzeile { grid-template-columns: 1fr auto; }
  .limitzeile .balken, .limitzeile .keinbalken { grid-column: 1 / -1; }
}

/* --- Zustand (mit Verlauf) ---
   Jede Kachel trägt Rubrik, Spitzenwert, Zahl, Balken, Kurve und Beizeile.
   Vorher standen dieselben Größen zweimal auf der Seite: oben als Zahl,
   zweihundert Pixel tiefer als Kurve mit derselben Zahl im Text. Die
   Mindestbreite ist wegen der Kurve von 190 auf 260 px gestiegen — darunter
   ist eine Kurve ein Strich. */
.zustandsgitter {
  display: grid; gap: 1.6rem 2rem;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.messwert { display: flex; flex-direction: column; gap: .4rem; }
.messwert .messkopf { display: flex; align-items: baseline; gap: .8rem; }
.messwert .spanne {
  margin-left: auto; font-family: var(--mono); font-size: .72rem;
  color: var(--leise); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.messwert .zahl {
  margin: 0; font-family: var(--serif); font-weight: 300;
  font-size: 2rem; line-height: 1; font-variant-numeric: tabular-nums;
}
.messwert .zahl .einheit { font-size: .42em; color: var(--mittel); margin-left: .2rem; }
.messwert .balken { margin-top: .15rem; }
.messwert .kurve { margin-top: .1rem; }
/* Netz ausgehend hat keinen Anschlag und deshalb keinen Balken. Damit die
   Kachel trotzdem auf derselben Grundlinie sitzt wie ihre Nachbarn,
   bekommt sie den fehlenden Balken als Abstand zurück. */
.messwert.ohne-balken .kurve { margin-top: calc(.1rem + 3px + .15rem); }
.messwert .neben { margin: 0; font-size: .76rem; color: var(--leise); }
.messwert .neben .alarm { color: var(--alarm); font-weight: 500; }

/* Ein Wert, den es auf diesem Server nicht gibt. Gedämpft UND im Text
   benannt — Farbe allein trüge die Aussage nicht. */
.messwert.nicht-messbar .zahl { color: var(--leise); }
.messwert.nicht-messbar .balken { opacity: .35; }

/* --- Diagramme --- */
.wahl { display: flex; gap: 1.1rem; margin-left: auto; }
.wahl[hidden] { display: none; }
.wahl button {
  background: none; border: none; padding: 0 0 .15rem; cursor: pointer;
  font-family: var(--mono); font-size: .72rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--leise);
  border-bottom: 1px solid transparent;
}
.wahl button.aktiv { color: var(--schrift); border-bottom-color: var(--messing); }

.diagramm { display: flex; flex-direction: column; gap: .35rem; }
.diagramm .diagrammkopf { display: flex; align-items: baseline; gap: .8rem; }
.diagramm h3 { margin: 0; font-size: .86rem; font-weight: 500; }
.diagramm .spanne {
  margin: 0 0 0 auto; font-family: var(--mono); font-size: .72rem;
  color: var(--leise); font-variant-numeric: tabular-nums;
}
.diagramm .leer { font-size: .8rem; color: var(--leise); padding: 1.6rem 0; }

/* Der Plot trägt den Tipp, deshalb position: relative. Die Höhe wächst mit
   dem SVG mit — ein fester Wert würde die x-Achse abschneiden. */
.diagramm .plot { position: relative; }
.diagramm svg { display: block; width: 100%; height: auto; touch-action: pan-y; }

.diagramm .gitterlinie { stroke: var(--gitter); stroke-width: 1; }
.diagramm text.achse {
  fill: var(--leiser); font-family: var(--mono); font-size: 10px;
  font-variant-numeric: tabular-nums;
}
.diagramm .kurvenflaeche { fill: var(--kurvenflaeche-fein); }
.diagramm .kurvenlinie   { fill: none; stroke: var(--messing); stroke-width: 1.6; }
.diagramm .punkt-marke   { fill: var(--messing); stroke: var(--grund); stroke-width: 2; }
.diagramm .fadenkreuz    { stroke: var(--leise); stroke-width: 1; }

/* Die große Kostenkurve trägt Titel und Spitzenwert bereits im
   Abschnittskopf — ein zweiter Kopf darüber wäre dieselbe Zahl zweimal
   innerhalb von drei Zentimetern. */
.diagramm.gross .diagrammkopf { display: none; }

/* Die große Kostenkurve: kräftigere Linie, satteres Feld, größere Achse. */
.diagramm.gross text.achse { font-size: 11px; }
.diagramm.gross .kurvenflaeche { fill: var(--kurvenflaeche); }
.diagramm.gross .kurvenlinie   { stroke-width: 1.75; }

/* Die Kurve in einer Zustandskachel: keine Achsen, keine Beschriftung,
   nur Grundlinie, Fläche und Linie. Sie ist eine Beigabe zur Zahl darüber —
   die trägt die Aussage. */
.diagramm.spark .kurvenlinie { stroke-width: 1.4; }
.diagramm.spark .leer { padding: .8rem 0; font-size: .76rem; }

/* --- Die große Kostenkurve --- */
/* Der noch offene Rest des Monats. Kein Messwert, sondern der Platz, den
   die Kurve noch bekommt — deshalb dunkler statt heller. */
.diagramm .monatsrest { fill: var(--monatsrest); }
/* Der Serversockel als eigene Fläche. Er verschwand vorher in der Summe;
   sichtbar beantwortet er die Frage, wie viel von einem Tag KI war. */
.diagramm .sockelflaeche { fill: var(--sockel); }
/* Gestrichelt heißt in dieser Oberfläche: gerechnet, nicht gemessen. */
.diagramm .mittellinie { stroke: var(--leise); stroke-width: 1; stroke-dasharray: 3 4; }

/* Zeichenerklärung unter der Kostenkurve. Drei Formen im Bild, alle drei
   benannt — sonst rät man. */
.legende {
  display: flex; flex-wrap: wrap; gap: .4rem 1.4rem;
  font-family: var(--mono); font-size: .72rem; color: var(--leise);
}
.legende[hidden] { display: none; }
.legendeneintrag { display: flex; align-items: center; gap: .4rem; }
.legendeneintrag i { flex: none; display: inline-block; }
.legendeneintrag .lg-linie   { width: 14px; height: 3px; background: var(--messing); }
.legendeneintrag .lg-flaeche { width: 14px; height: 9px; background: var(--sockel); }
.legendeneintrag .lg-strich  { width: 14px; height: 0; border-top: 1px dashed var(--leise); }
.legendeneintrag .lg-rest    { width: 14px; height: 9px; background: var(--monatsrest); }

.diagramm .tipp {
  position: absolute; top: 0; transform: translateX(-50%);
  background: var(--grund); border: 1px solid var(--rand);
  border-radius: 6px; padding: .2rem .45rem;
  font-family: var(--mono); font-size: .72rem; color: var(--schrift);
  font-variant-numeric: tabular-nums; white-space: nowrap;
  pointer-events: none;
}

/* --- Klappbare Abschnitte ---
   Jeder Abschnitt mit Kopfzeile lässt sich zuklappen; der Zustand wird je
   Abschnitt gemerkt (klappVerwalten in app.js). Zugeklappt bleibt der
   Kurzwert rechts stehen — er versteckt Details, nie einen Alarm. */
summary.abschnittskopf {
  cursor: pointer; list-style: none; user-select: none;
}
summary.abschnittskopf::-webkit-details-marker { display: none; }

/* Der Winkel steht VOR dem Titel und dreht sich beim Öffnen. Er ist ein
   eigenes Flex-Kind, deshalb reicht ::before ohne Positionierung. */
summary.abschnittskopf::before {
  content: '›';
  flex: none; display: inline-block;
  color: var(--leise); font-size: 1.05rem; line-height: 1;
  transition: transform .15s;
}
details[open] > summary.abschnittskopf::before { transform: rotate(90deg); }

@media (prefers-reduced-motion: reduce) {
  summary.abschnittskopf::before { transition: none; }
}
/* Größere Trefferfläche für den Finger, ohne die Zeile aufzublasen. */
@media (pointer: coarse) {
  summary.abschnittskopf { padding-top: .45rem; padding-bottom: .9rem; }
}

/* --- Behälter --- */

/* gap: 0 2.4rem — ohne Spaltenabstand stößt der Status der linken Spalte
   an den Punkt der rechten. */
/* Gruppiert nach der Vorsilbe des Namens (dapp-, kontor-, db-). Die
   Zuordnung steckt schon in den Namen — eine Tabelle dafür zu pflegen wäre
   Arbeit ohne Gewinn. */
.behaeltergruppen { display: flex; flex-direction: column; gap: 1.2rem; }
.behaeltergruppe { display: flex; flex-direction: column; gap: .2rem; }

.behaelterliste {
  list-style: none; margin: .2rem 0 0; padding: 0;
  display: grid; gap: 0 2.4rem;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.behaelterliste li {
  display: flex; align-items: baseline; gap: .7rem;
  padding: .55rem 0; border-bottom: 1px solid var(--rand-fein);
}
.behaelterliste .punkt {
  width: .4rem; height: .4rem; border-radius: 50%; flex: none;
  background: var(--alarm);
}
.behaelterliste .punkt.laeuft { background: var(--gut); }
.behaelterliste .name { font-size: .88rem; font-weight: 500; }
/* Heißt .lage-text und nicht .lage: Der Kasten oben im Inhalt trägt jetzt
   die Klasse .lage, und zwei gleichnamige Klassen an weit auseinander
   liegenden Stellen sind der Anfang eines Fehlers, den man lange sucht. */
.behaelterliste .lage-text {
  margin-left: auto; font-family: var(--mono); font-size: .72rem; color: var(--leise);
}
.behaelterliste li.gestoppt .lage-text { color: var(--alarm); }

/* ==================== Auslastung als Überblick ====================
 *
 * Dieselben drei Zahlen wie im Abschnitt „Zustand", hier nur ohne Scrollen:
 * am Schreibtisch unter den Sprungmarken, am Handy im klebenden Kopf. Das
 * Ganze ist ein Verweis auf „Zustand" — kein eigenes Bedienelement.
 *
 * Die Spur ist 3 px wie jeder Balken dieser Oberfläche; Bernstein ab 75 %,
 * Terrakotta ab 90 %, dieselben Grenzen wie in den Kacheln. Der Wert steht
 * immer als Zahl daneben — die Farbe trägt die Aussage nie allein.
 */
.auslastung {
  display: flex; flex-direction: column; gap: .5rem;
  padding: .3rem .8rem .4rem; margin-top: -.6rem;
  border-radius: 8px; color: inherit; text-decoration: none;
}
.auslastung:hover .lastname { color: var(--schrift); }
/* Im Quelltext steht der Wert VOR der Spur, damit eine Vorlesehilfe „CPU
   11 %" liest und nicht erst über einen leeren Balken stolpert. Gezeigt
   wird er rechts davon — deshalb die ausdrücklichen Spalten. */
.auslastung .lastzeile {
  display: grid; grid-template-columns: 3.4rem 1fr 2.8rem;
  align-items: center; gap: .6rem;
}
.auslastung .lastname { grid-column: 1; }
.auslastung .lastspur { grid-column: 2; grid-row: 1; }
.auslastung .lastwert { grid-column: 3; grid-row: 1; white-space: nowrap; }
.auslastung .lastname { font-size: .82rem; color: var(--leise); }
.auslastung .lastwert {
  font-family: var(--mono); font-size: .72rem; text-align: right;
  color: var(--leise); font-variant-numeric: tabular-nums;
}
.auslastung .lastspur {
  display: block; height: 3px; border-radius: 2px;
  background: var(--spur); overflow: hidden;
}
.auslastung .lastspur i {
  display: block; height: 100%; width: 0;
  background: var(--messing); transition: width .4s;
}
.auslastung .warn  .lastspur i { background: var(--warn); }
.auslastung .alarm .lastspur i { background: var(--alarm); }
.auslastung .warn  .lastwert { color: var(--warn); }
.auslastung .alarm .lastwert { color: var(--alarm); font-weight: 500; }
/* Nicht messbar (Server ohne Sammler): die Spur tritt zurück, der Strich
   „–" sagt den Rest. */
.auslastung .leer .lastspur { opacity: .45; }

/* Im Kopf: drei kleine Säulen nebeneinander, Name und Wert oben, Spur
   darunter. Die Rubrik entfällt — hier ist kein Platz für ein Wort, das
   die Zahlen ohnehin erklären. */
.auslastung.kompakt {
  flex-direction: row; gap: .7rem; padding: 0; margin: 0 0 0 auto; flex: none;
}
.auslastung.kompakt .lastzeile {
  grid-template-columns: auto auto; grid-template-rows: auto 3px;
  gap: .2rem .3rem; min-width: 2.9rem;
}
.auslastung.kompakt .lastname { grid-column: 1; font-family: var(--mono); font-size: .68rem; }
.auslastung.kompakt .lastwert { grid-column: 2; grid-row: 1; }
.auslastung.kompakt .lastspur { grid-column: 1 / -1; grid-row: 2; }
.auslastung.kompakt .lastprozent { font-size: .82em; }

@media (prefers-reduced-motion: reduce) {
  .auslastung .lastspur i { transition: none; }
}

/* ==================== Klebender Kopf (nur schmal) ====================
 *
 * Am Schreibtisch gibt es ihn nicht — dort steht alles in der Schiene. Am
 * Handy trägt er Servername, Standort, Uhrzeit und die Sprungmarken und
 * bleibt beim Scrollen stehen. Vorher waren es rund 360 px Schiene bis zur
 * ersten Zahl, und die Sprungmarken waren nach 60 px Scrollen weg — genau
 * auf dem Gerät, für das sie gebaut wurden.
 *
 * Er ist ein DIREKTES Kind des Rahmens, nicht Teil der Schiene: Ein
 * position:sticky-Element klebt nur, solange sein Elternteil im Bild ist.
 */
.handykopf { display: none; }

.handykopf .handyzeile {
  display: flex; align-items: center; gap: .6rem;
  padding: .8rem 1rem .5rem;
  padding-top: calc(.8rem + env(safe-area-inset-top));
}
.handykopf .handyzeile .netzm { flex: none; opacity: .9; }
.handykopf .hname {
  font-size: .9rem; font-weight: 600; letter-spacing: -.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  min-width: 3rem;
}
.handykopf .hmeta {
  font-family: var(--mono); font-size: .72rem; color: var(--leise);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.handykopf .hstand {
  flex: none;
  font-family: var(--mono); font-size: .72rem; color: var(--leise);
  font-variant-numeric: tabular-nums;
}

/* Die Sprungmarken wohnen mal hier, mal in der Schiene — umgehängt von
   markenUmhaengen() in app.js. Der Platzhalter selbst hat keine eigene
   Gestalt. */
.markenplatz { display: contents; }

/* ==================== Monatsklammer ====================
 *
 * Beim Blättern in einen vergangenen Monat zeigen Zustand, Limits und
 * Behälter weiter „jetzt". Das ist fachlich richtig, aber optisch trennte
 * nichts die alten Zahlen von den aktuellen. Die Klammer zieht eine Linie
 * um genau die Abschnitte, die mitblättern.
 */
.monatsteil.vergangen {
  border-left: 2px solid var(--messing);
  padding-left: clamp(.7rem, 2vw, 1.2rem);
  margin-left: calc(-1 * clamp(.7rem, 2vw, 1.2rem) - 2px);
}

/* Ein Servereintrag ist so frisch wie die Hetzner-Abfrage, aus der er
   stammt. War die alt, zeigte er trotzdem „running · 6,53 €" in voller
   Deckkraft, während daneben alles gedämpft war. */
.serverliste.veraltet { opacity: .45; }

/* ==================== Anmeldemaske ====================
   Deckt alles ab, statt nur zu überlagern: Zahlen, die man nicht mehr
   aktualisieren darf, sollen auch nicht durchschimmern. */
.anmeldung {
  position: fixed; inset: 0; z-index: 20;
  background: var(--grund);
  display: flex; align-items: center; justify-content: center;
  padding: 1.2rem;
  padding-top: calc(1.2rem + env(safe-area-inset-top));
  padding-bottom: calc(1.2rem + env(safe-area-inset-bottom));
}
.anmeldung[hidden] { display: none; }

.anmeldekarte {
  width: 100%; max-width: 340px;
  background: var(--flaeche); border: 1px solid var(--rand);
  border-radius: var(--radius); padding: 1.4rem;
  text-align: center;
}
.anmeldekarte h2 {
  margin: .6rem 0 .3rem; font-family: var(--serif);
  font-weight: 400; font-size: 1.3rem;
}
.anmeldekarte .klein { color: var(--leise); font-size: .8rem; margin: 0 0 1.1rem; }

.feld { display: block; text-align: left; margin-bottom: .9rem; }
.feld span { display: block; font-size: .78rem; color: var(--leise); margin-bottom: .3rem; }
.feld input {
  width: 100%; padding: .7rem .8rem;
  /* 16px: Alles darunter lässt Safari auf dem iPhone hineinzoomen, und
     danach steht die Karte schief. */
  font-size: 16px; font-family: var(--sans);
  background: var(--grund); color: var(--schrift);
  border: 1px solid var(--rand); border-radius: 8px;
}

.anmeldekarte button[type="submit"] {
  width: 100%; padding: .75rem;
  background: var(--messing); color: var(--auf-messing); border: none;
  border-radius: 8px; font: inherit; font-size: 1rem; font-weight: 600; cursor: pointer;
}
.anmeldekarte button[type="submit"]:disabled { opacity: .55; cursor: default; }

.anmeldefehler {
  margin: 0 0 .9rem; padding: .5rem .7rem; text-align: left;
  background: var(--fehler-grund); border: 1px solid var(--alarm);
  border-left-width: 4px; border-radius: 8px;
  font-size: .82rem; color: var(--fehler-schrift);
}
.anmeldefehler[hidden] { display: none; }

/* ==================== Schmale Fenster ====================
 *
 * Steht bewusst GANZ AM ENDE: Eine Medienabfrage gewinnt nicht dadurch, dass
 * sie eine Medienabfrage ist — bei gleicher Spezifität gewinnt die spätere
 * Regel. Weiter oben platziert wurde dieser Block von den Grundregeln der
 * Schiene wieder überschrieben, und die Sprungmarken standen schmal
 * weiterhin untereinander.
 *
 * Früher hat dieser Block Sprungmarken und „+ Server aufnehmen"
 * ausgeblendet. Das war falsch: Ein schmal gezogenes Fenster am Schreibtisch
 * ist kein Handy, und Bedienelemente verschwinden zu lassen ist etwas
 * anderes, als sie zu verkleinern. Jetzt ändert sich nur die Form — aus der
 * senkrechten Liste wird eine waagerechte Zeile, die notfalls seitlich
 * scrollt. Das kostet eine Zeile statt fünf, ohne dass etwas fehlt.
 */
@media (max-width: 900px) {
  /* Reihenfolge: klebender Kopf, Inhalt, dann die Schiene mit Serverliste,
     „+ Server aufnehmen" und Abmelden. Die Bedienelemente verschwinden
     also NICHT — sie stehen nur da, wo man sie sucht, wenn man sie
     braucht, und nicht vor der ersten Zahl. */
  .handykopf {
    display: block; order: -1; width: 100%;
    position: sticky; top: 0; z-index: 10;
    background: var(--kopf-grund);
    backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--rand);
  }
  .inhalt { order: 1; padding-top: 1.1rem; }
  .schiene {
    order: 2;
    border-top: 1px solid var(--rand);
    padding-top: 1.6rem;
  }
  /* Die Marke wiederholt sich im klebenden Kopf — einmal reicht. Ebenso
     die Auslastung: Sie steht oben im Kopf, am Seitenende wäre sie ein
     zweites Mal dieselbe Zahl. */
  .schiene .marke, .schiene .auslastung { display: none; }

  .sprungmarken {
    flex-direction: row; margin-top: 0; gap: .3rem;
    overflow-x: auto; scrollbar-width: none;
    padding: 0 .6rem .1rem;
  }
  .sprungmarken::-webkit-scrollbar { display: none; }
  .sprungmarken a {
    flex: none; white-space: nowrap;
    border-left: none; border-bottom: 2px solid transparent;
    border-radius: 8px 8px 0 0; padding: .4rem .6rem .5rem;
  }
  .sprungmarken a[aria-current="true"] {
    border-bottom-color: var(--messing);
  }
  .sprungmarken .zusatz { margin-left: .45rem; }

  /* Beim Springen darf der klebende Kopf das Ziel nicht verdecken. */
  .abschnitt { scroll-margin-top: 6.5rem; }

  /* Die Zeichenerklärung untereinander: nebeneinander umbrach jeder
     Eintrag für sich, und die Zeilen verzahnten sich. */
  .legende { flex-direction: column; gap: .3rem; }
  .legendeneintrag { align-items: flex-start; }
  .legendeneintrag i { margin-top: .45rem; }
}

/* Unter 640 px weicht Standort und Typ im Kopf der Auslastung. Standort
   und Typ stehen in der Serverliste am Seitenende; ob der Server gerade
   ausgelastet ist, steht nirgends sonst im Blick. */
@media (max-width: 640px) {
  .handykopf .hmeta { display: none; }
  .handykopf .handyzeile { gap: .55rem; }
  .auslastung.kompakt { gap: .55rem; }
  /* Das Prozentzeichen klein und ohne Abstand — siehe auslastungZeichnen().
     Die Einheit bleibt lesbar, kostet aber keine Spalte mehr. */
  .auslastung.kompakt .lastprozent { font-size: .7em; letter-spacing: -.05em; }
}
