/* Erscheinungsbild nach DOSSIER ("RAPPORT": Creme + Petrol-Grün), inkl. Dark Mode. Der linke Navigator (Zeichnungsebenen + Ebenen-Baum) übernimmt das DOSSIER-Look: aktive Zeile als Petrol-Pille, nicht-aktive gedimmt, ausgeblendete grau; Augen-Schalter, Farbtupfer, eingerückte Kinder. */ :root { color-scheme: light; /* Flächen */ --bg: #e0dbd4; --panel: #e0dbd4; --panel-2: #d4cfc8; --input: #ece8e2; --line: #d4cfc8; --border: #c8c2ba; /* Zeichenblatt-Hintergrund (Plan) — bewusst fix, unabhängig von der Panel- Farbe: helles „Papier" im Light-Mode. */ --sheet: #f0f0f0; /* Schrift */ --ink: #1a1a18; --ink-2: #555550; --muted: #8a8580; --label: #1a1a18; /* Petrol-Akzent + aktiver Marker */ --accent: #2f5d54; --accent-light: #4a8a7c; --accent-dim: #e6efed; --accent-border: rgba(47, 93, 84, 0.35); --active: #1a655a; --active-light: #2f8275; --active-dim: rgba(26, 101, 90, 0.12); /* Plan-/3D-Töne */ --wall: #2b3039; --swing: #9aa3b2; /* Warn-/Gefahr-Akzente (z. B. Löschen). */ --danger: #8a1a1a; --danger-light: #b03030; --shadow-1: 0 1px 2px rgba(26, 26, 24, 0.08); --shadow-2: 0 2px 8px rgba(26, 26, 24, 0.14); --shadow-3: 0 6px 24px rgba(26, 26, 24, 0.18); --overlay: rgba(26, 26, 24, 0.36); --font: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; --font-mono: "DM Mono", ui-monospace, "SF Mono", monospace; } @media (prefers-color-scheme: dark) { :root { color-scheme: dark; /* Gestufte Elevations-Palette (Wunsch: dunkler + mehr Tiefe). Tiefster Grund hinten, Flächen werden nach vorn schrittweise heller — leicht kühl-neutral, harmoniert mit dem Petrol-Akzent. --bg Ebene 0 — App-Grund / Rinnen hinter allem (am dunkelsten) --panel Ebene 1 — Oberleiste, Docks, Panel-Körper --panel-2 Ebene 2 — angehobene Flächen: Panel-Köpfe, Hover-Zeilen --input versenkt — Eingabefelder (dunkler als die Fläche → Inset) */ /* Zwei-Ton-Grundlage (Nutzer-Vorgabe): Fast-Schwarz hinten, dunkles Neutralgrau für die Flächen. Neutral (kein Blaustich), mit dezenten Elevations-Schritten für Tiefe. */ --bg: #0e0e0e; --panel: #1d1d1d; --panel-2: #262626; --input: #0a0a0a; --line: #2b2b2b; --border: #383838; /* --sheet bleibt bewusst hell (#f0f0f0) wie im Light-Mode: das Zeichenblatt ist immer „Papier", unabhängig vom UI-Theme (Wunsch des Nutzers). */ --ink: #ededed; --ink-2: #a8a8a8; --muted: #6e6e6e; --label: #c8c8c8; /* Akzent NEUTRAL (kein Petrol-Grün mehr, Nutzer-Vorgabe): helles Neutralgrau für aktive/ausgewählte Flächen; weiße Schrift darauf bleibt lesbar. Hover/ Dim sind dezente weiße Aufhellungen. */ --accent: #4d4d4d; --accent-light: #5e5e5e; --accent-dim: rgba(255, 255, 255, 0.07); --accent-border: rgba(255, 255, 255, 0.22); --active: #6a6a6a; --active-light: #7d7d7d; --active-dim: rgba(255, 255, 255, 0.1); --wall: #c8ccd2; --swing: #7e8794; --danger: #c85050; --danger-light: #d86060; /* Tiefere Schatten für klare Schichtung auf dunklem Grund. */ --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.5); --shadow-2: 0 3px 12px rgba(0, 0, 0, 0.55); --shadow-3: 0 12px 34px rgba(0, 0, 0, 0.62); --overlay: rgba(0, 0, 0, 0.62); } } * { box-sizing: border-box; } html, body, #root { height: 100%; margin: 0; } /* Native-App-Verhalten: KEINE Textauswahl / „Alles markieren" in der App-Chrome. user-select global aus; nur in echten Eingaben wieder an, damit Tippen und Markieren im Feld weiter funktioniert. (Ctrl+A außerhalb von Eingaben wird in main.tsx zusätzlich unterbunden.) */ html, body, #root { -webkit-user-select: none; user-select: none; /* Kein Browser-eigenes Antippen/Highlight auf Touch. */ -webkit-tap-highlight-color: transparent; } input, textarea, [contenteditable], [contenteditable] * { -webkit-user-select: text; user-select: text; } body { font-family: var(--font); color: var(--ink); background: var(--bg); -webkit-font-smoothing: antialiased; } .app { display: flex; flex-direction: column; height: 100%; } /* ── Oberleiste ──────────────────────────────────────────────────────── */ /* Gruppen links nach rechts mit Trennern; die rechte Gruppe (Layout/ Ressourcen/Projekt) wird per margin-left:auto an den Rand geschoben. Bei sehr schmalen Fenstern darf die Leiste horizontal scrollen, statt zu brechen. */ .topbar { display: flex; align-items: center; gap: 10px; padding: 0 14px; height: 56px; border-bottom: 1px solid var(--line); /* Oberleiste auf Ebene 1 (angehoben über dem App-Grund) + weicher Schatten nach unten → trennt sich klar von der Zeichenfläche (Tiefe). */ background: var(--panel); box-shadow: var(--shadow-1); position: relative; z-index: 2; overflow-x: auto; overflow-y: hidden; white-space: nowrap; /* Dezente, normalerweise unsichtbare Scrollleiste (Firefox). */ scrollbar-width: thin; scrollbar-color: transparent transparent; } /* Sehr ruhige eigene Scrollleiste (WebKit/Blink): Thumb nur beim Scrollen (`is-scrolling`, von TopBar gesetzt) oder beim Überfahren sichtbar. */ .topbar::-webkit-scrollbar { height: 6px; } .topbar::-webkit-scrollbar-track { background: transparent; } .topbar::-webkit-scrollbar-thumb { background: transparent; border-radius: 3px; transition: background 0.25s ease; } .topbar.is-scrolling { scrollbar-color: rgba(140, 140, 140, 0.45) transparent; } .topbar.is-scrolling::-webkit-scrollbar-thumb, .topbar:hover::-webkit-scrollbar-thumb { background: rgba(140, 140, 140, 0.4); } /* Eine Werkzeug-Gruppe der Oberleiste. */ .tb-group { display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto; } /* Vertikaler Trenner zwischen Gruppen. */ .tb-sep { flex: 0 0 auto; width: 1px; height: 22px; background: var(--border); } /* Beschriftetes Feld (Label + Control) in der Oberleiste. */ .tb-field { display: inline-flex; align-items: center; gap: 6px; } .tb-label { font-size: 11px; font-weight: 600; letter-spacing: 0.03em; color: var(--muted); } /* Kompaktes Dropdown der Oberleiste (Detailgrad, Massstab). */ .tb-select { border: 1px solid var(--border); background: var(--input); color: var(--ink); font-family: inherit; font-size: 11px; font-weight: 600; padding: 3px 6px; border-radius: 6px; cursor: pointer; } .tb-select:hover { border-color: var(--accent-border); } .tb-scale { font-family: var(--font-mono); min-width: 78px; } /* Gruppe aus Knöpfen (Zoom). */ /* Aktions-Pillen (100 % · Einpassen · Auswahl · PDF) — optisch eine Familie mit den Dropdown-Triggern (.tb-dd-trigger): jede Aktion ist eine eigene gerahmte, abgesetzte dunkle Pill mit demselben Akzent-Hover (Rand → accent-border, Fläche → accent-dim, Text → accent). Sie bleiben Buttons (Aktion ≠ Auswahl); nur die Optik ist angeglichen. */ .tb-btns { display: inline-flex; gap: 6px; } .tb-btn { display: inline-flex; align-items: center; border: 1px solid var(--border); background: var(--input); color: var(--ink); font-family: inherit; font-size: 11px; font-weight: 600; letter-spacing: 0.02em; padding: 3px 10px; border-radius: 999px; cursor: pointer; outline: none; transition: border-color 0.14s, background-color 0.14s, color 0.14s, box-shadow 0.14s; } .tb-btn:hover:not(:disabled) { border-color: var(--accent-border); background-color: var(--accent-dim); color: var(--accent); } .tb-btn:focus-visible { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-dim); } .tb-btn:disabled { color: var(--muted); opacity: 0.55; cursor: default; } /* Live-Zoom-Anzeige in der Oberleiste (monospace, fixe Breite). */ .tb-zoom { font-family: var(--font-mono); font-size: 12px; font-weight: 600; color: var(--ink-2); min-width: 44px; text-align: right; } /* LIVE-Massstab 1:N + Zoom% kompakt übereinander (platzsparend). */ .tb-zoomstack { display: inline-flex; flex-direction: column; align-items: flex-end; justify-content: center; gap: 1px; line-height: 1.1; } .tb-zoomstack .tb-live-scale, .tb-zoomstack .tb-zoom { font-size: 11px; min-width: 0; } /* Live-Papier-Massstab „1:N" in der Oberleiste (Akzent, monospace). Hebt sich vom gewählten Massstab im Dropdown ab — dies ist der aktuelle Ist-Massstab. */ .tb-live-scale { font-family: var(--font-mono); font-size: 12px; font-weight: 700; color: var(--accent); min-width: 56px; text-align: right; } /* Pillen-Toggle der Oberleiste (Referenzlinien). */ .tb-toggle { border: 1px solid var(--border); background: var(--input); color: var(--ink-2); font-family: inherit; font-size: 11px; font-weight: 600; letter-spacing: 0.03em; padding: 6px 12px; border-radius: 999px; cursor: pointer; transition: background 0.14s, color 0.14s, border-color 0.14s; } .tb-toggle:hover { background: var(--accent-dim); border-color: var(--accent-border); color: var(--accent); } .tb-toggle.active { background: var(--accent); border-color: var(--accent); color: #fff; } /* ── DOSSIER-Grundprimitive: Segmentpille · Icon-Knopf · Zoom-Cluster ──────── */ /* Segmentpille (3er/4er): Aussencontainer rund, Zellen gleich hoch, interne Trenner über border-left. Genutzt für Zoom-Aktionen, B/I/U, L/C/R. */ .tb-seg { display: inline-flex; align-items: stretch; height: 24px; box-sizing: border-box; border: 1px solid var(--border); border-radius: 999px; overflow: hidden; background: var(--input); flex: 0 0 auto; } /* Akzent-Rand, wenn ein Text-Ziel selektiert ist (Auswahl-Bewusstsein). */ .tb-seg-accent { border-color: var(--accent); } .tb-seg-cell { display: inline-flex; align-items: center; justify-content: center; flex: 1 1 0; min-width: 26px; padding: 0 6px; border: none; border-left: 1px solid var(--border); background: transparent; color: var(--ink-2); cursor: pointer; transition: background 0.14s, color 0.14s; } .tb-seg-cell:first-child { border-left: none; } .tb-seg-cell:hover:not(:disabled) { background: var(--accent-dim); color: var(--accent); } .tb-seg-cell.active { background: var(--accent); color: #fff; } .tb-seg-cell:disabled { opacity: 0.4; cursor: default; } /* Quadratischer Icon-Knopf (BarButton) — Export-Pillen (PDF/DXF). */ .tb-iconbtn { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; box-sizing: border-box; padding: 0; border: 1px solid var(--border); border-radius: 999px; background: var(--input); color: var(--ink-2); cursor: pointer; transition: background 0.14s, color 0.14s, border-color 0.14s; } .tb-iconbtn:hover:not(:disabled) { background: var(--accent-dim); border-color: var(--accent-border); color: var(--accent); } .tb-iconbtn:disabled { opacity: 0.4; cursor: default; } /* Massstab/Zoom-Cluster (2×2-Raster): Stat-Pille links über beide Zeilen. */ .tb-zoomcluster { display: grid; grid-template-columns: auto auto; gap: 4px 6px; align-items: center; } .tb-stat { grid-row: 1 / span 2; display: flex; flex-direction: column; justify-content: center; align-items: center; width: 70px; height: 50px; box-sizing: border-box; border: 1px solid var(--border); border-radius: 14px; background: var(--input); } .tb-stat-scale { font-family: var(--font-mono); font-size: 11px; font-weight: 700; line-height: 1.3; color: var(--accent); width: 100%; text-align: center; border-bottom: 1px solid var(--border); } .tb-stat-zoom { font-family: var(--font-mono); font-size: 11px; line-height: 1.3; color: var(--ink-2); width: 100%; text-align: center; } /* „am Massstab" (Live == gewählter Massstab): Akzent-Hervorhebung. */ .tb-stat-atscale { background: var(--accent-dim); border-color: var(--accent); } .tb-stat-atscale .tb-stat-scale { border-bottom-color: var(--accent-border); } .tb-stat-atscale .tb-stat-zoom { color: var(--accent); } .tb-zoomcluster-right { display: inline-flex; align-items: center; gap: 6px; } /* ── Text-Gruppe (immer sichtbar, 3×2) ───────────────────────────────────── */ .tb-textgroup { flex-direction: column; align-items: stretch; gap: 4px; } .tb-textgroup-row { display: inline-flex; align-items: center; gap: 6px; } /* „+ Text"-Knopf: Pille mit Icon + Label. */ .tb-addtext { display: inline-flex; align-items: center; gap: 4px; width: 80px; height: 24px; box-sizing: border-box; padding: 0 8px; border: 1px solid var(--border); border-radius: 999px; background: var(--input); color: var(--ink-2); font-family: inherit; font-size: 11px; font-weight: 600; cursor: pointer; transition: background 0.14s, color 0.14s, border-color 0.14s; } .tb-addtext:hover:not(:disabled) { background: var(--accent-dim); border-color: var(--accent-border); color: var(--accent); } .tb-addtext:disabled { opacity: 0.5; cursor: default; } .tb-addtext-label { flex: 1 1 auto; text-align: left; } .brand { display: flex; align-items: center; gap: 8px; font-weight: 650; font-size: 16px; letter-spacing: 0.2px; } .logo { color: var(--accent); font-size: 18px; } .tag { font-weight: 500; font-size: 11px; color: var(--muted); border: 1px solid var(--border); border-radius: 999px; padding: 2px 8px; } .project-name { color: var(--muted); font-size: 13px; } /* Rechte Gruppe der Oberleiste: Layout-Menü + Ressourcen-Knopf + Projektname. margin-left:auto schiebt sie an den rechten Rand. */ .topbar-right { display: inline-flex; align-items: center; gap: 12px; margin-left: auto; padding-left: 10px; flex: 0 0 auto; } /* „Ressourcen"-Eintrag der Oberleiste (öffnet die Manager-Schublade). */ .res-trigger { border: 1px solid var(--border); background: var(--input); color: var(--ink-2); font-family: inherit; font-size: 11px; font-weight: 600; letter-spacing: 0.04em; padding: 6px 14px; border-radius: 999px; cursor: pointer; transition: background 0.14s, color 0.14s, border-color 0.14s; } .res-trigger:hover { background: var(--accent-dim); border-color: var(--accent-border); color: var(--accent); } .res-trigger.active { background: var(--accent); border-color: var(--accent); color: #fff; } /* Ansichtstyp-Umschalter (Geschoss). */ .view-toggle { display: inline-flex; border: 1px solid var(--border); border-radius: 999px; overflow: hidden; background: var(--input); } .view-btn { border: none; background: transparent; color: var(--muted); font-family: inherit; font-size: 12px; font-weight: 600; letter-spacing: 0.03em; padding: 6px 16px; cursor: pointer; transition: background 0.14s, color 0.14s; } .view-btn + .view-btn { border-left: 1px solid var(--border); } .view-btn:hover { background: var(--accent-dim); color: var(--ink); } .view-btn.active { background: var(--accent); color: #fff; } /* ── Ansichten als kompaktes Icon-Grid (DOSSIER-Stil, 3 oben / 3 unten) ──── */ .view-grid { display: grid; grid-template-columns: repeat(3, auto); grid-auto-rows: 1fr; gap: 3px; flex: 0 0 auto; } .view-grid-4 { grid-template-columns: repeat(4, auto); } .view-icon { border: 1px solid var(--border); background: var(--input); color: var(--ink-2); display: inline-flex; align-items: center; justify-content: center; width: 31px; height: 22px; padding: 0; border-radius: 6px; cursor: pointer; transition: background 0.14s, color 0.14s, border-color 0.14s; } .view-icon:hover:not(:disabled) { background: var(--accent-dim); color: var(--ink); border-color: var(--accent-border); } .view-icon.active { background: var(--accent); color: #fff; border-color: var(--accent); } .view-icon:disabled { opacity: 0.4; cursor: default; } /* Kamera-Button steckt im Popover-Wrapper → als Grid-Zelle behandeln. */ .view-grid .tb-popwrap { display: inline-flex; } /* Material-Symbols-Icon in Oberleisten-Buttons (Referenzlinien, Linien-Modus, Ressourcen) — auf die kompakte Icon-Button-Höhe skaliert, currentColor erbend, sodass aktiv/hover die Farbe wie bei den View-Icons mitführt. */ .tb-ico { font-size: 17px; line-height: 1; } /* Linien-Modus-Segmente tragen jetzt Icons statt Text — Padding wie eine Icon-Zelle (zentriert), damit beide Segmente gleich breit wirken. */ .view-btn-ico { display: inline-flex; align-items: center; justify-content: center; padding: 4px 12px; } .view-btn-ico:disabled { opacity: 0.4; cursor: default; } /* Gestapelte Gruppe (Label-Felder untereinander, z. B. Ebenen-/Zeichn.-Komb.). */ .tb-group.tb-stack { flex-direction: column; align-items: stretch; gap: 4px; } .tb-field-row { justify-content: space-between; gap: 8px; } /* Rumpf: Navigator + Inhalt nebeneinander. */ .body { position: relative; /* Bezugsrahmen für schwebende Panels + Andock-Zonen. */ flex: 1; display: flex; min-height: 0; } /* ── Footer / Status-Leiste (unten) ────────────────────────────────────── App-Shell ist eine Spalte: Oberleiste / Rumpf (flex:1) / Status-Leiste. Die Leiste hat eine feste Höhe (~22 px) und schrumpft nicht. Links der Werkzeug-Hinweis, rechts ein Cluster abgeleiteter View-/Modell-Werte. */ .statusbar { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 12px; height: 22px; padding: 0 12px; border-top: 1px solid var(--line); background: var(--panel-2); font-size: 11px; color: var(--ink-2); user-select: none; } /* Werkzeug-Hinweis links (kontextueller Text). */ .sb-hint { font-weight: 600; letter-spacing: 0.02em; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* Rechter Wert-Cluster. */ .sb-cluster { display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto; white-space: nowrap; } /* Ein Wert-Feld: kleine Beschriftung + Wert. */ .sb-field { display: inline-flex; align-items: baseline; gap: 5px; } .sb-key { font-size: 10px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted); } .sb-val { font-family: var(--font-mono); font-size: 11px; color: var(--ink); } /* Vertikaler Trenner im Cluster. */ .sb-sep { width: 1px; height: 12px; background: var(--border); } /* Renderer-Umschalter (WebGL2 / Engine) in der Statusleiste — kleine Segmentpille, an die 22px-Leiste angepasst (siehe .tb-seg für das größere Vorbild in der Oberleiste). */ .sb-renderer-toggle { display: inline-flex; align-items: stretch; height: 16px; border: 1px solid var(--border); border-radius: 999px; overflow: hidden; background: var(--input); } .sb-renderer-btn { display: inline-flex; align-items: center; border: none; border-left: 1px solid var(--border); background: transparent; color: var(--muted); font-family: inherit; font-size: 10px; font-weight: 600; letter-spacing: 0.02em; padding: 0 8px; cursor: pointer; transition: background 0.14s, color 0.14s; } .sb-renderer-btn:first-child { border-left: none; } .sb-renderer-btn:hover:not(:disabled) { background: var(--accent-dim); color: var(--accent); } .sb-renderer-btn.active { background: var(--accent); color: #fff; } .sb-renderer-btn:disabled { opacity: 0.4; cursor: default; } /* Einzelner Umschalt-Button in der Statusleiste (z. B. Referenzlinien). */ .sb-toggle { display: inline-flex; align-items: center; border: 1px solid var(--border); border-radius: 5px; background: transparent; color: var(--muted); font-family: inherit; font-size: 10px; font-weight: 600; letter-spacing: 0.02em; padding: 2px 8px; cursor: pointer; transition: background 0.14s, color 0.14s, border-color 0.14s; } .sb-toggle:hover:not(:disabled) { background: var(--accent-dim); color: var(--accent); border-color: var(--accent); } .sb-toggle.active { background: var(--accent); border-color: var(--accent); color: #fff; } .sb-toggle:disabled { opacity: 0.4; cursor: default; } /* Generische Segment-Pille für die Statusleiste (Linien-Darstellung, Fang) — gleiche Masse/Optik wie .sb-renderer-toggle, aber nicht renderer-spezifisch. */ .sb-seg { display: inline-flex; align-items: stretch; height: 16px; border: 1px solid var(--border); border-radius: 999px; overflow: hidden; background: var(--input); } .sb-seg.disabled { opacity: 0.4; } .sb-seg-btn { display: inline-flex; align-items: center; border: none; border-left: 1px solid var(--border); background: transparent; color: var(--muted); font-family: inherit; font-size: 10px; font-weight: 600; letter-spacing: 0.02em; padding: 0 8px; cursor: pointer; transition: background 0.14s, color 0.14s; } .sb-seg-btn:first-child { border-left: none; } .sb-seg-btn:hover:not(:disabled) { background: var(--accent-dim); color: var(--accent); } .sb-seg-btn.active { background: var(--accent); color: #fff; } .sb-seg-btn:disabled { opacity: 0.4; cursor: default; } /* Caret-Segment (öffnet das Fang-Popover) — schmaler als die Text-Segmente. */ .sb-seg-caret { padding: 0 6px; font-size: 9px; line-height: 1; } /* Fang-Kontrolle: Wrapper ist relativ positioniert, damit das Popover NACH OBEN öffnen kann (die Leiste sitzt ganz unten im App-Shell). */ .sb-snap-wrap { position: relative; display: inline-flex; } .sb-snap-popover { position: absolute; right: 0; bottom: 100%; margin: 0 0 6px; padding: 6px 0; min-width: 170px; background: var(--panel, #1c2128); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45); z-index: 200; } .sb-snap-row { display: flex; align-items: center; gap: 8px; padding: 3px 12px; font-size: 12px; cursor: pointer; user-select: none; white-space: nowrap; } .sb-snap-row input[type="checkbox"] { accent-color: var(--accent); } .sb-snap-row-num { justify-content: space-between; cursor: default; } .sb-snap-row-num input[type="number"] { width: 64px; } /* ── Command-Line (Rhino-artig) — über der Statusleiste ────────────────────── Dunkle, ruhige Leiste mit Prompt links, klickbaren Inline-Optionen und einer monospace-Texteingabe rechts; das Autocomplete-Dropdown öffnet nach oben. */ .cmdline { position: relative; flex: 0 0 auto; display: flex; align-items: center; gap: 10px; height: 26px; padding: 0 12px; border-top: 1px solid var(--line); background: var(--input); font-size: 12px; user-select: none; } .cmdline-prompt { flex: 0 0 auto; font-weight: 600; color: var(--ink); white-space: nowrap; } .cmdline-options { display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto; } .cmdline-option { appearance: none; border: 1px solid var(--border); background: var(--panel-2); color: var(--ink); font: inherit; font-size: 11px; padding: 1px 7px; border-radius: 4px; cursor: pointer; } .cmdline-option:hover { border-color: var(--accent-border); background: var(--accent-dim); } .cmdline-option.active { border-color: var(--accent); background: var(--accent-dim); color: var(--accent); } .cmdline-option-val { color: var(--accent); font-family: var(--font-mono); } /* Tastatur-Kürzel vor dem Options-Label (z. B. „U" der Kopiermodi). */ .cmdline-option-key { display: inline-block; margin-right: 5px; padding: 0 4px; border-radius: 3px; background: var(--panel-3, var(--panel)); color: var(--ink-dim, var(--ink)); font-family: var(--font-mono); font-size: 10px; font-weight: 600; } .cmdline-option.active .cmdline-option-key { background: var(--accent); color: var(--bg, #fff); } /* Tab-Feld-Zyklus: kleine beschriftete Boxen (Länge/Winkel/…); aktives Feld hervorgehoben (Akzent-Rand). Wert „—" = ungelockt (folgt der Maus). */ .cmdline-fields { display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto; } .cmdline-field { display: inline-flex; align-items: baseline; gap: 5px; padding: 1px 7px; border: 1px solid var(--border); border-radius: 4px; background: var(--panel-2); font-size: 11px; white-space: nowrap; } .cmdline-field.active { border-color: var(--accent-border); background: var(--accent-dim); } .cmdline-field-label { color: var(--muted); } .cmdline-field.active .cmdline-field-label { color: var(--accent); } .cmdline-field-val { font-family: var(--font-mono); color: var(--ink); min-width: 1.2em; text-align: right; } /* Live (maus-folgender) Wert ruhiger als ein gelockter (getippter) Wert. */ .cmdline-field.live .cmdline-field-val { color: var(--muted); } .cmdline-field.locked .cmdline-field-val { color: var(--ink); font-weight: 600; } .cmdline-input { flex: 1 1 auto; min-width: 80px; appearance: none; border: none; background: transparent; color: var(--ink); font-family: var(--font-mono); font-size: 12px; outline: none; user-select: text; } .cmdline-input::placeholder { color: var(--muted); } /* Autocomplete-Dropdown öffnet nach OBEN (Leiste sitzt ganz unten). */ .cmdline-suggest { position: absolute; left: 12px; bottom: 100%; margin: 0 0 2px; padding: 4px 0; list-style: none; min-width: 160px; background: var(--panel-2); border: 1px solid var(--border); border-radius: 6px; box-shadow: var(--shadow-2); z-index: 50; } .cmdline-suggest-item { padding: 3px 12px; font-family: var(--font-mono); font-size: 12px; color: var(--ink); cursor: pointer; } .cmdline-suggest-item:hover { background: var(--accent-dim); color: var(--accent); } /* ── Navigator (links) ───────────────────────────────────────────────── */ .navigator { width: 252px; flex: 0 0 252px; display: flex; flex-direction: column; gap: 18px; padding: 14px 8px; border-right: 1px solid var(--line); background: var(--panel); overflow-y: auto; } .nav-group { display: flex; flex-direction: column; } .nav-group-head { display: flex; align-items: center; justify-content: space-between; gap: 6px; padding: 2px 6px 6px; } .nav-group-title { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); } .nav-group-actions { display: inline-flex; gap: 4px; } .nav-add { border: 1px solid var(--border); background: var(--input); color: var(--ink-2); font-family: inherit; font-size: 10px; font-weight: 600; letter-spacing: 0.02em; padding: 3px 9px; border-radius: 999px; cursor: pointer; transition: background 0.14s, color 0.14s, border-color 0.14s; } .nav-add:hover { background: var(--accent-dim); border-color: var(--accent-border); color: var(--accent); } .nav-list { display: flex; flex-direction: column; } /* ── Zeichnungsebenen: einklappbare Kategorien (Geschosse/Schnitte/ Ansichten/2D-Zeichnungen) ──────────────────────────────────────────── */ .level-cat { display: flex; flex-direction: column; } .level-cat-head { display: flex; align-items: center; gap: 6px; min-height: 24px; padding: 3px 10px 3px 6px; background: var(--panel-2); border-bottom: 1px solid var(--line); cursor: pointer; user-select: none; } .level-cat-head:hover { background: var(--accent-dim); } .level-cat-chevron { flex: 0 0 auto; display: inline-flex; font-size: 9px; color: var(--muted); transition: transform 0.12s; transform: rotate(0deg); } .level-cat-chevron.open { transform: rotate(90deg); } .level-cat-title { flex: 1; min-width: 0; font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* Blankes „+"-Glyph: reines Zeichen, keine Button-Chrome. */ .level-cat-add { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; font-size: 13px; line-height: 1; color: var(--muted); cursor: pointer; } .level-cat-add:hover { color: var(--accent-light); } /* Zeile (Zeichnungsebene). */ .nav-row { display: flex; align-items: center; gap: 6px; width: 100%; min-height: 26px; padding: 2px 10px 2px 2px; border-bottom: 1px solid var(--line); background: transparent; color: var(--label); font-size: 12px; text-align: left; cursor: pointer; user-select: none; transition: background 0.12s; } .nav-row:hover { background: var(--panel-2); } /* Aktive Zeile = Petrol-Pille; Trennlinie verschwindet. */ .nav-row.active { background: var(--active-dim); border-radius: 999px; border-bottom-color: transparent; color: var(--active-light); } .nav-row.active .nav-label { font-weight: 600; color: var(--active-light); } /* Ausgeblendete (nicht-aktive) Zeile: gedimmt. */ .nav-row.hidden { opacity: 0.45; } .nav-label { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--label); font-weight: 500; } .nav-elev { flex: 0 0 auto; font-family: var(--font-mono); font-size: 10px; color: var(--muted); } /* Augen-Schalter (Sichtbarkeit) — erbt Zeilenfarbe via currentColor. */ .eye { flex: 0 0 auto; width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center; border: none; background: transparent; color: var(--muted); cursor: pointer; border-radius: 50%; padding: 0; transition: background 0.12s, color 0.12s; } .eye:hover { background: rgba(0, 0, 0, 0.06); color: var(--ink); } .eye.is-on { color: var(--ink); } .nav-row.active .eye, .nav-row.active .eye.is-on { color: var(--active-light); } /* ── Kategorie-Badges (Chips) ────────────────────────────────────────── */ .chip { flex: 0 0 auto; font-size: 9px; font-weight: 600; letter-spacing: 0.06em; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border); background: var(--input); color: var(--ink-2); text-transform: uppercase; } .badge-floor { background: var(--active-dim); border-color: var(--accent-border); color: var(--active); } .badge-section { background: rgba(120, 90, 160, 0.14); border-color: rgba(120, 90, 160, 0.35); color: #6d4f93; } .badge-elevation { background: rgba(40, 120, 110, 0.14); border-color: rgba(40, 120, 110, 0.35); color: #2f7a6c; } .badge-drawing { background: rgba(181, 98, 30, 0.14); border-color: rgba(181, 98, 30, 0.35); color: #b5621e; } /* ── Ebenen-Baum (Kategorien) ────────────────────────────────────────── */ .cat-row { display: flex; align-items: center; gap: 6px; min-height: 24px; padding: 1px 10px 1px 6px; font-size: 12px; color: var(--label); border-bottom: 1px solid var(--line); cursor: default; user-select: none; transition: background 0.12s; } .cat-row:hover { background: var(--panel-2); } .cat-row { cursor: pointer; /* Zeile ist als „aktive Ebene wählen" klickbar */ } /* Aktive Ebene (Zeichen-Ziel): Akzentstreifen links + leichte Akzentfüllung. */ .cat-row.active { background: var(--accent-dim); box-shadow: inset 2px 0 0 var(--accent); } .cat-row.active .cat-name { color: var(--text, #e6e6e6); font-weight: 600; } .cat-row.hidden { opacity: 0.45; } /* Gesperrt (Modus „Andere grau & gesperrt"): gedämpft, Cursor signalisiert Nicht-Bearbeitbarkeit. Gilt für Ebenen- und Zeichnungsebenen-Zeilen. */ .cat-row.locked, .nav-row.locked { cursor: not-allowed; } .cat-row.locked .cat-name, .nav-row.locked .nav-label { font-style: italic; } .cat-code { flex: 0 0 auto; font-family: var(--font-mono); font-size: 9px; color: var(--muted); width: 20px; text-align: left; } .cat-swatch { flex: 0 0 auto; width: 12px; height: 12px; border-radius: 2px; border: 1px solid var(--border); } .cat-name { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 500; } /* ── Inhalt (rechts) ─────────────────────────────────────────────────── */ .content { flex: 1; display: flex; flex-direction: column; min-height: 0; min-width: 0; } /* Dokument-Tabs „Zeichnungen/Blätter" — Kopfzeile über der Zeichenfläche. Leiste auf Ebene 1 (--panel), der aktive Tab hebt sich auf Ebene 2 an und verschmilzt unten mit dem Grund der Zeichenfläche darunter (--bg), wie bei klassischen Dokument-Tabs. */ .drawing-tabs { display: flex; align-items: flex-end; gap: 2px; padding: 6px 10px 0; border-bottom: 1px solid var(--line); background: var(--panel); overflow-x: auto; scrollbar-width: thin; } .drawing-tab { border: 1px solid transparent; border-bottom: none; background: transparent; color: var(--muted); font-family: inherit; font-size: 12px; font-weight: 600; letter-spacing: 0.01em; padding: 7px 16px; border-radius: 8px 8px 0 0; cursor: pointer; white-space: nowrap; transition: background 0.14s, color 0.14s, border-color 0.14s; } .drawing-tab:hover { background: var(--panel-2); color: var(--ink); } .drawing-tab.active { background: var(--bg); border-color: var(--line); color: var(--ink); /* Nahtloser Übergang: die Unterkante verschwindet im Zeichenflächen-Grund. */ position: relative; top: 1px; } .drawing-tab-label { pointer-events: none; } /* Eine Ansicht füllt die Restfläche. */ .pane { position: relative; flex: 1; display: flex; flex-direction: column; min-height: 0; min-width: 0; overflow: hidden; } .pane-title { position: absolute; top: 12px; left: 12px; z-index: 2; font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); background: var(--accent-dim); border: 1px solid var(--accent-border); padding: 4px 9px; border-radius: 999px; } .placeholder { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; color: var(--muted); background: var(--panel); } .placeholder strong { color: var(--ink); font-size: 16px; } .placeholder span { font-size: 13px; max-width: 360px; text-align: center; line-height: 1.5; } /* Freie 2D-Zeichenfläche. */ .drawing-area { position: relative; flex: 1; min-height: 0; background: var(--bg); overflow: hidden; } .drawing-svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; } /* ── 3D-Viewport (Contract: Viewport3D rendert
) ── */ .viewport { position: relative; flex: 1; min-height: 0; overflow: hidden; } /* Anzeigegröße per CSS festnageln, entkoppelt von der Renderauflösung — verhindert die ResizeObserver-Wachstumsschleife auf HiDPI-Displays. */ .viewport canvas { position: absolute; inset: 0; display: block; width: 100% !important; height: 100% !important; } .viewport-fallback { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; padding: 24px; text-align: center; color: var(--muted); background: var(--panel); } .viewport-fallback strong { color: var(--ink); font-size: 15px; } .viewport-fallback span { max-width: 320px; font-size: 13px; line-height: 1.5; } .viewport-fallback code { font-family: var(--font-mono); background: var(--panel-2); padding: 1px 5px; border-radius: 4px; font-size: 12px; } /* ── Grundriss (SVG) ─────────────────────────────────────────────────── */ .plan-legend { position: absolute; bottom: 12px; left: 12px; z-index: 2; font-size: 11px; font-weight: 600; color: var(--muted); background: var(--accent-dim); border: 1px solid var(--accent-border); padding: 4px 9px; border-radius: 999px; } .plan-svg { flex: 1; min-height: 0; width: 100%; /* Die GESAMTE Zeichenfläche ist Papier (hell), nicht nur der Modell-Bereich: das SVG-Element-Backing füllt den sichtbaren Bereich unabhängig von Pan/Zoom (die .plan-bg-Rechteckfläche deckt nur die Modellgrenzen ab). */ background: var(--sheet); } .plan-bg { fill: var(--sheet); } /* CAD-typische Ecken: alle Plan-Striche gehren (miter) statt an dicken Ecken eine Stufe/Butt-Cap-Lücke zu zeigen. Der Miter-Grenzwert verhindert überlange Spitzen bei sehr spitzen Winkeln (dann kappen die Enden rund). Gilt für Poché-Umrisse (polygon), Wand-/Tür-/2D-Linien und Bögen gleichermaßen. */ .plan-svg polygon, .plan-svg polyline, .plan-svg line, .plan-svg path { stroke-linejoin: miter; stroke-linecap: round; stroke-miterlimit: 8; } /* Tür-/Fenster- + Referenz-Linien: NUR Farbe + fill hier. Strichstärke und Strichmuster kommen aus dem Modell in mm Papier und werden in PlanView inline gesetzt (vector-effect:non-scaling-stroke → papierkonstant beim Zoomen). Das Zeichenblatt ist IMMER hell (--sheet) → Plan-Tinte bleibt fix dunkel, unabhängig vom UI-Theme (sonst unsichtbar auf Weiß im Dark-Mode). */ .plan-svg .door-leaf { stroke: #1a1a1a; fill: none; } .plan-svg .door-swing { stroke: #1a1a1a; fill: none; } /* Anschlag-/Rahmenstriche der Tür (nur im Detailgrad „fein"). */ .plan-svg .door-frame { stroke: #1a1a1a; fill: none; } /* Glaslinien des Fensters (dünn, gedämpft — die Verglasung im Grundriss). */ .plan-svg .window-glass { stroke: #1a1a1a; fill: none; } /* Referenzlinie = Wand-Achslinie (Toggle „Referenzlinien"), gestrichelt. */ .plan-svg .wall-axis { stroke: var(--accent); fill: none; opacity: 0.85; } /* Auswahl-Hervorhebung (Links-Klick): Akzentkontur + leichte Füllung. */ .plan-svg .plan-selected { fill: var(--accent-dim); stroke: var(--accent); stroke-width: 2; vector-effect: non-scaling-stroke; } /* Hervorhebung selektierter 2D-Zeichenelemente (Mehrfach/Marquee): Akzentkontur über der Geometrie, keine Füllung. */ .plan-svg .plan-sel-draw { fill: none; stroke: var(--accent); stroke-width: 2.5; vector-effect: non-scaling-stroke; } /* Auswahl-Rechteck (Marquee, Links-Drag): gestrichelte Akzentkontur, leichte Füllung. Strichstärke + Strichmuster papierkonstant (non-scaling-stroke). Die Default-Variante (links→rechts, „einschließend") ist durchgezogen; die crossing-Variante (rechts→links, „berührend") gestrichelt — wie in CAD üblich. */ .plan-svg .plan-marquee { fill: var(--accent-dim); fill-opacity: 0.35; stroke: var(--accent); stroke-width: 1.25; vector-effect: non-scaling-stroke; } .plan-svg .plan-marquee-crossing { stroke-dasharray: 5 4; } /* Editier-Griffe (Grips) des selektierten Elements: gefüllte Akzent-Quadrate mit hellem Rand. Ziehbar (Treffer in PlanView per Bildschirm-Pixel). */ .plan-svg .plan-grip { fill: var(--accent-light); stroke: #fff; stroke-width: 1.5; vector-effect: non-scaling-stroke; } /* Kanten-/Seiten-Griffe (Edge Grips): dreieckiger Anfasser je Seite, Spitze nach außen. Gleiche Akzent-/Rand-Farben wie die Eckpunkt-Griffe. */ .plan-svg .plan-edge-grip { fill: var(--accent); stroke: #fff; stroke-width: 1.5; vector-effect: non-scaling-stroke; } /* ── Freie 2D-Zeichengeometrie (Drawing2D) ─────────────────────────────── Farbe kommt aus dem Modell (Kategorie/LineStyle) und wird in PlanView inline als stroke gesetzt; hier nur der Fallback + fill:none. */ .plan-svg .draw2d { /* Plan-Tinte fix dunkel: KEINE CSS-`stroke`-Regel hier — eine CSS-Property überstimmt sonst das inline gesetzte `stroke`-Presentation-Attribut, sodass im Dark-Mode `var(--ink)` (#edeef0, hell) gewänne und 2D-Linien auf dem hellen Papier (#f0f0f0) unsichtbar würden. Die Strichfarbe kommt deshalb ausschließlich aus dem Modell (Kategorie/LineStyle), inline in PlanView gesetzt, theme-unabhängig (generatePlan: dunkler Plan-Tinte-Default). */ fill: none; } /* Kontext-Konturen (importierte Höhenlinien): dezente Referenz-Linien. Die Strichfarbe wird in generatePlan inline gesetzt (gedämpftes Grau); hier nur fill:none + leichte Transparenz, damit sie hinter den Bauteilen ruhig bleiben. */ .plan-svg .context-line { fill: none; opacity: 0.7; } /* ── Zeichenwerkzeug-Overlay (Live-Vorschau, Stützpunkte, Snap, HUD) ───── Immer obenauf, nicht klickbar (pointer-events:none am in PlanView). */ .plan-svg .tool-preview-line { stroke: #8a8a8a; fill: none; stroke-width: 1.4; opacity: 0.95; } .plan-svg .tool-preview-fill { fill: var(--accent-dim); fill-opacity: 0.35; stroke: var(--accent-light); stroke-width: 1.25; } .plan-svg .tool-vertex { fill: var(--accent); stroke: #fff; stroke-width: 1; } .plan-svg .snap-glyph { fill: none; stroke: #ffcc44; stroke-width: 1.4; } .plan-svg .snap-glyph.snap-fill { fill: #ffcc44; } .plan-svg .snap-helper-line { stroke: #ffcc44; stroke-width: 1; stroke-dasharray: 4 4; opacity: 0.8; } .plan-svg .tool-hud { fill: var(--accent-light); paint-order: stroke; stroke: rgba(0, 0, 0, 0.55); stroke-width: 3px; font-family: var(--mono, ui-monospace, monospace); dominant-baseline: middle; } /* ── Modusleiste der Transformation (über der Mitte) ─────────────────────── */ .transform-bar { position: absolute; top: 12px; left: 50%; transform: translateX(-50%); z-index: 60; display: flex; align-items: center; gap: 10px; padding: 6px 10px; background: var(--panel, #1c2128); border: 1px solid var(--accent-border, #355); border-radius: 10px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45); font-size: 12px; user-select: none; } .transform-bar .tf-op { font-weight: 700; color: var(--accent-light, #6db5a4); } .transform-bar .tf-sep { width: 1px; align-self: stretch; background: var(--line, #333); } .transform-bar .tf-modes { display: flex; gap: 4px; } .transform-bar .tf-mode { display: inline-flex; align-items: center; gap: 5px; padding: 3px 8px; border-radius: 6px; border: 1px solid transparent; background: transparent; color: inherit; cursor: pointer; } .transform-bar .tf-mode:hover { background: var(--accent-dim); } .transform-bar .tf-mode.active { background: var(--accent); color: #fff; } .transform-bar .tf-key { display: inline-grid; place-items: center; width: 16px; height: 16px; border-radius: 4px; background: rgba(255, 255, 255, 0.14); font-weight: 700; font-size: 10px; } .transform-bar .tf-hint { opacity: 0.8; } .transform-bar .tf-cancel { border: none; background: transparent; color: inherit; cursor: pointer; opacity: 0.7; font-size: 13px; } .transform-bar .tf-cancel:hover { opacity: 1; } /* ── Snap-Menü (TopBar-Popover) ──────────────────────────────────────────── */ .snap-menu { position: relative; display: inline-flex; } .snap-popover { position: fixed; z-index: 200; min-width: 200px; padding: 6px; background: var(--panel, #1c2128); border: 1px solid var(--line, #333); border-radius: 8px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45); display: flex; flex-direction: column; gap: 2px; } .snap-row { display: flex; align-items: center; gap: 8px; padding: 4px 6px; font-size: 12px; border-radius: 5px; cursor: pointer; user-select: none; } .snap-row:hover { background: var(--accent-dim); } .snap-row input[type="checkbox"] { accent-color: var(--accent); } .snap-master { font-weight: 600; } .snap-field { justify-content: space-between; } .snap-field input, .snap-field select { width: 84px; } .snap-sep { height: 1px; margin: 4px 2px; background: var(--line, #333); } /* ── Kamera-Einstellungen (Popover in der Ansicht-3D-Gruppe) ─────────── */ .tb-popwrap { position: relative; display: inline-flex; } .tb-popover { position: fixed; z-index: 200; min-width: 200px; padding: 10px; background: var(--panel, #1c2128); border: 1px solid var(--line, #333); border-radius: 8px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45); } .tb-poprow { display: flex; flex-direction: column; gap: 6px; } .tb-poprow input[type="range"] { width: 100%; accent-color: var(--accent); } /* ── Fehlerseite (ErrorBoundary) ─────────────────────────────────────── */ .error-screen { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; height: 100%; padding: 40px; text-align: center; } .error-screen pre { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 12px 16px; color: #b42318; font-size: 13px; max-width: 90%; overflow: auto; } .error-screen button { border: 1px solid var(--accent); background: var(--accent); color: white; border-radius: 999px; padding: 8px 18px; font-size: 14px; cursor: pointer; } /* ── Ressourcen-Manager (schwebendes Fenster / Overlay) ─────────────────── Drei Tabs (Bauteile / Schraffuren / Linien). Dunkles DOSSIER-Look: abgesetzte Sektionen, Pill-Inputs, Petrol-Akzent für aktive Elemente. Schwebt ÜBER allem (hoher z-index, über dem Kontextmenü ~300) mit abgedunkeltem Hintergrund; Klick auf den Hintergrund schließt. */ .res-overlay { position: fixed; inset: 0; z-index: 1000; background: var(--overlay); display: flex; justify-content: flex-end; } .res-drawer { width: min(880px, 94vw); height: 100%; display: flex; flex-direction: column; background: var(--panel); border-left: 1px solid var(--border); box-shadow: var(--shadow-3); } /* Frei schwebendes, NICHT-modales Ressourcen-Fenster (kein Backdrop): schwebt über dem Grundriss, der dahinter bedienbar bleibt. Position/Größe kommen als Inline-Style; die Kopfzeile (res-head) ist der Verschiebegriff. */ .res-window { position: fixed; z-index: 700; display: flex; flex-direction: column; background: var(--panel); border: 1px solid var(--line); border-radius: 8px; box-shadow: var(--shadow-3, 0 12px 32px rgba(0, 0, 0, 0.45)); overflow: hidden; } .res-window .res-head { cursor: move; touch-action: none; user-select: none; } /* Greifer unten rechts: nutzt .floating-resize (siehe unten), sitzt aber im overflow:hidden-Fenster korrekt in der Ecke. */ .res-window .res-resize { z-index: 1; } /* Kopf der Schublade. */ .res-head { display: flex; align-items: center; justify-content: space-between; padding: 0 16px; height: 52px; flex: 0 0 auto; border-bottom: 1px solid var(--line); background: var(--bg); } .res-head-title { display: inline-flex; align-items: center; gap: 9px; font-weight: 650; font-size: 15px; letter-spacing: 0.2px; color: var(--ink); } .res-head-icon { display: inline-flex; color: var(--accent); } .res-close { width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center; border: none; background: transparent; color: var(--muted); font-size: 22px; line-height: 1; border-radius: 50%; cursor: pointer; transition: background 0.12s, color 0.12s; } .res-close:hover { background: var(--panel-2); color: var(--ink); } /* Tab-Leiste. */ .res-tabs { display: flex; gap: 4px; padding: 10px 16px 0; flex: 0 0 auto; border-bottom: 1px solid var(--line); background: var(--bg); } .res-tab-btn { border: 1px solid transparent; border-bottom: none; background: transparent; color: var(--muted); font-family: inherit; font-size: 12px; font-weight: 600; letter-spacing: 0.03em; padding: 8px 16px; border-radius: 8px 8px 0 0; cursor: pointer; transition: background 0.14s, color 0.14s, border-color 0.14s; } .res-tab-btn:hover { background: var(--accent-dim); color: var(--ink); } .res-tab-btn.active { background: var(--panel); border-color: var(--line); color: var(--accent); margin-bottom: -1px; } /* Scrollbarer Körper. */ .res-body { flex: 1; min-height: 0; overflow-y: auto; padding: 14px 16px 20px; } .res-tab { display: flex; flex-direction: column; gap: 12px; } .res-hint { font-size: 11px; font-style: italic; color: var(--muted); line-height: 1.4; } /* ── Wandstile: ein Block je Wandtyp (Überschrift + Schicht-/Fugen-Tabelle) ─── */ .res-wallstyle { display: flex; flex-direction: column; gap: 6px; } .res-wallstyle-head { font-size: 12px; font-weight: 600; color: var(--text); padding: 2px 2px 0; } /* Innerste Schicht: keine innere Fuge → gedämpfter Platzhalter statt Dropdown. */ .res-joint-none { color: var(--muted); padding-left: 4px; } /* ── Tabelle (saubere Liste, CONVENTIONS.md) ────────────────────────────────── Ein CSS-Grid trägt die Spalten (gridTemplateColumns wird je Tab inline gesetzt). Kopfzeile und Datenzeilen sind `display:contents`, damit ihre Zellen direkte Grid-Kinder werden und exakt fluchten. */ .res-table { display: grid; align-items: center; column-gap: 8px; row-gap: 2px; border: 1px solid var(--border); border-radius: 10px; background: var(--panel-2); overflow: hidden; } /* Kopf- und Datenzeile lösen sich auf — ihre Zellen sind Grid-Kinder. */ .res-thead, .res-tr { display: contents; } /* Sticky Kopfzeile: jede Titel-Zelle klebt am oberen Rand des Scrollbereichs (.res-body). Da Zellen einzelne Grid-Kinder sind, wird sticky je Zelle gesetzt; ein durchgehender Hintergrund verhindert Durchscheinen. */ .res-th { position: sticky; top: 0; z-index: 2; align-self: stretch; display: flex; align-items: center; padding: 7px 4px; font-size: 9px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--muted); background: var(--panel-2); border-bottom: 1px solid var(--border); } .res-th.num { justify-content: flex-end; } /* Erste/letzte Kopfzelle randvoll, damit die Sticky-Leiste durchläuft. */ .res-th:first-child { padding-left: 12px; } .res-th:last-child { padding-right: 12px; } /* Datenzeilen: dezente Trennlinie, Hover hebt die ganze Zeile leicht hervor. Die Trennlinie sitzt auf jeder Zelle, da die Zeile selbst kein Box hat. */ .res-td { display: flex; align-items: center; padding: 5px 4px; min-width: 0; } .res-td.num { justify-content: flex-end; } .res-td:first-child { padding-left: 12px; } .res-td:last-child { padding-right: 12px; } .res-tr:hover .res-td { background: var(--panel); } /* Verschneidungs-Rang (joinPriority) — die tragende Zelle hervorheben. */ .res-td.emphasis .res-input { font-weight: 700; color: var(--accent); border-color: var(--accent-border); background: var(--accent-dim); } /* Text-/Zahleneingabe (Pill). */ .res-input { font-family: var(--font); font-size: 12px; color: var(--ink); background: var(--input); border: 1px solid var(--border); border-radius: 999px; padding: 5px 11px; outline: none; width: 100%; transition: border-color 0.14s, box-shadow 0.14s, background 0.14s; } .res-input.mono { font-family: var(--font-mono); } .res-input.num { text-align: right; } .res-input:hover { border-color: var(--accent); background: var(--panel); } .res-input:focus { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-dim); } /* Pill-Dropdown — nativer Pfeil, Petrol-Hover. */ .res-select { appearance: none; -webkit-appearance: none; font-family: var(--font); font-size: 11px; font-weight: 500; letter-spacing: 0.02em; color: var(--ink); background-color: var(--input); background-image: url("data:image/svg+xml;utf8,"); background-repeat: no-repeat; background-position: right 10px center; border: 1px solid var(--border); border-radius: 999px; padding: 5px 26px 5px 12px; cursor: pointer; outline: none; width: 100%; min-width: 0; text-overflow: ellipsis; transition: border-color 0.14s, background-color 0.14s, box-shadow 0.14s; } .res-select:hover { border-color: var(--accent); background-color: var(--panel); } .res-select:focus { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-dim); } /* Farb-Swatch mit unsichtbarem nativem Picker darüber. */ .res-color { position: relative; display: block; width: 46px; height: 28px; border-radius: 999px; border: 1px solid var(--border); overflow: hidden; cursor: pointer; } .res-color:hover { border-color: var(--accent); } .res-color-swatch { position: absolute; inset: 0; box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.18); pointer-events: none; } .res-color input[type="color"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; border: none; padding: 0; margin: 0; cursor: pointer; background: transparent; } /* Linienstil-Vorschau (füllt die Vorschau-Zelle). */ .res-line-preview { width: 100%; min-width: 80px; height: 26px; background: var(--input); border: 1px solid var(--border); border-radius: 999px; padding: 0 8px; } /* ── Motiv-Editor (Custom-Linie / Kachel-Motiv) ─────────────────────────── */ .motif-editor { display: flex; flex-direction: column; gap: 8px; width: 100%; } .motif-canvas { width: 100%; height: auto; background: var(--input); border: 1px solid var(--border); border-radius: 6px; touch-action: none; cursor: crosshair; } .motif-frame { fill: none; stroke: var(--border); stroke-width: 1; } .motif-grid { stroke: var(--border); stroke-width: 0.5; opacity: 0.5; } .motif-axis { stroke: var(--ink-2); stroke-width: 0.75; stroke-dasharray: 3 3; opacity: 0.7; } .motif-path { stroke: var(--accent-light); stroke-width: 1.75; stroke-linejoin: round; stroke-linecap: round; } .motif-handle { fill: var(--input); stroke: var(--accent-light); stroke-width: 1.5; cursor: grab; } .motif-handle:hover { fill: var(--accent-light); } .motif-handle.is-drag { fill: var(--accent-light); cursor: grabbing; } .motif-controls { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } .motif-len { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink-2); } .motif-len input { width: 62px; } .motif-hint { font-size: 11px; color: var(--ink-2); opacity: 0.85; flex: 1 1 120px; line-height: 1.3; } .motif-preview { width: 100%; height: auto; background: var(--input); border: 1px solid var(--border); border-radius: 6px; } /* Löschen-Knopf (Mülleimer in der letzten Spalte, zentriert). */ .res-delete { flex: 0 0 auto; width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--border); background: var(--input); color: var(--muted); border-radius: 50%; cursor: pointer; transition: background 0.14s, color 0.14s, border-color 0.14s; } .res-delete:hover { background: var(--danger-light); border-color: var(--danger-light); color: #fff; } /* „+ Neu"-Knopf je Tab. */ .res-add-row { display: flex; padding-top: 2px; } .res-add { display: inline-flex; align-items: center; gap: 6px; border: 1px dashed var(--border); background: var(--input); color: var(--ink-2); font-family: inherit; font-size: 12px; font-weight: 600; letter-spacing: 0.02em; padding: 7px 16px; border-radius: 999px; cursor: pointer; transition: background 0.14s, color 0.14s, border-color 0.14s; } .res-add:hover { background: var(--accent-dim); border-color: var(--accent-border); color: var(--accent); } .res-add-plus { font-size: 15px; line-height: 1; } /* Leerer Zustand — überspannt alle Spalten der Tabelle. */ .res-empty { grid-column: 1 / -1; padding: 26px 16px; text-align: center; font-size: 12px; color: var(--muted); background: var(--panel-2); } /* ── Master-Detail (Schraffuren / Linien): Liste links, Detail rechts ──────── */ .res-md { display: grid; grid-template-columns: 240px 1fr; gap: 14px; align-items: start; min-height: 320px; } .res-md-list { display: flex; flex-direction: column; gap: 2px; padding: 6px; border: 1px solid var(--border); border-radius: 10px; background: var(--panel-2); max-height: 62vh; overflow-y: auto; } .res-md-row { display: flex; align-items: center; gap: 9px; width: 100%; padding: 6px 8px; border: 1px solid transparent; border-radius: 8px; background: transparent; color: var(--ink); font-family: inherit; font-size: 12px; text-align: left; cursor: pointer; transition: background 0.12s, border-color 0.12s; } .res-md-row:hover { background: var(--accent-dim); } .res-md-row.active { background: var(--accent-dim); border-color: var(--accent-border); color: var(--accent); } .res-md-row-thumb { flex: 0 0 auto; display: inline-flex; } .res-md-row-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 550; } /* Linien-Zeile: Name oben schmal, Swatch daneben rechts. */ .res-md-row-line .res-line-preview { flex: 0 0 auto; width: 150px; min-width: 0; } .res-md-listfoot { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 4px 2px; } .res-md-empty { padding: 22px 14px; text-align: center; font-size: 12px; color: var(--muted); } /* Detail-Panel (rechts). */ .res-md-detail { border: 1px solid var(--border); border-radius: 10px; background: var(--panel-2); min-height: 300px; } .res-md-detail-inner { display: flex; flex-direction: column; gap: 14px; padding: 14px 16px 18px; } .res-md-head { display: flex; align-items: center; gap: 10px; } .res-md-rename { flex: 1 1 auto; font-size: 13px; font-weight: 600; } .res-md-preview { display: flex; align-items: center; justify-content: center; padding: 16px; border: 1px solid var(--border); border-radius: 10px; background: var(--input); color: var(--ink); } .res-md-preview .res-line-preview { border: none; background: transparent; } /* Detail-Felder: Label links, Steuerelement rechts. */ .res-fields { display: flex; flex-direction: column; gap: 8px; } .res-field { display: grid; grid-template-columns: 120px 1fr; align-items: center; gap: 12px; } .res-field-label { font-size: 12px; color: var(--muted); } .res-field-control { display: flex; align-items: center; min-width: 0; } .res-field-control > * { min-width: 0; } /* Segmentierter Umschalter (Pillen-Gruppe). */ .res-seg { display: inline-flex; gap: 2px; padding: 2px; border: 1px solid var(--border); border-radius: 999px; background: var(--input); } .res-seg-btn { border: none; background: transparent; color: var(--muted); font-family: inherit; font-size: 11px; font-weight: 600; letter-spacing: 0.02em; padding: 4px 14px; border-radius: 999px; cursor: pointer; transition: background 0.12s, color 0.12s; } .res-seg-btn:hover { color: var(--ink); } .res-seg-btn.active { background: var(--accent); color: #fff; } /* Schraffur-Swatch (kleine Vorschau in Liste + große im Detail). */ .res-swatch { border-radius: 3px; } /* Modularer Linien-Segment-Editor (Strich / Punkt / Lücke). */ .line-seg-editor { display: flex; flex-direction: column; gap: 4px; align-items: flex-start; } .line-seg-row { display: flex; align-items: center; gap: 4px; } .line-seg-num { width: 56px; display: inline-flex; align-items: center; } .line-seg-dotlabel { color: var(--muted); font-variant-numeric: tabular-nums; padding-left: 4px; } .line-seg-add { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px; } /* ══ Panel-Chrome (Andockrahmen: Docks, Tabs, Panel-Rahmen) ═══════════════════ Der erweiterbare Rahmen: links/rechts je ein Dock mit Tab-Leiste und dem aktiven Panel. Greift dieselben Tokens wie die nav- und res-Klassen (dunkles DOSSIER- Look: Petrol-Akzent, Pill-Form, dezente Trennlinien). Die Breite trägt jedes Dock als CSS-Variable --dock-w (vom Dock-Component inline gesetzt). */ /* ── Dock (angedockte Spalte) ────────────────────────────────────────────── */ .dock { position: relative; flex: 0 0 var(--dock-w, 280px); width: var(--dock-w, 280px); display: flex; flex-direction: column; min-height: 0; min-width: 0; background: var(--panel); overflow: hidden; } /* Trennkante zum Inhalt: links rechts, rechts links. */ .dock-left { border-right: 1px solid var(--line); } .dock-right { border-left: 1px solid var(--line); } /* Während des Ziehens: keine Text-/Cursor-Flacker, weicher Cursor überall. */ .dock.resizing { user-select: none; cursor: col-resize; } /* Ziehgriff an der inneren Kante (eine schmale, unsichtbare Greiffläche mit sichtbarer Linie auf Hover/Drag). Liegt über dem Rand des Docks. Cursor = col-resize (horizontales Verschieben der Dock-Breite). */ .dock-resize { position: absolute; top: 0; bottom: 0; width: 7px; z-index: 5; cursor: col-resize; background: transparent; transition: background 0.12s; touch-action: none; } .dock-left .dock-resize { right: -3px; } .dock-right .dock-resize { left: -3px; } .dock-resize:hover, .dock.resizing .dock-resize { background: var(--accent-border); } /* ── Gestapelte Gruppen im Dock ──────────────────────────────────────────── */ /* Vertikaler Stapel der Gruppen; füllt den Dock-Körper. */ .dock-stack { flex: 1; display: flex; flex-direction: column; min-height: 0; min-width: 0; } /* Eine Gruppe = eigener Tab-Stapel (TabStrip + aktives Panel). Die Höhe ergibt sich aus flex-grow (= group.weight, inline gesetzt); flex-basis 0, damit nur die Gewichte zählen. */ .dock-group { flex: 1 1 0; display: flex; flex-direction: column; min-height: 0; min-width: 0; overflow: hidden; } /* Trennlinie zwischen gestapelten Gruppen (außer der ersten). */ .dock-group + .dock-group, .dock-group-resize + .dock-group { border-top: 1px solid var(--line); } /* Splitter zwischen zwei Gruppen: schmale Greiffläche, Cursor row-resize. */ .dock-group-resize { flex: 0 0 7px; margin: -3px 0; z-index: 4; cursor: row-resize; background: transparent; transition: background 0.12s; touch-action: none; } .dock-group-resize:hover { background: var(--accent-border); } /* ── Tab-Leiste (Dock-Kopf) ──────────────────────────────────────────────── */ .tabstrip { display: flex; gap: 4px; flex: 0 0 auto; padding: 8px 8px 0; border-bottom: 1px solid var(--line); background: var(--bg); overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; } /* Dünne, dezente Scrollleiste, wenn viele Tabs umlaufen (WebKit). */ .tabstrip::-webkit-scrollbar { height: 5px; } .tabstrip::-webkit-scrollbar-thumb { background: var(--border); border-radius: 999px; } .tab { flex: 0 0 auto; width: 34px; height: 30px; display: flex; align-items: center; justify-content: center; border: 1px solid transparent; border-bottom: none; background: transparent; color: var(--muted); font-family: inherit; padding: 0; border-radius: 8px 8px 0 0; cursor: pointer; transition: background 0.14s, color 0.14s, border-color 0.14s; } .tab svg { flex: 0 0 auto; } .tab:hover { background: var(--accent-dim); color: var(--ink); } .tab.active { background: var(--panel); border-color: var(--line); color: var(--accent); margin-bottom: -1px; } /* ── Panel-Rahmen (Kopf + scrollbarer Körper) ────────────────────────────── */ .panel-frame { flex: 1; display: flex; flex-direction: column; min-height: 0; min-width: 0; background: var(--panel); } .panel-frame-empty { /* Platzhalter, wenn kein Panel aktiv ist — nur Fläche, kein Inhalt. */ background: var(--panel); } .panel-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex: 0 0 auto; padding: 9px 12px; border-bottom: 1px solid var(--line); /* Panel-Kopf leicht angehoben (Ebene 2) → setzt sich vom Körper ab. */ background: var(--panel-2); } .panel-title { min-width: 0; font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .panel-body { flex: 1; min-height: 0; overflow-y: auto; padding: 10px 8px 16px; } /* ── Darstellungsmodus-Dropdown (kompaktes Pill, vgl. .res-select) ────────── */ .display-mode { flex: 0 0 auto; appearance: none; -webkit-appearance: none; max-width: 160px; font-family: var(--font); font-size: 10px; font-weight: 600; letter-spacing: 0.02em; color: var(--ink-2); background-color: var(--input); background-image: url("data:image/svg+xml;utf8,"); background-repeat: no-repeat; background-position: right 8px center; border: 1px solid var(--border); border-radius: 999px; padding: 4px 22px 4px 10px; cursor: pointer; outline: none; text-overflow: ellipsis; transition: border-color 0.14s, background-color 0.14s, color 0.14s, box-shadow 0.14s; } .display-mode:hover { border-color: var(--accent); color: var(--accent); background-color: var(--panel); } .display-mode:focus { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-dim); } /* ── Layout-Menü (Oberleiste: benannte Layouts sichern/laden) ─────────────── */ /* Kleines Pill-Dropdown im selben Stil wie .res-trigger; ein Aktions-Trigger, daher steht der angezeigte Wert immer auf „Layout …". */ .layout-menu { appearance: none; -webkit-appearance: none; font-family: var(--font); font-size: 11px; font-weight: 600; letter-spacing: 0.04em; color: var(--ink-2); background-color: var(--input); background-image: url("data:image/svg+xml;utf8,"); background-repeat: no-repeat; background-position: right 10px center; border: 1px solid var(--border); border-radius: 999px; padding: 6px 26px 6px 14px; cursor: pointer; outline: none; transition: border-color 0.14s, background-color 0.14s, color 0.14s, box-shadow 0.14s; } .layout-menu:hover { border-color: var(--accent-border); background-color: var(--accent-dim); color: var(--accent); } .layout-menu:focus { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-dim); } /* ── Eigenes Dropdown (Oberleiste) — Trigger + Popover im Kontextmenü-Stil ─── Ersetzt die nativen