/*
  style.css — Layout und Bedienelemente (Schicht 2).

  ROLLE: Setzt die in doc/mockup-layout.html freigegebene Aufteilung um
  (Freigabe 2026-09-20): Kopf, drei Reiter, links klebende Bedienleiste,
  rechts Karten mit Zeichnung oder Tabellen.

  WAS DIESE DATEI AUSDRÜCKLICH NICHT TUT:
  - Sie definiert keine Farbe, keinen Abstand, keine Schriftgröße als Zahl.
    Alles kommt aus css/themes.css (UNIVERSAL §3). Die einzigen Literale
    sind geometrische: 1px Trennlinie, 50 % Kreisradius, 100 % Breite.
  - Sie legt keine Papiergröße fest. Die @page-Regel der Vorlage
    (A4 quer) ist bewusst weg — Papiergröße ist eine Einstellung und wird
    in [10/12] von js/render/print.js gesetzt (doc/GUIDELINES.md §25).
  - Sie stylt den Dialog nicht. Der bringt sein CSS selbst mit
    (js/base/dialog-template.js), liest aber dieselben Tokens.

  HERKUNFT: css/style.css der Parabolspiegel-App (Stand 2026-09-19),
  ohne Canvas-, Graph- und Receiver-Regeln, angepasst an das Mockup.
*/

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; width: 100%; min-height: 100%; }
body {
  font-family: var(--font-ui);
  font-size: var(--fs-base);
  background:
    linear-gradient(var(--bg-grid) 1px, transparent 1px) 0 0 / var(--grid-cell) var(--grid-cell),
    linear-gradient(90deg, var(--bg-grid) 1px, transparent 1px) 0 0 / var(--grid-cell) var(--grid-cell),
    var(--bg);
  color: var(--ink);
  overflow-x: hidden;
  transition: background-color var(--t-fast) ease, color var(--t-fast) ease;
}
h1, h2, h3 { font-family: var(--font-ui); font-weight: 600; }
.mono, input, select, td, .formula { font-family: var(--font-mono); }

/* ---------- Kopf ---------------------------------------------------- */
header {
  padding: var(--sp-4) var(--sp-5);
  background: var(--surface);
  border-bottom: 2px solid var(--line-strong);
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
}
.header-text h1 { margin: 0; font-size: var(--fs-h1); line-height: 1.25; }
.header-text p { margin: var(--sp-1) 0 0; font-size: var(--fs-md); line-height: 1.4; color: var(--ink-soft); }


/* ---------- Reiter -------------------------------------------------- */
.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  width: 100%;
  padding: var(--sp-2) var(--sp-5) 0;
  background: var(--bg);
}
.tab-btn {
  width: auto;
  min-width: var(--tab-min-w);
  min-height: var(--tab-min-h);
  padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--line-strong);
  border-bottom: none;
  border-radius: var(--radius) var(--radius) 0 0;
  background: var(--surface);
  color: var(--ink-soft);
  font-weight: 600;
  font-size: var(--fs-md);
  line-height: 1.3;
  cursor: pointer;
  font-family: var(--font-ui);
  /* Der Reiter wächst mit seinem Text, wie der Knopf. */
  height: auto;
  white-space: normal;
  overflow-wrap: break-word;
}
.tab-btn.active {
  color: var(--ink);
  border-bottom: 2px solid var(--surface);
  margin-bottom: -2px;
  position: relative;
  z-index: 1;
}
.tab-btn:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}
.tab-content { display: none; }
.tab-content.active { display: block; }

/* ---------- Aufteilung ---------------------------------------------- */
main { width: 100%; padding: var(--sp-3) var(--sp-5) var(--sp-6); }

/* Zweispaltig als Element INNERHALB von .tab-content, nie auf dem Tab
   selbst — sonst schlägt display:grid das Ausblenden über
   .tab-content{display:none} (Bug aus der Vorlage, dort behoben). */
.layout {
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  gap: var(--sp-4);
  align-items: start;
}

/* Instrumenten-Rahmen: dünne Linie plus zwei Eckmarken, keine Schatten. */
.card {
  position: relative;
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--sp-4);
  margin-bottom: var(--sp-3);
  box-shadow: var(--card-shadow);
}
.card::before, .card::after {
  content: "";
  position: absolute;
  width: var(--corner-mark);
  height: var(--corner-mark);
  border-color: var(--line-strong);
  border-style: solid;
}
.card::before { top: -1px; left: -1px; border-width: 2px 0 0 2px; }
.card::after { top: -1px; right: -1px; border-width: 2px 2px 0 0; }

/* Bedienleiste: klebt und rollt in sich, damit 30 Maßfelder nicht die
   Zeichnung aus dem Bild schieben. */
.controls {
  position: sticky;
  top: var(--sp-3);
  max-height: calc(100vh - 2 * var(--sp-5));
  overflow: auto;
}

h2 { font-size: var(--fs-h2); line-height: 1.3; margin: 0 0 var(--sp-3); color: var(--ink); }
h3 {
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--ink-soft);
  margin: var(--sp-4) 0 var(--sp-2);
}
h3:first-of-type { margin-top: 0; }

/* ---------- Felder -------------------------------------------------- */
.fields { display: grid; grid-template-columns: 1fr; gap: var(--sp-3); }
.field { min-width: 0; margin: 0 0 var(--sp-2); }
/* Zwei Spalten, solange zwei Spalten lesbar sind — sonst eine. Starre
   1fr 1fr schneidet in der schmalen Leiste die Beschriftung ab ([5/6]). */
.two { display: grid; grid-template-columns: repeat(auto-fit, minmax(var(--field-min-w), 1fr)); gap: var(--sp-2); }
/* Die Wahlfelder (Ärmellänge, Kragen, Manschette …) liegen in einem eigenen
   Behälter, weil sie bei jedem Wechsel des Kleidungsstücks neu gebaut
   werden. Ohne display:contents wäre dieser Behälter EIN Rasterfeld: alle
   Wahlfelder stapelten sich in der rechten Spalte, während links darunter
   Platz frei blieb (Meldung des Users am 2026-09-21). Mit display:contents
   werden seine Kinder selbst Rasterfelder und füllen die Zeilen von links
   nach rechts. Der Neuaufbau in app.js bleibt unverändert. */
#option-fields { display: contents; }
.field-label-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-2); margin: 0 0 var(--sp-1);
}
.field-label-row label, .field > label {
  display: block; font-size: var(--fs-sm); font-weight: 600;
  color: var(--ink-soft); line-height: 1.3; margin: 0;
}
.field > label { margin-bottom: var(--sp-1); }

/* Hilfe-Knopf: sitzt neben Label oder Knopf, öffnet über js/base/help.js
   den Dialog mit data-help-title / data-help-message. */
.help-btn {
  width: var(--help-btn-size); height: var(--help-btn-size);
  min-height: var(--help-btn-size); flex: none;
  padding: 0; border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: transparent; color: var(--ink-soft);
  font-size: var(--fs-sm); font-weight: 700; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
}
.help-btn:hover { background: var(--accent-soft); color: var(--ink); }
.button-with-help { display: flex; align-items: stretch; gap: var(--sp-2); }
.button-with-help button:first-child { flex: 1; min-width: 0; }

input, select {
  display: block; width: 100%; min-width: 0; height: var(--control-h);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--sp-2) var(--sp-2);
  font-size: var(--fs-base); line-height: 1.2;
  background: var(--surface);
  color: var(--ink);
}
/* Ein natives Auswahlfeld kann nicht umbrechen. Damit nichts verloren
   geht, kürzt es sichtbar mit "…" und trägt seinen vollen Text als
   Tooltip (js/base/field-factory.js setzt ihn). */
select { border-color: var(--line-strong); text-overflow: ellipsis; padding-right: var(--sp-1); }
input:disabled, select:disabled { color: var(--ink-soft); background: var(--accent-soft); cursor: not-allowed; }
/* Eine Verhaeltnis-Warnung faerbt das Feld orange — dieselbe Farbe, die ein
   Wert ausserhalb des ueblichen Bereichs bekommt (.is-unnatural), denn es ist
   dieselbe Aussage: „rechenbar, aber vermutlich falsch". Ein Fehler steht
   DANACH und gewinnt damit die Kaskade; zusaetzlich setzt js/app.js eine
   Warnung erst gar nicht, wo schon ein Fehler steht ([5/9] der PD
   Koerper-Kurven-Default-Sprung). */
input.is-warned { border: 2px solid var(--unnatural); background: var(--unnatural-bg); }
input.is-invalid { border-color: var(--danger-ink); background: var(--danger-bg); }

/* Die Meldung unter einem Textfeld (FieldFactory.textField, §70). Ein
   gefangener Fehler, der nur in der Konsole landet, ist ein stiller
   Fehler (UNIVERSAL §15) — die Formel des Nutzers sagt hier selbst, was
   an ihr nicht stimmt. Keine Literale: Farbe, Abstand und Schriftgröße
   kommen aus der Token-Quelle (UNIVERSAL §3). */
.field-error {
  margin: var(--sp-1) 0 0;
  font-size: var(--fs-sm);
  line-height: 1.4;
  color: var(--danger-ink);
}

/* Knöpfe wachsen mit dem Text (min-height statt height) — lange deutsche
   Beschriftungen in der schmalen Leiste werden sonst abgeschnitten. */
button {
  display: flex; align-items: center; justify-content: center;
  width: 100%; min-width: 0; min-height: var(--control-h);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-base); line-height: 1.35;
  text-align: center; white-space: normal; overflow-wrap: break-word;
  background: var(--accent); color: var(--accent-ink);
  font-weight: 600; font-family: var(--font-ui);
  cursor: pointer;
}
button:hover { filter: brightness(1.08); }
button.secondary { background: transparent; color: var(--ink); border-color: var(--line-strong); }
button.secondary:hover { background: var(--accent-soft); }
button:disabled { opacity: .5; cursor: not-allowed; filter: none; }

.actions { display: grid; gap: var(--sp-2); margin-top: var(--sp-3); }
.actions.row { grid-template-columns: 1fr 1fr; }

/* ---------------------------------------------------------------------
   SYMBOLKNÖPFE IN DER SEITENLEISTE ([11/14] der PD Projektor-Stil-
   Symbolleiste, Abschnitt 1 des freigegebenen Mockups).

   Die Knopfreihe steht da, wo sonst die Klappliste stand: EINE Zeile statt
   drei, und die getroffene Wahl ist ohne Aufklappen zu sehen.
   SIE UMBRICHT. Die Leiste ist 320 px breit und wird schmaler; eine Reihe,
   die nicht umbrechen kann, ragt über den Rand hinaus und ist dann gar
   nicht mehr bedienbar.
   --------------------------------------------------------------------- */
.field-seg .bar-seg-icons {
  flex-wrap: wrap; gap: 2px; padding: 2px;
  width: max-content; max-width: 100%;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface);
}
/* Die Wort-Fassung (Maßstab, Einheit) behält den zusammengesetzten Block
   der Leiste — dort ist der Text selbst die Antwort. */
.field-seg .bar-seg:not(.bar-seg-icons) { flex-wrap: wrap; }
/* Fünf Silhouetten brauchen die ganze Zeile des zweispaltigen Rasters. */
.field-wide { grid-column: 1 / -1; }

/* DIE DREI FARBTUPFER DES THEMAS. Die Farben stehen hier als Literal, weil
   ein Thema seine eigenen Variablen nicht zeigen kann, solange ein anderes
   gilt (js/base/icons.js, themeSwatch). Je Tupfer die Fläche des Themas mit
   seiner Akzentfarbe als Rand — zwei Farben sagen mehr als eine. */
/* Seit [2/7] steht die Reihe an ZWEI Orten (V1-Menü und V2-Fenster), darum
   Klassen statt ids. */
.theme-seg .ib svg { stroke-width: 1.5; }
.theme-seg [data-value="blueprint"] svg { color: #e9f0f5; stroke: #c1552c; }
.theme-seg [data-value="sunglow"] svg { color: #322619; stroke: #f2a03d; }
.theme-seg [data-value="werkstatt"] svg { color: #242424; stroke: #ff6b1a; }

/* DIE REIHEN, DIE AUSLÖSEN (vier Knöpfe unter den Maßen, „Datei" und
   „Ausgabe" im Reiter Druck). Kein Umschalter: keiner ist gedrückt. */
.ib-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); }
.actions .ib-row {
  padding: 2px; width: max-content; max-width: 100%;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface);
}
/* DIE EINHEIT IN DER ZOOM-INSEL ([2/7], Ansage des Users): sie steht neben
   dem Maßstabsbalken und muss so hoch sein wie die Knöpfe daneben — sonst
   wächst die Insel um eine Zeile. Keine Beschriftung: der Name steht als
   aria-label an der Gruppe und als Tooltip an jedem Knopf. */
.zoom-island .zoom-unit .tool-btn {
  min-height: var(--ib-select-h); height: var(--ib-select-h);
  padding: 0 var(--sp-1); font-size: var(--fs-sm);
}

/* Zustandsmeldungen: ok / warn / err — Farbe UND Text, nie nur Farbe. */
.status {
  padding: var(--sp-2) var(--sp-2); border-radius: var(--radius); margin-top: var(--sp-3);
  font-size: var(--fs-sm); line-height: 1.45;
  border: 1px solid currentColor;
  background: var(--success-bg); color: var(--success-ink);
  white-space: pre-line; /* mehrere Befunde stehen untereinander, ein Zeilenumbruch je Befund */
}
.status.warn { background: var(--warn-bg); color: var(--warn-ink); }
.status.err, .status.error { background: var(--danger-bg); color: var(--danger-ink); }
.status:empty { display: none; }

.formula {
  margin-top: var(--sp-2); padding: var(--sp-2); border-left: 3px solid var(--accent);
  background: var(--accent-soft); font-size: var(--fs-md); line-height: 1.6;
  overflow-wrap: anywhere; color: var(--ink);
}
.hint { font-size: var(--fs-sm); color: var(--ink-soft); line-height: 1.5; }
.controls .hint { margin-top: var(--sp-2); margin-bottom: 0; }

/* Ein leerer Platz verschwindet mit seiner Überschrift ([8+3/12]). Ohne
   diese Zeile gewinnt eine spätere display-Regel gegen das Attribut. */
[hidden] { display: none; }

/* ---------- Weitere Maße: zugeklappt, nicht gelöscht ([8+3/12]) ------ */
.rest-measures {
  margin-top: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--sp-2);
}
.rest-measures > summary {
  cursor: pointer;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink-soft);
  list-style-position: inside;
}
.rest-measures > summary:hover { color: var(--ink); }
.rest-measures[open] > summary { margin-bottom: var(--sp-2); }

