* { box-sizing: border-box; }

/*
 * Die Farbtokens.
 *
 * Bis zum 18.09.2026 kamen sie aus `frontend/site/Polaris1 App v2.dc.html`
 * und das Seitenmenue war in beiden Modi nachtblau. Jetzt traegt die Leiste
 * denselben hellen Grund wie die Seite, und der aktive Punkt ist eine weisse
 * Plakette darauf -- der Aufbau aus dem Sequence-Entwurf.
 *
 * Zwei Gruens, nicht eins. Das ist der Punkt, an dem ein Token-Tausch
 * scheitert: `--brand`/`--plate` sind eine **Flaeche** (Minz, fast schwarze
 * Schrift darauf), `--acc` ist **Schrift** auf Hell (abgedunkelt, bis sie
 * lesbar ist). Ein Wert fuer beides ergibt entweder einen stumpfen Knopf
 * oder eine unlesbare Ziffer.
 */

:root {
  --bg: #f4f6f8; --card: #ffffff; --panel: #fafbfc; --panel2: #eef2f7;
  /* Die Seitenleiste, und eine eingesenkte Flaeche innerhalb einer Karte. */
  --rail: #eef1f5; --sunk: #f6f8fa;
  --ink: #0c1524; --ink2: #3d4854; --muted: #55606d; --faint: #7c8794;
  --line: #e5e9ee; --line2: #d7dde4;

  /* Gruen als Flaeche -- gefuellte Knoepfe, das O der Wortmarke, der Punkt
     am laufenden Test. Dunkle Schrift darauf. */
  --brand: #5ceda3; --onacc: #04180f;
  --plate: linear-gradient(180deg,#7df3b8 0%,#4fe39a 100%);
  --plateh: linear-gradient(180deg,#9cfbcd 0%,#6bedae 100%);
  /* Gruen als Schrift -- Links, Marken, Zahlen, aktive Zustaende. */
  --acc: #0b8f5c; --acc2: #077046; --acctint: #e6fbf1; --accline: #93e7c1;

  --red: #b0182a; --high: #c2410c; --amber: #a1690b; --green: #12864c;
  /*
   * Dieselben vier Stufen noch einmal, aber als **Flaeche** statt als Schrift.
   *
   * Die Werte darueber sind fuer Text auf Weiss gewaehlt: dunkel genug fuer
   * ausreichenden Kontrast. Als Balken oder Punkt wirken sie stumpf -- ein
   * gefuelltes #b0182a liest sich als Braunrot, nicht als „kritisch".
   *
   * Flaechen brauchen das umgekehrte: Saettigung statt Dunkelheit. Sie tragen
   * keinen Text, also gilt fuer sie auch keine Kontrastanforderung.
   */
  --fill-critical: #f0453f; --fill-high: #fb8b34;
  --fill-medium: #f0c02c;   --fill-low: #34c77b;
  --redt: #fceaec; --hight: #fdeee4; --ambert: #fdf4e6; --greent: #e9f6ef;

  /*
   * Das Seitenmenue. Die Namen bleiben, die Werte kippen von Nachtblau auf
   * Hell -- so mussten die Regeln darunter nicht angefasst werden, nur die
   * wenigen, die eine Farbe fest eingetragen hatten.
   */
  --sbbg: var(--rail); --sbline: var(--line); --sbink: var(--ink);
  --sbmuted: var(--ink2); --sbfaint: var(--faint);
  --sbhover: rgba(12,21,36,.045); --sbactive: var(--card);
  /* Die Schiene des Schalters im Aus-Zustand. `--line2` waere auf dem hellen
     Grund der Leiste zu schwach -- man saehe nur den weissen Knopf und nicht,
     wo er steht. */
  --switch-off: #ccd4dd;

  /* Karten heben sich mit einem Schatten statt mit einer zweiten Linie. */
  --shadow: 0 1px 2px rgba(12,21,36,.05);
  --shadow-lift: 0 1px 3px rgba(12,21,36,.09), 0 4px 12px rgba(12,21,36,.05);

  --mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", monospace;
  /*
   * Die Schrift der App: Helvetica, mit Inter als Rueckfall.
   *
   * Bis zum 08.09.2026 stand hier die Systemschrift, und fast jedes Etikett
   * -- Rubriken, Feldnamen, Zustaende, Tabellenkoepfe -- war Mono in
   * Grossbuchstaben mit weiter Sperrung. Das las sich wie ein Terminal.
   * Jetzt tragen Etiketten dieselbe Schrift wie der Text, halbfett und enger
   * gesperrt, und auch Hostnamen, Pfade, Adressen und Kennungen stehen in
   * Inter (`.val`). Mono bleibt nur, wo man Zeichen fuer Zeichen abschreibt:
   * DNS-Eintraege, Beweise, Wiederherstellungscodes, Code.
   *
   * Seit dem 18.09.2026 steht Helvetica davor. Sie liegt auf jedem Mac, auf
   * Windows und Linux aber nicht -- dort greift Inter, das ueber Google Fonts
   * geladen wird (siehe den `<link>` in index.html und dashboard/index.html).
   *
   * Das heisst: **wir und unsere Kunden sehen moeglicherweise nicht dasselbe.**
   * Die beiden sind sich naeher, als es klingt -- beide sind Grotesk mit
   * gleicher x-Hoehe-Tendenz --, aber Helvetica ist enger und kaelter. Wer
   * einen Screenshot fuer die Website macht, macht ihn auf einem Mac.
   *
   * Der saubere Ausweg waere eine lizenzierte Webschrift (Helvetica Now).
   * Bis dahin ist das hier eine bewusste Ungenauigkeit, keine uebersehene.
   */
  --sans: "Helvetica Neue", Helvetica, "Inter", -apple-system, BlinkMacSystemFont, Arial, sans-serif;
}

html.p1dark {
  --bg: #05080f; --card: #0a0e17; --panel: #0a0e17; --panel2: #0e131e;
  --rail: #080d16; --sunk: #0e131e;
  --ink: #ffffff; --ink2: rgba(255,255,255,.78); --muted: rgba(255,255,255,.56); --faint: rgba(255,255,255,.36);
  --line: rgba(255,255,255,.11); --line2: rgba(255,255,255,.2);
  --acc: #57e59d; --acc2: #8ff0bd; --acctint: rgba(87,229,157,.12); --accline: rgba(87,229,157,.34);
  --red: #ff5d6c; --high: #fb923c; --amber: #e7b04c; --green: #4fd493;
  /* Auf Dunkel sind die Textfarben bereits hell und gesaettigt. */
  --fill-critical: #ff5d6c; --fill-high: #fb923c;
  --fill-medium: #e7b04c;   --fill-low: #4fd493;
  --redt: rgba(255,93,108,.13); --hight: rgba(251,146,60,.13); --ambert: rgba(231,176,76,.13); --greent: rgba(79,212,147,.13);

  --sbhover: rgba(255,255,255,.05); --switch-off: rgba(255,255,255,.22);
  --shadow: 0 1px 2px rgba(0,0,0,.4);
  --shadow-lift: 0 1px 3px rgba(0,0,0,.5), 0 4px 12px rgba(0,0,0,.3);
}
html, body { margin: 0; padding: 0; background: var(--bg); }
body {
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  color: var(--ink);
}
a { color: var(--acc); }
a:hover { color: var(--acc2); }
input, select, button, textarea { font-family: inherit; }
::selection { background: var(--acctint); }

@keyframes p1spin { to { transform: rotate(360deg); } }
@keyframes p1pulse { 50% { opacity: .3; } }
@keyframes p1in { from { opacity: 0; transform: translateY(6px); } }

/* ── Bausteine ─────────────────────────────────────────────────────────── */

/* Eine Stufe dunkler als vorher (`--faint`): die Rubriken sind klein und in
   Grossbuchstaben, da war die hellste Textfarbe unter dem Kontrast fuer
   Kleinschrift -- aufgefallen am 03.09.2026 an der Zusammenfassung. */
.kicker {
  font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0;
  text-transform: none; color: var(--muted);
}

.field { display: block; }
.field > span {
  display: block; margin-bottom: 4px;
  font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0;
  text-transform: none; color: var(--faint);
}
.field > input {
  width: 100%; padding: 12px 12px;
  border: 1px solid var(--line2); border-radius: 6px;
  background: var(--card); color: var(--ink);
  font-family: var(--sans); font-size: 16px; outline: none;
}
.field > input:focus { border-color: var(--brand); box-shadow: 0 0 0 3px var(--acctint); }

.btn-provider {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  width: 100%; padding: 12px 16px;
  border: 1px solid var(--line2); border-radius: 6px;
  background: var(--card); color: var(--ink);
  font-size: 16px; font-weight: 500; cursor: pointer;
}
.btn-provider:hover:not(:disabled) { border-color: var(--ink); }
.btn-provider:disabled { opacity: .42; cursor: not-allowed; }
.btn-provider svg { width: 16px; height: 16px; }

/* Knoepfe in Satzschrift. Bis zum 03.09.2026 waren alle Knoepfe Mono in
   Grossbuchstaben mit Sperrung -- lesbar wie ein Terminal, nicht wie ein
   Produkt. Jetzt die Schrift der Seite, halbfett, normale Schreibung. Die
   Rubriken (`.kicker`) und Zustaende (`.pill`, `.phase-state`) behalten das
   Mono: sie sind Etiketten, keine Handlungen. */
.btn-plate {
  width: 100%; padding: 12px 20px; border: 0; border-radius: 6px;
  background: var(--plate); color: var(--onacc);
  font-family: inherit; font-size: 14px; font-weight: 500; letter-spacing: -.005em;
  cursor: pointer;
}
.btn-plate:hover:not(:disabled) { background: var(--plateh); }
.btn-plate:disabled { opacity: .5; cursor: progress; }

/* Der Rückweg neben einem Hauptknopf — sichtbar, aber ohne Gewicht. */
.btn-quiet {
  width: 100%; padding: 8px; border: 0; background: none; color: var(--muted);
  font-family: inherit; font-size: 14px; font-weight: 500;
  cursor: pointer;
}
.btn-quiet:hover { color: var(--ink); }

.rule {
  display: flex; align-items: center; gap: 12px; margin: 24px 0 20px;
  font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0;
  text-transform: none; color: var(--faint);
}
.rule::before, .rule::after { content: ""; flex: 1; height: 1px; background: var(--line); }

.note { font-family: var(--sans); font-size: 14px; line-height: 1.5; }
.note.err { color: var(--red); }
.note.ok  { color: var(--green); }

.mode-toggle {
  width: 32px; height: 18px; border-radius: 999px; border: 0; padding: 0;
  background: var(--switch-off); cursor: pointer; position: relative; transition: background .18s;
}
.mode-toggle::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 14px; height: 14px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 2px rgba(0,0,0,.25); transition: transform .18s;
}
.mode-toggle[aria-pressed="true"] { background: var(--brand); }
.mode-toggle[aria-pressed="true"]::after { transform: translateX(14px); }

/* Zwei Fassungen desselben Schalters, und `applyTheme` in app.js findet
   beide: es sucht nach `.mode-switch button`.

   Die **App** hat seit dem 18.09.2026 einen einzelnen Knopf (`.mode-toggle`)
   unten in der Seitenleiste -- die Huelle traegt dort keine eigene Gestalt.

   Die **Anmeldeseite** hat weiter Mond und Sonne nebeneinander (`.pair`):
   dort gibt es keine Seitenleiste, und ein Schalter ohne Beschriftung neben
   der Rubrik "Sign in" braucht seine beiden Zeichen, um erkennbar zu sein.

   Beim Aufraeumen am 19.09.2026 war `.pair` fuer einen Moment ungestaltet --
   auf der Anmeldeseite standen zwei leere graue Kaesten. */
.mode-switch { display: flex; }
.mode-switch.pair {
  gap: 2px; padding: 2px;
  border: 1px solid var(--line); border-radius: 6px; background: var(--card);
}
.mode-switch.pair button {
  display: grid; place-items: center; width: 26px; height: 22px;
  border: 0; border-radius: 6px; background: none; color: var(--faint); cursor: pointer;
  transition: color .2s, background .2s;
}
.mode-switch.pair button:hover { color: var(--ink); }
.mode-switch.pair button[aria-pressed="true"] { background: var(--acctint); color: var(--acc); }
/* Beim Hover kippt der Mond und die Sonne dreht ihre Strahlen -- eine kleine
   Bewegung, die sagt "hier passiert etwas", bevor man klickt. */
.mode-switch.pair svg {
  width: 13px; height: 13px; fill: currentColor;
  transition: transform .45s cubic-bezier(.2, .8, .2, 1);
}
.mode-switch.pair button[data-mode="dark"]:hover svg  { transform: rotate(-38deg); }
.mode-switch.pair button[data-mode="light"]:hover svg { transform: rotate(40deg); }

/* ── Hell/Dunkel: der Kreis ────────────────────────────────────────────────
   Beim Umschalten breitet sich das neue Thema als Kreis vom gedrueckten Knopf
   aus (`applyTheme` in app.js animiert den clip-path des neuen Bilds). Der
   Browser wuerde Alt und Neu sonst ueberblenden -- die Ueberblendung ist aus,
   damit nur der Kreis bleibt, und `mix-blend-mode` zurueck auf normal, weil
   die Ueberblendung sonst beide Bilder aufhellt. Das neue Bild liegt oben. */
::view-transition-old(root), ::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
::view-transition-old(root) { z-index: 1; }
::view-transition-new(root) { z-index: 2; }
/* Mittelpunkt und Radius setzt `applyTheme` als --p1x/--p1y/--p1r auf <html>,
   in Prozent (WebKit bemisst das Pseudo-Element in Geraetepixeln -- Pixel
   waeren dort doppelt); das Pseudo-Element erbt sie. Die Flaeche eines
   Kreises waechst mit dem Quadrat des Radius -- ease-in-out gleicht den
   traegen Anfang und das hastige Ende aus. */
@keyframes p1reveal {
  from { clip-path: circle(0 at var(--p1x) var(--p1y)); }
  to   { clip-path: circle(var(--p1r) at var(--p1x) var(--p1y)); }
}
html.p1swap::view-transition-new(root) { animation: p1reveal .52s ease-in-out both; }
/* Solange der Kreis laeuft, zieht kein Element seine Farbe nach -- das neue
   Bild soll fertig sein, wenn es freigelegt wird. */
html.p1swap *, html.p1swap *::before, html.p1swap *::after { transition: none !important; }

@media (prefers-reduced-motion: reduce) {
  .mode-toggle, .mode-toggle::after { transition: none; }
}

/* ── Anmeldung: zwei Spalten, links die Marke ──────────────────────────── */

.auth {
  min-height: 100vh; display: grid;
  grid-template-columns: minmax(0, .85fr) minmax(0, 1fr);
  background: var(--bg);
}
@media (max-width: 860px) { .auth { grid-template-columns: 1fr; } .auth-brand { display: none; } }

.auth-brand {
  position: relative; overflow: hidden; background: #05080f; color: #fff;
  padding: 36px 40px; display: flex; flex-direction: column;
}
/* Wortmarke oben, Satz in der Mitte des Restes. Bis zum 19.09.2026 stand hier
   `justify-content: space-between` und eine dritte Zeile unten ("EU
   processing · NDA by default · You set the scope"). Ohne sie haette
   `space-between` den Satz an den unteren Rand gezogen. */
.auth-brand .claim { margin-top: auto; margin-bottom: auto; }
.auth-brand::before {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(#04070e 0%, #050a14 46%, #071120 78%, #081a24 100%);
}
/* Die Leinwand liegt ueber dem Verlauf, unter allem Text.
   `pointer-events: none`, damit ein Klick links nichts abfaengt. */
.aurora-field {
  position: absolute; inset: 0; width: 100%; height: 100%;
  display: block; pointer-events: none;
}
.auth-brand > *:not(.aurora-field) { position: relative; z-index: 1; }
.auth-brand .wordmark {
  display: flex; align-items: baseline;
  font-family: "Orbitron", ui-monospace, monospace; font-weight: 500;
  font-size: 18px; text-transform: none; letter-spacing: 0;
}
/* Das O trägt die Markenfarbe, die übrigen Buchstaben nicht — deshalb eine
   feste Füllung statt `currentColor`. Der Stern bleibt die Aussparung
   (`fill-rule="evenodd"` am Pfad): Grün auf dem dunklen Grund steht bei rund
   9:1, die Sternfläche grün auf Weiß läge bei 1,7:1 und verschwömme in
   Wortmarkengröße zu einem hellen Fleck. */
.auth-brand .wordmark svg { display: block; width: 1.28cap; height: 1cap; margin: 0 .09em; fill: var(--brand); }
.auth-brand .claim { max-width: 21rem; }
.auth-brand .claim p:first-child {
  margin: 0; font-size: 24px; line-height: 1.3; font-weight: 500; letter-spacing: -.025em;
}
.auth-brand .claim p + p {
  margin: 16px 0 0; font-size: 16px; line-height: 1.65; color: rgba(255,255,255,.62);
}
/* ── Die Hülle: Seitenmenü + Inhalt ───────────────────────────────────────
 *
 * Aus `Polaris1 App v2.dc.html`, Zeile 123–177. Das Seitenmenü bleibt in
 * beiden Modi nachtblau — so war es entworfen, und es trägt die Marke.
 */

/* 20rem. Die Leiste traegt jetzt zwei Gruppen mit Ueberschriften; bei 15rem
   stand „Repositories" am Rand und die Ueberschriften wirkten eingequetscht. */
.shell { position: relative; height: 100vh; overflow: hidden; display: grid; grid-template-columns: 15rem minmax(0, 1fr); background: var(--bg); }
@media (max-width: 780px) { .shell { grid-template-columns: 3.6rem minmax(0, 1fr); } .side-label { display: none !important; } }
/* Von Hand eingeklappt. Dieselbe Wirkung wie die Breitenregel darueber --
   die Zeichen bleiben, die Woerter gehen. */
html.p1narrow .shell { grid-template-columns: 3.6rem minmax(0, 1fr); }
html.p1narrow .side-label { display: none !important; }
/* Eingefahren bleibt die Kachel oben links stehen -- sie ist die Ortsangabe.
   Der Knopf rueckt darunter: nebeneinander waeren es 21 + 8 + 22 = 51px bei
   rund 44 nutzbaren. */
html.p1narrow .side-top {
  flex-direction: column; align-items: center; gap: 8px; padding: 16px 0 8px;
}
html.p1narrow .side-collapse { margin-left: 0; }
html.p1narrow .side-nav a, html.p1narrow .side-soon { justify-content: center; padding: 0; }
html.p1narrow .side-foot { padding: 8px 8px; }
/* Eingeklappt bleibt der Schalter, das Mondzeichen geht -- beides nebeneinander
   passt nicht in 3.6rem, und von beidem ist der Schalter der, den man braucht. */
html.p1narrow .side-toggle { justify-content: center; padding: 0; }
html.p1narrow .side-toggle > svg { display: none; }
html.p1narrow .side-toggle .mode-switch { margin-left: 0; }
html.p1narrow .acct-card { justify-content: center; padding: 8px; }

/* `overflow: visible`, nicht `overflow-y: auto`. Eine Achse, die nicht
   `visible` ist, zwingt die andere in CSS auf `auto` -- die Leiste klemmte
   damit auch waagerecht, und das Kontomenue (15.5rem) wurde an ihrer Kante
   abgeschnitten: eingeklappt bei 3.6rem fast vollstaendig, ausgeklappt bei
   15rem um die letzten 8px. Gescrollt wird jetzt in `.side-nav`; die Fusszeile
   mit Konto und Themenschalter steht ohnehin auf `margin-top: auto` und soll
   gar nicht mitscrollen. */
.side { height: 100vh; overflow: visible; display: flex; flex-direction: column; background: var(--sbbg); border-right: 1px solid var(--sbline); }
.side-top { display: flex; align-items: center; padding: 16px 16px 8px; }
.side-collapse {
  margin-left: auto; padding: 4px; border: 0; border-radius: 6px;
  background: none; color: var(--sbfaint); cursor: pointer; display: flex;
}
.side-collapse:hover { color: var(--sbink); background: var(--sbhover); }
.side-collapse svg { width: 16px; height: 16px; }

/* Die Kachel aus `brand/icon.svg`, daneben der Name. Die typografische
   Fassung ("POLARIS1", das O als Stern) steht weiterhin auf der
   Anmeldeseite -- dort faehrt keine Leiste ein, aus der "PO" uebrig bliebe. */
.side-mark { display: flex; align-items: center; gap: 8px; min-width: 0; }

/* Ausgefahren die Wortmarke, eingefahren die Kachel -- und nie beides.
 *
 * Bis zum 18.09.2026 stand in der Leiste nur die typografische Fassung, und
 * sie wich, weil beim Einfahren "PO" von ihr uebrigblieb. Das Problem war
 * aber nicht die Wortmarke, sondern dass sie beschnitten wurde statt getauscht
 * zu werden. Jetzt liegen beide im DOM, und es zeigt sich genau eine:
 * `.side-label` nimmt die Wortmarke beim Einfahren weg (dieselbe Regel, die
 * auch die Menuetexte ausblendet), und die Kachel erscheint erst dann. */
.side-mark .side-tile { display: none; width: 21px; height: 21px; flex: none; }
html.p1narrow .side-mark .side-tile { display: block; }
@media (max-width: 780px) { .side-mark .side-tile { display: block; } }

/* Dieselbe Fassung wie auf der Anmeldeseite (`.auth-brand .wordmark`): das O
   traegt die Markenfarbe, der Stern bleibt Aussparung. Hier auf dunklem Grund,
   die uebrigen Buchstaben in der Schriftfarbe der Leiste. */
.side-wordmark {
  display: flex; align-items: baseline; min-width: 0;
  font-family: "Orbitron", ui-monospace, monospace; font-weight: 500;
  font-size: 16px; text-transform: none; letter-spacing: 0;
  color: var(--sbink); white-space: nowrap;
}
.side-wordmark svg {
  display: block; width: 1.28cap; height: 1cap; margin: 0 .09em;
  fill: var(--brand); flex: none;
}
.side-name-mark {
  font-size: 16px; font-weight: 500; letter-spacing: -.015em; color: var(--sbink);
  white-space: nowrap;
}
.side-nav { padding: 16px 12px; display: flex; flex-direction: column; gap: .15rem; flex: 1; min-height: 0; overflow-y: auto; }
.side-group {
  padding: 8px 8px 8px; font-family: var(--sans); font-size: 12px; font-weight: 500;
  letter-spacing: 0; text-transform: none; color: var(--faint);
}
.side-nav a {
  display: flex; align-items: center; gap: 8px; padding: 0 8px;
  height: 2.1rem; border-radius: 6px; color: var(--sbmuted); text-decoration: none;
  font-size: 13px; font-weight: 500;
}
.side-nav a:hover { background: var(--sbhover); color: var(--sbink); }
/* Der aktive Punkt ist eine Plakette, kein getoenter Streifen: auf hellem
   Grund traegt eine weisse Flaeche mit Schatten weiter als eine Tonung. */
.side-nav a[aria-current="page"] {
  background: var(--sbactive); color: var(--sbink); font-weight: 500;
  box-shadow: var(--shadow);
}
.side-nav a[aria-current="page"] svg { color: var(--acc); }
.side-nav svg { flex: none; width: 16px; height: 16px; }
/* Der Zaehler. Grau, solange nichts offen ist -- die Null gehoert hin, aber
   sie ist keine Meldung. */
.side-count {
  margin-left: auto; padding: .08rem 8px; border-radius: 999px;
  background: var(--panel2); color: var(--muted);
  font-family: var(--sans); font-size: 12px; font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.side-count.on { background: var(--brand); color: var(--onacc); }
.side-soon em { margin-left: auto; }
.side-foot { padding: 8px 12px 12px; margin-top: auto; }
.side-toggle {
  display: flex; align-items: center; gap: 8px;
  padding: 0 8px; height: 2.1rem; border-radius: 6px;
  color: var(--sbmuted); font-size: 13px; font-weight: 500;
}
.side-toggle > svg { flex: none; width: 16px; height: 16px; fill: currentColor; }
.side-toggle .mode-switch { margin-left: auto; border: 0; background: none; padding: 0; }
.side-copy { text-align: center; padding-top: 12px; font-size: 12px; color: var(--sbfaint); }
.side-user { display: flex; align-items: center; gap: 8px; }
.side-avatar {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  background: var(--plate); color: var(--onacc); display: grid; place-items: center;
  font-family: var(--sans); font-size: 12px; font-weight: 500;
}
.side-name { font-size: 14px; font-weight: 500; color: var(--sbink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.side-role { font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--sbfaint); }
/* Ein Menuepunkt, den es noch nicht gibt. Dieselbe Zeile wie ein Link, nur
   ohne Zeiger und mit dem Wort, das erklaert, warum nichts passiert. */
/* ── Kontomenü ──────────────────────────────────────────────────────────────
   Der Kreis oben rechts und was darunter aufklappt. Er hat die Kopfzeile
   uebernommen, wo vorher „New test" stand, und die Fusszeile der Seitenleiste
   abgeloest -- Konto und Abmelden liegen jetzt an einer Stelle statt an zwei. */
.acct { position: relative; }
/* Die breite Fassung unten in der Leiste. */
.acct-card {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 8px 8px; border-radius: 12px;
  border: 1px solid var(--line); background: var(--card); color: var(--ink);
  cursor: pointer; text-align: left; box-shadow: var(--shadow);
}
.acct-card:hover { border-color: var(--line2); }
.acct-card-av {
  flex: none; width: 26px; height: 26px; border-radius: 6px;
  background: var(--plate); color: var(--onacc);
  display: grid; place-items: center;
  font-family: var(--sans); font-size: 12px; font-weight: 500;
}
.acct-card-id { min-width: 0; flex: 1; }
.acct-card-name { display: block; font-size: 12px; font-weight: 500; line-height: 1.3; }
.acct-card-mail {
  display: block; font-family: var(--sans); font-size: 12px; color: var(--faint);
  line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.acct-card svg { width: 13px; height: 13px; color: var(--faint); }
/* Unten in der Leiste ist unter dem Knopf kein Platz -- das Menue geht nach oben. */
.acct-up .acct-pop { top: auto; bottom: calc(100% + .5rem); right: auto; left: 0; }
.acct-btn {
  width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--line2); background: var(--panel); color: var(--ink);
  font-size: 12px; font-weight: 500; letter-spacing: 0; cursor: pointer;
  display: grid; place-items: center; transition: border-color .2s, background .2s;
}
.acct-btn:hover { border-color: var(--brand); background: var(--acctint); }
.acct-btn[aria-expanded="true"] { border-color: var(--brand); background: var(--acctint); }

.acct-pop {
  position: absolute; top: calc(100% + .55rem); right: 0; z-index: 40;
  min-width: 15.5rem; padding: 8px;
  background: var(--card); border: 1px solid var(--line2); border-radius: 12px;
  box-shadow: 0 18px 44px -16px rgba(8, 14, 26, .3), 0 2px 8px -2px rgba(8, 14, 26, .12);
}
.acct-head {
  display: flex; gap: 12px; align-items: center;
  padding: 12px 12px; margin-bottom: 4px;
  background: var(--acctint); border-radius: 6px;
}
.acct-avatar {
  width: 32px; height: 32px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--brand); color: var(--onacc);
  font-size: 12px; font-weight: 500;
}
.acct-name { font-size: 14px; font-weight: 500; color: var(--acc2, var(--ink)); }
.acct-mail { font-size: 12px; color: var(--muted); word-break: break-all; }

/* Die Gruppen trennt eine Linie, kein Abstand -- so bleibt das Menue kompakt
   und die Trennung trotzdem sichtbar. */
.acct-group + .acct-group { border-top: 1px solid var(--line); margin-top: 4px; padding-top: 4px; }
.acct-label {
  padding: 8px 12px 4px;
  font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0;
  text-transform: none; color: var(--faint);
}
.acct-item {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 8px 12px; border: 0; border-radius: 6px;
  background: none; color: var(--ink); font: inherit; font-size: 14px;
  text-align: left; cursor: pointer;
}
.acct-item:hover { background: var(--panel2, var(--panel)); }
.acct-item:disabled { opacity: .5; cursor: default; }
.acct-item svg { width: 16px; height: 16px; flex: none; opacity: .7; }
.acct-dot {
  width: 18px; height: 18px; border-radius: 6px; flex: none;
  display: grid; place-items: center;
  background: var(--line2); color: var(--muted); font-size: 12px; font-weight: 500;
}
.acct-out { color: var(--red); }
.acct-out svg { opacity: .85; }
.acct-note {
  margin: 4px 4px .1rem; padding: 8px 8px; border-radius: 6px;
  background: var(--acctint); color: var(--ink2, var(--ink));
  font-size: 13px; line-height: 1.45;
}

.side-soon {
  display: flex; align-items: center; gap: 12px;
  padding: 0 8px; height: 2.1rem; border-radius: 6px;
  color: var(--sbfaint); font-size: 13px; cursor: default; user-select: none;
}
.side-soon svg { flex: none; opacity: .55; }
.side-soon em {
  margin-left: auto; font-style: normal;
  font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0;
  text-transform: none; opacity: .8;
}

.side-out {
  margin-top: 12px; width: 100%; padding: 8px;
  border: 1px solid var(--sbline); border-radius: 4px; background: transparent;
  color: var(--sbmuted); font-family: inherit; font-size: 13px; font-weight: 500;
  cursor: pointer;
}
.side-out:hover { border-color: var(--sbink); color: var(--sbink); }

/* `--colw` ist die Lesespalte, und sie steht hier, weil Kopfzeile und Inhalt
   sie *beide* brauchen: der Titel soll an derselben Kante beginnen wie die
   erste Karte darunter. Eine Variable weiter unten -- etwa in `.view` --
   erreicht die Kopfzeile nicht, die ist ihr Geschwister, und Variablen erben
   nach unten. Ansichten mit schmalerer Spalte setzen `.main-narrow`. */
.main { --colw: 82rem; min-width: 0; height: 100vh; overflow-y: auto; display: flex; flex-direction: column; }
.main-narrow { --colw: 72rem; }
/* Die Leiste bleibt voll breit -- ihre Trennlinie soll den Arbeitsbereich
   durchschneiden, nicht die Spalte. Begrenzt wird nur ihr Inhalt, auf dieselbe
   `--colw` wie die Karten darunter. */
.topbar {
  position: sticky; top: 0; z-index: 5;
  padding: 16px 28px;
  background: var(--bg); border-bottom: 1px solid var(--line);
}
.topbar-in {
  width: 100%; max-width: var(--colw); margin-inline: auto;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
.topbar .account { font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--faint); }
.topbar .title { margin-top: 4px; font-size: 18px; font-weight: 500; letter-spacing: -.02em; }
.topbar .right { display: flex; align-items: center; gap: 8px; flex: none; }
.btn-small {
  padding: 8px 16px; border: 0; border-radius: 6px; background: var(--plate);
  color: var(--onacc); font-family: inherit; font-size: 14px; font-weight: 500; letter-spacing: -.005em;
  cursor: pointer; line-height: 1.25;
}
.btn-small:hover:not(:disabled) { background: var(--plateh); }
.btn-small:disabled { opacity: .5; cursor: not-allowed; }
a.btn-small { text-decoration: none; display: inline-block; }
.btn-ghost { background: none; border: 1px solid var(--line2); color: var(--ink); }
.btn-ghost:hover:not(:disabled) { border-color: var(--ink); background: none; }

.view { flex: 1; padding: 24px 28px 48px; }
/* `margin-inline: auto`. Ohne sie klebte die Spalte am linken Rand, und auf
   einem breiten Bildschirm blieb die rechte Haelfte leer -- die Begrenzung war
   da, die Mitte fehlte. */
.view > * { max-width: var(--colw); margin-inline: auto; animation: p1in .35s ease both; }

/* Groesserer Radius und ein Schatten statt einer zweiten Linie -- so heben
   sich Karten auf dem hellen Grund ab, ohne ihn zu zerschneiden. */
.card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: 12px; padding: 20px 20px; box-shadow: var(--shadow);
}
/* `min-width: 0` auf den Karten, sonst sprengt ein langer Wert die Spalte.
   Gitter-Kinder stehen auf `min-width: auto`, also auf ihrer Mindestbreite --
   und die richtet sich nach dem laengsten unteilbaren Inhalt. Eine Karte mit
   einem 70 Zeichen langen Bezeichner wird damit breiter als ihre Spalte, statt
   ihn umzubrechen, und schiebt die ganze Seite nach rechts. */
.cards { display: grid; gap: 20px; }
.cards > * { min-width: 0; }
.row { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.stack { display: grid; gap: 8px; }
.mono { font-family: var(--mono); }
/* Ein Wert in Satzschrift: Hostname, Adresse, Kennung, Zeitstempel. Etwas
   schwerer als Fliesstext, Tabellenziffern, damit Zahlen untereinander
   stehen. Seit 08.09.2026 statt `.mono` -- Mono bleibt nur dort, wo man
   Zeichen fuer Zeichen abschreibt: Beweise, DNS-Eintraege, Codes. */
.val { font-family: var(--sans); font-weight: 500; font-variant-numeric: tabular-nums; }
.dim { color: var(--muted); }
.faint { color: var(--faint); }
.empty { text-align: center; padding: 48px 16px; color: var(--muted); }

/* Satzschrift statt Grossbuchstaben. „Complete" liest sich als Zustand,
   „COMPLETE" als Alarm -- und die Tabelle hat davon zwanzig untereinander. */
.pill {
  display: inline-flex; align-items: center; gap: 4px; padding: 4px 8px;
  border-radius: 999px; font-family: var(--sans); font-size: 12px; font-weight: 500;
  letter-spacing: 0;
}
.pill.ok      { background: var(--greent); color: var(--green); }
.pill.wait    { background: var(--ambert); color: var(--amber); }
.pill.bad     { background: var(--redt);   color: var(--red); }
.pill.neutral { background: var(--panel2); color: var(--muted); }

/* ── Der laufende Test ────────────────────────────────────────────────────
 * Aus `Polaris1 App v2.dc.html`, Zeile 394–436.
 */

.run-clock {
  font-family: var(--sans); font-size: 24px; font-weight: 500;
  letter-spacing: -.02em; font-variant-numeric: tabular-nums;
}
.plate-acts-clock { align-items: center; gap: 16px; }
.run-clock-box { text-align: right; }
.run-clock-box span {
  display: block; margin-top: .15rem; font-size: 12px; font-weight: 500;
  letter-spacing: 0; text-transform: none; opacity: .6;
}
/*
 * Der Stop-Knopf auf der Platte.
 *
 * Die Platte ist in beiden Modi dunkel -- deshalb stehen hier feste Werte und
 * keine Tokens: `--red` ist im Hellmodus fuer Text auf Weiss gewaehlt und
 * verschwaende auf Nachtblau.
 */
.plate .btn-stop {
  border-color: rgba(255, 93, 108, .45);
  color: #ff8d97;
}
.plate .btn-stop:hover:not(:disabled) { background: rgba(255, 93, 108, .16); }

.phases { display: grid; gap: 1px; background: var(--line); }
.phase { background: var(--card); padding: 20px 20px; }
.phase-top { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 16px; align-items: center; }
.phase-mark {
  flex: none; display: grid; place-items: center; width: 22px; height: 22px;
  border-radius: 50%; border: 1px solid var(--line2); background: var(--panel2);
  color: var(--faint); font-family: var(--sans); font-size: 12px; font-weight: 500;
}
.phase-label { display: block; font-size: 16px; font-weight: 500; letter-spacing: -.01em; }
.phase-line { display: block; margin-top: 4px; font-family: var(--sans); font-size: 13px; color: var(--faint); }
.phase-state { flex: none; font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--faint); }
.phase-bar { margin-top: 12px; height: 3px; border-radius: 2px; background: var(--panel2); overflow: hidden; position: relative; }
.phase-bar > i { display: block; height: 100%; width: 0; background: var(--acc); transition: width .4s ease; }
@keyframes p1dot { 0%,80%,100% { opacity: .2; } 30% { opacity: 1; } }
.phase-state-dots { display: inline-flex; gap: .15em; margin-left: .3em; vertical-align: middle; }
.phase-state-dots i {
  display: block; width: 3px; height: 3px; border-radius: 50%;
  background: currentColor; animation: p1dot 1.1s ease-in-out infinite;
}
.phase-state-dots i:nth-child(2) { animation-delay: .18s; }
.phase-state-dots i:nth-child(3) { animation-delay: .36s; }
.phase-metrics { margin-top: 12px; display: flex; gap: 24px; flex-wrap: wrap; }
.phase-metrics span { display: flex; align-items: baseline; gap: 8px; }
.phase-metrics b { font-size: 18px; font-weight: 500; font-variant-numeric: tabular-nums; }
.phase-metrics em {
  font-style: normal; font-family: var(--sans); font-size: 12px; font-weight: 500;
  letter-spacing: 0; text-transform: none; color: var(--faint);
}

/* Aktiv: der Ring pulsiert, der Balken ist grün. */
.phase[data-state="active"] .phase-mark { border-color: var(--accline); background: var(--acctint); color: var(--acc); animation: p1pulse 1.4s ease-in-out infinite; }
.phase[data-state="active"] .phase-state { color: var(--acc); }
.phase[data-state="done"] .phase-mark { border-color: var(--accline); background: var(--acctint); color: var(--acc); }
.phase[data-state="done"] .phase-state { color: var(--green); }
.phase[data-state="failed"] .phase-mark { border-color: var(--red); background: var(--redt); color: var(--red); }
.phase[data-state="failed"] .phase-state { color: var(--red); }
.phase[data-state="failed"] .phase-bar > i { background: var(--red); }
/* Übersprungen: sichtbar blass. Kein Balken, der Arbeit behauptet. */
.phase[data-state="skipped"] { opacity: .5; }
.phase[data-state="skipped"] .phase-bar { display: none; }
.phase[data-state="skipped"] .phase-metrics { display: none; }

.run-foot {
  display: flex; align-items: center; gap: 16px;
  flex-wrap: wrap; background: var(--panel); border: 1px solid var(--line);
  border-radius: 12px; padding: 16px 20px; box-shadow: var(--shadow);
}
.btn-stop {
  padding: 8px 16px; border: 1px solid var(--red); border-radius: 6px;
  background: transparent; color: var(--red); font-family: inherit;
  font-size: 14px; font-weight: 500; letter-spacing: -.005em;
  cursor: pointer; line-height: 1.25;
}
.btn-stop:hover:not(:disabled) { background: var(--redt); }
.btn-stop:disabled { opacity: .45; cursor: not-allowed; }

/* ── Das Ergebnis ─────────────────────────────────────────────────────────
 * Aus `Polaris1 App v2.dc.html`, Zeile 440–494 — mit einer Abweichung, die im
 * Kopf von `viewResults()` begründet ist: keine unscharfen Titel.
 */

.sev-grid {
  margin-top: 24px; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px; background: var(--line); border: 1px solid var(--line);
  border-radius: 6px; overflow: hidden;
}
.sev { padding: 16px 16px; }
.sev > span { font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0; text-transform: none; }
.sev > b {
  display: block; margin-top: 8px; font-size: 32px; font-weight: 500;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums; line-height: 1;
}
.sev.critical { background: var(--redt);   color: var(--red); }
.sev.high     { background: var(--hight);  color: var(--high); }
.sev.medium   { background: var(--ambert); color: var(--amber); }
.sev.low      { background: var(--greent); color: var(--green); }
.sev.zero     { background: var(--card);   color: var(--faint); }

.locked-head {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 12px 20px; border-bottom: 1px solid var(--line);
  font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0;
  text-transform: none; color: var(--faint);
}
.locked-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 16px;
  align-items: center; padding: 16px 20px; border-top: 1px solid var(--line);
}
/* Stand früher unter `.locked-row`. Die Fundliste und die Tafel brauchen
   dasselbe Abzeichen — zwei Definitionen mit denselben Werten laufen beim
   ersten Nachziehen auseinander, und zwar still. */
.badge {
  flex: none; padding: 4px 8px; border: 1px solid currentColor; border-radius: 2px;
  font-family: var(--sans); font-size: 12px; font-weight: 500;
  letter-spacing: 0; text-transform: none;
}
.badge.critical { color: var(--red); }
.badge.high     { color: var(--high); }
.badge.medium   { color: var(--amber); }
.badge.low      { color: var(--green); }
/* Ein Platzhalter, der ausdrücklich kein Text ist. Nichts zu entwischen. */
.locked-row .bar { height: .62rem; border-radius: 2px; background: var(--panel2); }
.locked-row svg { flex: none; width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.8; color: var(--faint); }

.unlock { border-color: var(--accline) !important; padding: 24px 24px; }
.unlock-grid { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 24px; align-items: start; }
@media (max-width: 680px) { .unlock-grid { grid-template-columns: 1fr; } }
.unlock h3 { margin: 0; font-size: 18px; font-weight: 500; letter-spacing: -.02em; }
.unlock p { margin: 8px 0 0; font-size: 16px; line-height: 1.6; color: var(--muted); }
.unlock ul { margin: 16px 0 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.unlock li { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px; align-items: baseline; font-size: 16px; line-height: 1.55; color: var(--ink2); }
.unlock li::before { content: "+"; font-family: var(--mono); font-size: 14px; color: var(--acc); }
.unlock-price { flex: none; text-align: right; min-width: 11rem; }
.unlock-price .amount { font-size: 32px; font-weight: 500; letter-spacing: -.035em; line-height: 1; }
.unlock-price .btn-plate { margin-top: 16px; padding: 12px 20px; }
.unlock-price .fine { margin-top: 12px; font-size: 13px; line-height: 1.5; color: var(--faint); }

.auth-form { display: grid; place-items: center; padding: 40px 32px; }
.auth-form > div { width: 100%; max-width: 23rem; animation: p1in .3s ease-out; }
.auth-form h1 { margin: 8px 0 0; font-size: 24px; font-weight: 500; letter-spacing: -.03em; }
.auth-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.auth-fine { margin: 24px 0 0; font-size: 13px; line-height: 1.6; color: var(--faint); }

/* ── Funde: Liste ────────────────────────────────────────────────────────── */

.find-bar { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.chips { display: flex; gap: 8px; flex-wrap: wrap; }
.chip {
  padding: 8px 12px; border: 1px solid var(--line2); border-radius: 999px;
  background: var(--card); color: var(--muted); cursor: pointer;
  font-family: inherit; font-size: 13px; font-weight: 500; line-height: 1.25;
}
.chip:hover { border-color: var(--faint); color: var(--ink2); }
.chip.on { background: var(--acctint); border-color: var(--accline); color: var(--acc2); }
.find-search {
  flex: 1 1 16rem; max-width: 22rem; padding: 8px 12px;
  border: 1px solid var(--line2); border-radius: 4px;
  background: var(--card); color: var(--ink); font: inherit; font-size: 14px;
}
.find-search:focus { outline: none; border-color: var(--accline); }

.find-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 16px;
  align-items: start; padding: 16px 20px; border-top: 1px solid var(--line);
  text-decoration: none; color: inherit;
}
.find-list > .find-row:first-child { border-top: 0; }
.find-row:hover { background: var(--panel); }
.find-title { font-size: 16px; font-weight: 500; letter-spacing: -.01em; }
.find-ctx { margin-top: 4px; font-size: 14px; line-height: 1.5; color: var(--muted); }
.find-meta { margin-top: 8px; display: flex; gap: 16px; flex-wrap: wrap; font-size: 12px; color: var(--faint); }
.find-ref { flex: none; font-size: 12px; color: var(--faint); }

/* Der Zustand ist eine Tatsache, kein Urteil — deshalb keine Ampelfarben.
   `fixed` ist die Behauptung des Kunden, `retested` der Beweis. Nur das
   Bewiesene bekommt die Akzentfarbe. */
.find-state {
  font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0; text-transform: none;
}
.find-state.open { color: var(--high); }
.find-state.fixed { color: var(--faint); }
.find-state.retested { color: var(--acc); }

/* ── Funde: die Tafel ────────────────────────────────────────────────────── */

.find-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.find-facts {
  margin-top: 20px; display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
  padding-top: 16px; border-top: 1px solid var(--line);
}
.find-facts > div { display: grid; gap: 4px; min-width: 0; }
.find-facts span {
  font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0;
  text-transform: none; color: var(--faint);
}
/* `overflow-wrap: anywhere`, nicht `word-break: break-word`.
   Beide brechen ein zu langes Wort um, aber nur `anywhere` senkt dabei die
   *Mindestbreite* des Elements -- `break-word` laesst sie bei der Laenge des
   ganzen Wortes stehen. Am 20.09.2026 stand in `kind` der verschlagwortete
   Fundtitel (70 Zeichen), und die Fakten-Zeile verlangte daraufhin 2211px in
   einer 1152px breiten Spalte. Der Umbruch war sichtbar da, die Breite blieb. */
.find-facts b { font-size: 16px; font-weight: 500; overflow-wrap: anywhere; }

.find-block + .find-block { margin-top: 20px; }
.find-block p { margin: 8px 0 0; font-size: 16px; line-height: 1.65; color: var(--ink2); }

/* Beweise werden nicht umbrochen — eine umgebrochene Anfrage ist eine andere
   Anfrage. Deshalb scrollt der Block waagrecht, statt den Inhalt zu verfälschen. */
.find-pre {
  margin: 8px 0 0; padding: 16px 16px; overflow-x: auto;
  background: var(--panel); border: 1px solid var(--line); border-radius: 6px;
  font-size: 13px; line-height: 1.6; white-space: pre; color: var(--ink2);
}
.find-steps { margin: 8px 0 0; padding-left: 20px; display: grid; gap: 8px; font-size: 16px; line-height: 1.55; color: var(--ink2); }
.find-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.find-actions .btn-plate { margin-left: auto; }
@media (max-width: 560px) { .find-actions .btn-plate { margin-left: 0; } }

/* ── Reports ─────────────────────────────────────────────────────────────── */

.report-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 16px;
  align-items: center; padding: 16px 0; border-top: 1px solid var(--line);
}
.report-row:first-of-type { border-top: 0; padding-top: 0; }
.report-name { font-size: 16px; font-weight: 500; letter-spacing: -.01em; }

/* ── Dashboard ───────────────────────────────────────────────────────────────
   Zwei Zeilen aus je zwei bis drei Feldern, nicht eine Spalte aus Karten. Der
   Bildschirm soll auf einen Blick beantworten: wie schlimm, wovon, und was
   fehlt noch. */
.dash { display: grid; gap: clamp(1rem, 2vw, 1.5rem); }

/* ── Die Platte ────────────────────────────────────────────────────────────
   Die eine Zahl, die zaehlt, und was man damit tut. Sie ist in beiden Modi
   nachtblau -- so wie das Seitenmenue es bis zum 18.09.2026 war. Die Marke
   braucht eine Flaeche, die ihr gehoert, und jetzt ist es diese. */
.plate {
  background: linear-gradient(118deg, #0c1524 0%, #16202f 100%);
  color: #fff; border-radius: 12px; padding: 20px 24px;
  display: flex; align-items: center; gap: 24px; flex-wrap: wrap;
  position: relative; overflow: hidden;
}
.plate::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(70% 140% at 88% 10%, rgba(255,255,255,.07), transparent 60%),
    radial-gradient(55% 115% at 100% 100%, rgba(92,237,163,.2), transparent 66%);
}
.plate-body { position: relative; z-index: 1; min-width: 0; flex: 1; }
.plate-k { font-size: 13px; font-weight: 500; opacity: .72; }
/* Der Puls sagt "jetzt", ohne dass ein Wort dafuer noetig waere. */
.plate-live { display: flex; align-items: center; gap: 8px; }
.plate-live i {
  width: 9px; height: 9px; border-radius: 50%; background: var(--brand);
  flex: none; animation: p1pulse 1.1s ease-in-out infinite;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 25%, transparent);
}
.plate-v { display: flex; align-items: baseline; gap: 12px; margin-top: 8px; flex-wrap: wrap; }
.plate-v b { font-size: 32px; font-weight: 500; letter-spacing: -.03em; line-height: 1; }
.plate-good { font-size: 14px; font-weight: 500; color: var(--brand); }
.plate-head {
  font-size: 24px; font-weight: 500; letter-spacing: -.028em; line-height: 1.2;
  max-width: 22ch; text-wrap: balance; margin-top: 4px;
}
.plate-note { font-size: 13px; opacity: .6; margin-top: 8px; max-width: 64ch; line-height: 1.6; }
/* Der Ergebnis-Satz ist laenger als "You don't know what's exposed yet". */
.plate-head.wide { max-width: 34ch; }
.plate .sevbar { margin-top: 16px; max-width: 34rem; }
.plate .sevbar .none { background: rgba(255,255,255,.22); }
.plate-acts { position: relative; z-index: 1; display: flex; gap: 8px; flex-wrap: wrap; }
.btn-on-plate {
  display: inline-flex; align-items: center; height: 2.2rem; padding: 0 16px;
  border-radius: 6px; cursor: pointer; text-decoration: none;
  background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.16);
  color: #fff; font-size: 13px; font-weight: 500;
}
.btn-on-plate:hover { background: rgba(255,255,255,.2); color: #fff; }
.btn-on-plate.primary {
  background: var(--plate); border-color: transparent; color: var(--onacc); font-weight: 500;
}
.btn-on-plate.primary:hover { background: var(--plateh); color: var(--onacc); }

/* ── Der Weg zum ersten Lauf ───────────────────────────────────────────── */
.step-card { display: flex; flex-direction: column; gap: 8px; }
.step-card[data-state="now"] { border-color: var(--acc); box-shadow: 0 0 0 1px var(--acc), var(--shadow); }
.step-n {
  width: 1.5rem; height: 1.5rem; border-radius: 6px; display: grid; place-items: center;
  font-size: 12px; font-weight: 500;
  background: var(--panel2); color: var(--faint); border: 1px solid var(--line);
}
.step-card[data-state="now"] .step-n { background: var(--plate); color: var(--onacc); border-color: transparent; }
.step-t { font-size: 16px; font-weight: 500; }
.step-d { font-size: 13px; color: var(--muted); line-height: 1.6; flex: 1; }
.step-card .btn-small { align-self: flex-start; }

/* ── Was offen steht ───────────────────────────────────────────────────────
   Die fette Zeile ist die Folge (`findings.impact`), nicht der Befund. Der
   technische Titel steht klein darunter -- er macht die Zeile sonst zu,
   bevor sie etwas gesagt hat. */
.dash-wide { display: grid; grid-template-columns: minmax(0, 1fr) 17rem; padding: 0; overflow: hidden; }
@media (max-width: 1080px) {
  .dash-wide { grid-template-columns: minmax(0, 1fr); }
  .dash-wide .rail { border-left: 0 !important; border-top: 1px solid var(--line); }
}
.dash-wide .card-head {
  display: flex; align-items: baseline; gap: 12px;
  padding: 16px 20px; border-bottom: 1px solid var(--line);
}
.dash-wide .card-head h2 { font-size: 16px; font-weight: 500; letter-spacing: -.01em; }
.dash-wide .card-head a { margin-left: auto; font-size: 13px; color: var(--acc); text-decoration: none; }
.dash-wide .card-head a:hover { text-decoration: underline; text-underline-offset: 3px; }

.expose { padding: 4px 0; }
.exp-row { display: flex; align-items: flex-start; gap: 12px; padding: 12px 20px; text-decoration: none; color: inherit; }
.exp-row + .exp-row { border-top: 1px solid var(--line); }
.exp-row:hover { background: var(--sunk); }
.exp-body { min-width: 0; flex: 1; }
.exp-lead { font-size: 14px; font-weight: 500; line-height: 1.4; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.exp-sub { display: block; font-size: 12px; color: var(--faint); margin-top: 4px; line-height: 1.5; }
.exp-age { flex: none; font-size: 12px; color: var(--muted); text-align: right; padding-top: .1rem; }
.exp-age b { display: block; font-weight: 500; color: var(--ink2); font-variant-numeric: tabular-nums; }
/* Der Zusatz, der eine Kritische von einer Kritischen unterscheidet: braucht
   es ein Konto, oder reicht das offene Netz? */
.noacct {
  font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0;
  text-transform: none; background: var(--redt); color: var(--red);
  padding: .1rem 8px; border-radius: 999px; white-space: nowrap;
}

.rail { border-left: 1px solid var(--line); padding: 20px; display: flex; flex-direction: column; gap: 16px; justify-content: center; }
.rail-k { font-size: 13px; color: var(--muted); line-height: 1.4; }
.rail-v { display: flex; align-items: baseline; gap: 8px; margin-top: 4px; }
.rail-v b { font-size: 24px; font-weight: 500; letter-spacing: -.03em; line-height: 1; }
.rail-v span { font-size: 12px; color: var(--faint); }
.rail-sep { height: 1px; background: var(--line); }

/* Der gute Ausgang: ein Haken, kein leerer Kasten. */
.clean { padding: 32px 24px 28px; text-align: center; }
.clean-mark {
  width: 2.9rem; height: 2.9rem; border-radius: 12px; margin: 0 auto 16px;
  display: grid; place-items: center; background: var(--greent); color: var(--green);
}
.clean-mark svg { width: 24px; height: 24px; stroke-width: 2; }
/* Verschlossen ist kein guter Ausgang -- dieselbe Form, ruhige Farbe. */
.clean-mark.locked { background: var(--panel2); color: var(--muted); }
.clean-h { font-size: 18px; font-weight: 500; letter-spacing: -.02em; }
.clean-p { font-size: 14px; color: var(--muted); line-height: 1.65; max-width: 46ch; margin: 8px auto 0; }
.clean .btn-small { margin-top: 16px; display: inline-block; }

/* Die Kacheln stehen jetzt als drei eigene Karten, nicht mehr als Zellen im
   Rahmen des Balkens -- der Balken ist in die Platte gewandert. */
.tile-card { display: flex; flex-direction: column; }
.tile-card .tile-foot {
  margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--line);
  font-size: 12px; color: var(--faint); line-height: 1.5;
}
.dash-row { display: grid; gap: clamp(1rem, 2vw, 1.5rem); grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
.dash-row.thirds { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 1080px) { .dash-row, .dash-row.thirds { grid-template-columns: minmax(0, 1fr); } }

.dash-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-bottom: 12px; }
.dash-head h2 { font-size: 16px; font-weight: 500; letter-spacing: -.01em; }
.dash-head a { font-size: 13px; color: var(--acc2, var(--brand)); text-decoration: none; }
.dash-head a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* Der Balken. Jeder Abschnitt traegt seinen Anteil als `flex-grow`, damit die
   Summe immer genau die Breite ergibt -- Prozentrechnung im Frontend waere eine
   Rundungsquelle. */
.sevbar { display: flex; gap: 4px; height: 8px; border-radius: 999px; overflow: hidden; }
.sevbar > i { display: block; border-radius: 999px; min-width: 3px; }
.sevbar .critical { background: var(--fill-critical); }
.sevbar .high     { background: var(--fill-high); }
.sevbar .medium   { background: var(--fill-medium); }
.sevbar .low      { background: var(--fill-low); }
.sevbar .none     { background: var(--line2); flex: 1; }

.sevtotal { display: flex; align-items: baseline; gap: 8px; margin-top: 16px; }
.sevtotal b { font-size: 32px; font-weight: 500; letter-spacing: -.03em; line-height: 1; }
.sevtotal span { font-size: 14px; color: var(--muted); }

.sevlegend { display: flex; gap: 16px; flex-wrap: wrap; margin-left: auto; }
.sevlegend span { display: inline-flex; align-items: center; gap: 4px; font-size: 14px; color: var(--muted); }
.sevlegend i { width: 7px; height: 7px; border-radius: 50%; display: block; }

/* Die Kacheln unter dem Balken sitzen im selben Rahmen wie er, getrennt nur
   durch Linien -- wie die Zellen einer Tabelle, nicht wie vier Karten. */
.tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin-top: 20px; border-top: 1px solid var(--line); }
@media (max-width: 720px) { .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.tile { padding: 16px 16px; border-right: 1px solid var(--line); }
.tile:last-child { border-right: 0; }
.tile-k { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); }
.tile-k i { width: 8px; height: 8px; border-radius: 3px; display: block; background: var(--line2); }
.tile-v { margin-top: 8px; display: flex; align-items: baseline; gap: 8px; }
.tile-v b { font-size: 24px; font-weight: 500; letter-spacing: -.02em; }
.tile-v span { font-size: 12px; color: var(--faint); }

