/* ============================================================
   Galaxyweb DNS-Manager — Auth & Error Pages
   ============================================================ */

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

:root {
  --gw:        #0098ef;
  --gw-dark:   #0077cc;
  --gw-deeper: #005fa3;
  --gw-light:  #e8f4fd;
  --gw-mid:    #bfdbfe;
  --bg:        #eef2f7;
  --surface:   #ffffff;
  --border:    #e4e9f0;
  --border-2:  #cdd5e0;
  --text-1:    #0d1b2a;
  --text-2:    #2d3e50;
  --text-3:    #5a6a7a;
  --text-4:    #8fa0b3;
  --ok:        #16a34a;
  --ok-bg:     #f0fdf4;
  --ok-bd:     #bbf7d0;
  --warn:      #d97706;
  --warn-bg:   #fffbeb;
  --warn-bd:   #fde68a;
  --warn-text: #92400e;
  --err:       #dc2626;
  --err-dark:  #991b1b;
  --err-bg:    #fff5f5;
  --err-bd:    #fecaca;
  --radius-sm: 6px;
  --radius:    10px;
  --radius-lg: 16px;
  --radius-xl: 20px;
  --shadow-sm: 0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04);
  --shadow:    0 4px 16px rgba(0,0,0,.07), 0 1px 4px rgba(0,0,0,.04);
  --shadow-lg: 0 12px 40px rgba(0,0,0,.10), 0 2px 8px rgba(0,0,0,.05);
  --font:      system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-mono: "SF Mono", "Fira Code", Consolas, "Liberation Mono", monospace;
}

/* Dark-Mode-Tokens für Auth-Seiten — auth.css definiert eigene `:root`-Variablen,
   weshalb die main.css-Dark-Mode-Werte hier ohne explizite Override-Regel
   überschrieben würden. Wir spiegeln das Dark-Schema 1:1. */
[data-theme="dark"] {
  --gw-light:  #0c2538;
  --gw-mid:    #1e40af;
  --bg:        #0f172a;
  --surface:   #1e293b;
  --border:    #2d3e50;
  --border-2:  #475569;
  --text-1:    #f1f5f9;
  --text-2:    #cbd5e1;
  --text-3:    #94a3b8;
  --text-4:    #64748b;
  --ok-bg:     #052e16;
  --ok-bd:     #14532d;
  --warn-bg:   #422006;
  --warn-bd:   #78350f;
  --warn-text: #fcd34d;
  --err-bg:    #450a0a;
  --err-bd:    #7f1d1d;
  --shadow-sm: 0 1px 3px rgba(0,0,0,.4), 0 1px 2px rgba(0,0,0,.3);
  --shadow:    0 4px 16px rgba(0,0,0,.4), 0 1px 4px rgba(0,0,0,.3);
  --shadow-lg: 0 12px 40px rgba(0,0,0,.5), 0 2px 8px rgba(0,0,0,.3);
  color-scheme: dark;
}
[data-theme="dark"] body { color: var(--text-1); background: var(--bg); }

body {
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-1);
  background: var(--bg);
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

/* ── Wrappers ───────────────────────────────────────────────── */
.auth-wrap    { width: 100%; max-width: 400px; }
.auth-wrap-lg { width: 100%; max-width: 460px; }
.auth-wrap-xl { width: 100%; max-width: 520px; }

/* ── Logo ───────────────────────────────────────────────────── */
.auth-logo { text-align: center; margin-bottom: 28px; }

.auth-logo-icon {
  width: 52px; height: 52px;
  margin: 0 auto 14px; display: block;
  filter: drop-shadow(0 4px 12px rgba(0,152,239,.30));
}

.auth-logo-name {
  font-size: 21px; font-weight: 700;
  color: var(--text-1); letter-spacing: -.4px;
}
.auth-logo-name span { color: var(--gw); }

.auth-logo-sub {
  font-size: 10.5px; font-weight: 600;
  letter-spacing: 1.8px; text-transform: uppercase;
  color: var(--text-4); margin-top: 4px;
}

/* ── Card ───────────────────────────────────────────────────── */
.auth-card {
  position: relative;
  overflow: hidden;
  background: var(--surface);
  border-radius: var(--radius-xl);
  border: 1px solid var(--border);
  padding: 32px;
  box-shadow: var(--shadow-lg);
}
/* Feine Akzentkante an der Oberkante — dieselbe Marke wie auf der MFA-Zwischenseite
   des Proxys: gibt der Karte eine Linie, ohne eine weitere
   Flaeche einzufaerben. Gilt fuer alle Anmeldeseiten (Login, Passwort, MFA, …). */
.auth-card::before {
  content: '';
  position: absolute; left: 0; right: 0; top: 0; height: 3px;
  background: linear-gradient(90deg, transparent,
    color-mix(in srgb, var(--gw) 85%, transparent), transparent);
}

.auth-title {
  font-size: 18px; font-weight: 700;
  color: var(--text-1); margin-bottom: 6px;
  letter-spacing: -.2px;
}
.auth-sub {
  font-size: 13.5px; color: var(--text-3);
  margin-bottom: 22px; line-height: 1.65;
}

/* ── Divider ────────────────────────────────────────────────── */
.auth-divider {
  display: flex; align-items: center; gap: 12px;
  margin: 18px 0; color: var(--text-4); font-size: 12px;
}
.auth-divider::before,
.auth-divider::after { content: ''; flex: 1; height: 1px; background: var(--border); }

/* ── Form ───────────────────────────────────────────────────── */
.form-group { margin-bottom: 16px; }

.form-label {
  display: block; font-size: 12px; font-weight: 600;
  color: var(--text-2);
  text-transform: uppercase; letter-spacing: .5px;
  margin-bottom: 6px;
}