/* ---------- Nahtpaare eines eigenen Teils ([14/17], §71.7) ----------- */
/* Eine Naht gehört ZWEI Kanten. Der Kasten hält beide Felder und den
   Auftrenn-Knopf zusammen, damit man bei drei Nähten nicht raten muss,
   welches Feld zu welcher Zeile gehört.
   DERSELBE KASTEN TRÄGT SEIT [12/14] AUCH DIE LISTE DER EINGRIFFE
   (.part-op, buildPartOpsList) — ein Eingriff ist derselbe Fall wie ein
   Nahtpaar: eine Zeile, Felder, ein Knopf. Zwei Klassen, EINE Regel. */
.custom-seam, .part-op {
  margin-top: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--sp-2);
}
.custom-seam-head { margin: 0 0 var(--sp-2); color: var(--ink); font-weight: 600; }
/* Derselbe Farbpunkt wie die Zahl auf der Zeichnung — EINE Quelle. */
.custom-seam .seam-dot {
  display: inline-block; width: 0.7em; height: 0.7em;
  border-radius: 50%; margin-right: var(--sp-2); vertical-align: baseline;
}
.custom-seam-warn { margin: var(--sp-2) 0 0; color: var(--warn-ink); }
.custom-seam .actions, .part-op .actions { margin-top: var(--sp-2); }

.disclaimer {
  margin-top: var(--sp-3); padding: var(--sp-3);
  border-left: 3px solid var(--warn-ink);
  background: var(--warn-bg); color: var(--warn-ink);
  font-size: var(--fs-sm); line-height: 1.55;
}

/* ---------- Zeichnung ----------------------------------------------- */
.toolbar {
  display: flex; gap: var(--sp-2) var(--sp-3); flex-wrap: wrap; align-items: center;
  margin-bottom: var(--sp-2); font-size: var(--fs-sm); color: var(--ink-soft);
}
.toolbar .chip { display: flex; align-items: center; gap: var(--sp-1); }
.toolbar input[type="checkbox"], .checkbox-field input[type="checkbox"] {
  width: var(--check-size); height: var(--check-size); min-height: 0; flex: none;
  accent-color: var(--accent);
}
.checkbox-field label {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink-soft); cursor: pointer;
}

/* Das Blatt: weiß auch im dunklen Thema, weil die Zeichnung Papier zeigt.
   Es hat seit [3/6] eine ECHTE Höhe und nicht nur eine Mindesthöhe —
   "Einpassen" braucht einen Kasten, in den es einpassen kann.
   overflow:hidden, weil nicht mehr die Bildlaufleiste schiebt, sondern
   die Maus (js/base/zoom-pan.js). */
.sheet {
  position: relative;
  border: 1px solid var(--line-strong);
  /* Fläche HINTER der Zeichnung (PD Pfeile-Grenzen-Farben [5/7]). */
  background: var(--sheet-behind);
  border-radius: var(--radius);
  overflow: hidden;
  /* Die Höhe setzt app.js (fitSheetHeight) nach Messung. Der Anteil hier
     gilt nur für den Augenblick zwischen Laden und erster Messung. */
  height: var(--sheet-h-fallback);
  min-height: var(--sheet-min-h);
  touch-action: none;
  cursor: grab;
}
.sheet.is-panning { cursor: grabbing; }
/* Das Kontrollviereck ([3/6]) ist greifbar; während des Zugs zeigt der
   Zeiger das, nicht das Schieben der Ansicht. */
.sheet [data-control-box] { cursor: move; }
.sheet.is-dragging-box { cursor: move; }
/* Ein Kontrollgriff ([6/9]) ist greifbar; während des Zugs sagt der
   Zeiger das — nicht das Schieben der Ansicht. */
/* Eine GESPERRTE Ecke ([13+1/17], §70.13) steht bewusst nicht dabei: sie
   lässt sich nicht greifen, und ein Zeiger, der das Gegenteil verspricht,
   ist eine Falle. */
.sheet [data-handle-dot], .sheet [data-measure-dot],
.sheet [data-vertex-dot]:not([data-locked]) { cursor: pointer; }
/* Der Ring einer Marke ([7/11] der PD Knoepfe-von-Hand, §74) ist seit
   heute greifbar. Er steht in derselben Zeile wie die anderen Griffe,
   damit ein Zeiger über einem Ring dasselbe verspricht wie über einem
   Punkt — zwei Zeiger für dieselbe Zusage wären zwei Regeln. */
.sheet [data-mark-handle] { cursor: pointer; }
/* WANN MAN DEN RING SIEHT ([7+1/11] der PD Knoepfe-von-Hand, §74).
   Der Renderer baut seit [7+1/11] JEDEN greifbaren Ring, auch an nicht
   angewählten Kanten — sonst gibt es keinen Weg, beim Überfahren einen
   zu zeigen, und ein Griff, den man vor dem Anwählen nicht sieht, wird
   nicht gefunden (Befund des Users vom 2026-09-25).
   HIER ENTSCHEIDET SICH, DASS DER SCHNITT TROTZDEM NICHT VOLLER RINGE
   STEHT: sichtbar ist nur, was angewählt (`data-mark-armed`), überfahren
   (`is-mark-near` an der ganzen Reihe) oder gerade unter der Maus ist
   (`is-mark-hot`). Die Klassen setzt app.js auf der fertigen Zeichnung,
   wie jede andere Hervorhebung (§35) — es wird nichts neu gebaut.
   `pointer-events` bleibt unangetastet: der unsichtbare Ring ist
   greifbar, und genau davon lebt „ich fahre hin und sehe ihn“. */
.sheet [data-mark-handle] { opacity: 0; transition: opacity 120ms ease; }
.sheet [data-mark-handle].is-mark-near { opacity: var(--draw-mark-handle-near-o); }
.sheet [data-mark-handle][data-mark-armed],
.sheet [data-mark-handle].is-mark-picked,
.sheet [data-mark-handle].is-mark-hot { opacity: 1; }
/* DIE ANGEWÄHLTE MARKE ([8/11] der PD Knoepfe-von-Hand, §74): ein
   gestrichelter Ring. Dieselbe Sprache wie beim gewählten gelben Punkt —
   wer den einen kennt, erkennt den anderen. KEINE zweite Farbe: Rot sind
   in dieser App Maßgriffe, die ein Körpermaß ziehen, und ein roter Ring
   an einem Knopf verspräche etwas, das er nicht kann. */
.sheet [data-mark-handle].is-mark-picked [data-mark-ring] {
  stroke-dasharray: var(--draw-mark-handle-sel-dash);
  stroke-width: var(--draw-mark-handle-sel-w-px);
}
/* DIE MASSKETTE DER KNOPFREIHE ([3/6] der PD Knopfabstaende-anzeigen,
   §75). Sie zeigt sich NACH DERSELBEN REGEL wie die Ringe, zu denen sie
   gehört: angewählte Kante (`data-mark-armed`, vom Renderer) oder
   überfahrene Reihe (`is-mark-near`, von app.js). Eine eigene Regel wäre
   eine zweite Antwort auf dieselbe Frage — und dann zeigte die Kette
   Abstände zu Ringen, die man gerade nicht sieht.
   SIE FÄNGT KEINEN DRUCK AB: `pointer-events: none`. Ein Text oder eine
   Maßlinie über der Knopflinie nähme dem Ring darunter den Griff und der
   Linie das Überfahren — und genau daran hinge, dass die Kette überhaupt
   erscheint. Der Schalter mit den drei Stufen kommt in [4/6]. */
.sheet [data-mark-spacing] { opacity: 0; pointer-events: none; transition: opacity 120ms ease; }
.sheet [data-mark-spacing].is-mark-near { opacity: var(--draw-mark-spacing-near-o); }
.sheet [data-mark-spacing][data-mark-armed] { opacity: 1; }
/* STUFE 2 „IMMER“ ([4/6], E-A2). Die Stufe steht am Blatt, gesetzt von
   `applyMarkSpacingStage()`. Eine Zeile CSS statt eines zweiten
   Zeichenwegs: der Renderer baut in Stufe 1 und 2 dasselbe, nur die
   Sichtbarkeit unterscheidet sich. STUFE 0 STEHT HIER NICHT — dort wird
   die Kette gar nicht erst gebaut, und das ist billiger als sie
   auszublenden (Befund B-PF2). */
.sheet[data-mark-spacing-stage="2"] [data-mark-spacing] { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .sheet [data-mark-handle], .sheet [data-mark-spacing] { transition: none; }
}
.sheet.is-dragging-handle, .sheet.is-dragging-handle [data-handle-dot],
.sheet.is-dragging-handle [data-measure-dot],
.sheet.is-dragging-handle [data-mark-handle],
.sheet.is-dragging-handle [data-vertex-dot]:not([data-locked]) { cursor: grabbing; }
/* ÜBERFAHREN ([2/10] der PD Zusatzpunkte-Richtungen). Die Fläche selbst
   zeigt schon „grab“ (Ansicht schieben) — über einem Griff zeigt der
   Zeiger deshalb die Hand zum Zeigen: sonst sähe Punkt und leere Fläche
   gleich aus. Gesetzt von app.js nach DERSELBEN Suche wie beim Druck
   (die Trefferfläche ist etwas größer als der sichtbare Kreis). */
.sheet.is-over-handle { cursor: pointer; }
.sheet.is-over-handle.is-dragging-handle { cursor: grabbing; }
/* LINIE ANWÄHLEN ([7/10] der PD Zusatzpunkte-Richtungen): über einer
   anwählbaren Nahtlinie zeigt der Zeiger die Hand — gesetzt von app.js
   nach derselben Suche, die der Klick benutzt (edgeAt). Ein Griff hat
   Vorrang; die Klasse fehlt dann. */
.sheet.is-over-edge { cursor: pointer; }
.sheet.is-panning.is-over-edge { cursor: grabbing; }
/* RICHTUNGSPFEILE ([3/10] der PD Zusatzpunkte-Richtungen). Feld
   „nur beim Überfahren“: Laschen nur am hervorgehobenen Kreis. Im Zug an
   einer Lasche treten die anderen Laschen ab (data-tab-off, gesetzt von
   SvgRenderer.markHover). Die Trefferprüfung in app.js überspringt
   dieselben Laschen — was man nicht sieht, greift man nicht. */
.sheet [data-arrows="hover"] [data-dot-tabs] { display: none; }
.sheet [data-arrows="hover"] [data-hover] [data-dot-tabs] { display: inline; }
.sheet [data-tab-off] { display: none; }
/* Die Hinweiszeile liegt ÜBER der Zeichnung, OBEN links, und fängt keine
   Maus. Leer = unsichtbar. Oben, weil die Unterkante der Fläche ohne
   Scrollen unter dem Fensterrand liegt (gemessen im Chrome, 2026-09-21:
   Fläche bis 817 px, Fenster 739 px). */
.dot-hint {
  position: absolute; left: var(--sp-2); top: var(--sp-2);
  width: max-content; max-width: calc(100% - 2 * var(--sp-2));
  padding: var(--sp-1) var(--sp-2);
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  font-size: var(--fs-sm);
  pointer-events: none;
}
.dot-hint:empty { display: none; }
/* DAS MASSFENSTER beim Ziehen ([4/10] der PD Zusatzpunkte-Richtungen).
   HTML über der Fläche, nicht im SVG — es kann deshalb nie in Datei oder
   Druck geraten. Den Ort setzt js/app.js (LabelPlacer) als left/top:
   ein Laufzeitwert aus Daten, deshalb inline (UNIVERSAL §3). */
.drag-readout {
  position: absolute; left: 0; top: 0;
  width: max-content; max-width: calc(100% - 2 * var(--sp-2));
  padding: var(--sp-1) var(--sp-2);
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  line-height: 1.35;
  pointer-events: none;
}
.drag-readout[hidden] { display: none; }
.drag-readout > :first-child { font-weight: 600; }
/* Die Ebene trägt die Größe der Zeichnung in Bildpunkten und wird
   verschoben und vergrößert. Das SVG selbst wird NICHT angefasst — es
   behält seine Millimeter für Export und Druck. */
/* KEIN will-change und KEIN scale(): beides erzeugt eine Grafikschicht
   mit fester Auflösung, deren Linien beim Zoomen gedehnt statt neu
   gezeichnet werden. Die Ebene bekommt stattdessen ihre wahre Größe
   (js/base/zoom-pan.js), verschoben wird nur. */
.zoom-layer {
  position: absolute; left: 0; top: 0;
  transform-origin: 0 0;
}
.zoom-layer > svg { display: block; width: 100%; height: 100%; }
/* PD Pfeile-Grenzen-Farben: [6/7] Griffe, Pfeile, Ringe und Schilder am
   Rand der Zeichnung werden NICHT am <svg> abgeschnitten (ein <svg>
   schneidet sonst an seinem Rand). Datei und Druck haben keine Griffe (§40).
   [5/7] Hintergrund der Zeichnung — nur am Bildschirm, per CSS, nie in der
   Datei (kein Rechteck im SVG). */
.zoom-layer > svg { overflow: visible; background: var(--sheet-canvas-bg); }
/* Die Zeichnung HAT ein Papier-Rechteck (data-layer="paper", fill im
   Attribut für die Datei). Am Bildschirm färbt es die CSS-Regel um — CSS
   schlägt das Attribut; die Datei (serialize liest Attribute) und der
   Druck (#print-root) bleiben weiß. Nachbesserung [5+1/7] der PD
   Pfeile-Grenzen-Farben: vorher verdeckte das Rechteck die Farbe. */
.zoom-layer > svg > [data-layer="paper"] { fill: var(--sheet-canvas-bg); }

/* Werkzeuge über der Zeichnung: Zoom, Einpassen, Ansicht. */
.sheet-tools { justify-content: flex-start; }
.toolbar .tool-btn {
  width: auto; min-width: 0; min-height: var(--toolbtn-h);
  padding: var(--sp-1) var(--sp-3);
  font-size: var(--fs-sm);
  background: transparent; color: var(--ink); border-color: var(--line-strong);
}
.toolbar .tool-btn:hover { background: var(--accent-soft); }
.toolbar .tool-btn[aria-pressed="true"] {
  background: var(--accent); color: var(--accent-ink); border-color: var(--accent);
}
/* Die Reset-Knöpfe bei den Schaltern (PD Massgriffe-Reset-Seitenleiste):
   abgeschaltet, solange es nichts zurückzusetzen gibt. */