/* Fundarten: ein Balken, darunter die Legende mit Zahlen rechts. */
.kindbar { display: flex; gap: 4px; height: 8px; margin-bottom: 16px; }
.kindbar > i { display: block; border-radius: 999px; min-width: 4px; }
.kindlist { display: grid; gap: .1rem; }
.kindrow { display: grid; grid-template-columns: 9px minmax(0, 1fr) auto; gap: 8px; align-items: center; padding: 8px 0; font-size: 14px; }
.kindrow i { width: 9px; height: 9px; border-radius: 50%; display: block; }
.kindrow span { color: var(--ink2, var(--ink)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kindrow b { font-weight: 500; font-variant-numeric: tabular-nums; }
.kindrow.zero span, .kindrow.zero b { color: var(--faint); }

/* Was noch fehlt. Eine Zeile je Schritt, erledigte ausgegraut. */
.ready { display: grid; gap: 0; }
.ready-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-top: 1px solid var(--line); font-size: 14px; }
.ready-row:first-child { border-top: 0; }
.ready-row .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--amber); }
.ready-row.done .dot { background: var(--green); }
.ready-row.done { color: var(--faint); }
.ready-row .act { margin-left: auto; }
.ready-row .act a, .ready-row .act span {
  font-family: inherit; font-size: 12px; font-weight: 500;
  padding: 4px 12px; border-radius: 999px; text-decoration: none;
  border: 1px solid var(--line2); color: var(--muted);
}
.ready-row.done .act span { border-color: transparent; color: var(--green); }
.ready-row .act a:hover { border-color: var(--brand); color: var(--acc2, var(--ink)); }

