/* Schriften, selbst gehostet (SIL Open Font License 1.1, siehe fonts/LICENSE-*.txt):
   keine externe Anfrage, keine IP-Übermittlung. Beide variabel, deshalb ein Eintrag für alle
   Stärken. Latin-Teilmenge (Deutsch/Englisch inkl. ä ö ü ß); andere Zeichen fallen auf den
   System-Stack zurück. Inter = Oberfläche, JetBrains Mono = nur Daten (IP, Kanäle, Codes). */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url(/fonts/inter-variable-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url(/fonts/jetbrains-mono-variable-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root,
.on-dark, .rk-frame > *, .pnl-plate, .fbx-frame, .device-node > *, .chain-solo .cso-card > *, .sc-pv-node > text, .gp-preview {
  /* Geräteflächen bleiben in beiden Darstellungen dunkel (Christian 09.10.2026: „Im hellen Modus können die
     Geräte auch dunkel bleiben, nur der Hintergrund kann hell werden“): Rack-Schrank samt Frontplatten,
     Patchfeld-Platte, Bodentank-Rahmen, Geräteknoten im Schaltplan, Gerätekarten der Kettenansicht und
     die Mini-Gerätevorschau der Gerätebibliothek (.gp-preview: Karten, Gerätefenster, „Eigenes Gerät bauen“)
     behalten diese DUNKLEN Tokens auch unter data-theme="light". Bei Knoten, Karten und Rack-Schrank gilt
     das für den Inhalt (> *): Rand, Auswahlring und Schatten des Elements selbst gehören zur Arbeitsfläche
     und folgen der Darstellung; seine Grundfläche kommt aus --hw-surface*. Ebenso die Beispielknoten der
     Farbcode-Vorschau (.sc-pv-node, SVG): nur ihre Schrift (> text) ist Gerät, der Rand des Kästchens folgt wie
     im Schaltplan der Darstellung. Die Signalkettendruck-Karten
     (.cso-print, außerhalb von .chain-solo) bleiben Papier. tests/theme-hardware.test.js prüft die Liste. */
  color-scheme: dark;
  /* Farbsystem: ConfigMind-Identität – tiefes Navy, Cyan→Blau als Markenverlauf.
     Die Token-Namen bleiben gleich, damit alle Feature-Stylesheets ohne Umbau erben.
     Das hier ist die DUNKLE Fassung (Vorgabe); die helle steht in css/theme-light.css und
     überschreibt dieselben Namen unter :root[data-theme="light"] (gesetzt von js/theme-init.js).
     Neue Farben gehören als Token hierher UND dorthin — keine Einzelwerte in Feature-Stylesheets
     (tests/theme-tokens.test.js prüft Vollständigkeit und Kontrast). */
  --bg-black: #05070d;          /* Seitenhintergrund */
  --bg-navy: #0a1120;           /* Arbeitsflächen (Canvas, eingelassene Bereiche) */
  --bg-navy-2: #0d1626;         /* abgesetzte Köpfe/Leisten */
  --bg-card: #0f192c;           /* Karten, Tabellenzeilen */
  --bg-raised: #132038;         /* schwebende Karten, Hover, Menüs */
  --bg-raised-2: #182842;
  --bg-sidebar: #070c17;        /* Rahmen: Seitenleiste (dunkler als Karten) */
  --bg-chrome: rgba(7, 12, 23, 0.82); /* Kopfzeile/Toolbar, mit Unschärfe */
  --border: rgba(var(--ov-rgb), 0.08);
  --border-strong: rgba(var(--ov-rgb), 0.14);
  --text-primary: #eef2f8;
  --text-secondary: #a9b5c9;
  --text-tertiary: #8795ad;     /* WCAG AA (4,5 : 1) auch auf --bg-raised-2 */
  --accent-rgb: 45, 212, 236;
  --accent: #2dd4ec;            /* Cyan */
  --accent-2-rgb: 79, 140, 255;
  --accent-2: #4f8cff;          /* Blau */
  --brand-cyan: #2dd4ec;        /* Markenverlauf: Fläche, in beiden Darstellungen gleich (--accent selbst wird hell dunkler) */
  --brand-blue: #4f8cff;
  --accent-grad: linear-gradient(135deg, var(--brand-cyan), var(--brand-blue));
  --accent-grad-h: linear-gradient(90deg, var(--brand-cyan), var(--brand-blue));
  --accent-ink: #031018;        /* Schrift auf dem Verlauf */
  --accent-strong: #1fb8d4;     /* Vollfläche, wo kein Verlauf geht (Umschalter, Punkte) */
  --accent-strong-hover: #2dd4ec;
  --accent-soft: rgba(var(--accent-rgb), 0.12);
  --accent-glow: 0 0 0 1px rgba(var(--accent-rgb), 0.2), 0 8px 20px rgba(var(--accent-rgb), 0.15);
  --accent-glow-hover: 0 0 0 1px rgba(var(--accent-rgb), 0.4), 0 10px 26px rgba(var(--accent-rgb), 0.28);
  --radius: 14px;               /* Karten, Flächen */
  --radius-md: 10px;            /* Buttons, Eingabefelder */
  --radius-sm: 8px;             /* kleine Steuerelemente, Chips in Leisten */
  --maxw: 1200px;
  --maxw-wide: 1480px;
  --sidebar-w: 248px;
  --topbar-h: 56px;
  --danger: #ff8a8a;
  --warn: #ffcf7a;
  --ok: #6ee7a8;
  --danger-rgb: 255, 90, 90;    /* Tönungen/Rahmen von Warn- und Fehlerflächen: rgba(var(--…-rgb), a) */
  --warn-rgb: 255, 190, 90;
  --ok-rgb: 110, 231, 168;
  --ov-rgb: 255, 255, 255;      /* Aufhellung/Linien auf Flächen: rgba(var(--ov-rgb), a) (hell: Navy) */
  --shadow-rgb: 0, 0, 0;        /* Schatten, Abdunklung, Hintergrundblende: rgba(var(--shadow-rgb), calc(a * var(--shadow-a))) */
  --shadow-a: 1;                /* Stärke aller Schatten (hell: schwächer) */
  --scrim: rgba(3, 6, 14, 0.62); /* Blende hinter Dialogen */
  --danger-bg: #2a0f16;         /* Fehler-Sprechblase/Hinweisband (solide Fläche) und Schrift darauf */
  --danger-ink: #ffd6d6;
  --maybe: #cbd5e1;             /* „ungeprüft/vielleicht“: neutrale Linie und Schrift */
  --ink-mix: 80%;               /* Datenfarbe als Schrift: color-mix(in srgb, var(--cat) var(--ink-mix), var(--ink-base)) — */
  --ink-base: #ffffff;          /* dunkel leicht aufgehellt, hell stark abgedunkelt: mindestens 4,5 : 1 auf der Karte */
  --mark-mix: 100%;             /* Kategorie-/Gewerkfarbe als Strich oder Rand (Listenstrich, Kartenkante, Kopf des Gerätefensters):
                                   color-mix(in srgb, var(--cat) var(--mark-mix), var(--cat-l)) — dunkel die Farbe selbst,
                                   hell (0 %) ihre eigene helle Fassung --cat-l: je Farbe gerade so weit abgedunkelt, dass
                                   sie 3 : 1 (WCAG 1.4.11) auf jeder hellen Fläche hat, Farbton bleibt (js/category-mark.js).
                                   tests/theme-hardware.test.js prüft alle Kategorie-, Gewerk- und Signalfarben (auch #1ef01e). */
  --dir-in: #60a5fa;            /* Richtung Ein/Aus in der Gerätebibliothek */
  --dir-out: #f472b6;
  --pr-hand: #ffb46b;           /* Herkunft „von Hand“ (Presets) */
  --tone-power: #eab308;        /* Rack-Analyse: Leistung, Wärme, Gewicht */
  --tone-heat: #f97316;
  --tone-weight: #60a5fa;
  --on-warn: #1f1500;           /* Schrift auf einer --warn-Fläche */
  --on-fill: #ffffff;           /* Schrift auf kräftigen Farbflächen (Fehler, Primär-Statusfarben) */
  --ring-hi: #ffffff;           /* heller Ring um hervorgehobene Anschlüsse (Verbinden, Hover) */
  --dot-ring: rgba(13, 24, 48, 0); /* Rand um Kategorie-/Farbpunkte: dunkel unnötig, hell hält er helle Punkte sichtbar */
  --reject-bg: #c0283a;         /* Anschluss, der die Verbindung ablehnt */
  --tag-hover-bg: #ffffff;      /* Kabelnummer unter dem Zeiger */
  --tag-hover-ink: #000000;
  --swatch-sel: #ffffff;        /* Spalt zwischen gewählter Farbfläche und ihrem farbigen Ring (Farbwähler) */
  --on-ok: #04130b;             /* Zeichen auf einer --ok-Fläche (Prüfhäkchen im Schaltplan) */
  --mute-bg: #b0444c;           /* aktive Stummschaltung (Processing), Schrift darauf --on-fill */
  /* Schrift auf der Hardware-Abbildung (dunkles Metall, in beiden Darstellungen gleich): je >= 4,5 : 1 auf den Metallflächen */
  --hw-text: #d7dade; --hw-text-2: #a4a9af; --hw-text-faint: #9aa0a8; --hw-warn: #f5c96b;
  /* Neutrales Metallgrau für Nebenschrift am Rack-Rahmen (Höhenzahlen, Kopf, „x HE“): Ton wie vor der Umstellung
     (#5a5a60), aber hell genug für 4,5 : 1 auf Rahmen (--hw-surface*), Schildern und den Plattentönen selbst
     (hellste Stelle --hw-rack-face-hi; auf Blind- und Lüfterplatten ist das Schild durchsichtig). */
  --hw-text-dim: #8c8f95;
  /* Hardware-Abbildung selbst (Rack-Frontplatten, Patchfeld-Platte, Bodentank): dunkles Metall wie die echten
     Geräte, deshalb in BEIDEN Darstellungen gleich (theme-light.css überschreibt sie nicht). Stufen von fast
     schwarz (0) bis Schraubenkopf (11); Glanz und Schatten als rgb für rgba(var(--hw-…-rgb), a). */
  --hw-metal-0: #070708; --hw-metal-1: #0b0b0c; --hw-metal-2: #111214; --hw-metal-3: #16171a;
  --hw-metal-4: #1c1d20; --hw-metal-5: #232428; --hw-metal-6: #2b2c31; --hw-metal-7: #383a40;
  --hw-metal-8: #4a4d53; --hw-metal-9: #5b6068; --hw-metal-10: #6b7178; --hw-metal-11: #9aa0a8;
  --hw-black: #000000; --hw-ink-light: #ffffff; --hw-ink-dark: #0b0b0b;
  --hw-screen: #111b2b; --hw-screen-deep: #070a10; --hw-led-red: #e0483a; --hw-led-red-deep: #9d2a20;
  --hw-sheen-rgb: 255, 255, 255; --hw-shade-rgb: 0, 0, 0; --hw-led-red-rgb: 224, 72, 58; --hw-led-amber-rgb: 234, 179, 8;
  /* Rack-Abbildung (rack-faceplate.css): die Grautöne von vor der Umstellung auf Tokens (Stand 533acd6), wo die
     Metallstufen oben sie sichtbar verschoben hätten — Frontplatten-Glanz, Ringe, Tasten, Blindplatte, Fachboden. */
  --hw-rack-face-hi: #25252a; --hw-rack-ring: #3b3b41; --hw-rack-key: #34343a; --hw-rack-key-hi: #4a4a50;
  --hw-rack-port-edge: #36363c; --hw-rack-socket: #2f2f35; --hw-rack-blank-hi: #1f1f23; --hw-rack-blank-lo: #18181b;
  --hw-rack-tray-lo: #26262b; --hw-rack-tray-edge: #55555c; --hw-rack-jack: #b8bdc3; --hw-rack-label-rgb: 9, 9, 10;
  /* Grundfläche der Geräte im Schaltplan, in der Kettenansicht und des Rack-Schranks: die dunklen Karten-/Flächenwerte. */
  --hw-surface: #0f192c; --hw-surface-lo: #0a1120; --hw-surface-2: #0d1626;
  /* Auswahl und Fokus AN einem dunklen Gerät (Schaltplan-Knoten, Fokuskarte der Kettenansicht): Rand im Gerät
     (--sel-ring, muss gegen --hw-surface stehen) und Ring außen (--sel-halo / --sel-focus, steht auf der
     Arbeitsfläche). Hell: Cyan-Rand + Petrol-Ring, damit beide Seiten ≥ 3 : 1 erreichen (tests/theme-tokens.test.js). */
  --sel-ring: #2dd4ec; --sel-halo: rgba(var(--accent-rgb), 0.35); --sel-focus: #2dd4ec;
  /* Gezeichnete Frontplatten (SVG, rack-faceplate-draw.css): Navy-Metall mit Tasten-, LED- und Anzeigefarben wie
     an echten Geräten — ebenfalls in beiden Darstellungen gleich. */
  --fp-face-hi: #1a2438; --fp-face: #131c2d; --fp-face-lo: #0f1726; --fp-rear-hi: #151e2f; --fp-rear-lo: #0e1523;
  --fp-key: #2a3548; --fp-key-grey: #4a5569; --fp-white: #dfe6ef; --fp-key-black: #0b111c; --fp-red: #e0565b;
  --fp-green: #34c38f; --fp-yellow: #efc34a; --fp-orange: #f28c38; --fp-blue: #4f8cff; --fp-knob-skirt: #0c1320;
  --fp-knob: #34405a; --fp-hole: #05080f; --fp-cap: #aeb8c8; --fp-cap-black: #1a2233; --fp-screen: #050a14;
  --fp-screen-edge: #2a3a57; --fp-touch: #33476b; --fp-screen-line: #22324d; --fp-screen-tile: #101b30;
  --fp-screen-tile-edge: #1d2c47; --fp-led: #1c7c8c; --fp-seg: #1a5f6c; --fp-seg-mid: #9a7d2a; --fp-seg-hi: #a23b40;
  --fp-power: #111827; --fp-power-blue: #1d3f7a; --fp-power-red: #8c2a2e; --fp-jog: #1d2739; --fp-jog-ring: #273349;
  --fp-vent: #04070d; --fp-plate: #0e1625; --fp-plate-text: #8190a8; --fp-bay: #080d17; --fp-generic: #27324a;
  --fp-jack-rim: #1b2436; --fp-sig-none: #64748b; --fp-jack-hole: #03060c; --fp-pin: #8a96aa; --fp-metal: #5b667a;
  --fp-socket: #070b14; --fp-ear: #1e2839; --fp-body: #162032;
  --fp-blue-rgb: 79, 140, 255; --fp-tag-rgb: 7, 12, 23;
  /* Ausdruck/PDF ist immer hell: feste Papierfarben, in beiden Darstellungen gleich (Dokumentation, Signalketten-Druck). */
  --print-paper: #ffffff; --print-ink: #111111; --print-ink-2: #444444; --print-ink-3: #666666;
  --print-line: #bbbbbb; --print-line-2: #cccccc; --print-line-soft: #dddddd; --print-rule: #999999;
  --print-warn: #8a6100; --print-warn-2: #8a4b00; --print-bad: #aa0000; --print-focus: #eeeeff;
  --print-card-line: #9ca3af; --print-card-tint: #f3f4f6; --print-label: #222222; --print-focus-ring: #2563eb; /* Signalketten-Grafik im Druck (chain-solo.css .cso-print) */
  /* Typografie: Inter für die Oberfläche, JetBrains Mono ausschließlich für Daten. */
  --font-ui: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --font-sans: var(--font-ui);
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace;
  /* Gewerke-Domänenfarben: einmal definiert, genutzt in style.css (.type-icon) UND
     canvas.css (.device-node[data-domain]). */
  --domain-light: #ffd25a;
  --domain-intercom: #ff8c8c;
  --domain-wireless: #c88cff;
}

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

html { scroll-behavior: smooth; color-scheme: dark; /* native Steuerelemente (Checkbox, Select, Datum) folgen der Darstellung; js/theme-init.js setzt es je Wahl */ }

body {
  background: var(--bg-black);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.5;
  font-feature-settings: "cv11";
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

a { color: inherit; text-decoration: none; }
h1, h2, h3 { letter-spacing: -0.02em; font-weight: 700; }

/* Daten-Schrift: IP-Adressen, Kanalnummern, Inventarnummern, Codes, Kabelnummern. */
.mono, code, kbd, samp { font-family: var(--font-mono); font-feature-settings: normal; }

/* Formularelemente erben die App-Schrift (Browser-Standard wäre eine fremde Sans). */
button, input, select, textarea { font-family: inherit; }

/* Nur für Screenreader sichtbar (z. B. Spaltenkopf ohne sichtbare Beschriftung). */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* Sichtbarer Fokusring für alle interaktiven Steuerelemente ohne eigenen Fokus-Stil (Buttons,
   Tabs, Chips, Icon-Buttons) — vorher nur Text-Inputs/Selects fokus-sichtbar, Tastaturbedienung
   war für den Rest der App unsichtbar. Nur bei :focus-visible (Tastatur), nicht bei Mausklick. */
.btn:focus-visible,
.zoom-btn:focus-visible,
.icon-btn:focus-visible,
.discipline-chip:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

/* Hellere, besser sichtbare Scrollbalken (die dunklen System-Standardbalken gehen auf dem
   dunklen Hintergrund optisch unter). */
* { scrollbar-color: rgba(var(--ov-rgb), 0.28) transparent; scrollbar-width: thin; }
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background-color: rgba(var(--ov-rgb), 0.28);
  border-radius: 8px; border: 3px solid transparent; background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background-color: rgba(var(--ov-rgb), 0.4); }

.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }
.wrap-narrow { max-width: 420px; margin: 0 auto; padding: 0 24px; }
.btn-block { width: 100%; }
.auth-footer-link { margin-top: 18px; font-size: 13.5px; color: var(--text-secondary); text-align: center; }
.auth-footer-link a { color: var(--accent); font-weight: 600; }

header {
  position: sticky; top: 0; z-index: 10;
  background: var(--bg-black);
  border-bottom: 1px solid var(--border);
}

nav {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 24px; max-width: var(--maxw); margin: 0 auto;
}

.logo { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 16px; letter-spacing: -0.01em; }
.logo-mark {
  width: 24px; height: 24px; border-radius: 7px;
  background: var(--accent-grad); color: var(--accent-ink);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 0 16px rgba(var(--accent-rgb), 0.35);
}
.logo-mark svg { width: 13px; height: 13px; }

main { padding: 40px 0 80px; }

.page-head { margin-bottom: 32px; }
.page-head h1 { font-size: clamp(22px, 3vw, 28px); letter-spacing: -0.02em; margin-bottom: 6px; }
.page-head p { color: var(--text-secondary); font-size: 14.5px; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 8px 16px; border-radius: var(--radius-md); font-size: 13.5px; font-weight: 600;
  cursor: pointer; border: 1px solid transparent; transition: .15s ease;
  font-family: inherit;
}
.btn:active { transform: scale(0.97); }
.btn-primary { background: var(--accent-grad); color: var(--accent-ink); box-shadow: var(--accent-glow); }
.btn-primary:hover { box-shadow: var(--accent-glow-hover); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; box-shadow: none; }
.btn-ghost {
  background: rgba(var(--ov-rgb), 0.03); color: var(--text-primary);
  border: 1px solid var(--border-strong);
}
.btn-ghost:hover { background: rgba(var(--ov-rgb), 0.06); border-color: rgba(var(--ov-rgb), 0.22); }
.btn-danger { background: rgba(var(--danger-rgb),0.1); color: var(--danger); border: 1px solid rgba(var(--danger-rgb),0.25); }
.btn-danger:hover { background: rgba(var(--danger-rgb),0.16); }

.card {
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 22px; transition: .2s;
}
.card:hover { border-color: var(--border-strong); }
.tag {
  font-size: 11px; padding: 3px 9px; border-radius: 100px;
  background: var(--accent-soft); color: var(--accent); border: 1px solid rgba(var(--accent-rgb), 0.2);
}

.empty-state {
  text-align: center; padding: 80px 20px; color: var(--text-tertiary);
  border: 1px dashed var(--border-strong); border-radius: var(--radius);
}
.empty-state h3 { color: var(--text-primary); margin-bottom: 8px; font-size: 18px; }
.empty-state p { margin-bottom: 20px; font-size: 14px; }

.form-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 28px; max-width: 560px; }
.field { margin-bottom: 18px; }
.field label { display: block; font-size: 13px; font-weight: 600; color: var(--text-secondary); margin-bottom: 8px; }
.field input, .field textarea {
  width: 100%; background: var(--bg-navy); border: 1px solid var(--border-strong);
  border-radius: var(--radius-md); padding: 10px 14px; color: var(--text-primary); font-family: inherit; font-size: 14px;
  outline: none; transition: .15s;
}
.field input:focus, .field textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.12); }
.field textarea { resize: vertical; min-height: 100px; }
.field .hint { font-size: 12px; color: var(--text-tertiary); margin-top: 6px; }
.field-hint { font-size: 12px; color: var(--text-tertiary); margin-bottom: 14px; line-height: 1.5; }