.toolbar .tool-btn:disabled { opacity: .45; cursor: default; background: transparent; }
/* Ein gezogener Formwert in der Punkte-Tabelle. */
tr.row-changed td { color: var(--accent); }
.sheet-tools .zoom-readout {
  font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--ink-soft);
  min-width: 5ch; text-align: right;
}
.sheet-tools .field { margin: 0; }
/* Feld „Richtungspfeile“ ([3/10]) steht zwischen den Schaltern: Beschriftung
   und Auswahl NEBENEINANDER, sonst wird die Leiste eine Zeile höher und die
   Zeichnung rückt nach unten (gesehen im Chrome, 2026-09-21: 64 px). */
.toolbar .arrows-field { display: flex; align-items: center; gap: var(--sp-1); margin: 0; }
/* `hidden` muss STÄRKER sein als das display der Zeile darüber — sonst
   stünde das Feld „Verschluss" (§63.7) an jeder Kante da, obwohl es nur
   an der Verschlusskante etwas bewirkt. Dieselbe Regel hat die
   Winkel-Gruppe weiter unten, aus demselben Grund. */
.toolbar .arrows-field[hidden] { display: none; }
.toolbar .arrows-field .field-label-row { margin: 0; }
/* Messanzeige ([8/9]): leiser als die Blattgröße, rechts daneben. */
.sheet-tools .perf-readout { opacity: .75; }
/* Die angewählte Linie ([7/10]): gedämpft, solange keine gewählt ist;
   mit gelber Unterkante, sobald eine gewählt ist — dieselbe Farbe wie die
   Unterlegung in der Zeichnung. */
.sheet-tools .edge-readout { opacity: .75; border-bottom: 2px solid transparent; }
.sheet-tools .edge-readout.is-set { opacity: 1; border-bottom-color: var(--draw-select); }
.sheet-tools .field > label { margin-bottom: 0; }
.sheet-tools .layout-field { min-width: var(--field-min-w); }

/* ---------- Die Leiste, neu (PD Leiste-Anordnung-Winkel, L1–L3) --------
   EINE Zeile aus Gruppen mit Trennstrich; die Schalter stecken in zwei
   Klappmenüs. Drei Stufen über body[data-bar]: "full" (Wörter),
   "compact" (nur Zeichen, Name im Tooltip), "off" (weg; der Knopf
   „☰ Leiste“ über der Zeichnung holt sie zurück). Mockup:
   doc/mockup-leiste-anordnung-winkel.html. */
.sheet-tools { gap: var(--sp-1) var(--sp-2); }
.bar-group {
  display: flex; align-items: center; gap: var(--sp-1);
  padding-right: var(--sp-2); border-right: 1px solid var(--line);
}
.bar-group:last-child { border-right: none; padding-right: 0; }
.bar-spacer { flex: 1 1 auto; }
.bar-label { color: var(--ink-soft); }
.undo-count { font-size: var(--fs-xs); color: var(--ink-soft); min-width: 2ch; }
.bar-menu { position: relative; }
.bar-pop {
  position: absolute; left: 0; top: calc(100% + var(--sp-1));
  z-index: 22;
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2);
  min-width: var(--bar-pop-min-w);
  /* Höher als das Bild wird es nicht — dann wird IM Fenster gescrollt.
     `overscroll-behavior` hält das Rad im Fenster: am Ende der Liste soll
     nicht die Zeichnung dahinter zoomen. */
  max-height: var(--bar-pop-max-h); overflow-y: auto; overscroll-behavior: contain;
  padding: var(--sp-3);
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: var(--card-shadow);
}
.bar-pop[hidden] { display: none; }
.bar-pop .tool-btn { width: 100%; }
.bar-seg { display: flex; }
.bar-seg .tool-btn { border-radius: 0; margin-left: -1px; }
.bar-seg .tool-btn:first-child { border-radius: var(--radius) 0 0 var(--radius); margin-left: 0; }
.bar-seg .tool-btn:last-child { border-radius: 0 var(--radius) var(--radius) 0; }
/* Zeichen oder Wort je Stufe. */
.bar-icon { display: none; }
body[data-bar="compact"] .sheet-tools .bar-icon { display: inline; }
body[data-bar="compact"] .sheet-tools .bar-text,
body[data-bar="compact"] .sheet-tools .bar-full-only,
body[data-bar="compact"] .sheet-tools .bar-field .field-label-row { display: none; }
body[data-bar="compact"] .sheet-tools .tool-btn { padding: var(--sp-1) var(--sp-2); }
body[data-bar="off"] .sheet-tools { display: none; }
/* Über der Zeichnung, ohne sie zu verschieben: Kontextzeile und der
   Knopf „☰ Leiste“. Eine Zeile der Höhe 0 vor der Fläche; ihr Inhalt
   liegt absolut über deren oberem Rand. */
.sheet-overlay { position: relative; height: 0; z-index: 5; }
.sheet-overlay-row {
  position: absolute; left: var(--sp-2); right: var(--sp-2); top: var(--sp-2);
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--sp-2);
  pointer-events: none;
}
.sheet-overlay-row > * { pointer-events: auto; }
.bar-pill { display: none; }
body[data-bar="off"] .bar-pill { display: inline-flex; }
.bar-pill {
  width: auto; min-width: 0; min-height: var(--toolbtn-h);
  padding: var(--sp-1) var(--sp-3); font-size: var(--fs-sm);
  background: var(--surface); color: var(--ink); border: 1px solid var(--line-strong);
}
.sheet-context {
  margin: 0; padding: var(--sp-1) var(--sp-2);
  background: var(--surface); border: 1px solid var(--draw-select); border-radius: var(--radius);
  box-shadow: var(--card-shadow);
}
.sheet-context[hidden] { display: none; }
.sheet-context .field { margin: 0; }
.sheet-context .edge-readout { font-weight: 600; color: var(--ink); }
.angle-group[hidden] { display: none; }
.angle-input { width: var(--angle-input-w); min-height: var(--toolbtn-h); text-align: right; }
/* Die Kontextzeile der Marke ([8/11] der PD Knoepfe-von-Hand, §74).
   `hidden` muss stärker sein als das `display: flex` der Gruppe — dieselbe
   Regel und derselbe Grund wie bei der Winkel-Gruppe darüber. */
.mark-group[hidden] { display: none; }
.mark-group .mark-field input { width: var(--mark-input-w); text-align: right; }
/* Das Schild „gerechnet“ / „von Hand“. Es ist LEISE, solange gerechnet
   wird, und tritt hervor, sobald der Mensch eingegriffen hat: der Schild
   soll auffallen, wenn er etwas meldet, und nicht die ganze Zeit. */
.row-badge {
  padding: 0 var(--sp-1); border: 1px solid var(--line); border-radius: var(--radius);
  font-size: var(--fs-xs); color: var(--ink-soft); white-space: nowrap;
}
.row-badge.is-manual {
  border-color: var(--draw-mark-handle); color: var(--draw-mark-handle); font-weight: 600;
}
/* Ein gesperrtes Zahlenfeld der Seitenleiste ([8/11]): auch sein NAME
   wird blass. Ohne das sieht nur das Eingabefeld gesperrt aus, und die
   Beschriftung daneben verspricht weiter eine Einstellung. */
.field.is-locked > .field-label-row { opacity: .6; }
/* Was nur liest, steht unter der Zeichnung (L2). */
.sheet-status {
  display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4);
  margin-top: var(--sp-1); font-size: var(--fs-sm); color: var(--ink-soft);
}
.sheet-status .zoom-readout { font-family: var(--font-mono); }
.sheet-status .perf-readout { opacity: .75; }
.sheet-status .is-warn { color: var(--warn-ink); font-weight: 600; }
/* ---------- Leiste Version 2 (PD Leiste-V2) -------------------------
   Stil 1:1 aus doc/mockup-leiste-v2.html (freigegeben 2026-09-21):
   Symbolknöpfe 30 × 30, durchsichtig, beim Überfahren hell hinterlegt,
   gedrückt mit Akzentrahmen, dritte Stufe („mixed“) voll gefüllt. */
.sheet-tools-v2 { display: none; gap: var(--sp-1) var(--ib-group-gap); }
body[data-bar="v2"] .sheet-tools-v2 { display: flex; }
body[data-bar="v2"] #sheet-tools { display: none; }
.sheet-tools-v2 .grp { display: flex; align-items: center; gap: var(--ib-gap); padding-right: var(--ib-group-gap); border-right: 1px solid var(--line); }
.sheet-tools-v2 .grp:last-child { border-right: none; }
/* GRUPPENNAMEN KLEIN UNTER DER LEISTE (W19, Freigabe mit „weiter"): der
   Name steht in `data-cap` (übersetzt), die CSS schreibt ihn unter die
   Gruppe. Er fängt keine Maus. */
.sheet-tools-v2 .grp-named { position: relative; padding-bottom: var(--bar-cap-h); }
/* STUFE „aus" und „beim Überfahren": kein Platz unter der Leiste — sie
   springt beim Umschalten nicht in der Höhe (das Zucken, das der User
   nicht will). Beim Überfahren legt sich der Name UNTER die Gruppe, über
   die Zeichnung, und fängt keine Maus. */
body[data-bar-caps="off"] .sheet-tools-v2 .grp-named,
body[data-bar-caps="hover"] .sheet-tools-v2 .grp-named { padding-bottom: 0; }
body[data-bar-caps="off"] .sheet-tools-v2 .grp-named::after { display: none; }
body[data-bar-caps="hover"] .sheet-tools-v2 .grp-named::after { display: none; }
body[data-bar-caps="hover"] .sheet-tools-v2 .grp-named:hover::after {
  display: block; top: 100%; bottom: auto; z-index: 21; padding: 0 var(--sp-1);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
}
.sheet-tools-v2 .grp-named::after {
  content: attr(data-cap); position: absolute; left: 0; right: var(--ib-group-gap); bottom: 0;
  font-size: var(--bar-cap-fs); line-height: var(--bar-cap-h); color: var(--ink-soft);
  text-align: center; white-space: nowrap; pointer-events: none; overflow: hidden;
}
/* „▾ mehr": ein Menü am Ende der Gruppe, das Fenster zeigt die Knöpfe in
   einer Reihe, die umbricht (sie sind Symbolknöpfe wie in der Leiste). */
.sheet-tools-v2 .bar-more > .bar-menu-btn {
  height: var(--ib-size); min-height: 0; padding: 0 var(--sp-1); font-size: var(--fs-sm);
  background: transparent; color: var(--ink-soft); border: 1px solid transparent; font-weight: 400;
}
.sheet-tools-v2 .bar-more > .bar-menu-btn:hover { background: var(--accent-soft); border-color: var(--line); }
.sheet-tools-v2 .bar-more-only > .bar-menu-btn { color: var(--ink); }
.sheet-tools-v2 .bar-more-only > .bar-menu-btn .bar-name { display: none; }
.sheet-tools-v2 .bar-more-only > .bar-menu-btn svg { width: var(--ib-icon); height: var(--ib-icon); stroke: currentColor; fill: none;
  stroke-width: var(--ib-stroke); stroke-linecap: round; stroke-linejoin: round; }
