@rslsp1/fa-app-tools 10.3.2 → 10.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/StageEngine-O5I654LD.js +1243 -0
- package/dist/StageEngine-PYWITIIY.mjs +1243 -0
- package/dist/{chunk-ACB2543O.js → chunk-DDH2SGZM.js} +113 -20
- package/dist/{chunk-TFWIMFNF.mjs → chunk-GKLCL2VQ.mjs} +111 -18
- package/dist/{chunk-HFX6D53W.js → chunk-VSHSZEGV.js} +1810 -606
- package/dist/{chunk-JP7LIWDR.mjs → chunk-XLNA2BD6.mjs} +1448 -244
- package/dist/index.d.mts +53 -2
- package/dist/index.d.ts +53 -2
- package/dist/index.js +265 -106
- package/dist/index.mjs +531 -372
- package/dist/szenen.d.mts +610 -279
- package/dist/szenen.d.ts +610 -279
- package/dist/szenen.js +75 -29
- package/dist/szenen.mjs +48 -2
- package/package.json +1 -1
- package/dist/StageEngine-3MOBM2WX.mjs +0 -590
- package/dist/StageEngine-5VR3KEZB.js +0 -590
package/dist/index.js
CHANGED
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
var
|
|
20
|
+
var _chunkVSHSZEGVjs = require('./chunk-VSHSZEGV.js');
|
|
21
21
|
require('./chunk-FTLEDU6C.js');
|
|
22
|
-
require('./chunk-
|
|
22
|
+
require('./chunk-DDH2SGZM.js');
|
|
23
23
|
|
|
24
24
|
// package.json
|
|
25
|
-
var version = "10.3.
|
|
25
|
+
var version = "10.3.3";
|
|
26
26
|
|
|
27
27
|
// src/hooks/useOnClickOutside.ts
|
|
28
28
|
var _react = require('react'); var _react2 = _interopRequireDefault(_react);
|
|
@@ -61,7 +61,7 @@ function useKeyboardNavigation(history, currentResult, setCurrentResult) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
// src/features/szenen/szenenViewStyles.generated.ts
|
|
64
|
-
var SZENEN_VIEW_STYLES = '/* ==========================================================================\n SZENEN VIEW\n ========================================================================== */\n\n.szenen-view {\n display: grid;\n gap: var(--space-md);\n width: 100%;\n min-width: 0;\n font-family: var(--font-sans);\n padding: var(--space-md);\n}\n\n@media (max-width: 760px) {\n .szenen-view {\n padding: var(--space-sm);\n gap: var(--space-sm);\n }\n}\n\n/* Kette `szenen-design`, P1 \u2014 Bild zuerst, Text auf Abruf. Der Kopf ist nur\n * noch Titel und \u24D8; die Erklaerung klappt darunter auf. */\n.szenen-view__intro {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: var(--space-sm);\n color: var(--color-text-primary);\n}\n\n.szenen-view__titel {\n display: grid;\n gap: 0.1rem;\n min-width: 0;\n}\n\n.szenen-view__intro h2,\n.szenen-view__intro p {\n margin: 0;\n}\n\n.szenen-view__intro h2 {\n font-size: clamp(1.5rem, 3vw, 1.9rem);\n font-weight: 700;\n letter-spacing: -0.01em;\n line-height: 1.15;\n}\n\n.szenen-view__eyebrow {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n.szenen-view .szenen-view__info {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n min-height: 2.75rem;\n padding: 0;\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-view__info[aria-expanded="true"] {\n color: var(--color-text-primary);\n border-color: var(--color-accent-teal, #2dd4bf);\n}\n\n.szenen-view__intro-text {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n font-size: 0.85rem;\n line-height: 1.4;\n}\n\n.szenen-icon {\n flex: none;\n}\n\n/* Fuer Screenreader sichtbar, fuer das Auge nicht \u2014 Status-Punkte und\n * Node-Symbole tragen ihre Bedeutung als Text. */\n.szenen-visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n/* Die Bereiche als Pill-Leiste. Sie scrollt in sich, nie die Seite: `min-width:\n * 0` haelt sie in der Spalte, `overflow-x: auto` macht jeden Bereich\n * erreichbar, auch wenn nicht alle nebeneinander passen. */\n.szenen-view__nav {\n display: flex;\n flex-wrap: nowrap;\n gap: var(--space-xs);\n min-width: 0;\n padding: 0 0 var(--space-xs);\n overflow-x: auto;\n scrollbar-width: thin;\n}\n\n.szenen-view__nav button,\n.szenen-view button {\n min-height: 2.25rem;\n padding: 0.45rem 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-view button:hover:not(:disabled) {\n color: var(--color-text-primary);\n background: var(--color-bg-surface-hover);\n border-color: var(--color-border-hover);\n}\n\n.szenen-view button:focus-visible,\n.szenen-view input:focus-visible,\n.szenen-view select:focus-visible,\n.szenen-view textarea:focus-visible {\n outline: 2px solid var(--color-accent-blue);\n outline-offset: 2px;\n}\n\n.szenen-view button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.szenen-view .szenen-view__nav button {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.4rem;\n min-height: 2.25rem;\n padding: 0 0.9rem;\n white-space: nowrap;\n border-radius: var(--radius-full);\n font-size: 0.875rem;\n}\n\n.szenen-view .szenen-view__nav button.is-active,\n.szenen-view .szenen-view__nav button[aria-selected="true"] {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border-color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-view__area {\n min-width: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-view__capability-note,\n.szenen-area__lead {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border-left: 3px solid var(--color-accent-purple);\n border-radius: var(--radius-sm);\n}\n\n.szenen-view__host-notes {\n color: var(--color-text-secondary);\n}\n\n.szenen-view__host-notes > summary {\n cursor: pointer;\n font-size: 0.8rem;\n}\n\n/* `box-sizing` steht hier und nicht beim Host: Die React-App bringt in\n * `master.css` einen globalen `* { box-sizing: border-box }` mit, Flow **nicht**\n * \u2014 dort ragte `width: 100%` plus Innenabstand um die Randbreite aus dem\n * Elternelement heraus und erzeugte auf ~390 px einen horizontalen Scroll. Die\n * gemeinsame Ansicht darf sich auf keinen Host-Reset verlassen. */\n.szenen-view input:not([type="checkbox"]),\n.szenen-view select,\n.szenen-view textarea {\n box-sizing: border-box;\n width: 100%;\n min-height: 2.25rem;\n padding: 0.5rem 0.65rem;\n color: var(--color-text-primary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font: inherit;\n}\n\n.szenen-view textarea {\n min-height: 7rem;\n resize: vertical;\n font-family: var(--font-mono);\n font-size: 0.8rem;\n}\n\n.szenen-view label {\n display: grid;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n.szenen-view code,\n.szenen-view pre {\n font-family: var(--font-mono);\n overflow-wrap: anywhere;\n}\n\n.szenen-view h3,\n.szenen-view h4,\n.szenen-view h5 {\n margin-top: 0;\n}\n\n.szenen-view ul,\n.szenen-view ol {\n padding-left: 1.25rem;\n}\n\n.szenen-elements,\n.szenen-detail,\n.szenen-scene,\n.szenen-setup,\n.szenen-erweitert,\n.szenen-prompts,\n.szenen-shot,\n.szenen-media,\n.szenen-runs {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n/* Arbeitsoberflaeche: Liste links, Bearbeitung rechts.\n *\n * Breit stehen beide Spalten nebeneinander \u2014 die Auswahl bleibt sichtbar,\n * waehrend bearbeitet wird. Schmal rendert die Komponente nur eine der beiden;\n * hier steht deshalb keine Regel, die die andere versteckt. */\n@media (min-width: 761px) {\n .szenen-elements {\n grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);\n align-items: start;\n }\n\n .szenen-elements__master,\n .szenen-elements__detail {\n min-width: 0;\n }\n}\n\n.szenen-elements__master,\n.szenen-elements__detail {\n display: grid;\n gap: var(--space-sm);\n align-content: start;\n min-width: 0;\n}\n\n.szenen-elements__toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-elements__heading {\n margin: 0;\n font-size: 1.05rem;\n}\n\n.szenen-elements__scope {\n display: flex;\n align-items: center;\n gap: var(--space-xs);\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-elements__scope > select {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.szenen-elements__new {\n flex: none;\n font-weight: 700;\n}\n\n.szenen-elements__create {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-accent-blue);\n border-radius: var(--radius-sm);\n}\n\n.szenen-elements__create label {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-elements__create-actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n}\n\n.szenen-elements__options > summary {\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n cursor: pointer;\n}\n\n.szenen-elements__back {\n justify-self: start;\n font-weight: 700;\n}\n\n.szenen-elements__empty-detail {\n margin: 0;\n color: var(--color-text-tertiary);\n}\n\n.szenen-elements__filter,\n.szenen-detail__actions,\n.szenen-runs__start,\n.szenen-scene-editor__add,\n.szenen-scene-editor__add-relation {\n display: flex;\n flex-wrap: wrap;\n align-items: end;\n gap: var(--space-sm);\n}\n\n.szenen-elements__filter > label,\n.szenen-runs__start > label,\n.szenen-scene-editor__add > input {\n flex: 1 1 16rem;\n}\n\n.szenen-elements__filter > label:has(input[type="checkbox"]) {\n display: flex;\n flex: 1 1 16rem;\n flex-direction: row;\n align-items: center;\n}\n\n.szenen-elements__filter input[type="checkbox"] {\n width: 1rem;\n height: 1rem;\n accent-color: var(--color-accent-blue);\n}\n\n.szenen-elements__list {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-elements__list > li > button {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs) var(--space-sm);\n width: 100%;\n height: 100%;\n text-align: left;\n}\n\n.szenen-elements__list > li > button > .szenen-elements__title {\n flex: 1 1 100%;\n}\n\n.szenen-elements__list > li > button.is-selected,\n.szenen-elements__list > li > button[aria-current="true"] {\n background: var(--color-accent-blue-dim);\n border-color: var(--color-accent-blue);\n}\n\n.szenen-elements__type {\n color: var(--color-accent-blue);\n font-size: 0.75rem;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.szenen-elements__title {\n color: var(--color-text-primary);\n font-size: 0.95rem;\n}\n\n.szenen-elements__subtype,\n.szenen-elements__retired {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-elements__retired {\n color: var(--color-warning);\n}\n\n.szenen-detail {\n margin-top: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n@media (min-width: 761px) {\n .szenen-detail {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n }\n}\n\n.szenen-detail > header,\n.szenen-detail__heads,\n.szenen-detail__draft,\n.szenen-capability {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n/* .szenen-runs ist ein eigenst\xE4ndiger sichtbarer Bereich, beh\xE4lt Styling auf Desktop */\n@media (min-width: 761px) {\n .szenen-runs {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n }\n}\n\n@media (max-width: 760px) {\n .szenen-runs {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n }\n}\n\n.szenen-detail__ids {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin-bottom: 0;\n color: var(--color-text-secondary);\n}\n\n.szenen-detail__heads ul,\n.szenen-scene-editor ul,\n.szenen-runs > ol,\n.szenen-capability > ul {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-detail__heads li,\n.szenen-scene-editor li,\n.szenen-runs > ol > li,\n.szenen-capability > ul > li {\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n\n/* Stufe 6.7.2 (D-126) \u2014 Advanced-/Debug-Fl\xE4che f\xFCr die rohe, schema-getriebene\n * Feldliste einer Szene. Gestrichelt wie die anderen \u201EAngebot statt\n * Auskunft"-Bereiche, aber ohne Akzentfarbe: sie ist kein Vorschlag, sondern\n * ein Eskalationsweg. */\n.szenen-detail__technical {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__technical > summary {\n margin-bottom: var(--space-sm);\n color: var(--color-text-secondary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-detail__technical[open] > summary {\n margin-bottom: var(--space-md);\n}\n\n.szenen-detail__field small,\n.szenen-capability small {\n color: var(--color-text-tertiary);\n}\n\n.szenen-detail__preview-errors,\n.szenen-detail__notice--error,\n.szenen-view [role="alert"] {\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-color: var(--color-accent-red);\n}\n\n.szenen-detail__notice {\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__notice--success,\n.szenen-view [data-tone="success"] {\n color: #bbf7d0;\n background: var(--color-accent-green-dim);\n border-color: var(--color-accent-green);\n}\n\n.szenen-scene-editor {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-md);\n margin-bottom: 0;\n}\n\n.szenen-scene-editor > section {\n min-width: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n/* \u2500\u2500 Stufe 6.7.2 (D-126): Node-/Relationskarten \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Nodes und Beziehungen sind `<details>` \u2014 dieselbe Interaktionssprache wie\n * \u201ERohantwort (Diagnose)" und \u201EBilder zu diesem Lauf" in RunsPanel.tsx. Kopf\n * (immer sichtbar) tr\xE4gt Inhalt zuerst, Technik zuletzt; Body (nur bei\n * ge\xF6ffneter Karte) tr\xE4gt die Bearbeitungscontrols. Padding wandert von der\n * `<li>` in Kopf/Body, damit die Karte keinen doppelten Rand bekommt. */\n.szenen-scene-editor li {\n padding: 0;\n overflow: hidden;\n}\n\n.szenen-node-karte__kopf,\n.szenen-relation-karte__kopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs) var(--space-sm);\n padding: var(--space-sm);\n cursor: pointer;\n list-style: none;\n}\n\n.szenen-node-karte__kopf::-webkit-details-marker,\n.szenen-relation-karte__kopf::-webkit-details-marker {\n display: none;\n}\n\n.szenen-node-karte__titel {\n flex: 1 1 12rem;\n min-width: 0;\n color: var(--color-text-primary);\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n\n.szenen-node-karte__typ {\n flex: none;\n padding: 0.15rem 0.55rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.72rem;\n white-space: nowrap;\n}\n\n/* node_id klein, monospace, sekund\xE4r \u2014 sichtbar auch bei zugeklappter Karte,\n * aber optisch klar hinter Beschreibung und Typ. */\n.szenen-node-karte__meta {\n flex: 1 1 100%;\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n}\n\n.szenen-node-karte__meta code {\n font-size: inherit;\n}\n\n.szenen-node-karte__body,\n.szenen-relation-karte__body {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-sm) var(--space-sm);\n border-top: 1px solid var(--color-border);\n}\n\n/* \xA74 \u2014 Prim\xE4raktion und destruktive Aktion optisch getrennt: \u201ENode/Beziehung\n * entfernen" bekommt einen eigenen, warnenden Ton statt gleichgewichtig neben\n * der normalen Bearbeitung zu stehen. */\n.szenen-node-karte__entfernen,\n.szenen-relation-karte__entfernen {\n justify-self: start;\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-color: var(--color-accent-red);\n}\n\n.szenen-relation-karte__kopf {\n font-size: 0.9rem;\n}\n\n.szenen-relation-karte__kopf code {\n overflow-wrap: anywhere;\n}\n\n.szenen-relation-karte__pfeil {\n flex: none;\n color: var(--color-text-secondary);\n}\n\n/* Die Composer-\xD6ffner (\u201E+ Node hinzuf\xFCgen", \u201E+ Beziehung hinzuf\xFCgen") sind\n * Angebote, keine Ausk\xFCnfte \u2014 dasselbe gestrichelte Muster wie beim Folgelauf\n * und der Fehlerrettung (\xA73.3/\xA73.5). */\n.szenen-scene-editor__oeffnen {\n width: 100%;\n border-style: dashed;\n}\n\n.szenen-refpicker {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n margin: var(--space-sm) 0;\n padding: var(--space-sm) 0;\n border: none;\n border-radius: 0;\n}\n\n.szenen-refpicker legend {\n padding: 0 var(--space-xs);\n color: var(--color-text-secondary);\n font-weight: 600;\n}\n\n.szenen-capability > ul > li {\n display: grid;\n grid-template-columns: minmax(10rem, 1fr) auto minmax(14rem, 2fr);\n align-items: start;\n gap: var(--space-sm);\n}\n\n.szenen-capability__state {\n padding: 0.1rem 0.5rem;\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.szenen-capability__state--yes {\n color: #bbf7d0;\n background: var(--color-accent-green-dim);\n}\n\n.szenen-capability__state--no {\n color: #fecaca;\n background: var(--color-accent-red-dim);\n}\n\n.szenen-capability__state--unknown {\n color: #fef08a;\n background: rgba(234, 179, 8, 0.2);\n}\n\n.szenen-runs > ol > li {\n display: grid;\n gap: var(--space-sm);\n}\n\n/* B1 \u2014 die geschlossene Runde. Vorher stand die `run_id` als erstes und war\n die einzige Information, die niemand liest; jetzt beantwortet die Kopfzeile\n welche Runde, ob sie durchging, mit welchem Modell und was ungef\xE4hr\n herauskam. */\n.szenen-runs__hinweis {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n}\n\n.szenen-runs__kopf {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-sm);\n width: 100%;\n padding: var(--space-xs) 0;\n text-align: left;\n color: var(--color-text-secondary);\n background: transparent;\n border: none;\n cursor: pointer;\n}\n\n.szenen-runs__marke {\n font-weight: 700;\n color: var(--color-text-primary);\n}\n\n.szenen-runs__status {\n padding: 0.05rem 0.4rem;\n font-size: 0.6875rem;\n font-weight: 600;\n text-transform: uppercase;\n border-radius: var(--radius-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n}\n\n.szenen-runs__status[data-status="succeeded"] {\n border-color: var(--color-success);\n}\n\n.szenen-runs__status[data-status="failed"] {\n border-color: var(--color-danger);\n}\n\n.szenen-runs__modell {\n font-size: 0.75rem;\n}\n\n/* Der Auszug ist die Inhaltsvorschau der Runde. Er bekommt eine eigene Zeile,\n damit er nicht mit Marke und Modell um dieselbe Zeile ringt. */\n.szenen-runs__auszug {\n flex: 1 1 100%;\n min-width: 0;\n color: var(--color-text-tertiary);\n font-size: 0.8125rem;\n}\n\n/* B2 \u2014 ein Fehler steht ausserhalb der aufklappbaren Fl\xE4che: Wer eine rote\n Runde sieht, soll nicht erst klicken m\xFCssen, um zu erfahren, woran sie\n gescheitert ist. */\n.szenen-runs__fehler {\n display: grid;\n gap: var(--space-xs);\n padding: var(--space-sm);\n border-radius: var(--radius-sm);\n}\n\n.szenen-runs__fehler p {\n margin: 0;\n}\n\n.szenen-runs__inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-runs__prompt > h5,\n.szenen-runs__sekundaer > h5 {\n margin: 0 0 var(--space-xs);\n}\n\n/* Im Kopf traegt die Zeile selbst den Abstand \u2014 sonst kaeme er doppelt. */\n.szenen-runs__promptkopf > h5 {\n margin: 0;\n}\n\n/* Ueberschrift und Kopierknopf in einer Zeile. Der Knopf gehoert an den Text,\n den er kopiert \u2014 nicht an den Rand der Runde, wo er neben dem falschen\n Abschnitt stuende. */\n.szenen-runs__promptkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-sm);\n margin: 0 0 var(--space-xs);\n}\n\n/* Ein kompakter Knopf, kein zweiter Titel: Der Prompt ist die Hauptsache des\n Abschnitts, die Aktion daneben darf ihn nicht ueberstimmen. Rahmen und\n Hintergrund kommen aus `.szenen-view button` und bleiben \u2014 dieselbe Optik wie\n jeder andere Knopf der Ansicht; hier wird nur die Groesse zurueckgenommen.\n Zwei Klassen im Selektor, weil `.szenen-view button` sonst spezifischer ist. */\n.szenen-runs__promptkopf .szenen-runs__kopieren {\n min-height: 0;\n padding: 0.1rem 0.45rem;\n font-size: 0.72rem;\n}\n\n/* Regel 11: die Bestaetigung nennt die Zahl, nicht nur \u201EErfolgreich". */\n.szenen-runs__kopiert {\n color: var(--color-text-tertiary, var(--color-text-secondary));\n font-size: 0.72rem;\n}\n\n.szenen-runs__prompt > p {\n margin: 0;\n white-space: pre-wrap;\n}\n\n.szenen-runs__prompt--negativ > p,\n.szenen-runs__sekundaer > p {\n margin: 0;\n color: var(--color-text-secondary);\n white-space: pre-wrap;\n}\n\n.szenen-runs__mehr {\n justify-self: start;\n margin-top: var(--space-xs);\n padding: 0;\n color: var(--color-accent-teal, var(--color-text-secondary));\n background: transparent;\n border: none;\n font-size: 0.75rem;\n text-decoration: underline;\n cursor: pointer;\n}\n\n.szenen-runs > ol > li[data-status="succeeded"] {\n border-left: 3px solid var(--color-success);\n}\n\n.szenen-runs > ol > li[data-status="failed"] {\n border-left: 3px solid var(--color-danger);\n}\n\n.szenen-runs details pre {\n max-height: 20rem;\n overflow: auto;\n padding: var(--space-sm);\n white-space: pre-wrap;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border-radius: var(--radius-sm);\n}\n\n.szenen-media > section {\n display: grid;\n gap: var(--space-sm);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-media__lookup,\n.szenen-media__attach {\n display: flex;\n flex-wrap: wrap;\n align-items: end;\n gap: var(--space-sm);\n}\n\n.szenen-media__lookup > label,\n.szenen-media__attach > label:first-child {\n flex: 1 1 18rem;\n}\n\n.szenen-media__list {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-media__list > li {\n display: grid;\n grid-template-columns: minmax(12rem, 1fr) auto auto auto;\n align-items: center;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n@media (max-width: 760px) {\n .szenen-view {\n gap: var(--space-sm);\n }\n\n /* C1 \u2014 auf 390 px bleiben drei Kacheln je Reihe gross genug zum Erkennen\n und klein genug, dass vier Bilder eine Reihe sind und keine Seite. */\n .szenen-bildgalerie {\n grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));\n }\n\n /* Der Viewer bekommt den ganzen Bildschirm; die Bl\xE4tterkn\xF6pfe bleiben am\n Rand, wo der Daumen sie erreicht. */\n .szenen-bildviewer {\n padding: var(--space-xs);\n }\n\n .szenen-bildviewer__blaettern {\n width: 2.25rem;\n height: 4rem;\n }\n\n .szenen-view__nav {\n position: sticky;\n top: 0;\n z-index: 2;\n padding: var(--space-xs) 0;\n background: var(--color-bg-app);\n }\n\n\n .szenen-scene-editor {\n grid-template-columns: 1fr;\n }\n\n .szenen-capability > ul > li {\n grid-template-columns: 1fr;\n }\n\n .szenen-derive,\n .szenen-elements,\n .szenen-scene,\n .szenen-setup,\n .szenen-shot,\n .szenen-media,\n .szenen-runs {\n gap: var(--space-sm);\n }\n\n .szenen-elements__filter {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--space-sm);\n }\n\n .szenen-elements__filter > label {\n width: 100%;\n min-width: 0;\n flex: none;\n }\n\n .szenen-elements__filter > label:has(input[type="checkbox"]) {\n flex: none;\n grid-column: 1 / -1;\n }\n\n /* Schmal ist die Liste eine Spalte, und die Auswahl fuehrt weiter \u2014 der\n * Eintrag ist deshalb ein Ziel fuer den Finger, keine Kachel. */\n .szenen-elements__list {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .szenen-elements__list > li > button {\n min-height: 2.75rem;\n }\n\n .szenen-elements__back {\n justify-self: stretch;\n min-height: 2.5rem;\n }\n\n .szenen-detail__actions,\n .szenen-runs__start,\n .szenen-scene-editor__add,\n .szenen-scene-editor__add-relation {\n align-items: stretch;\n flex-direction: column;\n }\n\n .szenen-runs__start > *,\n .szenen-scene-editor__add > *,\n .szenen-scene-editor__add-relation > * {\n width: 100%;\n flex: none;\n }\n}\n\n/* \u2500\u2500 Kette `szenen-design`, P2: Szenen-\xDCbersicht als Bildgalerie \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Kacheln wie in der Library: quadratisch, Deckbild, Titel ueber einem\n * Verlauf, Bildzahl als Plakette. Eine Szene ohne Bild zeigt ihre\n * Node-Symbole; ein nicht ladbares Deckbild nennt den Grund. Die Schrift auf\n * dem Bild ist hell auf dunklem Verlauf \u2014 unabhaengig vom Hostthema, weil das\n * Bild es auch ist. */\n.szenen-galerie {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-galerie__kopf > .szenen-elements__heading {\n flex: 1 1 auto;\n margin: 0;\n}\n\n.szenen-galerie__anzahl,\n.szenen-galerie__sortierung {\n color: var(--color-text-secondary);\n font-weight: 400;\n}\n\n.szenen-galerie__sortierung {\n font-size: 0.8rem;\n}\n\n.szenen-galerie__raster {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(min(100%, 9.5rem), 1fr));\n gap: 0.625rem;\n min-width: 0;\n}\n\n/* Die Kacheln sind Zellen desselben Rasters wie die Neu-Kachel. */\n.szenen-view .szenen-galerie__liste {\n display: contents;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-galerie__kachel {\n min-width: 0;\n}\n\n.szenen-view .szenen-galerie__kachel > button,\n.szenen-view .szenen-galerie__neu,\n.szenen-view .szenen-galerie__zuletzt {\n position: relative;\n display: block;\n width: 100%;\n min-width: 0;\n padding: 0;\n overflow: hidden;\n color: var(--color-text-primary);\n text-align: left;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-galerie__kachel > button {\n aspect-ratio: 1 / 1;\n}\n\n.szenen-view .szenen-galerie__kachel > button[aria-current="true"],\n.szenen-view .szenen-galerie__zuletzt[aria-current="true"] {\n border-color: var(--color-accent-blue);\n box-shadow: 0 0 0 1px var(--color-accent-blue);\n}\n\n.szenen-galerie__bild {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-galerie__scrim {\n position: absolute;\n inset: 0;\n background: linear-gradient(to top, rgba(0, 0, 0, 0.88) 0%, rgba(0, 0, 0, 0.4) 40%, rgba(0, 0, 0, 0) 65%);\n}\n\n.szenen-galerie__ohnebild {\n position: absolute;\n inset: 0;\n padding: 0.75rem;\n background:\n radial-gradient(var(--color-border) 1px, transparent 1px) 0 0 / 14px 14px,\n var(--color-bg-surface);\n}\n\n.szenen-galerie__bildfehler {\n position: absolute;\n inset: 0;\n /* Oben Platz fuer Status-Punkte und Bildzahl, die darueber liegen. */\n padding: 2.25rem 0.75rem 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n font-size: 0.75rem;\n line-height: 1.3;\n}\n\n.szenen-galerie__text {\n position: absolute;\n right: 0.75rem;\n bottom: 0.7rem;\n left: 0.75rem;\n display: grid;\n gap: 0.25rem;\n}\n\n.szenen-galerie__kachel--mitbild .szenen-galerie__text,\n.szenen-galerie__zuletzt--mitbild .szenen-galerie__zuletzt-text {\n color: #fff;\n}\n\n.szenen-galerie__titel {\n display: -webkit-box;\n overflow: hidden;\n font-size: 0.875rem;\n font-weight: 650;\n line-height: 1.25;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 3;\n overflow-wrap: anywhere;\n}\n\n.szenen-galerie__meta {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-galerie__kachel--mitbild .szenen-galerie__meta,\n.szenen-galerie__zuletzt--mitbild .szenen-galerie__meta {\n color: rgba(255, 255, 255, 0.82);\n}\n\n.szenen-galerie__tags {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n min-width: 0;\n}\n\n.szenen-galerie__tag {\n max-width: 100%;\n padding: 0.05rem 0.4rem;\n overflow: hidden;\n color: inherit;\n background: var(--color-bg-elevated);\n border-radius: var(--radius-full);\n font-size: 0.68rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-galerie__kachel--mitbild .szenen-galerie__tag {\n background: rgba(0, 0, 0, 0.5);\n}\n\n.szenen-galerie__status {\n position: absolute;\n top: 0.7rem;\n left: 0.7rem;\n display: flex;\n gap: 0.3rem;\n}\n\n.szenen-galerie__punkt {\n width: 0.625rem;\n height: 0.625rem;\n background: var(--color-text-secondary);\n border-radius: 50%;\n box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.55);\n}\n\n.szenen-galerie__punkt[data-ton="info"] { background: var(--color-accent-blue); }\n.szenen-galerie__punkt[data-ton="ok"] { background: var(--color-success); }\n.szenen-galerie__punkt[data-ton="fertig"] { background: var(--color-warning); }\n/* Unvollstaendig ist ein Ring: Die Form unterscheidet es von \u201Evollstaendig",\n * nicht nur der Farbton (P8). */\n.szenen-galerie__punkt[data-ton="warn"] {\n background: transparent;\n box-shadow: inset 0 0 0 2px var(--color-accent-orange), 0 0 0 2px rgba(0, 0, 0, 0.55);\n}\n\n/* Die Legende der Punkte \u2014 einmal je Ansicht. */\n.szenen-statuslegende {\n display: flex;\n flex-wrap: wrap;\n gap: 0.35rem 0.85rem;\n margin: 0;\n padding: 0;\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n list-style: none;\n}\n\n.szenen-statuslegende__eintrag {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.szenen-statuslegende .szenen-galerie__punkt {\n display: inline-block;\n width: 0.5rem;\n height: 0.5rem;\n}\n\n.szenen-galerie__bildzahl {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.15rem 0.5rem;\n color: #fff;\n background: rgba(0, 0, 0, 0.65);\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n}\n\n.szenen-galerie__symbole {\n display: flex;\n flex-wrap: wrap;\n gap: 0.3rem;\n}\n\n.szenen-galerie__symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 1.875rem;\n height: 1.875rem;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: 50%;\n}\n\n.szenen-galerie__symbol[data-node-type="light"] {\n color: var(--color-warning);\n}\n\n.szenen-galerie__symbol--rest {\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n}\n\n.szenen-view .szenen-galerie__neu {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.6rem;\n aspect-ratio: 1 / 1;\n text-align: center;\n background: var(--color-bg-app);\n border: 1.5px dashed var(--color-border-hover, var(--color-border));\n}\n\n.szenen-galerie__neu-plus {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3.25rem;\n height: 3.25rem;\n color: var(--color-bg-app);\n background: var(--color-accent-teal, #2dd4bf);\n border-radius: 50%;\n}\n\n.szenen-galerie__neu-titel {\n font-size: 0.95rem;\n font-weight: 600;\n}\n\n.szenen-galerie__neu-text {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-galerie__zuletzt-bild {\n position: relative;\n display: block;\n aspect-ratio: 4 / 3;\n max-height: 17rem;\n width: 100%;\n}\n\n.szenen-galerie__chip {\n position: absolute;\n top: 0.75rem;\n left: 0.75rem;\n padding: 0.3rem 0.6rem;\n color: #fff;\n background: rgba(0, 0, 0, 0.6);\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n}\n\n.szenen-galerie__zuletzt .szenen-galerie__status {\n right: 0.75rem;\n left: auto;\n top: 1rem;\n}\n\n/* Die Symbole einer Szene ohne Bild stehen unter dem Chip, nicht darauf. */\n.szenen-galerie__zuletzt .szenen-galerie__ohnebild {\n padding-top: 3rem;\n}\n\n.szenen-galerie__zuletzt-text {\n position: absolute;\n right: 1rem;\n bottom: 0.9rem;\n left: 1rem;\n display: grid;\n gap: 0.35rem;\n}\n\n.szenen-galerie__zuletzt-text .szenen-galerie__titel {\n font-size: 1.3rem;\n font-weight: 700;\n line-height: 1.2;\n}\n\n.szenen-galerie__zuletzt-fuss {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n padding: 0.75rem 0.9rem;\n}\n\n.szenen-galerie__oeffnen {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.25rem;\n color: var(--color-accent-teal, #2dd4bf);\n font-size: 0.875rem;\n font-weight: 600;\n}\n\n/* \u2500\u2500 Stufe 6.5: Rekonstruktion \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Bereich zeigt drei Dinge nebeneinander: den Vorschlag, das nicht\n * Ableitbare und die Widerspr\xFCche. Die Diagnosen sind deshalb bewusst nicht\n * kleiner gesetzt als der Vorschlag \u2014 wer sie \xFCbersieht, \xFCbernimmt Geratenes.\n */\n\n.szenen-derive {\n display: grid;\n gap: var(--space-md);\n}\n\n.szenen-form {\n display: grid;\n gap: var(--space-sm);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-field {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-field > span {\n color: var(--color-text-secondary);\n font-size: 0.875rem;\n}\n\n.szenen-error {\n padding: var(--space-sm) var(--space-md);\n color: var(--color-danger);\n background: var(--color-accent-red-dim);\n border: 1px solid var(--color-accent-red);\n border-radius: var(--radius-sm);\n}\n\n.szenen-empty {\n padding: var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-diagnose {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-warning);\n border-radius: var(--radius-sm);\n}\n\n/* Ein Widerspruch ist der schwerste der drei Befunde: dort steht eine\n * Entscheidung aus, die das System bewusst nicht getroffen hat (D-74). */\n.szenen-diagnose--konflikt {\n border-left-color: var(--color-danger);\n}\n\n.szenen-diagnose > h4 {\n margin: 0 0 var(--space-sm);\n font-size: 0.9375rem;\n}\n\n.szenen-diagnose ul {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding-left: var(--space-md);\n}\n\n.szenen-proposal {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-proposal > h4 {\n margin: 0 0 var(--space-sm);\n font-family: var(--font-mono);\n font-size: 0.9375rem;\n}\n\n.szenen-proposal__payload {\n max-height: 18rem;\n margin: 0 0 var(--space-sm);\n padding: var(--space-sm);\n overflow: auto;\n /* Ein erzeugter Prompt ist ein einziger langer Satz \u2014 ohne Umbruch\n verschwindet er nach rechts aus dem Bild. JSON-Payloads bringen ihre\n eigenen Zeilenumbrueche mit und leiden nicht darunter. */\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n font-family: var(--font-mono);\n font-size: 0.8125rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-proposal__done {\n margin: var(--space-sm) 0 0;\n color: var(--color-success);\n}\n\n/* Die Belege eines Laufs: Rohantwort und Systemprompt. Zum Lesen und Kopieren,\n nicht zum Bedienen \u2014 deshalb voll markierbar und in Monospace. */\n.szenen-beleg__text {\n width: 100%;\n margin: var(--space-sm) 0 0;\n padding: var(--space-sm);\n font-family: var(--font-mono);\n font-size: 0.8125rem;\n line-height: 1.5;\n white-space: pre;\n background: var(--color-bg-app);\n color: var(--color-text);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n resize: vertical;\n}\n\n/* Der Folgelauf (D-87): abgesetzt, damit er nicht wie Teil des Ergebnisses\n aussieht \u2014 er ist eine Frage, keine Auskunft. */\n.szenen-folgelauf {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-folgelauf > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-run__herkunft {\n margin: 0 0 var(--space-sm);\n font-size: 0.875rem;\n color: var(--color-text-muted, inherit);\n}\n\n/* Widerspricht das Modell, ist das das Wichtigste auf der Seite. */\n.szenen-diagnose--antwort {\n border-left: 3px solid var(--color-accent, var(--color-border));\n}\n\n/* Der Bildw\xE4hler (D-92) \u2014 Browser und Inspector, dem Labs-Tab nachgebildet,\n aber mit dem CSS dieser Ansicht: eine gemeinsame Komponente \xFCber zwei\n Dom\xE4nengrenzen w\xE4re eine Kopplung, die keiner gewollt hat.\n\n Der Review vom 2026-08-22 (R12.1/R12.2) hat den Ma\xDFstab gesetzt: Der Bestand\n ist ein **Browser**, kein Seiteninhalt. Vierzig Werke d\xFCrfen die Szenenseite\n nicht meterlang machen, und zw\xF6lf Varianten eines Werkes keine zw\xF6lf\n Bildschirmseiten. Deshalb steht hier alles unter zwei Regeln \u2014 begrenzte\n Fl\xE4che mit eigenem Scroll, und Kacheln statt Karten. */\n\n/* \u2500\u2500 Ebene 1: der Browser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-bildwahl {\n /* Dieselbe Begr\xFCndung wie beim Inspector: Als Grid-Element w\xFCrde der\n W\xE4hler sonst so breit wie sein breitester Inhalt. */\n min-width: 0;\n}\n\n.szenen-bildwahl__browser {\n /* Die eigene Scrollfl\xE4che ist der ganze Punkt: Der Bestand w\xE4chst nach\n innen, nicht nach unten. Dieselbe Gr\xF6\xDFenordnung wie `max-h-[300px]` im\n Labs-Browser. */\n max-height: 19rem;\n overflow-y: auto;\n overscroll-behavior: contain;\n margin-top: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__raster {\n display: grid;\n /* Vier Spalten auf schmalen Displays \u2014 der gemeldete Screenshot zeigte eine\n einzige Spalte gro\xDFer Karten. Breiter wird automatisch dichter. */\n grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildwahl__karte {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n overflow: hidden;\n background: var(--color-bg-surface);\n text-align: left;\n cursor: pointer;\n}\n\n/* Das fokussierte Werk ist klar markiert \u2014 sonst wei\xDF niemand, wessen Galerie\n der Inspector unten zeigt. */\n.szenen-bildwahl__karte.is-fokus {\n border-color: var(--color-accent, var(--color-text-primary));\n box-shadow: 0 0 0 2px var(--color-accent, var(--color-text-primary));\n}\n\n/* \u2500\u2500 Die Kachel selbst \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* Der Platz steht, bevor das Bild da ist \u2014 sonst springt das Raster, sobald\n die erste Vorschau eintrifft. */\n.szenen-bildkachel {\n display: block;\n width: 100%;\n aspect-ratio: 1;\n overflow: hidden;\n background: var(--color-bg-app);\n}\n\n.szenen-bildkachel img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.szenen-bildkachel__leer {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n background: linear-gradient(135deg, var(--color-bg-app), var(--color-bg-surface));\n}\n\n/* R12.3: Eine fehlende Vorschau bleibt kachelgro\xDF. Vorher fiel die Karte auf\n ihren Prompttext zur\xFCck \u2014 und ein Prompt hat im echten Bestand mehrere\n hundert Zeichen. */\n.szenen-bildkachel__zeichen {\n font-size: 0.875rem;\n font-weight: 700;\n color: var(--color-text-secondary);\n opacity: 0.6;\n}\n\n/* Wie viele Varianten das Werk hat \u2014 klein und \xFCberlagernd, nie als\n dominanter Text. */\n.szenen-bildwahl__anzahl {\n position: absolute;\n top: 0.15rem;\n right: 0.15rem;\n padding: 0.05rem 0.3rem;\n font-size: 0.625rem;\n font-weight: 700;\n line-height: 1.4;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* Eine Zeile, dann Schluss. Der Prompt eines Werkes ist oft mehrere hundert\n Zeichen lang und w\xE4re als Prim\xE4rdarstellung genau die Textw\xFCste, gegen die\n der Review antritt. */\n.szenen-bildwahl__kacheltitel {\n display: block;\n padding: 0.15rem 0.3rem;\n font-size: 0.625rem;\n line-height: 1.3;\n color: var(--color-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* \u2500\u2500 Ebene 2: der Inspector \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-bildwahl__inspector {\n /* Ohne `min-width: 0` gewinnt der Inhalt: Der W\xE4hler ist Element eines\n Grids (`.szenen-form`), und dort ist `min-width: auto` die Vorgabe. Der\n Streifen unten ist rund 1000 px breit \u2014 gemessen am 2026-08-22 im echten\n Browser zog er die Auswahl von 374 px auf 1088 px auf und schob die\n ganze Seite waagerecht heraus, statt selbst zu scrollen. */\n min-width: 0;\n margin-top: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n /* Sichtbar abgesetzt vom Browser: zwei Ebenen, nicht eine lange Liste. */\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent, var(--color-border));\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__inspektorkopf {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n margin-bottom: var(--space-sm);\n}\n\n.szenen-bildwahl__werktitel {\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--color-text-primary);\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-bildwahl__zurueck {\n flex: 0 0 auto;\n font-size: 0.6875rem;\n padding: 0.15rem 0.5rem;\n}\n\n/* Der Streifen: waagerecht scrollend, feste kleine Kacheln \u2014 zw\xF6lf Varianten\n bleiben ein \xDCberblick statt zw\xF6lf Bildschirmseiten. */\n.szenen-bildwahl__streifen {\n /* Die Breite kommt vom Elter, nie vom Inhalt \u2014 sonst scrollt hier nichts. */\n max-width: 100%;\n display: flex;\n gap: var(--space-sm);\n margin: 0;\n padding: 0 0 0.25rem;\n list-style: none;\n overflow-x: auto;\n overscroll-behavior-x: contain;\n}\n\n.szenen-bildwahl__streifen > li {\n flex: 0 0 auto;\n width: 5rem;\n}\n\n.szenen-bildwahl__variante {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n overflow: hidden;\n background: var(--color-bg-app);\n cursor: pointer;\n}\n\n.szenen-bildwahl__variante.is-gewaehlt {\n border-color: var(--color-accent, var(--color-text-primary));\n box-shadow: 0 0 0 2px var(--color-accent, var(--color-text-primary));\n}\n\n.szenen-bildwahl__nummer {\n position: absolute;\n bottom: 0.15rem;\n left: 0.15rem;\n padding: 0.05rem 0.3rem;\n font-size: 0.625rem;\n line-height: 1.4;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n}\n\n/* \u2500\u2500 Das Gew\xE4hlte \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-bildwahl__gewaehlt {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: var(--space-sm) 0 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildwahl__gewaehlt li {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.8125rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n max-width: 100%;\n}\n\n/* Das gew\xE4hlte Bild wird best\xE4tigt, nicht nur benannt: eine kleine Vorschau\n neben dem Titel. */\n.szenen-bildwahl__gewaehlt .szenen-bildkachel {\n width: 2.25rem;\n flex: 0 0 auto;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__gewaehlt .szenen-bildwahl__kacheltitel {\n min-width: 0;\n max-width: 12rem;\n font-size: 0.75rem;\n}\n\n.szenen-beleg__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n margin-top: var(--space-sm);\n}\n\n.szenen-diagnose > details + details {\n margin-top: var(--space-sm);\n}\n\n.szenen-diagnose > details > summary {\n cursor: pointer;\n font-weight: 600;\n}\n\n/* \u2500\u2500 Die Fehlerrettung (Stufe 6.6, A5) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Sie steht im Fehlerblock und muss trotzdem als Werkzeug lesbar sein, nicht\n * als weitere Fehlermeldung. Deshalb abgesetzt wie der Folgelauf \u2014 und aus\n * demselben Grund: Beides sind Angebote, keine Ausk\xFCnfte.\n *\n * Der wichtigste optische Punkt ist die Trennung von Original und\n * Arbeitskopie. Das Original bekommt den ruhigen, \u201Efesten" Hintergrund der\n * Belege; die Kopie sieht aus wie ein normales Eingabefeld, weil sie eines\n * ist. */\n.szenen-rettung {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-rettung > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-rettung textarea[readonly] {\n background: var(--color-bg-surface);\n color: var(--color-text-secondary);\n font-family: var(--font-mono, monospace);\n font-size: 0.8125rem;\n}\n\n.szenen-rettung textarea:not([readonly]) {\n font-family: var(--font-mono, monospace);\n font-size: 0.8125rem;\n}\n\n.szenen-rettung__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: var(--space-sm) 0;\n}\n\n/* Ein Befund tr\xE4gt Code, Bezug und Meldung. Der Code steht klein und\n * monospaced davor: Er ist die Kennung, nicht die Aussage. */\n.szenen-diagnose__liste {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding-left: var(--space-md);\n}\n\n.szenen-diagnose__liste code {\n font-size: 0.8125rem;\n}\n\n.szenen-diagnose__liste > li[data-severity=\'warning\'] {\n color: var(--color-text-secondary);\n}\n\n/* \u2500\u2500 Die Draft-Kette (Stufe 6.6, C4) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Hauptweg. Er steht nach den Einzel\xFCbernahmen und muss als das erkennbar\n * sein, was er ist: nicht eine weitere Option, sondern der k\xFCrzere Weg zum\n * selben Ziel. Deshalb durchgezogener Rahmen statt gestricheltem \u2014 er ist\n * Angebot **und** Empfehlung. */\n.szenen-kette {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent, var(--color-border));\n border-radius: var(--radius-sm);\n}\n\n.szenen-kette > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-kette ul {\n display: grid;\n gap: var(--space-xs);\n margin: 0 0 var(--space-sm);\n padding-left: var(--space-md);\n}\n\n.szenen-kette code {\n font-size: 0.8125rem;\n}\n\n/* Ein Hinweis, der eine Bedingung erklaert \u2014 nicht rot, weil er kein Fehler\n ist, aber abgesetzt, weil er eine Folge hat. */\n.szenen-detail__hint {\n margin: var(--space-sm) 0 0;\n padding: var(--space-sm);\n font-size: 0.875rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border-left: 3px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* \u2500\u2500 Stufe 6.7: Bilder am Prompt-Lauf (H0/H1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Bereich tr\xE4gt zwei Dinge, die man nie verwechseln darf: den **Eingang**\n * (woraus der Prompt entstand) und den **Ausgang** (was daraus wurde). Sie\n * bekommen deshalb verschiedene Akzentkanten statt nur verschiedener\n * \xDCberschriften \u2014 wer schnell liest, sieht die Trennung, bevor er sie liest.\n */\n.szenen-bilder {\n display: grid;\n gap: var(--space-md);\n margin-top: var(--space-sm);\n}\n\n.szenen-bilder__eingang,\n.szenen-bilder__ausgang {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__eingang {\n border-left: 3px solid var(--color-accent-purple, var(--color-border));\n}\n\n.szenen-bilder__ausgang {\n border-left: 3px solid var(--color-accent-teal, var(--color-border));\n}\n\n.szenen-bilder h5 {\n margin: 0;\n}\n\n.szenen-bilder__ids {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: 0;\n align-items: baseline;\n color: var(--color-text-secondary);\n font-size: 0.875rem;\n}\n\n.szenen-bilder__eingangsliste,\n.szenen-bilder__batchliste,\n.szenen-bilder__auftraege {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bilder__eingangsliste > li,\n.szenen-bilder__batchliste > li,\n.szenen-bilder__auftraege > li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font-size: 0.8125rem;\n}\n\n/* Ein unterbrochener Auftrag ist der Fall, f\xFCr den der Auftragssatz existiert.\n Er wird deshalb markiert \u2014 nicht rot, denn er ist kein Fehler, sondern eine\n offene Entscheidung. */\n.szenen-bilder__auftraege > li[data-status="started"] {\n border-left: 3px solid var(--color-warning);\n}\n\n.szenen-bilder__auftraege > li[data-status="succeeded"] {\n border-left: 3px solid var(--color-success);\n}\n\n.szenen-bilder__auftraege > li[data-status="partial"] {\n border-left: 3px solid var(--color-accent-blue, var(--color-border));\n}\n\n.szenen-bilder__auftraege > li[data-status="failed"] {\n border-left: 3px solid var(--color-danger);\n}\n\n/* Das Eingangsbild benutzt seit C3 dieselbe Kachel wie W\xE4hler und Galerie.\n Sie ist von Haus aus so breit wie ihr Platz \u2014 in dieser Zeile bekommt sie\n deshalb eine feste Gr\xF6sse, sonst sch\xF6be sie die Metadaten heraus. */\n.szenen-bilder__eingangsliste .szenen-bildkachel {\n flex: 0 0 auto;\n width: 4rem;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__batch {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__batchkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-bilder__herkunft {\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n}\n\n/* Review-Befund \u2014 ein transienter Bildfehler ist wiederholbar, kein\n endg\xFCltiges \u201Efehlt". Dezent wie ein Angebot, nicht wie ein Fehlerzustand. */\n.szenen-bilder__retry {\n justify-self: start;\n padding: 0.15rem 0.5rem;\n font-size: 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n/* C4 \u2014 die Provenienz vollst\xE4ndig, aber sekund\xE4r. */\n.szenen-bilder__technik > summary {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n cursor: pointer;\n}\n\n.szenen-bilder__meta {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n font-size: 0.75rem;\n color: var(--color-text-secondary);\n}\n\n/* C5 \u2014 der Verlauf verdichtet, seine Ausreisser nicht. */\n.szenen-bilder__verlauf > summary {\n color: var(--color-text-secondary);\n font-size: 0.8125rem;\n cursor: pointer;\n}\n\n.szenen-bilder__verlauf[open] > summary {\n margin-bottom: var(--space-sm);\n}\n\n.szenen-bilder__auffaellig {\n margin: 0;\n padding: var(--space-sm);\n border-radius: var(--radius-sm);\n font-size: 0.8125rem;\n}\n\n.szenen-bilder__auftragskennung {\n flex-basis: 100%;\n color: var(--color-text-tertiary);\n font-size: 0.6875rem;\n}\n\n/* \u2500\u2500 C1/C2 \u2014 Galerie und grosse Ansicht \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* Das Raster w\xE4chst mit dem Platz: auf 390 px drei bis vier Kacheln je Reihe,\n auf dem Desktop entsprechend mehr. Vorher war jedes Bild eine Zeile aus\n Daumennagel plus vier Metadatenfeldern \u2014 vier Bilder ergaben vier Textzeilen\n und das Protokoll war die Hauptsache. */\n.szenen-bildgalerie {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr));\n gap: var(--space-sm);\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildgalerie__kachel {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-bildgalerie__kachel:hover,\n.szenen-bildgalerie__kachel:focus-visible {\n border-color: var(--color-accent-teal, var(--color-text-primary));\n}\n\n.szenen-bildgalerie__nummer {\n position: absolute;\n bottom: 0.15rem;\n left: 0.15rem;\n padding: 0.05rem 0.3rem;\n font-size: 0.625rem;\n line-height: 1.4;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n}\n\n/* Die grosse Ansicht liegt \xFCber allem und bringt ihren eigenen Grund mit \u2014\n `position: fixed` bezieht sich im Flow-Canvas auf dessen Rahmen, in React auf\n das Fenster; in beiden F\xE4llen genau das Gew\xFCnschte. */\n.szenen-bildviewer {\n position: fixed;\n inset: 0;\n z-index: 1000;\n display: grid;\n grid-template-rows: auto 1fr auto;\n gap: var(--space-sm);\n padding: var(--space-sm);\n /* Deckend, nicht get\xF6nt: Bei 0.92 schimmerte der Laufbereich durch und man\n las Prompttext quer \xFCber dem Bild \u2014 im Browser gemessen. */\n background: #000;\n}\n\n/* Titel, Z\xE4hlung, Schliessen \u2014 drei Spalten, damit ein langer Werktitel die\n Z\xE4hlung nicht in die n\xE4chste Zeile und \xFCber das Bild schiebt. */\n.szenen-bildviewer__kopf {\n display: grid;\n /* Titel nimmt den Rest; Zaehler, eine optionale Bildaktion (P6) und\n Schliessen stehen rechts \u2014 mit und ohne Aktion in einer Zeile. */\n grid-template-columns: minmax(0, 1fr);\n grid-auto-columns: auto;\n grid-auto-flow: column;\n align-items: center;\n gap: var(--space-sm);\n color: var(--color-text-primary);\n}\n\n.szenen-bildviewer__titel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 600;\n}\n\n.szenen-bildviewer__zaehler {\n color: var(--color-text-secondary);\n font-size: 0.8125rem;\n}\n\n.szenen-bildviewer__buehne {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--space-sm);\n min-height: 0;\n min-width: 0;\n}\n\n/* Der Rahmen nimmt den Platz, der zwischen den Bl\xE4tterkn\xF6pfen \xFCbrig ist \u2014\n `min-width: 0`, damit er auch wirklich schrumpft statt sie hinauszuschieben. */\n.szenen-bildviewer__rahmen {\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 0;\n min-height: 0;\n height: 100%;\n}\n\n.szenen-bildviewer__bild {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n}\n\n.szenen-bildviewer__leer {\n color: var(--color-text-secondary);\n text-align: center;\n}\n\n/* Die Bl\xE4tterkn\xF6pfe sind daumengross und liegen an den R\xE4ndern \u2014 auf einem\n Telefon ist der Rand erreichbar, die Bildmitte nicht. */\n.szenen-bildviewer__blaettern {\n flex: 0 0 auto;\n width: 2.75rem;\n height: 3.5rem;\n font-size: 1.75rem;\n line-height: 1;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-bildviewer__details {\n max-height: 8rem;\n overflow-y: auto;\n color: var(--color-text-secondary);\n}\n\n/* Die Aktionen stehen abgesetzt: Sie sind Angebote, keine Ausk\xFCnfte \u2014 dasselbe\n Muster wie beim Folgelauf und bei der Fehlerrettung. */\n/* D \u2014 die Aktionen stehen abgesetzt und standardm\xE4ssig kompakt: Sie sind\n Angebote, keine Ausk\xFCnfte. Vorher hielten beide Formulare dauerhaft offen und\n machten aus jedem Lauf zwei zus\xE4tzliche Bildschirmseiten. */\n.szenen-bilder__aktion {\n min-width: 0;\n padding: var(--space-sm) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__aktion > summary {\n color: var(--color-text-primary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-bilder__aktion[open] > summary {\n margin-bottom: var(--space-sm);\n}\n\n.szenen-bilder__aktion-inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding-bottom: var(--space-sm);\n}\n\n.szenen-bilder__aktion h5 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-bilder__aktion ol {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding-left: var(--space-md);\n font-size: 0.8125rem;\n}\n\n/* Regelwerk-UX Schritt 16 \u2014 der ZIP-Sammelimport.\n *\n * \xA78: Der gemeldete Einsatz ist mobil. Deshalb **ein** Seedfeld statt einer\n * gestapelten Eingabe je Bild, und die Zuordnung Bild -> Seed als umbrechende\n * Zeile statt als Tabelle: Eine Tabelle waere auf 390 px abgeschnitten, und\n * abgeschnitten heisst hier, dass der Nutzer die Zuordnung nicht mehr pruefen\n * kann \u2014 genau die Pruefung, wegen der die Vorschau existiert. */\n.szenen-bilder__zip {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-bilder__zipkopf {\n margin: 0;\n overflow-wrap: anywhere;\n}\n\n.szenen-bilder__zipvorlagen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n margin: 0;\n}\n\n/* Eine laengere Liste bleibt scrollbar, statt die Sektion und damit den\n * Import-Knopf aus dem Blick zu schieben (\xA78, letzter Punkt). */\n.szenen-bilder__zipliste {\n max-height: 16rem;\n overflow-y: auto;\n}\n\n.szenen-bilder__zipliste > li {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-bilder__zipliste > li > span:first-child {\n overflow-wrap: anywhere;\n}\n\n.szenen-bilder__zipliste > li > span:last-child {\n color: var(--color-text-secondary);\n white-space: nowrap;\n}\n\n/* ==========================================================================\n STUFE 6.10 \u2014 ELEMENTEDITOR UND VERSIONSNAVIGATION\n ========================================================================== */\n\n/* \xA74.2 \u2014 vier Sachverhalte, vier Marken. Die Marken stehen in einer eigenen\n * Spalte, damit ANGEZEIGT + BEVORZUGT nebeneinander lesbar bleiben, statt sich\n * durch den Text zu schieben. */\n.szenen-detail__heads li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-version__titel {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n min-width: 0;\n margin-right: auto;\n}\n\n/* V17 \u2014 Kennungen bleiben vollst\xE4ndig sichtbar, aber optisch sekund\xE4r. */\n.szenen-version__id,\n.szenen-ref__id,\n.szenen-detail__field-key {\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-version__marken {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-version__marken > span {\n padding: 0.1rem 0.5rem;\n color: var(--color-text-primary);\n background: rgba(45, 212, 191, 0.12);\n border: 1px solid rgba(45, 212, 191, 0.35);\n border-radius: var(--radius-full);\n font-size: 0.7rem;\n font-weight: 800;\n letter-spacing: 0.08em;\n}\n\n.szenen-version--angezeigt {\n border-color: var(--color-accent-teal, #2dd4bf) !important;\n}\n\n/* V9 \u2014 der Basiswechsel ist eine Entscheidung, keine Nebenwirkung. */\n.szenen-detail__confirm {\n display: grid;\n gap: var(--space-sm);\n margin: var(--space-md) 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-accent-amber, #f59e0b);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__confirm p {\n margin: 0;\n}\n\n/* Untergruppen von Objektfeldern (`prompt_render_settings`, `overrides`,\n `blender_render_settings`) \u2014 seit A1/A2 auf- und zuklappbar. Eine optionale\n Gruppe startet zu: Blender und `overrides` f\xFCllten auf einem 390-px-Display\n sonst mehrere Bildschirmseiten, obwohl die meisten Shots sie nie anfassen. */\n.szenen-detail__group {\n min-width: 0;\n margin: var(--space-md) 0;\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__group > summary {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-detail__group[open] > summary {\n margin-bottom: var(--space-sm);\n}\n\n/* A2 \u2014 dass eine zugeklappte Gruppe schon Werte tr\xE4gt, muss man sehen, ohne\n sie zu \xF6ffnen. Sonst \xFCbersieht man eine gesetzte Blender-Ausgabe genau so\n lange, bis sie im Ergebnis auftaucht. */\n.szenen-detail__group-status {\n padding: 0.05rem 0.4rem;\n font-size: 0.6875rem;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--color-text-tertiary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__group[data-konfiguriert="ja"] > summary .szenen-detail__group-status {\n color: var(--color-text-primary);\n border-color: var(--color-accent-teal, var(--color-border));\n}\n\n.szenen-detail__group-inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding-bottom: var(--space-sm);\n}\n\n/* A3 \u2014 die Kernaussage steht am Feld, die Begr\xFCndung dahinter. Nicht als\n Tooltip: Auf einem Telefon gibt es kein Hover, und was dort unerreichbar ist,\n ist gestrichen \u2014 nur ohne dass es jemand entschieden h\xE4tte. */\n.szenen-detail__warum > summary {\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n cursor: pointer;\n}\n\n.szenen-detail__warum > small {\n display: block;\n padding-top: var(--space-xs);\n color: var(--color-text-tertiary);\n}\n\n.szenen-detail__fieldrow {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n margin-bottom: var(--space-md);\n}\n\n/* A4 \u2014 der technische Feldname bleibt lesbar, tritt aber hinter das fachliche\n Label zur\xFCck. */\n.szenen-detail__field-label {\n color: var(--color-text-primary);\n}\n\n.szenen-detail__field {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-detail__field > span {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n}\n\n/* Mehrfachauswahl und Listeneditoren. */\n.szenen-feld__mehrfach,\n.szenen-feld__liste,\n.szenen-feld__reflist,\n.szenen-feld__ref,\n.szenen-feld__zielmodell,\n.szenen-bilder__modellwahl,\n.szenen-feld__kamera {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n/* \u201ENeues Modell hinzufuegen" im Importdialog \u2014 dieselben Abstaende wie jedes\n andere Formular dieser Ansicht, damit es kein Fremdkoerper wird. */\n.szenen-feld__zielmodell-neu {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n padding: var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-feld__zielmodell-neu-aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-feld__mehrfach > label,\n.szenen-feld__null {\n display: flex;\n align-items: center;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n.szenen-feld__liste-zeile {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-feld__reflist ol {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-feld__reflist li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n padding: var(--space-xs) var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* \xA76.1 \u2014 Titel und Typ zuerst, Kennungen daneben. */\n.szenen-ref__anzeige {\n display: inline-flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-ref__typ {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-ref__warn {\n padding: 0.1rem 0.5rem;\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-radius: var(--radius-full);\n font-size: 0.72rem;\n font-weight: 700;\n}\n\n/* \xA76.5 \u2014 abgeleitete Angaben, ausdr\xFCcklich nur Anzeige. */\n.szenen-detail__derived {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__derived dl {\n display: grid;\n grid-template-columns: minmax(10rem, auto) 1fr;\n gap: var(--space-xs) var(--space-sm);\n margin: 0;\n}\n\n.szenen-detail__derived dt {\n color: var(--color-text-secondary);\n}\n\n.szenen-detail__derived dd {\n margin: 0;\n}\n\n.szenen-feld__abgeleitet {\n margin: 0;\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n}\n\n/* Bereich `Prompts` \u2014 die herkunftsuebergreifende Sicht (P1-A).\n *\n * Die Eintraege selbst rendert `RundenEintrag` und tragen damit die\n * `szenen-runs__*`-Regeln. Hier stehen nur Rahmen und Kennzeichen; eine zweite\n * Laufdarstellung gibt es nicht, also braucht sie auch kein zweites Aussehen. */\n.szenen-prompts__toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-prompts__heading {\n margin: 0;\n font-size: 1.05rem;\n margin-right: auto;\n}\n\n.szenen-view__fokus {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n margin-bottom: var(--space-sm);\n}\n\n.szenen-prompts__fokus {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n margin-bottom: var(--space-sm);\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-accent, #0d9488);\n border-radius: var(--radius-sm, 4px);\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-prompts__hinweis {\n font-style: italic;\n}\n\n.szenen-prompts__ausgeblendet {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n/* ==========================================================================\n Kette `szenen-design`, P8 \u2014 der Bereich `Prompts` als Bildraster\n ========================================================================== */\n\n/* Herkunfts-Chips: eine Zeile, die in sich scrollt \u2014 nie die Seite. */\n.szenen-prompts__chips {\n display: flex;\n flex-wrap: nowrap;\n gap: 0.375rem;\n min-width: 0;\n padding-bottom: 0.15rem;\n overflow-x: auto;\n scrollbar-width: thin;\n}\n\n.szenen-view .szenen-prompts__chip {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.35rem;\n min-height: 2.25rem;\n padding: 0 0.8rem;\n white-space: nowrap;\n border-radius: var(--radius-full);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-prompts__chip[aria-pressed="true"] {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border-color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-prompts__zeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.375rem;\n min-width: 0;\n}\n\n.szenen-prompts__anzahl {\n flex: 1 1 8rem;\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-prompts__umschalter {\n min-height: 2rem;\n padding: 0 0.65rem;\n font-size: 0.75rem;\n}\n\n.szenen-prompts__raster-bereich {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n/* Der neueste Lauf \u2014 gross, mit Promptzeile und Kopierknopf. */\n.szenen-prompts__neuester {\n min-width: 0;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-prompts__oeffnen {\n display: block;\n width: 100%;\n padding: 0;\n color: var(--color-text-primary);\n text-align: left;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-prompts__bild {\n position: relative;\n display: block;\n height: 17.5rem;\n overflow: hidden;\n}\n\n.szenen-prompts__neuester .szenen-galerie__status {\n top: 0.75rem;\n left: 0.75rem;\n padding: 0.35rem 0.5rem;\n background: rgba(0, 0, 0, 0.55);\n border-radius: var(--radius-full);\n}\n\n.szenen-prompts__neuester .szenen-galerie__bildzahl {\n top: 0.75rem;\n right: 0.75rem;\n}\n\n.szenen-prompts__promptzeile {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.6rem 0.5rem 0.6rem 0.9rem;\n}\n\n.szenen-prompts__prompt {\n flex: 1 1 auto;\n min-width: 0;\n margin: 0;\n overflow: hidden;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-view .szenen-kopieren--symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n min-height: 2.75rem;\n padding: 0;\n color: var(--color-text-primary);\n border-radius: var(--radius-lg);\n}\n\n.szenen-prompts__promptzeile .szenen-lauf__kopieren {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.4rem;\n}\n\n/* Gruppe aufeinanderfolgender Laeufe derselben Szene. */\n.szenen-prompts__gruppe {\n display: grid;\n gap: 0.6rem;\n min-width: 0;\n}\n\n.szenen-prompts__gruppenkopf {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-prompts__gruppenkopf h4 {\n min-width: 0;\n margin: 0;\n font-size: 1rem;\n font-weight: 650;\n line-height: 1.3;\n overflow-wrap: anywhere;\n}\n\n.szenen-prompts__gruppenkopf span {\n flex: none;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n/* Zwei Spalten, Kacheln im Format 3:4. */\n.szenen-view .szenen-prompts__raster {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 0.625rem;\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n@media (min-width: 761px) {\n .szenen-view .szenen-prompts__raster {\n grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));\n }\n}\n\n.szenen-prompts__kachel {\n min-width: 0;\n}\n\n.szenen-view .szenen-prompts__kachel > button {\n position: relative;\n display: block;\n width: 100%;\n min-width: 0;\n aspect-ratio: 3 / 4;\n padding: 0;\n overflow: hidden;\n color: var(--color-text-primary);\n text-align: left;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-prompts__kachel.is-fokus > button,\n.szenen-view .szenen-prompts__neuester.is-fokus {\n border-color: var(--color-accent-blue);\n box-shadow: 0 0 0 1px var(--color-accent-blue);\n}\n\n.szenen-prompts__text {\n position: absolute;\n right: 0.75rem;\n bottom: 0.7rem;\n left: 0.75rem;\n display: grid;\n gap: 0.2rem;\n min-width: 0;\n}\n\n.szenen-prompts--mitbild .szenen-prompts__text {\n color: #fff;\n}\n\n.szenen-prompts__titel {\n display: -webkit-box;\n overflow: hidden;\n font-size: 1.25rem;\n font-weight: 700;\n line-height: 1.2;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n overflow-wrap: anywhere;\n}\n\n.szenen-prompts__kachelrunde {\n display: flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.95rem;\n font-weight: 700;\n}\n\n.szenen-prompts__meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.3rem;\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-prompts--mitbild .szenen-prompts__meta {\n color: rgba(255, 255, 255, 0.82);\n}\n\n.szenen-prompts__statuspunkt {\n display: inline-block;\n flex: none;\n width: 0.5rem;\n height: 0.5rem;\n background: var(--color-success);\n border-radius: 50%;\n}\n\n.szenen-prompts__statuspunkt[data-status="failed"] {\n background: var(--color-danger);\n}\n\n/* Eine Kachel ohne Bild nennt ihren Grund \u2014 oben, damit der Text unten frei bleibt. */\n.szenen-prompts__grund {\n display: grid;\n align-content: start;\n gap: 0.3rem;\n padding-top: 2.25rem;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n line-height: 1.3;\n}\n\n.szenen-prompts__fehlertext {\n display: -webkit-box;\n overflow: hidden;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 4;\n overflow-wrap: anywhere;\n}\n\n/* ==========================================================================\n ZIP-MODELLVORSCHLAG (modaler Best\xE4tigungsdialog)\n ========================================================================== */\n\n/* Wie die grosse Bildansicht: eigener Grund, `position: fixed`, damit der\n Dialog im Flow-Canvas und in React gleichermassen \xFCber allem liegt. */\n.szenen-zipmodell {\n position: fixed;\n inset: 0;\n z-index: 1100;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--space-md);\n background: rgba(0, 0, 0, 0.72);\n}\n\n.szenen-zipmodell__karte {\n display: grid;\n gap: var(--space-sm);\n width: min(34rem, 100%);\n max-height: 100%;\n overflow-y: auto;\n padding: var(--space-md);\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-zipmodell__titel {\n margin: 0;\n font-size: 1rem;\n}\n\n.szenen-zipmodell__quelle,\n.szenen-zipmodell__treffer,\n.szenen-zipmodell__vertrauen,\n.szenen-zipmodell__fallback {\n margin: 0;\n font-size: 0.85rem;\n}\n\n.szenen-zipmodell__quelle,\n.szenen-zipmodell__vertrauen {\n color: var(--color-text-secondary);\n}\n\n/* Ein schwacher oder mehrdeutiger Treffer muss sich vom sicheren unterscheiden,\n sonst ist die Warnung nur ein weiterer Satz. */\n.szenen-zipmodell__warnung {\n margin: 0;\n padding: var(--space-xs) var(--space-sm);\n color: var(--color-text-primary);\n background: rgba(234, 179, 8, 0.14);\n border-left: 3px solid #eab308;\n border-radius: var(--radius-sm);\n font-size: 0.85rem;\n}\n\n.szenen-zipmodell__alternativen {\n display: grid;\n gap: 0.2rem;\n margin: 0;\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font-size: 0.85rem;\n}\n\n.szenen-zipmodell__alternativen > label {\n display: flex;\n align-items: center;\n gap: 0.4rem;\n}\n\n.szenen-zipmodell__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n/* ==========================================================================\n MEHR LADEN \u2014 der gemeinsame Fuss jeder seitenweise geladenen Liste\n ========================================================================== */\n\n.szenen-mehr-laden {\n display: grid;\n gap: var(--space-xs);\n justify-items: start;\n padding: var(--space-xs) 0;\n}\n\n.szenen-mehr-laden__button {\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n background: var(--color-bg-surface);\n color: var(--color-text-primary);\n font-size: 0.85rem;\n cursor: pointer;\n}\n\n.szenen-mehr-laden__button:disabled {\n cursor: progress;\n opacity: 0.6;\n}\n\n.szenen-mehr-laden__fehler {\n margin: 0;\n color: var(--color-danger, #f87171);\n font-size: 0.8rem;\n}\n\n/* ==========================================================================\n PROMPTKARTE \u2014 Tags, Vorschau und Bildzahl\n (Kette `szenen-prompt-anzeige-bilder-tags`)\n\n Der Zuschnitt ist der der Library-Karte (`.library-item` + der absolut\n gesetzte Bildstreifen in `LibraryTab`): Textteil links, Deckbild rechts am\n Rand ueber die ganze Kartenhoehe, Bildzahl als Plakette darauf. Dieselben\n Werte (7rem Streifenbreite, linke Trennlinie, Plakette unten rechts), nur\n hier statt in Tailwind-Klassen \u2014 die Szenen-Ansicht teilt dieses Stylesheet\n byteweise mit Flow, und Flow hat kein Tailwind.\n ========================================================================== */\n\n.szenen-promptkarte {\n position: relative;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n padding: var(--space-sm);\n}\n\n/* Nur wo ein Bild liegt, wird Platz dafuer freigehalten. Ohne Bild nutzt der\n Textteil die ganze Breite \u2014 keine leere Spalte. */\n.szenen-promptkarte--mitbild .szenen-promptkarte__inhalt {\n padding-right: calc(7rem + var(--space-sm));\n}\n\n.szenen-promptkarte__bild {\n position: absolute;\n top: 0;\n right: 0;\n width: 7rem;\n height: 100%;\n /* Hoechstens so hoch wie breit \u2014 der Streifen bleibt eine Kachel.\n `height: 100%` allein band ihn an die **Kartenhoehe**, und die ist in der\n aufgeklappten Runde die Hoehe des ganzen Prompts: Das Deckbild sprang\n dann als mehrere hundert Pixel hoher, auf Streifenbreite beschnittener\n Balken an den rechten Rand. Geschlossen aendert die Grenze nichts \u2014 dort\n ist die Karte niedriger als 7rem. */\n max-height: 7rem;\n border-left: 1px solid var(--color-border);\n background: #000;\n}\n\n/* Die gemeinsame Kachel bringt `width: 100%` und `aspect-ratio: 1` mit \u2014 hier\n fuellt sie stattdessen den Streifen, genau wie das Library-Deckbild. */\n.szenen-promptkarte__bild .szenen-bildkachel {\n width: 100%;\n height: 100%;\n aspect-ratio: auto;\n}\n\n.szenen-promptkarte__bildzahl {\n position: absolute;\n right: 0.25rem;\n bottom: 0.25rem;\n padding: 0.1rem 0.35rem;\n border-radius: var(--radius-sm);\n background: rgba(0, 0, 0, 0.6);\n color: #fff;\n font-size: 0.62rem;\n font-weight: 700;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n\n/* Ein Kasten je Karte, nicht zwei.\n *\n * `.szenen-view button` (master.css) gibt **jedem** Knopf der Ansicht Rahmen\n * und Hintergrund und schlaegt dabei `.szenen-runs__kopf` (eine Klasse gegen\n * Klasse plus Element). In der Laufhistorie ist das richtig: Dort ist der Kopf\n * der Eintrag. In der Promptkarte ist die Karte der Eintrag \u2014 ein zweiter\n * Kasten darin waere die doppelte Umrandung, die die Library nicht hat.\n * Der Hover braucht eine eigene Zeile, weil die Regel dort spezifischer ist. */\n.szenen-promptkarte .szenen-runs__kopf,\n.szenen-promptkarte .szenen-runs__kopf:hover:not(:disabled) {\n min-height: 0;\n padding: var(--space-xs) 0;\n background: transparent;\n border: none;\n}\n\n/* Dieselbe Karte in der Elementliste.\n *\n * Dort ist der Auswahlknopf die Karte \u2014 er traegt Rahmen, Hintergrund und die\n * Auswahlmarkierung. Der Bildstreifen liegt deshalb **darueber** statt darin:\n * Ein `<button>` nimmt nur Phrasing Content auf, ein Streifen-`div` darin\n * waere ungueltiges Markup. Damit der rechte Kartenrand trotzdem auswaehlbar\n * bleibt, laesst der Streifen Klicks durch. */\n.szenen-elementkarte {\n position: relative;\n}\n\n.szenen-elementkarte--mitbild > button {\n padding-right: calc(7rem + var(--space-sm));\n}\n\n.szenen-elementkarte > .szenen-promptkarte__bild {\n border-radius: 0 var(--radius-sm) var(--radius-sm) 0;\n}\n\n.szenen-promptkarte__bild--durchklickbar {\n pointer-events: none;\n}\n\n/* Null Bilder: die Zahl, keine Flaeche. */\n/* Die Tagliste bricht um. Auf einem Telefon ist das der Unterschied zwischen\n einer kompakten Karte und einer Zeile, die seitlich herauslaeuft. */\n.szenen-tagliste {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n align-items: center;\n margin: 0 0 var(--space-xs);\n padding: 0;\n list-style: none;\n}\n\n.szenen-tag {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.05rem 0.4rem;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n background: var(--color-bg-app);\n font-size: 0.72rem;\n line-height: 1.5;\n white-space: nowrap;\n}\n\n/* Herkunft sichtbar, aber ohne zweite Bedeutungsebene: Ein Prompt-Tag steht\n voll, ein reiner Library-Tag zurueckgenommen. Die Karte soll schnell lesbar\n sein, nicht zwei Farbcodes lehren. */\n.szenen-tag[data-herkunft="library"] {\n border-style: dashed;\n opacity: 0.85;\n}\n\n.szenen-tag--rest {\n border-style: none;\n opacity: 0.7;\n}\n\n.szenen-tag__weg {\n border: none;\n background: none;\n padding: 0;\n color: var(--color-text-secondary, inherit);\n font-size: 0.85rem;\n line-height: 1;\n cursor: pointer;\n}\n\n.szenen-tag__weg:disabled {\n cursor: progress;\n opacity: 0.5;\n}\n\n.szenen-taggeber {\n display: grid;\n gap: var(--space-xs);\n padding: var(--space-xs);\n margin-bottom: var(--space-xs);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-taggeber__zeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n margin: 0;\n}\n\n.szenen-taggeber__label {\n font-size: 0.72rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n opacity: 0.75;\n}\n\n.szenen-taggeber__leer,\n.szenen-taggeber__hinweis {\n font-size: 0.72rem;\n opacity: 0.75;\n}\n\n.szenen-taggeber input[type="text"] {\n flex: 1 1 8rem;\n min-width: 0;\n padding: var(--space-xs);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n background: var(--color-bg-surface);\n color: var(--color-text-primary);\n font-size: 0.8rem;\n}\n\n/* ==========================================================================\n BILDAUFTR\xC4GE \u2014 die bestandsweite Arbeitsqueue\n Kette `szenen-bildauftraege-arbeitsqueue`, Schritt 01.\n ========================================================================== */\n\n.szenen-bildauftraege {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-bildauftraege__steuerung,\n.szenen-bildauftraege__filter,\n.szenen-bildauftraege__aktionen,\n.szenen-bildauftraege__nachladen,\n.szenen-bildauftraege__blaettern {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n}\n\n/* Der manuelle Refresh \u2014 Schritt 03 \xA72. Er steht oben und sichtbar, weil er\n die einzige Stelle ist, an der dieser Bereich nachlaedt: Es gibt keinen\n Timer mehr, den er ersetzen koennte. */\n.szenen-bildauftraege__nachladen {\n justify-content: flex-start;\n}\n\n.szenen-bildauftraege__nachladen span {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n/* Die Blaetterleiste der Bildkontrolle \u2014 Schritt 03 \xA73.1. */\n.szenen-bildauftraege__blaettern {\n margin: 0;\n}\n\n/* \u201EWeitere Bilder" \u2014 seit Schritt 06 eine **Leiste in der Zeile**, kein\n aufklappbares Formular: Modell, Anzahl, Knopf nebeneinander. */\n.szenen-bildauftraege__weitere {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n margin: var(--space-xs) 0 0;\n font-size: 0.85rem;\n}\n\n.szenen-bildauftraege__weitere label {\n color: var(--color-text-secondary);\n}\n\n/* Der Lauf-Zaehler: sichtbar, aber nicht im Weg (Schritt 06). */\n.szenen-bildauftraege__laufzaehler {\n padding: 0.05rem var(--space-xs);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm, 4px);\n font-size: 0.8rem;\n font-variant-numeric: tabular-nums;\n}\n\n/* Die Vorschau steht oben und beh\xE4lt ihren Platz, auch solange noch kein Bild\n vorliegt \u2014 sie ist die Kontrollfl\xE4che des zweiten Browserfensters (\xA75). */\n.szenen-bildauftraege__letztes {\n display: grid;\n gap: var(--space-xs);\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-bildauftraege__letztes h3 {\n margin: 0;\n font-size: 0.95rem;\n}\n\n.szenen-bildauftraege__letztes .szenen-bildkachel {\n width: min(100%, 22rem);\n height: auto;\n}\n\n.szenen-bildauftraege__lauf {\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-bildauftraege__lauf p {\n margin: 0.1rem 0;\n}\n\n.szenen-bildauftraege__liste {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildauftraege__zeile {\n display: grid;\n gap: 0.25rem;\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-bildauftraege__kopf,\n.szenen-bildauftraege__prompt {\n margin: 0;\n}\n\n.szenen-bildauftraege__meta {\n display: flex;\n flex-wrap: wrap;\n gap: 0.15rem var(--space-sm);\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-bildauftraege__prompt {\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n/* \u2500\u2500 Kette `szenen-design`, P4: Szene als Studio \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Kopf mit Speichern, Hero mit Titelbild und Versions-Pill, die B\xFChne auf\n * einem Punktraster, das Element-Sheet von unten, der Prompt-Start als ein\n * Block, L\xE4ufe als Bildstreifen, Aufklapper unten. Kn\xF6pfe in der B\xFChne und im\n * Sheet setzen die Grundoptik von `.szenen-view button` gezielt zur\xFCck \u2014 daher\n * die zwei Klassen in diesen Selektoren. */\n.szenen-studio {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n.szenen-studio__kopf {\n position: sticky;\n top: 0;\n z-index: 3;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n min-height: 2.75rem;\n padding: var(--space-xs) 0;\n background: var(--color-bg-app);\n}\n\n.szenen-studio__kopf > .szenen-detail__ids {\n flex: 1 1 auto;\n margin: 0;\n}\n\n.szenen-studio__ungespeichert {\n color: var(--color-warning);\n font-size: 0.8rem;\n font-weight: 600;\n}\n\n.szenen-view .szenen-studio__speichern {\n min-height: 2.25rem;\n padding: 0 1rem;\n color: var(--color-accent-teal, #2dd4bf);\n background: transparent;\n border-color: var(--color-accent-teal, #2dd4bf);\n border-radius: var(--radius-full);\n font-weight: 650;\n}\n\n.szenen-studio__hero {\n position: relative;\n min-height: 12rem;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-studio__hero--mitbild {\n min-height: 16rem;\n border-color: transparent;\n}\n\n.szenen-studio__titelbild {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-studio__scrim {\n position: absolute;\n inset: 0;\n background: linear-gradient(to top, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.45) 42%, rgba(0, 0, 0, 0) 70%);\n}\n\n.szenen-studio__ohnebild {\n position: absolute;\n inset: 0;\n padding: var(--space-md);\n background:\n radial-gradient(var(--color-border) 1px, transparent 1px) 0 0 / 16px 16px,\n var(--color-bg-surface);\n}\n\n.szenen-studio__symbole {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n color: var(--color-text-secondary);\n}\n\n.szenen-studio__bildfehler {\n margin: 0 0 var(--space-sm);\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-studio__herotext {\n position: absolute;\n right: var(--space-md);\n bottom: var(--space-md);\n left: var(--space-md);\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-studio__herotext h3 {\n margin: 0;\n font-size: 1.5rem;\n line-height: 1.2;\n overflow-wrap: anywhere;\n}\n\n.szenen-studio__hero--mitbild .szenen-studio__herotext {\n color: #fff;\n}\n\n.szenen-studio__herometa {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-studio__pill {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n min-height: 2.25rem;\n padding: 0 0.75rem;\n color: inherit;\n background: rgba(0, 0, 0, 0.55);\n border: 1px solid rgba(255, 255, 255, 0.25);\n border-radius: var(--radius-full);\n}\n\n.szenen-studio__hero:not(.szenen-studio__hero--mitbild) .szenen-studio__pill {\n background: var(--color-bg-elevated);\n border-color: var(--color-border);\n}\n\n/* Kette `szenen-design`, P6 \u2014 Titelbild: \u22EF-Menue im Hero, Hinweis, Zeile\n unter \u201ETechnisch" und die Aktion im Bildviewer. */\n.szenen-studio__heromenu {\n position: relative;\n display: inline-flex;\n}\n\n.szenen-view .szenen-studio__menuknopf {\n justify-content: center;\n min-width: 2.25rem;\n padding: 0 0.5rem;\n}\n\n.szenen-studio__menu {\n position: absolute;\n top: calc(100% + 0.25rem);\n left: 0;\n z-index: 5;\n display: grid;\n min-width: 12rem;\n padding: var(--space-xs, 0.25rem);\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md, 0.5rem);\n}\n\n.szenen-studio__menu button {\n min-height: 2.25rem;\n padding: 0 0.75rem;\n text-align: left;\n color: inherit;\n background: transparent;\n border: 0;\n}\n\n.szenen-studio__menu button:disabled {\n color: var(--color-text-secondary);\n}\n\n.szenen-studio__titelbildhinweis {\n margin: 0;\n font-size: 0.8rem;\n color: var(--color-warning);\n}\n\n.szenen-studio__hero--mitbild .szenen-studio__titelbildhinweis {\n color: #fde68a;\n}\n\n.szenen-studio__titelbildzeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n padding: var(--space-sm) 0;\n font-size: 0.875rem;\n}\n\n.szenen-studio__titelbildref {\n display: block;\n overflow-wrap: anywhere;\n color: var(--color-text-secondary);\n}\n\n.szenen-view .szenen-bildviewer__aktion {\n min-height: 2.25rem;\n padding: 0 0.75rem;\n}\n\n.szenen-bildviewer__titelbild {\n color: var(--color-accent-teal, #2dd4bf);\n font-size: 0.8125rem;\n}\n\n.szenen-studio__komposition {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-studio__abschnittkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-studio__abschnittkopf h4 {\n margin: 0;\n}\n\n.szenen-studio__umschalter {\n display: inline-flex;\n padding: 3px;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-studio__umschalter button {\n min-height: 2rem;\n padding: 0 0.75rem;\n background: transparent;\n border: none;\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-studio__umschalter button[aria-pressed="true"] {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-studio__aufklapper {\n display: grid;\n min-width: 0;\n}\n\n.szenen-studio__aufklapper > details {\n min-width: 0;\n border-top: 1px solid var(--color-border);\n}\n\n.szenen-studio__aufklapper > details:last-child {\n border-bottom: 1px solid var(--color-border);\n}\n\n.szenen-studio__aufklapper > details > summary {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n min-height: 2.75rem;\n cursor: pointer;\n}\n\n.szenen-studio__zusammenfassung {\n margin-left: auto;\n overflow: hidden;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Die B\xFChne */\n.szenen-buehne {\n position: relative;\n width: 100%;\n aspect-ratio: 358 / 330;\n overflow: hidden;\n background:\n radial-gradient(var(--color-border) 1px, transparent 1px) 0 0 / 16px 16px,\n var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-buehne--leer {\n display: grid;\n place-items: center;\n aspect-ratio: auto;\n min-height: 8rem;\n color: var(--color-text-secondary);\n}\n\n.szenen-buehne__linien {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n}\n\n.szenen-buehne__linie {\n stroke: var(--color-text-tertiary);\n stroke-width: 1.5;\n}\n\n.szenen-buehne__linie--naehe {\n stroke-width: 1;\n stroke-dasharray: 3 4;\n}\n\n.szenen-buehne__linie--kontakt {\n stroke: var(--color-text-primary);\n stroke-width: 3;\n}\n\n.szenen-buehne__kegel-start {\n stop-color: var(--color-accent-amber, #f2c46d);\n stop-opacity: 0.35;\n}\n\n.szenen-buehne__kegel-ende {\n stop-color: var(--color-accent-amber, #f2c46d);\n stop-opacity: 0;\n}\n\n.szenen-view .szenen-buehne__node {\n position: absolute;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0.3rem;\n min-height: 0;\n max-width: 6rem;\n padding: 0;\n color: var(--color-text-primary);\n background: transparent;\n border: none;\n transform: translate(-50%, -50%);\n}\n\n.szenen-view .szenen-buehne__node:hover:not(:disabled) {\n background: transparent;\n}\n\n.szenen-buehne__symbol {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: 50%;\n}\n\n.szenen-buehne__node--mitte .szenen-buehne__symbol {\n width: 4rem;\n height: 4rem;\n border: 2px solid var(--color-text-primary);\n}\n\n.szenen-buehne__node--light .szenen-buehne__symbol {\n color: var(--color-accent-amber, #f2c46d);\n}\n\n.szenen-buehne__node[aria-pressed="true"] .szenen-buehne__symbol {\n box-shadow: 0 0 0 2px var(--color-accent-blue);\n}\n\n.szenen-buehne__name {\n max-width: 100%;\n padding: 0 0.25rem;\n overflow: hidden;\n background: var(--color-bg-app);\n border-radius: var(--radius-sm);\n font-size: 0.75rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-buehne__node--mitte .szenen-buehne__name {\n font-weight: 650;\n}\n\n.szenen-buehne__legende {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs) var(--space-md);\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-buehne__legende > span {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.szenen-buehne__legende-hinweis {\n margin-left: auto;\n}\n\n.szenen-buehne__muster {\n display: inline-block;\n width: 1.1rem;\n border-top: 1px dashed var(--color-text-tertiary);\n}\n\n.szenen-buehne__muster--kontakt {\n border-top: 3px solid var(--color-text-primary);\n}\n\n/* Das Element-Sheet */\n.szenen-sheet {\n position: fixed;\n inset: 0;\n z-index: 50;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.szenen-view .szenen-sheet__hintergrund {\n position: absolute;\n inset: 0;\n padding: 0;\n background: rgba(0, 0, 0, 0.6);\n border: none;\n border-radius: 0;\n cursor: default;\n}\n\n.szenen-sheet__flaeche {\n position: relative;\n display: grid;\n gap: var(--space-md);\n width: 100%;\n max-width: 40rem;\n max-height: 85vh;\n padding: var(--space-sm) var(--space-md) var(--space-md);\n overflow-y: auto;\n box-sizing: border-box;\n background: var(--color-bg-surface);\n border-top: 1px solid var(--color-border);\n border-radius: 1.5rem 1.5rem 0 0;\n}\n\n.szenen-sheet__griff {\n justify-self: center;\n width: 2.5rem;\n height: 4px;\n background: var(--color-border);\n border-radius: 2px;\n}\n\n.szenen-sheet__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-sheet__symbol {\n display: flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 3.5rem;\n height: 3.5rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: 50%;\n}\n\n.szenen-sheet__symbol--light {\n color: var(--color-accent-amber, #f2c46d);\n}\n\n.szenen-sheet__titel {\n display: grid;\n gap: 0.15rem;\n min-width: 0;\n}\n\n.szenen-sheet__titel strong {\n font-size: 1.25rem;\n}\n\n.szenen-sheet__titel code {\n overflow: hidden;\n color: var(--color-text-secondary);\n font-family: var(--font-mono);\n font-size: 0.75rem;\n text-overflow: ellipsis;\n}\n\n.szenen-view .szenen-sheet__schliessen {\n display: flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n margin-left: auto;\n padding: 0;\n border-radius: 50%;\n}\n\n.szenen-sheet__abschnitt {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-sheet__abschnitt h5 {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n font-weight: 500;\n}\n\n.szenen-sheet__leer {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-sheet__beziehungen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-sheet__beziehungen li {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n min-height: 2.25rem;\n padding: 0 0.75rem;\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.85rem;\n}\n\n.szenen-sheet__beziehungsart {\n color: var(--color-text-secondary);\n}\n\n.szenen-sheet__bilder {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-sheet__bild {\n position: relative;\n aspect-ratio: 1 / 1;\n overflow: hidden;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-sheet__bild img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-sheet__bildtext {\n display: grid;\n gap: 0.2rem;\n padding: 0.35rem;\n color: var(--color-text-secondary);\n font-size: 0.65rem;\n line-height: 1.25;\n overflow-wrap: anywhere;\n}\n\n.szenen-sheet__bildtext code {\n font-family: var(--font-mono);\n}\n\n.szenen-view .szenen-sheet__fertig {\n min-height: 3rem;\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border: none;\n border-radius: var(--radius-md);\n font-weight: 700;\n}\n\n/* Der Prompt-Start als ein Block */\n.szenen-start {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-start__primaer {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n min-height: 3.25rem;\n color: var(--color-bg-app);\n background: var(--color-accent-teal, #2dd4bf);\n border: none;\n border-radius: var(--radius-md);\n font-size: 1.05rem;\n font-weight: 700;\n}\n\n.szenen-start__kosten {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n text-align: center;\n}\n\n.szenen-start__manuell {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-view .szenen-start__zweit {\n min-height: 2.75rem;\n background: transparent;\n}\n\n.szenen-start__erklaerung > summary {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n cursor: pointer;\n}\n\n.szenen-start__erklaerung[open] .szenen-start__chevron {\n transform: rotate(90deg);\n}\n\n/* L\xE4ufe als Bildstreifen */\n.szenen-streifen {\n display: grid;\n gap: 0.35rem;\n padding: 0 var(--space-sm) var(--space-sm);\n}\n\n.szenen-streifen__bilder {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 4px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-streifen__bild {\n position: relative;\n aspect-ratio: 3 / 4;\n overflow: hidden;\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n}\n\n.szenen-streifen__bild img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-streifen__fehler {\n display: block;\n padding: 0.25rem;\n color: var(--color-text-secondary);\n font-size: 0.65rem;\n}\n\n.szenen-streifen__mehr {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #fff;\n background: rgba(0, 0, 0, 0.6);\n font-size: 0.95rem;\n font-weight: 700;\n}\n\n.szenen-streifen__anzahl {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n/* \xC4ltere Runden: kompakte Zeile mit \xFCberlappenden Miniaturen. */\n.szenen-streifen--zeile {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-streifen--zeile .szenen-streifen__bilder {\n display: flex;\n gap: 0;\n}\n\n.szenen-streifen--zeile .szenen-streifen__bild {\n width: 2.1rem;\n height: 2.75rem;\n aspect-ratio: auto;\n border: 2px solid var(--color-bg-surface);\n}\n\n.szenen-streifen--zeile .szenen-streifen__bild + .szenen-streifen__bild {\n margin-left: -0.75rem;\n}\n\n.szenen-runs__eintrag--karte {\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n/* Szenenst\xE4nde enthalten mehrere Runden derselben eingefrorenen Szene (#538). */\n.szenen-runs__stand > h5 {\n margin: 0;\n font-size: 1rem;\n}\n\n.szenen-runs__stand-laeufe {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-runs__stand-laeufe > li {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* ==========================================================================\n Kette `szenen-design`, P5 \u2014 der Prompt-Lauf als Ergebnisgalerie\n ========================================================================== */\n\n/* \u2500\u2500 Chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-chip,\n.szenen-view .szenen-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n min-height: 1.75rem;\n padding: 0 0.65rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n line-height: 1.2;\n white-space: nowrap;\n}\n\n.szenen-view .szenen-chip--knopf {\n min-height: 2.25rem;\n color: var(--color-text-primary);\n cursor: pointer;\n}\n\n.szenen-chip--library,\n.szenen-view .szenen-chip--library {\n color: var(--color-accent-teal, #2dd4bf);\n border-color: var(--color-accent-teal, #2dd4bf);\n}\n\n/* \u2500\u2500 Navigation der Laufansicht \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-lauf__nav {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n min-width: 0;\n scroll-margin-top: var(--space-md);\n}\n\n.szenen-view .szenen-lauf__zurueck {\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n min-height: 2.75rem;\n padding: 0 0.6rem 0 0.25rem;\n color: var(--color-text-primary);\n background: transparent;\n border: none;\n}\n\n.szenen-lauf__blaettern {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.2rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-lauf__blaettern button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2.5rem;\n height: 2.5rem;\n min-height: 2.5rem;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: var(--radius-full);\n}\n\n/* \u2500\u2500 Kopf: Runde, Status, Chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-laufinhalt {\n gap: var(--space-md);\n}\n\n.szenen-lauf__kopf {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-lauf__szene {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-lauf__titelzeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-lauf__runde {\n margin: 0;\n color: var(--color-text-primary);\n font-size: 1.6rem;\n font-weight: 700;\n line-height: 1.15;\n}\n\n.szenen-lauf__status {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n min-height: 1.6rem;\n padding: 0 0.6rem;\n border: 1px solid currentColor;\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n}\n\n.szenen-lauf__status::before {\n content: "";\n width: 0.4rem;\n height: 0.4rem;\n border-radius: 50%;\n background: currentColor;\n}\n\n.szenen-lauf__status[data-status="succeeded"] { color: var(--color-success); }\n.szenen-lauf__status[data-status="failed"] { color: var(--color-danger); }\n\n.szenen-lauf__chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.4rem;\n min-width: 0;\n}\n\n.szenen-lauf__hinweis {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n/* \u2500\u2500 Galerie \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-lauf .szenen-bilder__ausgang {\n padding: 0;\n background: none;\n border: none;\n}\n\n.szenen-lauf {\n gap: var(--space-md);\n margin-top: 0;\n}\n\n.szenen-lauf .szenen-bilder__batch {\n padding: 0;\n background: none;\n border: none;\n}\n\n.szenen-bildgalerie--ergebnis {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 4px;\n overflow: hidden;\n border-radius: var(--radius-md);\n}\n\n.szenen-bildgalerie--einzeln {\n grid-template-columns: minmax(0, 1fr);\n}\n\n.szenen-bildgalerie--ergebnis .szenen-bildgalerie__kachel {\n border: none;\n border-radius: 0;\n}\n\n.szenen-bildgalerie--einzeln .szenen-bildgalerie__kachel {\n border-radius: var(--radius-md);\n}\n\n.szenen-bildgalerie--ergebnis .szenen-bildkachel {\n aspect-ratio: 3 / 4;\n}\n\n.szenen-bildgalerie__alle-text {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.1rem;\n color: #fff;\n background: rgba(0, 0, 0, 0.65);\n font-size: 0.75rem;\n}\n\n.szenen-bildgalerie__alle-text strong {\n font-size: 1.25rem;\n}\n\n/* P5-Akzeptanz: Eine leere Kachel nennt ihren Grund \u2014 lesbar, nicht nur im\n Tooltip. */\n.szenen-bildkachel__grund {\n display: -webkit-box;\n max-width: 90%;\n overflow: hidden;\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n line-height: 1.3;\n text-align: center;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n}\n\n/* \u2500\u2500 Karten: Prompt, Tags \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-lauf__karte {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-lauf__kartenkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-lauf__label {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-lauf__legende {\n color: var(--color-text-tertiary, var(--color-text-secondary));\n font-size: 0.72rem;\n}\n\n.szenen-lauf__kopieren {\n display: inline-flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-lauf__prompttext {\n margin: 0;\n color: var(--color-text-primary);\n line-height: 1.5;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n/* Drei Zeilen Vorschau \u2014 der volle Text bleibt im Dokument (Kopieren,\n Markieren), gek\xFCrzt wird nur die Darstellung. */\n.szenen-lauf__prompttext--zu {\n display: -webkit-box;\n overflow: hidden;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n}\n\n.szenen-view .szenen-lauf__ganz {\n justify-self: start;\n min-height: 2.25rem;\n padding: 0;\n color: var(--color-accent-teal, var(--color-text-primary));\n background: transparent;\n border: none;\n}\n\n.szenen-lauf__negativ {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-lauf__negativ[hidden] {\n display: none;\n}\n\n.szenen-lauf__negativ p {\n margin: 0;\n color: var(--color-text-secondary);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n.szenen-lauf__karte .szenen-taggeber {\n margin: 0;\n}\n\n.szenen-tagliste .szenen-tag__neu {\n min-height: 2rem;\n}\n\n/* \u2500\u2500 \u201ENeue Bilder" (Serverauftrag des Hosts) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-neuebilder {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg, var(--radius-md));\n}\n\n.szenen-neuebilder__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-neuebilder__kopf h4 {\n margin: 0;\n color: var(--color-text-primary);\n font-size: 1.05rem;\n}\n\n.szenen-neuebilder__symbol {\n color: var(--color-accent-teal, #2dd4bf);\n}\n\n.szenen-neuebilder__weg {\n margin-left: auto;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-neuebilder__felder {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-sm);\n}\n\n.szenen-wahlfeld {\n display: grid;\n gap: 0.15rem;\n min-width: 0;\n padding: 0.4rem 0.6rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-wahlfeld__label {\n color: var(--color-text-secondary);\n font-size: 0.68rem;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n\n.szenen-view .szenen-wahlfeld select {\n min-height: 1.75rem;\n padding: 0;\n color: var(--color-text-primary);\n background: transparent;\n border: none;\n font-weight: 600;\n}\n\n.szenen-umschalter {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n padding: 3px;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-view .szenen-umschalter button {\n min-height: 2.5rem;\n background: transparent;\n border: none;\n}\n\n.szenen-view .szenen-umschalter button[aria-pressed="true"] {\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n font-weight: 600;\n}\n\n.szenen-view .szenen-neuebilder__start {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--space-sm);\n min-height: 3.25rem;\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border: none;\n border-radius: var(--radius-md);\n font-size: 1rem;\n font-weight: 700;\n}\n\n.szenen-view .szenen-neuebilder__start:hover:not(:disabled) {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n opacity: 0.9;\n}\n\n.szenen-neuebilder__laedt,\n.szenen-neuebilder__fehler {\n margin: 0;\n font-size: 0.85rem;\n}\n\n.szenen-neuebilder__laedt { color: var(--color-text-secondary); }\n\n/* Referenzbild eines Laufs (#569-Folge): eigener Bereich \xFCber den Ergebnissen. */\n.szenen-bilder__referenz {\n display: flex;\n gap: var(--space-md);\n align-items: center;\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent-blue);\n border-radius: var(--radius-md);\n}\n\n.szenen-bilder__referenzbild {\n flex: none;\n width: 9rem;\n}\n\n.szenen-bilder__referenzbild img {\n display: block;\n width: 100%;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__referenzleer {\n display: grid;\n place-items: center;\n aspect-ratio: 4 / 3;\n color: var(--color-text-secondary);\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n font-size: 0.8rem;\n}\n\n.szenen-bilder__referenztext {\n display: grid;\n gap: 0.2rem;\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.82rem;\n}\n\n.szenen-bilder__referenztext strong {\n color: var(--color-text-primary);\n}\n\n/* Referenzbild und Prompt am einzelnen Bildauftrag. */\n.szenen-zeitleiste__referenz {\n display: flex;\n gap: var(--space-sm);\n align-items: center;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-zeitleiste__referenz img,\n.szenen-zeitleiste__referenz-leer {\n display: block;\n width: 4.5rem;\n aspect-ratio: 4 / 3;\n object-fit: cover;\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-zeitleiste__prompt {\n white-space: pre-wrap;\n user-select: text;\n}\n\n/* Das mitgegebene Kamera-Preview (#569-Folge) \u2014 sichtbar, bevor bestellt wird. */\n.szenen-neuebilder__referenz {\n margin: 0;\n padding: 0.35rem 0.6rem;\n color: var(--color-text-primary);\n background: var(--color-accent-blue-dim);\n border-left: 2px solid var(--color-accent-blue);\n border-radius: var(--radius-sm);\n font-size: 0.82rem;\n}\n.szenen-neuebilder__fehler { color: var(--color-danger); }\n\n.szenen-neuebilder__warnung > summary {\n display: flex;\n align-items: flex-start;\n gap: var(--space-sm);\n color: var(--color-warning);\n font-size: 0.85rem;\n line-height: 1.45;\n cursor: pointer;\n list-style: none;\n}\n\n.szenen-neuebilder__warnung > summary::-webkit-details-marker { display: none; }\n\n.szenen-neuebilder__warnung > p,\n.szenen-neuebilder__zuordnung ul {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n line-height: 1.5;\n}\n\n.szenen-neuebilder__zuordnung > summary {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n cursor: pointer;\n}\n\n.szenen-neuebilder__zuordnung ul {\n padding-left: 1.1rem;\n}\n\n/* \u2500\u2500 Aufklapper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-aufklapper {\n display: grid;\n min-width: 0;\n border-bottom: 1px solid var(--color-border);\n}\n\n.szenen-aufklapper__eintrag,\n.szenen-aufklapper .szenen-bilder__aktion {\n min-width: 0;\n padding: 0;\n border: none;\n border-top: 1px solid var(--color-border);\n border-radius: 0;\n}\n\n.szenen-aufklapper__eintrag > summary,\n.szenen-aufklapper .szenen-bilder__aktion > summary {\n list-style: none;\n cursor: pointer;\n}\n\n.szenen-aufklapper__eintrag > summary::-webkit-details-marker { display: none; }\n\n.szenen-aufklapper .szenen-bilder__aktion[open] > summary {\n margin-bottom: 0;\n}\n\n.szenen-aufklapper__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n min-height: 2.75rem;\n padding: 0 var(--space-xs);\n color: var(--color-text-primary);\n font-weight: 400;\n}\n\n.szenen-aufklapper__pfeil {\n flex: none;\n transition: transform 0.15s ease;\n}\n\ndetails[open] > summary .szenen-aufklapper__pfeil {\n transform: rotate(90deg);\n}\n\n.szenen-aufklapper__titel {\n min-width: 0;\n}\n\n.szenen-aufklapper__meta {\n margin-left: auto;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-aufklapper__inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: 0 var(--space-xs) var(--space-md) 2rem;\n}\n\n@media (max-width: 760px) {\n .szenen-aufklapper__inhalt {\n padding-left: var(--space-xs);\n }\n}\n\n.szenen-aufklapper__inhalt > p {\n margin: 0;\n}\n\n/* \u2500\u2500 Zeitleiste der Bildauftr\xE4ge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-zeitleiste {\n display: grid;\n gap: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-zeitleiste__schritt {\n position: relative;\n display: flex;\n gap: var(--space-sm);\n min-width: 0;\n padding-bottom: var(--space-md);\n}\n\n/* Die Linie zur n\xE4chsten Zeile. */\n.szenen-zeitleiste__schritt:not(:last-child)::before {\n content: "";\n position: absolute;\n top: 2.1rem;\n bottom: 0;\n left: calc(1rem - 1px);\n width: 2px;\n background: var(--color-border);\n}\n\n.szenen-zeitleiste__symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n border: 1px solid var(--color-border);\n border-radius: 50%;\n background: var(--color-bg-elevated);\n color: var(--color-text-secondary);\n font-weight: 700;\n}\n\n.szenen-zeitleiste__symbol[data-zustand="fertig"] {\n color: var(--color-success);\n border-color: var(--color-success);\n background: var(--color-accent-green-dim, var(--color-bg-elevated));\n}\n\n.szenen-zeitleiste__symbol[data-zustand="fehlgeschlagen"] {\n color: var(--color-danger);\n border-color: var(--color-danger);\n background: var(--color-accent-red-dim, var(--color-bg-elevated));\n}\n\n.szenen-zeitleiste__symbol[data-zustand="teilweise"] {\n color: var(--color-warning);\n border-color: var(--color-warning);\n}\n\n.szenen-zeitleiste__inhalt {\n display: grid;\n gap: 0.15rem;\n min-width: 0;\n padding-top: 0.3rem;\n}\n\n.szenen-zeitleiste__titel {\n color: var(--color-text-primary);\n font-size: 0.9rem;\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n\n.szenen-zeitleiste__ergebnis,\n.szenen-zeitleiste__zusatz {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-zeitleiste__ergebnis[data-zustand="fehlgeschlagen"] { color: var(--color-danger); }\n.szenen-zeitleiste__ergebnis[data-zustand="teilweise"] { color: var(--color-warning); }\n\n.szenen-zeitleiste__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n margin-top: var(--space-xs);\n}\n\n.szenen-zeitleiste__meldung > summary {\n min-height: 2rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n line-height: 2rem;\n cursor: pointer;\n}\n\n.szenen-zeitleiste__meldung p {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-zeitleiste__meldung code {\n display: block;\n margin-top: var(--space-xs);\n color: var(--color-text-tertiary, var(--color-text-secondary));\n font-family: var(--font-mono);\n font-size: 0.72rem;\n overflow-wrap: anywhere;\n}\n\n/* \u2500\u2500 Annahmen \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-annahmen {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-annahmen__zeile {\n display: flex;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-annahmen__symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border-radius: 50%;\n}\n\n.szenen-annahmen__text {\n display: grid;\n gap: 0.1rem;\n min-width: 0;\n font-size: 0.85rem;\n line-height: 1.45;\n overflow-wrap: anywhere;\n}\n\n.szenen-annahmen__art {\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n\n.szenen-annahmen__text details > summary,\n.szenen-lauf__erlaeuterung > summary {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n cursor: pointer;\n}\n\n.szenen-annahmen__text details p,\n.szenen-lauf__erlaeuterung p {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n line-height: 1.5;\n white-space: pre-wrap;\n}\n\n.szenen-lauf__handeingabe h5 {\n margin: 0 0 var(--space-xs);\n}\n\n.szenen-lauf__handeingabe p {\n margin: 0;\n font-size: 0.85rem;\n}\n\n/* Kette `szenen-design`, P7 (#533) \u2014 die Szene aus Bausteinen. Felder als\n Karten, Bausteine im Feld als Chips; die Leiste ist das vorhandene\n Bottom-Sheet mit Bildkacheln. Bedient wird durch Antippen, nicht Ziehen. */\n.szenen-bausteinfelder {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n.szenen-bausteinfelder__liste {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bausteinfeld {\n display: grid;\n align-content: start;\n gap: var(--space-xs);\n min-width: 0;\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-bausteinfeld__kopf {\n display: flex;\n align-items: center;\n gap: 0.4rem;\n}\n\n.szenen-bausteinfeld__leer,\n.szenen-bausteinfeld__gesperrt {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-bausteinfeld__refs {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bausteinchip {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-view .szenen-bausteinchip__name {\n min-height: 2.25rem;\n max-width: 100%;\n padding: 0 0.75rem;\n overflow: hidden;\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.85rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-bausteinchip__aktionen {\n display: inline-flex;\n gap: var(--space-xs);\n}\n\n.szenen-view .szenen-bausteinchip__aktionen button {\n min-width: 2.25rem;\n min-height: 2.25rem;\n padding: 0 0.6rem;\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-bausteinfeld__plus {\n display: inline-flex;\n align-items: center;\n justify-self: start;\n gap: 0.35rem;\n min-height: 2.25rem;\n padding: 0 0.75rem;\n background: transparent;\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-full);\n}\n\n.szenen-bausteinfelder__weitere {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-bausteinfelder__weitere h5 {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n font-weight: 500;\n}\n\n.szenen-bausteinfelder__weitere ul {\n display: grid;\n gap: 0.25rem;\n margin: 0;\n padding: 0;\n list-style: none;\n font-size: 0.85rem;\n}\n\n.szenen-bausteinfelder__ort {\n color: var(--color-text-secondary);\n}\n\n.szenen-view .szenen-bausteinleiste__suche {\n min-height: 2.75rem;\n width: 100%;\n box-sizing: border-box;\n}\n\n.szenen-bausteinleiste {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-view .szenen-bausteinkachel {\n display: grid;\n gap: 0.25rem;\n width: 100%;\n padding: 0;\n overflow: hidden;\n text-align: left;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-view .szenen-bausteinkachel[aria-pressed="true"] {\n border-color: var(--color-text-primary);\n}\n\n.szenen-view .szenen-bausteinkachel:disabled {\n cursor: default;\n opacity: 0.7;\n}\n\n.szenen-bausteinkachel__name {\n display: flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0 0.4rem;\n overflow: hidden;\n font-size: 0.8rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-bausteinkachel__status,\n.szenen-bausteinkachel__grund {\n padding: 0 0.4rem 0.4rem;\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n line-height: 1.25;\n overflow-wrap: anywhere;\n}\n\n@media (min-width: 761px) {\n .szenen-bausteinleiste {\n grid-template-columns: repeat(4, minmax(0, 1fr));\n }\n}\n/* Issue #569: mobile stage controls and exact camera letterbox. */\n/* 3D-B\xFChne (#569): Ansicht zuerst, Werte als Karten darunter. */\n.szenen-3d {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-3d__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-3d__kopf h4 {\n margin: 0 auto 0 0;\n}\n\n/* Als Ansicht \u201E3D\u201C der Komposition: kein zweiter Rahmen im Abschnitt. */\n.szenen-3d--eingebettet {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-3d__kopf {\n flex-wrap: wrap;\n}\n\n.szenen-3d .szenen-3d__aufbau {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n min-width: 0;\n margin-right: auto;\n}\n\n.szenen-3d .szenen-3d__aufbau select {\n width: auto;\n min-width: 0;\n max-width: 100%;\n}\n\n.szenen-3d__stand {\n min-width: 0;\n margin-right: auto;\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-3d__sync {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-3d__sync::before {\n width: 0.5rem;\n height: 0.5rem;\n background: var(--color-success);\n border-radius: var(--radius-full);\n content: "";\n}\n\n.szenen-3d__sync[data-state="speichert"]::before {\n background: var(--color-warning);\n}\n\n.szenen-3d__sync[data-state="ansicht"]::before {\n background: var(--color-accent-blue);\n}\n\n.szenen-3d__meldung,\n.szenen-3d__fehler {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-elevated);\n border-left: 3px solid var(--color-accent-blue);\n border-radius: var(--radius-sm);\n}\n\n.szenen-3d__fehler {\n border-left-color: var(--color-danger);\n}\n\n.szenen-3d__oeffnen {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-3d label {\n display: grid;\n gap: 0.3rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-3d__leiste {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-3d__katalog {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.35rem;\n}\n\n.szenen-3d__katalog > span {\n margin-right: 0.15rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-3d__katalog button,\n.szenen-view .szenen-3d__elemente button {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n min-height: 2rem;\n padding: 0 0.7rem;\n border-radius: var(--radius-full);\n font-size: 0.85rem;\n}\n\n.szenen-3d__katalog i,\n.szenen-3d__elemente i {\n flex: none;\n width: 0.6rem;\n height: 0.6rem;\n border-radius: 2px;\n}\n\n.szenen-view .szenen-3d__elemente button[aria-pressed="true"] {\n color: var(--color-text-primary);\n background: var(--color-bg-surface-hover);\n border-color: var(--color-text-primary);\n}\n\n/* Viewport: feste H\xF6he f\xFCr Drauf- und Seitenansicht; die Kameraansicht wird\n * darin auf das gespeicherte Kameraformat eingepasst (Letterbox). */\n.szenen-3d__viewport {\n position: relative;\n display: grid;\n place-items: center;\n height: clamp(320px, 58vh, 560px);\n overflow: hidden;\n background: #0d0f12;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n container-type: size;\n outline: none;\n}\n\n.szenen-3d__viewport:focus-visible {\n border-color: var(--color-accent-blue);\n box-shadow: 0 0 0 1px var(--color-accent-blue);\n}\n\n.szenen-3d__surface {\n position: relative;\n width: 100%;\n height: 100%;\n touch-action: none;\n user-select: none;\n -webkit-user-select: none;\n}\n\n.szenen-3d__viewport[data-view="camera"] {\n background: #050607;\n}\n\n.szenen-3d__viewport[data-view="camera"] .szenen-3d__surface {\n width: min(100cqw, calc(100cqh * var(--seitenverhaeltnis)));\n height: min(100cqh, calc(100cqw / var(--seitenverhaeltnis)));\n}\n\n.szenen-3d__hud {\n position: absolute;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n color: #d4d4d4;\n font-size: 0.78rem;\n font-variant-numeric: tabular-nums;\n pointer-events: none;\n}\n\n.szenen-3d__hud--werkzeuge {\n top: 0.6rem;\n right: 0.6rem;\n gap: 0.25rem;\n pointer-events: auto;\n}\n\n.szenen-view .szenen-3d__hud--werkzeuge button {\n min-width: 2rem;\n min-height: 2rem;\n padding: 0 0.6rem;\n color: #e5e5e5;\n background: rgba(23, 23, 23, 0.85);\n border-color: rgba(255, 255, 255, 0.12);\n backdrop-filter: blur(4px);\n}\n\n.szenen-3d__hud--kamera {\n top: 0.6rem;\n left: 0.6rem;\n padding: 0.2rem 0.55rem;\n background: rgba(0, 0, 0, 0.65);\n border-radius: var(--radius-full);\n}\n\n.szenen-3d__hud--info {\n bottom: 0.6rem;\n left: 0.6rem;\n max-width: calc(100% - 7rem);\n padding: 0.25rem 0.6rem;\n background: rgba(0, 0, 0, 0.6);\n border-radius: var(--radius-full);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.szenen-3d__hud--info strong {\n color: #ffffff;\n font-weight: 600;\n}\n\n.szenen-3d__hud i {\n font-style: normal;\n font-weight: 700;\n}\n\n.szenen-3d__hud--achsen {\n right: 0.75rem;\n bottom: 0.7rem;\n gap: 0.6rem;\n font-weight: 700;\n}\n\n.szenen-3d__labels {\n position: absolute;\n inset: 0;\n overflow: hidden;\n pointer-events: none;\n}\n\n.szenen-3d__label {\n position: absolute;\n padding: 0.05rem 0.4rem;\n color: #f5f5f5;\n background: rgba(10, 10, 10, 0.72);\n border-left: 2px solid var(--farbe, #9bafbc);\n border-radius: 3px;\n font: 500 0.72rem/1.4 var(--font-sans);\n white-space: nowrap;\n transform: translate(-50%, 6px);\n}\n\n.szenen-3d__label--side {\n transform: translate(-50%, calc(-100% - 6px));\n}\n\n.szenen-3d__label--kamera {\n color: #bfdbfe;\n border-left-color: #60a5fa;\n transform: translate(14px, -50%);\n}\n\n.szenen-3d__label--kamera.is-links {\n transform: translate(calc(-100% - 14px), -50%);\n}\n\n.szenen-3d__label.is-selected {\n color: #000000;\n background: #ffffff;\n}\n\n.szenen-3d__inspektor {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));\n gap: var(--space-sm);\n}\n\n.szenen-3d__karte {\n display: grid;\n align-content: start;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-sm) var(--space-md) var(--space-md);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-3d__karte h5 {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.72rem;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n.szenen-3d__elemente {\n display: flex;\n flex-wrap: wrap;\n gap: 0.35rem;\n}\n\n.szenen-3d__werte {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 0.4rem;\n margin: 0;\n padding: 0;\n border: none;\n}\n\n.szenen-3d__werte legend {\n margin-bottom: 0.4rem;\n padding: 0;\n color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-3d__werte legend span {\n margin-left: 0.35rem;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n font-weight: 400;\n}\n\n.szenen-3d__zeilenkopf {\n grid-column: 1 / -1;\n margin-top: 0.2rem;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-3d__werte > button {\n grid-column: 1 / -1;\n}\n\n.szenen-3d .szenen-3d__feld {\n position: relative;\n display: block;\n}\n\n.szenen-3d__achse {\n position: absolute;\n top: 50%;\n left: 0.55rem;\n font-size: 0.72rem;\n font-weight: 700;\n transform: translateY(-50%);\n pointer-events: none;\n}\n\n.szenen-3d__achse--x { color: #f87171; }\n.szenen-3d__achse--y { color: #4ade80; }\n.szenen-3d__achse--z { color: #60a5fa; }\n\n.szenen-view .szenen-3d__feld input {\n padding-left: 1.6rem;\n font-variant-numeric: tabular-nums;\n}\n\n.szenen-3d__hinweis {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.82rem;\n}\n\n.szenen-3d__abschluss {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-view .szenen-3d__primaer {\n min-height: 2.75rem;\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border-color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-view .szenen-3d__primaer:hover:not(:disabled) {\n color: var(--color-bg-app);\n background: var(--color-primary-hover);\n}\n\n.szenen-view .szenen-3d__nebenaktion {\n justify-self: start;\n min-height: 2rem;\n padding: 0;\n background: none;\n border: none;\n font-size: 0.82rem;\n text-decoration: underline;\n}\n\n/* Hinweise passend zum Eingabeger\xE4t; ohne Angabe gilt die Maus-Variante. */\n.szenen-3d__nur-touch {\n display: none;\n}\n\n@media (hover: none) and (pointer: coarse) {\n .szenen-3d__nur-maus {\n display: none;\n }\n\n .szenen-3d__nur-touch {\n display: inline;\n }\n\n /* Fingergerechte Ziele (44 px) f\xFCr Ansichtssteuerung, Katalog und Elemente. */\n .szenen-view .szenen-3d__hud--werkzeuge button,\n .szenen-view .szenen-3d__katalog button,\n .szenen-view .szenen-3d__elemente button,\n .szenen-view .szenen-3d .szenen-studio__umschalter button {\n min-width: 2.75rem;\n min-height: 2.75rem;\n }\n}\n\n@media (max-width: 760px) {\n .szenen-3d {\n gap: var(--space-sm);\n padding: var(--space-sm);\n }\n\n .szenen-3d__leiste {\n display: grid;\n }\n\n .szenen-3d .szenen-studio__umschalter {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n }\n\n /* Katalog als eine Zeile, die in sich scrollt, statt die Ansicht nach unten zu schieben. */\n .szenen-3d__katalog {\n flex-wrap: nowrap;\n min-width: 0;\n overflow-x: auto;\n scrollbar-width: none;\n }\n\n .szenen-3d__katalog > * {\n flex: none;\n }\n\n .szenen-3d__viewport {\n height: clamp(300px, 62svh, 560px);\n margin: 0 calc(-1 * var(--space-sm));\n border-right: none;\n border-left: none;\n border-radius: 0;\n }\n\n .szenen-3d__hud--info {\n max-width: calc(100% - 1.2rem);\n bottom: 2.4rem;\n }\n\n .szenen-3d__hud--achsen {\n bottom: 0.8rem;\n left: 0.75rem;\n right: auto;\n }\n}\n\n/* One DOM canvas, no nested React renderer. */\n.szenen-3d__canvas { display: block; width: 100%; height: 100%; }\n\n/* Prompt choices before the 3D run; mobile buttons wrap within each category. */\n.szenen-3d__prompt details { margin-block: .65rem; }\n.szenen-3d__prompt summary { cursor: pointer; font-weight: 600; }\n.szenen-3d__prompt fieldset { border: 0; padding: .6rem 0; min-width: 0; }\n.szenen-3d__prompt legend { color: var(--color-text-secondary); font-size: .85rem; }\n.szenen-3d__prompt textarea { min-height: 6rem; width: 100%; box-sizing: border-box; }\n.szenen-3d__referenz { white-space: pre-wrap; overflow-wrap: anywhere; font-size: .9rem; }\n\n.szenen-3d__gemini img { display: block; width: 100%; max-height: 28rem; object-fit: contain; background: #eef0f3; border-radius: .4rem; }\n.szenen-3d__gemini pre { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 32rem; overflow: auto; font-size: .8rem; }\n.szenen-3d__gemini ul { list-style: none; padding: 0; }\n.szenen-3d__gemini li { margin-block: .6rem; overflow-wrap: anywhere; }\n.szenen-3d__gemini li i { display: inline-block; width: .9rem; height: .9rem; margin-right: .4rem; border-radius: .15rem; }\n';
|
|
64
|
+
var SZENEN_VIEW_STYLES = '/* ==========================================================================\n SZENEN VIEW\n ========================================================================== */\n\n.szenen-view {\n display: grid;\n gap: var(--space-md);\n width: 100%;\n min-width: 0;\n font-family: var(--font-sans);\n padding: var(--space-md);\n}\n\n@media (max-width: 760px) {\n .szenen-view {\n padding: var(--space-sm);\n gap: var(--space-sm);\n }\n}\n\n/* Kette `szenen-design`, P1 \u2014 Bild zuerst, Text auf Abruf. Der Kopf ist nur\n * noch Titel und \u24D8; die Erklaerung klappt darunter auf. */\n.szenen-view__intro {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: var(--space-sm);\n color: var(--color-text-primary);\n}\n\n.szenen-view__titel {\n display: grid;\n gap: 0.1rem;\n min-width: 0;\n}\n\n.szenen-view__intro h2,\n.szenen-view__intro p {\n margin: 0;\n}\n\n.szenen-view__intro h2 {\n font-size: clamp(1.5rem, 3vw, 1.9rem);\n font-weight: 700;\n letter-spacing: -0.01em;\n line-height: 1.15;\n}\n\n.szenen-view__eyebrow {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n.szenen-view .szenen-view__info {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n min-height: 2.75rem;\n padding: 0;\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-view__info[aria-expanded="true"] {\n color: var(--color-text-primary);\n border-color: var(--color-accent-teal, #2dd4bf);\n}\n\n.szenen-view__intro-text {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n font-size: 0.85rem;\n line-height: 1.4;\n}\n\n.szenen-icon {\n flex: none;\n}\n\n/* Fuer Screenreader sichtbar, fuer das Auge nicht \u2014 Status-Punkte und\n * Node-Symbole tragen ihre Bedeutung als Text. */\n.szenen-visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n/* Die Bereiche als Pill-Leiste. Sie scrollt in sich, nie die Seite: `min-width:\n * 0` haelt sie in der Spalte, `overflow-x: auto` macht jeden Bereich\n * erreichbar, auch wenn nicht alle nebeneinander passen. */\n.szenen-view__nav {\n display: flex;\n flex-wrap: nowrap;\n gap: var(--space-xs);\n min-width: 0;\n padding: 0 0 var(--space-xs);\n overflow-x: auto;\n scrollbar-width: thin;\n}\n\n.szenen-view__nav button,\n.szenen-view button {\n min-height: 2.25rem;\n padding: 0.45rem 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-view button:hover:not(:disabled) {\n color: var(--color-text-primary);\n background: var(--color-bg-surface-hover);\n border-color: var(--color-border-hover);\n}\n\n.szenen-view button:focus-visible,\n.szenen-view input:focus-visible,\n.szenen-view select:focus-visible,\n.szenen-view textarea:focus-visible {\n outline: 2px solid var(--color-accent-blue);\n outline-offset: 2px;\n}\n\n.szenen-view button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.szenen-view .szenen-view__nav button {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.4rem;\n min-height: 2.25rem;\n padding: 0 0.9rem;\n white-space: nowrap;\n border-radius: var(--radius-full);\n font-size: 0.875rem;\n}\n\n.szenen-view .szenen-view__nav button.is-active,\n.szenen-view .szenen-view__nav button[aria-selected="true"] {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border-color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-view__area {\n min-width: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-view__capability-note,\n.szenen-area__lead {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border-left: 3px solid var(--color-accent-purple);\n border-radius: var(--radius-sm);\n}\n\n.szenen-view__host-notes {\n color: var(--color-text-secondary);\n}\n\n.szenen-view__host-notes > summary {\n cursor: pointer;\n font-size: 0.8rem;\n}\n\n/* `box-sizing` steht hier und nicht beim Host: Die React-App bringt in\n * `master.css` einen globalen `* { box-sizing: border-box }` mit, Flow **nicht**\n * \u2014 dort ragte `width: 100%` plus Innenabstand um die Randbreite aus dem\n * Elternelement heraus und erzeugte auf ~390 px einen horizontalen Scroll. Die\n * gemeinsame Ansicht darf sich auf keinen Host-Reset verlassen. */\n.szenen-view input:not([type="checkbox"]),\n.szenen-view select,\n.szenen-view textarea {\n box-sizing: border-box;\n width: 100%;\n min-height: 2.25rem;\n padding: 0.5rem 0.65rem;\n color: var(--color-text-primary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font: inherit;\n}\n\n.szenen-view textarea {\n min-height: 7rem;\n resize: vertical;\n font-family: var(--font-mono);\n font-size: 0.8rem;\n}\n\n.szenen-view label {\n display: grid;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n.szenen-view code,\n.szenen-view pre {\n font-family: var(--font-mono);\n overflow-wrap: anywhere;\n}\n\n.szenen-view h3,\n.szenen-view h4,\n.szenen-view h5 {\n margin-top: 0;\n}\n\n.szenen-view ul,\n.szenen-view ol {\n padding-left: 1.25rem;\n}\n\n.szenen-elements,\n.szenen-detail,\n.szenen-scene,\n.szenen-setup,\n.szenen-erweitert,\n.szenen-prompts,\n.szenen-shot,\n.szenen-media,\n.szenen-runs {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n/* Arbeitsoberflaeche: Liste links, Bearbeitung rechts.\n *\n * Breit stehen beide Spalten nebeneinander \u2014 die Auswahl bleibt sichtbar,\n * waehrend bearbeitet wird. Schmal rendert die Komponente nur eine der beiden;\n * hier steht deshalb keine Regel, die die andere versteckt. */\n@media (min-width: 761px) {\n .szenen-elements {\n grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);\n align-items: start;\n }\n\n .szenen-elements__master,\n .szenen-elements__detail {\n min-width: 0;\n }\n}\n\n.szenen-elements__master,\n.szenen-elements__detail {\n display: grid;\n gap: var(--space-sm);\n align-content: start;\n min-width: 0;\n}\n\n.szenen-elements__toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-elements__heading {\n margin: 0;\n font-size: 1.05rem;\n}\n\n.szenen-elements__scope {\n display: flex;\n align-items: center;\n gap: var(--space-xs);\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-elements__scope > select {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.szenen-elements__new {\n flex: none;\n font-weight: 700;\n}\n\n.szenen-elements__create {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-accent-blue);\n border-radius: var(--radius-sm);\n}\n\n.szenen-elements__create label {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-elements__create-actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n}\n\n.szenen-elements__options > summary {\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n cursor: pointer;\n}\n\n.szenen-elements__back {\n justify-self: start;\n font-weight: 700;\n}\n\n.szenen-elements__empty-detail {\n margin: 0;\n color: var(--color-text-tertiary);\n}\n\n.szenen-elements__filter,\n.szenen-detail__actions,\n.szenen-runs__start,\n.szenen-scene-editor__add,\n.szenen-scene-editor__add-relation {\n display: flex;\n flex-wrap: wrap;\n align-items: end;\n gap: var(--space-sm);\n}\n\n.szenen-elements__filter > label,\n.szenen-runs__start > label,\n.szenen-scene-editor__add > input {\n flex: 1 1 16rem;\n}\n\n.szenen-elements__filter > label:has(input[type="checkbox"]) {\n display: flex;\n flex: 1 1 16rem;\n flex-direction: row;\n align-items: center;\n}\n\n.szenen-elements__filter input[type="checkbox"] {\n width: 1rem;\n height: 1rem;\n accent-color: var(--color-accent-blue);\n}\n\n.szenen-elements__list {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-elements__list > li > button {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs) var(--space-sm);\n width: 100%;\n height: 100%;\n text-align: left;\n}\n\n.szenen-elements__list > li > button > .szenen-elements__title {\n flex: 1 1 100%;\n}\n\n.szenen-elements__list > li > button.is-selected,\n.szenen-elements__list > li > button[aria-current="true"] {\n background: var(--color-accent-blue-dim);\n border-color: var(--color-accent-blue);\n}\n\n.szenen-elements__type {\n color: var(--color-accent-blue);\n font-size: 0.75rem;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.szenen-elements__title {\n color: var(--color-text-primary);\n font-size: 0.95rem;\n}\n\n.szenen-elements__subtype,\n.szenen-elements__retired {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-elements__retired {\n color: var(--color-warning);\n}\n\n.szenen-detail {\n margin-top: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n@media (min-width: 761px) {\n .szenen-detail {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n }\n}\n\n.szenen-detail > header,\n.szenen-detail__heads,\n.szenen-detail__draft,\n.szenen-capability {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n/* .szenen-runs ist ein eigenst\xE4ndiger sichtbarer Bereich, beh\xE4lt Styling auf Desktop */\n@media (min-width: 761px) {\n .szenen-runs {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n }\n}\n\n@media (max-width: 760px) {\n .szenen-runs {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n }\n}\n\n.szenen-detail__ids {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin-bottom: 0;\n color: var(--color-text-secondary);\n}\n\n.szenen-detail__heads ul,\n.szenen-scene-editor ul,\n.szenen-runs > ol,\n.szenen-capability > ul {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-detail__heads li,\n.szenen-scene-editor li,\n.szenen-runs > ol > li,\n.szenen-capability > ul > li {\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n\n/* Stufe 6.7.2 (D-126) \u2014 Advanced-/Debug-Fl\xE4che f\xFCr die rohe, schema-getriebene\n * Feldliste einer Szene. Gestrichelt wie die anderen \u201EAngebot statt\n * Auskunft"-Bereiche, aber ohne Akzentfarbe: sie ist kein Vorschlag, sondern\n * ein Eskalationsweg. */\n.szenen-detail__technical {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__technical > summary {\n margin-bottom: var(--space-sm);\n color: var(--color-text-secondary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-detail__technical[open] > summary {\n margin-bottom: var(--space-md);\n}\n\n.szenen-detail__field small,\n.szenen-capability small {\n color: var(--color-text-tertiary);\n}\n\n.szenen-detail__preview-errors,\n.szenen-detail__notice--error,\n.szenen-view [role="alert"] {\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-color: var(--color-accent-red);\n}\n\n.szenen-detail__notice {\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__notice--success,\n.szenen-view [data-tone="success"] {\n color: #bbf7d0;\n background: var(--color-accent-green-dim);\n border-color: var(--color-accent-green);\n}\n\n.szenen-scene-editor {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-md);\n margin-bottom: 0;\n}\n\n.szenen-scene-editor > section {\n min-width: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n/* \u2500\u2500 Stufe 6.7.2 (D-126): Node-/Relationskarten \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Nodes und Beziehungen sind `<details>` \u2014 dieselbe Interaktionssprache wie\n * \u201ERohantwort (Diagnose)" und \u201EBilder zu diesem Lauf" in RunsPanel.tsx. Kopf\n * (immer sichtbar) tr\xE4gt Inhalt zuerst, Technik zuletzt; Body (nur bei\n * ge\xF6ffneter Karte) tr\xE4gt die Bearbeitungscontrols. Padding wandert von der\n * `<li>` in Kopf/Body, damit die Karte keinen doppelten Rand bekommt. */\n.szenen-scene-editor li {\n padding: 0;\n overflow: hidden;\n}\n\n.szenen-node-karte__kopf,\n.szenen-relation-karte__kopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs) var(--space-sm);\n padding: var(--space-sm);\n cursor: pointer;\n list-style: none;\n}\n\n.szenen-node-karte__kopf::-webkit-details-marker,\n.szenen-relation-karte__kopf::-webkit-details-marker {\n display: none;\n}\n\n.szenen-node-karte__titel {\n flex: 1 1 12rem;\n min-width: 0;\n color: var(--color-text-primary);\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n\n.szenen-node-karte__typ {\n flex: none;\n padding: 0.15rem 0.55rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.72rem;\n white-space: nowrap;\n}\n\n/* node_id klein, monospace, sekund\xE4r \u2014 sichtbar auch bei zugeklappter Karte,\n * aber optisch klar hinter Beschreibung und Typ. */\n.szenen-node-karte__meta {\n flex: 1 1 100%;\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n}\n\n.szenen-node-karte__meta code {\n font-size: inherit;\n}\n\n.szenen-node-karte__body,\n.szenen-relation-karte__body {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-sm) var(--space-sm);\n border-top: 1px solid var(--color-border);\n}\n\n/* \xA74 \u2014 Prim\xE4raktion und destruktive Aktion optisch getrennt: \u201ENode/Beziehung\n * entfernen" bekommt einen eigenen, warnenden Ton statt gleichgewichtig neben\n * der normalen Bearbeitung zu stehen. */\n.szenen-node-karte__entfernen,\n.szenen-relation-karte__entfernen {\n justify-self: start;\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-color: var(--color-accent-red);\n}\n\n.szenen-relation-karte__kopf {\n font-size: 0.9rem;\n}\n\n.szenen-relation-karte__kopf code {\n overflow-wrap: anywhere;\n}\n\n.szenen-relation-karte__pfeil {\n flex: none;\n color: var(--color-text-secondary);\n}\n\n/* Die Composer-\xD6ffner (\u201E+ Node hinzuf\xFCgen", \u201E+ Beziehung hinzuf\xFCgen") sind\n * Angebote, keine Ausk\xFCnfte \u2014 dasselbe gestrichelte Muster wie beim Folgelauf\n * und der Fehlerrettung (\xA73.3/\xA73.5). */\n.szenen-scene-editor__oeffnen {\n width: 100%;\n border-style: dashed;\n}\n\n.szenen-refpicker {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n margin: var(--space-sm) 0;\n padding: var(--space-sm) 0;\n border: none;\n border-radius: 0;\n}\n\n.szenen-refpicker legend {\n padding: 0 var(--space-xs);\n color: var(--color-text-secondary);\n font-weight: 600;\n}\n\n.szenen-capability > ul > li {\n display: grid;\n grid-template-columns: minmax(10rem, 1fr) auto minmax(14rem, 2fr);\n align-items: start;\n gap: var(--space-sm);\n}\n\n.szenen-capability__state {\n padding: 0.1rem 0.5rem;\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.szenen-capability__state--yes {\n color: #bbf7d0;\n background: var(--color-accent-green-dim);\n}\n\n.szenen-capability__state--no {\n color: #fecaca;\n background: var(--color-accent-red-dim);\n}\n\n.szenen-capability__state--unknown {\n color: #fef08a;\n background: rgba(234, 179, 8, 0.2);\n}\n\n.szenen-runs > ol > li {\n display: grid;\n gap: var(--space-sm);\n}\n\n/* B1 \u2014 die geschlossene Runde. Vorher stand die `run_id` als erstes und war\n die einzige Information, die niemand liest; jetzt beantwortet die Kopfzeile\n welche Runde, ob sie durchging, mit welchem Modell und was ungef\xE4hr\n herauskam. */\n.szenen-runs__hinweis {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n}\n\n.szenen-runs__kopf {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-sm);\n width: 100%;\n padding: var(--space-xs) 0;\n text-align: left;\n color: var(--color-text-secondary);\n background: transparent;\n border: none;\n cursor: pointer;\n}\n\n.szenen-runs__marke {\n font-weight: 700;\n color: var(--color-text-primary);\n}\n\n.szenen-runs__status {\n padding: 0.05rem 0.4rem;\n font-size: 0.6875rem;\n font-weight: 600;\n text-transform: uppercase;\n border-radius: var(--radius-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n}\n\n.szenen-runs__status[data-status="succeeded"] {\n border-color: var(--color-success);\n}\n\n.szenen-runs__status[data-status="failed"] {\n border-color: var(--color-danger);\n}\n\n.szenen-runs__modell {\n font-size: 0.75rem;\n}\n\n/* Der Auszug ist die Inhaltsvorschau der Runde. Er bekommt eine eigene Zeile,\n damit er nicht mit Marke und Modell um dieselbe Zeile ringt. */\n.szenen-runs__auszug {\n flex: 1 1 100%;\n min-width: 0;\n color: var(--color-text-tertiary);\n font-size: 0.8125rem;\n}\n\n/* B2 \u2014 ein Fehler steht ausserhalb der aufklappbaren Fl\xE4che: Wer eine rote\n Runde sieht, soll nicht erst klicken m\xFCssen, um zu erfahren, woran sie\n gescheitert ist. */\n.szenen-runs__fehler {\n display: grid;\n gap: var(--space-xs);\n padding: var(--space-sm);\n border-radius: var(--radius-sm);\n}\n\n.szenen-runs__fehler p {\n margin: 0;\n}\n\n.szenen-runs__inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-runs__prompt > h5,\n.szenen-runs__sekundaer > h5 {\n margin: 0 0 var(--space-xs);\n}\n\n/* Im Kopf traegt die Zeile selbst den Abstand \u2014 sonst kaeme er doppelt. */\n.szenen-runs__promptkopf > h5 {\n margin: 0;\n}\n\n/* Ueberschrift und Kopierknopf in einer Zeile. Der Knopf gehoert an den Text,\n den er kopiert \u2014 nicht an den Rand der Runde, wo er neben dem falschen\n Abschnitt stuende. */\n.szenen-runs__promptkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-sm);\n margin: 0 0 var(--space-xs);\n}\n\n/* Ein kompakter Knopf, kein zweiter Titel: Der Prompt ist die Hauptsache des\n Abschnitts, die Aktion daneben darf ihn nicht ueberstimmen. Rahmen und\n Hintergrund kommen aus `.szenen-view button` und bleiben \u2014 dieselbe Optik wie\n jeder andere Knopf der Ansicht; hier wird nur die Groesse zurueckgenommen.\n Zwei Klassen im Selektor, weil `.szenen-view button` sonst spezifischer ist. */\n.szenen-runs__promptkopf .szenen-runs__kopieren {\n min-height: 0;\n padding: 0.1rem 0.45rem;\n font-size: 0.72rem;\n}\n\n/* Regel 11: die Bestaetigung nennt die Zahl, nicht nur \u201EErfolgreich". */\n.szenen-runs__kopiert {\n color: var(--color-text-tertiary, var(--color-text-secondary));\n font-size: 0.72rem;\n}\n\n.szenen-runs__prompt > p {\n margin: 0;\n white-space: pre-wrap;\n}\n\n.szenen-runs__prompt--negativ > p,\n.szenen-runs__sekundaer > p {\n margin: 0;\n color: var(--color-text-secondary);\n white-space: pre-wrap;\n}\n\n.szenen-runs__mehr {\n justify-self: start;\n margin-top: var(--space-xs);\n padding: 0;\n color: var(--color-accent-teal, var(--color-text-secondary));\n background: transparent;\n border: none;\n font-size: 0.75rem;\n text-decoration: underline;\n cursor: pointer;\n}\n\n.szenen-runs > ol > li[data-status="succeeded"] {\n border-left: 3px solid var(--color-success);\n}\n\n.szenen-runs > ol > li[data-status="failed"] {\n border-left: 3px solid var(--color-danger);\n}\n\n.szenen-runs details pre {\n max-height: 20rem;\n overflow: auto;\n padding: var(--space-sm);\n white-space: pre-wrap;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border-radius: var(--radius-sm);\n}\n\n.szenen-media > section {\n display: grid;\n gap: var(--space-sm);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-media__lookup,\n.szenen-media__attach {\n display: flex;\n flex-wrap: wrap;\n align-items: end;\n gap: var(--space-sm);\n}\n\n.szenen-media__lookup > label,\n.szenen-media__attach > label:first-child {\n flex: 1 1 18rem;\n}\n\n.szenen-media__list {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-media__list > li {\n display: grid;\n grid-template-columns: minmax(12rem, 1fr) auto auto auto;\n align-items: center;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n@media (max-width: 760px) {\n .szenen-view {\n gap: var(--space-sm);\n }\n\n /* C1 \u2014 auf 390 px bleiben drei Kacheln je Reihe gross genug zum Erkennen\n und klein genug, dass vier Bilder eine Reihe sind und keine Seite. */\n .szenen-bildgalerie {\n grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));\n }\n\n /* Der Viewer bekommt den ganzen Bildschirm; die Bl\xE4tterkn\xF6pfe bleiben am\n Rand, wo der Daumen sie erreicht. */\n .szenen-bildviewer {\n padding: var(--space-xs);\n }\n\n .szenen-bildviewer__blaettern {\n width: 2.25rem;\n height: 4rem;\n }\n\n .szenen-view__nav {\n position: sticky;\n top: 0;\n z-index: 2;\n padding: var(--space-xs) 0;\n background: var(--color-bg-app);\n }\n\n\n .szenen-scene-editor {\n grid-template-columns: 1fr;\n }\n\n .szenen-capability > ul > li {\n grid-template-columns: 1fr;\n }\n\n .szenen-derive,\n .szenen-elements,\n .szenen-scene,\n .szenen-setup,\n .szenen-shot,\n .szenen-media,\n .szenen-runs {\n gap: var(--space-sm);\n }\n\n .szenen-elements__filter {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--space-sm);\n }\n\n .szenen-elements__filter > label {\n width: 100%;\n min-width: 0;\n flex: none;\n }\n\n .szenen-elements__filter > label:has(input[type="checkbox"]) {\n flex: none;\n grid-column: 1 / -1;\n }\n\n /* Schmal ist die Liste eine Spalte, und die Auswahl fuehrt weiter \u2014 der\n * Eintrag ist deshalb ein Ziel fuer den Finger, keine Kachel. */\n .szenen-elements__list {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .szenen-elements__list > li > button {\n min-height: 2.75rem;\n }\n\n .szenen-elements__back {\n justify-self: stretch;\n min-height: 2.5rem;\n }\n\n .szenen-detail__actions,\n .szenen-runs__start,\n .szenen-scene-editor__add,\n .szenen-scene-editor__add-relation {\n align-items: stretch;\n flex-direction: column;\n }\n\n .szenen-runs__start > *,\n .szenen-scene-editor__add > *,\n .szenen-scene-editor__add-relation > * {\n width: 100%;\n flex: none;\n }\n}\n\n/* \u2500\u2500 Kette `szenen-design`, P2: Szenen-\xDCbersicht als Bildgalerie \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Kacheln wie in der Library: quadratisch, Deckbild, Titel ueber einem\n * Verlauf, Bildzahl als Plakette. Eine Szene ohne Bild zeigt ihre\n * Node-Symbole; ein nicht ladbares Deckbild nennt den Grund. Die Schrift auf\n * dem Bild ist hell auf dunklem Verlauf \u2014 unabhaengig vom Hostthema, weil das\n * Bild es auch ist. */\n.szenen-galerie {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-galerie__kopf > .szenen-elements__heading {\n flex: 1 1 auto;\n margin: 0;\n}\n\n.szenen-galerie__anzahl,\n.szenen-galerie__sortierung {\n color: var(--color-text-secondary);\n font-weight: 400;\n}\n\n.szenen-galerie__sortierung {\n font-size: 0.8rem;\n}\n\n.szenen-galerie__raster {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(min(100%, 9.5rem), 1fr));\n gap: 0.625rem;\n min-width: 0;\n}\n\n/* Die Kacheln sind Zellen desselben Rasters wie die Neu-Kachel. */\n.szenen-view .szenen-galerie__liste {\n display: contents;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-galerie__kachel {\n min-width: 0;\n}\n\n.szenen-view .szenen-galerie__kachel > button,\n.szenen-view .szenen-galerie__neu,\n.szenen-view .szenen-galerie__zuletzt {\n position: relative;\n display: block;\n width: 100%;\n min-width: 0;\n padding: 0;\n overflow: hidden;\n color: var(--color-text-primary);\n text-align: left;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-galerie__kachel > button {\n aspect-ratio: 1 / 1;\n}\n\n.szenen-view .szenen-galerie__kachel > button[aria-current="true"],\n.szenen-view .szenen-galerie__zuletzt[aria-current="true"] {\n border-color: var(--color-accent-blue);\n box-shadow: 0 0 0 1px var(--color-accent-blue);\n}\n\n.szenen-galerie__bild {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-galerie__scrim {\n position: absolute;\n inset: 0;\n background: linear-gradient(to top, rgba(0, 0, 0, 0.88) 0%, rgba(0, 0, 0, 0.4) 40%, rgba(0, 0, 0, 0) 65%);\n}\n\n.szenen-galerie__ohnebild {\n position: absolute;\n inset: 0;\n padding: 0.75rem;\n background:\n radial-gradient(var(--color-border) 1px, transparent 1px) 0 0 / 14px 14px,\n var(--color-bg-surface);\n}\n\n.szenen-galerie__bildfehler {\n position: absolute;\n inset: 0;\n /* Oben Platz fuer Status-Punkte und Bildzahl, die darueber liegen. */\n padding: 2.25rem 0.75rem 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n font-size: 0.75rem;\n line-height: 1.3;\n}\n\n.szenen-galerie__text {\n position: absolute;\n right: 0.75rem;\n bottom: 0.7rem;\n left: 0.75rem;\n display: grid;\n gap: 0.25rem;\n}\n\n.szenen-galerie__kachel--mitbild .szenen-galerie__text,\n.szenen-galerie__zuletzt--mitbild .szenen-galerie__zuletzt-text {\n color: #fff;\n}\n\n.szenen-galerie__titel {\n display: -webkit-box;\n overflow: hidden;\n font-size: 0.875rem;\n font-weight: 650;\n line-height: 1.25;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 3;\n overflow-wrap: anywhere;\n}\n\n.szenen-galerie__meta {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-galerie__kachel--mitbild .szenen-galerie__meta,\n.szenen-galerie__zuletzt--mitbild .szenen-galerie__meta {\n color: rgba(255, 255, 255, 0.82);\n}\n\n.szenen-galerie__tags {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n min-width: 0;\n}\n\n.szenen-galerie__tag {\n max-width: 100%;\n padding: 0.05rem 0.4rem;\n overflow: hidden;\n color: inherit;\n background: var(--color-bg-elevated);\n border-radius: var(--radius-full);\n font-size: 0.68rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-galerie__kachel--mitbild .szenen-galerie__tag {\n background: rgba(0, 0, 0, 0.5);\n}\n\n.szenen-galerie__status {\n position: absolute;\n top: 0.7rem;\n left: 0.7rem;\n display: flex;\n gap: 0.3rem;\n}\n\n.szenen-galerie__punkt {\n width: 0.625rem;\n height: 0.625rem;\n background: var(--color-text-secondary);\n border-radius: 50%;\n box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.55);\n}\n\n.szenen-galerie__punkt[data-ton="info"] { background: var(--color-accent-blue); }\n.szenen-galerie__punkt[data-ton="ok"] { background: var(--color-success); }\n.szenen-galerie__punkt[data-ton="fertig"] { background: var(--color-warning); }\n/* Unvollstaendig ist ein Ring: Die Form unterscheidet es von \u201Evollstaendig",\n * nicht nur der Farbton (P8). */\n.szenen-galerie__punkt[data-ton="warn"] {\n background: transparent;\n box-shadow: inset 0 0 0 2px var(--color-accent-orange), 0 0 0 2px rgba(0, 0, 0, 0.55);\n}\n\n/* Die Legende der Punkte \u2014 einmal je Ansicht. */\n.szenen-statuslegende {\n display: flex;\n flex-wrap: wrap;\n gap: 0.35rem 0.85rem;\n margin: 0;\n padding: 0;\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n list-style: none;\n}\n\n.szenen-statuslegende__eintrag {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.szenen-statuslegende .szenen-galerie__punkt {\n display: inline-block;\n width: 0.5rem;\n height: 0.5rem;\n}\n\n.szenen-galerie__bildzahl {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.15rem 0.5rem;\n color: #fff;\n background: rgba(0, 0, 0, 0.65);\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n}\n\n.szenen-galerie__symbole {\n display: flex;\n flex-wrap: wrap;\n gap: 0.3rem;\n}\n\n.szenen-galerie__symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 1.875rem;\n height: 1.875rem;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: 50%;\n}\n\n.szenen-galerie__symbol[data-node-type="light"] {\n color: var(--color-warning);\n}\n\n.szenen-galerie__symbol--rest {\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n}\n\n.szenen-view .szenen-galerie__neu {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.6rem;\n aspect-ratio: 1 / 1;\n text-align: center;\n background: var(--color-bg-app);\n border: 1.5px dashed var(--color-border-hover, var(--color-border));\n}\n\n.szenen-galerie__neu-plus {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3.25rem;\n height: 3.25rem;\n color: var(--color-bg-app);\n background: var(--color-accent-teal, #2dd4bf);\n border-radius: 50%;\n}\n\n.szenen-galerie__neu-titel {\n font-size: 0.95rem;\n font-weight: 600;\n}\n\n.szenen-galerie__neu-text {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-galerie__zuletzt-bild {\n position: relative;\n display: block;\n aspect-ratio: 4 / 3;\n max-height: 17rem;\n width: 100%;\n}\n\n.szenen-galerie__chip {\n position: absolute;\n top: 0.75rem;\n left: 0.75rem;\n padding: 0.3rem 0.6rem;\n color: #fff;\n background: rgba(0, 0, 0, 0.6);\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n}\n\n.szenen-galerie__zuletzt .szenen-galerie__status {\n right: 0.75rem;\n left: auto;\n top: 1rem;\n}\n\n/* Die Symbole einer Szene ohne Bild stehen unter dem Chip, nicht darauf. */\n.szenen-galerie__zuletzt .szenen-galerie__ohnebild {\n padding-top: 3rem;\n}\n\n.szenen-galerie__zuletzt-text {\n position: absolute;\n right: 1rem;\n bottom: 0.9rem;\n left: 1rem;\n display: grid;\n gap: 0.35rem;\n}\n\n.szenen-galerie__zuletzt-text .szenen-galerie__titel {\n font-size: 1.3rem;\n font-weight: 700;\n line-height: 1.2;\n}\n\n.szenen-galerie__zuletzt-fuss {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n padding: 0.75rem 0.9rem;\n}\n\n.szenen-galerie__oeffnen {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.25rem;\n color: var(--color-accent-teal, #2dd4bf);\n font-size: 0.875rem;\n font-weight: 600;\n}\n\n/* \u2500\u2500 Stufe 6.5: Rekonstruktion \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Bereich zeigt drei Dinge nebeneinander: den Vorschlag, das nicht\n * Ableitbare und die Widerspr\xFCche. Die Diagnosen sind deshalb bewusst nicht\n * kleiner gesetzt als der Vorschlag \u2014 wer sie \xFCbersieht, \xFCbernimmt Geratenes.\n */\n\n.szenen-derive {\n display: grid;\n gap: var(--space-md);\n}\n\n.szenen-form {\n display: grid;\n gap: var(--space-sm);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-field {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-field > span {\n color: var(--color-text-secondary);\n font-size: 0.875rem;\n}\n\n.szenen-error {\n padding: var(--space-sm) var(--space-md);\n color: var(--color-danger);\n background: var(--color-accent-red-dim);\n border: 1px solid var(--color-accent-red);\n border-radius: var(--radius-sm);\n}\n\n.szenen-empty {\n padding: var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-diagnose {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-warning);\n border-radius: var(--radius-sm);\n}\n\n/* Ein Widerspruch ist der schwerste der drei Befunde: dort steht eine\n * Entscheidung aus, die das System bewusst nicht getroffen hat (D-74). */\n.szenen-diagnose--konflikt {\n border-left-color: var(--color-danger);\n}\n\n.szenen-diagnose > h4 {\n margin: 0 0 var(--space-sm);\n font-size: 0.9375rem;\n}\n\n.szenen-diagnose ul {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding-left: var(--space-md);\n}\n\n.szenen-proposal {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-proposal > h4 {\n margin: 0 0 var(--space-sm);\n font-family: var(--font-mono);\n font-size: 0.9375rem;\n}\n\n.szenen-proposal__payload {\n max-height: 18rem;\n margin: 0 0 var(--space-sm);\n padding: var(--space-sm);\n overflow: auto;\n /* Ein erzeugter Prompt ist ein einziger langer Satz \u2014 ohne Umbruch\n verschwindet er nach rechts aus dem Bild. JSON-Payloads bringen ihre\n eigenen Zeilenumbrueche mit und leiden nicht darunter. */\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n font-family: var(--font-mono);\n font-size: 0.8125rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-proposal__done {\n margin: var(--space-sm) 0 0;\n color: var(--color-success);\n}\n\n/* Die Belege eines Laufs: Rohantwort und Systemprompt. Zum Lesen und Kopieren,\n nicht zum Bedienen \u2014 deshalb voll markierbar und in Monospace. */\n.szenen-beleg__text {\n width: 100%;\n margin: var(--space-sm) 0 0;\n padding: var(--space-sm);\n font-family: var(--font-mono);\n font-size: 0.8125rem;\n line-height: 1.5;\n white-space: pre;\n background: var(--color-bg-app);\n color: var(--color-text);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n resize: vertical;\n}\n\n/* Der Folgelauf (D-87): abgesetzt, damit er nicht wie Teil des Ergebnisses\n aussieht \u2014 er ist eine Frage, keine Auskunft. */\n.szenen-folgelauf {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-folgelauf > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-run__herkunft {\n margin: 0 0 var(--space-sm);\n font-size: 0.875rem;\n color: var(--color-text-muted, inherit);\n}\n\n/* Widerspricht das Modell, ist das das Wichtigste auf der Seite. */\n.szenen-diagnose--antwort {\n border-left: 3px solid var(--color-accent, var(--color-border));\n}\n\n/* Der Bildw\xE4hler (D-92) \u2014 Browser und Inspector, dem Labs-Tab nachgebildet,\n aber mit dem CSS dieser Ansicht: eine gemeinsame Komponente \xFCber zwei\n Dom\xE4nengrenzen w\xE4re eine Kopplung, die keiner gewollt hat.\n\n Der Review vom 2026-08-22 (R12.1/R12.2) hat den Ma\xDFstab gesetzt: Der Bestand\n ist ein **Browser**, kein Seiteninhalt. Vierzig Werke d\xFCrfen die Szenenseite\n nicht meterlang machen, und zw\xF6lf Varianten eines Werkes keine zw\xF6lf\n Bildschirmseiten. Deshalb steht hier alles unter zwei Regeln \u2014 begrenzte\n Fl\xE4che mit eigenem Scroll, und Kacheln statt Karten. */\n\n/* \u2500\u2500 Ebene 1: der Browser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-bildwahl {\n /* Dieselbe Begr\xFCndung wie beim Inspector: Als Grid-Element w\xFCrde der\n W\xE4hler sonst so breit wie sein breitester Inhalt. */\n min-width: 0;\n}\n\n.szenen-bildwahl__browser {\n /* Die eigene Scrollfl\xE4che ist der ganze Punkt: Der Bestand w\xE4chst nach\n innen, nicht nach unten. Dieselbe Gr\xF6\xDFenordnung wie `max-h-[300px]` im\n Labs-Browser. */\n max-height: 19rem;\n overflow-y: auto;\n overscroll-behavior: contain;\n margin-top: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__raster {\n display: grid;\n /* Vier Spalten auf schmalen Displays \u2014 der gemeldete Screenshot zeigte eine\n einzige Spalte gro\xDFer Karten. Breiter wird automatisch dichter. */\n grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildwahl__karte {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n overflow: hidden;\n background: var(--color-bg-surface);\n text-align: left;\n cursor: pointer;\n}\n\n/* Das fokussierte Werk ist klar markiert \u2014 sonst wei\xDF niemand, wessen Galerie\n der Inspector unten zeigt. */\n.szenen-bildwahl__karte.is-fokus {\n border-color: var(--color-accent, var(--color-text-primary));\n box-shadow: 0 0 0 2px var(--color-accent, var(--color-text-primary));\n}\n\n/* \u2500\u2500 Die Kachel selbst \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* Der Platz steht, bevor das Bild da ist \u2014 sonst springt das Raster, sobald\n die erste Vorschau eintrifft. */\n.szenen-bildkachel {\n display: block;\n width: 100%;\n aspect-ratio: 1;\n overflow: hidden;\n background: var(--color-bg-app);\n}\n\n.szenen-bildkachel img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.szenen-bildkachel__leer {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n background: linear-gradient(135deg, var(--color-bg-app), var(--color-bg-surface));\n}\n\n/* R12.3: Eine fehlende Vorschau bleibt kachelgro\xDF. Vorher fiel die Karte auf\n ihren Prompttext zur\xFCck \u2014 und ein Prompt hat im echten Bestand mehrere\n hundert Zeichen. */\n.szenen-bildkachel__zeichen {\n font-size: 0.875rem;\n font-weight: 700;\n color: var(--color-text-secondary);\n opacity: 0.6;\n}\n\n/* Wie viele Varianten das Werk hat \u2014 klein und \xFCberlagernd, nie als\n dominanter Text. */\n.szenen-bildwahl__anzahl {\n position: absolute;\n top: 0.15rem;\n right: 0.15rem;\n padding: 0.05rem 0.3rem;\n font-size: 0.625rem;\n font-weight: 700;\n line-height: 1.4;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* Eine Zeile, dann Schluss. Der Prompt eines Werkes ist oft mehrere hundert\n Zeichen lang und w\xE4re als Prim\xE4rdarstellung genau die Textw\xFCste, gegen die\n der Review antritt. */\n.szenen-bildwahl__kacheltitel {\n display: block;\n padding: 0.15rem 0.3rem;\n font-size: 0.625rem;\n line-height: 1.3;\n color: var(--color-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* \u2500\u2500 Ebene 2: der Inspector \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-bildwahl__inspector {\n /* Ohne `min-width: 0` gewinnt der Inhalt: Der W\xE4hler ist Element eines\n Grids (`.szenen-form`), und dort ist `min-width: auto` die Vorgabe. Der\n Streifen unten ist rund 1000 px breit \u2014 gemessen am 2026-08-22 im echten\n Browser zog er die Auswahl von 374 px auf 1088 px auf und schob die\n ganze Seite waagerecht heraus, statt selbst zu scrollen. */\n min-width: 0;\n margin-top: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n /* Sichtbar abgesetzt vom Browser: zwei Ebenen, nicht eine lange Liste. */\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent, var(--color-border));\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__inspektorkopf {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n margin-bottom: var(--space-sm);\n}\n\n.szenen-bildwahl__werktitel {\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--color-text-primary);\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-bildwahl__zurueck {\n flex: 0 0 auto;\n font-size: 0.6875rem;\n padding: 0.15rem 0.5rem;\n}\n\n/* Der Streifen: waagerecht scrollend, feste kleine Kacheln \u2014 zw\xF6lf Varianten\n bleiben ein \xDCberblick statt zw\xF6lf Bildschirmseiten. */\n.szenen-bildwahl__streifen {\n /* Die Breite kommt vom Elter, nie vom Inhalt \u2014 sonst scrollt hier nichts. */\n max-width: 100%;\n display: flex;\n gap: var(--space-sm);\n margin: 0;\n padding: 0 0 0.25rem;\n list-style: none;\n overflow-x: auto;\n overscroll-behavior-x: contain;\n}\n\n.szenen-bildwahl__streifen > li {\n flex: 0 0 auto;\n width: 5rem;\n}\n\n.szenen-bildwahl__variante {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n overflow: hidden;\n background: var(--color-bg-app);\n cursor: pointer;\n}\n\n.szenen-bildwahl__variante.is-gewaehlt {\n border-color: var(--color-accent, var(--color-text-primary));\n box-shadow: 0 0 0 2px var(--color-accent, var(--color-text-primary));\n}\n\n.szenen-bildwahl__nummer {\n position: absolute;\n bottom: 0.15rem;\n left: 0.15rem;\n padding: 0.05rem 0.3rem;\n font-size: 0.625rem;\n line-height: 1.4;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n}\n\n/* \u2500\u2500 Das Gew\xE4hlte \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-bildwahl__gewaehlt {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: var(--space-sm) 0 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildwahl__gewaehlt li {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.8125rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n max-width: 100%;\n}\n\n/* Das gew\xE4hlte Bild wird best\xE4tigt, nicht nur benannt: eine kleine Vorschau\n neben dem Titel. */\n.szenen-bildwahl__gewaehlt .szenen-bildkachel {\n width: 2.25rem;\n flex: 0 0 auto;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__gewaehlt .szenen-bildwahl__kacheltitel {\n min-width: 0;\n max-width: 12rem;\n font-size: 0.75rem;\n}\n\n.szenen-beleg__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n margin-top: var(--space-sm);\n}\n\n.szenen-diagnose > details + details {\n margin-top: var(--space-sm);\n}\n\n.szenen-diagnose > details > summary {\n cursor: pointer;\n font-weight: 600;\n}\n\n/* \u2500\u2500 Die Fehlerrettung (Stufe 6.6, A5) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Sie steht im Fehlerblock und muss trotzdem als Werkzeug lesbar sein, nicht\n * als weitere Fehlermeldung. Deshalb abgesetzt wie der Folgelauf \u2014 und aus\n * demselben Grund: Beides sind Angebote, keine Ausk\xFCnfte.\n *\n * Der wichtigste optische Punkt ist die Trennung von Original und\n * Arbeitskopie. Das Original bekommt den ruhigen, \u201Efesten" Hintergrund der\n * Belege; die Kopie sieht aus wie ein normales Eingabefeld, weil sie eines\n * ist. */\n.szenen-rettung {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-rettung > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-rettung textarea[readonly] {\n background: var(--color-bg-surface);\n color: var(--color-text-secondary);\n font-family: var(--font-mono, monospace);\n font-size: 0.8125rem;\n}\n\n.szenen-rettung textarea:not([readonly]) {\n font-family: var(--font-mono, monospace);\n font-size: 0.8125rem;\n}\n\n.szenen-rettung__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: var(--space-sm) 0;\n}\n\n/* Ein Befund tr\xE4gt Code, Bezug und Meldung. Der Code steht klein und\n * monospaced davor: Er ist die Kennung, nicht die Aussage. */\n.szenen-diagnose__liste {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding-left: var(--space-md);\n}\n\n.szenen-diagnose__liste code {\n font-size: 0.8125rem;\n}\n\n.szenen-diagnose__liste > li[data-severity=\'warning\'] {\n color: var(--color-text-secondary);\n}\n\n/* \u2500\u2500 Die Draft-Kette (Stufe 6.6, C4) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Hauptweg. Er steht nach den Einzel\xFCbernahmen und muss als das erkennbar\n * sein, was er ist: nicht eine weitere Option, sondern der k\xFCrzere Weg zum\n * selben Ziel. Deshalb durchgezogener Rahmen statt gestricheltem \u2014 er ist\n * Angebot **und** Empfehlung. */\n.szenen-kette {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent, var(--color-border));\n border-radius: var(--radius-sm);\n}\n\n.szenen-kette > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-kette ul {\n display: grid;\n gap: var(--space-xs);\n margin: 0 0 var(--space-sm);\n padding-left: var(--space-md);\n}\n\n.szenen-kette code {\n font-size: 0.8125rem;\n}\n\n/* Ein Hinweis, der eine Bedingung erklaert \u2014 nicht rot, weil er kein Fehler\n ist, aber abgesetzt, weil er eine Folge hat. */\n.szenen-detail__hint {\n margin: var(--space-sm) 0 0;\n padding: var(--space-sm);\n font-size: 0.875rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border-left: 3px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* \u2500\u2500 Stufe 6.7: Bilder am Prompt-Lauf (H0/H1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Bereich tr\xE4gt zwei Dinge, die man nie verwechseln darf: den **Eingang**\n * (woraus der Prompt entstand) und den **Ausgang** (was daraus wurde). Sie\n * bekommen deshalb verschiedene Akzentkanten statt nur verschiedener\n * \xDCberschriften \u2014 wer schnell liest, sieht die Trennung, bevor er sie liest.\n */\n.szenen-bilder {\n display: grid;\n gap: var(--space-md);\n margin-top: var(--space-sm);\n}\n\n.szenen-bilder__eingang,\n.szenen-bilder__ausgang {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__eingang {\n border-left: 3px solid var(--color-accent-purple, var(--color-border));\n}\n\n.szenen-bilder__ausgang {\n border-left: 3px solid var(--color-accent-teal, var(--color-border));\n}\n\n.szenen-bilder h5 {\n margin: 0;\n}\n\n.szenen-bilder__ids {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: 0;\n align-items: baseline;\n color: var(--color-text-secondary);\n font-size: 0.875rem;\n}\n\n.szenen-bilder__eingangsliste,\n.szenen-bilder__batchliste,\n.szenen-bilder__auftraege {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bilder__eingangsliste > li,\n.szenen-bilder__batchliste > li,\n.szenen-bilder__auftraege > li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font-size: 0.8125rem;\n}\n\n/* Ein unterbrochener Auftrag ist der Fall, f\xFCr den der Auftragssatz existiert.\n Er wird deshalb markiert \u2014 nicht rot, denn er ist kein Fehler, sondern eine\n offene Entscheidung. */\n.szenen-bilder__auftraege > li[data-status="started"] {\n border-left: 3px solid var(--color-warning);\n}\n\n.szenen-bilder__auftraege > li[data-status="succeeded"] {\n border-left: 3px solid var(--color-success);\n}\n\n.szenen-bilder__auftraege > li[data-status="partial"] {\n border-left: 3px solid var(--color-accent-blue, var(--color-border));\n}\n\n.szenen-bilder__auftraege > li[data-status="failed"] {\n border-left: 3px solid var(--color-danger);\n}\n\n/* Das Eingangsbild benutzt seit C3 dieselbe Kachel wie W\xE4hler und Galerie.\n Sie ist von Haus aus so breit wie ihr Platz \u2014 in dieser Zeile bekommt sie\n deshalb eine feste Gr\xF6sse, sonst sch\xF6be sie die Metadaten heraus. */\n.szenen-bilder__eingangsliste .szenen-bildkachel {\n flex: 0 0 auto;\n width: 4rem;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__batch {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__batchkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-bilder__herkunft {\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n}\n\n/* Review-Befund \u2014 ein transienter Bildfehler ist wiederholbar, kein\n endg\xFCltiges \u201Efehlt". Dezent wie ein Angebot, nicht wie ein Fehlerzustand. */\n.szenen-bilder__retry {\n justify-self: start;\n padding: 0.15rem 0.5rem;\n font-size: 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n/* C4 \u2014 die Provenienz vollst\xE4ndig, aber sekund\xE4r. */\n.szenen-bilder__technik > summary {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n cursor: pointer;\n}\n\n.szenen-bilder__meta {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n font-size: 0.75rem;\n color: var(--color-text-secondary);\n}\n\n/* C5 \u2014 der Verlauf verdichtet, seine Ausreisser nicht. */\n.szenen-bilder__verlauf > summary {\n color: var(--color-text-secondary);\n font-size: 0.8125rem;\n cursor: pointer;\n}\n\n.szenen-bilder__verlauf[open] > summary {\n margin-bottom: var(--space-sm);\n}\n\n.szenen-bilder__auffaellig {\n margin: 0;\n padding: var(--space-sm);\n border-radius: var(--radius-sm);\n font-size: 0.8125rem;\n}\n\n.szenen-bilder__auftragskennung {\n flex-basis: 100%;\n color: var(--color-text-tertiary);\n font-size: 0.6875rem;\n}\n\n/* \u2500\u2500 C1/C2 \u2014 Galerie und grosse Ansicht \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* Das Raster w\xE4chst mit dem Platz: auf 390 px drei bis vier Kacheln je Reihe,\n auf dem Desktop entsprechend mehr. Vorher war jedes Bild eine Zeile aus\n Daumennagel plus vier Metadatenfeldern \u2014 vier Bilder ergaben vier Textzeilen\n und das Protokoll war die Hauptsache. */\n.szenen-bildgalerie {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr));\n gap: var(--space-sm);\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildgalerie__kachel {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-bildgalerie__kachel:hover,\n.szenen-bildgalerie__kachel:focus-visible {\n border-color: var(--color-accent-teal, var(--color-text-primary));\n}\n\n.szenen-bildgalerie__nummer {\n position: absolute;\n bottom: 0.15rem;\n left: 0.15rem;\n padding: 0.05rem 0.3rem;\n font-size: 0.625rem;\n line-height: 1.4;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n}\n\n/* Die grosse Ansicht liegt \xFCber allem und bringt ihren eigenen Grund mit \u2014\n `position: fixed` bezieht sich im Flow-Canvas auf dessen Rahmen, in React auf\n das Fenster; in beiden F\xE4llen genau das Gew\xFCnschte. */\n.szenen-bildviewer {\n position: fixed;\n inset: 0;\n z-index: 1000;\n display: grid;\n grid-template-rows: auto 1fr auto;\n gap: var(--space-sm);\n padding: var(--space-sm);\n /* Deckend, nicht get\xF6nt: Bei 0.92 schimmerte der Laufbereich durch und man\n las Prompttext quer \xFCber dem Bild \u2014 im Browser gemessen. */\n background: #000;\n}\n\n/* Titel, Z\xE4hlung, Schliessen \u2014 drei Spalten, damit ein langer Werktitel die\n Z\xE4hlung nicht in die n\xE4chste Zeile und \xFCber das Bild schiebt. */\n.szenen-bildviewer__kopf {\n display: grid;\n /* Titel nimmt den Rest; Zaehler, eine optionale Bildaktion (P6) und\n Schliessen stehen rechts \u2014 mit und ohne Aktion in einer Zeile. */\n grid-template-columns: minmax(0, 1fr);\n grid-auto-columns: auto;\n grid-auto-flow: column;\n align-items: center;\n gap: var(--space-sm);\n color: var(--color-text-primary);\n}\n\n.szenen-bildviewer__titel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 600;\n}\n\n.szenen-bildviewer__zaehler {\n color: var(--color-text-secondary);\n font-size: 0.8125rem;\n}\n\n.szenen-bildviewer__buehne {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--space-sm);\n min-height: 0;\n min-width: 0;\n}\n\n/* Der Rahmen nimmt den Platz, der zwischen den Bl\xE4tterkn\xF6pfen \xFCbrig ist \u2014\n `min-width: 0`, damit er auch wirklich schrumpft statt sie hinauszuschieben. */\n.szenen-bildviewer__rahmen {\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 0;\n min-height: 0;\n height: 100%;\n}\n\n.szenen-bildviewer__bild {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n}\n\n.szenen-bildviewer__leer {\n color: var(--color-text-secondary);\n text-align: center;\n}\n\n/* Die Bl\xE4tterkn\xF6pfe sind daumengross und liegen an den R\xE4ndern \u2014 auf einem\n Telefon ist der Rand erreichbar, die Bildmitte nicht. */\n.szenen-bildviewer__blaettern {\n flex: 0 0 auto;\n width: 2.75rem;\n height: 3.5rem;\n font-size: 1.75rem;\n line-height: 1;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-bildviewer__details {\n max-height: 8rem;\n overflow-y: auto;\n color: var(--color-text-secondary);\n}\n\n/* Die Aktionen stehen abgesetzt: Sie sind Angebote, keine Ausk\xFCnfte \u2014 dasselbe\n Muster wie beim Folgelauf und bei der Fehlerrettung. */\n/* D \u2014 die Aktionen stehen abgesetzt und standardm\xE4ssig kompakt: Sie sind\n Angebote, keine Ausk\xFCnfte. Vorher hielten beide Formulare dauerhaft offen und\n machten aus jedem Lauf zwei zus\xE4tzliche Bildschirmseiten. */\n.szenen-bilder__aktion {\n min-width: 0;\n padding: var(--space-sm) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__aktion > summary {\n color: var(--color-text-primary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-bilder__aktion[open] > summary {\n margin-bottom: var(--space-sm);\n}\n\n.szenen-bilder__aktion-inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding-bottom: var(--space-sm);\n}\n\n.szenen-bilder__aktion h5 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-bilder__aktion ol {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding-left: var(--space-md);\n font-size: 0.8125rem;\n}\n\n/* Regelwerk-UX Schritt 16 \u2014 der ZIP-Sammelimport.\n *\n * \xA78: Der gemeldete Einsatz ist mobil. Deshalb **ein** Seedfeld statt einer\n * gestapelten Eingabe je Bild, und die Zuordnung Bild -> Seed als umbrechende\n * Zeile statt als Tabelle: Eine Tabelle waere auf 390 px abgeschnitten, und\n * abgeschnitten heisst hier, dass der Nutzer die Zuordnung nicht mehr pruefen\n * kann \u2014 genau die Pruefung, wegen der die Vorschau existiert. */\n.szenen-bilder__zip {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-bilder__zipkopf {\n margin: 0;\n overflow-wrap: anywhere;\n}\n\n.szenen-bilder__zipvorlagen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n margin: 0;\n}\n\n/* Eine laengere Liste bleibt scrollbar, statt die Sektion und damit den\n * Import-Knopf aus dem Blick zu schieben (\xA78, letzter Punkt). */\n.szenen-bilder__zipliste {\n max-height: 16rem;\n overflow-y: auto;\n}\n\n.szenen-bilder__zipliste > li {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-bilder__zipliste > li > span:first-child {\n overflow-wrap: anywhere;\n}\n\n.szenen-bilder__zipliste > li > span:last-child {\n color: var(--color-text-secondary);\n white-space: nowrap;\n}\n\n/* ==========================================================================\n STUFE 6.10 \u2014 ELEMENTEDITOR UND VERSIONSNAVIGATION\n ========================================================================== */\n\n/* \xA74.2 \u2014 vier Sachverhalte, vier Marken. Die Marken stehen in einer eigenen\n * Spalte, damit ANGEZEIGT + BEVORZUGT nebeneinander lesbar bleiben, statt sich\n * durch den Text zu schieben. */\n.szenen-detail__heads li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-version__titel {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n min-width: 0;\n margin-right: auto;\n}\n\n/* V17 \u2014 Kennungen bleiben vollst\xE4ndig sichtbar, aber optisch sekund\xE4r. */\n.szenen-version__id,\n.szenen-ref__id,\n.szenen-detail__field-key {\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-version__marken {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-version__marken > span {\n padding: 0.1rem 0.5rem;\n color: var(--color-text-primary);\n background: rgba(45, 212, 191, 0.12);\n border: 1px solid rgba(45, 212, 191, 0.35);\n border-radius: var(--radius-full);\n font-size: 0.7rem;\n font-weight: 800;\n letter-spacing: 0.08em;\n}\n\n.szenen-version--angezeigt {\n border-color: var(--color-accent-teal, #2dd4bf) !important;\n}\n\n/* V9 \u2014 der Basiswechsel ist eine Entscheidung, keine Nebenwirkung. */\n.szenen-detail__confirm {\n display: grid;\n gap: var(--space-sm);\n margin: var(--space-md) 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-accent-amber, #f59e0b);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__confirm p {\n margin: 0;\n}\n\n/* Untergruppen von Objektfeldern (`prompt_render_settings`, `overrides`,\n `blender_render_settings`) \u2014 seit A1/A2 auf- und zuklappbar. Eine optionale\n Gruppe startet zu: Blender und `overrides` f\xFCllten auf einem 390-px-Display\n sonst mehrere Bildschirmseiten, obwohl die meisten Shots sie nie anfassen. */\n.szenen-detail__group {\n min-width: 0;\n margin: var(--space-md) 0;\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__group > summary {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-detail__group[open] > summary {\n margin-bottom: var(--space-sm);\n}\n\n/* A2 \u2014 dass eine zugeklappte Gruppe schon Werte tr\xE4gt, muss man sehen, ohne\n sie zu \xF6ffnen. Sonst \xFCbersieht man eine gesetzte Blender-Ausgabe genau so\n lange, bis sie im Ergebnis auftaucht. */\n.szenen-detail__group-status {\n padding: 0.05rem 0.4rem;\n font-size: 0.6875rem;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--color-text-tertiary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__group[data-konfiguriert="ja"] > summary .szenen-detail__group-status {\n color: var(--color-text-primary);\n border-color: var(--color-accent-teal, var(--color-border));\n}\n\n.szenen-detail__group-inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding-bottom: var(--space-sm);\n}\n\n/* A3 \u2014 die Kernaussage steht am Feld, die Begr\xFCndung dahinter. Nicht als\n Tooltip: Auf einem Telefon gibt es kein Hover, und was dort unerreichbar ist,\n ist gestrichen \u2014 nur ohne dass es jemand entschieden h\xE4tte. */\n.szenen-detail__warum > summary {\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n cursor: pointer;\n}\n\n.szenen-detail__warum > small {\n display: block;\n padding-top: var(--space-xs);\n color: var(--color-text-tertiary);\n}\n\n.szenen-detail__fieldrow {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n margin-bottom: var(--space-md);\n}\n\n/* A4 \u2014 der technische Feldname bleibt lesbar, tritt aber hinter das fachliche\n Label zur\xFCck. */\n.szenen-detail__field-label {\n color: var(--color-text-primary);\n}\n\n.szenen-detail__field {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-detail__field > span {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n}\n\n/* Mehrfachauswahl und Listeneditoren. */\n.szenen-feld__mehrfach,\n.szenen-feld__liste,\n.szenen-feld__reflist,\n.szenen-feld__ref,\n.szenen-feld__zielmodell,\n.szenen-bilder__modellwahl,\n.szenen-feld__kamera {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n/* \u201ENeues Modell hinzufuegen" im Importdialog \u2014 dieselben Abstaende wie jedes\n andere Formular dieser Ansicht, damit es kein Fremdkoerper wird. */\n.szenen-feld__zielmodell-neu {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n padding: var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-feld__zielmodell-neu-aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-feld__mehrfach > label,\n.szenen-feld__null {\n display: flex;\n align-items: center;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n.szenen-feld__liste-zeile {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-feld__reflist ol {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-feld__reflist li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n padding: var(--space-xs) var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* \xA76.1 \u2014 Titel und Typ zuerst, Kennungen daneben. */\n.szenen-ref__anzeige {\n display: inline-flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-ref__typ {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-ref__warn {\n padding: 0.1rem 0.5rem;\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-radius: var(--radius-full);\n font-size: 0.72rem;\n font-weight: 700;\n}\n\n/* \xA76.5 \u2014 abgeleitete Angaben, ausdr\xFCcklich nur Anzeige. */\n.szenen-detail__derived {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__derived dl {\n display: grid;\n grid-template-columns: minmax(10rem, auto) 1fr;\n gap: var(--space-xs) var(--space-sm);\n margin: 0;\n}\n\n.szenen-detail__derived dt {\n color: var(--color-text-secondary);\n}\n\n.szenen-detail__derived dd {\n margin: 0;\n}\n\n.szenen-feld__abgeleitet {\n margin: 0;\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n}\n\n/* Bereich `Prompts` \u2014 die herkunftsuebergreifende Sicht (P1-A).\n *\n * Die Eintraege selbst rendert `RundenEintrag` und tragen damit die\n * `szenen-runs__*`-Regeln. Hier stehen nur Rahmen und Kennzeichen; eine zweite\n * Laufdarstellung gibt es nicht, also braucht sie auch kein zweites Aussehen. */\n.szenen-prompts__toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-prompts__heading {\n margin: 0;\n font-size: 1.05rem;\n margin-right: auto;\n}\n\n.szenen-view__fokus {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n margin-bottom: var(--space-sm);\n}\n\n.szenen-prompts__fokus {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n margin-bottom: var(--space-sm);\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-accent, #0d9488);\n border-radius: var(--radius-sm, 4px);\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-prompts__hinweis {\n font-style: italic;\n}\n\n.szenen-prompts__ausgeblendet {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n/* ==========================================================================\n Kette `szenen-design`, P8 \u2014 der Bereich `Prompts` als Bildraster\n ========================================================================== */\n\n/* Herkunfts-Chips: eine Zeile, die in sich scrollt \u2014 nie die Seite. */\n.szenen-prompts__chips {\n display: flex;\n flex-wrap: nowrap;\n gap: 0.375rem;\n min-width: 0;\n padding-bottom: 0.15rem;\n overflow-x: auto;\n scrollbar-width: thin;\n}\n\n.szenen-view .szenen-prompts__chip {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.35rem;\n min-height: 2.25rem;\n padding: 0 0.8rem;\n white-space: nowrap;\n border-radius: var(--radius-full);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-prompts__chip[aria-pressed="true"] {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border-color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-prompts__zeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.375rem;\n min-width: 0;\n}\n\n.szenen-prompts__anzahl {\n flex: 1 1 8rem;\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-prompts__umschalter {\n min-height: 2rem;\n padding: 0 0.65rem;\n font-size: 0.75rem;\n}\n\n.szenen-prompts__raster-bereich {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n/* Der neueste Lauf \u2014 gross, mit Promptzeile und Kopierknopf. */\n.szenen-prompts__neuester {\n min-width: 0;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-prompts__oeffnen {\n display: block;\n width: 100%;\n padding: 0;\n color: var(--color-text-primary);\n text-align: left;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-prompts__bild {\n position: relative;\n display: block;\n height: 17.5rem;\n overflow: hidden;\n}\n\n.szenen-prompts__neuester .szenen-galerie__status {\n top: 0.75rem;\n left: 0.75rem;\n padding: 0.35rem 0.5rem;\n background: rgba(0, 0, 0, 0.55);\n border-radius: var(--radius-full);\n}\n\n.szenen-prompts__neuester .szenen-galerie__bildzahl {\n top: 0.75rem;\n right: 0.75rem;\n}\n\n.szenen-prompts__promptzeile {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.6rem 0.5rem 0.6rem 0.9rem;\n}\n\n.szenen-prompts__prompt {\n flex: 1 1 auto;\n min-width: 0;\n margin: 0;\n overflow: hidden;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-view .szenen-kopieren--symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n min-height: 2.75rem;\n padding: 0;\n color: var(--color-text-primary);\n border-radius: var(--radius-lg);\n}\n\n.szenen-prompts__promptzeile .szenen-lauf__kopieren {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: 0.4rem;\n}\n\n/* Gruppe aufeinanderfolgender Laeufe derselben Szene. */\n.szenen-prompts__gruppe {\n display: grid;\n gap: 0.6rem;\n min-width: 0;\n}\n\n.szenen-prompts__gruppenkopf {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-prompts__gruppenkopf h4 {\n min-width: 0;\n margin: 0;\n font-size: 1rem;\n font-weight: 650;\n line-height: 1.3;\n overflow-wrap: anywhere;\n}\n\n.szenen-prompts__gruppenkopf span {\n flex: none;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n/* Zwei Spalten, Kacheln im Format 3:4. */\n.szenen-view .szenen-prompts__raster {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 0.625rem;\n min-width: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n@media (min-width: 761px) {\n .szenen-view .szenen-prompts__raster {\n grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));\n }\n}\n\n.szenen-prompts__kachel {\n min-width: 0;\n}\n\n.szenen-view .szenen-prompts__kachel > button {\n position: relative;\n display: block;\n width: 100%;\n min-width: 0;\n aspect-ratio: 3 / 4;\n padding: 0;\n overflow: hidden;\n color: var(--color-text-primary);\n text-align: left;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-prompts__kachel.is-fokus > button,\n.szenen-view .szenen-prompts__neuester.is-fokus {\n border-color: var(--color-accent-blue);\n box-shadow: 0 0 0 1px var(--color-accent-blue);\n}\n\n.szenen-prompts__text {\n position: absolute;\n right: 0.75rem;\n bottom: 0.7rem;\n left: 0.75rem;\n display: grid;\n gap: 0.2rem;\n min-width: 0;\n}\n\n.szenen-prompts--mitbild .szenen-prompts__text {\n color: #fff;\n}\n\n.szenen-prompts__titel {\n display: -webkit-box;\n overflow: hidden;\n font-size: 1.25rem;\n font-weight: 700;\n line-height: 1.2;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n overflow-wrap: anywhere;\n}\n\n.szenen-prompts__kachelrunde {\n display: flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.95rem;\n font-weight: 700;\n}\n\n.szenen-prompts__meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.3rem;\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-prompts--mitbild .szenen-prompts__meta {\n color: rgba(255, 255, 255, 0.82);\n}\n\n.szenen-prompts__statuspunkt {\n display: inline-block;\n flex: none;\n width: 0.5rem;\n height: 0.5rem;\n background: var(--color-success);\n border-radius: 50%;\n}\n\n.szenen-prompts__statuspunkt[data-status="failed"] {\n background: var(--color-danger);\n}\n\n/* Eine Kachel ohne Bild nennt ihren Grund \u2014 oben, damit der Text unten frei bleibt. */\n.szenen-prompts__grund {\n display: grid;\n align-content: start;\n gap: 0.3rem;\n padding-top: 2.25rem;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n line-height: 1.3;\n}\n\n.szenen-prompts__fehlertext {\n display: -webkit-box;\n overflow: hidden;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 4;\n overflow-wrap: anywhere;\n}\n\n/* ==========================================================================\n ZIP-MODELLVORSCHLAG (modaler Best\xE4tigungsdialog)\n ========================================================================== */\n\n/* Wie die grosse Bildansicht: eigener Grund, `position: fixed`, damit der\n Dialog im Flow-Canvas und in React gleichermassen \xFCber allem liegt. */\n.szenen-zipmodell {\n position: fixed;\n inset: 0;\n z-index: 1100;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--space-md);\n background: rgba(0, 0, 0, 0.72);\n}\n\n.szenen-zipmodell__karte {\n display: grid;\n gap: var(--space-sm);\n width: min(34rem, 100%);\n max-height: 100%;\n overflow-y: auto;\n padding: var(--space-md);\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-zipmodell__titel {\n margin: 0;\n font-size: 1rem;\n}\n\n.szenen-zipmodell__quelle,\n.szenen-zipmodell__treffer,\n.szenen-zipmodell__vertrauen,\n.szenen-zipmodell__fallback {\n margin: 0;\n font-size: 0.85rem;\n}\n\n.szenen-zipmodell__quelle,\n.szenen-zipmodell__vertrauen {\n color: var(--color-text-secondary);\n}\n\n/* Ein schwacher oder mehrdeutiger Treffer muss sich vom sicheren unterscheiden,\n sonst ist die Warnung nur ein weiterer Satz. */\n.szenen-zipmodell__warnung {\n margin: 0;\n padding: var(--space-xs) var(--space-sm);\n color: var(--color-text-primary);\n background: rgba(234, 179, 8, 0.14);\n border-left: 3px solid #eab308;\n border-radius: var(--radius-sm);\n font-size: 0.85rem;\n}\n\n.szenen-zipmodell__alternativen {\n display: grid;\n gap: 0.2rem;\n margin: 0;\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font-size: 0.85rem;\n}\n\n.szenen-zipmodell__alternativen > label {\n display: flex;\n align-items: center;\n gap: 0.4rem;\n}\n\n.szenen-zipmodell__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n/* ==========================================================================\n MEHR LADEN \u2014 der gemeinsame Fuss jeder seitenweise geladenen Liste\n ========================================================================== */\n\n.szenen-mehr-laden {\n display: grid;\n gap: var(--space-xs);\n justify-items: start;\n padding: var(--space-xs) 0;\n}\n\n.szenen-mehr-laden__button {\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n background: var(--color-bg-surface);\n color: var(--color-text-primary);\n font-size: 0.85rem;\n cursor: pointer;\n}\n\n.szenen-mehr-laden__button:disabled {\n cursor: progress;\n opacity: 0.6;\n}\n\n.szenen-mehr-laden__fehler {\n margin: 0;\n color: var(--color-danger, #f87171);\n font-size: 0.8rem;\n}\n\n/* ==========================================================================\n PROMPTKARTE \u2014 Tags, Vorschau und Bildzahl\n (Kette `szenen-prompt-anzeige-bilder-tags`)\n\n Der Zuschnitt ist der der Library-Karte (`.library-item` + der absolut\n gesetzte Bildstreifen in `LibraryTab`): Textteil links, Deckbild rechts am\n Rand ueber die ganze Kartenhoehe, Bildzahl als Plakette darauf. Dieselben\n Werte (7rem Streifenbreite, linke Trennlinie, Plakette unten rechts), nur\n hier statt in Tailwind-Klassen \u2014 die Szenen-Ansicht teilt dieses Stylesheet\n byteweise mit Flow, und Flow hat kein Tailwind.\n ========================================================================== */\n\n.szenen-promptkarte {\n position: relative;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n padding: var(--space-sm);\n}\n\n/* Nur wo ein Bild liegt, wird Platz dafuer freigehalten. Ohne Bild nutzt der\n Textteil die ganze Breite \u2014 keine leere Spalte. */\n.szenen-promptkarte--mitbild .szenen-promptkarte__inhalt {\n padding-right: calc(7rem + var(--space-sm));\n}\n\n.szenen-promptkarte__bild {\n position: absolute;\n top: 0;\n right: 0;\n width: 7rem;\n height: 100%;\n /* Hoechstens so hoch wie breit \u2014 der Streifen bleibt eine Kachel.\n `height: 100%` allein band ihn an die **Kartenhoehe**, und die ist in der\n aufgeklappten Runde die Hoehe des ganzen Prompts: Das Deckbild sprang\n dann als mehrere hundert Pixel hoher, auf Streifenbreite beschnittener\n Balken an den rechten Rand. Geschlossen aendert die Grenze nichts \u2014 dort\n ist die Karte niedriger als 7rem. */\n max-height: 7rem;\n border-left: 1px solid var(--color-border);\n background: #000;\n}\n\n/* Die gemeinsame Kachel bringt `width: 100%` und `aspect-ratio: 1` mit \u2014 hier\n fuellt sie stattdessen den Streifen, genau wie das Library-Deckbild. */\n.szenen-promptkarte__bild .szenen-bildkachel {\n width: 100%;\n height: 100%;\n aspect-ratio: auto;\n}\n\n.szenen-promptkarte__bildzahl {\n position: absolute;\n right: 0.25rem;\n bottom: 0.25rem;\n padding: 0.1rem 0.35rem;\n border-radius: var(--radius-sm);\n background: rgba(0, 0, 0, 0.6);\n color: #fff;\n font-size: 0.62rem;\n font-weight: 700;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n\n/* Ein Kasten je Karte, nicht zwei.\n *\n * `.szenen-view button` (master.css) gibt **jedem** Knopf der Ansicht Rahmen\n * und Hintergrund und schlaegt dabei `.szenen-runs__kopf` (eine Klasse gegen\n * Klasse plus Element). In der Laufhistorie ist das richtig: Dort ist der Kopf\n * der Eintrag. In der Promptkarte ist die Karte der Eintrag \u2014 ein zweiter\n * Kasten darin waere die doppelte Umrandung, die die Library nicht hat.\n * Der Hover braucht eine eigene Zeile, weil die Regel dort spezifischer ist. */\n.szenen-promptkarte .szenen-runs__kopf,\n.szenen-promptkarte .szenen-runs__kopf:hover:not(:disabled) {\n min-height: 0;\n padding: var(--space-xs) 0;\n background: transparent;\n border: none;\n}\n\n/* Dieselbe Karte in der Elementliste.\n *\n * Dort ist der Auswahlknopf die Karte \u2014 er traegt Rahmen, Hintergrund und die\n * Auswahlmarkierung. Der Bildstreifen liegt deshalb **darueber** statt darin:\n * Ein `<button>` nimmt nur Phrasing Content auf, ein Streifen-`div` darin\n * waere ungueltiges Markup. Damit der rechte Kartenrand trotzdem auswaehlbar\n * bleibt, laesst der Streifen Klicks durch. */\n.szenen-elementkarte {\n position: relative;\n}\n\n.szenen-elementkarte--mitbild > button {\n padding-right: calc(7rem + var(--space-sm));\n}\n\n.szenen-elementkarte > .szenen-promptkarte__bild {\n border-radius: 0 var(--radius-sm) var(--radius-sm) 0;\n}\n\n.szenen-promptkarte__bild--durchklickbar {\n pointer-events: none;\n}\n\n/* Null Bilder: die Zahl, keine Flaeche. */\n/* Die Tagliste bricht um. Auf einem Telefon ist das der Unterschied zwischen\n einer kompakten Karte und einer Zeile, die seitlich herauslaeuft. */\n.szenen-tagliste {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n align-items: center;\n margin: 0 0 var(--space-xs);\n padding: 0;\n list-style: none;\n}\n\n.szenen-tag {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.05rem 0.4rem;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n background: var(--color-bg-app);\n font-size: 0.72rem;\n line-height: 1.5;\n white-space: nowrap;\n}\n\n/* Herkunft sichtbar, aber ohne zweite Bedeutungsebene: Ein Prompt-Tag steht\n voll, ein reiner Library-Tag zurueckgenommen. Die Karte soll schnell lesbar\n sein, nicht zwei Farbcodes lehren. */\n.szenen-tag[data-herkunft="library"] {\n border-style: dashed;\n opacity: 0.85;\n}\n\n.szenen-tag--rest {\n border-style: none;\n opacity: 0.7;\n}\n\n.szenen-tag__weg {\n border: none;\n background: none;\n padding: 0;\n color: var(--color-text-secondary, inherit);\n font-size: 0.85rem;\n line-height: 1;\n cursor: pointer;\n}\n\n.szenen-tag__weg:disabled {\n cursor: progress;\n opacity: 0.5;\n}\n\n.szenen-taggeber {\n display: grid;\n gap: var(--space-xs);\n padding: var(--space-xs);\n margin-bottom: var(--space-xs);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-taggeber__zeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n margin: 0;\n}\n\n.szenen-taggeber__label {\n font-size: 0.72rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n opacity: 0.75;\n}\n\n.szenen-taggeber__leer,\n.szenen-taggeber__hinweis {\n font-size: 0.72rem;\n opacity: 0.75;\n}\n\n.szenen-taggeber input[type="text"] {\n flex: 1 1 8rem;\n min-width: 0;\n padding: var(--space-xs);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n background: var(--color-bg-surface);\n color: var(--color-text-primary);\n font-size: 0.8rem;\n}\n\n/* ==========================================================================\n BILDAUFTR\xC4GE \u2014 die bestandsweite Arbeitsqueue\n Kette `szenen-bildauftraege-arbeitsqueue`, Schritt 01.\n ========================================================================== */\n\n.szenen-bildauftraege {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-bildauftraege__steuerung,\n.szenen-bildauftraege__filter,\n.szenen-bildauftraege__aktionen,\n.szenen-bildauftraege__nachladen,\n.szenen-bildauftraege__blaettern {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n}\n\n/* Der manuelle Refresh \u2014 Schritt 03 \xA72. Er steht oben und sichtbar, weil er\n die einzige Stelle ist, an der dieser Bereich nachlaedt: Es gibt keinen\n Timer mehr, den er ersetzen koennte. */\n.szenen-bildauftraege__nachladen {\n justify-content: flex-start;\n}\n\n.szenen-bildauftraege__nachladen span {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n/* Die Blaetterleiste der Bildkontrolle \u2014 Schritt 03 \xA73.1. */\n.szenen-bildauftraege__blaettern {\n margin: 0;\n}\n\n/* \u201EWeitere Bilder" \u2014 seit Schritt 06 eine **Leiste in der Zeile**, kein\n aufklappbares Formular: Modell, Anzahl, Knopf nebeneinander. */\n.szenen-bildauftraege__weitere {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n margin: var(--space-xs) 0 0;\n font-size: 0.85rem;\n}\n\n.szenen-bildauftraege__weitere label {\n color: var(--color-text-secondary);\n}\n\n/* Der Lauf-Zaehler: sichtbar, aber nicht im Weg (Schritt 06). */\n.szenen-bildauftraege__laufzaehler {\n padding: 0.05rem var(--space-xs);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm, 4px);\n font-size: 0.8rem;\n font-variant-numeric: tabular-nums;\n}\n\n/* Die Vorschau steht oben und beh\xE4lt ihren Platz, auch solange noch kein Bild\n vorliegt \u2014 sie ist die Kontrollfl\xE4che des zweiten Browserfensters (\xA75). */\n.szenen-bildauftraege__letztes {\n display: grid;\n gap: var(--space-xs);\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-bildauftraege__letztes h3 {\n margin: 0;\n font-size: 0.95rem;\n}\n\n.szenen-bildauftraege__letztes .szenen-bildkachel {\n width: min(100%, 22rem);\n height: auto;\n}\n\n.szenen-bildauftraege__lauf {\n padding: var(--space-xs) var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-bildauftraege__lauf p {\n margin: 0.1rem 0;\n}\n\n.szenen-bildauftraege__liste {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildauftraege__zeile {\n display: grid;\n gap: 0.25rem;\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-bildauftraege__kopf,\n.szenen-bildauftraege__prompt {\n margin: 0;\n}\n\n.szenen-bildauftraege__meta {\n display: flex;\n flex-wrap: wrap;\n gap: 0.15rem var(--space-sm);\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-bildauftraege__prompt {\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n/* \u2500\u2500 Kette `szenen-design`, P4: Szene als Studio \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Kopf mit Speichern, Hero mit Titelbild und Versions-Pill, die B\xFChne auf\n * einem Punktraster, das Element-Sheet von unten, der Prompt-Start als ein\n * Block, L\xE4ufe als Bildstreifen, Aufklapper unten. Kn\xF6pfe in der B\xFChne und im\n * Sheet setzen die Grundoptik von `.szenen-view button` gezielt zur\xFCck \u2014 daher\n * die zwei Klassen in diesen Selektoren. */\n.szenen-studio {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n.szenen-studio__kopf {\n position: sticky;\n top: 0;\n z-index: 3;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n min-height: 2.75rem;\n padding: var(--space-xs) 0;\n background: var(--color-bg-app);\n}\n\n.szenen-studio__kopf > .szenen-detail__ids {\n flex: 1 1 auto;\n margin: 0;\n}\n\n.szenen-studio__ungespeichert {\n color: var(--color-warning);\n font-size: 0.8rem;\n font-weight: 600;\n}\n\n.szenen-view .szenen-studio__speichern {\n min-height: 2.25rem;\n padding: 0 1rem;\n color: var(--color-accent-teal, #2dd4bf);\n background: transparent;\n border-color: var(--color-accent-teal, #2dd4bf);\n border-radius: var(--radius-full);\n font-weight: 650;\n}\n\n.szenen-studio__hero {\n position: relative;\n min-height: 12rem;\n overflow: hidden;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-studio__hero--mitbild {\n min-height: 16rem;\n border-color: transparent;\n}\n\n.szenen-studio__titelbild {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-studio__scrim {\n position: absolute;\n inset: 0;\n background: linear-gradient(to top, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.45) 42%, rgba(0, 0, 0, 0) 70%);\n}\n\n.szenen-studio__ohnebild {\n position: absolute;\n inset: 0;\n padding: var(--space-md);\n background:\n radial-gradient(var(--color-border) 1px, transparent 1px) 0 0 / 16px 16px,\n var(--color-bg-surface);\n}\n\n.szenen-studio__symbole {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n color: var(--color-text-secondary);\n}\n\n.szenen-studio__bildfehler {\n margin: 0 0 var(--space-sm);\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-studio__herotext {\n position: absolute;\n right: var(--space-md);\n bottom: var(--space-md);\n left: var(--space-md);\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-studio__herotext h3 {\n margin: 0;\n font-size: 1.5rem;\n line-height: 1.2;\n overflow-wrap: anywhere;\n}\n\n.szenen-studio__hero--mitbild .szenen-studio__herotext {\n color: #fff;\n}\n\n.szenen-studio__herometa {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-studio__pill {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n min-height: 2.25rem;\n padding: 0 0.75rem;\n color: inherit;\n background: rgba(0, 0, 0, 0.55);\n border: 1px solid rgba(255, 255, 255, 0.25);\n border-radius: var(--radius-full);\n}\n\n.szenen-studio__hero:not(.szenen-studio__hero--mitbild) .szenen-studio__pill {\n background: var(--color-bg-elevated);\n border-color: var(--color-border);\n}\n\n/* Kette `szenen-design`, P6 \u2014 Titelbild: \u22EF-Menue im Hero, Hinweis, Zeile\n unter \u201ETechnisch" und die Aktion im Bildviewer. */\n.szenen-studio__heromenu {\n position: relative;\n display: inline-flex;\n}\n\n.szenen-view .szenen-studio__menuknopf {\n justify-content: center;\n min-width: 2.25rem;\n padding: 0 0.5rem;\n}\n\n.szenen-studio__menu {\n position: absolute;\n top: calc(100% + 0.25rem);\n left: 0;\n z-index: 5;\n display: grid;\n min-width: 12rem;\n padding: var(--space-xs, 0.25rem);\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md, 0.5rem);\n}\n\n.szenen-studio__menu button {\n min-height: 2.25rem;\n padding: 0 0.75rem;\n text-align: left;\n color: inherit;\n background: transparent;\n border: 0;\n}\n\n.szenen-studio__menu button:disabled {\n color: var(--color-text-secondary);\n}\n\n.szenen-studio__titelbildhinweis {\n margin: 0;\n font-size: 0.8rem;\n color: var(--color-warning);\n}\n\n.szenen-studio__hero--mitbild .szenen-studio__titelbildhinweis {\n color: #fde68a;\n}\n\n.szenen-studio__titelbildzeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n padding: var(--space-sm) 0;\n font-size: 0.875rem;\n}\n\n.szenen-studio__titelbildref {\n display: block;\n overflow-wrap: anywhere;\n color: var(--color-text-secondary);\n}\n\n.szenen-view .szenen-bildviewer__aktion {\n min-height: 2.25rem;\n padding: 0 0.75rem;\n}\n\n.szenen-bildviewer__titelbild {\n color: var(--color-accent-teal, #2dd4bf);\n font-size: 0.8125rem;\n}\n\n.szenen-studio__komposition {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-studio__abschnittkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-studio__abschnittkopf h4 {\n margin: 0;\n}\n\n.szenen-studio__umschalter {\n display: inline-flex;\n padding: 3px;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-studio__umschalter button {\n min-height: 2rem;\n padding: 0 0.75rem;\n background: transparent;\n border: none;\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-studio__umschalter button[aria-pressed="true"] {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-studio__aufklapper {\n display: grid;\n min-width: 0;\n}\n\n.szenen-studio__aufklapper > details {\n min-width: 0;\n border-top: 1px solid var(--color-border);\n}\n\n.szenen-studio__aufklapper > details:last-child {\n border-bottom: 1px solid var(--color-border);\n}\n\n.szenen-studio__aufklapper > details > summary {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n min-height: 2.75rem;\n cursor: pointer;\n}\n\n.szenen-studio__zusammenfassung {\n margin-left: auto;\n overflow: hidden;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Die B\xFChne */\n.szenen-buehne {\n position: relative;\n width: 100%;\n aspect-ratio: 358 / 330;\n overflow: hidden;\n background:\n radial-gradient(var(--color-border) 1px, transparent 1px) 0 0 / 16px 16px,\n var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-buehne--leer {\n display: grid;\n place-items: center;\n aspect-ratio: auto;\n min-height: 8rem;\n color: var(--color-text-secondary);\n}\n\n.szenen-buehne__linien {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n}\n\n.szenen-buehne__linie {\n stroke: var(--color-text-tertiary);\n stroke-width: 1.5;\n}\n\n.szenen-buehne__linie--naehe {\n stroke-width: 1;\n stroke-dasharray: 3 4;\n}\n\n.szenen-buehne__linie--kontakt {\n stroke: var(--color-text-primary);\n stroke-width: 3;\n}\n\n.szenen-buehne__kegel-start {\n stop-color: var(--color-accent-amber, #f2c46d);\n stop-opacity: 0.35;\n}\n\n.szenen-buehne__kegel-ende {\n stop-color: var(--color-accent-amber, #f2c46d);\n stop-opacity: 0;\n}\n\n.szenen-view .szenen-buehne__node {\n position: absolute;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0.3rem;\n min-height: 0;\n max-width: 6rem;\n padding: 0;\n color: var(--color-text-primary);\n background: transparent;\n border: none;\n transform: translate(-50%, -50%);\n}\n\n.szenen-view .szenen-buehne__node:hover:not(:disabled) {\n background: transparent;\n}\n\n.szenen-buehne__symbol {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: 50%;\n}\n\n.szenen-buehne__node--mitte .szenen-buehne__symbol {\n width: 4rem;\n height: 4rem;\n border: 2px solid var(--color-text-primary);\n}\n\n.szenen-buehne__node--light .szenen-buehne__symbol {\n color: var(--color-accent-amber, #f2c46d);\n}\n\n.szenen-buehne__node[aria-pressed="true"] .szenen-buehne__symbol {\n box-shadow: 0 0 0 2px var(--color-accent-blue);\n}\n\n.szenen-buehne__name {\n max-width: 100%;\n padding: 0 0.25rem;\n overflow: hidden;\n background: var(--color-bg-app);\n border-radius: var(--radius-sm);\n font-size: 0.75rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-buehne__node--mitte .szenen-buehne__name {\n font-weight: 650;\n}\n\n.szenen-buehne__legende {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs) var(--space-md);\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-buehne__legende > span {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n}\n\n.szenen-buehne__legende-hinweis {\n margin-left: auto;\n}\n\n.szenen-buehne__muster {\n display: inline-block;\n width: 1.1rem;\n border-top: 1px dashed var(--color-text-tertiary);\n}\n\n.szenen-buehne__muster--kontakt {\n border-top: 3px solid var(--color-text-primary);\n}\n\n/* Das Element-Sheet */\n.szenen-sheet {\n position: fixed;\n inset: 0;\n z-index: 50;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.szenen-view .szenen-sheet__hintergrund {\n position: absolute;\n inset: 0;\n padding: 0;\n background: rgba(0, 0, 0, 0.6);\n border: none;\n border-radius: 0;\n cursor: default;\n}\n\n.szenen-sheet__flaeche {\n position: relative;\n display: grid;\n gap: var(--space-md);\n width: 100%;\n max-width: 40rem;\n max-height: 85vh;\n padding: var(--space-sm) var(--space-md) var(--space-md);\n overflow-y: auto;\n box-sizing: border-box;\n background: var(--color-bg-surface);\n border-top: 1px solid var(--color-border);\n border-radius: 1.5rem 1.5rem 0 0;\n}\n\n.szenen-sheet__griff {\n justify-self: center;\n width: 2.5rem;\n height: 4px;\n background: var(--color-border);\n border-radius: 2px;\n}\n\n.szenen-sheet__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-sheet__symbol {\n display: flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 3.5rem;\n height: 3.5rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: 50%;\n}\n\n.szenen-sheet__symbol--light {\n color: var(--color-accent-amber, #f2c46d);\n}\n\n.szenen-sheet__titel {\n display: grid;\n gap: 0.15rem;\n min-width: 0;\n}\n\n.szenen-sheet__titel strong {\n font-size: 1.25rem;\n}\n\n.szenen-sheet__titel code {\n overflow: hidden;\n color: var(--color-text-secondary);\n font-family: var(--font-mono);\n font-size: 0.75rem;\n text-overflow: ellipsis;\n}\n\n.szenen-view .szenen-sheet__schliessen {\n display: flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n height: 2.75rem;\n margin-left: auto;\n padding: 0;\n border-radius: 50%;\n}\n\n.szenen-sheet__abschnitt {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-sheet__abschnitt h5 {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n font-weight: 500;\n}\n\n.szenen-sheet__leer {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-sheet__beziehungen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-sheet__beziehungen li {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n min-height: 2.25rem;\n padding: 0 0.75rem;\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.85rem;\n}\n\n.szenen-sheet__beziehungsart {\n color: var(--color-text-secondary);\n}\n\n.szenen-sheet__bilder {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-sheet__bild {\n position: relative;\n aspect-ratio: 1 / 1;\n overflow: hidden;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-sheet__bild img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-sheet__bildtext {\n display: grid;\n gap: 0.2rem;\n padding: 0.35rem;\n color: var(--color-text-secondary);\n font-size: 0.65rem;\n line-height: 1.25;\n overflow-wrap: anywhere;\n}\n\n.szenen-sheet__bildtext code {\n font-family: var(--font-mono);\n}\n\n.szenen-view .szenen-sheet__fertig {\n min-height: 3rem;\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border: none;\n border-radius: var(--radius-md);\n font-weight: 700;\n}\n\n/* Der Prompt-Start als ein Block */\n.szenen-start {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view .szenen-start__primaer {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n min-height: 3.25rem;\n color: var(--color-bg-app);\n background: var(--color-accent-teal, #2dd4bf);\n border: none;\n border-radius: var(--radius-md);\n font-size: 1.05rem;\n font-weight: 700;\n}\n\n.szenen-start__kosten {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n text-align: center;\n}\n\n.szenen-start__manuell {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-view .szenen-start__zweit {\n min-height: 2.75rem;\n background: transparent;\n}\n\n.szenen-start__erklaerung > summary {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n cursor: pointer;\n}\n\n.szenen-start__erklaerung[open] .szenen-start__chevron {\n transform: rotate(90deg);\n}\n\n/* L\xE4ufe als Bildstreifen */\n.szenen-streifen {\n display: grid;\n gap: 0.35rem;\n padding: 0 var(--space-sm) var(--space-sm);\n}\n\n.szenen-streifen__bilder {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 4px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-streifen__bild {\n position: relative;\n aspect-ratio: 3 / 4;\n overflow: hidden;\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n}\n\n.szenen-streifen__bild img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.szenen-streifen__fehler {\n display: block;\n padding: 0.25rem;\n color: var(--color-text-secondary);\n font-size: 0.65rem;\n}\n\n.szenen-streifen__mehr {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #fff;\n background: rgba(0, 0, 0, 0.6);\n font-size: 0.95rem;\n font-weight: 700;\n}\n\n.szenen-streifen__anzahl {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n/* \xC4ltere Runden: kompakte Zeile mit \xFCberlappenden Miniaturen. */\n.szenen-streifen--zeile {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-streifen--zeile .szenen-streifen__bilder {\n display: flex;\n gap: 0;\n}\n\n.szenen-streifen--zeile .szenen-streifen__bild {\n width: 2.1rem;\n height: 2.75rem;\n aspect-ratio: auto;\n border: 2px solid var(--color-bg-surface);\n}\n\n.szenen-streifen--zeile .szenen-streifen__bild + .szenen-streifen__bild {\n margin-left: -0.75rem;\n}\n\n.szenen-runs__eintrag--karte {\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n/* Szenenst\xE4nde enthalten mehrere Runden derselben eingefrorenen Szene (#538). */\n.szenen-runs__stand > h5 {\n margin: 0;\n font-size: 1rem;\n}\n\n.szenen-runs__stand-laeufe {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-runs__stand-laeufe > li {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* ==========================================================================\n Kette `szenen-design`, P5 \u2014 der Prompt-Lauf als Ergebnisgalerie\n ========================================================================== */\n\n/* \u2500\u2500 Chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-chip,\n.szenen-view .szenen-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n min-height: 1.75rem;\n padding: 0 0.65rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n line-height: 1.2;\n white-space: nowrap;\n}\n\n.szenen-view .szenen-chip--knopf {\n min-height: 2.25rem;\n color: var(--color-text-primary);\n cursor: pointer;\n}\n\n.szenen-chip--library,\n.szenen-view .szenen-chip--library {\n color: var(--color-accent-teal, #2dd4bf);\n border-color: var(--color-accent-teal, #2dd4bf);\n}\n\n/* \u2500\u2500 Navigation der Laufansicht \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-lauf__nav {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n min-width: 0;\n scroll-margin-top: var(--space-md);\n}\n\n.szenen-view .szenen-lauf__zurueck {\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n min-height: 2.75rem;\n padding: 0 0.6rem 0 0.25rem;\n color: var(--color-text-primary);\n background: transparent;\n border: none;\n}\n\n.szenen-lauf__blaettern {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.2rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-lauf__blaettern button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2.5rem;\n height: 2.5rem;\n min-height: 2.5rem;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: var(--radius-full);\n}\n\n/* \u2500\u2500 Kopf: Runde, Status, Chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-laufinhalt {\n gap: var(--space-md);\n}\n\n.szenen-lauf__kopf {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-lauf__szene {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-lauf__titelzeile {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-lauf__runde {\n margin: 0;\n color: var(--color-text-primary);\n font-size: 1.6rem;\n font-weight: 700;\n line-height: 1.15;\n}\n\n.szenen-lauf__status {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n min-height: 1.6rem;\n padding: 0 0.6rem;\n border: 1px solid currentColor;\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n}\n\n.szenen-lauf__status::before {\n content: "";\n width: 0.4rem;\n height: 0.4rem;\n border-radius: 50%;\n background: currentColor;\n}\n\n.szenen-lauf__status[data-status="succeeded"] { color: var(--color-success); }\n.szenen-lauf__status[data-status="failed"] { color: var(--color-danger); }\n\n.szenen-lauf__chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.4rem;\n min-width: 0;\n}\n\n.szenen-lauf__hinweis {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n/* \u2500\u2500 Galerie \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-lauf .szenen-bilder__ausgang {\n padding: 0;\n background: none;\n border: none;\n}\n\n.szenen-lauf {\n gap: var(--space-md);\n margin-top: 0;\n}\n\n.szenen-lauf .szenen-bilder__batch {\n padding: 0;\n background: none;\n border: none;\n}\n\n.szenen-bildgalerie--ergebnis {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 4px;\n overflow: hidden;\n border-radius: var(--radius-md);\n}\n\n.szenen-bildgalerie--einzeln {\n grid-template-columns: minmax(0, 1fr);\n}\n\n.szenen-bildgalerie--ergebnis .szenen-bildgalerie__kachel {\n border: none;\n border-radius: 0;\n}\n\n.szenen-bildgalerie--einzeln .szenen-bildgalerie__kachel {\n border-radius: var(--radius-md);\n}\n\n.szenen-bildgalerie--ergebnis .szenen-bildkachel {\n aspect-ratio: 3 / 4;\n}\n\n/* Ein einzelnes Ergebnisbild im echten Format zeigen \u2014 wie das Gemini-Preview:\n zentriert, ganz sichtbar, nichts abgeschnitten (vorher 3:4 mit cover). */\n.szenen-bildgalerie--einzeln .szenen-bildkachel {\n aspect-ratio: auto;\n background: none;\n}\n\n.szenen-bildgalerie--einzeln .szenen-bildkachel:not(:has(img)) {\n aspect-ratio: 4 / 3;\n}\n\n.szenen-bildgalerie--einzeln .szenen-bildkachel img {\n width: auto;\n max-width: 100%;\n height: auto;\n max-height: 28rem;\n margin-inline: auto;\n object-fit: contain;\n border: 1px solid var(--color-border-hover);\n border-radius: var(--radius-md);\n}\n\n.szenen-bildgalerie__alle-text {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.1rem;\n color: #fff;\n background: rgba(0, 0, 0, 0.65);\n font-size: 0.75rem;\n}\n\n.szenen-bildgalerie__alle-text strong {\n font-size: 1.25rem;\n}\n\n/* P5-Akzeptanz: Eine leere Kachel nennt ihren Grund \u2014 lesbar, nicht nur im\n Tooltip. */\n.szenen-bildkachel__grund {\n display: -webkit-box;\n max-width: 90%;\n overflow: hidden;\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n line-height: 1.3;\n text-align: center;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n}\n\n/* \u2500\u2500 Karten: Prompt, Tags \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-lauf__karte {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-lauf__kartenkopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-lauf__label {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-lauf__legende {\n color: var(--color-text-tertiary, var(--color-text-secondary));\n font-size: 0.72rem;\n}\n\n.szenen-lauf__kopieren {\n display: inline-flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-lauf__prompttext {\n margin: 0;\n color: var(--color-text-primary);\n line-height: 1.5;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n/* Drei Zeilen Vorschau \u2014 der volle Text bleibt im Dokument (Kopieren,\n Markieren), gek\xFCrzt wird nur die Darstellung. */\n.szenen-lauf__prompttext--zu {\n display: -webkit-box;\n overflow: hidden;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n}\n\n.szenen-view .szenen-lauf__ganz {\n justify-self: start;\n min-height: 2.25rem;\n padding: 0;\n color: var(--color-accent-teal, var(--color-text-primary));\n background: transparent;\n border: none;\n}\n\n.szenen-lauf__negativ {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-lauf__negativ[hidden] {\n display: none;\n}\n\n.szenen-lauf__negativ p {\n margin: 0;\n color: var(--color-text-secondary);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n.szenen-lauf__karte .szenen-taggeber {\n margin: 0;\n}\n\n.szenen-tagliste .szenen-tag__neu {\n min-height: 2rem;\n}\n\n/* \u2500\u2500 \u201ENeue Bilder" (Serverauftrag des Hosts) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-neuebilder {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg, var(--radius-md));\n}\n\n.szenen-neuebilder__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-neuebilder__kopf h4 {\n margin: 0;\n color: var(--color-text-primary);\n font-size: 1.05rem;\n}\n\n.szenen-neuebilder__symbol {\n color: var(--color-accent-teal, #2dd4bf);\n}\n\n.szenen-neuebilder__weg {\n margin-left: auto;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-neuebilder__felder {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-sm);\n}\n\n.szenen-wahlfeld {\n display: grid;\n gap: 0.15rem;\n min-width: 0;\n padding: 0.4rem 0.6rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-wahlfeld__label {\n color: var(--color-text-secondary);\n font-size: 0.68rem;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n\n.szenen-view .szenen-wahlfeld select {\n min-height: 1.75rem;\n padding: 0;\n color: var(--color-text-primary);\n background: transparent;\n border: none;\n font-weight: 600;\n}\n\n.szenen-umschalter {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n padding: 3px;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-view .szenen-umschalter button {\n min-height: 2.5rem;\n background: transparent;\n border: none;\n}\n\n.szenen-view .szenen-umschalter button[aria-pressed="true"] {\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n font-weight: 600;\n}\n\n.szenen-view .szenen-neuebilder__start {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--space-sm);\n min-height: 3.25rem;\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border: none;\n border-radius: var(--radius-md);\n font-size: 1rem;\n font-weight: 700;\n}\n\n.szenen-view .szenen-neuebilder__start:hover:not(:disabled) {\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n opacity: 0.9;\n}\n\n.szenen-neuebilder__laedt,\n.szenen-neuebilder__fehler {\n margin: 0;\n font-size: 0.85rem;\n}\n\n.szenen-neuebilder__laedt { color: var(--color-text-secondary); }\n\n/* Referenzbild eines Laufs (#569-Folge): eigener Bereich \xFCber den Ergebnissen. */\n.szenen-bilder__referenz {\n display: flex;\n gap: var(--space-md);\n align-items: center;\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent-blue);\n border-radius: var(--radius-md);\n}\n\n.szenen-bilder__referenzbild {\n flex: none;\n width: 9rem;\n}\n\n.szenen-bilder__referenzbild img {\n display: block;\n width: 100%;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__referenzleer {\n display: grid;\n place-items: center;\n aspect-ratio: 4 / 3;\n color: var(--color-text-secondary);\n background: var(--color-bg-elevated);\n border-radius: var(--radius-sm);\n font-size: 0.8rem;\n}\n\n.szenen-bilder__referenztext {\n display: grid;\n gap: 0.2rem;\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.82rem;\n}\n\n.szenen-bilder__referenztext strong {\n color: var(--color-text-primary);\n}\n\n/* Referenzbild und Prompt am einzelnen Bildauftrag. */\n.szenen-zeitleiste__referenz {\n display: flex;\n gap: var(--space-sm);\n align-items: center;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-zeitleiste__referenz img,\n.szenen-zeitleiste__referenz-leer {\n display: block;\n width: 4.5rem;\n aspect-ratio: 4 / 3;\n object-fit: cover;\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-zeitleiste__prompt {\n white-space: pre-wrap;\n user-select: text;\n}\n\n/* Das mitgegebene Kamera-Preview (#569-Folge) \u2014 sichtbar, bevor bestellt wird. */\n.szenen-neuebilder__referenz {\n margin: 0;\n padding: 0.35rem 0.6rem;\n color: var(--color-text-primary);\n background: var(--color-accent-blue-dim);\n border-left: 2px solid var(--color-accent-blue);\n border-radius: var(--radius-sm);\n font-size: 0.82rem;\n}\n.szenen-neuebilder__fehler { color: var(--color-danger); }\n\n.szenen-neuebilder__warnung > summary {\n display: flex;\n align-items: flex-start;\n gap: var(--space-sm);\n color: var(--color-warning);\n font-size: 0.85rem;\n line-height: 1.45;\n cursor: pointer;\n list-style: none;\n}\n\n.szenen-neuebilder__warnung > summary::-webkit-details-marker { display: none; }\n\n.szenen-neuebilder__warnung > p,\n.szenen-neuebilder__zuordnung ul {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n line-height: 1.5;\n}\n\n.szenen-neuebilder__zuordnung > summary {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n cursor: pointer;\n}\n\n.szenen-neuebilder__zuordnung ul {\n padding-left: 1.1rem;\n}\n\n/* \u2500\u2500 Aufklapper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-aufklapper {\n display: grid;\n min-width: 0;\n border-bottom: 1px solid var(--color-border);\n}\n\n.szenen-aufklapper__eintrag,\n.szenen-aufklapper .szenen-bilder__aktion {\n min-width: 0;\n padding: 0;\n border: none;\n border-top: 1px solid var(--color-border);\n border-radius: 0;\n}\n\n.szenen-aufklapper__eintrag > summary,\n.szenen-aufklapper .szenen-bilder__aktion > summary {\n list-style: none;\n cursor: pointer;\n}\n\n.szenen-aufklapper__eintrag > summary::-webkit-details-marker { display: none; }\n\n.szenen-aufklapper .szenen-bilder__aktion[open] > summary {\n margin-bottom: 0;\n}\n\n.szenen-aufklapper__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n min-height: 2.75rem;\n padding: 0 var(--space-xs);\n color: var(--color-text-primary);\n font-weight: 400;\n}\n\n.szenen-aufklapper__pfeil {\n flex: none;\n transition: transform 0.15s ease;\n}\n\ndetails[open] > summary .szenen-aufklapper__pfeil {\n transform: rotate(90deg);\n}\n\n.szenen-aufklapper__titel {\n min-width: 0;\n}\n\n.szenen-aufklapper__meta {\n margin-left: auto;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-aufklapper__inhalt {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n padding: 0 var(--space-xs) var(--space-md) 2rem;\n}\n\n@media (max-width: 760px) {\n .szenen-aufklapper__inhalt {\n padding-left: var(--space-xs);\n }\n}\n\n.szenen-aufklapper__inhalt > p {\n margin: 0;\n}\n\n/* \u2500\u2500 Zeitleiste der Bildauftr\xE4ge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-zeitleiste {\n display: grid;\n gap: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-zeitleiste__schritt {\n position: relative;\n display: flex;\n gap: var(--space-sm);\n min-width: 0;\n padding-bottom: var(--space-md);\n}\n\n/* Die Linie zur n\xE4chsten Zeile. */\n.szenen-zeitleiste__schritt:not(:last-child)::before {\n content: "";\n position: absolute;\n top: 2.1rem;\n bottom: 0;\n left: calc(1rem - 1px);\n width: 2px;\n background: var(--color-border);\n}\n\n.szenen-zeitleiste__symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n border: 1px solid var(--color-border);\n border-radius: 50%;\n background: var(--color-bg-elevated);\n color: var(--color-text-secondary);\n font-weight: 700;\n}\n\n.szenen-zeitleiste__symbol[data-zustand="fertig"] {\n color: var(--color-success);\n border-color: var(--color-success);\n background: var(--color-accent-green-dim, var(--color-bg-elevated));\n}\n\n.szenen-zeitleiste__symbol[data-zustand="fehlgeschlagen"] {\n color: var(--color-danger);\n border-color: var(--color-danger);\n background: var(--color-accent-red-dim, var(--color-bg-elevated));\n}\n\n.szenen-zeitleiste__symbol[data-zustand="teilweise"] {\n color: var(--color-warning);\n border-color: var(--color-warning);\n}\n\n.szenen-zeitleiste__inhalt {\n display: grid;\n gap: 0.15rem;\n min-width: 0;\n padding-top: 0.3rem;\n}\n\n.szenen-zeitleiste__titel {\n color: var(--color-text-primary);\n font-size: 0.9rem;\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n\n.szenen-zeitleiste__ergebnis,\n.szenen-zeitleiste__zusatz {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-zeitleiste__ergebnis[data-zustand="fehlgeschlagen"] { color: var(--color-danger); }\n.szenen-zeitleiste__ergebnis[data-zustand="teilweise"] { color: var(--color-warning); }\n\n.szenen-zeitleiste__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n margin-top: var(--space-xs);\n}\n\n.szenen-zeitleiste__meldung > summary {\n min-height: 2rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n line-height: 2rem;\n cursor: pointer;\n}\n\n.szenen-zeitleiste__meldung p {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-zeitleiste__meldung code {\n display: block;\n margin-top: var(--space-xs);\n color: var(--color-text-tertiary, var(--color-text-secondary));\n font-family: var(--font-mono);\n font-size: 0.72rem;\n overflow-wrap: anywhere;\n}\n\n/* \u2500\u2500 Annahmen \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.szenen-annahmen {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-annahmen__zeile {\n display: flex;\n gap: var(--space-sm);\n min-width: 0;\n}\n\n.szenen-annahmen__symbol {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border-radius: 50%;\n}\n\n.szenen-annahmen__text {\n display: grid;\n gap: 0.1rem;\n min-width: 0;\n font-size: 0.85rem;\n line-height: 1.45;\n overflow-wrap: anywhere;\n}\n\n.szenen-annahmen__art {\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n\n.szenen-annahmen__text details > summary,\n.szenen-lauf__erlaeuterung > summary {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n cursor: pointer;\n}\n\n.szenen-annahmen__text details p,\n.szenen-lauf__erlaeuterung p {\n margin: var(--space-xs) 0 0;\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n line-height: 1.5;\n white-space: pre-wrap;\n}\n\n.szenen-lauf__handeingabe h5 {\n margin: 0 0 var(--space-xs);\n}\n\n.szenen-lauf__handeingabe p {\n margin: 0;\n font-size: 0.85rem;\n}\n\n/* Kette `szenen-design`, P7 (#533) \u2014 die Szene aus Bausteinen. Felder als\n Karten, Bausteine im Feld als Chips; die Leiste ist das vorhandene\n Bottom-Sheet mit Bildkacheln. Bedient wird durch Antippen, nicht Ziehen. */\n.szenen-bausteinfelder {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n.szenen-bausteinfelder__liste {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bausteinfeld {\n display: grid;\n align-content: start;\n gap: var(--space-xs);\n min-width: 0;\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-bausteinfeld__kopf {\n display: flex;\n align-items: center;\n gap: 0.4rem;\n}\n\n.szenen-bausteinfeld__leer,\n.szenen-bausteinfeld__gesperrt {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-bausteinfeld__refs {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bausteinchip {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-view .szenen-bausteinchip__name {\n min-height: 2.25rem;\n max-width: 100%;\n padding: 0 0.75rem;\n overflow: hidden;\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.85rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-bausteinchip__aktionen {\n display: inline-flex;\n gap: var(--space-xs);\n}\n\n.szenen-view .szenen-bausteinchip__aktionen button {\n min-width: 2.25rem;\n min-height: 2.25rem;\n padding: 0 0.6rem;\n border-radius: var(--radius-full);\n}\n\n.szenen-view .szenen-bausteinfeld__plus {\n display: inline-flex;\n align-items: center;\n justify-self: start;\n gap: 0.35rem;\n min-height: 2.25rem;\n padding: 0 0.75rem;\n background: transparent;\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-full);\n}\n\n.szenen-bausteinfelder__weitere {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-bausteinfelder__weitere h5 {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n font-weight: 500;\n}\n\n.szenen-bausteinfelder__weitere ul {\n display: grid;\n gap: 0.25rem;\n margin: 0;\n padding: 0;\n list-style: none;\n font-size: 0.85rem;\n}\n\n.szenen-bausteinfelder__ort {\n color: var(--color-text-secondary);\n}\n\n.szenen-view .szenen-bausteinleiste__suche {\n min-height: 2.75rem;\n width: 100%;\n box-sizing: border-box;\n}\n\n.szenen-bausteinleiste {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-view .szenen-bausteinkachel {\n display: grid;\n gap: 0.25rem;\n width: 100%;\n padding: 0;\n overflow: hidden;\n text-align: left;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-view .szenen-bausteinkachel[aria-pressed="true"] {\n border-color: var(--color-text-primary);\n}\n\n.szenen-view .szenen-bausteinkachel:disabled {\n cursor: default;\n opacity: 0.7;\n}\n\n.szenen-bausteinkachel__name {\n display: flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0 0.4rem;\n overflow: hidden;\n font-size: 0.8rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-bausteinkachel__status,\n.szenen-bausteinkachel__grund {\n padding: 0 0.4rem 0.4rem;\n color: var(--color-text-secondary);\n font-size: 0.7rem;\n line-height: 1.25;\n overflow-wrap: anywhere;\n}\n\n@media (min-width: 761px) {\n .szenen-bausteinleiste {\n grid-template-columns: repeat(4, minmax(0, 1fr));\n }\n}\n/* MCP_STAGE_START: shared stage styles embedded in the gateway resource. */\n/* Issue #569: mobile stage controls and exact camera letterbox. */\n/* 3D-B\xFChne (#569): Ansicht zuerst, Werte als Karten darunter. */\n.szenen-3d {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-3d__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-3d__kopf h4 {\n margin: 0 auto 0 0;\n}\n\n/* Als Ansicht \u201E3D\u201C der Komposition: kein zweiter Rahmen im Abschnitt. */\n.szenen-3d--eingebettet {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-3d__kopf {\n flex-wrap: wrap;\n}\n\n.szenen-3d .szenen-3d__aufbau {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n min-width: 0;\n margin-right: auto;\n}\n\n.szenen-3d .szenen-3d__aufbau select {\n width: auto;\n min-width: 0;\n max-width: 100%;\n}\n\n.szenen-3d__stand {\n min-width: 0;\n margin-right: auto;\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-3d__sync {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-3d__sync::before {\n width: 0.5rem;\n height: 0.5rem;\n background: var(--color-success);\n border-radius: var(--radius-full);\n content: "";\n}\n\n.szenen-3d__sync[data-state="speichert"]::before {\n background: var(--color-warning);\n}\n\n.szenen-3d__sync[data-state="ansicht"]::before {\n background: var(--color-accent-blue);\n}\n\n.szenen-3d__meldung,\n.szenen-3d__fehler {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-elevated);\n border-left: 3px solid var(--color-accent-blue);\n border-radius: var(--radius-sm);\n}\n\n.szenen-3d__fehler {\n border-left-color: var(--color-danger);\n}\n\n.szenen-3d__oeffnen {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-3d label {\n display: grid;\n gap: 0.3rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-3d__leiste {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-3d__katalog {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.35rem;\n}\n\n.szenen-3d__katalog > span {\n margin-right: 0.15rem;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-view .szenen-3d__katalog button,\n.szenen-view .szenen-3d__elemente button {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n min-height: 2rem;\n padding: 0 0.7rem;\n border-radius: var(--radius-full);\n font-size: 0.85rem;\n}\n\n.szenen-3d__katalog i,\n.szenen-3d__elemente i {\n flex: none;\n width: 0.6rem;\n height: 0.6rem;\n border-radius: 2px;\n}\n\n.szenen-view .szenen-3d__elemente button[aria-pressed="true"] {\n color: var(--color-text-primary);\n background: var(--color-bg-surface-hover);\n border-color: var(--color-text-primary);\n}\n\n/* Viewport: feste H\xF6he f\xFCr Drauf- und Seitenansicht; die Kameraansicht wird\n * darin auf das gespeicherte Kameraformat eingepasst (Letterbox). */\n.szenen-3d__viewport {\n position: relative;\n display: grid;\n place-items: center;\n /* Dieselbe Gr\xF6\xDFe wie die 2D-B\xFChne (`.szenen-buehne`): Beim Wechsel springt nichts. */\n width: 100%;\n aspect-ratio: 358 / 330;\n overflow: hidden;\n background: #0d0f12;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n container-type: size;\n outline: none;\n}\n\n.szenen-3d__viewport--laden {\n background:\n linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px) 0 0 / 32px 32px,\n linear-gradient(90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px) 0 0 / 32px 32px,\n #0d0f12;\n}\n\n.szenen-3d__geruest {\n display: contents;\n}\n\n.szenen-3d__geruest button {\n pointer-events: none;\n}\n\n.szenen-3d__viewport:focus-visible {\n border-color: var(--color-accent-blue);\n box-shadow: 0 0 0 1px var(--color-accent-blue);\n}\n\n.szenen-3d__surface {\n position: relative;\n width: 100%;\n height: 100%;\n touch-action: none;\n user-select: none;\n -webkit-user-select: none;\n}\n\n.szenen-3d__viewport[data-view="camera"] {\n background: #050607;\n}\n\n.szenen-3d__viewport[data-view="camera"] .szenen-3d__surface {\n width: min(100cqw, calc(100cqh * var(--seitenverhaeltnis)));\n height: min(100cqh, calc(100cqw / var(--seitenverhaeltnis)));\n}\n\n.szenen-3d__hud {\n position: absolute;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n color: #d4d4d4;\n font-size: 0.78rem;\n font-variant-numeric: tabular-nums;\n pointer-events: none;\n}\n\n.szenen-3d__hud--werkzeuge {\n top: 0.6rem;\n right: 0.6rem;\n gap: 0.25rem;\n pointer-events: auto;\n}\n\n.szenen-view .szenen-3d__hud--werkzeuge button {\n min-width: 2rem;\n min-height: 2rem;\n padding: 0 0.6rem;\n color: #e5e5e5;\n background: rgba(23, 23, 23, 0.85);\n border-color: rgba(255, 255, 255, 0.12);\n backdrop-filter: blur(4px);\n}\n\n.szenen-3d__hud--kamera {\n top: 0.6rem;\n left: 0.6rem;\n padding: 0.2rem 0.55rem;\n background: rgba(0, 0, 0, 0.65);\n border-radius: var(--radius-full);\n}\n\n.szenen-3d__hud--info {\n bottom: 0.6rem;\n left: 0.6rem;\n max-width: calc(100% - 7rem);\n padding: 0.25rem 0.6rem;\n background: rgba(0, 0, 0, 0.6);\n border-radius: var(--radius-full);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.szenen-3d__hud--info strong {\n color: #ffffff;\n font-weight: 600;\n}\n\n.szenen-3d__hud i {\n font-style: normal;\n font-weight: 700;\n}\n\n.szenen-3d__hud--achsen {\n right: 0.75rem;\n bottom: 0.7rem;\n gap: 0.6rem;\n font-weight: 700;\n}\n\n.szenen-3d__labels {\n position: absolute;\n inset: 0;\n overflow: hidden;\n pointer-events: none;\n}\n\n.szenen-3d__label {\n position: absolute;\n padding: 0.05rem 0.4rem;\n color: #f5f5f5;\n background: rgba(10, 10, 10, 0.72);\n border-left: 2px solid var(--farbe, #9bafbc);\n border-radius: 3px;\n font: 500 0.72rem/1.4 var(--font-sans);\n white-space: nowrap;\n transform: translate(-50%, 6px);\n}\n\n.szenen-3d__label--side {\n transform: translate(-50%, calc(-100% - 6px));\n}\n\n.szenen-3d__label--kamera {\n color: #bfdbfe;\n border-left-color: #60a5fa;\n transform: translate(14px, -50%);\n}\n\n.szenen-3d__label--kamera.is-links {\n transform: translate(calc(-100% - 14px), -50%);\n}\n\n.szenen-3d__label.is-selected {\n color: #000000;\n background: #ffffff;\n}\n\n.szenen-3d__inspektor {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));\n gap: var(--space-sm);\n}\n\n.szenen-3d__karte {\n display: grid;\n align-content: start;\n gap: var(--space-sm);\n min-width: 0;\n padding: var(--space-sm) var(--space-md) var(--space-md);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-3d__karte h5 {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.72rem;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n.szenen-3d__elemente {\n display: flex;\n flex-wrap: wrap;\n gap: 0.35rem;\n}\n\n.szenen-3d__werte {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 0.4rem;\n margin: 0;\n padding: 0;\n border: none;\n}\n\n.szenen-3d__werte legend {\n margin-bottom: 0.4rem;\n padding: 0;\n color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-3d__werte legend span {\n margin-left: 0.35rem;\n color: var(--color-text-secondary);\n font-size: 0.78rem;\n font-weight: 400;\n}\n\n.szenen-3d__zeilenkopf {\n grid-column: 1 / -1;\n margin-top: 0.2rem;\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-3d__werte > button {\n grid-column: 1 / -1;\n}\n\n/* Markerfarbe eines Proxys (#587): W\xE4hler, Hexfeld und R\xFCcksetzen in einer\n Zeile; auf schmalem Touch-Viewport bricht sie um, ohne Controls zu verdecken. */\n.szenen-3d__farbe {\n grid-column: 1 / -1;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.4rem;\n}\n\n.szenen-view .szenen-3d__farbe input[type="color"] {\n flex: 0 0 auto;\n width: 2.75rem;\n min-height: 2.75rem;\n padding: 0.15rem;\n cursor: pointer;\n}\n\n.szenen-view .szenen-3d__farbe input[type="text"] {\n flex: 1 1 6.5rem;\n min-width: 6.5rem;\n min-height: 2.75rem;\n font-family: var(--font-mono, monospace);\n text-transform: lowercase;\n}\n\n.szenen-view .szenen-3d__farbe button {\n flex: 0 0 auto;\n min-height: 2.75rem;\n}\n\n.szenen-3d__entfernen {\n grid-column: 1 / -1;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.4rem;\n}\n\n.szenen-3d__entfernen > span {\n flex: 1 1 100%;\n color: var(--color-text-primary);\n font-size: 0.85rem;\n}\n\n.szenen-view .szenen-3d__entfernen button {\n min-height: 2.75rem;\n}\n\n.szenen-view .szenen-3d__gefahr {\n color: #fff;\n background: var(--color-danger);\n border-color: var(--color-danger);\n}\n\n.szenen-3d__farbe-auto {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-3d__farbe-hinweis {\n grid-column: 1 / -1;\n margin: 0;\n color: var(--color-warning, #eab308);\n font-size: 0.78rem;\n}\n\n.szenen-3d .szenen-3d__feld {\n position: relative;\n display: block;\n}\n\n.szenen-3d__achse {\n position: absolute;\n top: 50%;\n left: 0.55rem;\n font-size: 0.72rem;\n font-weight: 700;\n transform: translateY(-50%);\n pointer-events: none;\n}\n\n.szenen-3d__achse--x { color: #f87171; }\n.szenen-3d__achse--y { color: #4ade80; }\n.szenen-3d__achse--z { color: #60a5fa; }\n\n.szenen-view .szenen-3d__feld input {\n padding-left: 1.6rem;\n font-variant-numeric: tabular-nums;\n}\n\n.szenen-3d__hinweis {\n margin: 0;\n color: var(--color-text-secondary);\n font-size: 0.82rem;\n}\n\n.szenen-3d__abschluss {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-view .szenen-3d__primaer {\n min-height: 2.75rem;\n color: var(--color-bg-app);\n background: var(--color-text-primary);\n border-color: var(--color-text-primary);\n font-weight: 600;\n}\n\n.szenen-view .szenen-3d__primaer:hover:not(:disabled) {\n color: var(--color-bg-app);\n background: var(--color-primary-hover);\n}\n\n.szenen-view .szenen-3d__nebenaktion {\n justify-self: start;\n min-height: 2rem;\n padding: 0;\n background: none;\n border: none;\n font-size: 0.82rem;\n text-decoration: underline;\n}\n\n/* Hinweise passend zum Eingabeger\xE4t; ohne Angabe gilt die Maus-Variante. */\n.szenen-3d__nur-touch {\n display: none;\n}\n\n@media (hover: none) and (pointer: coarse) {\n .szenen-3d__nur-maus {\n display: none;\n }\n\n .szenen-3d__nur-touch {\n display: inline;\n }\n\n /* Fingergerechte Ziele (44 px) f\xFCr Ansichtssteuerung, Katalog und Elemente. */\n .szenen-view .szenen-3d__hud--werkzeuge button,\n .szenen-view .szenen-3d__katalog button,\n .szenen-view .szenen-3d__elemente button,\n .szenen-view .szenen-3d .szenen-studio__umschalter button {\n min-width: 2.75rem;\n min-height: 2.75rem;\n }\n}\n\n@media (max-width: 760px) {\n .szenen-3d {\n gap: var(--space-sm);\n padding: var(--space-sm);\n }\n\n .szenen-3d__leiste {\n display: grid;\n }\n\n .szenen-3d .szenen-studio__umschalter {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n }\n\n /* Katalog als eine Zeile, die in sich scrollt, statt die Ansicht nach unten zu schieben. */\n .szenen-3d__katalog {\n flex-wrap: nowrap;\n min-width: 0;\n overflow-x: auto;\n scrollbar-width: none;\n }\n\n .szenen-3d__katalog > * {\n flex: none;\n }\n\n .szenen-3d__viewport {\n aspect-ratio: 358 / 330;\n margin: 0 calc(-1 * var(--space-sm));\n border-right: none;\n border-left: none;\n border-radius: 0;\n }\n\n .szenen-3d__hud--info {\n max-width: calc(100% - 1.2rem);\n bottom: 2.4rem;\n }\n\n .szenen-3d__hud--achsen {\n bottom: 0.8rem;\n left: 0.75rem;\n right: auto;\n }\n}\n\n/* One DOM canvas, no nested React renderer. */\n.szenen-3d__canvas { display: block; width: 100%; height: 100%; }\n\n/* Prompt choices before the 3D run; mobile buttons wrap within each category. */\n.szenen-3d__prompt details { margin-block: .65rem; }\n.szenen-3d__prompt summary { cursor: pointer; font-weight: 600; }\n.szenen-3d__prompt fieldset { border: 0; padding: .6rem 0; min-width: 0; }\n.szenen-3d__prompt legend { color: var(--color-text-secondary); font-size: .85rem; }\n.szenen-3d__prompt textarea { min-height: 6rem; width: 100%; box-sizing: border-box; }\n.szenen-3d__referenz { white-space: pre-wrap; overflow-wrap: anywhere; font-size: .9rem; }\n\n/* Das Preview in seinem echten Format (z. B. 4:3) \u2014 keine F\xFCllfl\xE4che in Hintergrundfarbe, die ein Querformat vort\xE4uscht. */\n.szenen-3d__gemini img { display: block; width: auto; max-width: 100%; height: auto; max-height: 28rem; margin-inline: auto; border: 1px solid var(--color-border-hover); border-radius: .4rem; }\n.szenen-3d__gemini pre { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 32rem; overflow: auto; font-size: .8rem; }\n.szenen-3d__gemini ul { list-style: none; padding: 0; }\n.szenen-3d__gemini li { margin-block: .6rem; overflow-wrap: anywhere; }\n.szenen-3d__gemini li i { display: inline-block; width: .9rem; height: .9rem; margin-right: .4rem; border-radius: .15rem; }\n\n/* Desktop: 2D- und 3D-B\xFChne auf 60 % der Breite, gleich gro\xDF und zentriert.\n Unter 761 px bleibt die volle Breite (Touch, schmale Spalte). Steht am\n Dateiende, damit es die Grundregeln beider B\xFChnen \xFCberschreibt. */\n@media (min-width: 761px) {\n .szenen-buehne,\n .szenen-3d__viewport {\n width: 60%;\n justify-self: center;\n margin-inline: auto;\n }\n}\n\n/* One mobile object sheet and a separate ring gesture on the selected object. */\n.szenen-3d__drehring { position:absolute; overflow:visible; pointer-events:none; z-index:12; }\n.szenen-3d__drehring circle { pointer-events:stroke; cursor:grab; touch-action:none; }\n.szenen-3d__drehring circle:focus-visible { stroke:#ffffff; outline:none; }\n.szenen-3d__blatt-schliessen { display:none; }\n.szenen-3d__objekt-aktionen, .szenen-3d__pose { display:flex; flex-wrap:wrap; gap:.4rem; grid-column:1/-1; }\n.szenen-3d__morph { display:flex; align-items:center; gap:.6rem; grid-column:1/-1; }\n.szenen-3d__morph input { flex:1; min-width:0; min-height:44px; }\n.szenen-3d__pose button[aria-pressed="true"] { border-color:var(--color-accent-blue); }\n@media (max-width:760px) {\n .szenen-3d__objektblatt { position:fixed; left:0; right:0; bottom:0; z-index:50; max-height:42dvh; overflow:auto; overscroll-behavior:contain; background:var(--color-bg-secondary,#15171b); border:1px solid var(--color-border); border-radius:18px 18px 0 0; padding:.7rem 1rem calc(.8rem + env(safe-area-inset-bottom)); box-shadow:0 -8px 30px #0008; }\n .szenen-3d__blatt-schliessen { display:block; margin-left:auto; min-height:44px; }\n .szenen-3d__objektblatt button, .szenen-3d__objektblatt input, .szenen-3d__objektblatt select { min-height:44px; }\n}\n\n.szenen-3d__werte { min-width:0; }\n.szenen-3d__objektblatt input, .szenen-3d__objektblatt select { min-width:0; max-width:100%; }\n\n@media (max-width:760px) { .szenen-3d__objektblatt { width:100vw; max-width:100vw; box-sizing:border-box; } }\n\n.szenen-3d__karte, .szenen-3d__abschluss { grid-template-columns:minmax(0,1fr); }\n\n\n.szenen-3d { overflow-x:clip; }\n\n/* Display options (walls, fullscreen) and the fullscreen stage (#582 follow-up).\n Fullscreen: the stage frame covers the screen; sheets lie over the 3D view. */\n.szenen-3d__ansichtsoptionen { display:flex; flex-wrap:wrap; gap:.4rem; }\n.szenen-view .szenen-3d__ansichtsoptionen button[aria-pressed="true"] { border-color:var(--color-accent-blue); }\n.szenen-3d__buehne { display:grid; gap:var(--space-sm); min-width:0; }\n.szenen-3d__buehne.is-vollbild { position:fixed; inset:0; z-index:1000; display:flex; flex-direction:column; gap:0; background:#0d0f12;\n padding:env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left); }\n/* Two rows, both always visible: the four views, then walls/camera/exit. */\n.szenen-3d__buehne.is-vollbild .szenen-3d__leiste { display:grid; flex:none; gap:.35rem; padding:.4rem; }\n.szenen-3d__buehne.is-vollbild .szenen-studio__umschalter { display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); }\n.szenen-3d__buehne.is-vollbild .szenen-studio__umschalter button { min-width:0; padding-inline:.3rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n.szenen-3d__buehne.is-vollbild .szenen-3d__ansichtsoptionen { display:grid; grid-auto-flow:column; grid-auto-columns:minmax(0,1fr); }\n.szenen-3d__buehne.is-vollbild .szenen-3d__katalog { display:none; }\n.szenen-3d__buehne.is-vollbild .szenen-3d__viewport { flex:1; min-height:0; width:100%; aspect-ratio:auto; margin:0; border:0; border-radius:0; }\n.szenen-3d__buehne.is-vollbild .szenen-3d__objektblatt { position:absolute; left:0; right:0; bottom:0; z-index:20; width:auto; max-width:none; max-height:45%;\n overflow:auto; overscroll-behavior:contain; box-sizing:border-box; background:var(--color-bg-secondary,#15171b); border:1px solid var(--color-border);\n border-radius:18px 18px 0 0; padding:.7rem 1rem calc(.8rem + env(safe-area-inset-bottom)); box-shadow:0 -8px 30px #0008; }\n.szenen-3d__buehne.is-vollbild .szenen-3d__blatt-schliessen { display:block; margin-left:auto; min-height:44px; }\n.szenen-3d__buehne.is-vollbild .szenen-3d__objektblatt button,\n.szenen-3d__buehne.is-vollbild .szenen-3d__objektblatt input,\n.szenen-3d__buehne.is-vollbild .szenen-3d__objektblatt select { min-height:44px; }\n.szenen-3d__kamerablatt label { display:grid; gap:.25rem; grid-column:1/-1; }\n@media (min-width:761px) {\n .szenen-3d__buehne.is-vollbild .szenen-3d__objektblatt { left:auto; top:0; width:min(26rem,40%); max-height:none; border-radius:18px 0 0 18px; }\n}\n\n/* Visibility list and sheet switch (editor display only, never saved).\n "Objektblatt" only matters where the sheet covers the stage: fullscreen and phone width. */\n.szenen-3d__sichtbar { position:relative; min-width:0; }\n.szenen-3d__sichtbar > summary { display:flex; align-items:center; justify-content:center; box-sizing:border-box; height:100%; min-height:2.25rem;\n padding:.45rem .75rem; color:var(--color-text-secondary); background:var(--color-bg-elevated); border:1px solid var(--color-border);\n border-radius:var(--radius-sm); cursor:pointer; list-style:none; text-align:center; }\n.szenen-3d__sichtbar > summary::-webkit-details-marker { display:none; }\n.szenen-3d__sichtbar[open] > summary { border-color:var(--color-accent-blue); color:var(--color-text-primary); }\n.szenen-3d__sichtbar-liste { position:absolute; top:calc(100% + .3rem); left:0; z-index:40; display:grid; gap:.1rem; width:max-content; min-width:14rem;\n max-width:min(22rem,calc(100vw - 1rem)); max-height:60vh; overflow:auto; overscroll-behavior:contain; box-sizing:border-box; padding:.4rem;\n background:var(--color-bg-secondary,#15171b); border:1px solid var(--color-border); border-radius:var(--radius-md); box-shadow:0 8px 30px #0008; }\n.szenen-3d__sichtbar-liste label { display:flex; align-items:center; gap:.5rem; min-height:44px; padding:0 .4rem; cursor:pointer; }\n.szenen-3d__sichtbar-liste input { width:1.15rem; height:1.15rem; margin:0; flex:none; }\n.szenen-3d__sichtbar-liste i { flex:none; width:.6rem; height:.6rem; border-radius:2px; }\n.szenen-3d__sichtbar-liste button { margin-top:.3rem; min-height:44px; }\n.szenen-3d__blatt-schalter { display:none; }\n.szenen-3d__buehne.is-vollbild .szenen-3d__blatt-schalter { display:block; }\n@media (max-width:760px) {\n .szenen-3d__blatt-schalter { display:block; }\n .szenen-3d__objektblatt.is-zu { display:none; }\n}\n\n/* MCP_STAGE_END */\n';
|
|
65
65
|
|
|
66
66
|
// src/lib/utils.ts
|
|
67
67
|
var getFormattedTimestamp = () => {
|
|
@@ -2416,7 +2416,7 @@ function useHFState(token, namespace) {
|
|
|
2416
2416
|
setForks(findForks(dag));
|
|
2417
2417
|
setEventCount(afterConsolidation.length);
|
|
2418
2418
|
if (afterConsolidation.length) setLastEventTs(Math.max(...afterConsolidation.map((e) => e.ts)));
|
|
2419
|
-
return
|
|
2419
|
+
return _chunkVSHSZEGVjs.applyEvents.call(void 0, snapshot, afterConsolidation);
|
|
2420
2420
|
}, []);
|
|
2421
2421
|
const loadFull = _react.useCallback.call(void 0, async () => {
|
|
2422
2422
|
if (!token || !namespace) return;
|
|
@@ -2424,14 +2424,14 @@ function useHFState(token, namespace) {
|
|
|
2424
2424
|
setError(null);
|
|
2425
2425
|
knownFilePaths.current = /* @__PURE__ */ new Set();
|
|
2426
2426
|
try {
|
|
2427
|
-
const snapshot = await
|
|
2427
|
+
const snapshot = await _chunkVSHSZEGVjs.loadHFState.call(void 0, namespace, token);
|
|
2428
2428
|
setHasStateZip(snapshot !== null);
|
|
2429
2429
|
const base = _nullishCoalesce(snapshot, () => ( {
|
|
2430
2430
|
metadata: [],
|
|
2431
2431
|
tags: { by_category: {}, all: [] },
|
|
2432
2432
|
meta: { consolidatedAt: 0, version: 1 }
|
|
2433
2433
|
}));
|
|
2434
|
-
const hfEvents = await
|
|
2434
|
+
const hfEvents = await _chunkVSHSZEGVjs.loadPendingEvents.call(void 0, namespace, token, base.meta.consolidatedAt, knownFilePaths.current);
|
|
2435
2435
|
const hfEventKeys = new Set(hfEvents.map((e) => `${e.ts}_${e.clientId}`));
|
|
2436
2436
|
const localOnlyEvents = allEventsRef.current.filter(
|
|
2437
2437
|
(e) => !hfEventKeys.has(`${e.ts}_${e.clientId}`)
|
|
@@ -2449,14 +2449,14 @@ function useHFState(token, namespace) {
|
|
|
2449
2449
|
const failed = [];
|
|
2450
2450
|
for (const evt of buffer) {
|
|
2451
2451
|
try {
|
|
2452
|
-
await
|
|
2452
|
+
await _chunkVSHSZEGVjs.writeHFEvent.call(void 0, namespace, token, evt.type, evt.payload, evt.prevTs);
|
|
2453
2453
|
} catch (e5) {
|
|
2454
2454
|
failed.push(evt);
|
|
2455
2455
|
}
|
|
2456
2456
|
}
|
|
2457
2457
|
writeOfflineBuffer(failed);
|
|
2458
2458
|
setPendingBufferCount(failed.length);
|
|
2459
|
-
const freshEvents = await
|
|
2459
|
+
const freshEvents = await _chunkVSHSZEGVjs.loadPendingEvents.call(void 0, namespace, token, base.meta.consolidatedAt, knownFilePaths.current);
|
|
2460
2460
|
freshEvents.forEach((e) => knownEventPaths.current.add(`${e.ts}_${e.clientId}`));
|
|
2461
2461
|
setState((prev) => prev ? applyNewEvents(base, freshEvents) : prev);
|
|
2462
2462
|
}
|
|
@@ -2469,7 +2469,7 @@ function useHFState(token, namespace) {
|
|
|
2469
2469
|
const pollNew = _react.useCallback.call(void 0, async () => {
|
|
2470
2470
|
if (!token || !namespace || !state) return;
|
|
2471
2471
|
try {
|
|
2472
|
-
const events = await
|
|
2472
|
+
const events = await _chunkVSHSZEGVjs.loadPendingEvents.call(void 0, namespace, token, state.meta.consolidatedAt, knownFilePaths.current);
|
|
2473
2473
|
const newEvents = events.filter((e) => !knownEventPaths.current.has(`${e.ts}_${e.clientId}`));
|
|
2474
2474
|
if (!newEvents.length) return;
|
|
2475
2475
|
newEvents.forEach((e) => knownEventPaths.current.add(`${e.ts}_${e.clientId}`));
|
|
@@ -2494,7 +2494,7 @@ function useHFState(token, namespace) {
|
|
|
2494
2494
|
await pollNew();
|
|
2495
2495
|
try {
|
|
2496
2496
|
console.log("[HF] writeHFEvent start, path will be:", `${namespace}events/...`);
|
|
2497
|
-
const event = await
|
|
2497
|
+
const event = await _chunkVSHSZEGVjs.writeHFEvent.call(void 0, namespace, token, type, payload, prevTs);
|
|
2498
2498
|
console.log("[HF] writeHFEvent success:", event.ts);
|
|
2499
2499
|
knownEventPaths.current.add(`${event.ts}_${event.clientId}`);
|
|
2500
2500
|
const confirmedKey = `${event.ts}_${event.clientId}`;
|
|
@@ -2511,7 +2511,7 @@ function useHFState(token, namespace) {
|
|
|
2511
2511
|
type,
|
|
2512
2512
|
ts: Date.now(),
|
|
2513
2513
|
prevTs,
|
|
2514
|
-
clientId:
|
|
2514
|
+
clientId: _chunkVSHSZEGVjs.getSessionClientId.call(void 0, ),
|
|
2515
2515
|
payload
|
|
2516
2516
|
};
|
|
2517
2517
|
writeOfflineBuffer([...buffer, offline]);
|
|
@@ -2544,11 +2544,11 @@ function useHFState(token, namespace) {
|
|
|
2544
2544
|
var _jszip = require('jszip'); var _jszip2 = _interopRequireDefault(_jszip);
|
|
2545
2545
|
var CURRENT_TAG_EVENT_VERSION = { major: 1, minor: 0 };
|
|
2546
2546
|
async function loadTagBase(namespace, token) {
|
|
2547
|
-
const files = await
|
|
2547
|
+
const files = await _chunkVSHSZEGVjs.hfListDir.call(void 0, namespace, "", token);
|
|
2548
2548
|
const tagBaseFiles = files.filter((f) => f.type === "file" && /^tags-state-[\dT\-]+Z\.zip$/.test(f.path.split("/").pop() || "")).sort((a, b) => b.path.localeCompare(a.path));
|
|
2549
2549
|
if (!tagBaseFiles.length) return null;
|
|
2550
2550
|
const newestPath = tagBaseFiles[0].path;
|
|
2551
|
-
const zipBytes = await
|
|
2551
|
+
const zipBytes = await _chunkVSHSZEGVjs.hfDownloadBinaryByPath.call(void 0, newestPath, token);
|
|
2552
2552
|
const zip = await _jszip2.default.loadAsync(zipBytes);
|
|
2553
2553
|
const [usersStr, contextsStr, tagsStr, metaStr] = await Promise.all([
|
|
2554
2554
|
_optionalChain([zip, 'access', _50 => _50.file, 'call', _51 => _51("users.json"), 'optionalAccess', _52 => _52.async, 'call', _53 => _53("string")]),
|
|
@@ -2573,14 +2573,14 @@ async function writeTagEvent(namespace, token, event) {
|
|
|
2573
2573
|
const uuid = crypto.randomUUID().slice(0, 8);
|
|
2574
2574
|
const filename = `${tsToFilename(event.ts)}_${uuid}.json`;
|
|
2575
2575
|
const repoPath = `${namespace}tag-events/${filename}`;
|
|
2576
|
-
await
|
|
2576
|
+
await _chunkVSHSZEGVjs.hfUploadSmallFile.call(void 0, repoPath, JSON.stringify(event, null, 2), token, `TagEvent: ${event.type}`);
|
|
2577
2577
|
}
|
|
2578
2578
|
function createTagCreatedEvent(baseVersion, userId, payload) {
|
|
2579
2579
|
return {
|
|
2580
2580
|
v: CURRENT_TAG_EVENT_VERSION,
|
|
2581
2581
|
type: "tag_created",
|
|
2582
2582
|
ts: Date.now(),
|
|
2583
|
-
clientId:
|
|
2583
|
+
clientId: _chunkVSHSZEGVjs.getSessionClientId.call(void 0, ),
|
|
2584
2584
|
baseVersion,
|
|
2585
2585
|
userId,
|
|
2586
2586
|
payload
|
|
@@ -2591,7 +2591,7 @@ function createTagUpdatedEvent(baseVersion, userId, id, delta) {
|
|
|
2591
2591
|
v: CURRENT_TAG_EVENT_VERSION,
|
|
2592
2592
|
type: "tag_updated",
|
|
2593
2593
|
ts: Date.now(),
|
|
2594
|
-
clientId:
|
|
2594
|
+
clientId: _chunkVSHSZEGVjs.getSessionClientId.call(void 0, ),
|
|
2595
2595
|
baseVersion,
|
|
2596
2596
|
userId,
|
|
2597
2597
|
payload: { id, delta }
|
|
@@ -5530,6 +5530,162 @@ function FlowWorkspacePicker({
|
|
|
5530
5530
|
] }) });
|
|
5531
5531
|
}
|
|
5532
5532
|
|
|
5533
|
+
// src/components/FlowBridgePanel.tsx
|
|
5534
|
+
|
|
5535
|
+
|
|
5536
|
+
// src/lib/flowBridgeClient.ts
|
|
5537
|
+
var FLOW_BRIDGE_REQUEST_EVENT = "fine-art-flow-bridge:request:v1";
|
|
5538
|
+
var FLOW_BRIDGE_RESPONSE_EVENT = "fine-art-flow-bridge:response:v1";
|
|
5539
|
+
var FLOW_BRIDGE_HELLO_TIMEOUT_MS = 1500;
|
|
5540
|
+
var FLOW_BRIDGE_REQUEST_TIMEOUT_MS = 15e3;
|
|
5541
|
+
function isRecord(value) {
|
|
5542
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5543
|
+
}
|
|
5544
|
+
function readError(value) {
|
|
5545
|
+
if (isRecord(value) && typeof value.code === "string" && typeof value.message === "string") {
|
|
5546
|
+
return { code: value.code, message: value.message };
|
|
5547
|
+
}
|
|
5548
|
+
return { code: "invalid-message", message: "Antwort der Flow-Bridge ohne gueltige Fehlerangabe." };
|
|
5549
|
+
}
|
|
5550
|
+
function noBridge(timeoutMs) {
|
|
5551
|
+
return {
|
|
5552
|
+
code: "no-bridge",
|
|
5553
|
+
message: `Keine Antwort der Flow-Bridge innerhalb von ${timeoutMs} ms \u2014 Extension nicht installiert, deaktiviert oder fuer diesen Frame nicht freigegeben.`
|
|
5554
|
+
};
|
|
5555
|
+
}
|
|
5556
|
+
var nullableNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
5557
|
+
var nextId = 0;
|
|
5558
|
+
function createFlowBridgeClient({
|
|
5559
|
+
target = document,
|
|
5560
|
+
appVersion,
|
|
5561
|
+
helloTimeoutMs = FLOW_BRIDGE_HELLO_TIMEOUT_MS,
|
|
5562
|
+
requestTimeoutMs = FLOW_BRIDGE_REQUEST_TIMEOUT_MS,
|
|
5563
|
+
clock = () => performance.now()
|
|
5564
|
+
} = {}) {
|
|
5565
|
+
function exchange(payload, timeoutMs) {
|
|
5566
|
+
nextId += 1;
|
|
5567
|
+
const id = `fb-${Date.now().toString(36)}-${nextId}`;
|
|
5568
|
+
return new Promise((resolve) => {
|
|
5569
|
+
const onResponse = (event) => {
|
|
5570
|
+
const detail = event.detail;
|
|
5571
|
+
if (typeof detail !== "string") return;
|
|
5572
|
+
let parsed;
|
|
5573
|
+
try {
|
|
5574
|
+
parsed = JSON.parse(detail);
|
|
5575
|
+
} catch (e20) {
|
|
5576
|
+
return;
|
|
5577
|
+
}
|
|
5578
|
+
if (!isRecord(parsed) || parsed.id !== id) return;
|
|
5579
|
+
cleanup();
|
|
5580
|
+
resolve(parsed);
|
|
5581
|
+
};
|
|
5582
|
+
const timer = setTimeout(() => {
|
|
5583
|
+
cleanup();
|
|
5584
|
+
resolve(null);
|
|
5585
|
+
}, timeoutMs);
|
|
5586
|
+
const cleanup = () => {
|
|
5587
|
+
clearTimeout(timer);
|
|
5588
|
+
target.removeEventListener(FLOW_BRIDGE_RESPONSE_EVENT, onResponse);
|
|
5589
|
+
};
|
|
5590
|
+
target.addEventListener(FLOW_BRIDGE_RESPONSE_EVENT, onResponse);
|
|
5591
|
+
target.dispatchEvent(new CustomEvent(FLOW_BRIDGE_REQUEST_EVENT, { detail: JSON.stringify({ id, ...payload }) }));
|
|
5592
|
+
});
|
|
5593
|
+
}
|
|
5594
|
+
return {
|
|
5595
|
+
async status() {
|
|
5596
|
+
const started = clock();
|
|
5597
|
+
const reply = await exchange({ op: "hello", app: "flowfa", ...appVersion ? { appVersion } : {} }, helloTimeoutMs);
|
|
5598
|
+
const roundTripMs = Math.round(clock() - started);
|
|
5599
|
+
if (!reply) return { available: false, error: noBridge(helloTimeoutMs), roundTripMs };
|
|
5600
|
+
if (reply.ok !== true) return { available: false, error: readError(reply.error), roundTripMs };
|
|
5601
|
+
const bridge = reply.bridge;
|
|
5602
|
+
if (!isRecord(bridge) || typeof bridge.name !== "string" || typeof bridge.version !== "string" || typeof bridge.protocol !== "number") {
|
|
5603
|
+
return { available: false, error: { code: "invalid-message", message: "Handshake-Antwort ohne Bridge-Kennung." }, roundTripMs };
|
|
5604
|
+
}
|
|
5605
|
+
return { available: true, name: bridge.name, version: bridge.version, protocol: bridge.protocol, roundTripMs };
|
|
5606
|
+
},
|
|
5607
|
+
async request(request) {
|
|
5608
|
+
const started = clock();
|
|
5609
|
+
const reply = await exchange({ op: "request", target: request.target, method: request.method, path: request.path }, requestTimeoutMs);
|
|
5610
|
+
const roundTripMs = Math.round(clock() - started);
|
|
5611
|
+
if (!reply) {
|
|
5612
|
+
return { ok: false, transport: null, status: null, data: null, latencyMs: null, roundTripMs, error: noBridge(requestTimeoutMs) };
|
|
5613
|
+
}
|
|
5614
|
+
const ok = reply.ok === true;
|
|
5615
|
+
return {
|
|
5616
|
+
ok,
|
|
5617
|
+
transport: typeof reply.transport === "string" ? reply.transport : null,
|
|
5618
|
+
status: nullableNumber(reply.status),
|
|
5619
|
+
data: ok ? _nullishCoalesce(reply.data, () => ( null)) : null,
|
|
5620
|
+
latencyMs: nullableNumber(reply.latencyMs),
|
|
5621
|
+
roundTripMs,
|
|
5622
|
+
error: ok ? null : readError(reply.error)
|
|
5623
|
+
};
|
|
5624
|
+
}
|
|
5625
|
+
};
|
|
5626
|
+
}
|
|
5627
|
+
|
|
5628
|
+
// src/components/FlowBridgePanel.tsx
|
|
5629
|
+
|
|
5630
|
+
var STATUS_REQUEST = { target: "dev", method: "GET", path: "/api/status" };
|
|
5631
|
+
var FlowBridgePanel = ({ appVersion, client }) => {
|
|
5632
|
+
const bridge = _react.useMemo.call(void 0, () => _nullishCoalesce(client, () => ( createFlowBridgeClient({ appVersion }))), [client, appVersion]);
|
|
5633
|
+
const [status, setStatus] = _react.useState.call(void 0, null);
|
|
5634
|
+
const [response, setResponse] = _react.useState.call(void 0, null);
|
|
5635
|
+
const [busy, setBusy] = _react.useState.call(void 0, null);
|
|
5636
|
+
const checkStatus = async () => {
|
|
5637
|
+
setBusy("status");
|
|
5638
|
+
try {
|
|
5639
|
+
setStatus(await bridge.status());
|
|
5640
|
+
} finally {
|
|
5641
|
+
setBusy(null);
|
|
5642
|
+
}
|
|
5643
|
+
};
|
|
5644
|
+
_react.useEffect.call(void 0, () => {
|
|
5645
|
+
let active = true;
|
|
5646
|
+
void bridge.status().then((result) => {
|
|
5647
|
+
if (active) setStatus(result);
|
|
5648
|
+
});
|
|
5649
|
+
return () => {
|
|
5650
|
+
active = false;
|
|
5651
|
+
};
|
|
5652
|
+
}, [bridge]);
|
|
5653
|
+
const runRequest = async () => {
|
|
5654
|
+
setBusy("request");
|
|
5655
|
+
setResponse(null);
|
|
5656
|
+
try {
|
|
5657
|
+
setResponse(await bridge.request(STATUS_REQUEST));
|
|
5658
|
+
} finally {
|
|
5659
|
+
setBusy(null);
|
|
5660
|
+
}
|
|
5661
|
+
};
|
|
5662
|
+
const buttonStyle = {
|
|
5663
|
+
height: 36,
|
|
5664
|
+
border: "1px solid rgba(255,255,255,0.12)",
|
|
5665
|
+
color: "rgba(255,255,255,0.7)",
|
|
5666
|
+
background: "rgba(255,255,255,0.04)"
|
|
5667
|
+
};
|
|
5668
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "details", { className: "w-full max-w-[280px] rounded-xl px-3 py-2", style: { border: "1px solid rgba(255,255,255,0.08)" }, children: [
|
|
5669
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "summary", { className: "text-white/40 text-[10px] uppercase tracking-widest font-bold cursor-pointer", children: "Flow-Bridge (Firefox)" }),
|
|
5670
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-2 mt-2 text-[10px] font-mono", children: [
|
|
5671
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-2 gap-2", children: [
|
|
5672
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", onClick: checkStatus, disabled: busy !== null, className: "rounded-lg text-[11px] font-bold disabled:opacity-40", style: buttonStyle, children: busy === "status" ? "Pr\xFCfe\u2026" : "Bridge pr\xFCfen" }),
|
|
5673
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", onClick: runRequest, disabled: busy !== null, className: "rounded-lg text-[11px] font-bold disabled:opacity-40", style: buttonStyle, children: busy === "request" ? "L\xE4uft\u2026" : "Dev /api/status" })
|
|
5674
|
+
] }),
|
|
5675
|
+
status && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { role: "status", "data-testid": "flow-bridge-status", style: { color: status.available ? "#4ade80" : "#f87171" }, children: status.available ? `Bridge: verbunden \xB7 ${status.name} v${status.version} \xB7 Protokoll ${status.protocol} \xB7 ${status.roundTripMs} ms` : `Bridge: nicht verbunden \xB7 ${status.error.code}: ${status.error.message}` }),
|
|
5676
|
+
response && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { "data-testid": "flow-bridge-response", className: "flex flex-col gap-1", children: [
|
|
5677
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { style: { color: response.ok ? "#4ade80" : "#f87171" }, children: [
|
|
5678
|
+
`${STATUS_REQUEST.method} ${STATUS_REQUEST.path} (${STATUS_REQUEST.target}) \u2192 `,
|
|
5679
|
+
response.status !== null ? `HTTP ${response.status}` : "kein HTTP-Status",
|
|
5680
|
+
response.ok ? "" : ` \xB7 ${_optionalChain([response, 'access', _154 => _154.error, 'optionalAccess', _155 => _155.code])}: ${_optionalChain([response, 'access', _156 => _156.error, 'optionalAccess', _157 => _157.message])}`
|
|
5681
|
+
] }),
|
|
5682
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-white/40", children: `Transport: ${_nullishCoalesce(response.transport, () => ( "keiner"))} \xB7 Server ${_nullishCoalesce(response.latencyMs, () => ( "\u2014"))} ms \xB7 gesamt ${response.roundTripMs} ms` }),
|
|
5683
|
+
response.ok && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "pre", { className: "text-white/60 whitespace-pre-wrap break-all bg-black/30 rounded-lg p-2", children: JSON.stringify(response.data, null, 2) })
|
|
5684
|
+
] })
|
|
5685
|
+
] })
|
|
5686
|
+
] });
|
|
5687
|
+
};
|
|
5688
|
+
|
|
5533
5689
|
// src/lib/flowBootstrapTarget.ts
|
|
5534
5690
|
var PROD_NAMESPACE = "app.art-by-rolands.de/";
|
|
5535
5691
|
var DEV_NAMESPACE = "dev-app.art-by-rolands.de/";
|
|
@@ -5597,7 +5753,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5597
5753
|
const [layoutChoice, setLayoutChoice] = _react.useState.call(void 0, () => {
|
|
5598
5754
|
try {
|
|
5599
5755
|
return localStorage.getItem("aa-layout") || null;
|
|
5600
|
-
} catch (
|
|
5756
|
+
} catch (e21) {
|
|
5601
5757
|
return null;
|
|
5602
5758
|
}
|
|
5603
5759
|
});
|
|
@@ -5606,7 +5762,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5606
5762
|
const [hfNamespaceLocal, setHfNamespaceLocal] = _react.useState.call(void 0, () => {
|
|
5607
5763
|
try {
|
|
5608
5764
|
return normalizeSelectableNamespace(localStorage.getItem("aa-hf-namespace"));
|
|
5609
|
-
} catch (
|
|
5765
|
+
} catch (e22) {
|
|
5610
5766
|
return DEFAULT_NAMESPACE;
|
|
5611
5767
|
}
|
|
5612
5768
|
});
|
|
@@ -5631,7 +5787,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5631
5787
|
});
|
|
5632
5788
|
const effectiveNamespace = _nullishCoalesce(bootstrapTarget.namespace, () => ( ""));
|
|
5633
5789
|
const kontextRef = _react.useRef.call(void 0, null);
|
|
5634
|
-
const szenenPort = _react.useMemo.call(void 0, () => hfToken && effectiveNamespace ?
|
|
5790
|
+
const szenenPort = _react.useMemo.call(void 0, () => hfToken && effectiveNamespace ? _chunkVSHSZEGVjs.createFlowSzenenViewPort.call(void 0, {
|
|
5635
5791
|
generateText: onGeneratePrompt,
|
|
5636
5792
|
token: hfToken,
|
|
5637
5793
|
namespace: effectiveNamespace,
|
|
@@ -5690,7 +5846,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5690
5846
|
setIsBootstrapping(true);
|
|
5691
5847
|
setBootstrapLog([]);
|
|
5692
5848
|
try {
|
|
5693
|
-
await
|
|
5849
|
+
await _chunkVSHSZEGVjs.hfBootstrapFromLegacy.call(void 0, effectiveNamespace, hfToken, (msg) => setBootstrapLog((prev) => [...prev, msg]));
|
|
5694
5850
|
setBootstrapLog((prev) => [...prev, "\u2713 Fertig"]);
|
|
5695
5851
|
setTimeout(() => refreshHF(), 1500);
|
|
5696
5852
|
} catch (e) {
|
|
@@ -5709,7 +5865,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5709
5865
|
const startApp = (choice) => {
|
|
5710
5866
|
try {
|
|
5711
5867
|
localStorage.setItem("aa-layout", choice);
|
|
5712
|
-
} catch (
|
|
5868
|
+
} catch (e23) {
|
|
5713
5869
|
}
|
|
5714
5870
|
setLayoutChoice(choice);
|
|
5715
5871
|
setTargetConfirmed(true);
|
|
@@ -5730,9 +5886,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5730
5886
|
const loadThumbnailsForEntries = _react.useCallback.call(void 0, async (entries) => {
|
|
5731
5887
|
await loadThumbnailsSequentially(entries, {
|
|
5732
5888
|
inFlight: hfInFlightRef.current,
|
|
5733
|
-
isAlreadyLoaded: (entry) => !!_optionalChain([galleryItemsRef, 'access',
|
|
5889
|
+
isAlreadyLoaded: (entry) => !!_optionalChain([galleryItemsRef, 'access', _158 => _158.current, 'access', _159 => _159.find, 'call', _160 => _160((g) => g.id === entry.id), 'optionalAccess', _161 => _161.base64]),
|
|
5734
5890
|
isKnownMissing: (entry) => hfImageNotFoundRef.current.has(entry.id),
|
|
5735
|
-
loadImage: (entry) =>
|
|
5891
|
+
loadImage: (entry) => _chunkVSHSZEGVjs.hfLoadImageAsBase64.call(void 0, entry.id, hfToken, effectiveNamespace, entry.filename, void 0, entry.mimeType, entry.hasThumb),
|
|
5736
5892
|
onLoaded: (entry, b64) => {
|
|
5737
5893
|
const prefix = `data:${entry.mimeType || "image/jpeg"};base64,`;
|
|
5738
5894
|
setGalleryItems((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
|
|
@@ -5749,7 +5905,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5749
5905
|
}, [hfToken, effectiveNamespace]);
|
|
5750
5906
|
_react.useEffect.call(void 0, () => {
|
|
5751
5907
|
if (!hfState) return;
|
|
5752
|
-
if (_optionalChain([hfState, 'access',
|
|
5908
|
+
if (_optionalChain([hfState, 'access', _162 => _162.tags, 'optionalAccess', _163 => _163.by_category])) setWorkspaceTags(hfState.tags);
|
|
5753
5909
|
const hfIds = new Set(hfState.metadata.map((m) => m.id));
|
|
5754
5910
|
const skeletons = hfState.metadata.map((m) => ({
|
|
5755
5911
|
id: m.id,
|
|
@@ -5795,7 +5951,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5795
5951
|
try {
|
|
5796
5952
|
const v = parseInt(localStorage.getItem("aa-image-count") || "", 10);
|
|
5797
5953
|
return v >= 1 && v <= 8 ? v : 4;
|
|
5798
|
-
} catch (
|
|
5954
|
+
} catch (e24) {
|
|
5799
5955
|
return 4;
|
|
5800
5956
|
}
|
|
5801
5957
|
});
|
|
@@ -5804,7 +5960,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5804
5960
|
setImageCount(n);
|
|
5805
5961
|
try {
|
|
5806
5962
|
localStorage.setItem("aa-image-count", String(n));
|
|
5807
|
-
} catch (
|
|
5963
|
+
} catch (e25) {
|
|
5808
5964
|
}
|
|
5809
5965
|
};
|
|
5810
5966
|
const imageCountOptions = [
|
|
@@ -5818,14 +5974,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5818
5974
|
const [leftPanelWidth, setLeftPanelWidth] = _react.useState.call(void 0, () => {
|
|
5819
5975
|
try {
|
|
5820
5976
|
return parseInt(localStorage.getItem("aa-left-width") || "260", 10);
|
|
5821
|
-
} catch (
|
|
5977
|
+
} catch (e26) {
|
|
5822
5978
|
return 260;
|
|
5823
5979
|
}
|
|
5824
5980
|
});
|
|
5825
5981
|
const [rightPanelWidth, setRightPanelWidth] = _react.useState.call(void 0, () => {
|
|
5826
5982
|
try {
|
|
5827
5983
|
return parseInt(localStorage.getItem("aa-right-width") || "320", 10);
|
|
5828
|
-
} catch (
|
|
5984
|
+
} catch (e27) {
|
|
5829
5985
|
return 320;
|
|
5830
5986
|
}
|
|
5831
5987
|
});
|
|
@@ -5834,7 +5990,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5834
5990
|
const [highContrast, setHighContrast] = _react.useState.call(void 0, () => {
|
|
5835
5991
|
try {
|
|
5836
5992
|
return localStorage.getItem("aa-contrast") === "high";
|
|
5837
|
-
} catch (
|
|
5993
|
+
} catch (e28) {
|
|
5838
5994
|
return false;
|
|
5839
5995
|
}
|
|
5840
5996
|
});
|
|
@@ -5847,14 +6003,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5847
6003
|
const [zoomOffset, setZoomOffset] = _react.useState.call(void 0, { x: 0, y: 0 });
|
|
5848
6004
|
const { historyVisible, galleryVisible } = computePrefetchVisibility({
|
|
5849
6005
|
layoutChoice,
|
|
5850
|
-
appShellVisible: !showStart && !requireWorkspaceSelection && !(isFullscreen && !!_optionalChain([currentResult, 'optionalAccess',
|
|
6006
|
+
appShellVisible: !showStart && !requireWorkspaceSelection && !(isFullscreen && !!_optionalChain([currentResult, 'optionalAccess', _164 => _164.base64])),
|
|
5851
6007
|
mobileTab,
|
|
5852
6008
|
middlePanel,
|
|
5853
6009
|
activeTab,
|
|
5854
6010
|
isRightCollapsed
|
|
5855
6011
|
});
|
|
5856
6012
|
useThumbnailPrefetch({
|
|
5857
|
-
metadata: _optionalChain([hfState, 'optionalAccess',
|
|
6013
|
+
metadata: _optionalChain([hfState, 'optionalAccess', _165 => _165.metadata]),
|
|
5858
6014
|
historyVisible,
|
|
5859
6015
|
galleryVisible,
|
|
5860
6016
|
historyVisibleCount,
|
|
@@ -5910,12 +6066,12 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5910
6066
|
setHighContrast(next);
|
|
5911
6067
|
try {
|
|
5912
6068
|
localStorage.setItem("aa-contrast", next ? "high" : "low");
|
|
5913
|
-
} catch (
|
|
6069
|
+
} catch (e29) {
|
|
5914
6070
|
}
|
|
5915
6071
|
};
|
|
5916
6072
|
const handleSelectReference = async () => {
|
|
5917
6073
|
const media = await onSelectMedia();
|
|
5918
|
-
if (!_optionalChain([media, 'optionalAccess',
|
|
6074
|
+
if (!_optionalChain([media, 'optionalAccess', _166 => _166.length])) return;
|
|
5919
6075
|
const first = media[0];
|
|
5920
6076
|
if (first.mediaId) {
|
|
5921
6077
|
setActiveReferenceId(first.mediaId);
|
|
@@ -5938,7 +6094,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5938
6094
|
generateImage: onGenerateImage,
|
|
5939
6095
|
saveResult: async (item) => {
|
|
5940
6096
|
const frame = item.frames[0];
|
|
5941
|
-
if (_optionalChain([frame, 'optionalAccess',
|
|
6097
|
+
if (_optionalChain([frame, 'optionalAccess', _167 => _167.base64])) {
|
|
5942
6098
|
const gen = frameToGeneration(frame, item);
|
|
5943
6099
|
setGalleryItems((prev) => [gen, ...prev]);
|
|
5944
6100
|
setHistory((prev) => [gen, ...prev]);
|
|
@@ -5956,7 +6112,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5956
6112
|
setLeftPanelWidth(w);
|
|
5957
6113
|
try {
|
|
5958
6114
|
localStorage.setItem("aa-left-width", String(w));
|
|
5959
|
-
} catch (
|
|
6115
|
+
} catch (e30) {
|
|
5960
6116
|
}
|
|
5961
6117
|
};
|
|
5962
6118
|
const onUp = () => {
|
|
@@ -5975,7 +6131,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
5975
6131
|
setRightPanelWidth(w);
|
|
5976
6132
|
try {
|
|
5977
6133
|
localStorage.setItem("aa-right-width", String(w));
|
|
5978
|
-
} catch (
|
|
6134
|
+
} catch (e31) {
|
|
5979
6135
|
}
|
|
5980
6136
|
};
|
|
5981
6137
|
const onUp = () => {
|
|
@@ -6006,7 +6162,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6006
6162
|
setIsScanningImage(false);
|
|
6007
6163
|
}
|
|
6008
6164
|
};
|
|
6009
|
-
const currentIndex = _react.useMemo.call(void 0, () => history.findIndex((h) => h.id === _optionalChain([currentResult, 'optionalAccess',
|
|
6165
|
+
const currentIndex = _react.useMemo.call(void 0, () => history.findIndex((h) => h.id === _optionalChain([currentResult, 'optionalAccess', _168 => _168.id])), [history, currentResult]);
|
|
6010
6166
|
const goToPrev = _react.useCallback.call(void 0, () => {
|
|
6011
6167
|
if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
|
|
6012
6168
|
}, [currentIndex, history]);
|
|
@@ -6017,10 +6173,10 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6017
6173
|
setCurrentResult(g);
|
|
6018
6174
|
setMobileTab("stage");
|
|
6019
6175
|
if (g.hasThumb && g.filename && hfToken && !g.fullBase64) {
|
|
6020
|
-
|
|
6176
|
+
_chunkVSHSZEGVjs.hfLoadImageAsBase64.call(void 0, g.id, hfToken, effectiveNamespace, g.filename, void 0, g.mimeType, false).then((b64) => {
|
|
6021
6177
|
if (!b64) return;
|
|
6022
6178
|
const full = `data:${g.mimeType || "image/jpeg"};base64,${b64}`;
|
|
6023
|
-
setCurrentResult((prev) => _optionalChain([prev, 'optionalAccess',
|
|
6179
|
+
setCurrentResult((prev) => _optionalChain([prev, 'optionalAccess', _169 => _169.id]) === g.id ? { ...prev, fullBase64: full } : prev);
|
|
6024
6180
|
setGalleryItems((prev) => prev.map((item) => item.id === g.id ? { ...item, fullBase64: full } : item));
|
|
6025
6181
|
}).catch(() => {
|
|
6026
6182
|
});
|
|
@@ -6036,13 +6192,13 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6036
6192
|
}
|
|
6037
6193
|
}, [hfToken, effectiveNamespace, hfWriteEvent]);
|
|
6038
6194
|
const currentGroup = _react.useMemo.call(void 0, () => {
|
|
6039
|
-
if (!_optionalChain([currentResult, 'optionalAccess',
|
|
6195
|
+
if (!_optionalChain([currentResult, 'optionalAccess', _170 => _170.prompt])) return [];
|
|
6040
6196
|
const groups = groupByPrompt(galleryItems.filter((g) => g.status === "done" && !!g.base64));
|
|
6041
6197
|
const group = groups.find((gr) => gr.prompt === currentResult.prompt);
|
|
6042
6198
|
return group ? group.items : [];
|
|
6043
|
-
}, [galleryItems, _optionalChain([currentResult, 'optionalAccess',
|
|
6199
|
+
}, [galleryItems, _optionalChain([currentResult, 'optionalAccess', _171 => _171.prompt])]);
|
|
6044
6200
|
_react.useEffect.call(void 0, () => {
|
|
6045
|
-
if (!_optionalChain([currentResult, 'optionalAccess',
|
|
6201
|
+
if (!_optionalChain([currentResult, 'optionalAccess', _172 => _172.prompt]) || !hfToken || !effectiveNamespace || !hfState) return;
|
|
6046
6202
|
const siblings = galleryItemsRef.current.filter(
|
|
6047
6203
|
(g) => g.prompt === currentResult.prompt && !g.base64 && !hfImageNotFoundRef.current.has(g.id)
|
|
6048
6204
|
);
|
|
@@ -6052,7 +6208,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6052
6208
|
const meta = hfState.metadata.find((m) => m.id === sib.id);
|
|
6053
6209
|
if (!meta) continue;
|
|
6054
6210
|
try {
|
|
6055
|
-
const b64 = await
|
|
6211
|
+
const b64 = await _chunkVSHSZEGVjs.hfLoadImageAsBase64.call(void 0, sib.id, hfToken, effectiveNamespace, meta.filename, void 0, meta.mimeType, meta.hasThumb);
|
|
6056
6212
|
if (!b64) {
|
|
6057
6213
|
hfImageNotFoundRef.current.set(sib.id, Date.now());
|
|
6058
6214
|
continue;
|
|
@@ -6060,12 +6216,12 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6060
6216
|
const prefix = `data:${meta.mimeType || "image/jpeg"};base64,`;
|
|
6061
6217
|
setGalleryItems((prev) => prev.map((g) => g.id === sib.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
|
|
6062
6218
|
setHistory((prev) => prev.map((g) => g.id === sib.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
|
|
6063
|
-
} catch (
|
|
6219
|
+
} catch (e32) {
|
|
6064
6220
|
hfImageNotFoundRef.current.set(sib.id, Date.now());
|
|
6065
6221
|
}
|
|
6066
6222
|
}
|
|
6067
6223
|
})();
|
|
6068
|
-
}, [_optionalChain([currentResult, 'optionalAccess',
|
|
6224
|
+
}, [_optionalChain([currentResult, 'optionalAccess', _173 => _173.id]), _optionalChain([currentResult, 'optionalAccess', _174 => _174.prompt])]);
|
|
6069
6225
|
const hcStyle = highContrast ? { filter: "brightness(1.6) contrast(1.05)" } : void 0;
|
|
6070
6226
|
const runningBadge = activeGenerationsCount > 0 ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
6071
6227
|
"div",
|
|
@@ -6124,7 +6280,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6124
6280
|
console.log("[HF] handleGenerateImage \u2014 condition check:", { hfToken: !!hfToken, base64: !!base64, effectiveNamespace });
|
|
6125
6281
|
if (hfToken && base64 && effectiveNamespace) {
|
|
6126
6282
|
setImageUploadStatus((m) => new Map(m).set(genId, "uploading"));
|
|
6127
|
-
|
|
6283
|
+
_chunkVSHSZEGVjs.hfUploadImage.call(void 0, base64, genId, hfToken).then(() => setImageUploadStatus((m) => new Map(m).set(genId, "done"))).catch((e) => {
|
|
6128
6284
|
console.error("[HF] hfUploadImage failed:", e);
|
|
6129
6285
|
setImageUploadStatus((m) => new Map(m).set(genId, "failed"));
|
|
6130
6286
|
});
|
|
@@ -6146,7 +6302,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6146
6302
|
const errorGen = { ...newGen, status: "error", error: { message: err.message || "Unbekannter Fehler", details: err.toString() } };
|
|
6147
6303
|
setHistory((prev) => prev.map((g) => g.id === genId ? errorGen : g));
|
|
6148
6304
|
setGalleryItems((prev) => prev.filter((g) => g.id !== genId));
|
|
6149
|
-
if (!options.silent || _optionalChain([currentResult, 'optionalAccess',
|
|
6305
|
+
if (!options.silent || _optionalChain([currentResult, 'optionalAccess', _175 => _175.id]) === genId) setCurrentResult(errorGen);
|
|
6150
6306
|
} finally {
|
|
6151
6307
|
setActiveGenerationsCount((prev) => Math.max(0, prev - 1));
|
|
6152
6308
|
}
|
|
@@ -6181,7 +6337,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6181
6337
|
timestamp: Date.now(),
|
|
6182
6338
|
mimeType: "image/jpeg"
|
|
6183
6339
|
};
|
|
6184
|
-
await
|
|
6340
|
+
await _chunkVSHSZEGVjs.hfUploadImage.call(void 0, base64, genId, hfToken);
|
|
6185
6341
|
await hfWriteEvent("image_added", entry);
|
|
6186
6342
|
return [genId];
|
|
6187
6343
|
} catch (e) {
|
|
@@ -6202,7 +6358,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6202
6358
|
setActivePrompt(prompt);
|
|
6203
6359
|
setFocusedNodeId(nodeId);
|
|
6204
6360
|
if (autoGenerate) handleGenerateImage(prompt, void 0, nodeId);
|
|
6205
|
-
} catch (
|
|
6361
|
+
} catch (e33) {
|
|
6206
6362
|
setActivePrompt("Synthese-Fehler");
|
|
6207
6363
|
} finally {
|
|
6208
6364
|
setIsSynthesizing(false);
|
|
@@ -6275,14 +6431,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6275
6431
|
const { prompt, feedback } = parsePromptResponse(raw);
|
|
6276
6432
|
setActivePrompt(prompt);
|
|
6277
6433
|
setPromptFeedback(feedback);
|
|
6278
|
-
} catch (
|
|
6434
|
+
} catch (e34) {
|
|
6279
6435
|
setActivePrompt("Synthese-Fehler");
|
|
6280
6436
|
} finally {
|
|
6281
6437
|
setIsPromptTabGenerating(false);
|
|
6282
6438
|
}
|
|
6283
6439
|
};
|
|
6284
6440
|
const handleDownloadSingle = async () => {
|
|
6285
|
-
if (!_optionalChain([currentResult, 'optionalAccess',
|
|
6441
|
+
if (!_optionalChain([currentResult, 'optionalAccess', _176 => _176.base64])) return;
|
|
6286
6442
|
try {
|
|
6287
6443
|
const downloadSrc = currentResult.fullBase64 || currentResult.base64;
|
|
6288
6444
|
const base64Data = downloadSrc.split(",")[1];
|
|
@@ -6298,9 +6454,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6298
6454
|
const reader = new FileReader();
|
|
6299
6455
|
reader.onload = (ev) => {
|
|
6300
6456
|
try {
|
|
6301
|
-
const root = JSON.parse(_optionalChain([ev, 'access',
|
|
6457
|
+
const root = JSON.parse(_optionalChain([ev, 'access', _177 => _177.target, 'optionalAccess', _178 => _178.result]));
|
|
6302
6458
|
const rawTags = root.tags || root;
|
|
6303
|
-
if (!_optionalChain([rawTags, 'optionalAccess',
|
|
6459
|
+
if (!_optionalChain([rawTags, 'optionalAccess', _179 => _179.by_category])) return;
|
|
6304
6460
|
const filtered = {};
|
|
6305
6461
|
const EXCLUDED2 = ["pdf-export", "book.micro-edit-rules"];
|
|
6306
6462
|
Object.entries(rawTags.by_category).forEach(([cat, items]) => {
|
|
@@ -6317,7 +6473,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6317
6473
|
};
|
|
6318
6474
|
const handleHfInitialSync = async (onProgress) => {
|
|
6319
6475
|
if (!hfToken || !effectiveNamespace) return;
|
|
6320
|
-
const existingIds = new Set((_optionalChain([hfState, 'optionalAccess',
|
|
6476
|
+
const existingIds = new Set((_optionalChain([hfState, 'optionalAccess', _180 => _180.metadata]) || []).map((m) => m.id));
|
|
6321
6477
|
const gens = galleryItems.filter((g) => g.base64 && g.status === "done" && !existingIds.has(g.id));
|
|
6322
6478
|
const total = gens.length;
|
|
6323
6479
|
onProgress(0, total);
|
|
@@ -6325,7 +6481,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6325
6481
|
for (const gen of gens) {
|
|
6326
6482
|
const raw = gen.base64.includes(",") ? gen.base64.split(",")[1] : gen.base64;
|
|
6327
6483
|
const mimeType = gen.base64.startsWith("data:image/png") ? "image/png" : "image/jpeg";
|
|
6328
|
-
await
|
|
6484
|
+
await _chunkVSHSZEGVjs.hfUploadImage.call(void 0, raw, gen.id, hfToken, mimeType).catch(() => {
|
|
6329
6485
|
});
|
|
6330
6486
|
const entry = {
|
|
6331
6487
|
id: gen.id,
|
|
@@ -6343,7 +6499,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6343
6499
|
}
|
|
6344
6500
|
};
|
|
6345
6501
|
const mergeWorkspaceTags = (local, remote) => {
|
|
6346
|
-
if (!_optionalChain([remote, 'optionalAccess',
|
|
6502
|
+
if (!_optionalChain([remote, 'optionalAccess', _181 => _181.by_category])) return local;
|
|
6347
6503
|
const merged = {};
|
|
6348
6504
|
const allCategories = /* @__PURE__ */ new Set([...Object.keys(local.by_category), ...Object.keys(remote.by_category)]);
|
|
6349
6505
|
for (const cat of allCategories) {
|
|
@@ -6353,7 +6509,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6353
6509
|
const localValues = new Set(localTags.map((t) => t.value));
|
|
6354
6510
|
const mergedLocal = localTags.map((t) => {
|
|
6355
6511
|
const remote2 = remoteMap.get(t.value);
|
|
6356
|
-
return _optionalChain([remote2, 'optionalAccess',
|
|
6512
|
+
return _optionalChain([remote2, 'optionalAccess', _182 => _182.is_deleted]) ? { ...t, is_deleted: true } : t;
|
|
6357
6513
|
});
|
|
6358
6514
|
const onlyInRemote = remoteTags.filter((t) => !localValues.has(t.value));
|
|
6359
6515
|
merged[cat] = [...mergedLocal, ...onlyInRemote];
|
|
@@ -6361,7 +6517,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6361
6517
|
const all = Object.entries(merged).flatMap(([cat, tags]) => tags.map((t) => ({ ...t, category: cat })));
|
|
6362
6518
|
return { by_category: merged, all };
|
|
6363
6519
|
};
|
|
6364
|
-
if (isFullscreen && _optionalChain([currentResult, 'optionalAccess',
|
|
6520
|
+
if (isFullscreen && _optionalChain([currentResult, 'optionalAccess', _183 => _183.base64])) {
|
|
6365
6521
|
const fsRaw = currentResult.fullBase64 || currentResult.base64;
|
|
6366
6522
|
const fsBase64 = fsRaw.startsWith("data:") ? fsRaw : `data:image/png;base64,${fsRaw}`;
|
|
6367
6523
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
@@ -6475,7 +6631,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6475
6631
|
setHfNamespaceLocal(ns);
|
|
6476
6632
|
try {
|
|
6477
6633
|
localStorage.setItem("aa-hf-namespace", ns);
|
|
6478
|
-
} catch (
|
|
6634
|
+
} catch (e35) {
|
|
6479
6635
|
}
|
|
6480
6636
|
},
|
|
6481
6637
|
className: "px-3 py-1 rounded-lg text-[11px] font-bold transition-colors",
|
|
@@ -6511,7 +6667,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6511
6667
|
)) }),
|
|
6512
6668
|
layoutChoice === "mobile-desktop" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-white/20 text-[9px] text-center", children: "Mobil-Layout skaliert f\xFCr Desktop-Modus" }),
|
|
6513
6669
|
layoutChoice === "tablet-landscape" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-white/20 text-[9px] text-center", children: "2-Spalten-Layout f\xFCr Landscape-Tablet im Desktop-Mode" })
|
|
6514
|
-
] })
|
|
6670
|
+
] }),
|
|
6671
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, FlowBridgePanel, { appVersion: version })
|
|
6515
6672
|
] });
|
|
6516
6673
|
}
|
|
6517
6674
|
if (requireWorkspaceSelection) {
|
|
@@ -6556,7 +6713,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6556
6713
|
);
|
|
6557
6714
|
}
|
|
6558
6715
|
}
|
|
6559
|
-
const szenenPane = szenenPort ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flow-szenen-pane", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
6716
|
+
const szenenPane = szenenPort ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flow-szenen-pane", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVSHSZEGVjs.SzenenView, { port: szenenPort, contextId: szenenKontextId }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flow-szenen-pane flow-szenen-pane--empty", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { children: [
|
|
6560
6717
|
"Szenen brauchen einen HF-Token f\xFCr Namespace ",
|
|
6561
6718
|
effectiveNamespace || "(noch nicht bestimmt)",
|
|
6562
6719
|
" \u2014 auf der Flow-Startseite setzen."
|
|
@@ -6575,7 +6732,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6575
6732
|
}, children: [
|
|
6576
6733
|
mobileTab === "labs" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-col flex-1 min-h-0", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LabsTab, { services: labServices, onResult: (item) => {
|
|
6577
6734
|
const frame = item.frames[0];
|
|
6578
|
-
if (_optionalChain([frame, 'optionalAccess',
|
|
6735
|
+
if (_optionalChain([frame, 'optionalAccess', _184 => _184.base64])) {
|
|
6579
6736
|
setCurrentResult(frameToGeneration(frame, item));
|
|
6580
6737
|
setMobileTab("stage");
|
|
6581
6738
|
}
|
|
@@ -6599,7 +6756,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6599
6756
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] }),
|
|
6600
6757
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CompactDropdown, { value: String(imageCount), displayValue: `${imageCount}\xD7`, onChange: updateImageCount, options: imageCountOptions }),
|
|
6601
6758
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1" }),
|
|
6602
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TaskExecutor, { openTasks: _optionalChain([hfState, 'optionalAccess',
|
|
6759
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TaskExecutor, { openTasks: _optionalChain([hfState, 'optionalAccess', _185 => _185.openTasks]) || {}, onExecute: handleExecuteTask, onTaskCompleted: handleTaskCompleted }),
|
|
6603
6760
|
runningBadge,
|
|
6604
6761
|
activeReferenceThumbnail ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden mr-2", style: { height: 28 }, children: [
|
|
6605
6762
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
|
|
@@ -6650,21 +6807,21 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6650
6807
|
setTouchStartX(null);
|
|
6651
6808
|
},
|
|
6652
6809
|
children: [
|
|
6653
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
6810
|
+
_optionalChain([currentResult, 'optionalAccess', _186 => _186.status]) === "processing" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center gap-3 opacity-40", children: [
|
|
6654
6811
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[40px]", children: "hourglass_top" }),
|
|
6655
6812
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-[11px] uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
|
|
6656
6813
|
] }),
|
|
6657
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
6814
|
+
_optionalChain([currentResult, 'optionalAccess', _187 => _187.status]) === "error" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "p-6 text-center flex flex-col items-center gap-3", children: [
|
|
6658
6815
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-red-400 text-[36px]", children: "warning" }),
|
|
6659
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-white/50 text-[13px]", children: _optionalChain([currentResult, 'access',
|
|
6816
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-white/50 text-[13px]", children: _optionalChain([currentResult, 'access', _188 => _188.error, 'optionalAccess', _189 => _189.message]) }),
|
|
6660
6817
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => handleGenerateImage(currentResult.prompt), className: "px-4 py-2 rounded-lg border border-white/20 text-[13px] text-white/70 active:bg-white/10", children: "Erneut versuchen" })
|
|
6661
6818
|
] }),
|
|
6662
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
6819
|
+
_optionalChain([currentResult, 'optionalAccess', _190 => _190.status]) === "done" && currentResult.base64 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: currentResult.fullBase64 || currentResult.base64, className: "w-full h-full object-contain" }),
|
|
6663
6820
|
!currentResult && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
|
|
6664
6821
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[64px]", children: "palette" }),
|
|
6665
6822
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-[11px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
|
|
6666
6823
|
] }),
|
|
6667
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
6824
|
+
_optionalChain([currentResult, 'optionalAccess', _191 => _191.status]) === "done" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: openFullscreen, className: "absolute top-2 right-2 w-8 h-8 flex items-center justify-center rounded-full bg-black/60 border border-white/10 z-10", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[18px]", children: "fullscreen" }) }),
|
|
6668
6825
|
history.length > 1 && currentResult && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
6669
6826
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: goToPrev, disabled: currentIndex <= 0, className: "absolute left-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0 transition-opacity", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
|
|
6670
6827
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: goToNext, disabled: currentIndex >= history.length - 1, className: "absolute right-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0 transition-opacity", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
|
|
@@ -6677,7 +6834,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6677
6834
|
]
|
|
6678
6835
|
}
|
|
6679
6836
|
),
|
|
6680
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
6837
|
+
_optionalChain([currentResult, 'optionalAccess', _192 => _192.status]) === "done" && currentGroup.length > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mt-2 flex gap-1.5 overflow-x-auto pb-1", style: { scrollbarWidth: "none" }, children: currentGroup.map((item) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { position: "relative", flexShrink: 0 }, children: [
|
|
6681
6838
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
6682
6839
|
"div",
|
|
6683
6840
|
{
|
|
@@ -6720,7 +6877,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6720
6877
|
}
|
|
6721
6878
|
)
|
|
6722
6879
|
] }, item.id)) }),
|
|
6723
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
6880
|
+
_optionalChain([currentResult, 'optionalAccess', _193 => _193.status]) === "done" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex gap-2 mt-3", children: [
|
|
6724
6881
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { onClick: () => setActivePrompt(currentResult.prompt || ""), className: "flex-1 flex items-center justify-center gap-1.5 rounded-xl border border-white/10 bg-white/5 active:bg-white/10 transition-colors", style: { height: 44 }, children: [
|
|
6725
6882
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "replay" }),
|
|
6726
6883
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-[12px] text-white/60", children: "Prompt" })
|
|
@@ -6742,14 +6899,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6742
6899
|
hfToken && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => refreshHF(), disabled: isHfRefreshing, className: "w-12 flex items-center justify-center text-white/20 active:text-white transition-colors disabled:opacity-30", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: `material-symbols-outlined text-[20px]${isHfRefreshing ? " animate-spin" : ""}`, children: "sync" }) })
|
|
6743
6900
|
] }),
|
|
6744
6901
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 overflow-hidden relative", children: [
|
|
6745
|
-
activeTab === "history" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HistoryPanel, { history, currentResultId: _optionalChain([currentResult, 'optionalAccess',
|
|
6902
|
+
activeTab === "history" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HistoryPanel, { history, currentResultId: _optionalChain([currentResult, 'optionalAccess', _194 => _194.id]) || null, onSelect: handleGallerySelect, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)), visibleCount: historyVisibleCount, onLoadMore: () => setHistoryVisibleCount((c) => c + 20) }),
|
|
6746
6903
|
activeTab === "gallery" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
6747
6904
|
MediaLibrary,
|
|
6748
6905
|
{
|
|
6749
6906
|
items: galleryItems,
|
|
6750
6907
|
onImport: async () => {
|
|
6751
6908
|
const media = await onSelectMedia();
|
|
6752
|
-
if (!_optionalChain([media, 'optionalAccess',
|
|
6909
|
+
if (!_optionalChain([media, 'optionalAccess', _195 => _195.length])) return;
|
|
6753
6910
|
setGalleryItems((prev) => [...media.map((m) => ({ id: crypto.randomUUID(), nodeId: "1", base64: `data:${m.mimeType};base64,${m.base64}`, mediaId: m.mediaId, prompt: m.name || "Importiert", timestamp: Date.now(), status: "done", tags: [], type: "import" })), ...prev]);
|
|
6754
6911
|
},
|
|
6755
6912
|
onDelete: (id) => setGalleryItems((g) => g.filter((x) => x.id !== id)),
|
|
@@ -6897,7 +7054,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6897
7054
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] }),
|
|
6898
7055
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CompactDropdown, { value: String(imageCount), displayValue: `${imageCount}\xD7`, onChange: updateImageCount, options: imageCountOptions }),
|
|
6899
7056
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { flex: 1 } }),
|
|
6900
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TaskExecutor, { openTasks: _optionalChain([hfState, 'optionalAccess',
|
|
7057
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TaskExecutor, { openTasks: _optionalChain([hfState, 'optionalAccess', _196 => _196.openTasks]) || {}, onExecute: handleExecuteTask, onTaskCompleted: handleTaskCompleted }),
|
|
6901
7058
|
runningBadge,
|
|
6902
7059
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: toggleContrast, style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: highContrast ? "light_mode" : "dark_mode" }) }),
|
|
6903
7060
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => setShowStart(true), style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "apps" }) })
|
|
@@ -6926,7 +7083,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6926
7083
|
]
|
|
6927
7084
|
}
|
|
6928
7085
|
) }),
|
|
6929
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { flex: 1, overflow: "hidden", position: "relative" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HistoryPanel, { history, currentResultId: _optionalChain([currentResult, 'optionalAccess',
|
|
7086
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { flex: 1, overflow: "hidden", position: "relative" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HistoryPanel, { history, currentResultId: _optionalChain([currentResult, 'optionalAccess', _197 => _197.id]) || null, onSelect: handleGallerySelect, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)), visibleCount: historyVisibleCount, onLoadMore: () => setHistoryVisibleCount((c) => c + 20) }) })
|
|
6930
7087
|
] }),
|
|
6931
7088
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { flex: 1, height: tlH, display: "flex", flexDirection: "column", background: "#0b0b0b" }, children: [
|
|
6932
7089
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
@@ -6942,21 +7099,21 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6942
7099
|
setTouchStartX(null);
|
|
6943
7100
|
},
|
|
6944
7101
|
children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { height: "100%", width: "100%", borderRadius: 20, border: "1px solid rgba(255,255,255,0.05)", background: "rgba(0,0,0,0.4)", position: "relative", overflow: "hidden", display: "flex", alignItems: "center", justifyContent: "center" }, children: [
|
|
6945
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7102
|
+
_optionalChain([currentResult, 'optionalAccess', _198 => _198.status]) === "processing" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 12, opacity: 0.4 }, children: [
|
|
6946
7103
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 36 }, children: "hourglass_top" }),
|
|
6947
7104
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { style: { fontSize: 10, color: "rgba(255,255,255,0.6)", textTransform: "uppercase", fontWeight: "bold", letterSpacing: "0.15em" }, children: "Erstelle Bild..." })
|
|
6948
7105
|
] }),
|
|
6949
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7106
|
+
_optionalChain([currentResult, 'optionalAccess', _199 => _199.status]) === "error" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { padding: 24, textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
|
|
6950
7107
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 32, color: "#f87171" }, children: "warning" }),
|
|
6951
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: { fontSize: 11, color: "rgba(255,255,255,0.5)", margin: 0 }, children: _optionalChain([currentResult, 'access',
|
|
7108
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: { fontSize: 11, color: "rgba(255,255,255,0.5)", margin: 0 }, children: _optionalChain([currentResult, 'access', _200 => _200.error, 'optionalAccess', _201 => _201.message]) }),
|
|
6952
7109
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => handleGenerateImage(currentResult.prompt), style: { padding: "8px 16px", borderRadius: 8, border: "1px solid rgba(255,255,255,0.2)", fontSize: 11, color: "rgba(255,255,255,0.7)", background: "none", cursor: "pointer", fontFamily: "inherit" }, children: "Erneut versuchen" })
|
|
6953
7110
|
] }),
|
|
6954
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7111
|
+
_optionalChain([currentResult, 'optionalAccess', _202 => _202.status]) === "done" && currentResult.base64 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: currentResult.fullBase64 || currentResult.base64, style: { maxWidth: "100%", maxHeight: "100%", objectFit: "contain" } }),
|
|
6955
7112
|
!currentResult && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 8, opacity: 0.1 }, children: [
|
|
6956
7113
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 64 }, children: "palette" }),
|
|
6957
7114
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { style: { fontSize: 11, fontWeight: "bold", textTransform: "uppercase", letterSpacing: "0.2em" }, children: "Avatar Architect" })
|
|
6958
7115
|
] }),
|
|
6959
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7116
|
+
_optionalChain([currentResult, 'optionalAccess', _203 => _203.status]) === "done" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: openFullscreen, style: { position: "absolute", top: 8, right: 8, width: 32, height: 32, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "fullscreen" }) }),
|
|
6960
7117
|
history.length > 1 && currentResult && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
6961
7118
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: goToPrev, disabled: currentIndex <= 0, style: { position: "absolute", left: 8, top: "50%", transform: "translateY(-50%)", width: 36, height: 36, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff", opacity: currentIndex <= 0 ? 0 : 1, transition: "opacity 0.2s" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_left" }) }),
|
|
6962
7119
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: goToNext, disabled: currentIndex >= history.length - 1, style: { position: "absolute", right: 8, top: "50%", transform: "translateY(-50%)", width: 36, height: 36, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff", opacity: currentIndex >= history.length - 1 ? 0 : 1, transition: "opacity 0.2s" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_right" }) }),
|
|
@@ -6969,7 +7126,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
6969
7126
|
] })
|
|
6970
7127
|
}
|
|
6971
7128
|
),
|
|
6972
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7129
|
+
_optionalChain([currentResult, 'optionalAccess', _204 => _204.status]) === "done" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { padding: "0 16px 16px", display: "flex", gap: 8, flexShrink: 0 }, children: [
|
|
6973
7130
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { onClick: () => setActivePrompt(currentResult.prompt || ""), style: { flex: 1, height: 40, display: "flex", alignItems: "center", justifyContent: "center", gap: 6, borderRadius: 10, border: "1px solid rgba(255,255,255,0.1)", background: "rgba(255,255,255,0.05)", color: "rgba(255,255,255,0.6)", fontSize: 11, cursor: "pointer", fontFamily: "inherit" }, children: [
|
|
6974
7131
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "replay" }),
|
|
6975
7132
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Prompt" })
|
|
@@ -7091,7 +7248,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
7091
7248
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Ref" })
|
|
7092
7249
|
] }),
|
|
7093
7250
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
|
|
7094
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TaskExecutor, { openTasks: _optionalChain([hfState, 'optionalAccess',
|
|
7251
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, TaskExecutor, { openTasks: _optionalChain([hfState, 'optionalAccess', _205 => _205.openTasks]) || {}, onExecute: handleExecuteTask, onTaskCompleted: handleTaskCompleted }),
|
|
7095
7252
|
runningBadge,
|
|
7096
7253
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, PillButton, { variant: "solid", icon: "bolt", disabled: !activePrompt.trim(), onClick: () => handleGenerateBatch(), children: "Generieren" })
|
|
7097
7254
|
] })
|
|
@@ -7103,7 +7260,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
7103
7260
|
] }) }),
|
|
7104
7261
|
middlePanel === "szenen" ? szenenPane : middlePanel === "labs" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LabsTab, { services: labServices, onResult: (item) => {
|
|
7105
7262
|
const frame = item.frames[0];
|
|
7106
|
-
if (_optionalChain([frame, 'optionalAccess',
|
|
7263
|
+
if (_optionalChain([frame, 'optionalAccess', _206 => _206.base64])) setCurrentResult(frameToGeneration(frame, item));
|
|
7107
7264
|
} }) }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 overflow-hidden flex flex-col", children: [
|
|
7108
7265
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full w-full max-w-4xl aspect-square rounded-3xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center group shadow-2xl", children: currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center gap-4 opacity-40", children: [
|
|
7109
7266
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[40px]", children: "hourglass_top" }),
|
|
@@ -7112,7 +7269,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
7112
7269
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
|
|
7113
7270
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-2", children: [
|
|
7114
7271
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
|
|
7115
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-white/60 text-[12px] leading-relaxed", children: _optionalChain([currentResult, 'access',
|
|
7272
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-white/60 text-[12px] leading-relaxed", children: _optionalChain([currentResult, 'access', _207 => _207.error, 'optionalAccess', _208 => _208.message]) })
|
|
7116
7273
|
] }),
|
|
7117
7274
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
|
|
7118
7275
|
] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "h-full w-full relative flex items-center justify-center", children: [
|
|
@@ -7126,7 +7283,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
7126
7283
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
|
|
7127
7284
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
|
|
7128
7285
|
] }) }) }),
|
|
7129
|
-
_optionalChain([currentResult, 'optionalAccess',
|
|
7286
|
+
_optionalChain([currentResult, 'optionalAccess', _209 => _209.status]) === "done" && currentGroup.length > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "px-6 pb-4 shrink-0 flex gap-2 overflow-x-auto", style: { scrollbarWidth: "none" }, children: currentGroup.map((item) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { position: "relative", flexShrink: 0 }, children: [
|
|
7130
7287
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
7131
7288
|
"div",
|
|
7132
7289
|
{
|
|
@@ -7207,14 +7364,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
7207
7364
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "material-symbols-outlined text-[40px] text-white/10 block mb-3", children: "label_off" }),
|
|
7208
7365
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-[11px] text-white/20", children: "Erst Workspace importieren um Tags zu verwalten." })
|
|
7209
7366
|
] }) }),
|
|
7210
|
-
activeTab === "history" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HistoryPanel, { history, currentResultId: _optionalChain([currentResult, 'optionalAccess',
|
|
7367
|
+
activeTab === "history" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HistoryPanel, { history, currentResultId: _optionalChain([currentResult, 'optionalAccess', _210 => _210.id]) || null, onSelect: handleGallerySelect, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)), visibleCount: historyVisibleCount, onLoadMore: () => setHistoryVisibleCount((c) => c + 20) }),
|
|
7211
7368
|
activeTab === "gallery" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
7212
7369
|
MediaLibrary,
|
|
7213
7370
|
{
|
|
7214
7371
|
items: galleryItems,
|
|
7215
7372
|
onImport: async () => {
|
|
7216
7373
|
const media = await onSelectMedia();
|
|
7217
|
-
if (!_optionalChain([media, 'optionalAccess',
|
|
7374
|
+
if (!_optionalChain([media, 'optionalAccess', _211 => _211.length])) return;
|
|
7218
7375
|
setGalleryItems((prev) => [...media.map((m) => ({ id: crypto.randomUUID(), nodeId: "1", base64: `data:${m.mimeType};base64,${m.base64}`, mediaId: m.mediaId, prompt: m.name || "Importiert", timestamp: Date.now(), status: "done", tags: [], type: "import" })), ...prev]);
|
|
7219
7376
|
},
|
|
7220
7377
|
onDelete: (id) => setGalleryItems((g) => g.filter((x) => x.id !== id)),
|
|
@@ -7265,7 +7422,7 @@ function FaApp({
|
|
|
7265
7422
|
});
|
|
7266
7423
|
}, [serverBaseUrl]);
|
|
7267
7424
|
const wrappedPrompt = _react.useMemo.call(void 0,
|
|
7268
|
-
() =>
|
|
7425
|
+
() => _chunkVSHSZEGVjs.alsFlowTextZugang.call(void 0, onGeneratePrompt),
|
|
7269
7426
|
[onGeneratePrompt]
|
|
7270
7427
|
);
|
|
7271
7428
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
@@ -7370,7 +7527,7 @@ function createFaStore({ contracts, descriptors, persistence, workspaceId }) {
|
|
|
7370
7527
|
};
|
|
7371
7528
|
};
|
|
7372
7529
|
const applyWriteResult = (sliceId, result, savedData, signal) => {
|
|
7373
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
7530
|
+
if (_optionalChain([signal, 'optionalAccess', _212 => _212.aborted])) {
|
|
7374
7531
|
patchMeta(sliceId, { saveState: "idle" });
|
|
7375
7532
|
return result;
|
|
7376
7533
|
}
|
|
@@ -7398,8 +7555,8 @@ function createFaStore({ contracts, descriptors, persistence, workspaceId }) {
|
|
|
7398
7555
|
const requestId = _nullishCoalesce(externalRequestId, () => ( nextRequestId()));
|
|
7399
7556
|
patchMeta(sliceId, { loadRequestId: requestId, saveState: "restoring" });
|
|
7400
7557
|
const result = await persistence.load(workspaceId, descriptor, _nullishCoalesce(signal, () => ( new AbortController().signal)));
|
|
7401
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
7402
|
-
if (_optionalChain([signal, 'optionalAccess',
|
|
7558
|
+
if (_optionalChain([signal, 'optionalAccess', _213 => _213.aborted]) || _optionalChain([get, 'call', _214 => _214(), 'access', _215 => _215.meta, 'access', _216 => _216[sliceId], 'optionalAccess', _217 => _217.loadRequestId]) !== requestId) {
|
|
7559
|
+
if (_optionalChain([signal, 'optionalAccess', _218 => _218.aborted]) && _optionalChain([get, 'call', _219 => _219(), 'access', _220 => _220.meta, 'access', _221 => _221[sliceId], 'optionalAccess', _222 => _222.loadRequestId]) === requestId) {
|
|
7403
7560
|
patchMeta(sliceId, { saveState: "idle", loadRequestId: null });
|
|
7404
7561
|
}
|
|
7405
7562
|
return result;
|
|
@@ -7434,7 +7591,7 @@ function createFaStore({ contracts, descriptors, persistence, workspaceId }) {
|
|
|
7434
7591
|
},
|
|
7435
7592
|
async resetSlice(sliceId, signal, options) {
|
|
7436
7593
|
const contract = requireContract(sliceId);
|
|
7437
|
-
if (get().meta[sliceId].dirty && !_optionalChain([options, 'optionalAccess',
|
|
7594
|
+
if (get().meta[sliceId].dirty && !_optionalChain([options, 'optionalAccess', _223 => _223.confirmed])) {
|
|
7438
7595
|
throw new Error(`Reset for slice ${sliceId} requires confirmation while unsaved changes exist`);
|
|
7439
7596
|
}
|
|
7440
7597
|
const defaultData = contract.createDefault();
|
|
@@ -7487,7 +7644,7 @@ function createInMemoryWorkspacePersistence(now = () => Date.now()) {
|
|
|
7487
7644
|
}
|
|
7488
7645
|
const saved = {
|
|
7489
7646
|
...clone(slice),
|
|
7490
|
-
revision: (_nullishCoalesce(_optionalChain([current, 'optionalAccess',
|
|
7647
|
+
revision: (_nullishCoalesce(_optionalChain([current, 'optionalAccess', _224 => _224.revision]), () => ( 0))) + 1,
|
|
7491
7648
|
updatedAt: now(),
|
|
7492
7649
|
...resetAt !== void 0 ? { resetAt } : {}
|
|
7493
7650
|
};
|
|
@@ -7568,7 +7725,7 @@ function createPersistenceCoordinator({
|
|
|
7568
7725
|
if (disposed) return;
|
|
7569
7726
|
const runtime = runtimeOf(sliceId);
|
|
7570
7727
|
const meta = store.getState().meta[sliceId];
|
|
7571
|
-
if (!_optionalChain([meta, 'optionalAccess',
|
|
7728
|
+
if (!_optionalChain([meta, 'optionalAccess', _225 => _225.dirty])) return;
|
|
7572
7729
|
if (meta.saveState === "restoring" || meta.saveState === "saving") {
|
|
7573
7730
|
runtime.pendingSave = true;
|
|
7574
7731
|
return;
|
|
@@ -7596,7 +7753,7 @@ function createPersistenceCoordinator({
|
|
|
7596
7753
|
return {
|
|
7597
7754
|
async load(sliceId) {
|
|
7598
7755
|
const runtime = runtimeOf(sliceId);
|
|
7599
|
-
_optionalChain([runtime, 'access',
|
|
7756
|
+
_optionalChain([runtime, 'access', _226 => _226.loadController, 'optionalAccess', _227 => _227.abort, 'call', _228 => _228()]);
|
|
7600
7757
|
runtime.loadController = new AbortController();
|
|
7601
7758
|
const controller = runtime.loadController;
|
|
7602
7759
|
try {
|
|
@@ -7624,8 +7781,8 @@ function createPersistenceCoordinator({
|
|
|
7624
7781
|
disposed = true;
|
|
7625
7782
|
for (const runtime of runtimes.values()) {
|
|
7626
7783
|
clearTimer(runtime);
|
|
7627
|
-
_optionalChain([runtime, 'access',
|
|
7628
|
-
_optionalChain([runtime, 'access',
|
|
7784
|
+
_optionalChain([runtime, 'access', _229 => _229.loadController, 'optionalAccess', _230 => _230.abort, 'call', _231 => _231()]);
|
|
7785
|
+
_optionalChain([runtime, 'access', _232 => _232.saveController, 'optionalAccess', _233 => _233.abort, 'call', _234 => _234()]);
|
|
7629
7786
|
runtime.pendingSave = false;
|
|
7630
7787
|
}
|
|
7631
7788
|
runtimes.clear();
|
|
@@ -7729,7 +7886,7 @@ function parseLegacyLibraryFilters(source, knownTagIds) {
|
|
|
7729
7886
|
return null;
|
|
7730
7887
|
}).filter((id) => id !== null && knownTagIds.has(id));
|
|
7731
7888
|
}
|
|
7732
|
-
} catch (
|
|
7889
|
+
} catch (e36) {
|
|
7733
7890
|
tagIds = [];
|
|
7734
7891
|
}
|
|
7735
7892
|
}
|
|
@@ -7740,7 +7897,7 @@ function parseLegacyLibraryFilters(source, knownTagIds) {
|
|
|
7740
7897
|
if (Array.isArray(parsed)) {
|
|
7741
7898
|
recentFilterTagIds = parsed.filter((entry) => typeof entry === "string" || typeof entry === "number").map((entry) => String(entry)).filter((id) => knownTagIds.has(id)).slice(0, 5);
|
|
7742
7899
|
}
|
|
7743
|
-
} catch (
|
|
7900
|
+
} catch (e37) {
|
|
7744
7901
|
recentFilterTagIds = [];
|
|
7745
7902
|
}
|
|
7746
7903
|
}
|
|
@@ -7779,9 +7936,9 @@ function hatNavigationsziele(zugehoerigkeit) {
|
|
|
7779
7936
|
var kennung = (wert) => typeof wert === "string" && wert.trim().length > 0;
|
|
7780
7937
|
var kurz = (id) => id.slice(0, 8);
|
|
7781
7938
|
function zugehoerigkeitOf(item) {
|
|
7782
|
-
const runId = _optionalChain([item, 'optionalAccess',
|
|
7939
|
+
const runId = _optionalChain([item, 'optionalAccess', _235 => _235.szenen, 'optionalAccess', _236 => _236.prompt_run_id]);
|
|
7783
7940
|
if (!kennung(runId)) return null;
|
|
7784
|
-
const links = _nullishCoalesce(_optionalChain([item, 'optionalAccess',
|
|
7941
|
+
const links = _nullishCoalesce(_optionalChain([item, 'optionalAccess', _237 => _237.szenen_links]), () => ( null));
|
|
7785
7942
|
if (!links || links.prompt_run_id !== runId) {
|
|
7786
7943
|
return {
|
|
7787
7944
|
run: null,
|
|
@@ -7812,15 +7969,15 @@ function zugehoerigkeitOf(item) {
|
|
|
7812
7969
|
return { run, scene, hinweis: null };
|
|
7813
7970
|
}
|
|
7814
7971
|
function zugehoerigkeitenOf(item) {
|
|
7815
|
-
const szenen = _optionalChain([item, 'optionalAccess',
|
|
7972
|
+
const szenen = _optionalChain([item, 'optionalAccess', _238 => _238.szenen]);
|
|
7816
7973
|
if (!szenen) return [];
|
|
7817
7974
|
const laeufe = [];
|
|
7818
7975
|
const merken = (id) => {
|
|
7819
7976
|
if (kennung(id) && !laeufe.includes(id)) laeufe.push(id);
|
|
7820
7977
|
};
|
|
7821
7978
|
merken(szenen.prompt_run_id);
|
|
7822
|
-
for (const run of _nullishCoalesce(szenen.runs, () => ( []))) merken(_optionalChain([run, 'optionalAccess',
|
|
7823
|
-
const linkFuer = (runId) => _nullishCoalesce((_nullishCoalesce(_optionalChain([item, 'optionalAccess',
|
|
7979
|
+
for (const run of _nullishCoalesce(szenen.runs, () => ( []))) merken(_optionalChain([run, 'optionalAccess', _239 => _239.prompt_run_id]));
|
|
7980
|
+
const linkFuer = (runId) => _nullishCoalesce((_nullishCoalesce(_optionalChain([item, 'optionalAccess', _240 => _240.szenen_run_links]), () => ( []))).find((l) => l.prompt_run_id === runId), () => ( (_optionalChain([item, 'optionalAccess', _241 => _241.szenen_links]) && item.szenen_links.prompt_run_id === runId ? item.szenen_links : null)));
|
|
7824
7981
|
const ergebnis = [];
|
|
7825
7982
|
for (const runId of laeufe) {
|
|
7826
7983
|
const z = zugehoerigkeitOf({ szenen: { prompt_run_id: runId }, szenen_links: linkFuer(runId) });
|
|
@@ -7966,7 +8123,7 @@ function parseLegacyRecentTags(raw) {
|
|
|
7966
8123
|
}
|
|
7967
8124
|
return null;
|
|
7968
8125
|
}).filter((entry) => entry !== null).slice(0, 10);
|
|
7969
|
-
} catch (
|
|
8126
|
+
} catch (e38) {
|
|
7970
8127
|
return [];
|
|
7971
8128
|
}
|
|
7972
8129
|
}
|
|
@@ -8093,4 +8250,6 @@ async function runTagsLegacyImport(options) {
|
|
|
8093
8250
|
|
|
8094
8251
|
|
|
8095
8252
|
|
|
8096
|
-
|
|
8253
|
+
|
|
8254
|
+
|
|
8255
|
+
exports.AvatarArchitectApp = AvatarArchitectApp; exports.CURRENT_TAG_EVENT_VERSION = CURRENT_TAG_EVENT_VERSION; exports.CollapsibleCard = CollapsibleCard; exports.CompactDropdown = CompactDropdown; exports.FaApp = FaApp; exports.FaToolsBadge = FaToolsBadge; exports.FlowBridgePanel = FlowBridgePanel; exports.FlowWorkspacePicker = FlowWorkspacePicker; exports.GLOBAL_STYLES = GLOBAL_STYLES; exports.HfMediaSyncTab = HfMediaSyncTab; exports.HistoryPanel = HistoryPanel; exports.InspectPanel = InspectPanel; exports.LIBRARY_CUTOVER_MARKER = LIBRARY_CUTOVER_MARKER; exports.LIBRARY_SLICE_SCHEMA_VERSION = LIBRARY_SLICE_SCHEMA_VERSION; exports.LIB_VERSION = version; exports.LabBlend = LabBlend; exports.LabCompare = LabCompare; exports.LabFrameExtractor = LabFrameExtractor; exports.LabImagePicker = LabImagePicker; exports.LabLoop = LabLoop; exports.LabRemix = LabRemix; exports.LabsTab = LabsTab; exports.LibraryView = LibraryView; exports.ListView = ListView; exports.MediaLibrary = MediaLibrary; exports.PillButton = PillButton; exports.PromptTab = PromptTab; exports.SCOPE_MAP = SCOPE_MAP; exports.SectionLabel = SectionLabel; exports.ServerTab = ServerTab; exports.SetupPanel = SetupPanel; exports.TAGS_CUTOVER_MARKER = TAGS_CUTOVER_MARKER; exports.TAGS_SLICE_SCHEMA_VERSION = TAGS_SLICE_SCHEMA_VERSION; exports.TagBaseSection = TagBaseSection; exports.TagManager = TagManager; exports.TagManagerPanel = TagManagerPanel; exports.ZugehoerigkeitLinks = ZugehoerigkeitLinks; exports.autoLabel = autoLabel; exports.buildBlendInstruction = buildBlendInstruction; exports.buildCompareInstruction = buildCompareInstruction; exports.buildFallbackPrompt = buildFallbackPrompt; exports.buildGenerationPrompt = buildGenerationPrompt; exports.buildImageGenerationOptions = buildImageGenerationOptions; exports.buildLoopInstruction = buildLoopInstruction; exports.buildPromptTabPayload = buildPromptTabPayload; exports.buildReferenceImageMediaIds = buildReferenceImageMediaIds; exports.buildRemixInstruction = buildRemixInstruction; exports.buildScanInstruction = buildScanInstruction; exports.cleanAiResponse = cleanAiResponse; exports.createFaStore = createFaStore; exports.createFlowBridgeClient = createFlowBridgeClient; exports.createFlowServices = createFlowServices; exports.createInMemoryLibraryDataSource = createInMemoryLibraryDataSource; exports.createInMemoryWorkspacePersistence = createInMemoryWorkspacePersistence; exports.createLibraryDefault = createLibraryDefault; exports.createPersistenceCoordinator = createPersistenceCoordinator; exports.createTagCreatedEvent = createTagCreatedEvent; exports.createTagUpdatedEvent = createTagUpdatedEvent; exports.createTagsDefault = createTagsDefault; exports.deriveTagBaseWorkspaceTags = deriveTagBaseWorkspaceTags; exports.deriveTagViewModel = deriveTagViewModel; exports.formatTreeToMarkdown = formatTreeToMarkdown; exports.frameToGeneration = frameToGeneration; exports.getFormattedTimestamp = getFormattedTimestamp; exports.getHFToken = _chunkVSHSZEGVjs.getHFToken; exports.getSessionClientId = _chunkVSHSZEGVjs.getSessionClientId; exports.groupGenerationsToLabItems = groupGenerationsToLabItems; exports.hatNavigationsziele = hatNavigationsziele; exports.hfBatchArchive = _chunkVSHSZEGVjs.hfBatchArchive; exports.hfBootstrapFromLegacy = _chunkVSHSZEGVjs.hfBootstrapFromLegacy; exports.hfListDir = _chunkVSHSZEGVjs.hfListDir; exports.hfLoadImageAsBase64 = _chunkVSHSZEGVjs.hfLoadImageAsBase64; exports.hfUploadImage = _chunkVSHSZEGVjs.hfUploadImage; exports.hfUploadSmallFile = _chunkVSHSZEGVjs.hfUploadSmallFile; exports.injectXMPMetadata = injectXMPMetadata; exports.interpretSdkError = interpretSdkError; exports.libraryContract = libraryContract; exports.libraryReactDescriptor = libraryReactDescriptor; exports.listCategories = listCategories; exports.loadHFState = _chunkVSHSZEGVjs.loadHFState; exports.loadPendingEvents = _chunkVSHSZEGVjs.loadPendingEvents; exports.loadTagBase = loadTagBase; exports.parseLegacyLibraryFilters = parseLegacyLibraryFilters; exports.parseLegacyRecentTags = parseLegacyRecentTags; exports.parsePromptFile = parsePromptFile; exports.parsePromptResponse = parsePromptResponse; exports.runLegacyMigration = runLegacyMigration; exports.runLibraryLegacyImport = runLibraryLegacyImport; exports.runTagsLegacyImport = runTagsLegacyImport; exports.setHFToken = _chunkVSHSZEGVjs.setHFToken; exports.tagsContract = tagsContract; exports.tagsReactDescriptor = tagsReactDescriptor; exports.tsFromEventPath = _chunkVSHSZEGVjs.tsFromEventPath; exports.useFaSlice = useFaSlice; exports.useFaSliceMeta = useFaSliceMeta; exports.useHFState = useHFState; exports.useKeyboardNavigation = useKeyboardNavigation; exports.useOnClickOutside = useOnClickOutside; exports.useTagBase = useTagBase; exports.validateTagBaseSelection = validateTagBaseSelection; exports.writeHFEvent = _chunkVSHSZEGVjs.writeHFEvent; exports.writeTagEvent = writeTagEvent; exports.zugehoerigkeitOf = zugehoerigkeitOf; exports.zugehoerigkeitenOf = zugehoerigkeitenOf;
|