// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2026 Karim Gabriele Varano
import { useState, useEffect } from 'react'
import Icon from './Icon'
import { BarToggle, BarButton, BAR_H } from './BarControls'
import {
  openLibrary, pickTextureFile, onMessage,
  renameLinetype, deleteLinetype, loadLinetypeDefaults, importLinetypeFile,
  renameHatch, deleteHatch, importHatchFile,
  listLibraryItems, addLibraryFile, updateLibraryItem, deleteLibraryItem,
  saveSelectionAsLibrary,
  saveRaumStil, deleteRaumStil, duplicateRaumStil, reorderRaumStile,
  saveStempelStil, deleteStempelStil, duplicateStempelStil, reorderStempelStile,
} from '../lib/rhinoBridge'

/* Field — Stack-Layout fuer komplexe Inputs (mehrere Felder nebeneinander) */
function Field({ label, hint, children, style }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 4,
                   padding: '6px 0', ...style }}>
      <span style={{ fontSize: 9, color: 'var(--text-muted)',
                     fontWeight: 500, letterSpacing: '0.06em',
                     textTransform: 'uppercase' }}>{label}</span>
      <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>{children}</div>
      {hint && (
        <span style={{ fontSize: 9, color: 'var(--text-muted)', lineHeight: 1.4 }}>
          {hint}
        </span>
      )}
    </div>
  )
}

/* InlineTextField — Label links, Text-Input rechts (kompakt) */
function InlineTextField({ label, value, onChange, placeholder, width = 240 }) {
  return (
    <div style={{ padding: '5px 0',
                   display: 'flex', alignItems: 'center', gap: 10 }}>
      <span style={{ flex: 1, fontSize: 11, color: 'var(--text-primary)' }}>
        {label}
      </span>
      <input type="text" value={value || ''}
        placeholder={placeholder || ''}
        onChange={(ev) => onChange(ev.target.value)}
        style={{ width, height: BAR_H, padding: '0 12px',
                  fontSize: 11 }} />
    </div>
  )
}

/* TextareaField — Label oben, mehrzeiliges Input darunter (full-width) */
function TextareaField({ label, value, onChange, rows = 3, placeholder }) {
  return (
    <div style={{ padding: '6px 0' }}>
      <div style={{ fontSize: 11, color: 'var(--text-primary)',
                     marginBottom: 4 }}>{label}</div>
      <textarea value={value || ''}
        placeholder={placeholder || ''}
        rows={rows}
        onChange={(ev) => onChange(ev.target.value)}
        style={{ width: '100%', boxSizing: 'border-box',
                  padding: '6px 12px',
                  fontSize: 11, fontFamily: 'var(--font)',
                  background: 'var(--bg-input)',
                  color: 'var(--text-primary)',
                  border: '1px solid var(--border)',
                  borderRadius: 12,
                  resize: 'vertical', outline: 'none',
                  lineHeight: 1.5 }} />
    </div>
  )
}