.sheet-tools-v2 .bar-more-pop { flex-direction: row; flex-wrap: wrap; align-items: center; gap: var(--ib-gap); min-width: 0; max-width: var(--bar-more-max-w); padding: var(--sp-2); }
.ib {
  position: relative; flex: none;
  width: var(--ib-size); height: var(--ib-size); min-width: 0; min-height: 0;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0; margin: 0;
  border: 1px solid transparent; border-radius: var(--ib-radius);
  background: transparent; color: var(--ink); cursor: pointer;
  filter: none;
}
.ib:hover { background: var(--accent-soft); border-color: var(--line); filter: none; }
.ib[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.ib[aria-pressed="mixed"] { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.ib:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.ib:disabled { opacity: .4; cursor: default; background: transparent; border-color: transparent; }
.ib svg {
  width: var(--ib-icon); height: var(--ib-icon);
  stroke: currentColor; fill: none; stroke-width: var(--ib-stroke);
  stroke-linecap: round; stroke-linejoin: round;
}
.ib .lvl { position: absolute; right: var(--ib-gap); bottom: 1px; font-size: var(--ib-lvl-fs); font-weight: 700; }
.sheet-tools-v2 select, .zoom-island select {
  font: inherit; font-size: var(--fs-sm); height: var(--ib-select-h); min-height: 0; width: auto;
  padding: 0 var(--sp-1); border: 1px solid var(--line-strong); border-radius: var(--ib-radius);
  background: var(--surface); color: var(--ink);
}
.sheet-tools-v2 .origin { display: none; align-items: center; gap: var(--sp-1); font-size: var(--fs-sm); color: var(--ink-soft); }
.sheet-tools-v2 .origin.show { display: inline-flex; }
.sheet-tools-v2 .cnt { font-size: var(--ib-cnt-fs); color: var(--ink-soft); min-width: var(--ib-cnt-w); }
/* Der Tooltip (js/base/tooltip.js): dunkel, klein, fängt keine Maus. */
.app-tip {
  position: fixed; z-index: 60;
  max-width: var(--tip-max-w); padding: var(--tip-pad-y) var(--sp-2);
  border-radius: var(--ib-radius);
  background: var(--tip-bg); color: var(--tip-ink);
  border: 1px solid var(--tip-line);
  font-size: var(--fs-sm); line-height: 1.35;
  pointer-events: none; box-shadow: var(--tip-shadow);
}
.app-tip[hidden] { display: none; }
.app-tip b { display: block; margin-bottom: 2px; }
/* A·B·C (Mockup doc/mockup-tooltip-abc.html, freigegeben 2026-09-27 mit
   „kleinen Wörtern"): B und C je eine eigene Zeile, das Kennwort klein
   und blass davor. */
.app-tip .tip-what, .app-tip .tip-how { display: block; }
.app-tip .tip-how { margin-top: var(--tip-part-gap); }
.app-tip .tip-lab { color: var(--tip-lab-ink); font-size: var(--fs-xs); font-weight: 600; margin-right: var(--tip-lab-gap); }
.app-tip kbd {
  font-family: inherit; font-size: var(--fs-xs);
  border: 1px solid var(--tip-kbd-line); border-radius: 3px;
  padding: 0 var(--sp-1); margin-left: var(--sp-1);
}
/* Zoom-Insel unten rechts in der Zeichnung (Figma/Framer-Muster, R1). */
.zoom-island {
  position: absolute; right: var(--zoom-island-inset); bottom: var(--zoom-island-inset); z-index: 4;
  display: none; align-items: center; gap: var(--ib-gap); padding: var(--zoom-island-pad);
  background: var(--zoom-island-bg);
  border: 1px solid var(--line-strong); border-radius: var(--zoom-island-radius);
  box-shadow: var(--zoom-island-shadow);
  cursor: default;
}
body[data-bar="v2"] .zoom-island { display: flex; }
/* Wechselknopf ⤢ ⇄ 100 % ([ST] 2026-09-21): eingepasst trägt er Text. */
.ib.ib-wide { width: auto; padding: 0 var(--sp-1); }
.ib .ib-text { font-size: var(--fs-sm); font-weight: 700; white-space: nowrap; }

/* Text unter der Zeichnung aus ([ST] 2026-09-21): Legende und die
   Fußzeile IM Blatt. Nur Bildschirm — Datei und Druck bleiben (§23). */
body[data-foottext="off"] #sheet .legend,
body[data-foottext="off"] #sheet [data-layer="footer"] { display: none; }

/* Körperschablone ([6/10] der PD Vorschau-Koerper-Punktlisten, §57).
   Kommt NIE in Datei oder Druck (§56.10) — deshalb reine CSS-Klassen statt
   Attribut-Farben, anders als der Schnitt-Renderer (svg-renderer.js). */
/* Alle Maße hier sind SVG-BENUTZEREINHEITEN (= mm, wie im Schnitt-SVG),
   keine Bildschirm-Pixel — die "px" ist nur die von CSS verlangte
   Einheit; sie wächst und schrumpft mit dem Zoom, weil .zoom-layer > svg
   die ganze Zeichnung samt viewBox skaliert. */
/* Die GRÖSSEN kommen als CSS-Variablen am Wurzelknoten des Körper-SVG an
   (js/render/body-renderer.js, [5/7] der PD Koerperfigur-Nacharbeit): sie
   hängen an der Figurhöhe, nicht am Thema. Die Ersatzwerte hier gelten
   nur, falls ein SVG ohne diese Variablen ankommt. */
.body-svg { --body-title-fs: 50px; --body-mark-fs: 38px; --body-fig-w: 5px;
            --body-mark-w: 5px; --body-lead-w: 2px; }
.body-view .fig { fill: var(--draw-body-fill); stroke: var(--draw-body-stroke);
                  stroke-width: var(--body-fig-w); stroke-linejoin: round; }
/* Die Beschriftung liegt IN der Zeichnung, also auf weißem Papier — sie
   nimmt ein Token der ZEICHNUNG, kein Token der Oberfläche ([2/7] der PD
   Koerperfigur-Nacharbeit). Mit --ink-soft stand sie in den dunklen Themen
   hellgrau auf Weiß. */
.body-view .fig-title { font-size: var(--body-title-fs); fill: var(--draw-constr); }
/* ANSICHT „ZUSAMMENGESETZT" (§60): die gelegten Schnittteile über der
   Figur. Sie liegen halb durchsichtig darüber, damit die Figur darunter
   sichtbar bleibt — sie ist der Bezug, an dem man sieht, ob etwas sitzt.
   Die Nahtlinien sind gestrichelt (Vorgabe): eine Naht ist eine LINIE, an
   der genäht wird, und kein Schnittrand. Beides ist umschaltbar. */
.body-svg .lay { fill: var(--draw-fabric-fill); stroke: var(--draw-fabric-line);
                 stroke-width: calc(var(--body-fig-w) * 1.1); stroke-linejoin: round; }
.body-svg.seam-dashed .lay { stroke-dasharray: calc(var(--body-fig-w) * 4) calc(var(--body-fig-w) * 3); }
.body-svg.lay-multi .lay { fill: hsl(var(--lay-hue) 55% 45% / .18);
                           stroke: hsl(var(--lay-hue) 60% 34%); }
/* Überfahren sagt, welches Abbild man vor sich hat — beim Ärmel gibt es
   zwei, und der Tooltip nennt seinen Namen. */
.body-svg .lay:hover { stroke-width: calc(var(--body-fig-w) * 2.2); }
/* DAS KLEINE SONDERMENÜ „Stoff und Nähte" ([1/7] der PD
   Leiste-aufraeumen-und-Anspringen): je Zeile ein Wort und daneben die
   Symbolknöpfe. Es steht neben dem Umschalter und nur, solange die
   Ansicht „Zusammengesetzt" läuft. */
.asm-menu[hidden] { display: none; }
.asm-row { display: flex; align-items: center; gap: var(--sp-1); margin-bottom: var(--sp-1); }
.asm-row-label { font-size: var(--fs-sm); color: var(--ink-soft); min-width: 7.5em; }
.asm-row .ib[aria-pressed="true"] { background: var(--accent-soft, rgba(36, 87, 214, .14)); }
.mk { cursor: pointer; }
.mk .mk-ln { stroke: var(--draw-measure); stroke-width: var(--body-mark-w); fill: none; stroke-linecap: round; }
.mk .mk-dot { fill: var(--draw-paper); stroke: var(--draw-measure); stroke-width: var(--body-mark-w); }
.mk .mk-lbl { font-size: var(--body-mark-fs); fill: var(--draw-measure); dominant-baseline: middle; }
/* Die Zeigerlinie zur Beschriftung ist duenn und blass: sie verbindet,
   sie zeigt nichts an. */
.mk .mk-lead { stroke: var(--draw-measure); stroke-width: var(--body-lead-w); opacity: .55; fill: none; }
/* Blass, wer nicht zum gewählten Kleidungsstück gehört — wie „Weitere
   Maße" (§30): ausgeblendet wird nichts, damit man sieht, dass es da ist. */
.mk.mk-dim .mk-ln, .mk.mk-dim .mk-dot, .mk.mk-dim .mk-lead { opacity: .3; }
.mk.mk-dim .mk-lbl { opacity: .4; }
/* Überfahren der Marke SELBST, und die Hervorhebung vom Maßfeld aus
   (applyMarkHighlight() in js/app.js, W9) — dieselbe Wirkung, zwei Wege
   dorthin. */
.mk:hover .mk-ln, .mk.mk-active .mk-ln { stroke-width: calc(var(--body-mark-w) * 2); }
.mk:hover .mk-lbl, .mk.mk-active .mk-lbl { font-weight: 700; }
/* MARKE MIT BEFUND ([6/9] derselben PD): die Marke ist der Ort, an dem ein
   falsches Mass am schnellsten auffaellt — man sieht die zu breite Huefte UND
   den Strich daneben leuchten. Kein neues Token: orange ist --draw-unnatural
   (wie Feld und Griff), rot ist --draw-control, das dunkle Rot, das auch auf
   Papier auffallen muss — es hebt sich vom gewoehnlichen Markenrot
   (--draw-measure) ab. Blass (mk-dim) wird ueberstimmt: ein Befund an einem
   Mass, das dieses Kleidungsstueck nicht braucht, ist trotzdem ein Befund. */
.mk.mk-warn .mk-ln, .mk.mk-warn .mk-lead { stroke: var(--draw-unnatural); }
.mk.mk-warn .mk-dot { stroke: var(--draw-unnatural); }
.mk.mk-warn .mk-lbl { fill: var(--draw-unnatural); font-weight: 700; }
.mk.mk-err .mk-ln, .mk.mk-err .mk-lead { stroke: var(--draw-control); }
.mk.mk-err .mk-dot { stroke: var(--draw-control); }
.mk.mk-err .mk-lbl { fill: var(--draw-control); font-weight: 700; }
.mk.mk-warn .mk-ln, .mk.mk-err .mk-ln { stroke-width: calc(var(--body-mark-w) * 1.8); }
.mk.mk-dim.mk-warn .mk-ln, .mk.mk-dim.mk-warn .mk-dot, .mk.mk-dim.mk-warn .mk-lead,
.mk.mk-dim.mk-err .mk-ln, .mk.mk-dim.mk-err .mk-dot, .mk.mk-dim.mk-err .mk-lead { opacity: 1; }
.mk.mk-dim.mk-warn .mk-lbl, .mk.mk-dim.mk-err .mk-lbl { opacity: 1; }

/* Ein Klick auf eine Marke springt zum Maßfeld — kurzes Aufblitzen als
   Echo, dass etwas passiert ist (W9). */
@keyframes field-flash { from { background: var(--accent-soft); } to { background: transparent; } }
.field-flash { animation: field-flash 900ms ease-out; border-radius: var(--radius); }

/* Zeiger über Winkelende/Hebel und über einem Teil bei „frei“ (L4, L7). */
.sheet.is-over-aux { cursor: pointer; }
.sheet.is-over-piece { cursor: move; }
.sheet.is-dragging-piece { cursor: grabbing; }

/* Ansicht "Nur Zeichnung" ([4/6]): Kopf, Reiter und Seitenleiste werden
   AUSGEBLENDET, nicht abgeräumt — die Felder behalten ihre Werte (§30). */
body[data-focus="sheet"] header,
body[data-focus="sheet"] .tabs,
body[data-focus="sheet"] .tab-content.active .controls,
body[data-sidebar="hidden"] .tab-content.active .controls { display: none; }
body[data-focus="sheet"] .tab-content.active .layout,
body[data-sidebar="hidden"] .tab-content.active .layout { grid-template-columns: minmax(0, 1fr); }
body[data-focus="sheet"] main { padding: var(--sp-2); }
body[data-focus="sheet"] .card { margin-bottom: var(--sp-2); }
/* VOLLBILD ([4/6], berichtigt am 2026-09-21 nach der Meldung des Users
   „im Vollbild geht der Canvas nicht bis zum Bottom").
   VORHER stand am Blatt eine Höhe aus Bildschirmanteilen (62vh bzw.
   100vh minus geratener 150px). Im Vollbild ist der Bildschirm der ganze
   Platz — das Blatt bekam davon 62 % und ließ den Rest leer.
   JETZT RECHNET DER BROWSER: die Karte wird eine Spalte über die volle
   Höhe, Titel, Werkzeuge und Legende nehmen sich, was sie brauchen, und
   das Blatt bekommt den REST (flex: 1). Keine geratene Zahl mehr.
   `min-height: 0` ist Pflicht — ohne sie darf ein Flex-Kind nicht unter
   seine Inhaltsgröße schrumpfen, und das Blatt schiebt die Legende aus
   dem Bild. */
/* SEIT [8/8] DER PD MASSGRIFFE-RESET-SEITENLEISTE geht das ganze
   Dokument ins Vollbild (body[data-fullscreen]), nicht mehr die Karte:
   nur so kann die Seitenleiste als Schublade darüberfahren. Die Regeln
   der Karte bleiben dieselben — sie hängen jetzt am body-Attribut. */
body[data-fullscreen="true"] main { padding: 0; }
/* DIE BREITE IST `auto`, NICHT 100vw ([2/17] der PD Naehte-Verschluesse-
   Eigene-Teile, Meldung des Users „ich kann sie nicht mehr schließen"):
   Seit die Druckvorschau auch im Vollbild dem Knopf folgt (§61.3), ist
   `.measure-main` dort ZWEISPALTIG. Eine Karte mit 100vw füllt die erste
   Spalte und ragt genau um die Breite der Vorschau nach rechts hinaus —
   die Vorschau liegt dann ÜBER dem rechten Ende der Werkzeugleiste, also
   über „Druckvorschau", „Drucken", „Nur Zeichnung" und „Vollbild". Der
   Knopf zum Schließen war damit verdeckt. Mit `auto` teilt das Gitter die
   Breite, und die Karte bleibt in ihrer Spalte. */
body[data-fullscreen="true"] #sheet-card {
  display: flex; flex-direction: column;
  width: auto; height: 100vh;
  margin: 0; border-radius: 0; border: none;
  overflow: hidden;
  background: var(--surface);
}
body[data-fullscreen="true"] #sheet-card > .phead,
body[data-fullscreen="true"] #sheet-card > .toolbar,
body[data-fullscreen="true"] #sheet-card > .legend { flex: none; }
body[data-fullscreen="true"] #sheet-card .sheet {
  flex: 1 1 auto;
  height: auto !important;   /* schlägt die gemessene Höhe aus app.js */
  min-height: 0;
}

/* DIE SCHUBLADE ([8/8]): bei „Nur Zeichnung" (und damit im Vollbild)
   liegt die Seitenleiste fest am linken Rand, außerhalb des Bildes, und
   fährt mit body[data-sidebar="open"] herein — ÜBER die Zeichnung, die
   Zeichnung rückt nicht. Dasselbe Element, nur ein anderer Ort (§30). */
body[data-focus="sheet"] .tab-content.active .controls {
  display: block;
  position: fixed; left: 0; top: 0; bottom: 0;
  width: var(--sidebar-w); max-height: none;
  margin: 0; border-radius: 0;
  overflow: auto;
  z-index: 20;
  transform: translateX(-100%);
  visibility: hidden;
  transition: transform var(--t-fast) ease, visibility 0s linear var(--t-fast);
  box-shadow: var(--card-shadow);
}
body[data-focus="sheet"][data-sidebar="open"] .tab-content.active .controls {
  transform: none;
  visibility: visible;
  transition: transform var(--t-fast) ease, visibility 0s;
}
/* DIE SCHUBLADE VERDECKT NICHTS MEHR (Ansage des Users am 2026-09-26: „Die
   Eingabe darf den Canvas und das Buttonmenü am Top nicht verdecken, darum
   muss der Canvas dynamisch einrücken").
   VORHER lag sie ÜBER der Zeichnung und über dem linken Ende der Leiste: die
   Knöpfe dort waren nicht erreichbar, solange sie offen war, und vom Teil war
   ein Streifen verdeckt. JETZT RÜCKT DER INHALT EIN — um genau die Breite der
   Schublade. Es ist EINE Regel je Ansicht, und sie hängt am Inhalt (`main`),
   nicht an der Karte: so rücken Leiste, Zeichnung, Legende und Statuszeile
   gemeinsam, und keine der drei Ansichten braucht eine eigene Rechnung.
   DIE ZEICHENFLÄCHE MISST SICH DANACH SELBST: `fitSheetHeight()` läuft beim
   Umschalten, und der Zoom-Baustein passt eine eingepasste Ansicht über
   seinen ResizeObserver neu ein. Keine geratene Zahl. */
/* OHNE ÜBERGANG, UND ZWAR ABSICHTLICH: die Höhe der Zeichenfläche wird
   direkt nach dem Umschalten gemessen (js/app.js, setSidebar). Liefe das
   Einrücken über eine Animation, misste die App mitten in der Bewegung —
   und die Zahl wäre die von vorhin. Die Schublade selbst fährt weiter. */
body[data-sidebar="open"] main {
  padding-left: calc(var(--sidebar-w) + var(--sp-2));
}
body[data-fullscreen="true"][data-sidebar="open"] main,
body[data-projector="bare"][data-sidebar="open"] main { padding-left: var(--sidebar-w); }

/* Der Knopf „Eingabe" am linken Rand — nur bei „Nur Zeichnung" da. Er
   wandert mit der Schublade: geschlossen am Fensterrand, offen an der
   rechten Kante der Leiste. */