/* ---- Listen im Panel „Frühere Stände“ (project-history.js) ---- */
.viewers-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; max-height: 220px; overflow-y: auto; }
.viewer-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: rgba(var(--ov-rgb), 0.03); border: 1px solid var(--border); border-radius: 8px;
  padding: 8px 10px 8px 14px; font-size: 13.5px;
}
.viewer-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.viewer-stamp { white-space: nowrap; }
.history-editors { font-size: 11.5px; color: var(--text-tertiary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.viewer-tag { font-size: 11.5px; color: var(--text-tertiary); }
.viewer-row .btn { height: 32px; padding: 0 12px; font-size: 13px; }
.viewer-meta { flex: 0 0 auto; white-space: nowrap; font: 11.5px var(--font-mono); color: var(--text-tertiary); }
/* Nur-Lesen-Modus: bekannte mutierende Steuerelemente ausblenden. Das Backend (server.js
   Dispatcher, lib/projectGuard.js) ist die eigentliche Sicherheitsgrenze — das hier ist reine UX-Politur, damit
   ein Viewer gar nicht erst auf eine Aktion trifft, die ohnehin mit 403 abgelehnt würde. */
body.is-readonly #addDeviceBtn,
body.is-readonly #addLocationBtn,
body.is-readonly #docUploadBtn,
body.is-readonly #docFolderUploadBtn,
body.is-readonly .location-header .icon-btn {
  display: none !important;
}
body.is-readonly .device-node, body.is-readonly .tray-chip, body.is-readonly .location-header {
  cursor: default;
}

.spinner {
  width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid rgba(var(--ov-rgb), 0.2); border-top-color: currentColor;
  animation: spin 0.7s linear infinite; display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }

.alert { padding: 12px 16px; border-radius: 8px; font-size: 13.5px; margin-bottom: 16px; }
.alert-error { background: rgba(var(--danger-rgb),0.1); color: var(--danger); border: 1px solid rgba(var(--danger-rgb),0.25); }
.alert-warn { background: rgba(var(--warn-rgb),0.08); color: var(--warn); border: 1px solid rgba(var(--warn-rgb),0.25); }
.alert-info { background: var(--accent-soft); color: var(--text-secondary); border: 1px solid rgba(var(--accent-rgb), 0.3); }
.alert-ok { background: rgba(var(--ok-rgb),0.1); color: var(--ok); border: 1px solid rgba(var(--ok-rgb),0.25); }
.alert-ok a { text-decoration: underline; }

/* Hinweise im Konto (P05, public/app.js renderAccountNotices): schmale Leiste im Seitenfluss direkt unter der
   Kopfzeile – überdeckt nichts; im Editor zieht css/editor.css ihre Höhe (--cm-notices-h) von der Arbeitsfläche ab. */
.cm-notices { display: flex; flex-direction: column; border-bottom: 1px solid var(--border); background: var(--bg-raised); }
.cm-notice {
  display: flex; align-items: center; gap: 8px 12px; flex-wrap: wrap; padding: 7px var(--page-pad-x, 24px);
  font-size: 13px; color: var(--text-primary); line-height: 1.45; box-shadow: inset 3px 0 0 var(--accent);
}
.cm-notice + .cm-notice { border-top: 1px solid var(--border); }
.cm-notice > span { flex: 1 1 260px; min-width: 0; }
.cm-notice.is-must { background: rgba(var(--warn-rgb), 0.08); box-shadow: inset 3px 0 0 var(--warn); }
.cm-notice-short { display: none; }
@media (max-width: 560px) {
  .cm-notice { padding: 6px 12px; font-size: 12.5px; flex-wrap: nowrap; }
  .cm-notice-long { display: none; }
  .cm-notice > .cm-notice-short { flex: 1 1 0; min-width: 0; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
  .cm-notice .btn { flex: none; white-space: nowrap; }
}

/* ---- Toast (showErrorToast in app.js): ersetzt native alert()-Popups bei Speicherfehlern
   im Canvas-Editor — passt zum dunklen Theme und blockiert den Thread nicht. ---- */
.toast-stack {
  position: fixed; bottom: calc(20px + var(--cm-progress-lift, 0px)); left: 50%; transform: translateX(-50%); z-index: 200;
  display: flex; flex-direction: column-reverse; gap: 8px; pointer-events: none;
  transition: bottom 0.18s ease-out; /* rückt über die Fortschrittsanzeige (progress-ui.js), solange sie steht */
  max-width: calc(100vw - 32px);
}
.toast {
  pointer-events: auto; padding: 12px 16px; border-radius: 8px; font-size: 13.5px;
  box-shadow: 0 12px 28px rgba(var(--shadow-rgb), calc(0.4 * var(--shadow-a))); animation: toast-in .18s ease-out;
}
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }

