/* ===================================================================
   KabelFlux v5 — Layout view (consolidated Diagram + Formboard, per Day 2)
   - Chip toolbar grouped: Wires / Labels / Detail (per DEMO_SCRIPT Part 2)
   - Pin face Z-order corrected (H2 fix): faces drawn UNDER labels
   - Reduced motion respected (H5)
   - Wire mode banner (per Part 4.5)
   =================================================================== */

const SYM = {
  Circular: (props) => {
    const { x, y, pins, gender, sel, showPinNums=true } = props;
    const r = 38;
    return (
      <g transform={`translate(${x} ${y})`}>
        <circle r={r} fill="var(--bg-3)" stroke={sel ? 'var(--info)' : 'var(--line-strong)'} strokeWidth="1.6"/>
        <circle r={r - 6} fill="none" stroke="var(--line)" strokeWidth="1"/>
        {Array.from({ length: pins }).map((_, i) => {
          const a = (i / pins) * Math.PI * 2 - Math.PI / 2;
          const cx = Math.cos(a) * (r - 14);
          const cy = Math.sin(a) * (r - 14);
          return (
            <g key={i}>
              {gender === 'M'
                ? <circle cx={cx} cy={cy} r="3" fill="var(--t-2)"/>
                : <circle cx={cx} cy={cy} r="3" fill="none" stroke="var(--t-2)" strokeWidth="1.4"/>}
              {showPinNums && (
                <text x={cx} y={cy + 11} textAnchor="middle" fontSize="7" fill="var(--t-3)" fontFamily="var(--f-mono)">{i + 1}</text>
              )}
            </g>
          );
        })}
      </g>
    );
  },
  Rect: (props) => {
    const { x, y, pins, gender, sel, w=78, h=56, showPinNums=true } = props;
    const rows = Math.min(2, Math.ceil(pins / 4));
    const cols = Math.ceil(pins / rows);
    return (
      <g transform={`translate(${x} ${y})`}>
        <rect x={-w/2} y={-h/2} width={w} height={h} rx="6" fill="var(--bg-3)" stroke={sel ? 'var(--info)' : 'var(--line-strong)'} strokeWidth="1.6"/>
        {Array.from({ length: pins }).map((_, i) => {
          const col = i % cols, row = Math.floor(i / cols);
          const cx = -w/2 + 14 + col * ((w - 28) / Math.max(1, cols - 1));
          const cy = rows === 1 ? 0 : -h/2 + 14 + row * (h - 28);
          return (
            <g key={i}>
              {gender === 'M'
                ? <circle cx={cx} cy={cy} r="3" fill="var(--t-2)"/>
                : <circle cx={cx} cy={cy} r="3" fill="none" stroke="var(--t-2)" strokeWidth="1.4"/>}
              {showPinNums && (
                <text x={cx} y={cy + 11} textAnchor="middle" fontSize="7" fill="var(--t-3)" fontFamily="var(--f-mono)">{i + 1}</text>
              )}
            </g>
          );
        })}
      </g>
    );
  }
};

const NODE_GLYPH = {
  splice:    (col) => <circle r="9" fill={col} stroke="#fff" strokeWidth="1.6"/>,
  fuse:      (col) => <g><rect x="-11" y="-5" width="22" height="10" rx="2" fill="none" stroke={col} strokeWidth="1.6"/><line x1="-8" y1="0" x2="8" y2="0" stroke={col} strokeWidth="1.4"/></g>,
  ground:    (col) => <g><line x1="0" y1="-9" x2="0" y2="0" stroke={col} strokeWidth="1.6"/><line x1="-10" y1="0" x2="10" y2="0" stroke={col} strokeWidth="1.8"/><line x1="-7" y1="3.5" x2="7" y2="3.5" stroke={col} strokeWidth="1.4"/><line x1="-4" y1="7" x2="4" y2="7" stroke={col} strokeWidth="1.2"/></g>,
};

/* — Canvas — */
const LayoutView = ({ wireMode, setWireMode, renderMode, density, wires=[], connectors=[], nodes=[], bundles=[], loading=false, project, toast }) => {
  // Analyse — consistency check against the backend's audit_project rules.
  // Same engine as the old "🔍 Audit" button in the legacy SPA, just
  // surfaced here next to Wire mode where designers will actually find it.
  const [analyseRunning, setAnalyseRunning] = useState(false);
  const [analyseResult, setAnalyseResult] = useState(null);  // { issues, projectName }
  const runAnalyse = async () => {
    if (!project || !project.realId) {
      toast && toast.warn && toast.warn('Open a project first to analyse it.');
      return;
    }
    setAnalyseRunning(true);
    try {
      // Call the backend's audit endpoint directly — same engine as the
      // legacy SPA's old "🔍 Audit" button.
      const resp = await window.kfxFetch('/projects/' + project.realId + '/audit');
      const issues = (resp && Array.isArray(resp.issues)) ? resp.issues : [];
      setAnalyseResult({ issues: issues, projectName: project.name || '' });
      const n = (issues || []).length;
      const errs = (issues || []).filter(i => i.severity === 'error').length;
      const warns = (issues || []).filter(i => i.severity === 'warning').length;
      if (n === 0) toast && toast.success && toast.success('Analyse · no issues found.');
      else toast && toast.info && toast.info('Analyse · ' + errs + ' error' + (errs===1?'':'s') + ', ' + warns + ' warning' + (warns===1?'':'s') + ' found.');
    } catch (e) {
      toast && toast.err && toast.err('Analyse failed: ' + (e.message || e));
    } finally {
      setAnalyseRunning(false);
    }
  };
  const [tools, setTools] = useState({
    nets: true, nodes: true, gauges: false, callouts: true,
    pinFaces: true, shieldGlow: true, tables: false, dims: true, grid: true, bezier: true,
  });
  const [zoom, setZoom] = useState(1);
  const [sel, setSel] = useState(null);
  const [hover, setHover] = useState(null);
  const reducedMotion = useRef(typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches);

  const toggle = k => setTools(t => ({ ...t, [k]: !t[k] }));

  /* Wire paths */
  const wirePath = (w) => {
    const from = connectors.find(c => c.id === w.fromConn) || nodes.find(n => n.id === w.fromConn);
    const to   = connectors.find(c => c.id === w.toConn)   || nodes.find(n => n.id === w.toConn);
    if (!from || !to) return null;
    if (renderMode === 'formboard') {
      // 90° formboard routing
      const midX = (from.x + to.x) / 2;
      return `M ${from.x} ${from.y} L ${midX} ${from.y} L ${midX} ${to.y} L ${to.x} ${to.y}`;
    }
    if (!tools.bezier) {
      // straight line when Bezier is toggled off
      return `M ${from.x} ${from.y} L ${to.x} ${to.y}`;
    }
    // schematic bezier
    const dx = (to.x - from.x) * 0.4;
    return `M ${from.x} ${from.y} C ${from.x + dx} ${from.y}, ${to.x - dx} ${to.y}, ${to.x} ${to.y}`;
  };

  return (
    <div className="kf-layout">
      {/* Chip toolbar — grouped per Day 2 */}
      <div className="kf-canvas-bar">
        <div className="kf-bar-group" aria-label="Wires display">
          <span className="kf-bar-label">Wires</span>
          <Chip size="sm" active={tools.bezier} onClick={() => toggle('bezier')} icon="bundle">Bezier</Chip>
          <Chip size="sm" active={tools.shieldGlow} onClick={() => toggle('shieldGlow')}>Shield glow</Chip>
        </div>
        <div className="divider-v"/>
        <div className="kf-bar-group" aria-label="Labels display">
          <span className="kf-bar-label">Labels</span>
          <Chip size="sm" active={tools.nets} onClick={() => toggle('nets')}>Nets</Chip>
          <Chip size="sm" active={tools.nodes} onClick={() => toggle('nodes')}>Nodes</Chip>
          <Chip size="sm" active={tools.gauges} onClick={() => toggle('gauges')}>Gauges</Chip>
          <Chip size="sm" active={tools.callouts} onClick={() => toggle('callouts')}>Callouts</Chip>
        </div>
        <div className="divider-v"/>
        <div className="kf-bar-group" aria-label="Detail display">
          <span className="kf-bar-label">Detail</span>
          <Chip size="sm" active={tools.pinFaces} onClick={() => toggle('pinFaces')}>Pin faces</Chip>
          <Chip size="sm" active={tools.dims} onClick={() => toggle('dims')} icon="ruler">Dimensions</Chip>
          <Chip size="sm" active={tools.grid} onClick={() => toggle('grid')} icon="grid">Grid</Chip>
        </div>

        <div className="divider-v"/>

        {/* Wire mode toggle — same format as the other toolbar chips. */}
        <div className="kf-bar-group" aria-label="Wire actions">
          <span className="kf-bar-label">Action</span>
          <Chip size="sm" tone={wireMode ? 'success' : 'neutral'} active={wireMode}
                onClick={() => setWireMode(!wireMode)}
                icon="bolt" ariaLabel="Toggle wire-creation mode">
            {wireMode ? 'Wire mode • ON' : 'Wire mode'}
          </Chip>
          {/* Analyse — runs the backend consistency audit, formerly the "Audit"
              button in the legacy SPA. Surfaces unknown connectors, duplicate
              wires, pin overruns, etc. */}
          <Chip size="sm" tone={analyseRunning ? 'info' : 'neutral'}
                onClick={runAnalyse} icon="search"
                ariaLabel="Analyse this harness for design issues">
            {analyseRunning ? 'Analysing…' : 'Analyse'}
          </Chip>
        </div>

        <div className="spacer"/>
      </div>

      {/* Wire-mode hint banner */}
      {wireMode && (
        <div className="kf-banner kf-banner-success fade-in" role="status">
          <Icon name="bolt" size={14}/>
          <span><b>Wire mode active</b> — click pin A, then pin B to create a wire. <Kbd>Esc</Kbd> to exit.</span>
        </div>
      )}

      <div className="kf-canvas-wrap">
        {/* Left rail: zoom + render mode */}
        <div className="kf-canvas-rail">
          <IconBtn icon="zoomIn"  label="Zoom in"  onClick={() => setZoom(z => Math.min(2, z + .15))}/>
          <IconBtn icon="zoomOut" label="Zoom out" onClick={() => setZoom(z => Math.max(.4, z - .15))}/>
          <div className="kf-rail-zoom num">{Math.round(zoom * 100)}%</div>
          <div className="kf-rail-sep"/>
          <IconBtn icon="move"    label="Pan canvas (Space + drag)"/>
          <IconBtn icon="grid"    label="Snap to grid" active={tools.grid} onClick={() => toggle('grid')}/>
        </div>

        {/* The SVG canvas */}
        <div className="kf-canvas" style={{ background: tools.grid ? 'radial-gradient(circle, var(--grid-dot) 1px, transparent 1px) 0 0/24px 24px, var(--bg-1)' : 'var(--bg-1)' }}>
          <svg viewBox="0 0 1200 620" preserveAspectRatio="xMidYMid meet"
               style={{ width: `${100 * zoom}%`, height: `${100 * zoom}%`, minWidth: '100%', minHeight: '100%' }}
               role="img" aria-label="Harness layout canvas">

            {/* Bundles (drawn first) */}
            {bundles.map(b => (
              <g key={b.id}>
                <path d={`M ${b.from.x} ${b.from.y} L ${b.to.x} ${b.to.y}`}
                      stroke="rgba(74,158,255,.16)" strokeWidth={Math.min(28, 6 + b.count * 2)}
                      strokeLinecap="round" fill="none"/>
              </g>
            ))}

            {/* Wires */}
            {wires.map(w => {
              const hex = COLOR_HEX[w.color] || '#888';
              const d = wirePath(w);
              if (!d) return null;
              const isOpen = (w.notes || '').toLowerCase().includes('open');
              return (
                <g key={w.id}>
                  {w.shield && tools.shieldGlow && !reducedMotion.current && (
                    <path d={d} stroke="rgba(74,158,255,.45)" strokeWidth="6" fill="none"
                          opacity=".55" strokeLinecap="round"/>
                  )}
                  <path d={d} stroke={hex} strokeWidth={w.gauge === '18 AWG' ? 2.6 : w.gauge === '20 AWG' ? 2.2 : 1.8}
                        fill="none" strokeLinecap="round"
                        strokeDasharray={isOpen ? '4 3' : null}
                        opacity={hover && hover !== w.id ? .35 : 1}
                        onMouseEnter={() => setHover(w.id)} onMouseLeave={() => setHover(null)}/>
                </g>
              );
            })}

            {/* Net labels */}
            {tools.nets && wires.filter((_, i) => i % 3 === 0).map(w => {
              const from = connectors.find(c => c.id === w.fromConn) || nodes.find(n => n.id === w.fromConn);
              const to   = connectors.find(c => c.id === w.toConn)   || nodes.find(n => n.id === w.toConn);
              if (!from || !to) return null;
              const mx = (from.x + to.x) / 2, my = (from.y + to.y) / 2 - 8;
              return (
                <g key={`l-${w.id}`}>
                  <rect x={mx - 24} y={my - 8} width="48" height="14" rx="3"
                        fill="var(--bg-2)" stroke="var(--line)" strokeWidth=".8"/>
                  <text x={mx} y={my + 2} textAnchor="middle" fontSize="9" fill="var(--t-2)" fontFamily="var(--f-mono)" fontWeight="600">{w.net}</text>
                </g>
              );
            })}

            {/* Gauge labels — AWG at wire midpoint, below the wire */}
            {tools.gauges && wires.map(w => {
              if (!w.gauge) return null;
              const from = connectors.find(c => c.id === w.fromConn) || nodes.find(n => n.id === w.fromConn);
              const to   = connectors.find(c => c.id === w.toConn)   || nodes.find(n => n.id === w.toConn);
              if (!from || !to) return null;
              const mx = (from.x + to.x) / 2, my = (from.y + to.y) / 2 + 10;
              const lw = Math.max(36, w.gauge.length * 6);
              return (
                <g key={`gau-${w.id}`} pointerEvents="none">
                  <rect x={mx - lw/2} y={my - 7} width={lw} height="12" rx="2"
                        fill="var(--bg-2)" stroke="var(--line)" strokeWidth=".6" opacity=".9"/>
                  <text x={mx} y={my + 2} textAnchor="middle" fontSize="8"
                        fill="var(--t-3)" fontFamily="var(--f-mono)">{w.gauge}</text>
                </g>
              );
            })}

            {/* Dimension arrows (industry-standard, per DEMO_SCRIPT Part 3) */}
            {tools.dims && bundles.map(b => {
              const y = Math.min(b.from.y, b.to.y) - 48;
              const x1 = b.from.x + 8, x2 = b.to.x - 8;
              return (
                <g key={`d-${b.id}`} stroke="var(--info)" strokeWidth="1.2" fill="none">
                  <line x1={x1} y1={y} x2={x2} y2={y}/>
                  <line x1={x1} y1={y - 6} x2={x1} y2={y + 6}/>
                  <line x1={x2} y1={y - 6} x2={x2} y2={y + 6}/>
                  <line x1={x1} y1={b.from.y - 6} x2={x1} y2={y + 4} strokeDasharray="2 2"/>
                  <line x1={x2} y1={b.to.y - 6}   x2={x2} y2={y + 4} strokeDasharray="2 2"/>
                  <rect x={(x1 + x2) / 2 - 30} y={y - 18} width="60" height="14" rx="3" fill="var(--bg-2)" stroke="var(--info)" strokeWidth=".8"/>
                  <text x={(x1 + x2) / 2} y={y - 8} textAnchor="middle" fontSize="9.5" fill="var(--info)" fontFamily="var(--f-mono)" fontWeight="700">{b.label} = {b.length} mm</text>
                </g>
              );
            })}

            {/* Callout annotations — leader line + text box, from project.callouts */}
            {tools.callouts && (project?.callouts || []).map((c, i) => {
              const lx = c.lx != null ? c.lx : c.x + 44;
              const ly = c.ly != null ? c.ly : c.y - 22;
              const label = c.text || c.label || '';
              const bw = Math.max(52, label.length * 6.2 + 16);
              return (
                <g key={`co-${i}`} pointerEvents="none">
                  <line x1={c.x} y1={c.y} x2={lx} y2={ly}
                        stroke="var(--info)" strokeWidth="1" strokeDasharray="3 2" opacity=".8"/>
                  <circle cx={c.x} cy={c.y} r="2.5" fill="var(--info)" opacity=".9"/>
                  <rect x={lx - 2} y={ly - 13} width={bw} height="14" rx="3"
                        fill="var(--info-soft)" stroke="var(--info)" strokeWidth=".8"/>
                  <text x={lx + bw/2 - 2} y={ly - 3} textAnchor="middle" fontSize="9"
                        fill="var(--info)" fontFamily="var(--f-mono)" fontWeight="600">{label}</text>
                </g>
              );
            })}

            {/* Connectors (drawn AFTER wires; pin faces are INSIDE the symbol → no overlap, H2 fix) */}
            {connectors.map(c => {
              const isSel = sel === c.id;
              const Sym = ['Circular','Deutsch DT'].includes(c.type) ? SYM.Circular : SYM.Rect;
              return (
                <g key={c.id} onClick={() => setSel(c.id)} style={{ cursor: 'pointer' }}>
                  <Sym x={c.x} y={c.y} pins={c.pins} gender={c.gender} sel={isSel} showPinNums={tools.pinFaces}/>
                  <text x={c.x} y={c.y - 56} textAnchor="middle" fontSize="11.5" fontWeight="700" fill="var(--t-1)" fontFamily="var(--f-sans)">{c.id}</text>
                  <text x={c.x} y={c.y - 44} textAnchor="middle" fontSize="9.5" fill="var(--t-3)" fontFamily="var(--f-mono)">{c.type} · {c.gender === 'M' ? 'Male' : 'Female'} · {c.pins}P</text>
                </g>
              );
            })}

            {/* Nodes */}
            {tools.nodes && nodes.map(n => {
              const t = { splice:'#f5a623', fuse:'#ef4e4e', ground:'#9aa3b8' }[n.type] || '#888';
              const G = NODE_GLYPH[n.type] || NODE_GLYPH.splice;
              return (
                <g key={n.id} transform={`translate(${n.x} ${n.y})`}>
                  {G(t)}
                  <text x="0" y="-16" textAnchor="middle" fontSize="9" fill="var(--t-2)" fontFamily="var(--f-mono)" fontWeight="600">{n.label}{n.value && ` · ${n.value}`}</text>
                </g>
              );
            })}

            {/* Selected pin pulse (wire mode) */}
            {wireMode && (
              <g transform="translate(180 140)">
                <circle r="14" fill="none" stroke="var(--success)" strokeWidth="2">
                  {!reducedMotion.current && (
                    <>
                      <animate attributeName="r" values="14;22;14" dur="1.4s" repeatCount="indefinite"/>
                      <animate attributeName="opacity" values=".9;0;.9" dur="1.4s" repeatCount="indefinite"/>
                    </>
                  )}
                </circle>
              </g>
            )}
          </svg>
        </div>

        {/* Right inspector */}
        <div className="kf-canvas-inspector">
          <div className="kf-inspector-head">
            <div className="kf-inspector-title">Inspector</div>
            {sel && <Chip size="sm" tone="info" icon="connector">{sel}</Chip>}
          </div>
          {sel ? (
            <div className="kf-inspector-body">
              {(() => {
                const c = connectors.find(x => x.id === sel);
                if (!c) return null;
                const wiresOn = wires.filter(w => w.fromConn === sel || w.toConn === sel);
                return (
                  <>
                    <div className="kf-inspector-field">
                      <label>Reference</label>
                      <div className="kf-inspector-value">{c.label}</div>
                    </div>
                    <div className="kf-inspector-field">
                      <label>Type</label>
                      <div className="kf-inspector-value">{c.type}</div>
                    </div>
                    <div className="kf-inspector-row">
                      <div className="kf-inspector-field flex"><label>Gender</label><div className="kf-inspector-value">{c.gender === 'M' ? 'Male' : 'Female'}</div></div>
                      <div className="kf-inspector-field flex"><label>Pins</label><div className="kf-inspector-value num">{c.pins}</div></div>
                    </div>
                    <div className="kf-inspector-sep"/>
                    <div className="kf-inspector-label">Pinout · {wiresOn.length} wired</div>
                    <div className="kf-pinout">
                      {Array.from({ length: c.pins }).map((_, i) => {
                        const w = wiresOn.find(w => (w.fromConn === sel && w.fromPin === i + 1) || (w.toConn === sel && w.toPin === i + 1));
                        return (
                          <div key={i} className={`kf-pinout-row ${w ? 'wired' : ''}`}>
                            <span className="kf-pinout-cav num">{i + 1}</span>
                            {w ? (
                              <>
                                <span className="kf-pinout-sw" style={{ background: COLOR_HEX[w.color] }}/>
                                <span className="kf-pinout-net">{w.net}</span>
                                <span className="kf-pinout-to num">→ {w.fromConn === sel ? `${w.toConn}:${w.toPin}` : `${w.fromConn}:${w.fromPin}`}</span>
                              </>
                            ) : (
                              <span className="kf-pinout-empty">open</span>
                            )}
                          </div>
                        );
                      })}
                    </div>
                    <div className="kf-inspector-actions">
                      <Btn size="sm" kind="ghost" icon="edit">Edit</Btn>
                      <Btn size="sm" kind="ghost" icon="copy">Duplicate</Btn>
                      <Btn size="sm" kind="danger" icon="trash" ariaLabel="Delete connector"/>
                    </div>
                  </>
                );
              })()}
            </div>
          ) : (
            <EmptyState compact icon="connector"
              title="Nothing selected"
              hint="Click a connector or node on the canvas to inspect pinouts, wires and references."/>
          )}
        </div>
      </div>

      {/* Analyse results — same modal layout as the legacy SPA's audit modal,
          restyled to the bundle's design language. */}
      {analyseResult && (
        <Modal title={'Analyse — ' + (analyseResult.projectName || 'Project')}
               size="lg" onClose={() => setAnalyseResult(null)}
               footer={<Btn kind="primary" onClick={() => setAnalyseResult(null)}>Close</Btn>}>
          {analyseResult.issues.length === 0 ? (
            <div style={{padding:'28px 12px', textAlign:'center'}}>
              <div style={{fontSize:24, marginBottom:8}}>✅</div>
              <div style={{fontSize:14, color:'var(--success)', fontWeight:600}}>No issues found</div>
              <div style={{fontSize:12, color:'var(--t-3)', marginTop:4}}>This harness looks clean.</div>
            </div>
          ) : (
            <div>
              {/* Severity summary */}
              <div className="kf-analyse-summary">
                {[['error','danger','🔴'],['warning','warning','🟡'],['info','info','🔵']].map(([sev, tone, dot]) => {
                  const n = analyseResult.issues.filter(i => i.severity === sev).length;
                  if (!n) return null;
                  return (
                    <span key={sev} className={'kf-analyse-pill kf-analyse-pill-' + tone}>
                      <span style={{marginRight:4}}>{dot}</span>{n} {sev}{n!==1?'s':''}
                    </span>
                  );
                })}
                <span style={{marginLeft:'auto', fontSize:11, color:'var(--t-3)'}}>
                  {analyseResult.issues.length} total issue{analyseResult.issues.length!==1?'s':''}
                </span>
              </div>
              {/* Issue list */}
              <div className="kf-analyse-list">
                {analyseResult.issues.map((issue, i) => (
                  <div key={i} className={'kf-analyse-row kf-analyse-row-' + (issue.severity || 'info')}>
                    <span className="kf-analyse-sev">
                      {issue.severity === 'error' ? 'ERROR' : issue.severity === 'warning' ? 'WARN' : 'INFO'}
                    </span>
                    <div className="kf-analyse-body">
                      <div className="kf-analyse-msg">
                        <span className="kf-analyse-cat">[{issue.category || '—'}]</span> {issue.message}
                      </div>
                      {issue.fix && (
                        <div className="kf-analyse-fix">💡 <i>{issue.fix}</i></div>
                      )}
                    </div>
                  </div>
                ))}
              </div>
            </div>
          )}
        </Modal>
      )}
    </div>
  );
};