.sidebar-tab { display: none; }
body[data-focus="sheet"] .sidebar-tab {
  display: block;
  position: fixed; left: 0; top: 50%;
  transform: translateY(-50%);
  z-index: 21;
  width: auto; min-width: 0; min-height: var(--toolbtn-h);
  padding: var(--sp-2) var(--sp-2);
  font-size: var(--fs-sm);
  writing-mode: vertical-rl;
  border-radius: 0 var(--radius) var(--radius) 0;
  background: var(--surface); color: var(--ink); border: 1px solid var(--line-strong); border-left: none;
  transition: left var(--t-fast) ease;
}
body[data-focus="sheet"] .sidebar-tab::before { content: "▸ "; }
body[data-focus="sheet"][data-sidebar="open"] .sidebar-tab { left: var(--sidebar-w); }
body[data-focus="sheet"][data-sidebar="open"] .sidebar-tab::before { content: "◂ "; }

/* Die Legende wird hier NICHT mehr versteckt ([ST] 2026-09-21 23:40):
   sie liegt jetzt als Insel IN der Zeichnung und bleibt in jeder Ansicht
   sichtbar; aus schaltet sie nur der Knopf „Text unter der Zeichnung“. */
body[data-focus="sheet"] .disclaimer,
body[data-focus="sheet"] #construction-note { display: none; }

.legend {
  list-style: none; display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-5);
  margin: var(--sp-3) 0 0; padding: 0; font-size: var(--fs-sm); color: var(--ink-soft);
}
.legend li { display: flex; align-items: center; gap: var(--sp-2); }
/* LEGENDE ALS INSEL unten links IN der Zeichnung ([ST] 2026-09-21 23:40,
   Meldung des Users „Die Legende wird niemals sichtbar“). Vorher stand sie
   UNTER dem Blatt; fitSheetHeight() zieht das Blatt bis zum Ende der
   Seitenleiste, also lag sie unter dem Bildrand, und bei „Nur Zeichnung“/
   Vollbild war sie ausgeblendet. Gegenstück zur Zoom-Insel unten rechts,
   dieselben Tokens. Sie fängt keine Maus — ziehen geht durch sie hindurch. */
#sheet .legend {
  position: absolute; left: var(--zoom-island-inset); bottom: var(--zoom-island-inset); z-index: 4;
  margin: 0; padding: var(--sp-1) var(--sp-2); gap: var(--sp-1) var(--sp-3);
  max-width: calc(100% - 2 * var(--zoom-island-inset));
  font-size: var(--fs-xs);
  background: var(--zoom-island-bg);
  border: 1px solid var(--line-strong); border-radius: var(--zoom-island-radius);
  box-shadow: var(--zoom-island-shadow);
  pointer-events: none;
}
.sw { width: var(--legend-sw); height: 0; border-top-width: 2px; border-top-style: solid; flex: none; }
.sw.cut    { border-top-color: var(--draw-cut); border-top-width: 3px; }
.sw.seam   { border-top-color: var(--draw-seam); border-top-style: dashed; }
.sw.constr { border-top-color: var(--draw-constr); border-top-style: dashed; }
.sw.grain  { border-top-color: var(--draw-grain); }

/* ---------- Kachelkarte im Druck-Reiter ([4/5]) --------------------- */
.tiling-map {
  display: grid;
  gap: 2px;
  margin-top: var(--sp-3);
  max-width: var(--tiling-map-max-w);
}
.tile-cell {
  border: 1px dashed var(--line-strong);
  background: var(--accent-soft);
  color: var(--ink-soft);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  text-align: center;
  padding: var(--sp-2) 0;
}

/* ---------- Tabellen ------------------------------------------------ */
.table-wrap { max-height: var(--table-max-h); overflow: auto; border: 1px solid var(--line); border-radius: var(--radius); }
table { width: 100%; border-collapse: collapse; font-size: var(--fs-md); }
th, td { padding: var(--sp-2) var(--sp-2); border-bottom: 1px solid var(--line); line-height: 1.4; text-align: right; }
th {
  position: sticky; top: 0; z-index: 1;
  background: var(--surface); font-family: var(--font-ui); font-weight: 600; color: var(--ink-soft);
}
th:first-child, td:first-child { text-align: left; }
tbody tr:hover { background: var(--accent-soft); }

/* Die Kopfzeile der Punkte-Tabelle nennt das System, das gerechnet hat.
   Sie ist Herkunft, kein Messwert — deshalb abgesetzt. */
tbody tr.row-system td { font-weight: 600; background: var(--accent-soft); }

/* ---------- Druck-Reiter -------------------------------------------- */
.paper-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-1); margin-top: var(--sp-2); }
.paper-grid div {
  border: 1px dashed var(--line-strong); padding: var(--sp-3) var(--sp-1); text-align: center;
  font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-soft);
  background: var(--accent-soft);
}

/* ---------- Fehlerzähler (UNIVERSAL §15, Sammelstelle) -------------- */
.error-counter { font-size: var(--fs-sm); color: var(--danger-ink); }
.error-counter:empty { display: none; }

/* ---------- Schmale Fenster ----------------------------------------- */
@media (max-width: 1050px) {
  .layout { grid-template-columns: var(--sidebar-w-narrow) minmax(0, 1fr); gap: var(--sp-2); }
  main { padding: var(--sp-2); }
  .card { padding: var(--sp-3); }
}
@media (max-width: 900px) {
  .layout { grid-template-columns: 1fr; }
  .controls { position: static; max-height: none; }
  .tabs { overflow-x: auto; }
}
@media (max-width: 500px) {
  header { padding: var(--sp-3); }
  .two, .actions.row { grid-template-columns: 1fr; }
  .tab-btn { min-width: 0; }
}

/* ---------- Druck --------------------------------------------------- */
/* Keine @page-Größe hier: Papiergröße und Ausrichtung setzt
   js/render/print.js zur Laufzeit aus der Einstellung (ab [10/12]). */
/* Die Druckseiten liegen am Bildschirm unsichtbar im Dokument. Sie
   werden erst auf Knopfdruck gebaut (js/render/print.js) — und nur im
   Druck sind sie das Einzige, was zu sehen ist. */
#print-root { display: none; }
.print-page { position: relative; background: #fff; overflow: hidden; }
.print-inner { position: relative; }
.print-inner > svg { position: absolute; left: 0; top: 0; }
.print-foot {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: var(--print-foot-h);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-ui); font-size: var(--fs-xs); color: #333;
}

/* ---------- Vorspann: Übersicht und Maßblatt (§39) ------------------ */
/* WARUM EIGENE KLASSE statt .print-inner: dort liegt jedes SVG absolut
   in der Ecke (das ist bei einer Kachel richtig). Die Vorspannseiten
   setzen ihre Blöcke untereinander — sie brauchen den normalen Fluss.
   FESTE FARBEN, KEINE TOKENS: Papier ist weiß, egal welches Thema am
   Bildschirm eingestellt ist. Ein Maßblatt in Blaupausen-Weiß-auf-Blau
   wäre eine leere Seite und eine leere Patrone. */