/* ── Funde als Tabelle ───────────────────────────────────────────────────────
   Eine Liste beantwortet „was gibt es", eine Tabelle beantwortet „wie
   vergleicht sich das". Bei Funden ist die zweite Frage die haeufigere: welcher
   ist der schlimmste, welcher liegt wo, was ist schon behoben. */
.ftools {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: 16px;
}
.fsearch {
  flex: 1 1 14rem; max-width: 20rem; padding: 8px 12px;
  border: 1px solid var(--line2); border-radius: 6px;
  background: var(--card); color: var(--ink); font: inherit; font-size: 14px;
}
.fsearch:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--acctint); }
.fcount { margin-left: auto; font-size: 13px; color: var(--faint); }

.ftable { width: 100%; border-collapse: collapse; font-size: 14px; }
.ftable thead th {
  text-align: left; padding: 8px 12px;
  border-bottom: 1px solid var(--line2);
  font-family: var(--sans); font-size: 12px; font-weight: 500;
  letter-spacing: 0; text-transform: none; color: var(--faint);
  white-space: nowrap;
}
.ftable tbody tr { border-bottom: 1px solid var(--line); }
/* Die ganze Zeile fuehrt zum Fund. Der Zeiger sagt es, der Fokusrahmen macht
   sie mit der Tastatur auffindbar -- `tabindex` allein zeigt nichts an. */