/* ---------- Styles ---------- */
const LAYOUT_STYLE = `
.kf-layout { display: flex; flex-direction: column; height: 100%; }

.kf-canvas-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 14px;
  background: var(--bg-2);
  border-bottom: 1px solid var(--line);
}
.kf-bar-group { display: inline-flex; align-items: center; gap: 5px; }
.kf-bar-label {
  font-size: 9.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 1px; color: var(--t-3); margin-right: 4px;
}

.kf-banner {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 14px;
  font-size: 12.5px;
  border-bottom: 1px solid var(--line);
}
.kf-banner b { color: inherit; font-weight: 700; }
.kf-banner-success { background: var(--success-soft); color: var(--success); }
.kf-banner-warning { background: var(--warning-soft); color: var(--warning); }
.kf-banner-info    { background: var(--info-soft);    color: var(--info); }

.kf-canvas-wrap {
  display: grid;
  grid-template-columns: 44px 1fr 280px;
  flex: 1;
  min-height: 0;
}

.kf-canvas-rail {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 8px 4px;
  background: var(--bg-2);
  border-right: 1px solid var(--line);
}
.kf-rail-zoom { font-size: 10px; color: var(--t-3); padding: 4px 0; }
.kf-rail-sep  { width: 24px; height: 1px; background: var(--line); margin: 6px 0; }

.kf-canvas {
  overflow: auto;
  position: relative;
}

.kf-canvas-inspector {
  background: var(--bg-2);
  border-left: 1px solid var(--line);
  display: flex; flex-direction: column;
  overflow: hidden;
}
.kf-inspector-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
}
.kf-inspector-title { font-size: 11px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase; color: var(--t-3); }
.kf-inspector-body  { padding: 14px; flex: 1; overflow-y: auto; }
.kf-inspector-field { display: flex; flex-direction: column; gap: 3px; margin-bottom: 12px; }
.kf-inspector-field.flex { flex: 1; }
.kf-inspector-field label { font-size: 9.5px; text-transform: uppercase; letter-spacing: .6px; color: var(--t-3); font-weight: 700; }
.kf-inspector-value { font-size: 12.5px; color: var(--t-1); }
.kf-inspector-value.num { font-family: var(--f-mono); }
.kf-inspector-row { display: flex; gap: 12px; }
.kf-inspector-sep { height: 1px; background: var(--line); margin: 6px 0 12px; }
.kf-inspector-label { font-size: 10px; text-transform: uppercase; letter-spacing: .8px; color: var(--t-3); font-weight: 700; margin-bottom: 8px; }
.kf-inspector-actions { display: flex; gap: 6px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }

.kf-pinout {
  display: flex; flex-direction: column; gap: 2px;
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  padding: 4px;
}
.kf-pinout-row {
  display: grid;
  grid-template-columns: 22px 14px 1fr auto;
  gap: 8px; align-items: center;
  padding: 4px 6px;
  border-radius: 3px;
  font-size: 11px;
}
.kf-pinout-row:hover { background: var(--bg-3); }
.kf-pinout-cav  { color: var(--t-3); font-weight: 600; text-align: right; }
.kf-pinout-sw   { width: 14px; height: 6px; border-radius: 1px; }
.kf-pinout-net  { color: var(--t-1); font-family: var(--f-mono); font-size: 11px; }
.kf-pinout-to   { color: var(--t-3); }
.kf-pinout-empty{ color: var(--t-4); font-style: italic; font-size: 10.5px; }

/* — Analyse-results modal — */
.kf-analyse-summary {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px;
  background: var(--bg-3);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  margin-bottom: 12px;
  font-size: 12px; font-weight: 600;
}
.kf-analyse-pill {
  display: inline-flex; align-items: center;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  font-size: 11px; font-weight: 700;
}
.kf-analyse-pill-danger  { background: rgba(239,78,78,.12); color: var(--danger); }
.kf-analyse-pill-warning { background: var(--warning-soft); color: var(--warning); }
.kf-analyse-pill-info    { background: var(--info-soft); color: var(--info); }

.kf-analyse-list { max-height: 50vh; overflow-y: auto; }
.kf-analyse-row {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-left-width: 3px;
  border-radius: var(--r-2);
  margin-bottom: 6px;
  background: var(--bg-2);
}
.kf-analyse-row-error   { border-left-color: var(--danger); background: rgba(239,78,78,.04); }
.kf-analyse-row-warning { border-left-color: var(--warning); background: rgba(245,166,35,.05); }
.kf-analyse-row-info    { border-left-color: var(--info); background: rgba(74,158,255,.04); }
.kf-analyse-sev {
  flex-shrink: 0;
  font-size: 10px; font-weight: 800;
  letter-spacing: 0.5px;
  color: var(--t-3);
  min-width: 44px; padding-top: 2px;
}
.kf-analyse-row-error   .kf-analyse-sev { color: var(--danger); }
.kf-analyse-row-warning .kf-analyse-sev { color: var(--warning); }
.kf-analyse-row-info    .kf-analyse-sev { color: var(--info); }
.kf-analyse-body { flex: 1; min-width: 0; }
.kf-analyse-msg  { font-size: 12.5px; color: var(--t-1); line-height: 1.4; }
.kf-analyse-cat  { font-family: var(--f-mono); font-size: 11px; color: var(--t-2); font-weight: 700; }
.kf-analyse-fix  { font-size: 11.5px; color: var(--t-3); margin-top: 4px; }
`;
document.head.appendChild(Object.assign(document.createElement('style'), { textContent: LAYOUT_STYLE }));

window.LayoutView = LayoutView;