.print-front {
  position: relative;
  display: flex; flex-direction: column; gap: 3mm;
  color: #000; font-family: var(--font-ui); font-size: 3.2mm; line-height: 1.35;
  overflow: hidden;
}
.print-title { font-size: 5.5mm; font-weight: 700; letter-spacing: 0.02em; }
.print-block-title { font-size: 3.4mm; font-weight: 700; margin-bottom: 1mm; }
.print-note { font-size: 2.9mm; color: #333; }
.print-note.warn { font-weight: 700; color: #000; }

.print-overview-box { flex: 1; display: flex; align-items: center; justify-content: center; min-height: 0; }
.print-overview-svg { display: block; }

.print-map { display: grid; gap: 0.6mm; }
.print-map-cell {
  border: 0.3mm dashed #666; text-align: center; padding: 1.4mm 0;
  font-family: var(--font-mono); font-size: 2.8mm; color: #333;
}

/* DIE TABELLEN GEBEN NACH, DAS KONTROLLQUADRAT NICHT. Auf kleinem Papier
   oder bei einem Kleidungsstück mit sehr vielen Maßen wäre sonst genau
   das Quadrat das, was unten vom Blatt fällt — und damit die einzige
   Aussage, die man mit dem Lineal prüfen kann (§26). */
.print-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 6mm; align-items: start;
  flex: 1 1 auto; min-height: 0; overflow: hidden; }
.print-col { display: flex; flex-direction: column; gap: 3mm; min-width: 0; }
.print-table { width: 100%; border-collapse: collapse; font-size: 2.9mm; }
.print-table td {
  padding: 0.6mm 1mm; border: none; border-bottom: 0.2mm solid #ccc;
  background: transparent; color: #000; line-height: 1.3;
}
.print-table .print-key { text-align: left; }
.print-table .print-val { text-align: right; font-family: var(--font-mono); white-space: nowrap; }
/* Liste „Punkte zum Übertragen“ ([4/10] der PD Vorschau-Koerper-Punktlisten). */
.print-transfer-sketch-box { flex: none; display: flex; justify-content: center; border: 0.3mm dashed #bbb; }
.print-transfer-sketch { display: block; }
.print-transfer-table th {
  text-align: right; font-weight: 700; padding: 0.6mm 1mm; border-bottom: 0.3mm solid #000;
  background: transparent; color: #000;
}
.print-transfer-table th:nth-child(2), .print-transfer-table td:nth-child(2) { text-align: left; font-family: var(--font-ui); }
.print-transfer-table td { text-align: right; font-family: var(--font-mono); white-space: nowrap; }
.print-transfer-table tr.corner td { font-weight: 700; }

.print-control-box { display: flex; gap: 6mm; align-items: flex-start; flex: none; }
.print-control-box.solo { justify-content: center; margin-top: 6mm; }
.print-control-notes { flex: 1; display: flex; flex-direction: column; gap: 1.5mm; min-width: 0; }
.print-control { display: block; flex: none; }
/* Die Schere (2026-09-27): solange sie scharf ist, zeigt die Fläche ein
   Fadenkreuz — jeder Druck legt eine Schneidelinie, nichts wird geschoben. */
.sheet.is-scissors, .sheet.is-scissors * { cursor: crosshair !important; }
/* „Ansicht drucken" (W18): die Zeichnung mittig auf dem Blatt. */
.print-view { display: flex; align-items: center; justify-content: center; overflow: hidden; }
.print-view > svg { display: block; flex: none; }

@media print {
  body { background: var(--draw-paper); }
  /* Gedruckt werden die Kachelseiten, nicht die Oberfläche. */
  body > *:not(#print-root) { display: none !important; }
  #print-root { display: block !important; }
  .print-page {
    display: block !important;
    page-break-after: always;
    break-after: page;
  }
  .print-page:last-child { page-break-after: auto; break-after: auto; }
  /* Gedruckt wird die Zeichnung, nicht der Ausschnitt: der Zoom wird
     zurückgenommen, sonst landet die Vergrößerung auf dem Papier. */
  .zoom-layer { transform: none !important; position: static; width: auto !important; height: auto !important; }
  .zoom-layer > svg { width: auto; height: auto; }
  .sheet { height: auto; cursor: auto; }
  header, .tabs, .no-print, .toolbar, .controls, .legend { display: none !important; }
  main { display: block; padding: 0; }
  .card { box-shadow: none; padding: 0; margin: 0; border: none; }
  .card::before, .card::after { display: none; }
  .sheet { border: none; overflow: visible; min-height: 0; }
  .table-wrap { max-height: none; overflow: visible; }
  .tab-content { display: none !important; }
  .tab-content.active { display: block !important; }
  .layout { display: block !important; }
}

/* ---------------------------------------------------------------------------
   PD Grenzen-Raster-Kalibrierung (Mockup doc/mockup-grenzen-raster-
   kalibrierung.html, freigegeben 2026-09-21).
   --------------------------------------------------------------------------- */
/* Raster ▾: nur der Pfeil ist sichtbar, der Name steht als aria-label/Titel. */
.grid-menu > .bar-menu-btn {
  width: var(--grid-caret-w); min-width: 0; height: var(--ib-size); min-height: 0;
  padding: 0; font-size: 0; border: 1px solid transparent; background: transparent; color: var(--ink-soft);
}
/* DAS ▾ WIRD GEZEICHNET, NICHT GESCHRIEBEN (2026-09-26, „nirgends
   erkennbar"): als Winkel aus zwei Rändern in der Schriftfarbe. Ein
   Textzeichen hängt an der Schrift und war in 11 px Grau kaum zu sehen. */
.grid-menu > .bar-menu-btn { color: var(--ink); }
.grid-menu > .bar-menu-btn .bar-caret,
#projector-menu > .bar-menu-btn .bar-caret {
  display: inline-block; font-size: 0; color: var(--ink);
  width: var(--caret-size); height: var(--caret-size);
  border-right: var(--caret-stroke) solid currentColor; border-bottom: var(--caret-stroke) solid currentColor;
  transform: translateY(calc(var(--caret-size) * -0.3)) rotate(45deg);
}
.grid-menu > .bar-menu-btn:hover { background: var(--accent-soft); }
.grid-menu .bar-pop .field { width: 100%; }
.grid-menu .bar-pop .field input[type="color"] { width: 100%; height: var(--ib-select-h); padding: 0; }
.grid-menu .grid-hint { margin: 0; font-size: var(--fs-xs); color: var(--ink-soft); }
/* Quadrate am Blattrand (PD Blattgroesse-Raender [6/8]): Zeiger je Richtung. */
.sheet[data-sheet-square="l"], .sheet[data-sheet-square="r"] { cursor: ew-resize; }
.sheet[data-sheet-square="t"], .sheet[data-sheet-square="b"] { cursor: ns-resize; }
.sheet[data-sheet-square="lt"], .sheet[data-sheet-square="rb"] { cursor: nwse-resize; }
.sheet[data-sheet-square="rt"], .sheet[data-sheet-square="lb"] { cursor: nesw-resize; }
/* SYMBOLKNOPF-MENÜ (.icon-menu): der Symbolknopf IM Menü öffnet es, das
   eigene ▾ des Menüs ist unsichtbar, das Fenster steht rechtsbündig (die
   Gruppe sitzt rechts in der Leiste). DREI MENÜS TEILEN SICH DIESE REGEL —
   „Stil“, „Blatt“ und „Stoff und Nähte“.
   SIE HIESS BIS ZUM 2026-09-25 .sheet-color-menu, nach ihrem ersten
   Benutzer. Beim Umbau des Farben-Menüs zum Stil-Menü ([4/14] der PD
   Projektor-Stil) wurde sie mit umbenannt — und damit verloren die zwei
   ANDEREN Menüs ihre Regel: ihr ▾-Knopf wurde sichtbar und schob den
   Knopf „Blatt“ aus der Reihe. Der Name sagt jetzt, was die Regel tut,
   und nicht, wer sie zuerst gebraucht hat (§33: ein geteilter Baustein hat
   einen Besitzer — und einen Namen, der nicht nach einem Benutzer klingt). */
.icon-menu > .bar-menu-btn { display: none; }
.icon-menu { position: relative; display: inline-flex; }
.icon-menu .bar-pop { left: auto; right: 0; }
/* Das Stil-Fenster: EINE Einrückung für jede Zeile. Links der Name, rechts
   ein Block fester Breite — und in der Zeile „Linie“ stecken in diesem
   Block die drei Bedienelemente. So beginnen alle Namen an derselben Kante
   und alle Eingaben an derselben, gleich ob die Zeile ein Feld oder drei
   trägt (Wunsch des Users, 2026-09-25). */
#style-pop { width: 340px; align-items: stretch; }
.style-fields .field { width: 100%; margin: 0; }
.style-fields .arrows-field,
.style-fields .style-line {
  display: grid; grid-template-columns: 1fr 168px;
  align-items: center; gap: var(--sp-1); margin: 0; font-size: var(--fs-xs);
}
.style-fields .arrows-field > label,
.style-fields .arrows-field .field-label-row { margin: 0; min-width: 0; }
.style-fields .style-line-ctl {
  display: grid; grid-template-columns: var(--sp-6) 1fr 68px;
  align-items: center; gap: var(--sp-1);
}
/* DIE ZEILE EINER BESCHRIFTUNG ([8+7/14]): Farbe + Größe, ohne Einheit —
   dieselbe Einrückung wie eine Linien-Zeile, nur zwei Bedienelemente. */
.style-fields .style-ink-ctl { grid-template-columns: var(--sp-6) 1fr; }
.style-fields .style-line .field { width: auto; }
.style-fields .style-line .field-label-row { display: none; }
.style-fields input[type="color"] { width: 100%; height: var(--ib-select-h); padding: 0; }
.style-fields input[type="number"],
.style-fields select { width: 100%; font: inherit; font-size: var(--fs-xs); }
.style-fields .style-line-head { color: var(--ink-soft); }
.style-fields .style-line-head .style-line-ctl span { text-align: center; }
.style-fields .grid-hint { margin: 0; }
/* Der Dreier-Schalter „Bildschirm · Projektor · Druck“ ([5/14]): drei
   gleich breite Knöpfe über die ganze Breite des Fensters. Er ist KEIN
   Feld und trägt darum auch keine Zweispalten-Einrückung — er sagt, wofür
   alle Felder darunter gelten. */
.style-fields .style-set-seg { display: flex; }
.style-fields .style-set-seg .tool-btn {
  flex: 1 1 0; width: auto; min-width: 0;
  padding: var(--sp-1) var(--sp-2); font-size: var(--fs-xs);
}
/* Die kleine Marke neben dem roten Ring ([6/14] der PD Projektor-Stil):
   beim Ziehen weg. Während man zieht, weiß man, was man greift — und die
   Marke läge unter der Maus. */
.sheet.is-dragging-piece [data-piece-grab-label] { display: none; }
/* Das Kreuz zum freien Verschieben ist in Ruhe halb durchsichtig, voll beim
   Überfahren (data-hover vom Renderer) und beim Ziehen (Ansage des Users
   2026-09-27: „weniger aufdringlich"). */
[data-piece-grab] { opacity: var(--draw-piece-grab-rest-opacity); transition: opacity var(--t-fast); }
[data-piece-grab][data-hover="true"], .sheet.is-dragging-piece [data-piece-grab] { opacity: 1; }
.sheet-status[hidden] { display: none; }
/* Die Hinweiszeile der Ansicht „Zusammengesetzt" (§60.6): eigene Zeile,
   damit sie nicht mit der Statuszeile verschwindet. */
.sheet-hint { margin: var(--sp-1) 0 0; font-size: var(--fs-sm); color: var(--ink-soft); }
.sheet-hint[hidden] { display: none; }

/* ▾-Popups K1–K3 ([7/9] der PD Winkel-Achsen-Einrasten): reine Auswahlfelder
   nutzen .grid-menu unverändert (Pfeil-only-Knopf, volle Feldbreite). Die
   Liste „Eigene Winkel“ (E5) ist das einzige Neue hier. */
#snap-pop { width: 300px; }
.own { border-top: 1px solid var(--line); margin-top: var(--sp-2); padding-top: var(--sp-1); }
.own-head { display: flex; align-items: center; gap: var(--sp-1); }
.own-head b { flex: 1; font-size: var(--fs-sm); }
.own-add { font-size: var(--fs-xs); padding: 2px var(--sp-1); }
.own-add:disabled { opacity: .5; cursor: default; }
.own-row {
  display: grid; grid-template-columns: auto 60px 1fr auto auto;
  align-items: center; gap: var(--sp-1); margin: var(--sp-1) 0; font-size: var(--fs-xs);
}
.own-row input[type="number"] { width: 60px; font: inherit; }
.own-row select { font: inherit; font-size: var(--fs-xs); }
.own-mirror { display: flex; align-items: center; gap: 3px; white-space: nowrap; }
.own-mirror.off { visibility: hidden; }
.own-del { border: 0; background: transparent; font-size: var(--fs-md); cursor: pointer; color: var(--ink-soft); padding: 0 2px; }
.own-del:hover { color: var(--ink); }

/* Maßstab an der Lupe: |———| = n mm */
.zoom-scale {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: 0 var(--sp-1); margin-right: var(--ib-gap);
  font-size: var(--fs-xs); color: var(--ink-soft); white-space: nowrap;
  border-right: 1px solid var(--line);
}
.zoom-scale i {
  display: inline-block; height: var(--zoom-scale-h);
  border: var(--zoom-scale-w) solid var(--ink); border-top: none;
}

/* Dialog „Bildschirm messen“ */
.calib p { margin: var(--sp-1) 0; font-size: var(--fs-md); line-height: 1.45; }
.calib-square-wrap { display: flex; justify-content: center; padding: var(--sp-4) 0; }
.calib-square {
  position: relative; box-sizing: content-box;
  outline: var(--calib-outline) solid var(--ink); outline-offset: 0;
  background:
    linear-gradient(var(--line) 1px, transparent 1px) 0 0 / 10% 10%,
    linear-gradient(90deg, var(--line) 1px, transparent 1px) 0 0 / 10% 10%;
}
.calib-square span {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  font-size: var(--fs-md); color: var(--ink-soft); background: var(--surface); padding: 0 var(--sp-1);
}
.calib-steps { display: flex; gap: var(--sp-2); justify-content: center; align-items: center; flex-wrap: wrap; }
.calib-steps .tool-btn, .calib-reset { width: auto; }
.calib-steps output { font-family: var(--font-mono); font-size: var(--fs-base); min-width: 9em; text-align: center; }
.calib-reset { display: block; margin: var(--sp-2) auto 0; }
.calib .calib-note { font-size: var(--fs-sm); color: var(--ink-soft); }

/* „Grenzen frei“ (Schloss) gedrückt = orange statt blau: die Farbe sagt „Vorsicht“. */
.ib.ib-unnatural[aria-pressed="true"] { background: var(--unnatural-bg); border-color: var(--unnatural); color: var(--unnatural); }
/* Maßfeld jenseits des üblichen Bereichs (nur optisch, gesperrt wird nichts). */
.field.is-unnatural input, input.is-unnatural { border: 2px solid var(--unnatural); background: var(--unnatural-bg); }
.field .unnatural-msg { display: block; font-size: var(--fs-xs); color: var(--unnatural); margin-top: var(--sp-1); }
.drag-readout .unnatural-line { color: var(--unnatural); font-weight: 600; }

/* ---------------------------------------------------------------------------
   PD Vorschau-Koerper-Punktlisten [3/10] (Mockup doc/mockup-vorschau-koerper-
   punkte.html, freigegeben 2026-09-21): Punkte zum Übertragen.
   --------------------------------------------------------------------------- */
/* Das ▾-Menü sitzt rechts in der Leiste — es klappt nach links auf. */
/* DER PROJEKTOR ([7/14] der PD Projektor-Stil, §77): das Fenster steht
   rechts in der Leiste (.icon-menu), die Blätter-Zeile ist drei Felder —
   Knopf, Name, Knopf. Der Name steht in der Mitte und bekommt den Platz,
   der übrig ist, damit die zwei Knöpfe nicht bei jedem Teilnamen wandern. */
/* STUFE 2 DES PROJEKTORS: ALLES HELLE WEG ([8+2/14] der PD Projektor-Stil,
   §77.10, Bestellung des Users am 2026-09-25). „Nur Zeichnung" nimmt Kopf,
   Reiter und Seitenleiste; HIER fällt der Rest der Oberfläche weg — die
   Leiste über der Zeichnung, die Legende, die Zoom-Insel, die Statuszeile
   und der Rahmen der Karte. Was bleibt, ist die Zeichnung auf der Fläche
   dahinter (--sheet-behind, also die Farbe aus dem geltenden Stilsatz) und
   eine Zeile mit dem Rückweg.
   ES IST KEIN ZWEITES FENSTER UND KEIN ZWEITER BILDSCHIRM (§77.1): dieselbe
   Karte, dieselbe Zeichenfläche, nur ohne das Helle drumherum. */
body[data-projector="bare"] { background: var(--sheet-behind); }
body[data-projector="bare"] main { padding: 0; background: var(--sheet-behind); }
body[data-projector="bare"] #sheet-card {
  margin: 0; padding: 0; border: none; box-shadow: none; border-radius: 0;
  background: var(--sheet-behind);
}
body[data-projector="bare"] #sheet-card > .phead,
body[data-projector="bare"] #sheet-tools,
body[data-projector="bare"] #sheet-card > .legend,
body[data-projector="bare"] #sheet-status,
body[data-projector="bare"] #sheet-hint,
body[data-projector="bare"] .sidebar-tab { display: none; }
/* DIE ZOOM-INSEL BLEIBT AUCH IN STUFE 2 (Ansage des Users am 2026-09-26:
   „Wenn die Buttonleiste versteckt ist, soll die kleine Buttonleiste rechts
   unten immer sichtbar sein" — und „Projektor 2 soll alle Funktionen zulassen,
   die Projektor 1 auch bietet"). Sie trägt Einpassen, Zoom, den Maßstab und
   die Einheit; wer am Stoff steht, braucht genau das. */ 
body[data-projector="bare"] #sheet { border-radius: 0; }
/* DER KNOPF „LEISTE ZEIGEN" BLEIBT AUCH HIER (Ansage des Users am
   2026-09-26: „Der ,Liste zeigen' Button muss auch in Projektor 1 vorhanden
   sein und funktionieren und auch in Projektor 2").
   ES IST KEIN WIDERSPRUCH ZU „alles Helle weg": weg ist, was man nicht
   bedient. Der Knopf, der die Leiste zurückholt, ist der Rückweg — und ein
   Rückweg darf nie mit dem verschwinden, was er zurückholt (§77.18).
   WAS HIER TROTZDEM WEGBLEIBT: die Kontextzeile der angewählten Linie (im
   Projektor wird nichts angewählt) und die Pille „☰ Leiste" der alten
   Leisten-Stufe „aus". */
body[data-projector="bare"] #sheet-context,
body[data-projector="bare"] #btn-bar-show { display: none; }
/* IN STUFE 2 BLEIBT DIE LEISTE STEHEN (Ansage des Users am 2026-09-26:
   „Projektor 2 soll nicht automatisch die Buttons verstecken"). Weggenommen
   wird nur das Helle DRUMHERUM — Kopf, Reiter, Seitenleiste, Rahmen. Wer die
   Leiste weghaben will, drückt „Leiste zeigen"; im Vollbild ist der Knopf da.
   AUF DEM DUNKLEN GRUND BRAUCHT SIE EINEN EIGENEN: sonst stehen schwarze
   Zeichen auf schwarz. */
body[data-projector="bare"] #sheet-tools-v2 {
  background: var(--surface); border-radius: var(--radius);
  padding-left: var(--sp-2); padding-right: var(--sp-2);
}
/* Auf der dunklen Fläche braucht der Knopf einen eigenen Grund, sonst steht
   ein schwarzes Zeichen auf schwarz. Dieselbe Hülle wie die Blätter-Knöpfe
   daneben und wie die Insel unten rechts.
   IN JEDER STUFE, nicht nur in Stufe 2 (Meldung des Users 2026-09-27: „manche
   Buttons werden bei Projektor nicht zu sehen sein wegen der Farbe, z. B.
   ,Liste zeigen'"). Dunkel ist die Fläche schon in Stufe 1, sobald der
   Stilsatz „Projektor" gilt — dann stand das Zeichen des NICHT gedrückten
   Knopfes in --ink auf Schwarz. Die Farbe der Fläche kommt aus dem Stilsatz
   und nicht aus dem Thema; eine Regel je Zustand wäre eine Wette darauf,
   dass niemand „Projektor" in Stufe 1 wählt. */
.solo-overlay > .ib {
  background: var(--zoom-island-bg); border: 1px solid var(--line-strong);
}
/* Die Zeile mit dem Rückweg: klein, blass, über der dunklen Fläche, und
   sie fängt keine Maus ab — ein Zug auf der Zeichnung geht durch. */
.projector-exit {
  margin: var(--sp-1) 0 0; text-align: center; font-size: var(--fs-xs);
  color: var(--ink-soft); pointer-events: none;
}
.projector-exit[hidden] { display: none; }
/* SIE BLENDET SICH AUS ([9/14], §77.20): drei Sekunden nach der letzten
   Mausbewegung wird sie blass, bei der nächsten kommt sie zurück. Sie bleibt
   im Dokument stehen — nur die Deckkraft wandert, und der Übergang macht
   aus dem Verschwinden kein Zucken. */
.projector-exit { transition: opacity .4s ease; }
.projector-exit.is-faded { opacity: 0; }
/* NOCH NICHT GEEICHT ([10/14], §77.21): die Auskunft steht in Orange —
   derselben Farbe, in der die App überall „unüblich, sieh hin" sagt
   (--unnatural). Sie ist kein Fehler, aber sie ist eine Warnung: ein
   projizierter Schnitt ohne Eichung ist maßstäblich falsch, und zwar
   still. */
.projector-exit.is-warn, .pj-calib-line.is-warn, #pj-calib-factor.is-warn {
  color: var(--unnatural); font-weight: 600;
}