.ftable tbody tr.frow { cursor: pointer; }
.ftable tbody tr:hover { background: var(--panel); }
.ftable tbody tr.frow:focus-visible {
  outline: 2px solid var(--brand); outline-offset: -2px; background: var(--panel);
}
.ftable td { padding: 12px; vertical-align: top; }
.ftable td.shrink { width: 1%; white-space: nowrap; }

.fname { display: block; font-weight: 500; color: var(--ink); text-decoration: none; }
.fname:hover { text-decoration: underline; text-underline-offset: 3px; }
.fsub { margin-top: 4px; font-size: 13px; color: var(--muted); line-height: 1.45; }
.floc {
  font-family: var(--sans); font-weight: 500; font-size: 14px; color: var(--muted);
  overflow-wrap: anywhere; word-break: normal;
}
.fdate { font-size: 13px; color: var(--faint); white-space: nowrap; }

/* Die Stufe als Pille mit Punkt -- dieselbe Farbe wie im Balken auf dem
   Dashboard, damit ein „kritisch" ueberall gleich aussieht. */
.sevpill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 4px 8px; border-radius: 999px;
  border: 1px solid var(--line2); background: var(--card);
  font-size: 12px; font-weight: 500; text-transform: capitalize; white-space: nowrap;
}
.sevpill i { width: 6px; height: 6px; border-radius: 50%; display: block; }
.sevpill.critical { border-color: color-mix(in srgb, var(--fill-critical) 40%, transparent); color: var(--red); }
.sevpill.critical i { background: var(--fill-critical); }
.sevpill.high     { border-color: color-mix(in srgb, var(--fill-high) 45%, transparent); color: var(--high); }
.sevpill.high i   { background: var(--fill-high); }
.sevpill.medium   { border-color: color-mix(in srgb, var(--fill-medium) 50%, transparent); color: var(--amber); }
.sevpill.medium i { background: var(--fill-medium); }
.sevpill.low      { border-color: color-mix(in srgb, var(--fill-low) 40%, transparent); color: var(--green); }
.sevpill.low i    { background: var(--fill-low); }