/* InlineNumberField — Label links, schmales Number-Input rechts (kompakt) */
function InlineNumberField({ label, hint, value, onChange, step, min, max, suffix }) {
  return (
    <div style={{ padding: '5px 0' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <span style={{ flex: 1, fontSize: 11, color: 'var(--text-primary)',
                        letterSpacing: '0.01em' }}>{label}</span>
        <input type="number" value={value ?? ''}
          step={step} min={min} max={max}
          onChange={(ev) => onChange(parseFloat(ev.target.value))}
          style={{ width: 80, height: BAR_H, padding: '0 10px',
                    fontSize: 11, textAlign: 'right' }} />
        {suffix && (
          <span style={{ width: 24, fontSize: 10, color: 'var(--text-muted)' }}>
            {suffix}
          </span>
        )}
      </div>
      {hint && (
        <div style={{ fontSize: 9, color: 'var(--text-muted)',
                       lineHeight: 1.4, marginTop: 3 }}>
          {hint}
        </div>
      )}
    </div>
  )
}

/* Pill-Tabs — gleicher Stil wie BarToggle aus der Oberleiste */
function TabBar({ tabs, active, onChange }) {
  return (
    <div style={{
      display: 'flex', gap: 4,
      padding: '8px 12px',
      borderBottom: '1px solid var(--border)',
    }}>
      {tabs.map(t => (
        <BarToggle key={t.key}
          label={t.label}
          active={active === t.key}
          onClick={() => onChange(t.key)} />
      ))}
    </div>
  )
}

/* LinetypePreview — SVG-Linie mit Strich-Segmenten. segments = [{length,type}]
   type ∈ Line/Space (manchmal auch Continuous-Ableitungen). Width in px;
   wir skalieren die Segmente damit das Gesamtmuster in width passt. */
function LinetypePreview({ segments, width = 120, height = 12 }) {
  if (!segments || segments.length === 0) {
    return (
      <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`}
            style={{ color: 'var(--text-primary)', display: 'block' }}>
        <line x1="0" y1={height/2} x2={width} y2={height/2}
              stroke="currentColor" strokeWidth="1" />
      </svg>
    )
  }
  // Dot hat length=0 — fuer Layout-Zwecke kleinen Pseudo-Wert
  const DOT_DRAW_LEN = 0.6
  const lenOf = (seg) => {
    const l = Math.abs(seg.length || 0)
    return seg.type === 'Dot' ? DOT_DRAW_LEN : l
  }
  const patternLen = segments.reduce((s, seg) => s + lenOf(seg), 0)
  if (patternLen <= 0) {
    return (
      <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`}
            style={{ color: 'var(--text-primary)', display: 'block' }}>
        <line x1="0" y1={height/2} x2={width} y2={height/2}
              stroke="currentColor" strokeWidth="1" />
      </svg>
    )
  }
  // Statt das Pattern auf die ganze Breite zu strecken: tilen mit fixer
  // Skala. Ziel: ca. 4-5 Pattern-Repetitions sichtbar, dann ist die
  // Sequenz auch bei kurzen Patterns (Dots) deutlich erkennbar.
  const TARGET_REPETITIONS = 4
  const scale = width / (patternLen * TARGET_REPETITIONS)
  const scaledPatternLen = patternLen * scale
  const repetitions = Math.ceil(width / scaledPatternLen) + 1
  const parts = []
  let x = 0
  let key = 0
  for (let r = 0; r < repetitions && x < width; r++) {
    for (const seg of segments) {
      const drawLen = lenOf(seg) * scale
      if (x >= width) break
      const x2 = Math.min(x + drawLen, width)
      if (seg.type === 'Line' && drawLen > 0) {
        parts.push(<line key={key++} x1={x} y1={height/2}
          x2={x2} y2={height/2}
          stroke="currentColor" strokeWidth="1.4"
          strokeLinecap="square" />)
      } else if (seg.type === 'Dot') {
        parts.push(<circle key={key++} cx={x + drawLen/2} cy={height/2}
          r={1.2} fill="currentColor" />)
      }
      x += drawLen
    }
  }
  return (
    <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`}
          style={{ color: 'var(--text-primary)', display: 'block' }}>
      {parts}
    </svg>
  )
}

/* LinetypeListRow — Zeile mit Name + Preview + selected-state */
function LinetypeListRow({ lt, isSelected, onSelect }) {
  return (
    <div onClick={onSelect}
      style={{
        display: 'flex', flexDirection: 'column',
        gap: 2,
        padding: '6px 10px',
        cursor: 'pointer',
        background: isSelected ? 'var(--accent-dim)' : 'transparent',
        borderLeft: '2px solid ' + (isSelected ? 'var(--accent)' : 'transparent'),
        transition: 'background 0.12s',
      }}
      onMouseEnter={(e) => {
        if (!isSelected) e.currentTarget.style.background = 'var(--bg-item-hover)'
      }}
      onMouseLeave={(e) => {
        if (!isSelected) e.currentTarget.style.background = 'transparent'
      }}>
      <span style={{ fontSize: 11, color: 'var(--text-primary)',
                      overflow: 'hidden', textOverflow: 'ellipsis',
                      whiteSpace: 'nowrap' }}>{lt.name || 'Unbenannt'}</span>
      <LinetypePreview segments={lt.segments} width={140} height={10} />
    </div>
  )
}

/* HatchPreview — rendert das ECHTE Hatch-Pattern (alle HatchLines mit
   Winkel/Offset/Dashes) als SVG-Tile. Solid/Gradient haben keine Lines.
   pixelsPerUnit skaliert das Pattern damit's im Tile gut sichtbar ist. */
function HatchPreview({ pattern, size = 28, pixelsPerUnit = 8 }) {
  const ft = (pattern.fillType || '').toLowerCase()
  const stroke = 'var(--text-primary)'
  const bg = 'var(--bg-input)'
  if (ft === 'solid') {
    return (
      <svg width={size} height={size}
            style={{ display: 'block', color: stroke }}>
        <rect x="0" y="0" width={size} height={size}
              fill="currentColor"
              stroke="var(--border-light)" strokeWidth="0.5" rx="2" />
      </svg>
    )
  }
  if (ft === 'gradient') {
    const id = 'gr_' + (pattern.index ?? 0)
    return (
      <svg width={size} height={size}
            style={{ display: 'block', color: stroke }}>
        <defs>
          <linearGradient id={id} x1="0" y1="0" x2="1" y2="1">
            <stop offset="0%" stopColor="currentColor" />
            <stop offset="100%" stopColor="currentColor" stopOpacity="0.2" />
          </linearGradient>
        </defs>
        <rect x="0" y="0" width={size} height={size}
              fill={`url(#${id})`}
              stroke="var(--border-light)" strokeWidth="0.5" rx="2" />
      </svg>
    )
  }
  // Lines: jede HatchLine ist eine Familie paralleler Linien, mit
  // Angle, BasePoint, Offset (zwischen Linien), Dashes (Strich/Lücke).
  const hls = pattern.hatchLines || []
  const clipId = 'hp_clip_' + (pattern.index ?? 0)
  const pieces = []
  let lineKey = 0
  // Tile-Mitte im SVG-Koordinatensystem
  const cx = size / 2
  const cy = size / 2
  hls.forEach((hl, hi) => {
    // SVG hat Y nach unten — Rhino-Pattern definiert Y nach oben.
    // Wir spiegeln nicht, weil's nur ein Visual ist; Rotation reicht.
    const a = hl.angle || 0           // rad
    const cosA = Math.cos(a)
    const sinA = Math.sin(a)
    // Perpendicular zur Linie:
    const perpX = -sinA
    const perpY =  cosA
    // Offset entlang perp + along — Rhino's Offset ist {X, Y} im
    // Pattern-Koord-System. Die Komponente PARALLEL zur Linien-Richtung
    // (entlang) entscheidet uebers Stagger (Strich-Versatz).
    const offX = hl.offX || 0
    const offY = hl.offY || 0
    // Spacing = Komponente von Offset SENKRECHT zur Linien-Richtung
    const spacing = Math.abs(offX * perpX + offY * perpY)
    const drawSpacing = Math.max(spacing * pixelsPerUnit, 1.5)
    // Stagger = Komponente von Offset PARALLEL zur Linien-Richtung
    const stagger = offX * cosA + offY * sinA
    const drawStagger = stagger * pixelsPerUnit
    // Dashes in Pixel
    const dashes = (hl.dashes || []).map(d => Math.abs(d) * pixelsPerUnit)
    const dashLen = dashes.reduce((s, d) => s + d, 0)
    const strokeDasharray = (dashes.length >= 2 && dashLen > 0.1)
      ? dashes.join(',') : undefined
    // Basis-Punkt in Pixel (von Tile-Center)
    const baseX = (hl.baseX || 0) * pixelsPerUnit
    const baseY = (hl.baseY || 0) * pixelsPerUnit
    // Wir zeichnen genug parallele Linien um Tile zu fuellen
    const halfDiag = size * 1.5  // overlap fuer rotate-clip
    const nLines = Math.ceil((size * 2.0) / drawSpacing) + 4
    const start = -Math.floor(nLines / 2)
    for (let i = 0; i < nLines; i++) {
      const k = start + i
      // Mittelpunkt dieser Linie: base + k*offset, vom Tile-Center aus
      // Wir setzen die Pattern-Origin in die Tile-Mitte.
      const mx = cx + baseX + k * (offX * pixelsPerUnit)
      const my = cy + baseY + k * (offY * pixelsPerUnit)
      // Linie streckt sich +-halfDiag entlang Linien-Richtung
      const x1 = mx - cosA * halfDiag
      const y1 = my - sinA * halfDiag
      const x2 = mx + cosA * halfDiag
      const y2 = my + sinA * halfDiag
      pieces.push(<line key={'l' + lineKey++}
        x1={x1} y1={y1} x2={x2} y2={y2}
        stroke="currentColor"
        strokeWidth="0.7"
        strokeDasharray={strokeDasharray} />)
    }
  })
  // Fallback wenn keine HatchLines kamen (Hatch ist 'Lines' aber leer)
  const hasLines = pieces.length > 0
  return (
    <svg width={size} height={size}
          style={{ display: 'block', color: stroke }}
          viewBox={`0 0 ${size} ${size}`}>
      <defs>
        <clipPath id={clipId}>
          <rect x="0" y="0" width={size} height={size} />
        </clipPath>
      </defs>
      <rect x="0" y="0" width={size} height={size}
            fill={bg}
            stroke="var(--border-light)" strokeWidth="0.5" rx="2" />
      <g clipPath={`url(#${clipId})`}>
        {hasLines ? pieces : (
          // Fallback: einzelne Diagonale alle 4 px
          Array.from({length: Math.ceil(size * 2 / 4)}, (_, i) => i * 4 - size)
            .map(i => (
              <line key={i} x1={i} y1="0" x2={i + size} y2={size}
                stroke="currentColor" strokeWidth="0.8" />
            ))
        )}
      </g>
    </svg>
  )
}

/* HatchListRow */
function HatchListRow({ hp, isSelected, onSelect }) {
  return (
    <div onClick={onSelect}
      style={{
        display: 'grid', gridTemplateColumns: '32px 1fr',
        alignItems: 'center', gap: 8,
        padding: '6px 10px',
        cursor: 'pointer',
        background: isSelected ? 'var(--accent-dim)' : 'transparent',
        borderLeft: '2px solid ' + (isSelected ? 'var(--accent)' : 'transparent'),
        transition: 'background 0.12s',
      }}
      onMouseEnter={(e) => {
        if (!isSelected) e.currentTarget.style.background = 'var(--bg-item-hover)'
      }}
      onMouseLeave={(e) => {
        if (!isSelected) e.currentTarget.style.background = 'transparent'
      }}>
      <HatchPreview pattern={hp} />
      <div style={{ minWidth: 0 }}>
        <div style={{ fontSize: 11, color: 'var(--text-primary)',
                       overflow: 'hidden', textOverflow: 'ellipsis',
                       whiteSpace: 'nowrap' }}>{hp.name || 'Unbenannt'}</div>
        <div style={{ fontSize: 9, color: 'var(--text-muted)' }}>{hp.fillType}</div>
      </div>
    </div>
  )
}

/* MaterialListRow — schmale Listen-Zeile links (ArchiCAD-Stil):
   Color-Swatch + Name + Source-Badge. Click selektiert. */
function MaterialListRow({ mat, isBuiltin, isSelected, onSelect }) {
  const isLibrary = mat.source === 'library'
  return (
    <div onClick={onSelect}
      style={{
        display: 'grid', gridTemplateColumns: '14px 1fr 14px',
        alignItems: 'center', gap: 6,
        padding: '4px 10px',
        cursor: 'pointer',
        background: isSelected ? 'var(--accent-dim)' : 'transparent',
        borderLeft: '2px solid ' + (isSelected ? 'var(--accent)' : 'transparent'),
        transition: 'background 0.12s',
      }}
      onMouseEnter={(e) => {
        if (!isSelected) e.currentTarget.style.background = 'var(--bg-item-hover)'
      }}
      onMouseLeave={(e) => {
        if (!isSelected) e.currentTarget.style.background = 'transparent'
      }}>
      <div style={{
        width: 14, height: 14, borderRadius: 3,
        background: mat.color || '#888888',
        border: '1px solid var(--border-light)',
      }} title={mat.color} />
      <span style={{
        fontSize: 11,
        color: isSelected ? 'var(--text-primary)' : 'var(--text-primary)',
        fontWeight: isSelected ? 500 : 400,
        overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
      }}>{mat.name || 'Unbenannt'}</span>
      <span style={{
        fontSize: 9, fontWeight: 600,
        color: isLibrary ? 'var(--accent)'
              : isBuiltin ? 'var(--text-muted)'
              : 'transparent',
        textAlign: 'center',
      }} title={isLibrary ? 'Library' : isBuiltin ? 'Builtin' : 'Lokal'}>
        {isLibrary ? 'L' : isBuiltin ? 'B' : ''}
      </span>
    </div>
  )
}

/* Slider — Pill-Track mit Accent-Fill, Wert rechts daneben */
function Slider({ label, value, onChange, min = 0, max = 1, step = 0.01,
                  display, disabled }) {
  const v = value ?? min
  const pct = ((v - min) / (max - min)) * 100
  return (
    <div style={{ padding: '4px 0' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <span style={{ flex: 1, fontSize: 11,
                        color: disabled ? 'var(--text-muted)' : 'var(--text-primary)' }}>
          {label}
        </span>
        <span style={{ fontSize: 10, color: 'var(--text-muted)',
                        fontFamily: 'var(--font-mono)', minWidth: 40,
                        textAlign: 'right' }}>
          {display !== undefined ? display : v.toFixed(2)}
        </span>
      </div>
      <input type="range"
        min={min} max={max} step={step} value={v}
        disabled={disabled}
        onChange={(ev) => onChange(parseFloat(ev.target.value))}
        style={{
          width: '100%', marginTop: 4,
          accentColor: 'var(--accent)',
          opacity: disabled ? 0.5 : 1,
        }} />
    </div>
  )
}

/* TextureSlot — Datei-Picker + Vorschau-Mini-Tile + Clear-Button.
   tex: {path: string} oder null */
function TextureSlot({ label, slot, tex, onChange, disabled }) {
  const hasPath = !!(tex && tex.path)
  const filename = hasPath ? tex.path.split('/').pop() : ''
  return (
    <div style={{ padding: '5px 0' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
        <div style={{
          width: 36, height: 36, borderRadius: 4,
          background: hasPath
            ? `url(file://${tex.path}) center/cover, var(--bg-input)`
            : 'var(--bg-input)',
          border: '1px solid var(--border)',
          flexShrink: 0,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          {!hasPath && (
            <Icon name="image" size={14}
                  style={{ color: 'var(--text-muted)', opacity: 0.5 }} />
          )}
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 11, color: 'var(--text-primary)',
                         letterSpacing: '0.01em' }}>{label}</div>
          <div style={{ fontSize: 9, color: 'var(--text-muted)',
                         marginTop: 2,
                         overflow: 'hidden', textOverflow: 'ellipsis',
                         whiteSpace: 'nowrap' }}
                title={hasPath ? tex.path : ''}>
            {hasPath ? filename : 'Keine Textur'}
          </div>
        </div>
        <BarButton icon="folder_open"
          onClick={() => pickTextureFile(slot)}
          title="Datei waehlen"
          disabled={disabled} />
        {hasPath && (
          <BarButton icon="close"
            onClick={() => onChange(null)}
            title="Textur entfernen"
            disabled={disabled} />
        )}
      </div>
    </div>
  )
}

/* DetailSection — Section-Header + Body, immer offen (collapsible spaeter) */
function DetailSection({ title, children }) {
  return (
    <div style={{ marginBottom: 14 }}>
      <div style={{
        fontSize: 9, fontWeight: 600,
        color: 'var(--text-muted)',
        letterSpacing: '0.08em', textTransform: 'uppercase',
        padding: '4px 0', marginBottom: 6,
        borderBottom: '1px solid var(--border-light)',
      }}>{title}</div>
      {children}
    </div>
  )
}

/* MaterialDetail — rechte Seite (ArchiCAD-Stil): editiert das aktuell
   ausgewaehlte Material. Material = REIN 3D (Color + PBR + Texturen).
   Section-Hatch (2D-Schnitt) wird via Ebenen-Settings am Layer gesetzt. */
function MaterialDetail({ mat, isBuiltin, onChange, onDelete }) {
  if (!mat) {
    return (
      <div style={{ padding: 40, textAlign: 'center',
                     color: 'var(--text-muted)', fontSize: 11 }}>
        Kein Material ausgewaehlt.
        <div style={{ marginTop: 8, fontSize: 10 }}>
          Wähle links oder lege ein neues an.
        </div>
      </div>
    )
  }
  const isLibrary = mat.source === 'library'
  return (
    <div style={{ padding: '12px 14px',
                   display: 'flex', flexDirection: 'column',
                   height: '100%', overflowY: 'auto' }}>
      {/* Identitaet */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 10,
                     marginBottom: 14 }}>
        <div style={{
          width: 56, height: 56, borderRadius: 8,
          background: mat.color || '#888888',
          border: '1px solid var(--border)',
          flexShrink: 0,
        }} />
        <div style={{ flex: 1, minWidth: 0 }}>
          <input type="text" value={mat.name || ''}
            onChange={(ev) => onChange({ ...mat, name: ev.target.value })}
            disabled={isBuiltin}
            placeholder="Material-Name"
            style={{ width: '100%', height: BAR_H, padding: '0 12px',
                      fontSize: 12, fontWeight: 500,
                      opacity: isBuiltin ? 0.7 : 1 }} />
          <div style={{ fontSize: 9, color: 'var(--text-muted)',
                         marginTop: 4, letterSpacing: '0.04em' }}>
            {isLibrary ? 'Aus Dossier-Library'
              : isBuiltin ? 'Eingebaut (Builtin)'
              : 'Lokales Material'}
          </div>
        </div>
        {!isBuiltin && onDelete && (
          <BarButton icon="delete" onClick={onDelete}
                      title="Material loeschen" />
        )}
      </div>

      <DetailSection title="Oberflächenfarbe">
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <input type="color" value={mat.color || '#888888'}
            onChange={(ev) => onChange({ ...mat, color: ev.target.value })}
            title="Farbe"
            style={{ width: 32, height: BAR_H, padding: 0, border: 'none',
                      background: 'transparent', cursor: 'pointer' }} />
          <input type="text"
            value={mat.color || '#888888'}
            onChange={(ev) => onChange({ ...mat, color: ev.target.value })}
            style={{ flex: 1, height: BAR_H, padding: '0 12px',
                      fontSize: 11, fontFamily: 'var(--font-mono)' }} />
        </div>
      </DetailSection>

      <DetailSection title="Texturen (3D-Render)">
        <TextureSlot label="Diffuse" slot="diffuse"
          tex={mat.textures?.diffuse}
          onChange={(t) => onChange({ ...mat, textures: {
            ...(mat.textures || {}), diffuse: t } })}
          disabled={isBuiltin} />
        <TextureSlot label="Bump / Normal" slot="bump"
          tex={mat.textures?.bump}
          onChange={(t) => onChange({ ...mat, textures: {
            ...(mat.textures || {}), bump: t } })}
          disabled={isBuiltin} />
        <TextureSlot label="Roughness" slot="roughness"
          tex={mat.textures?.roughness}
          onChange={(t) => onChange({ ...mat, textures: {
            ...(mat.textures || {}), roughness: t } })}
          disabled={isBuiltin} />
        <TextureSlot label="Transparenz (Alpha)" slot="transparency"
          tex={mat.textures?.transparency}
          onChange={(t) => onChange({ ...mat, textures: {
            ...(mat.textures || {}), transparency: t } })}
          disabled={isBuiltin} />
        <div style={{ marginTop: 4 }}>
          <InlineNumberField label="UV-Skalierung"
            value={mat.uvScaleM ?? 1.0}
            step={0.1} min={0.01} suffix="m"
            onChange={(v) => onChange({ ...mat, uvScaleM: v || 1.0 })}
            hint="1 Welt-Meter ≙ wieviel Textur-Tile" />
        </div>
      </DetailSection>

      <DetailSection title="Oberflächen-Eigenschaften (PBR)">
        <Slider label="Rauheit (Roughness)"
          value={mat.roughness ?? 0.7}
          onChange={(v) => onChange({ ...mat, roughness: v })}
          disabled={isBuiltin} />
        <Slider label="Reflexion"
          value={mat.reflection ?? 0.1}
          onChange={(v) => onChange({ ...mat, reflection: v })}
          disabled={isBuiltin} />
        <Slider label="Transparenz"
          value={mat.transparency ?? 0.0}
          onChange={(v) => onChange({ ...mat, transparency: v })}
          disabled={isBuiltin} />
        <Slider label="IoR (Brechungsindex)"
          value={mat.iorN ?? 1.0}
          min={1.0} max={2.5} step={0.01}
          display={(mat.iorN ?? 1.0).toFixed(2)}
          onChange={(v) => onChange({ ...mat, iorN: v })}
          disabled={isBuiltin} />
      </DetailSection>
    </div>
  )
}

export default function ProjectSettingsDialog({
  initial, onSave, onClose, embedded = false,
}) {
  const [tab, setTab] = useState('defaults')
  const [draft, setDraft] = useState(() => ({
    defaults:  { ...(initial.defaults || {}) },
    materials: [...(initial.materials || [])],
    project:   { ...(initial.project   || {}) },
  }))
  const setProject = (k, v) =>
    setDraft(d => ({ ...d, project: { ...(d.project || {}), [k]: v } }))
  const [selMat, setSelMat] = useState(() => {
    // Default-Auswahl: erstes Builtin wenn vorhanden, sonst erstes Local
    const b = initial.builtinMaterials || []
    if (b.length) return { kind: 'builtin', name: b[0].name }
    const m = initial.materials || []
    if (m.length) return { kind: 'local', idx: 0 }
    return null
  })
  const [matSearch, setMatSearch] = useState('')
  // Linetype + Hatch-Tabellen — initial aus params, danach via
  // TABLES_UPDATED Message vom Backend nach jeder CRUD-Op.
  const [linetypes, setLinetypes] = useState(initial.linetypes || [])
  const [hatches, setHatches] = useState(initial.hatchPatternsFull || [])
  const [selLt, setSelLt] = useState(null)
  const [selHt, setSelHt] = useState(null)
  const [libItems, setLibItems] = useState(initial.libraryItems || [])
  const [libRoot, setLibRoot] = useState(initial.libraryRoot || '')
  const [selLib, setSelLib] = useState(null)
  const builtin = initial.builtinMaterials || []
  // Raumstile-State: kommt von initial + wird per STATE-Refresh aktualisiert
  // wenn Backend CRUD-Op fertig ist. Drag-Reorder lokal + commit beim Drop.
  const [raumStile, setRaumStile] = useState(initial.raumStempelStile || [])
  const [dragStilIdx, setDragStilIdx] = useState(null)
  // Stempel-Stile (Bilanz-Stempel-Presets) — parallele Liste
  const [stempelStile, setStempelStile] = useState(initial.stempelStile || [])
  const [dragStempelIdx, setDragStempelIdx] = useState(null)
  const fontsList = initial.fonts || []

  // Aktuell ausgewaehltes Material aus Selection ableiten
  const selectedMat = (() => {
    if (!selMat) return null
    if (selMat.kind === 'builtin') return builtin.find(m => m.name === selMat.name) || null
    if (selMat.kind === 'local')   return draft.materials[selMat.idx] || null
    return null
  })()
  const selectedIsBuiltin = selMat?.kind === 'builtin'
  const updateSelected = (newMat) => {
    if (!selMat) return
    if (selMat.kind === 'local') {
      setMat(selMat.idx, newMat)
    }
    // builtin: Schreibend in Phase 1 nur Color/Hatch — Backend ignoriert
    // Name-Aenderungen. UI laesst diese sowieso disabled.
  }
  const deleteSelected = () => {
    if (selMat?.kind !== 'local') return
    delMat(selMat.idx)
    setSelMat(null)
  }

  // Linetype/Hatch-Tabelle nach Backend-CRUD aktualisieren
  useEffect(() => {
    onMessage('TABLES_UPDATED', ({ linetypes: lts, hatchPatternsFull: hps }) => {
      if (lts) setLinetypes(lts)
      if (hps) setHatches(hps)
    })
    onMessage('LIBRARY_ITEMS', ({ items, libraryRoot }) => {
      if (Array.isArray(items)) setLibItems(items)
      if (libraryRoot) setLibRoot(libraryRoot)
    })
    onMessage('LIBRARY_ERROR', ({ msg }) => {
      if (msg) alert(msg)
    })
    onMessage('STILE_UPDATED', ({ raumStempelStile }) => {
      if (Array.isArray(raumStempelStile)) setRaumStile(raumStempelStile)
    })
    onMessage('STEMPEL_STILE_UPDATED', ({ stempelStile: ss }) => {
      if (Array.isArray(ss)) setStempelStile(ss)
    })
  }, [])

  // Backend-File-Picker-Antwort: aktualisiert das Slot im aktuell
  // selektierten Material. Wenn path leer = User abgebrochen → no-op.
  useEffect(() => {
    onMessage('TEXTURE_PICKED', ({ slot, path }) => {
      if (!path || !selMat || selMat.kind !== 'local') return
      setDraft(d => ({
        ...d,
        materials: d.materials.map((m, i) => {
          if (i !== selMat.idx) return m
          const newTex = (m.textures && typeof m.textures === 'object')
            ? { ...m.textures } : {}
          newTex[slot] = { path }
          return { ...m, textures: newTex }
        }),
      }))
    })
  }, [selMat])
  // Suchbar — case-insensitive substring auf Name
  const matchSearch = (m) => {
    const q = matSearch.trim().toLowerCase()
    if (!q) return true
    return (m.name || '').toLowerCase().includes(q)
  }
  const filteredBuiltin = builtin.filter(matchSearch)
  const filteredLocal = draft.materials
    .map((m, i) => ({ m, i }))
    .filter(({ m }) => matchSearch(m))

  const setDefault = (k, v) =>
    setDraft(d => ({ ...d, defaults: { ...d.defaults, [k]: v } }))

  const setMat = (i, newMat) => setDraft(d => ({
    ...d, materials: d.materials.map((m, idx) => idx === i ? newMat : m),
  }))
  const delMat = (i) => setDraft(d => ({
    ...d, materials: d.materials.filter((_, idx) => idx !== i),
  }))
  const addMat = () => {
    setDraft(d => ({
      ...d,
      materials: [...d.materials, {
        name: 'Neues Material', color: '#aaaaaa',
        hatch: 'Solid', scale: 1.0,
        source: 'local', libraryId: null,
      }],
    }))
    // Direkt selektieren — User kann gleich editieren
    setSelMat({ kind: 'local', idx: draft.materials.length })
  }

  const wrapperStyle = embedded ? {
    width: '100%', height: '100%',
    background: 'var(--bg-dialog)',
    display: 'flex', flexDirection: 'column',
    overflow: 'hidden',
    fontFamily: 'var(--font)', color: 'var(--text-primary)', fontSize: 11,
  } : {
    position: 'absolute', inset: 0, zIndex: 150,
    background: 'var(--bg-overlay)',
    display: 'flex', alignItems: 'flex-start', justifyContent: 'center',
    paddingTop: 40,
  }
  return (
    <div style={wrapperStyle}>
      <div style={{ display: 'flex', flexDirection: 'column', flex: 1,
                     minHeight: 0, overflow: 'hidden' }}>
        <TabBar tabs={[
          { key: 'defaults',     label: 'Voreinstellungen' },
          { key: 'materials',    label: 'Materialien' },
          { key: 'linetypes',    label: 'Linientypen' },
          { key: 'hatches',      label: 'Schraffuren' },
          { key: 'symbols',      label: 'Symbole' },
          { key: 'raumstile',    label: 'Raumstile' },
          { key: 'stempelstile', label: 'Stempelstile' },
        ]} active={tab} onChange={setTab} />

        {/* Body */}
        <div style={{ flex: 1, minHeight: 0, overflowY: 'auto',
                       padding: '8px 14px' }}>
          {tab === 'defaults' && (
            <div style={{ maxWidth: 560 }}>
              <DetailSection title="Projektdaten">
                <InlineTextField label="Projektname"
                  value={draft.project?.name}
                  placeholder="z.B. Wohnhaus Müller"
                  onChange={(v) => setProject('name', v)} />
                <InlineTextField label="Projekt-Nr."
                  value={draft.project?.number}
                  placeholder="z.B. 2026-014"
                  width={140}
                  onChange={(v) => setProject('number', v)} />
                <TextareaField label="Adresse"
                  value={draft.project?.address}
                  placeholder="Strasse, PLZ Ort"
                  rows={2}
                  onChange={(v) => setProject('address', v)} />
                <InlineTextField label="Bauherrschaft"
                  value={draft.project?.bauherr}
                  onChange={(v) => setProject('bauherr', v)} />
                <InlineTextField label="Architekt:in"
                  value={draft.project?.architekt}
                  onChange={(v) => setProject('architekt', v)} />
                <InlineNumberField label="EG-Nullpunkt m.ü.M"
                  value={draft.project?.projectZeroMum ?? 0.0}
                  step={0.01} suffix="m"
                  onChange={(v) => setProject('projectZeroMum', v || 0.0)}
                  hint="Höhe von Rhino z=0 (= EG OKFF) über Meeresspiegel. Wird vom Swisstopo-Terrain-Import zur Kalibrierung verwendet." />
                <TextareaField label="Notizen"
                  value={draft.project?.notes}
                  rows={2}
                  onChange={(v) => setProject('notes', v)} />
              </DetailSection>
              <div style={{ fontSize: 10, color: 'var(--text-muted)',
                             padding: '6px 0 10px', lineHeight: 1.5 }}>
                Voreinstellungen fuer neue Elemente. Pro-Element editierte
                Werte bleiben davon unberuehrt.
              </div>
              <DetailSection title="Arbeitseinheit">
                <div style={{ padding: '5px 0',
                               display: 'flex', alignItems: 'center', gap: 6 }}>
                  <span style={{ flex: 1, fontSize: 11,
                                  color: 'var(--text-primary)' }}>
                    Einheit
                  </span>
                  <div style={{ display: 'flex', gap: 3 }}>
                    {[
                      { code: 'meters',      label: 'Meter (m)' },
                      { code: 'centimeters', label: 'cm' },
                      { code: 'millimeters', label: 'mm' },
                    ].map(u => (
                      <BarToggle key={u.code} label={u.label}
                        active={(draft.defaults.unit || 'meters') === u.code}
                        onClick={() => setDefault('unit', u.code)}
                        title={`Doc-Unit auf ${u.label} einstellen`} />
                    ))}
                  </div>
                </div>
                <div style={{ fontSize: 9, color: 'var(--text-muted)',
                               lineHeight: 1.4, padding: '2px 0 4px' }}>
                  Wenn ein geoeffnetes Doc nicht in dieser Einheit ist, fragt
                  DOSSIER ob umgestellt werden soll. Architektur-Standard: Meter.
                </div>
              </DetailSection>
              <DetailSection title="Geschoss">
                <InlineNumberField label="Standard-Geschosshöhe"
                  value={draft.defaults.geschossHoehe ?? 3.0}
                  step={0.05} min={1.0} max={10} suffix="m"
                  onChange={(v) => setDefault('geschossHoehe', v || 3.0)}
                  hint="Vorgabe fuer neue Geschosse — pro Geschoss ueberschreibbar" />
                <InlineNumberField label="Standard-Schnitthöhe"
                  value={draft.defaults.schnitthoehe ?? 1.0}
                  step={0.05} min={0.1} max={3} suffix="m"
                  onChange={(v) => setDefault('schnitthoehe', v || 1.0)}
                  hint="Höhe der horizontalen Schnitt-Plane über OKFF eines Geschosses" />
              </DetailSection>
              <DetailSection title="Schnitte / Ansichten">
                <InlineNumberField label="Standard-Tiefe hinten"
                  value={draft.defaults.schnittDepthBack ?? 8.0}
                  step={0.5} min={0.5} suffix="m"
                  onChange={(v) => setDefault('schnittDepthBack', v || 8.0)}
                  hint="Default-Tiefe fuer neue Schnitte/Ansichten" />
                <InlineNumberField label="Höhe unten"
                  value={draft.defaults.schnittHeightMin ?? -1.0}
                  step={0.1} suffix="m"
                  onChange={(v) => setDefault('schnittHeightMin', v)} />
                <InlineNumberField label="Höhe oben"
                  value={draft.defaults.schnittHeightMax ?? 12.0}
                  step={0.1} suffix="m"
                  onChange={(v) => setDefault('schnittHeightMax', v)} />
              </DetailSection>
            </div>
          )}

          {tab === 'materials' && (
            <div style={{ display: 'flex', height: '100%',
                           margin: '-8px -14px',  /* Tab-Padding aufheben */
                           minHeight: 0 }}>
              {/* Links: Liste */}
              <div style={{
                width: 240, flexShrink: 0,
                display: 'flex', flexDirection: 'column',
                borderRight: '1px solid var(--border)',
                background: 'var(--bg-dialog)',
              }}>
                <div style={{ padding: '8px 10px',
                               borderBottom: '1px solid var(--border-light)' }}>
                  <input type="text" value={matSearch}
                    onChange={(ev) => setMatSearch(ev.target.value)}
                    placeholder="Suchen…"
                    style={{ width: '100%', height: BAR_H,
                              padding: '0 12px', fontSize: 11,
                              boxSizing: 'border-box' }} />
                </div>
                <div style={{ flex: 1, overflowY: 'auto',
                               padding: '4px 0' }}>
                  {filteredBuiltin.length > 0 && (
                    <div style={{ fontSize: 8, fontWeight: 600,
                                   color: 'var(--text-muted)',
                                   padding: '6px 12px 2px',
                                   letterSpacing: '0.1em',
                                   textTransform: 'uppercase' }}>
                      Eingebaut
                    </div>
                  )}
                  {filteredBuiltin.map((m) => (
                    <MaterialListRow key={'b_' + m.name}
                      mat={m} isBuiltin
                      isSelected={selMat?.kind === 'builtin' && selMat.name === m.name}
                      onSelect={() => setSelMat({ kind: 'builtin', name: m.name })} />
                  ))}
                  {filteredLocal.length > 0 && (
                    <div style={{ fontSize: 8, fontWeight: 600,
                                   color: 'var(--text-muted)',
                                   padding: '10px 12px 2px',
                                   letterSpacing: '0.1em',
                                   textTransform: 'uppercase' }}>
                      Projekt
                    </div>
                  )}
                  {filteredLocal.map(({ m, i }) => (
                    <MaterialListRow key={'u_' + i}
                      mat={m}
                      isSelected={selMat?.kind === 'local' && selMat.idx === i}
                      onSelect={() => setSelMat({ kind: 'local', idx: i })} />
                  ))}
                  {filteredBuiltin.length === 0 && filteredLocal.length === 0 && (
                    <div style={{ padding: 20, textAlign: 'center',
                                   color: 'var(--text-muted)', fontSize: 10 }}>
                      Nichts gefunden.
                    </div>
                  )}
                </div>
                <div style={{ display: 'flex', gap: 4,
                               padding: '6px 8px',
                               borderTop: '1px solid var(--border-light)' }}>
                  <BarToggle icon="add" onClick={addMat}
                    title="Neues Material" />
                  <BarToggle icon="inventory_2" onClick={openLibrary}
                    title="Aus Library importieren" />
                </div>
              </div>
              {/* Rechts: Detail */}
              <div style={{ flex: 1, minWidth: 0, overflow: 'hidden' }}>
                <MaterialDetail
                  mat={selectedMat}
                  isBuiltin={selectedIsBuiltin}
                  onChange={updateSelected}
                  onDelete={selMat?.kind === 'local' ? deleteSelected : null} />
              </div>
            </div>
          )}

          {tab === 'linetypes' && (
            <div style={{ display: 'flex', height: '100%',
                           margin: '-8px -14px', minHeight: 0 }}>
              <div style={{
                width: 240, flexShrink: 0,
                display: 'flex', flexDirection: 'column',
                borderRight: '1px solid var(--border)',
                background: 'var(--bg-dialog)',
              }}>
                <div style={{ flex: 1, overflowY: 'auto',
                               padding: '4px 0' }}>
                  {linetypes.length === 0 && (
                    <div style={{ padding: 20, textAlign: 'center',
                                   color: 'var(--text-muted)', fontSize: 10 }}>
                      Keine Linientypen geladen.
                    </div>
                  )}
                  {linetypes.map((lt) => (
                    <LinetypeListRow key={lt.index}
                      lt={lt}
                      isSelected={selLt === lt.index}
                      onSelect={() => setSelLt(lt.index)} />
                  ))}
                </div>
                <div style={{ display: 'flex', gap: 4,
                               padding: '6px 8px',
                               borderTop: '1px solid var(--border-light)' }}>
                  <BarToggle icon="upload_file" onClick={importLinetypeFile}
                    title="Aus .lin-Datei importieren" />
                  <BarToggle icon="refresh" onClick={loadLinetypeDefaults}
                    title="Rhino-Defaults laden" />
                </div>
              </div>
              <div style={{ flex: 1, minWidth: 0, overflow: 'hidden',
                             padding: '12px 14px', overflowY: 'auto' }}>
                {(() => {
                  const lt = linetypes.find(x => x.index === selLt)
                  if (!lt) return (
                    <div style={{ padding: 40, textAlign: 'center',
                                   color: 'var(--text-muted)', fontSize: 11 }}>
                      Linientyp links auswählen.
                    </div>
                  )
                  return (
                    <>
                      <DetailSection title="Identität">
                        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                          <input type="text" value={lt.name}
                            onChange={(ev) => {
                              const newName = ev.target.value
                              setLinetypes(arr => arr.map(x =>
                                x.index === lt.index ? { ...x, name: newName } : x))
                            }}
                            onBlur={(ev) => renameLinetype(lt.index, ev.target.value)}
                            style={{ flex: 1, height: BAR_H, padding: '0 12px',
                                      fontSize: 12, fontWeight: 500 }} />
                          {!lt.isContinuous && (
                            <BarButton icon="delete"
                              onClick={() => { deleteLinetype(lt.index); setSelLt(null) }}
                              title="Linientyp löschen" />
                          )}
                        </div>
                      </DetailSection>
                      <DetailSection title="Vorschau">
                        <div style={{ padding: '8px 12px',
                                       background: 'var(--bg-section)',
                                       borderRadius: 4 }}>
                          <LinetypePreview segments={lt.segments}
                                            width={280} height={16} />
                        </div>
                      </DetailSection>
                      {lt.segments.length > 0 && (
                        <DetailSection title="Segmente">
                          <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)',
                                         color: 'var(--text-muted)',
                                         lineHeight: 1.6 }}>
                            {lt.segments.map((s, i) => (
                              <div key={i}>
                                {String(i+1).padStart(2, '0')} —
                                {' '}{s.type.padEnd(10)}
                                {' '}{s.length.toFixed(3)}
                              </div>
                            ))}
                          </div>
                        </DetailSection>
                      )}
                    </>
                  )
                })()}
              </div>
            </div>
          )}

          {tab === 'hatches' && (
            <div style={{ display: 'flex', height: '100%',
                           margin: '-8px -14px', minHeight: 0 }}>
              <div style={{
                width: 240, flexShrink: 0,
                display: 'flex', flexDirection: 'column',
                borderRight: '1px solid var(--border)',
                background: 'var(--bg-dialog)',
              }}>
                <div style={{ flex: 1, overflowY: 'auto',
                               padding: '4px 0' }}>
                  {hatches.length === 0 && (
                    <div style={{ padding: 20, textAlign: 'center',
                                   color: 'var(--text-muted)', fontSize: 10 }}>
                      Keine Schraffuren geladen.
                    </div>
                  )}
                  {hatches.map((hp) => (
                    <HatchListRow key={hp.index}
                      hp={hp}
                      isSelected={selHt === hp.index}
                      onSelect={() => setSelHt(hp.index)} />
                  ))}
                </div>
                <div style={{ display: 'flex', gap: 4,
                               padding: '6px 8px',
                               borderTop: '1px solid var(--border-light)' }}>
                  <BarToggle icon="upload_file" onClick={importHatchFile}
                    title="Aus .pat-Datei importieren" />
                </div>
              </div>
              <div style={{ flex: 1, minWidth: 0, overflow: 'hidden',
                             padding: '12px 14px', overflowY: 'auto' }}>
                {(() => {
                  const hp = hatches.find(x => x.index === selHt)
                  if (!hp) return (
                    <div style={{ padding: 40, textAlign: 'center',
                                   color: 'var(--text-muted)', fontSize: 11 }}>
                      Schraffur links auswählen.
                    </div>
                  )
                  return (
                    <>
                      <DetailSection title="Identität">
                        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                          <HatchPreview pattern={hp} size={36} />
                          <input type="text" value={hp.name}
                            onChange={(ev) => {
                              const newName = ev.target.value
                              setHatches(arr => arr.map(x =>
                                x.index === hp.index ? { ...x, name: newName } : x))
                            }}
                            onBlur={(ev) => renameHatch(hp.index, ev.target.value)}
                            style={{ flex: 1, height: BAR_H, padding: '0 12px',
                                      fontSize: 12, fontWeight: 500 }} />
                          <BarButton icon="delete"
                            onClick={() => { deleteHatch(hp.index); setSelHt(null) }}
                            title="Schraffur löschen" />
                        </div>
                        <div style={{ fontSize: 9, color: 'var(--text-muted)',
                                       marginTop: 4 }}>
                          Typ: {hp.fillType}
                          {hp.isReference && ' · importiert'}
                        </div>
                      </DetailSection>
                      {hp.description && (
                        <DetailSection title="Beschreibung">
                          <div style={{ fontSize: 10,
                                         color: 'var(--text-muted)',
                                         lineHeight: 1.5 }}>
                            {hp.description}
                          </div>
                        </DetailSection>
                      )}
                      <DetailSection title="Verwendung">
                        <div style={{ fontSize: 10, color: 'var(--text-muted)',
                                       lineHeight: 1.5 }}>
                          Schraffuren werden ueber das Gestaltung-Panel
                          oder via Layer Section-Hatch im Ebenen-Editor
                          auf Objekte/Layer angewendet.
                        </div>
                      </DetailSection>
                    </>
                  )
                })()}
              </div>
            </div>
          )}

          {tab === 'symbols' && (
            <div style={{ display: 'flex', height: '100%',
                           margin: '-8px -14px', minHeight: 0 }}>
              {/* Links: Items-Liste */}
              <div style={{
                width: 240, flexShrink: 0,
                display: 'flex', flexDirection: 'column',
                borderRight: '1px solid var(--border)',
                background: 'var(--bg-dialog)',
              }}>
                <div style={{ flex: 1, overflowY: 'auto', padding: '4px 0' }}>
                  {libItems.length === 0 && (
                    <div style={{ padding: 20, textAlign: 'center',
                                   color: 'var(--text-muted)', fontSize: 10 }}>
                      Noch keine Symbole/Objekte.
                      <div style={{ marginTop: 6 }}>
                        Erstes Item via ⬇ unten hinzufügen.
                      </div>
                    </div>
                  )}
                  {libItems.map((it) => {
                    const isSel = selLib === it.id
                    return (
                      <div key={it.id}
                        onClick={() => setSelLib(it.id)}
                        style={{
                          display: 'grid',
                          gridTemplateColumns: '32px 1fr',
                          alignItems: 'center', gap: 8,
                          padding: '5px 10px',
                          cursor: 'pointer',
                          background: isSel ? 'var(--accent-dim)' : 'transparent',
                          borderLeft: '2px solid ' + (isSel ? 'var(--accent)' : 'transparent'),
                          transition: 'background 0.12s',
                        }}
                        onMouseEnter={(e) => {
                          if (!isSel) e.currentTarget.style.background = 'var(--bg-item-hover)'
                        }}
                        onMouseLeave={(e) => {
                          if (!isSel) e.currentTarget.style.background = 'transparent'
                        }}>
                        <div style={{
                          width: 32, height: 32, borderRadius: 4,
                          background: it.previewDataUri
                            ? `url("${it.previewDataUri}") center/contain no-repeat, var(--bg-input)`
                            : 'var(--bg-input)',
                          border: '1px solid var(--border-light)',
                          display: 'flex', alignItems: 'center', justifyContent: 'center',
                          flexShrink: 0,
                        }}>
                          {!it.previewDataUri && (
                            <Icon name={it.type === 'symbol' ? 'navigation' : 'forest'}
                                  size={14}
                                  style={{ color: 'var(--text-muted)' }} />
                          )}
                        </div>
                        <div style={{ minWidth: 0 }}>
                          <div style={{ fontSize: 11,
                                         color: 'var(--text-primary)',
                                         overflow: 'hidden',
                                         textOverflow: 'ellipsis',
                                         whiteSpace: 'nowrap' }}>
                            {it.name || 'Unbenannt'}
                          </div>
                          <div style={{ fontSize: 9,
                                         color: 'var(--text-muted)' }}>
                            {(it.files2d || []).length > 0 ? '2D ' : ''}
                            {(it.files3d || []).length > 0 ? '3D' : ''}
                            {!(it.files2d || []).length && !(it.files3d || []).length && '— leer'}
                          </div>
                        </div>
                      </div>
                    )
                  })}
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 4,
                               padding: '6px 8px',
                               borderTop: '1px solid var(--border-light)' }}>
                  <BarToggle icon="upload_file" label="Aus Datei"
                    onClick={() => addLibraryFile('2d', null, 'object')}
                    title=".3dm-Datei waehlen → kopiert in Library + neues Item" />
                  <BarToggle icon="add_to_photos" label="Aus Auswahl"
                    onClick={() => saveSelectionAsLibrary('2d', null, 'object')}
                    title="Selektierte Objekte in Rhino als Library-Item speichern" />
                </div>
              </div>

              {/* Rechts: Item-Detail */}
              <div style={{ flex: 1, minWidth: 0, overflow: 'hidden',
                             padding: '12px 14px', overflowY: 'auto' }}>
                {(() => {
                  const it = libItems.find(x => x.id === selLib)
                  if (!it) return (
                    <div style={{ padding: 40, textAlign: 'center',
                                   color: 'var(--text-muted)', fontSize: 11 }}>
                      Item links auswählen oder neues anlegen.
                    </div>
                  )
                  return (
                    <>
                      <DetailSection title="Identität">
                        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                          <div style={{
                            width: 56, height: 56, borderRadius: 6,
                            background: it.previewDataUri
                              ? `url("${it.previewDataUri}") center/contain no-repeat, var(--bg-input)`
                              : 'var(--bg-input)',
                            border: '1px solid var(--border)',
                            display: 'flex', alignItems: 'center', justifyContent: 'center',
                            flexShrink: 0,
                          }}>
                            {!it.previewDataUri && (
                              <Icon name={it.type === 'symbol' ? 'navigation' : 'forest'}
                                    size={22}
                                    style={{ color: 'var(--accent)' }} />
                            )}
                          </div>
                          <input type="text" value={it.name || ''}
                            onChange={(ev) => {
                              const nm = ev.target.value
                              setLibItems(arr => arr.map(x =>
                                x.id === it.id ? { ...x, name: nm } : x))
                            }}
                            onBlur={(ev) => updateLibraryItem(it.id,
                              { name: ev.target.value })}
                            style={{ flex: 1, height: BAR_H, padding: '0 12px',
                                      fontSize: 12, fontWeight: 500 }} />
                          <BarButton icon="delete"
                            onClick={() => {
                              deleteLibraryItem(it.id)
                              setSelLib(null)
                            }}
                            title="Item löschen" />
                        </div>
                        <div style={{ display: 'flex', gap: 8, marginTop: 6 }}>
                          <BarToggle label="Symbol (nur 2D)"
                            active={it.type === 'symbol'}
                            onClick={() => updateLibraryItem(it.id,
                              { type: 'symbol' })} />
                          <BarToggle label="Objekt (2D + 3D)"
                            active={it.type === 'object'}
                            onClick={() => updateLibraryItem(it.id,
                              { type: 'object' })} />
                        </div>
                      </DetailSection>

                      <DetailSection title="2D-Darstellung (Plan)">
                        {(it.files2d || []).length === 0 ? (
                          <div style={{ fontSize: 10,
                                         color: 'var(--text-muted)',
                                         padding: '6px 0 8px' }}>
                            Keine 2D-Datei zugewiesen.
                          </div>
                        ) : (
                          <div style={{ fontSize: 10,
                                         fontFamily: 'var(--font-mono)',
                                         color: 'var(--text-muted)',
                                         padding: '4px 0' }}>
                            {(it.files2d || []).join(', ')}
                          </div>
                        )}
                        <div style={{ display: 'flex', gap: 4 }}>
                          <BarToggle icon="upload_file" label="Datei wählen"
                            onClick={() => addLibraryFile('2d', it.id, it.type)} />
                          <BarToggle icon="add_to_photos" label="Aus Auswahl"
                            onClick={() => saveSelectionAsLibrary('2d', it.id, it.type)}
                            title="Selektierte Objekte als 2D-Variante speichern" />
                        </div>
                      </DetailSection>

                      <DetailSection title="3D-Darstellung (Perspektive)">
                        {(it.files3d || []).length === 0 ? (
                          <div style={{ fontSize: 10,
                                         color: 'var(--text-muted)',
                                         padding: '6px 0 8px' }}>
                            Keine 3D-Datei zugewiesen.
                          </div>
                        ) : (
                          <div style={{ fontSize: 10,
                                         fontFamily: 'var(--font-mono)',
                                         color: 'var(--text-muted)',
                                         padding: '4px 0' }}>
                            {(it.files3d || []).join(', ')}
                          </div>
                        )}
                        <div style={{ display: 'flex', gap: 4 }}>
                          <BarToggle icon="upload_file" label="Datei wählen"
                            onClick={() => addLibraryFile('3d', it.id, it.type)} />
                          <BarToggle icon="add_to_photos" label="Aus Auswahl"
                            onClick={() => saveSelectionAsLibrary('3d', it.id, it.type)}
                            title="Selektierte Objekte als 3D-Variante speichern" />
                        </div>
                      </DetailSection>

                      <DetailSection title="Tags">
                        <input type="text"
                          value={(it.tags || []).join(', ')}
                          placeholder="komma-getrennt"
                          onChange={(ev) => {
                            const tg = ev.target.value
                            setLibItems(arr => arr.map(x =>
                              x.id === it.id ? {
                                ...x, tags: tg.split(',').map(s => s.trim()).filter(Boolean)
                              } : x))
                          }}
                          onBlur={(ev) => updateLibraryItem(it.id, {
                            tags: ev.target.value.split(',')
                              .map(s => s.trim()).filter(Boolean)
                          })}
                          style={{ width: '100%', height: BAR_H,
                                    padding: '0 12px', fontSize: 11,
                                    boxSizing: 'border-box' }} />
                      </DetailSection>

                      <div style={{ fontSize: 9, color: 'var(--text-muted)',
                                     marginTop: 14, lineHeight: 1.5 }}>
                        ID: <span style={{ fontFamily: 'var(--font-mono)' }}>{it.id}</span><br />
                        Library: <span style={{ fontFamily: 'var(--font-mono)' }}>{libRoot}</span>
                      </div>
                    </>
                  )
                })()}
              </div>
            </div>
          )}

          {tab === 'raumstile' && (
            <div style={{ maxWidth: 760 }}>
              <div style={{ fontSize: 10, color: 'var(--text-muted)',
                             padding: '6px 0 10px', lineHeight: 1.5 }}>
                Raumstempel-Stile (Presets). Werden via Raum-Properties
                erstellt ("+ Aktuelle Settings als Stil speichern"), hier nur
                verwaltet. Drag zum Umsortieren — die Reihenfolge entspricht
                dem Dropdown in den Raum-Properties.
              </div>
              {raumStile.length === 0 ? (
                <div style={{ padding: 30, textAlign: 'center',
                               color: 'var(--text-muted)', fontSize: 11 }}>
                  Noch keine Stile gespeichert. Im Raum-Properties einen Raum
                  konfigurieren und "+ Aktuelle Settings als Stil speichern".
                </div>
              ) : (
                <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                  {raumStile.map((s, idx) => {
                    const isDrag = dragStilIdx === idx
                    return (
                      <div key={s.id}
                        draggable
                        onDragStart={(e) => {
                          setDragStilIdx(idx)
                          try { e.dataTransfer.effectAllowed = 'move' } catch (_) {}
                        }}
                        onDragOver={(e) => { e.preventDefault() }}
                        onDrop={(e) => {
                          e.preventDefault()
                          if (dragStilIdx == null || dragStilIdx === idx) return
                          const next = [...raumStile]
                          const [moved] = next.splice(dragStilIdx, 1)
                          next.splice(idx, 0, moved)
                          setRaumStile(next)
                          reorderRaumStile(next.map(x => x.id))
                          setDragStilIdx(null)
                        }}
                        onDragEnd={() => setDragStilIdx(null)}
                        style={{
                          display: 'flex', alignItems: 'center', gap: 8,
                          padding: '8px 10px',
                          background: isDrag ? 'var(--bg-item-active)' : 'var(--bg-input)',
                          border: '1px solid var(--border)',
                          borderRadius: 'var(--r)',
                          cursor: 'grab',
                          opacity: isDrag ? 0.5 : 1,
                          transition: 'opacity 0.15s',
                        }}>
                        <Icon name="drag_indicator" size={14}
                          style={{ color: 'var(--text-muted)' }} />
                        <input type="text" value={s.name}
                          onChange={(e) => {
                            const next = raumStile.map(x =>
                              x.id === s.id ? { ...x, name: e.target.value } : x)
                            setRaumStile(next)
                          }}
                          onBlur={(e) => {
                            const newName = (e.target.value || '').trim()
                            if (newName && newName !== s.name) {
                              // Re-save mit gleicher id → effektiv rename
                              const { id, name: _n, ...rest } = s
                              saveRaumStil(id, newName, rest)
                            }
                          }}
                          onKeyDown={(e) => { if (e.key === 'Enter') e.target.blur() }}
                          style={{ flex: 1, fontSize: 11, height: BAR_H,
                                    padding: '0 10px',
                                    fontFamily: s.font ? `"${s.font}", monospace` : 'inherit',
                                    fontWeight: s.bold ? 700 : 400,
                                    fontStyle: s.italic ? 'italic' : 'normal' }} />
                        {/* Mini-Preview: Felder die in Layout vorkommen */}
                        <span style={{ fontSize: 9,
                                        color: 'var(--text-muted)',
                                        fontFamily: 'DM Mono, monospace',
                                        minWidth: 100, textAlign: 'right' }}>
                          {(s.layout && s.layout.length)
                            ? s.layout.map(row => row.join('·')).join(' / ')
                            : '—'}
                        </span>
                        <button onClick={() => duplicateRaumStil(s.id)}
                          title="Duplizieren"
                          style={{
                            background: 'transparent', border: '1px solid var(--border)',
                            borderRadius: 'var(--r)', cursor: 'pointer',
                            padding: '4px 8px', fontSize: 10,
                            color: 'var(--text-primary)',
                          }}>
                          <Icon name="content_copy" size={11} />
                        </button>
                        <button onClick={() => {
                          if (window.confirm(`Stil "${s.name}" löschen?`))
                            deleteRaumStil(s.id)
                        }}
                          title="Löschen"
                          style={{
                            background: 'transparent', border: '1px solid var(--border)',
                            borderRadius: 'var(--r)', cursor: 'pointer',
                            padding: '4px 8px', fontSize: 10,
                            color: 'var(--text-danger, #c44)',
                          }}>
                          <Icon name="delete" size={11} />
                        </button>
                      </div>
                    )
                  })}
                </div>
              )}
            </div>
          )}

          {tab === 'stempelstile' && (
            <div style={{ maxWidth: 760 }}>
              <div style={{ fontSize: 10, color: 'var(--text-muted)',
                             padding: '6px 0 10px', lineHeight: 1.5 }}>
                Stempel-Stile (Presets) für SIA-Bilanz-Stempel. Werden via
                Stempel-Properties erstellt ("+ Aktuelle Settings als Stil
                speichern"), hier nur verwaltet. Drag zum Umsortieren —
                Reihenfolge entspricht dem Dropdown in den Stempel-Properties.
              </div>
              {stempelStile.length === 0 ? (
                <div style={{ padding: 30, textAlign: 'center',
                               color: 'var(--text-muted)', fontSize: 11 }}>
                  Noch keine Stempel-Stile gespeichert. Im Elemente-Panel
                  einen Stempel platzieren, konfigurieren und im Stempel-
                  Properties "+ Aktuelle Settings als Stil speichern".
                </div>
              ) : (
                <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                  {stempelStile.map((s, idx) => {
                    const isDrag = dragStempelIdx === idx
                    // Show-Flags zaehlen fuer ein Mini-Preview
                    const onCount = [
                      'showHnf','showNnf','showNf','showVf','showFf',
                      'showNgf','showGf','showAgf','showCount','showScope',
                    ].filter(k => s[k] !== false).length
                    return (
                      <div key={s.id}
                        draggable
                        onDragStart={(e) => {
                          setDragStempelIdx(idx)
                          try { e.dataTransfer.effectAllowed = 'move' } catch (_) {}
                        }}
                        onDragOver={(e) => { e.preventDefault() }}
                        onDrop={(e) => {
                          e.preventDefault()
                          if (dragStempelIdx == null || dragStempelIdx === idx) return
                          const next = [...stempelStile]
                          const [moved] = next.splice(dragStempelIdx, 1)
                          next.splice(idx, 0, moved)
                          setStempelStile(next)
                          reorderStempelStile(next.map(x => x.id))
                          setDragStempelIdx(null)
                        }}
                        onDragEnd={() => setDragStempelIdx(null)}
                        style={{
                          display: 'flex', alignItems: 'center', gap: 8,
                          padding: '8px 10px',
                          background: isDrag ? 'var(--bg-item-active)' : 'var(--bg-input)',
                          border: '1px solid var(--border)',
                          borderRadius: 'var(--r)',
                          cursor: 'grab',
                          opacity: isDrag ? 0.5 : 1,
                          transition: 'opacity 0.15s',
                        }}>
                        <Icon name="drag_indicator" size={14}
                          style={{ color: 'var(--text-muted)' }} />
                        <input type="text" value={s.name}
                          onChange={(e) => {
                            const next = stempelStile.map(x =>
                              x.id === s.id ? { ...x, name: e.target.value } : x)
                            setStempelStile(next)
                          }}
                          onBlur={(e) => {
                            const newName = (e.target.value || '').trim()
                            if (newName && newName !== s.name) {
                              const { id, name: _n, ...rest } = s
                              saveStempelStil(id, newName, rest)
                            }
                          }}
                          onKeyDown={(e) => { if (e.key === 'Enter') e.target.blur() }}
                          style={{ flex: 1, fontSize: 11, height: BAR_H,
                                    padding: '0 10px',
                                    fontFamily: s.font ? `"${s.font}", monospace` : 'inherit',
                                    fontWeight: s.bold ? 700 : 400,
                                    fontStyle: s.italic ? 'italic' : 'normal' }} />
                        <span style={{ fontSize: 9,
                                        color: 'var(--text-muted)',
                                        fontFamily: 'DM Mono, monospace',
                                        minWidth: 140, textAlign: 'right' }}>
                          {s.header ? `"${s.header}"` : '—'} · {onCount} Felder
                        </span>
                        <button onClick={() => duplicateStempelStil(s.id)}
                          title="Duplizieren"
                          style={{
                            background: 'transparent', border: '1px solid var(--border)',
                            borderRadius: 'var(--r)', cursor: 'pointer',
                            padding: '4px 8px', fontSize: 10,
                            color: 'var(--text-primary)',
                          }}>
                          <Icon name="content_copy" size={11} />
                        </button>
                        <button onClick={() => {
                          if (window.confirm(`Stil "${s.name}" löschen?`))
                            deleteStempelStil(s.id)
                        }}
                          title="Löschen"
                          style={{
                            background: 'transparent', border: '1px solid var(--border)',
                            borderRadius: 'var(--r)', cursor: 'pointer',
                            padding: '4px 8px', fontSize: 10,
                            color: 'var(--text-danger, #c44)',
                          }}>
                          <Icon name="delete" size={11} />
                        </button>
                      </div>
                    )
                  })}
                </div>
              )}
            </div>
          )}
        </div>

        {/* Footer — Pill-Buttons */}
        <div style={{
          display: 'flex', alignItems: 'center', gap: 6,
          padding: '8px 12px',
          borderTop: '1px solid var(--border)',
          background: 'var(--bg-section)',
        }}>
          <div style={{ flex: 1 }} />
          <BarToggle label="Abbrechen" onClick={onClose} />
          <BarToggle label="Übernehmen" active onClick={() => onSave(draft)} />
        </div>
      </div>
    </div>
  )
}