/* ------------------------------------------------------------------------
   DIE GRÖSSTE ANSICHT IM BEARBEITUNGSMODUS (§77.17/§77.18, [8+6/14],
   Bestellung des Users am 2026-09-25). Ein Teil allein, groß, weiter
   bearbeitbar — und die Leiste fährt ein, damit die Fläche dem Teil
   gehört. Sie ist NICHT weg: der Knopf mit den Balken fährt sie von oben
   wieder herein (eingeslided, wie der User es bestellt hat).
   ES IST EINE ANSICHT UND KEIN ZWEITES FENSTER — dieselbe Karte, dieselbe
   Zeichenfläche (§77.1).
   ------------------------------------------------------------------------ */
/* DER KOPF DER KARTE ENTFÄLLT HIER ([5/7], Bestellung des Users vom
   2026-09-26: „,Am Größten' wird platzsparender: Der Header ,Zeichnung'
   entfällt"). Im Vollbild und in Stufe 2 ist er schon weg — das sind die zwei
   Zeilen darüber im Vollbild-Block und im Projektor-Block; das ist die dritte.
   DER RÜCKWEG HÄNGT NICHT AN IHM: „← Zurück" in dieser Zeile führt aus einem
   groß gezogenen Feld zurück, und dasselbe tut Escape. Escape holt auch aus
   dieser Ansicht heraus (eine Stufe je Druck) — geprüft, bevor die Zeile
   fiel. */
body[data-solo="on"] #sheet-card > .phead { display: none; }
/* DIE LEISTE IST EINGEFAHREN, WENN `data-solo-bar="off"` STEHT — und nur
   dann (Ansage des Users am 2026-09-26: „Der ,Liste Zeigen' Button soll die
   Buttonleiste auch im Vollbild ohne Projektor verstecken").
   VORHER HING DIE REGEL AM PROJEKTOR (`data-solo="on"`), und damit konnte der
   Knopf im Vollbild nichts verstecken: dort gibt es keine Stufe. JETZT SAGT
   EIN ATTRIBUT, ob die Leiste da ist, und WER es setzt, entscheidet der
   Zusammenhang — Stufe 1 und 2 fangen eingefahren an, jede andere Ansicht
   ausgefahren (js/app.js, setSoloBar/syncSoloControls).
   OHNE ATTRIBUT IST DIE LEISTE DA. Das ist der Zustand beim Start und in
   jeder Ansicht, die den Knopf nicht anbietet — eine versteckte Leiste ohne
   Knopf wäre eine Falle. */
body[data-solo-bar="off"] #sheet-tools-v2 {
  max-height: 0; opacity: 0; transform: translateY(-8px);
  overflow: hidden; padding-top: 0; padding-bottom: 0; margin: 0;
  transition: max-height .18s ease, opacity .18s ease, transform .18s ease;
}
/* Die Bedienung, die BLEIBT: sie liegt im Überlagerungs-Streifen über der
   Zeichnung und fängt ihre Zeiger selbst (sonst schiebt ein Klick die
   Ansicht). */
.solo-overlay { display: flex; align-items: center; gap: var(--ib-gap); pointer-events: auto; }
.solo-nav { display: flex; align-items: center; gap: var(--ib-gap);
  padding: 0 var(--sp-1); border-radius: var(--ib-radius);
  background: var(--zoom-island-bg); border: 1px solid var(--line-strong); }
.solo-nav[hidden] { display: none; }
.solo-name { font-size: var(--fs-xs); color: var(--ink-soft); white-space: nowrap; }

/* DIE INSEL DER STUFE 2 (§77.12, Bestellung des Users am 2026-09-25): vier
   Knöpfe unten rechts IN der Zeichenfläche — Projektor, Stil, Bildschirm
   messen, Kontrollviereck. Sie sieht aus wie die Zoom-Insel und liegt an
   deren Platz; die Zoom-Insel ist in Stufe 2 weg, sie treffen sich also
   nicht. Die Knöpfe darin sind DIESELBEN wie in der Leiste, nur umgezogen. */
/* SIE SITZT ÜBER DER ZOOM-INSEL, seit die in Stufe 2 stehen bleibt: zwei
   Inseln in derselben Ecke würden sich überdecken, und die untere gewinnt
   nichts dadurch. `--ib-size` ist die Höhe eines Symbolknopfes, zweimal
   Rand dazu — dieselben Token, aus denen die Insel selbst gebaut ist. */
.projector-island {
  position: absolute; right: var(--zoom-island-inset); z-index: 5;
  bottom: calc(var(--zoom-island-inset) + var(--ib-size) + 2 * var(--zoom-island-pad) + var(--sp-1));
  display: none; align-items: center; gap: var(--ib-gap); padding: var(--zoom-island-pad);
  background: var(--zoom-island-bg);
  border: 1px solid var(--line-strong); border-radius: var(--zoom-island-radius);
  box-shadow: var(--zoom-island-shadow);
  cursor: default;
}
/* SIE STEHT DA, SOBALD DIE LEISTE WEG IST (§77.29, Meldung des Users am
   2026-09-26: „Es fehlt immer noch, dass wenn die Buttons versteckt sind,
   mindestens der kleine Projektorknopf unten rechts im Zoom-Menü zu sehen
   ist"). Nicht erst in Stufe 2: der Projektor-Knopf liegt in der Leiste, und
   mit ihr wäre der Weg zurück verschwunden. */
body[data-solo-bar="off"] .projector-island,
body[data-projector="bare"] .projector-island { display: flex; }
/* …und immer, wenn ein Knopf in ihr steht (2026-09-27: das Kontrollviereck
   wandert in der Ansicht „ein Teil allein" auch bei sichtbarer Leiste). */
.projector-island:not(:empty) { display: flex; }
/* EIN KLAPPFENSTER AM UNTEREN RAND ÖFFNET NACH OBEN. Unten ist kein Platz:
   die Insel klebt am unteren Rand der Zeichenfläche, und ein Fenster, das
   nach unten aufgeht, liegt außerhalb des Bildes — also unerreichbar. */
.projector-island .bar-pop { top: auto; bottom: calc(100% + var(--sp-1)); left: auto; right: 0; }
/* DER ▾ DES PROJEKTOR-MENÜS IST SICHTBAR — in der Leiste UND in der Insel
   (Meldung des Users am 2026-09-25: „Ich kann den Projektor nicht mehr
   ausschalten"). Die anderen Symbolmenüs verstecken ihren ▾, weil dort der
   Symbolknopf das Fenster öffnet. Beim Projektor SCHALTET der Symbolknopf
   die Stufen, also braucht das Fenster einen eigenen Griff. Er trägt nur
   das Zeichen (den Text nimmt app.js weg). */
#projector-menu > .bar-menu-btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0 var(--sp-1); min-height: var(--ib-size);
}

.projector-nav { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--sp-1); }
.projector-nav .tool-btn { width: auto; }
.projector-name { text-align: center; font-size: var(--fs-xs); color: var(--ink-soft); }

.transfer-menu .bar-pop { left: auto; right: 0; }
.transfer-menu .bar-pop .field, #transfer-fields .field { width: 100%; }
.transfer-hint { margin: 0; font-size: var(--fs-xs); color: var(--ink-soft); }
.transfer-help { margin: 0 0 var(--sp-3); padding-left: var(--sp-5); font-size: var(--fs-sm); }
.transfer-help li { margin-bottom: var(--sp-1); }
.transfer-piece { margin-bottom: var(--sp-4); }
.transfer-piece h3 { text-transform: none; letter-spacing: 0; font-size: var(--fs-md); color: var(--ink); }
/* Ecken fett: dort treffen zwei Linien aufeinander. */
tr.transfer-corner td { font-weight: 700; }

/* ---------------------------------------------------------------------------
   PD Dreifeld-Ansicht (Mockup doc/mockup-dreifeld-ansicht.html, freigegeben
   2026-09-22). Drei Felder im Reiter „Punkte übertragen“, Druckvorschau
   rechts im Reiter „Maße & Schnitt“. Die Karten wandern (app.js
   placePanelCards); hier steht nur, wie sie in ihrem Platz aussehen.
   --------------------------------------------------------------------------- */
/* Kopfzeile eines Feldes: Titel + ⤢ (klein) bzw. ← Zurück (groß). */
.phead { display: flex; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-2); }
.phead h2 { margin: 0; flex: 1; }
/* Gleicher Stil wie die Knöpfe der Leiste (.toolbar .tool-btn) — die
   allgemeine button-Regel (volle Breite, 40 px hoch) gilt hier NICHT
   (User-Befund 2026-09-22: „Zurück viel zu breit, anderer Stil“). */
.phead .pbtn {
  flex: none; width: auto; min-width: 0; min-height: var(--toolbtn-h);
  padding: var(--sp-1) var(--sp-3);
  font-size: var(--fs-sm); white-space: nowrap;
  background: transparent; color: var(--ink); border-color: var(--line-strong);
}
.phead .pbtn:hover { background: var(--accent-soft); filter: none; }
/* Außerhalb der drei Felder (Reiter „Maße & Schnitt“) gibt es kein Groß/Klein. */
.phead .pbtn { display: none; }
.fields[data-panel="all"] .phead .pgrow { display: inline-flex; }
.fields:not([data-panel="all"]) .phead .pback { display: inline-flex; }
.fields[data-panel="all"] .phead { cursor: zoom-in; user-select: none; }
.fields[data-panel="all"] #preview-card,
.fields[data-panel="all"] #list-card { cursor: zoom-in; }
.fields[data-panel="all"] #preview-card :is(button, select, input, label, a),
.fields[data-panel="all"] #list-card :is(button, select, input, label, a) { cursor: pointer; }

/* Reiter „Maße & Schnitt“: rechts die Vorschau-Spalte, wenn an. */
.measure-main { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 var(--sp-4); align-items: start; min-width: 0; }
.measure-main.with-preview { grid-template-columns: minmax(0, 1fr) var(--preview-col-w); }
.slot-mprint[hidden] { display: none; }

/* DIE VORSCHAU GROSS — auch hier ([2/17] der PD Naehte-Verschluesse-
   Eigene-Teile, Ansage des Users). Derselbe Zustand wie im Reiter „Punkte
   übertragen“ (state.view.panel), nur dass in dieser Fläche allein die
   Vorschau groß werden kann: „Zeichnung“ und „Liste“ gehören dem anderen
   Reiter. Die Knöpfe ⤢ und „← Zurück“ standen immer schon in der
   Kopfzeile der Karte (index.html) — sie waren nur an `.fields` gebunden
   und hier deshalb unsichtbar. */
.measure-main[data-panel="print"] { grid-template-columns: minmax(0, 1fr); }
.measure-main[data-panel="print"] > .slot-mdraw { display: none; }
.measure-main[data-panel="print"] > .slot-mprint { display: block; }
.measure-main[data-panel="print"] #preview-card { overflow: auto; margin-bottom: 0; }
.measure-main[data-panel="all"] #preview-card .phead { cursor: zoom-in; user-select: none; }
.measure-main[data-panel="all"] #preview-card .phead .pgrow { display: inline-flex; }
.measure-main[data-panel="print"] #preview-card .phead .pback { display: inline-flex; }
.measure-main[data-panel="print"] #preview-card .phead {
  position: sticky; top: calc(-1 * var(--sp-4)); z-index: 5;
  background: var(--surface); padding: var(--sp-1) 0;
}

/* Reiter „Punkte übertragen“: Zeichnung | Vorschau / Liste | Vorschau. */
.fields {
  display: grid; min-width: 0;
  grid-template-columns: minmax(0, 1fr) var(--preview-col-w);
  grid-template-areas: "draw print" "list print";
  gap: 0 var(--sp-4); align-items: start;
}
.fields > .slot-draw { grid-area: draw; min-width: 0; }
.fields > .slot-print { grid-area: print; min-width: 0; }
.fields > .slot-list { grid-area: list; min-width: 0; }
/* Ein Feld groß: nur dieses, über die ganze Breite, es rollt in sich. */
.fields:not([data-panel="all"]) { grid-template-columns: minmax(0, 1fr); grid-template-areas: "only"; }
.fields:not([data-panel="all"]) > div { display: none; }
.fields[data-panel="draw"] > .slot-draw,
.fields[data-panel="print"] > .slot-print,
.fields[data-panel="list"] > .slot-list { display: block; grid-area: only; }
.fields[data-panel="print"] #preview-card,
.fields[data-panel="list"] #list-card { overflow: auto; margin-bottom: 0; }
.fields:not([data-panel="all"]) .phead {
  position: sticky; top: calc(-1 * var(--sp-4)); z-index: 5;
  background: var(--surface); padding: var(--sp-1) 0;
}
.fields[data-panel="list"] .table-wrap { max-height: none; }

/* Die Vorschau-Seiten: echte Druckseiten (mm), per `zoom` verkleinert
   (app.js fitPreviewPages). Klein zeigt Seite 1, groß alle untereinander. */
.preview-kind { margin-bottom: var(--sp-2); }
.preview-kind[hidden] { display: none; }
.preview-pages { display: flex; flex-direction: column; align-items: center; gap: var(--preview-gap); }
.preview-pages .print-page { flex: none; border: 1px solid var(--line); box-shadow: var(--card-shadow); }
.fields[data-panel="all"] .preview-pages .print-page:not(:first-child),
.measure-main:not([data-panel="print"]) .preview-pages .print-page:not(:first-child) { display: none; }
#preview-note { margin: var(--sp-2) 0 0; }

@media (max-width: 1150px) {
  .measure-main.with-preview { grid-template-columns: minmax(0, 1fr); }
  .fields { grid-template-columns: minmax(0, 1fr); grid-template-areas: "draw" "print" "list"; }
}

/* „Nur Zeichnung“ (F) und Vollbild im Reiter „Punkte übertragen“: nur die
   Zeichnung, wie in „Maße & Schnitt“ — Vorschau und Liste treten zurück. */
body[data-focus="sheet"] .fields { grid-template-columns: minmax(0, 1fr); grid-template-areas: "draw"; }
body[data-focus="sheet"] .fields > .slot-print,
body[data-focus="sheet"] .fields > .slot-list { display: none; }
body[data-focus="sheet"] .fields > .slot-draw { display: block; grid-area: draw; }
/* DIE DRUCKVORSCHAU RECHTS FOLGT DEM KNOPF, AUCH HIER ([4/7] der PD
   Leiste-aufraeumen-und-Anspringen, Ansage des Users). Vorher stand hier
   das Gegenteil: in „Nur Zeichnung" und im Vollbild wurde die Spalte
   ausgeblendet, der Knopf schaltete also richtig und man sah nichts.
   Der Gedanke von damals („nur die Zeichnung") gilt weiter für die Liste
   im Reiter „Punkte übertragen" — dort steht er zwei Zeilen höher —, aber
   nicht mehr für eine Vorschau, die der Nutzer gerade angefordert hat. */