.fstat {
  display: inline-block; padding: 4px 12px; border-radius: 999px;
  border: 1px solid var(--line2); background: var(--card);
  font-size: 12px; color: var(--muted); text-transform: capitalize; white-space: nowrap;
}
.fstat.open { border-color: var(--accline, var(--line2)); color: var(--ink2, var(--ink)); }
.fstat.fixed, .fstat.retested { color: var(--green); border-color: color-mix(in srgb, var(--fill-low) 35%, transparent); }

@media (max-width: 900px) {
  .ftable thead { display: none; }
  .ftable tbody tr { display: grid; gap: 4px; padding: 16px 4px; }
  .ftable td { padding: 0; }
  .ftable td.shrink { width: auto; }
}

/* ── Eigentumsnachweis: Schranke und Anleitung ───────────────────────────────
   `.gate` ist die Tafel, die vor dem ersten Lauf steht -- auf `#/pentest`
   als Verweis, auf `#/domains` mit der ganzen Anleitung. Derselbe Rahmen wie
   `.unlock`: die Akzentlinie markiert die eine Stelle, an der es weitergeht.
   Die Schritte sind eine nummerierte Liste mit CSS-Zaehler, damit die Zahl
   nicht im Text steht und beim Umsortieren mitwandert. */
.gate { border-color: var(--accline) !important; padding: 24px 24px; }
.gate h3 { margin: 8px 0 0; font-size: 18px; font-weight: 500; letter-spacing: -.02em; }
.gate > p { margin: 8px 0 0; font-size: 16px; line-height: 1.65; color: var(--muted); max-width: 48rem; }
.gate > p.gate-state { color: var(--ink2); }
.gate-actions { margin-top: 20px; display: flex; gap: 16px; flex-wrap: wrap; align-items: center; }
/* `.btn-plate` ist als Formularknopf volle Breite; als Link neben einem Hinweis nicht. */
.gate-actions .btn-plate { width: auto; padding-left: 20px; padding-right: 20px; }