.form-input {
  width: 100%; height: 44px;
  border: 1.5px solid var(--border-2);
  border-radius: var(--radius);
  padding: 0 14px;
  font-size: 14px; color: var(--text-1);
  background: var(--surface);
  font-family: var(--font);
  outline: none;
  transition: border-color .15s, box-shadow .15s;
  appearance: none;
}
.form-input::placeholder { color: var(--text-4); }
.form-input:hover  { border-color: #a0b0c4; }
.form-input:focus  {
  border-color: var(--gw);
  box-shadow: 0 0 0 3px rgba(0,152,239,.12);
}
.form-input.is-error { border-color: var(--err); }
.form-input.is-error:focus { box-shadow: 0 0 0 3px rgba(220,38,38,.10); }

.form-input-wrap { position: relative; }
.form-input-icon-left {
  position: absolute; left: 13px; top: 50%;
  transform: translateY(-50%);
  color: var(--text-4); display: flex; align-items: center;
  pointer-events: none;
}
.form-input-wrap.has-left-icon .form-input { padding-left: 40px; }

.form-input-wrap .form-input { padding-right: 42px; }
.form-input-icon {
  position: absolute; right: 12px; top: 50%;
  transform: translateY(-50%);
  background: none; border: none; cursor: pointer;
  color: var(--text-4); display: flex; align-items: center;
  padding: 0; transition: color .15s;
}
.form-input-icon:hover { color: var(--text-2); }

/* ── Buttons ────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 8px; height: 44px; padding: 0 22px;
  border-radius: var(--radius); border: none;
  font-size: 14px; font-weight: 600;
  font-family: var(--font); cursor: pointer;
  text-decoration: none; letter-spacing: .1px;
  transition: all .15s;
  white-space: nowrap; user-select: none;
}
.btn:disabled { opacity: .45; cursor: not-allowed; pointer-events: none; }
.btn-full { width: 100%; }

.btn-primary {
  background: var(--gw); color: #fff;
  box-shadow: 0 2px 8px rgba(0,152,239,.28);
}
.btn-primary:hover {
  background: var(--gw-dark);
  box-shadow: 0 4px 14px rgba(0,152,239,.38);
}

.btn-secondary {
  background: var(--surface); color: var(--text-2);
  border: 1.5px solid var(--border-2);
}
.btn-secondary:hover {
  border-color: var(--gw); color: var(--gw);
  background: var(--gw-light);
}

.btn-row { display: flex; gap: 10px; }

/* ── Alerts ─────────────────────────────────────────────────── */
.alert {
  display: flex; align-items: flex-start; gap: 10px;
  border-radius: var(--radius); padding: 12px 14px;
  font-size: 13.5px; line-height: 1.5;
  margin-bottom: 18px; border: 1px solid;
}
.alert-icon {
  flex-shrink: 0; width: 20px; height: 20px;
  display: flex; align-items: center; justify-content: center;
  margin-top: 1px;
}
.alert-icon svg { width: 20px; height: 20px; }
.alert-body { flex: 1; }
.alert-title { font-weight: 600; margin-bottom: 1px; }

.alert-error {
  background: var(--err-bg);
  border-color: var(--err-bd);
  color: var(--err-dark);
}
.alert-error .alert-icon { color: var(--err); }

.alert-success {
  background: var(--ok-bg);
  border-color: var(--ok-bd);
  color: #14532d;
}
.alert-success .alert-icon { color: var(--ok); }

.alert-warning {
  background: var(--warn-bg);
  border-color: var(--warn-bd);
  color: #78350f;
}
.alert-warning .alert-icon { color: var(--warn); }

.alert-info {
  background: var(--gw-light);
  border-color: var(--gw-mid);
  color: #1e3a5f;
}
.alert-info .alert-icon { color: var(--gw); }
.alert-info .alert-icon svg { stroke: #fff; }

/* ── Footer links ───────────────────────────────────────────── */
.auth-footer {
  display: flex; justify-content: space-between;
  margin-top: 18px; font-size: 12.5px;
}
.auth-footer a,
.auth-back {
  color: var(--text-3); text-decoration: none;
  transition: color .15s;
}
.auth-footer a:hover,
.auth-back:hover { color: var(--gw); }

.auth-back {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12.5px; margin-top: 16px;
}

/* ── Password strength ──────────────────────────────────────── */
.pw-bar {
  height: 3px; border-radius: 2px;
  background: var(--border); margin-top: 7px; overflow: hidden;
}
.pw-fill { height: 100%; border-radius: 2px; transition: width .25s, background .25s; width: 0; }
.pw-hint { font-size: 11.5px; color: var(--text-4); margin-top: 5px; }

/* ── MFA digits ─────────────────────────────────────────────── */
.mfa-code-row { display: flex; justify-content: center; gap: 8px; margin: 20px 0; }

.mfa-digit {
  width: 48px; height: 58px;
  border: 2px solid var(--border-2);
  border-radius: var(--radius); text-align: center;
  font-size: 24px; font-weight: 700;
  color: var(--text-1); font-family: var(--font-mono);
  background: var(--surface); outline: none;
  transition: border-color .15s, box-shadow .15s;
  caret-color: var(--gw);
}
.mfa-digit:focus {
  border-color: var(--gw);
  box-shadow: 0 0 0 3px rgba(0,152,239,.12);
}
.mfa-digit.filled {
  border-color: var(--gw);
  background: var(--gw-light);
  color: var(--gw-deeper);
}

/* ── QR / Secret ────────────────────────────────────────────── */
.qr-box {
  background: #f8fafb; border: 1px solid var(--border);
  border-radius: var(--radius); padding: 20px;
  text-align: center; margin-bottom: 14px;
}
.qr-box img {
  width: 164px; height: 164px; border-radius: 6px;
  box-shadow: var(--shadow-sm);
}

.secret-box {
  background: #f8fafb; border: 1px solid var(--border);
  border-radius: var(--radius); padding: 12px 14px;
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 14px;
}
.secret-label {
  font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .7px;
  color: var(--text-4); margin-bottom: 4px;
}
.secret-val {
  font-family: var(--font-mono); font-size: 14px;
  font-weight: 700; color: var(--gw); letter-spacing: 2px;
}
.secret-copy {
  height: 32px; padding: 0 12px;
  border: 1.5px solid var(--border-2);
  border-radius: var(--radius-sm);
  background: var(--surface); font-size: 12px;
  color: var(--text-3); cursor: pointer;
  font-family: var(--font); white-space: nowrap; flex-shrink: 0;
  transition: all .15s;
}
.secret-copy:hover { border-color: var(--gw); color: var(--gw); }
.secret-copy.copied { border-color: var(--ok); color: var(--ok); }

/* ── Recovery codes ─────────────────────────────────────────── */
.rc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-bottom: 16px; }
.rc-item {
  background: #f8fafb; border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 7px 10px;
  font-family: var(--font-mono); font-size: 12.5px;
  color: var(--text-1); text-align: center; letter-spacing: .5px;
}

/* ── Error pages ────────────────────────────────────────────── */
.error-wrap { text-align: center; }
.error-icon {
  width: 56px; height: 56px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto 16px;
}
.error-code {
  font-size: 64px; font-weight: 800; line-height: 1;
  color: var(--border); margin-bottom: 10px; letter-spacing: -3px;
}
.error-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: nowrap; margin-top: 22px; }
/* Beide Buttons gleich breit nebeneinander (statt Umbruch, wenn die Labels die
   schmale Auth-Karte sprengen). min-width:0 erlaubt das Schrumpfen. */