/* Dreier-Schalter „Punkte zum Übertragen“: der Knopf sitzt IM Menü, das
   eigene ▾ des Menüs ist unsichtbar — der Knopf selbst öffnet es als
   zweite Stufe. Die Stufe zeigt die Ziffer (FieldFactory.setStage) —
   der frühere Punkt „offen“ am Knopf ist entfallen, er lag an derselben
   Stelle und sagte dasselbe (PD Pfeile-Snap-Groesse-Hinweise [2/7]). */
.transfer-menu > .bar-menu-btn { display: none; }
.transfer-menu { position: relative; display: inline-flex; }
.transfer-menu .pop-close {
  position: absolute; top: var(--sp-1); right: var(--sp-1);
  border: 0; background: transparent; color: var(--ink-soft);
  font-size: var(--fs-md); line-height: 1; cursor: pointer; padding: var(--sp-1);
}
.transfer-menu .pop-close:hover { color: var(--ink); }
/* Die Felder eines blauen oder roten Punktes in der Kontextzeile
   ([8+1/13]). Ist ein solcher Punkt angewählt (data-mode="point"), steht
   NUR seine Gruppe in der Zeile — die Knöpfe der Linie gehören zu keiner
   Linie. */
.sheet-context[data-mode="point"] > :not(.point-group) { display: none; }
.sheet-context[data-mode="edge"] > .point-group { display: none; }
.point-group { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.point-group[hidden] { display: none; }
.point-fields { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.point-shared { color: var(--ink-soft); }
/* Die Schnittkante ([8/14] der PD Teil-trennen). Solange sie offen ist
   (data-mode="cut"), steht NUR ihre Gruppe in der Zeile — dieselbe Regel
   wie beim blauen und roten Punkt. */
.sheet-context[data-mode="cut"] > :not(.cut-group) { display: none; }
.sheet-context[data-mode="edge"] > .cut-group,
.sheet-context[data-mode="point"] > .cut-group { display: none; }
/* DAS FENSTER DER SCHNITTKANTE ([7+5/9] der PD Schnittkante-Punktfang-
   Winkel-Hover, freigegebenes Mockup doc/mockup-schnittkante-fenster-
   kompakt.html). Ein Kopf, der immer steht (Name, Prüfzeile, Schneiden,
   Verwerfen), darunter klappbare Abschnitte (FieldFactory.section). Das
   Raster ist Beschriftung · Feld · Einheit, jedes Feld gleich breit.
   Gemessen vorher: die alte Zeile verdeckte bei 1366 × 768 58,7 % der
   Zeichenfläche — 40 px hohe Felder mit der Beschriftung DARÜBER. */
.cut-panel {
  display: flex; flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 0; margin: 0;
  min-width: 0; font-size: var(--fs-md); color: var(--ink);
}
.cut-group[hidden] { display: none; }
.cut-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-2); padding-bottom: var(--sp-1); }
/* Der Name gibt zuerst nach (Auslassungspunkte), bevor die Knöpfe in eine
   zweite Zeile rutschen; voll steht er im Tooltip (syncCutRow). */
.cut-head .cut-readout { flex: 1 1 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cut-head .tool-btn { flex: none; padding: 0 var(--sp-2); }
.cut-grip { display: none; color: var(--ink-soft); letter-spacing: -2px; user-select: none; }
.cut-note { flex: 1 1 100%; order: 9; font-size: var(--fs-sm); }
.cut-sug-label { font-variant-numeric: tabular-nums; }
.cut-why, .cut-note { color: var(--ink-soft); }
.fold { border-top: 1px solid var(--line); }
.fold-head {
  list-style: none; cursor: pointer; user-select: none;
  display: flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-1) 0; font-size: var(--fs-sm); font-weight: 600; color: var(--ink);
}
.fold-head::-webkit-details-marker { display: none; }
.fold-head::before { content: "▸"; width: 1em; flex: none; color: var(--ink-soft); }
.fold[open] > .fold-head::before { content: "▾"; }
.fold-head:hover { color: var(--accent); }
.fold-peek { margin-left: auto; padding-left: var(--sp-2); font-weight: 400; color: var(--ink-soft); white-space: nowrap; font-variant-numeric: tabular-nums; }
.fold[open] > .fold-head .fold-peek { display: none; }
.fold-body { padding: 0 0 var(--sp-2) var(--sp-3); }
.cut-grid {
  display: grid; grid-template-columns: var(--cut-label-w) var(--cut-field-w) var(--cut-unit-w);
  gap: var(--sp-1) var(--sp-2); align-items: center;
}
.cut-grid .cut-field { display: contents; }
.cut-grid .field-label-row { margin: 0; }
.cut-panel .cut-field input {
  width: var(--cut-field-w); height: var(--cut-input-h); min-height: 0;
  padding: 0 var(--sp-1); font-size: var(--fs-md); text-align: right;
}
.cut-unit { color: var(--ink-soft); font-size: var(--fs-sm); }
.cut-atab {
  display: grid; grid-template-columns: var(--cut-end-w) var(--cut-field-w) var(--cut-field-w) auto;
  gap: var(--sp-1) var(--sp-2); align-items: center;
}
.cut-atab .cut-field { margin: 0; }
/* Die Namen „Ende A · α" bleiben für den Vorleser — sichtbar steht die
   Tabelle mit Kopf α β und der Zeile „Ende A" (UNIVERSAL §15). */
.cut-atab .field-label-row {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; margin: 0;
}
.cut-atab-h { text-align: center; font-weight: 600; color: var(--ink-soft); }
.cut-end { font-weight: 700; color: var(--draw-cut-tool); }
.cut-sug { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); }
.cut-why { font-size: var(--fs-sm); margin-top: var(--sp-1); }
.cut-panel .cut-order { margin-top: var(--sp-1); }
.cut-panel .cut-order select { height: var(--cut-input-h); min-height: 0; padding: 0 var(--sp-1); font-size: var(--fs-md); }
.cut-panel .tool-btn { min-height: var(--cut-input-h); }
/* OBEN ANGEDOCKT (bis 2026-09-27 die Vorgabe, jetzt „schwebend“): flach — Prüfzeile im Kopf, zwei Felder je
   Zeile, die Abschnitte nebeneinander. Die Höhe ist hier das knappe Gut. */
.cut-panel[data-place="dock"] { flex: 1 1 100%; }
.cut-panel[data-place="dock"] .cut-note { flex: 1 1 16em; order: 1; }
.cut-panel[data-place="dock"] .cut-head > .tool-btn { order: 2; }
.cut-panel[data-place="dock"] .cut-secs { display: flex; flex-wrap: wrap; align-items: flex-start; }
.cut-panel[data-place="dock"] .fold { border-top: 0; border-left: 1px solid var(--line); padding: 0 var(--sp-2); }
.cut-panel[data-place="dock"] .fold:first-child { border-left: 0; padding-left: 0; }
.cut-panel[data-place="dock"] .cut-grid {
  grid-template-columns: var(--cut-label-w) var(--cut-field-w) var(--cut-unit-w) var(--cut-label-w) var(--cut-field-w) var(--cut-unit-w);
}
/* SCHWEBEND UND SEITENLEISTE: ein eigenes Fenster im Streifen über der
   Zeichnung (#sheet-overlay). Die Lage beim Schweben setzt js/app.js
   (placeCutPanel) — ein Laufzeitwert, daher inline. */
.cut-panel[data-place="float"], .cut-panel[data-place="side"] {
  position: absolute; z-index: 6; width: var(--cut-panel-w);
  padding: var(--sp-1) var(--sp-2); overflow: auto;
  background: var(--surface); border: 1px solid var(--draw-select); border-radius: var(--radius);
}
.cut-panel[data-place="float"] { max-height: var(--bar-pop-max-h); box-shadow: var(--tip-shadow); }
.cut-panel[data-place="float"] .cut-head { cursor: move; }
.cut-panel[data-place="float"] .cut-grip { display: inline; }
.cut-panel.is-moving { opacity: .85; }
.cut-panel[data-place="side"] { top: 0; right: 0; }
/* In der Seitenleiste deckt das Fenster NICHTS zu: die Fläche wird um
   seine Breite schmaler; eine eingepasste Ansicht passt ZoomPan selbst an
   (ResizeObserver, §35). */
#sheet-card[data-cut-side="on"] .sheet { margin-right: calc(var(--cut-panel-w) + var(--sp-2)); }
/* Im geworfenen Projektor gibt es keine Kontextzeile (§77.10) — und damit
   auch kein Fenster der Kante, wo immer es sitzt. */
body[data-projector="bare"] .cut-panel { display: none; }
body[data-projector="bare"] #sheet-card[data-cut-side="on"] .sheet { margin-right: 0; }
/* KEIN ZUCKEN (User 2026-09-27: „Das Fenster darf nicht immer zucken …
   weil es ständig die Größe anpasst"). Alles, dessen TEXT sich beim Ziehen
   oder Umstellen ändert, hat einen festen Platz — sonst wächst das Fenster,
   angedockt schiebt es die Zeichnung, und die passt sich neu ein.
   - Prüfzeile und Grund: immer genau --cut-text-lines Zeilen hoch; mehr
     wird gekürzt, voll steht es im Tooltip (syncCutRow).
   - Stand in der Überschrift: schrumpft mit Auslassungspunkten statt das
     Fenster zu verbreitern; angedockt eine feste Breite.
   - „Schneiden“ ⇄ „Einschneiden (kommt später)“: EINE feste Breite; der
     lange Name wird gekürzt (voll im Tooltip), statt die Knöpfe in eine
     zweite Zeile zu schieben oder im Knopf umzubrechen.
   - „Vorschlag n von m“ ⇄ „kein Vorschlag“: feste Breite. */
.cut-note, .cut-why {
  line-height: var(--cut-text-lh);
  height: calc(var(--cut-text-lines) * var(--cut-text-lh) * 1em);
  overflow: hidden;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: var(--cut-text-lines);
}
.fold-name { flex: none; }
.fold-peek { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.cut-panel[data-place="dock"] .fold-peek { flex: none; width: var(--cut-peek-w); text-align: right; }
.cut-panel[data-place="dock"] .cut-why { width: var(--cut-why-w); }
.cut-sug-label { display: inline-block; width: var(--cut-sug-w); text-align: center; white-space: nowrap; }
.cut-head #btn-cut-go { flex: none; width: var(--cut-go-w); min-width: 0; overflow: hidden; }
.cut-head #btn-cut-go .bar-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* „so trennt das nicht“ hängt nicht allein an der Farbe: der Knopf
   „Schneiden“ ist dann gesperrt und heißt anders (UNIVERSAL §15). */
.cut-note.is-bad { color: var(--danger-ink); }
.cut-group .tool-btn.is-go { background: var(--accent-soft); border-color: var(--accent); font-weight: 600; }

/* ---- PROJEKT: Name, Speichern, Laden, Stil (PD Stil-Speichern-Laden-
   Projektname [4/9]/[5/9], Mockup doc/mockup-speichern-laden-projektname.html).
   Die Gruppe steht ganz vorn und ist hervorgehoben (Bild 1). */
.grp-project {
  background: var(--accent-soft); border: 1px solid var(--accent);
  border-radius: var(--ib-radius); padding: 0 var(--sp-1);
}
.project-name {
  width: var(--project-name-w); height: var(--ib-size);
  padding: 0 var(--sp-2); margin-right: var(--sp-1);
  font-family: var(--font-ui); font-size: var(--fs-sm); color: var(--ink); background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--ib-radius);
}
.project-name::placeholder { color: var(--ink-soft); font-style: italic; }
.project-dirty { color: var(--accent); font-weight: 700; margin: 0 var(--sp-1) 0 calc(-1 * var(--sp-1)); cursor: default; }
.project-dirty[hidden] { display: none; }

/* Das Schild „Gespeichert/Geladen" oben in der Zeichnung. */
#bar-status {
  position: absolute; top: var(--zoom-island-inset); left: 50%; transform: translateX(-50%); z-index: 5;
  padding: var(--sp-1) var(--sp-3); border-radius: var(--zoom-island-radius);
  font-size: var(--fs-sm); pointer-events: none;
  background: var(--success-bg); color: var(--success-ink); border: 1px solid var(--line-strong);
  box-shadow: var(--zoom-island-shadow);
}
#bar-status.warn { background: var(--warn-bg); color: var(--warn-ink); }
#bar-status[hidden] { display: none; }

/* Der Namens-Dialog beim ersten Speichern (Bild 3). */
.name-dialog { display: grid; gap: var(--sp-2); }
.name-dialog-label { display: grid; gap: var(--sp-1); font-size: var(--fs-sm); font-weight: 600; }
.name-dialog-label input { height: var(--ib-select-h); padding: 0 var(--sp-2); font: inherit; font-weight: 400;
  border: 1px solid var(--line-strong); border-radius: var(--ib-radius); color: var(--ink); background: var(--surface); }
.name-dialog-hint { font-size: var(--fs-xs); color: var(--ink-soft); }

/* Der Lade-Dialog mit Ablagefeld (Bild 2). */
.load-dialog { display: grid; gap: var(--sp-3); }
.load-pick {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: calc(var(--ib-size) + var(--sp-2)); padding: 0 var(--sp-3);
  background: var(--accent); color: var(--accent-ink); border: 1px solid var(--accent);
  border-radius: var(--ib-radius); font: inherit; font-weight: 600; cursor: pointer;
}
.load-pick-icon { display: inline-flex; width: var(--ib-icon); height: var(--ib-icon); }
.load-pick-icon svg { width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: var(--ib-stroke); }
.load-or { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-xs); color: var(--ink-soft); }
.load-or::before, .load-or::after { content: ""; flex: 1; border-top: 1px solid var(--line); }
.load-drop {
  display: grid; justify-items: center; align-content: center; gap: var(--sp-1);
  min-height: var(--load-drop-min-h); padding: var(--sp-4); text-align: center;
  background: var(--surface); color: var(--ink-soft); font: inherit; cursor: pointer;
  border: 2px dashed var(--line-strong); border-radius: var(--radius);
}
.load-drop.is-over { background: var(--accent-soft); border-color: var(--accent); border-style: solid; }
.load-drop-big { font-size: var(--load-drop-icon); line-height: 1; color: var(--line-strong); }
.load-drop.is-over .load-drop-big, .load-drop.is-over .load-drop-text { color: var(--accent); }
.load-drop-text { font-weight: 600; color: var(--ink); }
.load-drop-hint { font-size: var(--fs-xs); }
.load-drop-error { font-size: var(--fs-sm); color: var(--danger-ink); font-weight: 600; }
.load-drop-error[hidden] { display: none; }
.load-note { font-size: var(--fs-xs); color: var(--ink-soft); }