/* Zwei Spalten, 2:1 -- Anleitung links, Formular rechts. Nicht `.dash-row`:
   die gehoert dem Dashboard, und ein zweiter Nutzer wuerde sie beim naechsten
   Umbau dort still mitziehen. */
.two { display: grid; gap: 20px; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); align-items: start; }
@media (max-width: 1080px) { .two { grid-template-columns: minmax(0, 1fr); } }

.steps { margin: 20px 0 0; padding: 0; list-style: none; counter-reset: step; }
.step {
  display: grid; grid-template-columns: 1.7rem minmax(0, 1fr); gap: 16px;
  padding: 16px 0; border-top: 1px solid var(--line); counter-increment: step;
}
.step::before {
  content: counter(step); display: grid; place-items: center;
  width: 1.7rem; height: 1.7rem; border-radius: 50%;
  border: 1px solid var(--accline); background: var(--acctint); color: var(--acc);
  font-family: var(--sans); font-size: 12px; font-weight: 500;
}
.step h4 { margin: 4px 0 0; font-size: 16px; font-weight: 500; letter-spacing: -.01em; }
.step p { margin: 8px 0 0; font-size: 14px; line-height: 1.6; color: var(--muted); }
.step code, .trouble code {
  font-family: var(--mono); font-size: .8em; padding: .1em .35em;
  background: var(--panel2); border-radius: 3px; color: var(--ink2);
}