.error-actions .btn { flex: 1 1 0; min-width: 0; padding: 0 14px; }
/* Icon nie mitschrumpfen: bei min-width:0 staucht der Flexbox sonst das SVG des
   laengeren Buttons („Erneut versuchen") auf Mikro-Groesse. */
.error-actions .btn svg { flex: 0 0 auto; }
/* Kein Glow auf der Fehlerseite — der Blau-Schatten des Primary-Buttons wirkt neben
   dem flachen Secondary uneinheitlich. Beide flach: gefuellt (primary) + Outline (secondary). */
.error-actions .btn-primary,
.error-actions .btn-primary:hover { box-shadow: none; }

/* ── Debug ──────────────────────────────────────────────────── */
.debug-box {
  margin-top: 20px; text-align: left;
  background: #0d1b2a; color: #94a3b8;
  border-radius: var(--radius); padding: 16px;
  font-family: var(--font-mono); font-size: 11.5px;
  overflow: auto; white-space: pre-wrap; max-height: 260px;
  border: 1px solid #1e3a5f;
}

/* ── MFA shake animation (wrong code) ────────────────────────────────── */
@keyframes mfa-shake {
  0%, 100% { transform: translateX(0); }
  15%       { transform: translateX(-6px); }
  30%       { transform: translateX(6px); }
  45%       { transform: translateX(-5px); }
  60%       { transform: translateX(5px); }
  75%       { transform: translateX(-3px); }
  90%       { transform: translateX(3px); }
}
.mfa-shake { animation: mfa-shake .45s ease-out; }
.mfa-shake .mfa-digit { border-color: #fca5a5 !important; background: #fff5f5; }

/* ── Passwort-Stärke-Indikator (auch auf Auth-Seiten) ───────────────── */
.pw-strength { margin-top: 8px; }
.pw-strength-bar {
  height: 4px; border-radius: 2px; overflow: hidden;
  display: flex; gap: 2px;
}
.pw-strength-seg { flex: 1; background: #e2e8f0; border-radius: 2px; transition: background .15s; }
.pw-strength-bar.is-1 .pw-strength-seg:nth-child(-n+1),
.pw-strength-bar.is-2 .pw-strength-seg:nth-child(-n+2),
.pw-strength-bar.is-3 .pw-strength-seg:nth-child(-n+3),
.pw-strength-bar.is-4 .pw-strength-seg:nth-child(-n+4) { background: var(--strength-color, var(--gw, #0098ef)); }
.pw-strength-bar.is-1 { --strength-color: #ef4444; }
.pw-strength-bar.is-2 { --strength-color: #f59e0b; }
.pw-strength-bar.is-3 { --strength-color: #0098ef; }
.pw-strength-bar.is-4 { --strength-color: #16a34a; }
.pw-strength-label {
  margin-top: 6px; font-size: 11.5px; color: #64748b;
  display: flex; justify-content: space-between; gap: 8px;
}
.pw-strength-label .pw-strength-text { font-weight: 600; }
.pw-strength-label.is-1 .pw-strength-text { color: #ef4444; }
.pw-strength-label.is-2 .pw-strength-text { color: #d97706; }
.pw-strength-label.is-3 .pw-strength-text { color: #0098ef; }
.pw-strength-label.is-4 .pw-strength-text { color: #16a34a; }
.pw-rules { margin-top: 8px; display: flex; flex-direction: column; gap: 3px; }
.pw-rule { display: flex; align-items: center; gap: 7px; font-size: 11.5px; color: #94a3b8; transition: color .12s; }
.pw-rule.is-met { color: #16a34a; }
.pw-rule-icon {
  width: 14px; height: 14px; border-radius: 50%;
  background: #f1f5f9; border: 1px solid #cbd5e1;
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  transition: background .12s, border-color .12s;
}
.pw-rule.is-met .pw-rule-icon {
  background: #16a34a; border-color: #16a34a;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>");
  background-size: 9px 9px; background-position: center; background-repeat: no-repeat;
}

/* ============================================================
   Dark-Mode Sweep für Auth-Pages
   ============================================================ */
[data-theme="dark"] .auth-card,
[data-theme="dark"] .secret-box,
[data-theme="dark"] .qr-box                    { background: var(--surface) !important; border-color: var(--border) !important; }
[data-theme="dark"] .secret-val                { background: var(--bg) !important; color: var(--text-1) !important; }
[data-theme="dark"] .secret-copy               { background: var(--bg) !important; color: var(--text-2) !important; border-color: var(--border-2) !important; }
[data-theme="dark"] .secret-copy:hover         { background: var(--gw-light) !important; color: var(--gw) !important; }
[data-theme="dark"] .mfa-digit                 { background: var(--bg) !important; color: var(--text-1) !important; border-color: var(--border-2) !important; }
[data-theme="dark"] .mfa-shake .mfa-digit      { background: rgba(220,38,38,.10) !important; border-color: var(--err) !important; }
[data-theme="dark"] .mfa-app-chips .mfa-chip   { background: var(--gw-light) !important; color: var(--gw) !important; border-color: var(--border) !important; }
[data-theme="dark"] .pw-strength-seg           { background: var(--border) !important; }
[data-theme="dark"] .pw-strength-label         { color: var(--text-3) !important; }
[data-theme="dark"] .pw-strength-label.is-1 .pw-strength-text { color: var(--err-text) !important; }
[data-theme="dark"] .pw-strength-label.is-2 .pw-strength-text { color: var(--warn-text) !important; }
[data-theme="dark"] .pw-strength-label.is-4 .pw-strength-text { color: var(--ok-text) !important; }
[data-theme="dark"] .pw-rule                   { color: var(--text-3) !important; }
[data-theme="dark"] .pw-rule.is-met            { color: var(--ok-text) !important; }
/* Nur die noch nicht erfüllten Bullets dunkel einfärben — sonst löscht das
   `background`-Shorthand (!important) bei erfüllten Regeln die grüne Füllung +
   den Haken (Bug: im Dark-Mode blieben erfüllte Punkte leer). Erfüllte behalten
   die grüne is-met-Füllung aus dem Light-Block (auf Dunkel gut lesbar). */
[data-theme="dark"] .pw-rule:not(.is-met) .pw-rule-icon { background: var(--bg) !important; border-color: var(--border-2) !important; }
[data-theme="dark"] .auth-logo-name            { color: var(--text-1) !important; }
[data-theme="dark"] .auth-logo-sub             { color: var(--text-3) !important; }
[data-theme="dark"] .auth-title                { color: var(--text-1) !important; }
[data-theme="dark"] .auth-link                 { color: var(--gw) !important; }
[data-theme="dark"] .form-label                { color: var(--text-2) !important; }
[data-theme="dark"] .form-input,
[data-theme="dark"] .inp                       { background: var(--bg) !important; color: var(--text-1) !important; border-color: var(--border-2) !important; }
[data-theme="dark"] .form-input::placeholder,
[data-theme="dark"] .inp::placeholder          { color: var(--text-4); }
[data-theme="dark"] .auth-meta,
[data-theme="dark"] .auth-foot                 { color: var(--text-3) !important; }

/* ── MFA-Methodenwahl im Onboarding-Wizard (TOTP ↔ Sicherheitsschlüssel) ───── */
.mfa-choice            { display:grid; grid-template-columns:1fr 1fr; gap:12px; margin:16px 0 18px; }
@media (max-width:560px){ .mfa-choice { grid-template-columns:1fr; } }
.mfa-method            { font:inherit; color:inherit; appearance:none; -webkit-appearance:none;
                         display:flex; align-items:center; gap:13px; text-align:left; width:100%;
                         padding:15px 16px; border:1.5px solid var(--border); border-radius:14px;
                         background:var(--surface); cursor:pointer; position:relative;
                         transition:border-color .15s, box-shadow .15s, transform .12s, background .15s; }
.mfa-method:hover      { border-color:var(--gw);
                         box-shadow:0 6px 18px color-mix(in srgb, var(--gw) 22%, transparent); }
.mfa-method:focus-visible { outline:none; border-color:var(--gw);
                         box-shadow:0 0 0 3px color-mix(in srgb, var(--gw) 26%, transparent); }
.mfa-method.is-active  { border-color:var(--gw);
                         box-shadow:0 0 0 3px color-mix(in srgb, var(--gw) 22%, transparent);
                         background:color-mix(in srgb, var(--gw) 7%, var(--surface)); }
.mfa-method__ic        { width:42px; height:42px; flex:0 0 42px; border-radius:11px; display:flex;
                         align-items:center; justify-content:center;
                         background:color-mix(in srgb, var(--gw) 13%, var(--surface));
                         color:var(--gw); transition:.15s; }
.mfa-method.is-active .mfa-method__ic { background:linear-gradient(135deg, var(--gw), var(--gw-deeper)); color:#fff; }
.mfa-method__ic svg    { width:21px; height:21px; }
.mfa-method__txt       { display:flex; flex-direction:column; gap:2px; min-width:0; }
.mfa-method__txt strong{ font-size:13.5px; font-weight:650; color:var(--text-1); letter-spacing:-.1px; }
.mfa-method__txt span  { font-size:11.5px; color:var(--text-3); line-height:1.42; }
.mfa-method__check     { margin-left:auto; flex:0 0 auto; width:20px; height:20px; border-radius:50%;
                         border:2px solid var(--border); display:flex; align-items:center;
                         justify-content:center; color:#fff; transition:.15s; }
.mfa-method__check svg { width:12px; height:12px; opacity:0; transition:opacity .15s; }
.mfa-method.is-active .mfa-method__check     { background:var(--gw); border-color:var(--gw); }
.mfa-method.is-active .mfa-method__check svg { opacity:1; }
.mfa-panel[hidden]     { display:none; }
/* WebAuthn-Panel: ruhige Hero-Fläche mit grossem Trigger */
.mfa-wa-hero           { display:flex; flex-direction:column; align-items:center; text-align:center;
                         gap:12px; padding:22px 18px; border:1px dashed var(--border); border-radius:14px;
                         background:color-mix(in srgb, var(--gw) 5%, var(--surface)); margin-top:4px; }
.mfa-wa-hero__ic       { width:56px; height:56px; border-radius:16px; display:flex; align-items:center;
                         justify-content:center; background:linear-gradient(135deg, var(--gw), var(--gw-deeper));
                         color:#fff; box-shadow:0 8px 22px color-mix(in srgb, var(--gw) 36%, transparent); }
.mfa-wa-hero__ic svg   { width:28px; height:28px; }

/* ── Sprachwaehler-Bar (Login/Auth, unten) v4.67.415 ────────────────────────
   Flagge + Sprachname als dezente Pillen, aktive Sprache hervorgehoben. Reine
   Links (?ui_lang=xx), funktioniert vor dem Login. Dark-Mode via Tokens.
   Bewusst keine Trennlinie + grosszuegiger Abstand zur Login-Card (frei stehend). */
.auth-langbar {
  display: flex; flex-wrap: wrap; gap: 5px;
  justify-content: center; align-items: center;
  margin: 40px auto 0; max-width: 360px;
}
.auth-langbar__opt {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 11px; border-radius: 999px;
  font-size: 12.5px; font-weight: 500; line-height: 1;
  color: var(--text-3); text-decoration: none;
  background: transparent;
  transition: background .15s, color .15s, opacity .15s;
}
.auth-langbar__opt:hover { background: var(--surface-2, rgba(127,127,127,.10)); color: var(--text-1); }
.auth-langbar__opt.is-active {
  color: var(--text-1); font-weight: 600;
  background: var(--gw-soft, rgba(0,152,239,.12));
}
.auth-langbar__flag {
  border-radius: 3px; box-shadow: 0 0 0 1px rgba(0,0,0,.12);
  flex-shrink: 0;
}
.auth-langbar__opt:not(.is-active) .auth-langbar__flag { opacity: .6; }
.auth-langbar__opt:hover .auth-langbar__flag { opacity: 1; }
[data-theme="dark"] .auth-langbar__opt:hover { background: rgba(255,255,255,.06); }

/* ── Die Buehne der Anmeldung ───────────────────────────────────
   Anmeldung und MFA-Abfrage setzen $authAside; die Flaeche steht dann randlos
   rechts ueber die ganze Bildschirmhoehe. Das Formular bleibt in der Mitte des
   linken Teils.
   Alles hier greift erst ab 1080 px — darunter bleibt die Seite die einspaltige
   Karte, die sie vorher war.

   Was hier nicht mehr steht, und warum
   Bis v7.2.573 lag hier «Der Rand» (Lichthorizont, leuchtende Linie, Raster mit
   Maske, Leucht-Striche), danach kurz ein «Punktfeld» (v7.2.574). Beide wurden
   verworfen: ein abstrakter Umgebungseffekt (Leuchtlinien, Raster, wandernde
   Streifen, Partikel, Verlaeufe) wirkt wie alte Science-Fiction und sagt nichts.
   Die Flaeche soll Sicherheit, DNS und Analytics zeigen, also Substanz statt
   Stimmung. Darum keinen weiteren Umgebungseffekt bauen.

   Aufbau: eine flache Markenfarbe, ein grosses Punktraster als Motiv, wenig
   linksbuendiger Text. Kein Verlauf, kein Schein, keine Partikel.

   Zwei Regeln, die bleiben:
     · So langsam bewegen, dass man der Bewegung nicht folgen kann.
     · Wenige Lagen. Gestapelte Effekte lesen sich als Unruhe, nicht als Tiefe. */
.auth-split {
  display: flex; align-items: center; justify-content: center;
  gap: clamp(28px, 5vw, 72px);
  width: 100%; max-width: 1240px; margin: 0 auto;
}
.auth-split > .auth-wrap { flex: 0 0 auto; }
.auth-aside { display: none; }

@media (min-width: 1080px) {
  /* Der Rahmen der Seite gibt Polsterung und Mitte auf. Beides haengt an
     `body.auth-has-aside`, damit die uebrigen Anmeldeseiten unberuehrt bleiben. */
  body.auth-has-aside { padding: 0; align-items: stretch; }
  body.auth-has-aside .auth-split {
    max-width: none; gap: 0; min-height: 100vh; align-items: stretch;
  }

  /* Die linke Spalte nimmt den Rest und zentriert ihren Inhalt darin. Ihre Kinder
     behalten ihre Breite — sonst zoege sich die Anmeldekarte ueber die halbe Spalte.
     Achtung: Alle drei Rahmenbreiten stehen hier: `_header.php` laesst jede Seite ihre
     eigene setzen ($wrapClass), und eine nicht genannte faellt lautlos aus dem
     Aufbau. Der Riegel prueft, dass jede Seite mit Buehne hier vorkommt. */
  body.auth-has-aside .auth-split > .auth-wrap,
  body.auth-has-aside .auth-split > .auth-wrap-lg,
  body.auth-has-aside .auth-split > .auth-wrap-xl {
    flex: 1 1 auto; max-width: none;
    display: flex; flex-direction: column; justify-content: center; align-items: center;
    padding: 40px clamp(24px, 4vw, 64px);
  }
  body.auth-has-aside .auth-split > .auth-wrap    { --auth-col: 400px; }
  body.auth-has-aside .auth-split > .auth-wrap-lg { --auth-col: 460px; }
  body.auth-has-aside .auth-split > .auth-wrap-xl { --auth-col: 520px; }
  body.auth-has-aside .auth-split > [class^="auth-wrap"] > * {
    width: 100%; max-width: var(--auth-col, 400px);
  }

  .auth-aside {
    display: block;
    position: relative; overflow: hidden;
    flex: 0 0 clamp(420px, 40vw, 720px); min-height: 100vh;

    /* Die Flaeche traegt immer die DUNKEL-PALETTE — auch auf einer hellen
       Seite: sie nimmt die Farben des DNS-Managers im Dunkelmodus auf.
       Achtung: Darum stehen die Werte hier fest und nicht als var(--bg) & Co.: dieselben
         Token bedeuten hell etwas voellig anderes (--bg ist hell #f0f4f8, dunkel
         #0f172a; --text-1 hell #0d1b2a, dunkel #f1f5f9). Uebernaehme die Flaeche
         die Token der Seite, waere sie im Hellmodus eine weisse Flaeche mit
         weisser Schrift. Die Werte sind 1:1 die aus main.css, Block
         [data-theme="dark"] — wer sie dort aendert, aendert sie hier mit.
       → Der Akzent bleibt `var(--gw)`: er ist in beiden Themen #0098ef, also
         dieselbe Farbe wie der Anmeldeknopf daneben. Kein zweites Blau. */
    --ax-bg:       #0f172a;   /* --bg       im Dunkelmodus */
    --ax-surface:  #1e293b;   /* --surface  im Dunkelmodus */
    --ax-border:   #2d3e50;   /* --border   im Dunkelmodus */
    --ax-border-2: #475569;   /* --border-2 im Dunkelmodus */
    --ax-t1:       #f1f5f9;   /* --text-1   im Dunkelmodus */
    --ax-t2:       #cbd5e1;   /* --text-2   im Dunkelmodus */
    --ax-t3:       #94a3b8;   /* --text-3   im Dunkelmodus */
    --ax-t4:       #64748b;   /* --text-4   im Dunkelmodus */
    /* Der Grund der Flaeche ist nicht --ax-bg, sonst unterscheiden sich im Dunkelmodus
       linke und rechte Haelfte nicht und die Flaeche wirkt abgeschnitten. Im Dunkelmodus ist die Seite selbst
       #0f172a — dieselbe Farbe. Damit verschwand die Kante, und das Punktfeld hoerte
       links einfach auf, statt an einer Flaeche zu enden.
       ⇒ #0b1322 ist der Grund der Code-Bloecke aus main.css, also eine Hausfarbe und
         der einzige Ton, der dunkler ist als --bg. Er traegt in beiden Themen: dunkel
         setzt er sich von der Seite ab, hell bleibt er die dunkle Flaeche.
       Achtung: Nicht heller machen: die Marke, die Symbole und die Pillen stehen auf
         --ax-surface (#1e293b). Waere die Flaeche selbst --ax-surface, waeren sie weg. */
    --ax-deep:     #0b1322;   /* == [data-theme="dark"] pre in main.css */

    /* Eine Farbe, flach. Kein Verlauf: ein Verlauf ueber die volle Bildschirmhoehe
       erzeugt einen sichtbaren Lichtkegel. */
    background: var(--ax-deep);
    /* Dezente Haarlinie an der Kante zur Anmeldung.
       Der Ton allein trennt die Haelften zwar, laesst die Kante aber weich wirken —
       1 px in `--ax-border` macht sie zu einer gewollten Linie.
       Achtung: Eine Linie, kein Schein: ein `box-shadow` mit Farbe waere wieder die
         Leucht-Kante des verworfenen Entwurfs. Der Riegel verbietet sie. */
    border-left: 1px solid var(--ax-border);
  }

  /* ── Das Motiv: die Weltkarte als Punktbild ──────────────────────────────
     Der Unterschied zum verworfenen Punktraster ist nicht die Dichte, sondern
       die FORM. Ein gleichmaessiges Raster ist eine Textur und sagt nichts; hier
       hat jeder Punkt einen Ort, und man erkennt, was man sieht.

     Die Punkte kommen aus unseren eigenen Kartendaten
       (`assets/vendor/worldmap/world.json`, dieselbe Quelle wie die Landkarten der
       Analytik). Erzeugt wurde daraus ein Rasterbild: 3'200 Quadrate auf einem
       8er-Raster, gerechnet mit Punkt-in-Polygon ueber 1'533 Teilflaechen.
       Achtung: Es ist ein `<path>` in einer Datei — 51 KB, gzip 7,7 KB, und als
         `background-image` cachebar. Als Elemente waeren es 3'200 Knoten auf der
         Anmeldeseite.
       Achtung: Die Fuellfarbe steht IN der SVG-Datei (#475569 = `--ax-border-2`). Ein
         `background-image` kann keine CSS-Variable lesen. Der Riegel haelt beide
         Werte zusammen, damit sie nicht auseinanderlaufen.

     Es bewegt sich nichts, und das ist eine Sicherheitsentscheidung, keine
       Bequemlichkeit: eine Stelle auf der Karte, die aufleuchtet, liest sich als
       Verkehr. Auf einer Seite ohne Anmeldung waere das eine Rueckmeldung an den
       Angreifer ueber sein eigenes Verhalten — und zwar auch dann, wenn die Punkte gar
       keine echten Daten zeigen: er kann es nicht unterscheiden. */
  .auth-aside__deko { position: absolute; inset: 0; z-index: 0; overflow: hidden; }

  /* Achtung: Die Geometrie steht einmal fuer beide Lagen. Die Lichter muessen exakt auf der
       Karte liegen; zwei getrennte Angaben waeren zwei Wahrheiten, und beim naechsten
       Verschieben laegen die Lichter im Meer. */
  .auth-aside__map,
  .auth-aside__lights {
    position: absolute; display: block;
    left: -14%; top: 50%; transform: translateY(-50%);
    width: 150%; aspect-ratio: 1010 / 666;
  }
  .auth-aside__map {
    background: url("../img/world-dots.svg") no-repeat center / contain;
    opacity: .40;
  }

  /* ── Die Lichter: zwoelf Punkte der Karte, die langsam aufleuchten ──────────
     sie sind fest verdrahtet, und das ist die Sicherheitsbedingung. Ein
       Anzeigewert auf einer Seite ohne Anmeldung, der sich mit dem Verhalten des
       Besuchers aendert, ist eine Rueckmeldung an den Angreifer.
       Ein festes Muster dagegen traegt keine Information: wer es beobachtet, misst
       nur sich selbst. Diese Lichter duerfen nie an echte Daten gehaengt werden —
       der Riegel prueft, dass in `_aside.php` ausser den Texten nichts ausgegeben wird.

     Die Orte sind echte Landpunkte des Rasters, gesucht mit `bin/world-dots.py`
       (naechster gesetzter Punkt zu zwoelf ueber die Kontinente verteilten Stellen).
       Geraten waere die Haelfte im Meer gelandet.

     Die Groesse steht in Prozent der Karte (ein Kartenpunkt ist 3/1010 = 0,297 %
       breit) — so bleibt ein Licht bei jeder Fenstergroesse genau so viel groesser
       als ein Kartenpunkt wie hier gemeint, ohne Pixel gegen Prozent zu halten.
     Achtung: Nachgemessen: mit 0,42 % und Spitze 0,92 waren die Lichter in der Aufnahme
       praktisch unsichtbar — ein Punkt von 4,5 px, halb durchsichtig, neben einem
       Kartenpunkt von 3,2 px. 0,52 % (rund das 1,7-fache eines Kartenpunkts) und
       volle Deckkraft in der Spitze liest sich als «dieser Punkt leuchtet auf»,
       ohne dass es blinkt. Gleichzeitig brennen 2 bis 4 der zwoelf. */
  .auth-aside__pulse {
    position: absolute; display: block;
    width: .52%; aspect-ratio: 1; margin: -.26% 0 0 -.26%;
    border-radius: 1px; background: var(--gw);
    opacity: 0;
    animation: gwLichtPunkt var(--ax-takt) ease-out var(--ax-vorlauf) infinite;
    will-change: opacity, transform;
  }
  /* Der Ring. Er ist eckig, nicht rund: ein Kreis, der aus einem Punkt nach aussen
     laeuft, ist ein Radarschirm — und damit genau die Optik, die zweimal
     durchgefallen ist. Ein Quadrat spricht dieselbe Sprache wie das Punktraster.
     Kein eigenes Element: `::before` haengt am Punkt und erbt ueber `--d`/`--v`
       automatisch dessen Takt. Zwoelf Lichter bleiben zwoelf Knoten. */
  .auth-aside__pulse::before {
    content: ''; position: absolute; inset: 0; display: block;
    border: 1px solid var(--gw); border-radius: 2px;
    opacity: 0; transform: scale(1);
    animation: gwLichtRing var(--ax-takt) ease-out var(--ax-vorlauf) infinite;
  }
  /* Der Punkt: kurz da, mit einem winzigen Sprung in der Groesse — das liest sich
     als «schaltet an», nicht als «wird heller». */
  @keyframes gwLichtPunkt {
    0%, 5%  { opacity: 0; transform: scale(.7); }
    9%      { opacity: 1; transform: scale(1.25); }
    14%     { opacity: 1; transform: scale(1); }
    30%     { opacity: 0; transform: scale(1); }
    100%    { opacity: 0; transform: scale(1); }
  }
  /* Der Ring: einmal nach aussen und weg. Er startet auf dem Punkt und wird auf das
     Achtfache gezogen — das ist gross genug, um gesehen zu werden, und klein genug,
     dass er die Nachbarpunkte nicht ueberdeckt. */
  @keyframes gwLichtRing {
    0%, 6%  { opacity: 0; transform: scale(1); }
    9%      { opacity: .7; transform: scale(1.4); }
    26%     { opacity: 0; transform: scale(8); }
    100%    { opacity: 0; transform: scale(8); }
  }
  /* Achtung: zwei Dinge stehen hier absichtlich beieinander:
     · Takt und Vorlauf als `--ax-takt`/`--ax-vorlauf` am Punkt, damit der Ring sie
       erbt. Zwei getrennte Angaben liefen frueher oder spaeter auseinander, und dann
       liefe der Ring zu einem Punkt, der gar nicht leuchtet.
     · Die Orte sind die Mitten der Kartenquadrate, nicht ihre Ecken. `bin/world-dots.py`
       zeichnet jedes Quadrat ab dem Rasterpunkt (`M{x} {y}h3v3h-3z`) — seine Mitte
       liegt also 1,5 Einheiten weiter rechts und unten. Ohne diese Korrektur sass
       jedes Licht oben links neben seinem Punkt. */
  .auth-aside__pulse:nth-child(1)  { left: 21.14%; top: 33.26%; --ax-takt: 17.3s; --ax-vorlauf: -3.1s; }
  .auth-aside__pulse:nth-child(2)  { left: 14.01%; top: 18.84%; --ax-takt: 23.9s; --ax-vorlauf: -19.4s; }
  .auth-aside__pulse:nth-child(3)  { left: 32.23%; top: 78.90%; --ax-takt: 19.1s; --ax-vorlauf: -8.6s; }
  .auth-aside__pulse:nth-child(4)  { left: 48.07%; top: 45.27%; --ax-takt: 26.7s; --ax-vorlauf: -24.2s; }
  .auth-aside__pulse:nth-child(5)  { left: 51.24%; top: 60.89%; --ax-takt: 21.3s; --ax-vorlauf: -13.7s; }
  .auth-aside__pulse:nth-child(6)  { left: 53.61%; top: 84.91%; --ax-takt: 29.3s; --ax-vorlauf: -5.8s; }
  .auth-aside__pulse:nth-child(7)  { left: 69.46%; top: 59.68%; --ax-takt: 18.7s; --ax-vorlauf: -16.1s; }
  .auth-aside__pulse:nth-child(8)  { left: 75.00%; top: 51.28%; --ax-takt: 24.1s; --ax-vorlauf: -9.9s; }
  .auth-aside__pulse:nth-child(9)  { left: 82.92%; top: 47.67%; --ax-takt: 20.9s; --ax-vorlauf: -2.4s; }
  .auth-aside__pulse:nth-child(10) { left: 84.50%; top: 83.71%; --ax-takt: 27.4s; --ax-vorlauf: -21.6s; }
  .auth-aside__pulse:nth-child(11) { left: 71.04%; top: 24.85%; --ax-takt: 22.6s; --ax-vorlauf: -11.3s; }
  .auth-aside__pulse:nth-child(12) { left: 58.37%; top: 53.68%; --ax-takt: 31.1s; --ax-vorlauf: -27.8s; }

  /* ── Der Text ──
     Achtung: Kein `backdrop-filter` an Marke, Kacheln oder Schildern: zwoelf davon ueber
     einer geblurrten Flaeche haben den Aufnahme-Browser zum Stillstand gebracht —
     und was hier haengt, ruckelt beim Betrachter. */
  .auth-aside__body {
    position: relative; z-index: 1;
    padding: 48px clamp(36px, 4vw, 64px);
    display: flex; flex-direction: column; justify-content: center;
    min-height: 100vh;
  }
  .auth-aside__eyebrow {
    align-self: flex-start;
    display: inline-flex; align-items: center; gap: 8px;
    padding: 6px 13px 6px 11px; margin-bottom: 20px;
    border-radius: 6px;
    font-size: 10.5px; font-weight: 700; letter-spacing: 1.3px; text-transform: uppercase;
    color: var(--ax-t3);
    background: var(--ax-surface);
    border: 1px solid var(--ax-border);
  }
  /* Der blaue Punkt in der Marke ist entfallen, er lenkte ab. Er behauptete
     ohnehin einen Betriebszustand, den eine Anmeldeseite gar nicht kennt. Das
     Element bleibt in der Vorlage stehen und wird hier ausgeblendet — so bleibt
     die Marke in allen sechs Sprachen unveraendert. */
  .auth-aside__eyebrow i { display: none; }

  .auth-aside__title {
    font-size: clamp(25px, 2.2vw, 32px); line-height: 1.24; font-weight: 700;
    letter-spacing: -.6px; color: var(--ax-t1);
    /* Ausgeglichener Umbruch — sonst steht ein einzelnes Wort auf Zeile zwei,
       und in fr/es/pt bricht der Satz ohnehin woanders. */
    text-wrap: balance;
    margin-bottom: 22px;
  }

  .auth-aside__list { list-style: none; display: grid; gap: 13px; }
  .auth-aside__list li {
    display: flex; gap: 11px; align-items: flex-start;
    font-size: 13.5px; line-height: 1.55; color: var(--ax-t2);
  }
  /* Eine Zeile, eine Helligkeit. Die zweigeteilte Fassung (Aussage hell, Beleg
     grau) machte aus der Spalte eine graue Platte, die das Bild zudeckte. */
  .auth-aside__ico {
    flex: 0 0 auto; width: 24px; height: 24px; margin-top: 1px;
    display: flex; align-items: center; justify-content: center;
    border-radius: 7px; color: var(--ax-t3);
    background: var(--ax-surface);
    border: 1px solid var(--ax-border);
  }

  /* Eckig wie alles andere auf dieser Flaeche — vollrunde Pillen neben eckigen
     Kacheln waeren eine zweite Formensprache. */
  .auth-aside__tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 26px; }
  .auth-aside__tags span {
    padding: 5px 10px; border-radius: 6px;
    font-size: 9.5px; font-weight: 700; letter-spacing: 1.1px; text-transform: uppercase;
    color: var(--ax-t3);
    background: var(--ax-surface);
    border: 1px solid var(--ax-border);
  }
}

/* Wer Bewegung abbestellt hat, bekommt dieselbe Flaeche — nur still.
   Die Regel faengt pauschal alles im Schmuck-Behaelter ab und nennt die Lichter
   ausdruecklich. Achtung: `animation: none` allein genuegt bei ihnen nicht: sie stuenden dann
   auf ihrer Ruhelage — und die ist `opacity: 0`, also unsichtbar. Genau richtig hier:
   ohne Bewegung ist ein aufleuchtender Punkt sinnlos, die Karte traegt allein. */
@media (prefers-reduced-motion: reduce) {
  .auth-aside__deko *, .auth-aside__pulse,
  .auth-aside__pulse::before { animation: none !important; opacity: 0 !important; }
}