.trouble { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--line); }
.trouble ul { margin: 12px 0 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.trouble li {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px; align-items: baseline;
  font-size: 14px; line-height: 1.55; color: var(--muted);
}
.trouble li::before { content: "–"; font-family: var(--mono); color: var(--faint); }
.trouble li b { color: var(--ink2); font-weight: 500; }

/* Der Eintrag wie im DNS-Panel: Typ, Name, Wert. Die Werte brechen um, statt
   die Karte zu sprengen -- ein Token ist 40 Zeichen, ein Hostname beliebig. */
.rec { margin-top: 12px; border: 1px solid var(--line2); border-radius: 6px; overflow: hidden; }
.rec-row {
  display: grid; grid-template-columns: 4.2rem minmax(0, 1fr) auto; gap: 12px; align-items: center;
  padding: 8px 12px; border-top: 1px solid var(--line); background: var(--card);
}
.rec-row:first-child { border-top: 0; }
.rec-k { font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--faint); }
.rec-v { font-family: var(--mono); font-size: 13px; color: var(--ink); word-break: break-all; line-height: 1.5; }
.rec-copy {
  flex: none; padding: 4px 8px; border: 1px solid var(--line2); border-radius: 999px;
  background: none; color: var(--muted); cursor: pointer;
  font-family: inherit; font-size: 12px; font-weight: 500;
}
.rec-copy:hover { border-color: var(--brand); color: var(--acc2, var(--ink)); }

/* Zugeklappt, sobald ein Ziel bestaetigt ist. */
.guide-ref > summary {
  cursor: pointer; font-size: 14px; font-weight: 500; color: var(--ink2); list-style: none;
  display: flex; align-items: center; gap: 8px;
}
.guide-ref > summary::-webkit-details-marker { display: none; }
.guide-ref > summary::before { content: "+"; font-family: var(--mono); color: var(--acc); width: 1rem; }
.guide-ref[open] > summary::before { content: "–"; }
.guide-ref[open] > summary { margin-bottom: 4px; }

/* ── Der Assistent vor dem Lauf ─────────────────────────────────────────────
   Links der Schritt, rechts die Leiste mit allen acht. Die Leiste ist eine
   Liste aus Links, keine Fortschrittsgrafik mit Klicksperre: wer zu Schritt
   sechs will, klickt Schritt sechs. Erledigt ist, was einmal mit „Continue"
   verlassen wurde -- das steht im Entwurf (`done`), nicht in der URL. */
/* Die Lesespalte ist gedeckelt, die Leiste nicht.
   Vorher nahm `.wiz-main` den ganzen Rest der Breite: auf einem grossen
   Bildschirm lief der Erklaersatz ueber hundert Zeichen, und wer eine
   Auswahl traf, sprang mit den Augen quer ueber die Seite. Der Assistent ist
   ein Formular mit Fliesstext, und der will eine Spalte, keine Flaeche. */
.wiz-head h2 { margin: 0; font-size: 24px; font-weight: 500; letter-spacing: -.025em; }
.wiz-lead { margin: 8px 0 0; font-size: 16px; line-height: 1.6; color: var(--muted); max-width: 62ch; }
.wiz-nav { display: flex; gap: 8px; justify-content: flex-end; padding-top: 4px; }

/* ── Die Einrichtung als Uebernahme ────────────────────────────────────────

   Der Assistent laeuft seit dem 20.09.2026 nicht mehr in der Huelle, sondern
   legt sich darueber: keine Seitenleiste, keine Navigation, nur die acht
   Fragen und ein X.

   Der Grund ist nicht Geschmack. Acht Fragen sind lang genug, dass jedes
   Abschweifen ein Abbruch ist -- ein Klick auf „Findings" in der Leiste, und
   der halb ausgefuellte Entwurf ist aus dem Blick. Die Leiste nimmt man weg,
   damit es den Klick nicht gibt. Was sie kostet, ist der Rueckweg, und den
   traegt das X oben rechts.

   Verloren geht dabei nichts: der Entwurf liegt im `sessionStorage`
   (`draftKey`), das X fuehrt auf die Projektliste, und wer zurueckkommt,
   findet jede Antwort wieder.

   Die Schrittleiste wandert von rechts nach oben und wird waagrecht. Rechts
   war sie eine Liste, oben ist sie ein Weg -- acht Punkte auf einer Linie,
   die sich fuellt. Dieselbe Auskunft in der Form, die zur Sache passt: man
   kommt von links nach rechts, nicht von oben nach unten. */
.tk {
  position: fixed; inset: 0; z-index: 60; background: var(--bg);
  display: grid; grid-template-rows: auto minmax(0, 1fr);
}
.tk-bar {
  display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 20px;
  padding: 12px 20px; background: var(--card); border-bottom: 1px solid var(--line);
}
.tk-brand { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* Die Kachel ist in der Leiste ausgeblendet und erscheint nur eingefahren
   (`.side-mark .side-tile`). Hier traegt die Wortmarke, also bleibt sie weg. */
.tk-brand .side-tile { display: none; }
.tk-brand .side-wordmark { display: flex; }
.tk-sep { color: var(--line2); font-size: 16px; flex: none; }
.tk-proj {
  font-size: 14px; font-weight: 500; color: var(--ink2); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tk-x {
  justify-self: end; width: 2.15rem; height: 2.15rem; flex: none; display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 6px; background: var(--card); color: var(--muted);
  cursor: pointer; padding: 0; transition: color .15s, border-color .15s;
}
.tk-x:hover { color: var(--ink); border-color: var(--line2); }
.tk-x svg { width: 1rem; height: 1rem; display: block; }

.tk-rail { display: flex; align-items: flex-start; gap: 0; min-width: 0; }
.tk-step {
  position: relative; display: grid; justify-items: center; gap: 8px;
  width: 6.4rem; min-width: 0; padding: 0 4px; text-decoration: none;
}
/* Die Verbindung gehoert dem *rechten* Punkt, nicht dem linken: so faerbt sich
   das Stueck genau dann, wenn der Schritt dahinter erreicht ist. */
.tk-step + .tk-step::before {
  content: ''; position: absolute; top: .41rem; right: 50%; left: -50%; height: 1.5px;
  background: var(--line2); border-radius: 999px;
}
.tk-step.done + .tk-step::before, .tk-step.now::before { background: var(--acc); }
.tk-dot {
  position: relative; z-index: 1; width: .85rem; height: .85rem; border-radius: 50%;
  border: 1.5px solid var(--line2); background: var(--card); display: grid; place-items: center;
}
.tk-step.done .tk-dot { border-color: var(--acc); background: var(--acc); }
.tk-step.done .tk-dot::after {
  content: ''; width: .42rem; height: .24rem; margin-top: -.06rem;
  border-left: 1.5px solid var(--onacc); border-bottom: 1.5px solid var(--onacc); transform: rotate(-45deg);
}
.tk-step.now .tk-dot { border-color: var(--acc); box-shadow: 0 0 0 3.5px var(--acctint); }
.tk-step.now .tk-dot::after { content: ''; width: .4rem; height: .4rem; border-radius: 50%; background: var(--acc); }
.tk-lab {
  font-size: 12px; line-height: 1.3; color: var(--muted); text-align: center;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tk-step.now .tk-lab { color: var(--ink); font-weight: 500; }
.tk-step.done .tk-lab { color: var(--ink2); }
.tk-step:hover .tk-lab { color: var(--ink); }

/* Schmal: erst gehen die Beschriftungen, dann der ganze Weg. Eine Leiste, die
   sich staucht, bis die Woerter uebereinanderliegen, sagt weniger als „3 von 8". */
.tk-mini { display: none; font-size: 13px; color: var(--muted); white-space: nowrap; }
.tk-mini b { color: var(--ink); font-weight: 500; }
@media (max-width: 1080px) { .tk-step { width: 2.6rem; } .tk-lab { display: none; } }
@media (max-width: 620px) { .tk-rail { display: none; } .tk-mini { display: block; } .tk-sep, .tk-proj { display: none; } }

.tk-body { overflow-y: auto; padding: 40px 24px 80px; }
.tk-col { max-width: 40rem; margin-inline: auto; display: grid; gap: 20px; animation: p1in .35s ease both; }

/* Kaesten zur Auswahl: Titel, Beschreibung, Punkt. Ein Kasten je Moeglichkeit,
   damit die Begruendung neben der Wahl steht. */
.opts { display: grid; gap: 8px; }
.opt {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 12px; align-items: start;
  width: 100%; text-align: left; padding: 8px 12px; border: 1px solid var(--line2); border-radius: 6px;
  background: var(--card); color: var(--ink); cursor: pointer; font: inherit;
}
.opt:hover { border-color: var(--faint); }
.opt.on { border-color: var(--accline); background: var(--acctint); }
.opt-dot { margin-top: 4px; width: .85rem; height: .85rem; border-radius: 50%; border: 1.5px solid var(--line2); background: var(--card); }
.opt.on .opt-dot { border-color: var(--acc); background: radial-gradient(circle, var(--acc) 42%, transparent 46%); }
.opt-title { display: block; font-weight: 500; font-size: 14px; }
.opt-desc { display: block; margin-top: .15rem; font-size: 13px; line-height: 1.45; color: var(--muted); }

.wiz-area {
  width: 100%; box-sizing: border-box; padding: 12px 12px; border: 1px solid var(--line2); border-radius: 6px;
  background: var(--card); color: var(--ink); font-family: var(--sans); font-size: 14px; line-height: 1.6; outline: none; resize: vertical;
}
.wiz-area:focus { border-color: var(--brand); box-shadow: 0 0 0 3px var(--acctint); }

/* Warum-Liste: derselbe Bau wie `.trouble`, andere Rolle. */
.why { margin: 12px 0 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.why li { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px; align-items: baseline; font-size: 14px; line-height: 1.55; color: var(--muted); }
.why li::before { content: "+"; font-family: var(--mono); color: var(--acc); }
.why li b { color: var(--ink2); font-weight: 500; }

/* Testkonten und Repositories: eine Zeile je Eintrag. */
.tu-list { display: grid; }
.tu-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 12px; align-items: center;
  padding: 12px 0; border-top: 1px solid var(--line);
}
.tu-row:first-child { border-top: 0; }
.tu-row .note { grid-column: 1 / -1; }
.tu-form { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); align-items: end; }
.tu-form > label:last-of-type, .tu-form > .row { grid-column: 1 / -1; }

/* Domains: Host links, was wir tun rechts. */
.dom-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 16px; align-items: center; padding: 8px 0; border-top: 1px solid var(--line); }
.dom-row.head { border-top: 0; padding-top: 0; font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--faint); }
.dom-row code { font-family: var(--sans); font-weight: 500; font-size: 14px; }

/* Was den Start verhindert. */
.blk-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 12px 0; border-top: 1px solid var(--line); }
.blk-row:first-child { border-top: 0; }

/* ── Dialog: neues Projekt ───────────────────────────────────────────────── */
.dlg {
  width: min(30rem, calc(100vw - 2rem)); padding: 24px 24px; border: 1px solid var(--line); border-radius: 12px;
  background: var(--card); color: var(--ink); box-shadow: 0 24px 60px rgba(0,0,0,.25);
}
.dlg::backdrop { background: rgba(6,19,33,.55); backdrop-filter: blur(2px); }
.dlg h3 { margin: 8px 0 0; font-size: 18px; font-weight: 500; letter-spacing: -.02em; }
.dlg > p { margin: 8px 0 20px; font-size: 14px; line-height: 1.6; color: var(--muted); }
.dlg .btn-plate { width: auto; padding-left: 20px; padding-right: 20px; }

/* Knoepfe, die Links sind: `a:hover` (0,1,1) schlug `.btn-small` (0,1,0) und
   faerbte den Text beim Ueberfahren hellgruen -- auf der gruenen Platte im
   Dunkelmodus unsichtbar. Aufgefallen am 03.09.2026 beim „Continue" des
   Assistenten. */
a.btn-plate:hover, a.btn-small:hover:not(.btn-ghost) { color: var(--onacc); }
a.btn-ghost:hover { color: var(--ink); }

/* ── Schieberegler fuer die Rate ─────────────────────────────────────────────
   Der Verlauf links vom Knopf ist der eingestellte Anteil (`--pct`, per
   Skript gesetzt); die Spur rechts davon bleibt grau. Kein Bibliothekswidget:
   ein `input[type=range]` mit zwei Pseudo-Elementen reicht. */
.rps-value { font-size: 24px; font-weight: 500; letter-spacing: -.03em; }
.rps-value small { margin-left: 8px; font-size: 14px; font-weight: 500; color: var(--muted); letter-spacing: 0; }
.rps {
  --pct: 0%;
  width: 100%; margin: 16px 0 8px; height: 6px; border-radius: 999px; appearance: none; -webkit-appearance: none;
  background: linear-gradient(90deg, #4fe39a 0%, #5ceda3 var(--pct), var(--panel2) var(--pct), var(--panel2) 100%);
  outline: none; cursor: pointer;
}
.rps::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 20px; height: 20px; border-radius: 50%;
  background: var(--card); border: 2px solid var(--acc); box-shadow: 0 1px 4px rgba(0,0,0,.2);
}
.rps::-moz-range-thumb { width: 18px; height: 18px; border-radius: 50%; background: var(--card); border: 2px solid var(--acc); }
.rps:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 4px var(--acctint); }
.rps-warn { color: var(--amber); }
.rps-danger { color: var(--red); }

/* Preis: zwei Faelle nebeneinander. Der freie Fall ist gruen, damit die
   Regel "nur bei hoch oder kritisch" das erste ist, was man sieht. */
.price-cases { margin-top: 16px; display: grid; gap: 12px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 720px) { .price-cases { grid-template-columns: minmax(0, 1fr); } }
.price-case { padding: 16px 16px; border-radius: 6px; border: 1px solid var(--line); background: var(--panel2); }
.price-case.free { background: var(--greent); border-color: color-mix(in srgb, var(--fill-low) 40%, transparent); }
.price-amount { font-size: 32px; font-weight: 500; letter-spacing: -.035em; line-height: 1; color: var(--ink); }
.price-case.free .price-amount { color: var(--green); }
/* Der Preis ist netto (DECISION-14). Ohne diesen Zusatz stuende auf dem
   Knopf eine andere Zahl als an der Kasse. */
.price-when { margin-top: 8px; font-size: 16px; font-weight: 500; color: var(--ink); line-height: 1.4; }
.price-what { margin-top: 4px; font-size: 14px; line-height: 1.5; color: var(--muted); }
.sev-explain { margin-top: 12px; display: grid; gap: 8px; }
.sev-explain > div { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 12px; align-items: baseline; font-size: 14px; line-height: 1.55; color: var(--muted); }
.sev-explain b { color: var(--ink2); }

/* ── Laden ohne Blitz ──────────────────────────────────────────────────────
   Die alte Ansicht bleibt stehen, bis die neue da ist (siehe `render()` im
   Dashboard). Dauert es laenger als einen Wimpernschlag, laeuft oben in
   `.main` ein Balken -- nicht sofort, sonst waere er selbst das Flackern. */
.main { position: relative; }
html.p1loading .main::before {
  content: ""; position: absolute; top: 0; left: 0; z-index: 5;
  height: 2px; width: 38%; border-radius: 999px; background: var(--plate);
  animation: p1load 1.1s ease-in-out infinite;
}
@keyframes p1load { from { transform: translateX(-110%); } to { transform: translateX(290%); } }
@media (prefers-reduced-motion: reduce) {
  html.p1loading .main::before { animation: none; width: 100%; opacity: .6; }
  .view > * { animation: none; }
}

/* Ein gesperrter Abschnitt: grau, ohne Eingabe. Die Steuerelemente sind
   zusaetzlich `disabled` -- `pointer-events: none` allein liesse die Tastatur
   durch. Der Hinweis (`.note`) bleibt lesbar, deshalb eigene Deckkraft. */
.card.is-off {
  background: color-mix(in srgb, var(--ink) 7%, var(--card)); border-style: dashed;
  pointer-events: none; user-select: none; filter: grayscale(1);
}
.card.is-off > :not(.note) { opacity: .45; }
.card.is-off > .note { color: var(--ink2); }

/* ── Zusammenfassung vor dem Start ─────────────────────────────────────────
   Kacheln statt Tabelle. Die Beschriftung ist dunkel und fett in Satzschrift
   -- das helle Mono in Grossbuchstaben (`.kicker`) ist fuer Rubriken gedacht,
   nicht fuer neun Zeilen, die man vor dem Knopf wirklich lesen soll. */
.sum-title { margin: 0; font-size: 18px; font-weight: 500; letter-spacing: -.015em; color: var(--ink); }
.sum-sub { margin: 4px 0 0; font-size: 14px; line-height: 1.5; color: var(--muted); }
.sum { margin-top: 16px; display: grid; gap: 12px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 720px) { .sum { grid-template-columns: minmax(0, 1fr); } }
.sum-item { padding: 12px 16px; border: 1px solid var(--line); border-radius: 6px; background: var(--panel2); }
.sum-item.wide { grid-column: 1 / -1; }
.sum-k { display: block; font-size: 13px; font-weight: 500; color: var(--ink); }
.sum-v { display: block; margin-top: 4px; font-size: 16px; line-height: 1.55; color: var(--ink2); word-break: break-word; }
.sum-v .mono { font-size: .92em; }

/* ── Domains als Tabelle ──────────────────────────────────────────────────── */
.dom-head { display: flex; flex-direction: column; gap: 16px; }
.dom-intro {
  margin: 0; max-width: 78ch; font-size: 14px; color: var(--muted); line-height: 1.6;
}
.dom-pills { display: flex; gap: 8px; flex-wrap: wrap; }
.dom-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* Dunkle Spaltenkoepfe in Satzschrift -- dieselbe Entscheidung wie bei der
   Zusammenfassung: was man wirklich liest, ist nicht hellgrau. */
.dom-table thead th { font-family: inherit; font-size: 13px; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--ink); padding: 12px 16px; }
.dom-table td { padding: 12px 16px; }
.dom-table tbody tr.frow { cursor: default; }
.dom-table tbody tr.frow:hover { background: transparent; }
.dom-table tbody tr.frow-detail td { padding: 0 16px 16px; background: var(--panel); }
.dom-verify { padding: 16px 16px; border: 1px solid var(--line); border-radius: 6px; background: var(--card); max-width: 48rem; }

/* Offene Funde je Domain: vier Zaehler, farbig ab eins. */
.iss { display: inline-flex; gap: 4px; }
.iss span {
  min-width: 1.7rem; padding: .18rem 8px; border: 1px solid var(--line2); border-radius: 6px;
  text-align: center; font-size: 12px; font-variant-numeric: tabular-nums; color: var(--faint);
}
.iss span.n { color: var(--ink); font-weight: 500; }
.iss span.n.critical { color: var(--red);   border-color: color-mix(in srgb, var(--fill-critical) 45%, transparent); background: var(--redt); }
.iss span.n.high     { color: var(--high);  border-color: color-mix(in srgb, var(--fill-high) 45%, transparent);     background: var(--hight); }
.iss span.n.medium   { color: var(--amber); border-color: color-mix(in srgb, var(--fill-medium) 50%, transparent);   background: var(--ambert); }
.iss span.n.low      { color: var(--green); border-color: color-mix(in srgb, var(--fill-low) 40%, transparent);      background: var(--greent); }

@media (max-width: 900px) {
  .dom-table tbody tr.frow-detail td { padding: 0 4px 16px; background: transparent; }
}

/* ── Der laufende Test in der Seitenleiste ─────────────────────────────────── */
.side-live {
  display: flex; align-items: center; gap: 12px; margin: .1rem 0 4px 8px; padding: 8px 12px;
  border-radius: 6px; border: 0; background: none;
  color: var(--sbmuted); text-decoration: none; font-size: 12px;
}
.side-live:hover { background: var(--sbhover); color: var(--sbink); }
.side-live[aria-current="page"] { background: var(--sbactive); }
.side-live-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--brand); animation: p1pulse 1.1s ease-in-out infinite; }
.side-live-title { display: block; font-weight: 500; }
.side-live-app { display: block; font-family: var(--sans); font-size: 12px; color: var(--sbmuted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 780px) { .side-live { margin-left: 0; justify-content: center; padding: 8px; } }

/* ── Das Protokoll eines Laufs ──────────────────────────────────────────────
   Eine Zeile je gemeldetem Ereignis, neueste unten, rollt mit. Farbe nur
   dort, wo sie etwas sagt: fertig gruen, gescheitert rot, uebersprungen grau. */
.runlog-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding: 12px 16px; border-bottom: 1px solid var(--line); }
.runlog { max-height: 18rem; overflow-y: auto; padding: 8px 0; font-size: 14px; }
.runlog-row { display: grid; grid-template-columns: 5rem 12rem minmax(0, 1fr); gap: 12px; padding: 4px 16px; align-items: baseline; }
.runlog-row:hover { background: var(--panel); }
.runlog-time { font-size: 12px; color: var(--faint); font-variant-numeric: tabular-nums; }
.runlog-phase { color: var(--ink2); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.runlog-text { color: var(--muted); min-width: 0; overflow-wrap: anywhere; }
.runlog-row.done .runlog-text { color: var(--green); }
.runlog-row.failed .runlog-text { color: var(--red); }
.runlog-row.skipped .runlog-text { color: var(--faint); }
.runlog-row.active .runlog-phase { color: var(--acc2, var(--acc)); }
@media (max-width: 700px) { .runlog-row { grid-template-columns: 4.2rem minmax(0, 1fr); } .runlog-row .runlog-text { grid-column: 2; } }

/* ── Wo die Domain liegt ───────────────────────────────────────────────────── */
.host-note { display: grid; gap: 8px; }
.host-line { font-size: 14px; line-height: 1.55; color: var(--ink2); }
.host-line b { font-weight: 500; color: var(--ink); }
.host-line code { font-family: var(--sans); font-weight: 500; font-size: .95em; padding: .05em .3em; background: var(--panel2); border-radius: 3px; }
.host-line.warn { padding: 8px 12px; border-radius: 6px; background: var(--ambert); color: var(--ink2); }
.host-line.warn b { color: var(--amber); }

/* ── Erreichbarkeit ────────────────────────────────────────────────────────── */
.probe { font-size: 14px; line-height: 1.6; color: var(--ink2); padding: 12px 12px; border-radius: 6px; }
.probe b { font-weight: 500; }
.probe.ok { background: var(--greent); }
.probe.ok b { color: var(--green); }
.probe.warn { background: var(--ambert); }
.probe.warn b { color: var(--amber); }
.probe.dim { background: var(--panel2); color: var(--muted); }
