iobroker.alias-workbench 0.8.0

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.
Files changed (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +516 -0
  3. package/admin/alias-workbench.png +0 -0
  4. package/admin/css/werkbank.css +916 -0
  5. package/admin/detector.js +1 -0
  6. package/admin/geraetewissen/tasmota-befehle.json +116 -0
  7. package/admin/i18n/de.json +552 -0
  8. package/admin/i18n/en.json +552 -0
  9. package/admin/js/aufzaehlungen.js +332 -0
  10. package/admin/js/basis.js +36 -0
  11. package/admin/js/baum.js +453 -0
  12. package/admin/js/detail.js +335 -0
  13. package/admin/js/einstellungen.js +40 -0
  14. package/admin/js/entwurf.js +908 -0
  15. package/admin/js/enums.js +23 -0
  16. package/admin/js/ergebnis.js +934 -0
  17. package/admin/js/erkennung.js +126 -0
  18. package/admin/js/katalog.js +313 -0
  19. package/admin/js/mqtt.js +885 -0
  20. package/admin/js/musternamen.js +94 -0
  21. package/admin/js/musterwahl.js +334 -0
  22. package/admin/js/objekte.js +243 -0
  23. package/admin/js/pruefungen.js +130 -0
  24. package/admin/js/quellentausch.js +570 -0
  25. package/admin/js/rollenwahl.js +199 -0
  26. package/admin/js/schreiben.js +1537 -0
  27. package/admin/js/sprache.js +137 -0
  28. package/admin/js/start.js +39 -0
  29. package/admin/js/verbindung.js +10 -0
  30. package/admin/js/vorlagen.js +572 -0
  31. package/admin/js/vorlagenblatt.js +1907 -0
  32. package/admin/js/vorschlagen.js +391 -0
  33. package/admin/js/werte.js +193 -0
  34. package/admin/js/zielleiste.js +339 -0
  35. package/admin/js/zuordnung.js +695 -0
  36. package/admin/js/zustand.js +47 -0
  37. package/admin/js/zustandsliste.js +515 -0
  38. package/admin/jsonConfig.json +249 -0
  39. package/admin/tab.html +148 -0
  40. package/admin/vorlagen/hm-dimmer.json +204 -0
  41. package/admin/vorlagen/hm-fensterkontakt-hm.json +176 -0
  42. package/admin/vorlagen/hm-fensterkontakt-hmip.json +191 -0
  43. package/admin/vorlagen/hm-heizgruppe.json +214 -0
  44. package/admin/vorlagen/hm-heizkoerper.json +236 -0
  45. package/admin/vorlagen/hm-rollladen.json +190 -0
  46. package/admin/vorlagen/hm-schaltaktor-lampe.json +197 -0
  47. package/admin/vorlagen/hm-schaltaktor-mehrfach.json +203 -0
  48. package/admin/vorlagen/hm-schaltaktor-steckdose.json +197 -0
  49. package/admin/vorlagen/hm-temperatur-feuchte.json +166 -0
  50. package/admin/vorlagen/hm-wandthermostat.json +228 -0
  51. package/admin/vorlagen/index.json +21 -0
  52. package/admin/vorlagen/messpunkt.json +225 -0
  53. package/admin/vorlagen/tasmota-lampe.json +263 -0
  54. package/admin/vorlagen/tasmota-mehrfach.json +203 -0
  55. package/admin/vorlagen/tasmota-rgb.json +239 -0
  56. package/admin/vorlagen/tasmota-steckdose.json +265 -0
  57. package/io-package.json +122 -0
  58. package/package.json +48 -0
@@ -0,0 +1,916 @@
1
+ /* Farb- und Formensprache des Admin 8 (gemessen am Produktivsystem,
2
+ 25.08.2026): Slate-Grau statt Warmgrau, Akzentblau #137BF8, Karten
3
+ 12 px rund mit 1px #E2E8F0 und hauchduennem Schatten, Knoepfe 8 px,
4
+ Chips als getoente Pillen (Farbe mit ~16% Deckung als Grund, die
5
+ volle Farbe als Schrift). */
6
+ :root {
7
+ --ground:#F1F5F9; --surface:#FFFFFF; --surface-2:#F1F5F9; --surface-3:#E2E8F0;
8
+ --ink:#101827; --ink-2:#475569; --ink-3:#8A94A6;
9
+ --line:#E2E8F0; --line-strong:#CBD5E1;
10
+ --accent:#137BF8; --accent-ink:#FFFFFF; --accent-soft:#DCEAFD;
11
+ --hover:#4B9BFA; --hover-ink:#FFFFFF;
12
+ --ok:#1E8E3E; --ok-soft:#DCEDE2;
13
+ --warn:#C77700; --warn-soft:#F7EBD8;
14
+ --bad:#C0392B; --bad-soft:#F8E3DF;
15
+ --shadow:0 1px 2px rgba(15,23,42,.05);
16
+ --shadow-hoch:0 1px 2px rgba(15,23,42,.06), 0 10px 30px rgba(15,23,42,.12);
17
+ --sans:"Segoe UI Variable Text","Segoe UI",system-ui,-apple-system,Roboto,Arial,sans-serif;
18
+ --mono:"Cascadia Mono","Cascadia Code",ui-monospace,"JetBrains Mono",Consolas,monospace;
19
+ --pfeil:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M0 0h10L5 6z' fill='%238A94A6'/%3E%3C/svg%3E");
20
+ --r:8px; /* Knoepfe, Felder, Zeilen */
21
+ --r-lg:12px; /* Karten, Dialoge, Kaesten */
22
+ --r-sm:6px; /* kleine Marken */
23
+ }
24
+ /* Vier Farbthemen des Admin (Sonnen-Knopf, gemessen an 8.0.2 am
25
+ 25.08.2026): modernLight #137BF8, modernDark #137BF8 auf #121A26,
26
+ klassisch light #3399CC, klassisch dark #4DABF5 auf #121212. Der
27
+ Admin nennt sein Thema in der Reiter-Adresse (react=...), tab.html
28
+ setzt daraus data-adminthema. Ist es gesetzt, gilt genau diese
29
+ Palette; ohne (Reiter direkt geoeffnet) faellt die Werkbank auf die
30
+ Systemeinstellung hell/dunkel zurueck. */
31
+ @media (prefers-color-scheme: dark) {
32
+ :root:not([data-adminthema]) {
33
+ --ground:#0B1220; --surface:#101a2c; --surface-2:#182338; --surface-3:#223045;
34
+ --ink:#E2E8F0; --ink-2:#A7B4C6; --ink-3:#6E7E95;
35
+ --line:#223045; --line-strong:#334760;
36
+ --accent:#5CA5F9; --accent-ink:#081527; --accent-soft:#16304F;
37
+ --hover:#0B62D6; --hover-ink:#FFFFFF;
38
+ --ok:#5FBF80; --ok-soft:#122C1C;
39
+ --warn:#D3A44A; --warn-soft:#302713;
40
+ --bad:#E1806C; --bad-soft:#33201C;
41
+ --shadow:0 1px 2px rgba(0,0,0,.4);
42
+ --shadow-hoch:0 1px 2px rgba(0,0,0,.4), 0 10px 30px rgba(0,0,0,.35);
43
+ --pfeil:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M0 0h10L5 6z' fill='%236E7E95'/%3E%3C/svg%3E");
44
+ }
45
+ }
46
+ /* modernLight ist die Grundpalette oben — der blosse Attributwert
47
+ schaltet nur den Dunkel-Rueckfall ab. */
48
+ :root[data-adminthema="modernDark"] {
49
+ --ground:#0C1320; --surface:#121A26; --surface-2:#1A2434; --surface-3:#243349;
50
+ --ink:#E8EDF5; --ink-2:#A9B6C9; --ink-3:#6E7E95;
51
+ --line:#243349; --line-strong:#33475F;
52
+ --accent:#137BF8; --accent-ink:#FFFFFF; --accent-soft:#16304F;
53
+ --hover:#0B62D6; --hover-ink:#FFFFFF;
54
+ --ok:#5FBF80; --ok-soft:#122C1C;
55
+ --warn:#D3A44A; --warn-soft:#302713;
56
+ --bad:#E1806C; --bad-soft:#33201C;
57
+ --shadow:0 1px 2px rgba(0,0,0,.4);
58
+ --shadow-hoch:0 1px 2px rgba(0,0,0,.4), 0 10px 30px rgba(0,0,0,.35);
59
+ --pfeil:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M0 0h10L5 6z' fill='%236E7E95'/%3E%3C/svg%3E");
60
+ }
61
+ :root[data-adminthema="light"] {
62
+ --ground:#F0F0F0; --surface:#FFFFFF; --surface-2:#F0F0F0; --surface-3:#E2E2E2;
63
+ --ink:#212121; --ink-2:#525252; --ink-3:#8C8C8C;
64
+ --line:#E0E0E0; --line-strong:#C6C6C6;
65
+ --accent:#3399CC; --accent-ink:#FFFFFF; --accent-soft:#DBEEF7;
66
+ --hover:#76D0FD; --hover-ink:#212121;
67
+ --ok:#388E3C; --ok-soft:#DFF0E0;
68
+ --warn:#C77700; --warn-soft:#F7EBD8;
69
+ --bad:#C0392B; --bad-soft:#F8E3DF;
70
+ --shadow:0 1px 2px rgba(0,0,0,.06);
71
+ --shadow-hoch:0 1px 2px rgba(0,0,0,.08), 0 10px 30px rgba(0,0,0,.14);
72
+ --pfeil:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M0 0h10L5 6z' fill='%238C8C8C'/%3E%3C/svg%3E");
73
+ }
74
+ :root[data-adminthema="dark"] {
75
+ --ground:#0F0F0F; --surface:#1B1B1B; --surface-2:#252525; --surface-3:#303030;
76
+ --ink:#FFFFFF; --ink-2:#C9C9C9; --ink-3:#909090;
77
+ --line:#2E2E2E; --line-strong:#414141;
78
+ --accent:#4DABF5; --accent-ink:#FFFFFF; --accent-soft:#173A57;
79
+ --hover:#3577AB; --hover-ink:#FFFFFF;
80
+ --ok:#66BB6A; --ok-soft:#143318;
81
+ --warn:#D3A44A; --warn-soft:#302713;
82
+ --bad:#E1806C; --bad-soft:#33201C;
83
+ --shadow:0 1px 2px rgba(0,0,0,.5);
84
+ --shadow-hoch:0 1px 2px rgba(0,0,0,.5), 0 10px 30px rgba(0,0,0,.45);
85
+ --pfeil:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M0 0h10L5 6z' fill='%23909090'/%3E%3C/svg%3E");
86
+ }
87
+
88
+ * { box-sizing:border-box; }
89
+ /* Grundgestalt aller tx-Felder, per :where() ohne Gewicht: jede
90
+ Bereichsregel (.detail, .zielbar, .musterwahl ...) gewinnt. Ohne
91
+ diese Grundlage fielen Felder in Bereichen ohne eigene Regel auf
92
+ die Browservoreinstellung zurueck - im Vorlagenblatt standen sie
93
+ in Arial mit eckigen Kanten (Ricardo, 25.08.2026). */
94
+ :where(input.tx, select.tx) {
95
+ font-family:var(--mono); font-size:12px; padding:4px 7px;
96
+ border:1px solid var(--line-strong); border-radius:var(--r-sm);
97
+ background-color:var(--surface); color:var(--ink);
98
+ }
99
+ :where(input.tx, select.tx):disabled { color:var(--ink-3); background-color:var(--surface-2); }
100
+ /* Alle Haekchen in der Akzentfarbe des Themas - nicht nur die der
101
+ Zustandsliste. Die im Vorlagenblatt blieben browserblau. */
102
+ input[type="checkbox"], input[type="radio"] { accent-color:var(--accent); }
103
+
104
+ /* Jedes Auswahlfeld traegt denselben Pfeil - nicht den des Browsers.
105
+ Groesse nach dem festgelegten Mass der Klapp-Pfeile (14px-Klasse,
106
+ siehe .ca2): Dreieck 10×6. */
107
+ select.tx, input.musterwahl, input.rollenwahl {
108
+ appearance:none; -webkit-appearance:none;
109
+ background-image:var(--pfeil); background-repeat:no-repeat;
110
+ background-position:right 7px center; background-size:10px 6px;
111
+ padding-right:24px;
112
+ }
113
+ html, body { height:100%; }
114
+ /* Spalte: Banner und Kopfzeile nehmen ihre Hoehe, der Rest gehoert der
115
+ Arbeitsflaeche. Vorher bekam .split volle 100% und schob die Fussleiste
116
+ genau um die Hoehe von Banner plus Kopf unter den Rand. */
117
+ body {
118
+ margin:0; background:var(--ground); color:var(--ink);
119
+ font-family:var(--sans); font-size:14px; line-height:1.5;
120
+ -webkit-font-smoothing:antialiased; overflow:hidden;
121
+ display:flex; flex-direction:column; height:100%;
122
+ }
123
+ header.top { flex:0 0 auto; }
124
+ code,.mono { font-family:var(--mono); font-variant-ligatures:none; }
125
+ :focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
126
+ [hidden] { display:none !important; }
127
+
128
+ header.top {
129
+ display:flex; align-items:center; gap:12px; padding:9px 16px;
130
+ background:var(--surface); border-bottom:1px solid var(--line); flex-wrap:wrap;
131
+ }
132
+ header.top h1 { margin:0; font-size:15px; font-weight:650; }
133
+ header.top .meta { font-family:var(--mono); font-size:11px; color:var(--ink-3); }
134
+ header.top .sp { flex:1; }
135
+ .conn { font-size:11.5px; font-family:var(--mono); padding:2px 10px; border-radius:999px; }
136
+ .conn.on { background:var(--ok-soft); color:var(--ok); }
137
+ .conn.off { background:var(--bad-soft); color:var(--bad); }
138
+
139
+ .split {
140
+ display:grid; grid-template-columns:minmax(280px,32%) minmax(0,1fr);
141
+ flex:1 1 auto; min-height:0;
142
+ }
143
+ @media (max-width:880px) {
144
+ body { overflow:auto; display:block; height:auto; }
145
+ .split { grid-template-columns:minmax(0,1fr); height:auto; }
146
+ .pickpane { height:240px; }
147
+ }
148
+ .pickpane, .respane { display:flex; flex-direction:column; min-height:0; min-width:0; }
149
+ .pickpane { background:var(--surface); border-right:1px solid var(--line); }
150
+ .respane { background:var(--ground); }
151
+
152
+ .panehead {
153
+ padding:7px 11px; border-bottom:1px solid var(--line); background:var(--surface);
154
+ display:flex; align-items:center; gap:8px; flex:0 0 auto;
155
+ }
156
+ .panehead .lbl { font-size:9.5px; font-weight:700; letter-spacing:.07em; text-transform:uppercase; color:var(--ink-3); }
157
+ .search {
158
+ flex:1; min-width:0; font-family:var(--mono); font-size:12px;
159
+ padding:4px 8px; border:1px solid var(--line-strong); border-radius:var(--r-sm);
160
+ background:var(--ground); color:var(--ink);
161
+ }
162
+ .scroll { overflow:auto; flex:1 1 auto; min-height:0; }
163
+
164
+ .tree { font-family:var(--mono); font-size:12.5px; padding:5px 3px 24px; }
165
+ .tree ul { list-style:none; margin:0; padding-left:12px; }
166
+ .tree > ul { padding-left:1px; }
167
+ .tree .node {
168
+ display:flex; align-items:center; gap:5px; padding:2px 6px;
169
+ border-radius:var(--r); white-space:nowrap;
170
+ }
171
+ .tree .node.pick { cursor:pointer; }
172
+ /* Mauszeiger und Auswahl wie im Objekt-Explorer des Admin: zwei
173
+ Blautoene je Thema, die Auswahl (dunkler) gewinnt gegen den
174
+ Mauszeiger. Kinderfarben erben, sonst staende blasses Grau auf
175
+ kraeftigem Blau. */
176
+ .tree .node.pick:hover:not(.sel) { background:var(--hover); color:var(--hover-ink); }
177
+ /* Ueber der gewaehlten Zeile bleibt die Auswahl dominant - der Zeiger
178
+ dunkelt sie nur leicht ab (Material: Zustand + Ueberlagerung, der
179
+ fluechtige Hinweis ersetzt nicht den festen Zustand). Der Admin
180
+ selbst laesst dort die Hover-Farbe gewinnen; die Konvention ist
181
+ andersherum, und Ricardo hat sich fuer die Konvention entschieden. */
182
+ .tree .node.sel:hover { background:color-mix(in srgb, var(--accent) 90%, #000); }
183
+ .tree .node.pick:hover:not(.sel) .nam,
184
+ .tree .node.pick:hover:not(.sel) .cnt,
185
+ .tree .node.pick:hover:not(.sel) .grp { color:inherit; opacity:.85; }
186
+ .tree .node.pick:hover:not(.sel) .kind { background:rgba(255,255,255,.3); color:inherit; }
187
+ .tree .node.pick:hover:not(.sel) .geraetepunkt { color:inherit; }
188
+ .tree .node.sel { background:var(--accent); color:var(--accent-ink); font-weight:600; }
189
+ .tree .node.sel .kind { background:rgba(255,255,255,.22); color:inherit; }
190
+ /* Die Vorlagenliste benutzt dieselben Knotenzeilen, hat aber statt
191
+ `kind`/`nam`/`cnt` ein Abzeichen, einen Namen und rechts die Kennung.
192
+ Auf der Akzentflaeche muessen die drei mitziehen, sonst steht auf der
193
+ markierten Zeile graue Schrift auf farbigem Grund. */
194
+ .tree .node.sel .chip { background:rgba(255,255,255,.22); color:var(--accent-ink); border-color:transparent; }
195
+ .tree .node.sel .nm { color:var(--accent-ink); }
196
+ .tree .node.sel > span { color:var(--accent-ink) !important; }
197
+ .tree .kind {
198
+ font-size:8px; padding:0 4px; border-radius:4px; background:var(--surface-3);
199
+ color:var(--ink-3); text-transform:uppercase; letter-spacing:.04em;
200
+ font-family:var(--sans); font-weight:700; flex:0 0 auto;
201
+ }
202
+ .tree .idstueck { flex:0 0 auto; }
203
+ /* Der Name weicht zurueck: gedaempft, und er ist es, der gekuerzt wird,
204
+ wenn die Spalte nicht reicht. Die Kennung bleibt vollstaendig. */
205
+ .tree .nam, .nm3 .nam {
206
+ color:var(--ink-3); font-family:var(--sans); font-size:11px;
207
+ flex:0 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis;
208
+ }
209
+ .nm3 .nam { margin-left:8px; }
210
+ .tree .node.sel .nam { color:var(--accent-ink); opacity:.85; }
211
+ .tree .cnt { margin-left:auto; font-size:9.5px; color:var(--ink-3); }
212
+ .tree .node.sel .cnt { color:var(--accent-ink); }
213
+ /* 11 px waren zu klein, um als Schaltflaeche erkannt zu werden — und
214
+ in der blassesten Farbe der Oberflaeche. Als Mindestmass fuer eine
215
+ Trefferflaeche gelten 24 px; so weit gehen wir hier nicht, aber
216
+ deutlich naeher heran. */
217
+ .tree .tw {
218
+ cursor:pointer; width:18px; text-align:center; color:var(--ink-2);
219
+ flex:0 0 auto; font-size:12px; line-height:1; border-radius:var(--r-sm);
220
+ }
221
+ .tree .tw:hover { color:var(--accent); background:var(--accent-soft); }
222
+ .tree .grp { color:var(--ink-3); }
223
+
224
+ .resscroll { overflow:auto; flex:1 1 auto; min-height:0; padding:14px; }
225
+ .resinner { max-width:820px; margin:0 auto; display:flex; flex-direction:column; gap:13px; }
226
+
227
+ .rhead .id { font-family:var(--mono); font-size:16px; font-weight:700; word-break:break-all; }
228
+ .rhead .pfad {
229
+ font-family:var(--mono); font-size:11px; color:var(--ink-3);
230
+ margin-top:3px; word-break:break-all;
231
+ }
232
+ .rhead .sub { font-family:var(--mono); font-size:11.5px; color:var(--ink-3); margin-top:2px; }
233
+
234
+ .card {
235
+ background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg);
236
+ box-shadow:var(--shadow); overflow:hidden;
237
+ }
238
+ .card > .ch {
239
+ display:flex; align-items:center; gap:10px; padding:9px 13px;
240
+ border-bottom:1px solid var(--line); background:var(--surface-2); flex-wrap:wrap;
241
+ }
242
+ .card > .ch .typ { font-family:var(--mono); font-size:15px; font-weight:700; color:var(--accent); }
243
+ .card.infod { border-style:dashed; }
244
+ .card.infod > .ch .typ { color:var(--ink-3); }
245
+
246
+ .slot {
247
+ display:grid; grid-template-columns:15px 130px 1fr auto; gap:9px; align-items:center;
248
+ padding:5px 13px; border-bottom:1px solid var(--line); font-family:var(--mono); font-size:12px;
249
+ }
250
+ .slot:last-child { border-bottom:0; }
251
+ .slot .mk { text-align:center; }
252
+ .slot.hit .mk { color:var(--ok); }
253
+ .slot.miss .mk { color:var(--bad); }
254
+ .slot.free .mk { color:var(--ink-3); }
255
+ .slot .sn { font-weight:600; }
256
+ .slot.free .sn, .slot.free .who { color:var(--ink-3); }
257
+ .slot .who { color:var(--ink-2); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
258
+ .slot .v { font-variant-numeric:tabular-nums; white-space:nowrap; color:var(--ink); }
259
+ .slot .rx { font-size:10px; color:var(--ink-3); }
260
+ /* Vorlagentabelle: erst die drei Entscheidungen, dann der Text. Ein
261
+ langer Name darf nichts mehr verschieben — deshalb feste Spalten
262
+ zuerst, und die Textspalten duerfen schrumpfen (min-width:0). */
263
+ .vzeile { grid-template-columns:66px 58px 84px minmax(0,1.4fr) minmax(0,1fr); }
264
+ .vzeile > * { min-width:0; }
265
+ .vzeile .sn { word-break:break-all; font-weight:600; }
266
+ .vzeile .pf { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
267
+ .vkopf { font-weight:600; opacity:.7; }
268
+ .vkopf > span { font-size:10px; color:var(--ink-3); }
269
+
270
+ .stlist .row {
271
+ display:grid; grid-template-columns:1fr 170px 110px 13px; gap:9px; align-items:center;
272
+ padding:6px 13px; border-bottom:1px solid var(--line); font-size:12.5px; cursor:pointer;
273
+ }
274
+ .stlist .row:last-of-type { border-bottom:0; }
275
+ .stlist .row:hover { background:var(--surface-2); }
276
+ .stlist .row.open { background:var(--surface-2); }
277
+ .stlist .row .nm { font-family:var(--mono); font-weight:600; overflow:hidden; text-overflow:ellipsis; }
278
+ .stlist .row .nm em { font-style:normal; font-weight:400; color:var(--ink-3); font-size:11px; margin-left:6px; }
279
+ .stlist .row .ro { font-family:var(--mono); font-size:11px; color:var(--ink-3); overflow:hidden; text-overflow:ellipsis; }
280
+ .stlist .row .vl { font-family:var(--mono); text-align:right; font-variant-numeric:tabular-nums; overflow:hidden; text-overflow:ellipsis; }
281
+ .stlist .row .ca { font-size:9px; color:var(--ink-3); text-align:center; }
282
+
283
+ .detail {
284
+ padding:11px 13px 13px 26px; background:var(--surface-2);
285
+ border-bottom:1px solid var(--line); font-family:var(--mono); font-size:11.5px;
286
+ }
287
+ .detail .dr { display:grid; grid-template-columns:88px 1fr; gap:8px; padding:3px 0; align-items:start; }
288
+ .detail .k {
289
+ font-family:var(--sans); font-size:9px; text-transform:uppercase; letter-spacing:.06em;
290
+ color:var(--ink-3); font-weight:700; padding-top:3px;
291
+ }
292
+ .detail .raw {
293
+ background:var(--surface); border:1px solid var(--line); border-radius:var(--r-sm);
294
+ padding:5px 6px; word-break:break-all; color:var(--ink-2);
295
+ max-height:80px; overflow:auto; line-height:1.5;
296
+ }
297
+ .detail .res { font-size:14px; font-weight:700; font-variant-numeric:tabular-nums; }
298
+
299
+ /* Vergleich im Trockenlauf: links der Bestand, rechts was entstuende,
300
+ Zeile gegen Zeile wie in einem Vergleichswerkzeug (Ricardo,
301
+ 25.08.2026). Geaenderte Zeilen gelb, entfallende rot, neue gruen;
302
+ die leere Gegenzeile bleibt gedeckelt, damit die Luecke sichtbar
303
+ ist statt nur weiss zu wirken. */
304
+ .dvgl {
305
+ display:grid; grid-template-columns:1fr 1fr; gap:0 8px;
306
+ margin:4px 12px 10px; align-items:stretch;
307
+ }
308
+ .dvgl .dkopf {
309
+ font-family:var(--sans); font-size:8.5px; letter-spacing:.06em;
310
+ text-transform:uppercase; color:var(--ink-3); font-weight:700;
311
+ padding:0 5px 3px;
312
+ }
313
+ .dvgl .dz {
314
+ font-family:var(--mono); font-size:11px; line-height:1.55;
315
+ white-space:pre-wrap; word-break:break-all; padding:0 5px;
316
+ color:var(--ink-2); border-left:2px solid transparent;
317
+ }
318
+ .dvgl .dz.anders { background:var(--warn-soft); color:var(--ink); border-left-color:var(--warn); }
319
+ .dvgl .dz.l.weg { background:var(--bad-soft); color:var(--ink); border-left-color:var(--bad); }
320
+ .dvgl .dz.r.dazu { background:var(--ok-soft); color:var(--ink); border-left-color:var(--ok); }
321
+ .dvgl .dz.r.weg, .dvgl .dz.l.dazu { background:var(--surface-2); }
322
+
323
+ .chip {
324
+ display:inline-flex; align-items:center; gap:4px; font-size:10px; font-weight:700;
325
+ letter-spacing:.04em; text-transform:uppercase; padding:2px 8px; border-radius:999px; white-space:nowrap;
326
+ }
327
+ .chip.ok{background:var(--ok-soft);color:var(--ok);} .chip.warn{background:var(--warn-soft);color:var(--warn);}
328
+ .chip.bad{background:var(--bad-soft);color:var(--bad);} .chip.mut{background:var(--surface-3);color:var(--ink-3);}
329
+
330
+ .aside {
331
+ font-size:12px; color:var(--ink-2); line-height:1.6;
332
+ background:var(--surface); border:1px solid var(--line); border-left:2px solid var(--accent);
333
+ padding:9px 11px; border-radius:0 var(--r-lg) var(--r-lg) 0;
334
+ }
335
+ .aside.w { border-left-color:var(--warn); }
336
+ .aside b { color:var(--ink); }
337
+
338
+ .empty { color:var(--ink-3); font-size:13px; padding:36px 8px; text-align:center; }
339
+ /* Der Erklaertext der leeren Seite: lesbar breit, nicht ueber die
340
+ ganze Flaeche gezogen, zweiter Absatz gedaempft. */
341
+ .leerhilfe { max-width:520px; margin:0 auto; text-align:left; line-height:1.6; }
342
+
343
+ /* Der Auswahlbaum im Tauschdialog: feste Hoehe, damit der Dialog nicht
344
+ bei jedem Aufklappen springt, und eigener Rahmen wie ein Feld. */
345
+ .tauschbaum {
346
+ height:230px; overflow:auto; margin-top:4px;
347
+ border:1px solid var(--line-strong); border-radius:var(--r-sm);
348
+ background:var(--surface); padding:4px 0;
349
+ }
350
+ .tauschbaum .node { cursor:default; }
351
+ .tauschbaum .node.pick { cursor:pointer; }
352
+ .tauschbaum .empty { padding:18px 8px; }
353
+
354
+ /* „Vorlage: x" an einer Zeile, deren Bestand von der Vorlage abweicht -
355
+ gedaempfter als die Marke „geaendert", es ist ja nur ein Angebot. */
356
+ .erow .geae.tplabw { color:var(--ink-3); background:var(--surface-2); }
357
+ .leerhilfe .lh2 { margin-top:11px; font-size:12px; color:var(--ink-3); }
358
+
359
+ .footbar {
360
+ flex:0 0 auto; border-top:1px solid var(--line); background:var(--surface);
361
+ padding:8px 14px; display:flex; gap:9px; align-items:center; flex-wrap:wrap;
362
+ position:sticky; bottom:0; z-index:2;
363
+ }
364
+ button.btn {
365
+ font:inherit; font-size:12.5px; border-radius:var(--r); padding:5px 11px;
366
+ border:1px solid var(--line-strong); background:var(--surface); color:var(--ink); cursor:pointer;
367
+ }
368
+ button.btn:hover:not(:disabled) { background:var(--surface-2); }
369
+ button.btn:disabled { opacity:.4; cursor:not-allowed; }
370
+ /* Ein laufender Knopf traegt einen Drehkreis - sonst sieht gesperrt
371
+ aus wie tot, obwohl gerade gearbeitet wird. */
372
+ /* box-sizing:border-box gilt projektweit - der Ring ist also samt
373
+ Rand 12 px hoch, und -6 px setzen ihn exakt auf die Mitte. Rechts
374
+ genug Luft, damit er nicht am Text klebt. */
375
+ button.laedt { position:relative; padding-right:30px; opacity:.75; }
376
+ button.laedt::after {
377
+ content:""; position:absolute; right:9px; top:50%; margin-top:-6px;
378
+ width:12px; height:12px; border-radius:50%;
379
+ border:2px solid var(--line-strong); border-top-color:var(--accent);
380
+ animation:drehkreis .8s linear infinite;
381
+ }
382
+ @keyframes drehkreis { to { transform:rotate(360deg); } }
383
+ @media (prefers-reduced-motion: reduce) {
384
+ button.laedt::after { animation:none; border-top-color:var(--line-strong); }
385
+ }
386
+ /* Warum die Knoepfe links daneben gesperrt sind. */
387
+ .sperrgrund { font-size:11.5px; color:var(--warn); }
388
+
389
+ /* ---- Kopf mit Musterwahl ---- */
390
+ .rhead { display:flex; gap:12px; align-items:flex-start; flex-wrap:wrap; justify-content:space-between; }
391
+ .verdictwrap {
392
+ border:1px solid var(--ok); background:var(--ok-soft); border-radius:var(--r);
393
+ padding:6px 8px; display:flex; flex-direction:column; gap:5px; align-items:flex-start;
394
+ }
395
+ .verdictwrap.bad { border-color:var(--bad); background:var(--bad-soft); }
396
+ .musterwahl {
397
+ font-family:var(--mono); font-size:14px; font-weight:700;
398
+ border:1px solid var(--line-strong); border-radius:var(--r-sm);
399
+ background-color:var(--surface); color:var(--ink);
400
+ padding:2px 24px 2px 6px; width:290px; max-width:290px;
401
+ }
402
+ .vmeta { display:flex; gap:5px; align-items:center; flex-wrap:wrap; }
403
+
404
+ /* ---- Geraetekarte ---- */
405
+
406
+ /* ---- Werkzeugleiste + Kopfzeile der Liste ---- */
407
+ .listbar { display:flex; align-items:center; gap:7px; flex-wrap:wrap; padding:6px 15px;
408
+ border-top:1px solid var(--line); border-bottom:1px solid var(--line);
409
+ background:var(--surface-2); font-size:11px; color:var(--ink-2); }
410
+ .listbar .cnt { font-family:var(--mono); font-weight:600; color:var(--ink); }
411
+ .listbar .sp2 { flex:1; }
412
+ /* Zweite Zeile fuer die Auswahlknoepfe: `flex-basis:100%` erzwingt den
413
+ Umbruch, damit sie immer geschlossen untereinander stehen statt je
414
+ nach Fensterbreite anders zu brechen. */
415
+ .listbar .chipzeile {
416
+ flex:0 0 100%; display:flex; gap:7px; flex-wrap:wrap;
417
+ align-items:center; margin-top:5px;
418
+ }
419
+ .listbar .chipzeile .weit { margin-left:auto; }
420
+ .listbar button { font:inherit; font-size:11px; cursor:pointer; border:1px solid var(--line-strong);
421
+ border-radius:999px; padding:1px 10px; background:var(--surface); color:var(--ink-2); }
422
+ .listbar button:hover { background:var(--surface-3); color:var(--ink); }
423
+ /* Der Vorschlagsknopf meldet sich, wenn er neu erscheint - drei Wellen,
424
+ dann Ruhe. Ein Ring statt eines Farbwechsels: an einem Knopf liest
425
+ sich Blinken als „kaputt", ein Ring als „hier". */
426
+ @keyframes knopfPochen {
427
+ 0% { box-shadow:0 0 0 0 color-mix(in srgb, var(--accent) 50%, transparent); }
428
+ 70% { box-shadow:0 0 0 8px color-mix(in srgb, var(--accent) 0%, transparent); }
429
+ 100% { box-shadow:0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent); }
430
+ }
431
+ .listbar button.frisch { animation:knopfPochen 1s ease-out 3;
432
+ border-color:var(--accent); color:var(--accent); }
433
+ @media (prefers-reduced-motion: reduce) {
434
+ .listbar button.frisch { animation:none; }
435
+ }
436
+ .lhead { display:grid; grid-template-columns:19px 14px 1fr 150px 105px 12px; gap:8px;
437
+ padding:4px 15px; border-bottom:1px solid var(--line);
438
+ font-size:8.5px; letter-spacing:.06em; text-transform:uppercase; font-weight:700; color:var(--ink-3); }
439
+ .lhead .r { text-align:right; }
440
+ .erow { display:grid; grid-template-columns:19px 14px 1fr 150px 105px 15px; gap:8px; align-items:center;
441
+ padding:6px 15px; border-bottom:1px solid var(--line); font-size:12.5px; cursor:pointer; }
442
+ .erow:last-of-type { border-bottom:0; }
443
+ .erow:hover, .erow.open { background:var(--surface-2); }
444
+ /* Abgewaehlt heisst ausgegraut, nicht durchgestrichen - der Haken
445
+ fehlt ja sichtbar, und durchgestrichen liest sich der Name schlecht. */
446
+ .erow.skip { opacity:.42; }
447
+ .erow input[type="checkbox"] { accent-color:var(--accent); cursor:pointer; margin:0; }
448
+ .erow .mk2 { text-align:center; font-size:11px; }
449
+ .erow .mk2.ok { color:var(--ok); } .erow .mk2.bad { color:var(--bad); } .erow .mk2.out { color:var(--ink-3); }
450
+ .erow .nm3 { font-family:var(--mono); font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
451
+ .erow .nm3 em { font-style:normal; font-weight:400; color:var(--ink-3); font-size:10.5px; margin-left:6px; }
452
+ .erow .nm3 .hand { font-family:var(--sans); font-size:8px; font-weight:700; letter-spacing:.05em;
453
+ text-transform:uppercase; background:var(--surface-3); color:var(--ink-3);
454
+ padding:0 6px; border-radius:999px; margin-left:6px; }
455
+ .erow .nm3 .geae { font-family:var(--sans); font-size:8px; font-weight:700; letter-spacing:.05em;
456
+ text-transform:uppercase; background:var(--warn-soft); color:var(--warn);
457
+ padding:0 6px; border-radius:999px; margin-left:6px; }
458
+ .erow .nm3 .rat { font-family:var(--sans); font-size:8px; font-weight:700; letter-spacing:.05em;
459
+ text-transform:uppercase; background:var(--accent-soft); color:var(--accent);
460
+ padding:0 6px; border-radius:999px; margin-left:6px; }
461
+ .erow .nm3 .ratknopf { font-family:var(--sans); font-size:11px; cursor:pointer; margin-left:5px;
462
+ color:var(--ink-3); padding:0 4px; border-radius:var(--r-sm); }
463
+ .erow .nm3 .ratknopf:hover { background:var(--surface-3); color:var(--ink); }
464
+ .ratleiste { display:flex; align-items:center; gap:9px; flex-wrap:wrap;
465
+ padding:6px 15px; border-bottom:1px solid var(--line);
466
+ background:color-mix(in srgb, var(--accent) 7%, transparent); }
467
+ .ratleiste .zq { color:var(--ink-2); font-size:11.5px; }
468
+ .erow .ro2 { font-family:var(--mono); font-size:10.5px; color:var(--ink-3); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
469
+ .erow .ro2.warnrole { color:var(--warn); font-weight:700; }
470
+ .erow .vl2 { font-family:var(--mono); text-align:right; font-variant-numeric:tabular-nums;
471
+ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
472
+ /* Der Pfeil ist die einzige Anzeige, dass eine Zeile mehr hergibt —
473
+ bei 8,5px in Grau war er nicht zu sehen. Gleiche Groesse, gleiche
474
+ Seite und gleiches Verhalten in beiden Listen. */
475
+ /* Kartenkopf, der sich auf- und zuklappen laesst. */
476
+ .ch.klappbar { cursor:pointer; transition:background .12s; }
477
+ .ch.klappbar:hover { background:var(--surface-2); }
478
+ .ch.klappbar .klappz { color:var(--ink-2); margin-right:2px; }
479
+ .ch.klappbar:hover .klappz { color:var(--accent); }
480
+
481
+ /* 11 px am Zeilenende waren kaum zu sehen. Groesser, kraeftiger, und die
482
+ ganze Zeile faerbt sich beim Ueberfahren — die klappt naemlich auf,
483
+ nicht nur das Zeichen. */
484
+ .erow .ca2, .slot .ca2 { font-size:14px; line-height:1; color:var(--ink-2);
485
+ text-align:center; transition:color .12s; }
486
+ .erow:hover .ca2, .slot.vklick:hover .ca2 { color:var(--accent); }
487
+ .erow.open .ca2, .slot.vklick.offen .ca2 { color:var(--accent); }
488
+ .slot.vklick { cursor:pointer; }
489
+ .slot.vklick:hover, .slot.vklick.offen { background:var(--surface-2); }
490
+
491
+ .addrow { display:flex; align-items:center; gap:7px; width:100%; font:inherit; font-size:12.5px;
492
+ cursor:pointer; padding:8px 15px; border:0; border-top:1px dashed var(--line-strong);
493
+ background:var(--surface); color:var(--accent); font-weight:600; text-align:left; }
494
+ .addrow:hover { background:var(--accent-soft); }
495
+
496
+ /* ---- Bearbeitungsfelder im Detail ---- */
497
+ .detail .fields { display:flex; gap:12px; flex-wrap:wrap; align-items:flex-end; }
498
+ .detail .fld { display:flex; flex-direction:column; gap:2px; }
499
+ .detail .fld > span { font-family:var(--sans); font-size:8.5px; letter-spacing:.06em;
500
+ text-transform:uppercase; color:var(--ink-3); font-weight:700; }
501
+ .detail input.tx, .detail select.tx {
502
+ font-family:var(--mono); font-size:11.5px; padding:3px 5px;
503
+ border:1px solid var(--line-strong); border-radius:var(--r-sm); background-color:var(--surface); color:var(--ink);
504
+ }
505
+ .detail select.tx { padding-right:24px; }
506
+ .detail input.tx.w { width:100%; } .detail select.tx.w { width:100%; }
507
+ .detail input.tx.miss, .detail select.tx.miss { border-color:var(--bad); background:var(--bad-soft); }
508
+ .detail .sugg { font-family:var(--sans); font-size:10px; color:var(--ink-3); padding-top:3px; }
509
+ .detail .sugg b { color:var(--accent); font-weight:600; }
510
+
511
+ dialog { border:1px solid var(--line-strong); border-radius:var(--r-lg); background:var(--surface);
512
+ color:var(--ink); padding:0; max-width:560px; width:calc(100% - 32px);
513
+ box-shadow:var(--shadow-hoch); }
514
+ dialog::backdrop { background:rgba(8,14,16,.55); }
515
+ dialog h3 { margin:0; padding:11px 15px; font-size:13.5px; border-bottom:1px solid var(--line); background:var(--surface-2); }
516
+ dialog .dbody { padding:15px; font-size:13px; max-height:60vh; overflow:auto; }
517
+ .hint { font-size:10.5px; color:var(--ink-3); line-height:1.45; }
518
+ dialog .dfoot { padding:11px 15px; border-top:1px solid var(--line); display:flex; gap:8px;
519
+ justify-content:flex-end; background:var(--surface-2); }
520
+ ul.checks { list-style:none; margin:0; padding:0; font-size:12.5px; }
521
+ ul.checks li { display:grid; grid-template-columns:15px 1fr auto; gap:9px; padding:6px 0;
522
+ border-bottom:1px solid var(--line); align-items:baseline; }
523
+ ul.checks li:last-child { border-bottom:0; }
524
+ ul.checks .m.ok { color:var(--ok); } ul.checks .m.bad { color:var(--bad); }
525
+ ul.checks .m.warn { color:var(--warn); } ul.checks .m.mut { color:var(--ink-3); }
526
+ ul.checks .det { font-family:var(--mono); font-size:11px; color:var(--ink-3); }
527
+ #checkchip { margin-left:5px; }
528
+
529
+ .suggestbox { border:1px solid var(--accent); background:var(--accent-soft); border-radius:var(--r-lg);
530
+ padding:10px 12px; display:flex; gap:13px; align-items:flex-start; flex-wrap:wrap; }
531
+ .suggestbox .txt { flex:1; min-width:220px; }
532
+ /* Flex, damit der Aufklapper rechts andocken kann. Umbrechen darf sie:
533
+ bei langen Vorlagennamen rutscht er sonst aus dem Kasten. */
534
+ .suggestbox .hd {
535
+ font-weight:650; margin-bottom:2px;
536
+ display:flex; align-items:baseline; gap:7px; flex-wrap:wrap;
537
+ }
538
+ .suggestbox ul { margin:5px 0 0; padding-left:16px; font-family:var(--mono);
539
+ font-size:11px; color:var(--ink-2); line-height:1.7; }
540
+ .suggestbox .acts { display:flex; gap:7px; flex-wrap:wrap; }
541
+
542
+ button.btn.primary { background:var(--accent); border-color:var(--accent); color:var(--accent-ink); font-weight:600; }
543
+ button.btn.primary:hover:not(:disabled) { filter:brightness(1.08); background:var(--accent); }
544
+
545
+ /* Beide Leisten (Raum/Funktion und Ablegen unter/Name) teilen ein
546
+ Raster mit fester Beschriftungsspalte - so stehen die vier Felder
547
+ gleich breit und exakt untereinander. */
548
+ .zielbar {
549
+ display:grid; grid-template-columns:96px minmax(140px,1fr) 96px minmax(140px,1fr);
550
+ gap:6px 9px; align-items:center;
551
+ background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg);
552
+ /* Rechts mehr Rand, damit das Bild der Funktion daneben Platz hat.
553
+ Das Bild haengt absolut am Feldrahmen; ohne diesen Rand lief es auf
554
+ schmalen Fenstern aus der Leiste heraus - gemessen bei 760 px, wo
555
+ die Leiste die volle Breite fuellt (26.08.2026).
556
+
557
+ Der Rand gilt fuer BEIDE Leisten, auch die ohne Bild: sonst waeren
558
+ die `1fr`-Spalten verschieden breit und Ordner- und Namensfeld
559
+ stuenden nicht mehr unter Raum und Funktion (S8). */
560
+ padding:8px 41px 8px 11px;
561
+ }
562
+ /* Rechtsbuendig an ihr Feld geschmiegt - linksbuendig klaffte
563
+ zwischen kurzer Beschriftung und Feld eine Luecke. */
564
+ .zielbar .zl { font-size:9px; letter-spacing:.06em; text-transform:uppercase;
565
+ font-weight:700; color:var(--ink-3);
566
+ justify-self:end; text-align:right; }
567
+ /* Die Vorschlags-Marke steht in Zeile 2, in der Spalte ihres Feldes.
568
+ Beides muss ausdruecklich dastehen: nur mit Spalte nahm sie am
569
+ automatischen Einsortieren teil und schob dessen Zeiger in Zeile 2 -
570
+ alles nach ihr (Funktion samt Feld) rutschte mit. Voll platziert
571
+ liegt sie ausserhalb des Flusses, und Zeile 1 bleibt Zeile 1.
572
+ In den Feldrahmen darf sie auch nicht - dort verschob sie Kreuz
573
+ und Aufklappliste. */
574
+ .zielbar .vorschlagsmarke { justify-self:start; margin-top:-2px; }
575
+ .zielbar .vorschlagsmarke.raum { grid-row:2; grid-column:2; }
576
+ .zielbar .vorschlagsmarke.funktion { grid-row:2; grid-column:4; }
577
+ .zielbar .tx { width:100%; font-family:var(--mono); font-size:12px; padding:3px 7px;
578
+ border:1px solid var(--line-strong); border-radius:var(--r-sm);
579
+ background:var(--ground); color:var(--ink); }
580
+ /* Die entstehende ID immer auf eigener Zeile, links buendig. */
581
+ .zielbar .zid {
582
+ grid-column:1 / -1;
583
+ font-family:var(--mono); font-size:12.5px; font-weight:700;
584
+ color:var(--accent); word-break:break-all;
585
+ }
586
+
587
+ .umschalter { display:inline-flex; border:1px solid var(--line-strong); border-radius:var(--r); overflow:hidden; flex:0 0 auto; }
588
+ .umschalter button {
589
+ font:inherit; font-size:11px; padding:3px 9px; border:0; cursor:pointer;
590
+ background:var(--surface); color:var(--ink-3);
591
+ }
592
+ .umschalter button + button { border-left:1px solid var(--line-strong); }
593
+ .umschalter button.an { background:var(--accent); color:var(--accent-ink); font-weight:600; }
594
+ /* Die Modusleiste bekam eine eigene Zeile: „Quellen/Aliase" benannte die
595
+ Datenquelle, nicht die Absicht - wer zum ersten Mal draufschaut, weiss
596
+ nicht, wo er anfaengt (Ricardo, 25.08.2026). In der Filterzeile war
597
+ fuer die laengeren Texte kein Platz. */
598
+ .modusleiste { padding-bottom:0; border-bottom:0; }
599
+ .umschalter.breit { display:flex; width:100%; }
600
+ .umschalter.breit button { flex:1; font-size:12px; padding:5px 6px; white-space:nowrap; }
601
+
602
+ .tree .geraetepunkt { margin-left:auto; font-size:8px; color:var(--accent); }
603
+ .tree .node.sel .geraetepunkt { color:var(--accent-ink); }
604
+ .tree .geraetepunkt + .cnt { margin-left:5px; }
605
+
606
+ .erow .fehltnoch {
607
+ margin-left:7px; font-style:normal; font-size:10px; font-weight:700;
608
+ letter-spacing:.04em; text-transform:uppercase;
609
+ color:var(--warn); background:var(--warn-soft);
610
+ border-radius:999px; padding:1px 7px;
611
+ }
612
+
613
+ .klapp {
614
+ border:1px solid var(--line); background:var(--surface); color:var(--ink-3);
615
+ border-radius:var(--r-sm); width:24px; height:24px; cursor:pointer;
616
+ padding:0; flex:none; display:inline-flex; align-items:center; justify-content:center;
617
+ }
618
+ /* Dieselben Ordner wie im Objektbrowser des Admin: aufgeklappt ist der
619
+ leere Umriss, zugeklappt der gefuellte. */
620
+ .klapp svg { width:15px; height:15px; fill:currentColor; display:block; }
621
+ .klapp:hover { border-color:var(--accent); color:var(--accent); }
622
+
623
+ .freikopf {
624
+ display:flex; align-items:center; gap:8px; padding:6px 15px;
625
+ border-top:1px solid var(--line); border-bottom:1px solid var(--line);
626
+ background:var(--surface-2); font-size:9px; letter-spacing:.06em;
627
+ text-transform:uppercase; font-weight:700; color:var(--ink-3);
628
+ }
629
+ .freikopf .cnt2 { margin-left:auto; font-family:var(--mono); letter-spacing:0; text-transform:none; font-weight:400; }
630
+ .freirow {
631
+ display:grid; grid-template-columns:19px 150px 180px 1fr; gap:9px; align-items:center;
632
+ padding:4px 15px; border-bottom:1px solid var(--line); cursor:pointer;
633
+ font-family:var(--mono); font-size:11.5px; color:var(--ink-3);
634
+ }
635
+ .freirow:hover { background:var(--accent-soft); color:var(--ink); }
636
+ .freirow .mk3 { text-align:center; color:var(--accent); font-weight:700; }
637
+ .freirow .sn2 { font-weight:600; }
638
+ .freirow .rl2 { color:var(--ink-2); }
639
+ .freirow .rx2 { font-size:10px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
640
+ .freirow.pflicht { background:var(--bad-soft); color:var(--bad); }
641
+ .freirow.pflicht .mk3, .freirow.pflicht .rl2, .freirow.pflicht .rx2 { color:var(--bad); }
642
+ .freirow.pflicht .rx2 { font-weight:700; }
643
+
644
+ /* Ein Abschnittskopf muss aussehen wie etwas, auf das man druecken
645
+ kann. Ein Zeichen allein reicht nicht — man sieht es schlicht nicht.
646
+ Deshalb eine eigene Flaeche, die beim Ueberfahren deutlicher wird. */
647
+ .klappz { display:inline-flex; align-items:center; justify-content:center;
648
+ width:18px; height:18px; flex:0 0 auto; }
649
+ .klappz svg { width:15px; height:15px; fill:currentColor; display:block; }
650
+
651
+ .warum { margin-top:5px; font-size:11.5px; color:var(--ink-3); }
652
+ /* Der Aufklapper steht in der Kopfzeile ganz rechts. `margin-left:auto`
653
+ schiebt ihn dorthin, ohne dass die Kopfzeile etwas davon wissen muss. */
654
+ .suggestbox .hd .wkopf {
655
+ display:inline-flex; align-items:center; gap:6px; cursor:pointer;
656
+ margin-left:auto; padding:2px 7px; border-radius:var(--r-sm);
657
+ font-size:11.5px; font-weight:400; color:var(--ink-3);
658
+ user-select:none; transition:background .12s, color .12s;
659
+ white-space:nowrap;
660
+ }
661
+ .suggestbox .hd .wkopf .klappz { color:var(--ink-2); font-size:10px; }
662
+ .suggestbox .hd .wkopf:hover { color:var(--ink); background:var(--surface-2); }
663
+ .suggestbox .hd .wkopf:hover .klappz { color:var(--accent); }
664
+ .warum .wleib { margin:0; }
665
+ .warum .wleib ul { margin:0; padding-left:16px; }
666
+ .warum .wleib li { margin:1px 0; }
667
+ .warum .wtrenn {
668
+ margin:7px 0 3px; font-size:9.5px; letter-spacing:.05em;
669
+ text-transform:uppercase; font-weight:700; color:var(--ink-3);
670
+ }
671
+
672
+ .suggestbox .hd { display:flex; align-items:center; flex-wrap:wrap; }
673
+
674
+ .suggestbox { flex-direction:column; align-items:stretch; gap:9px; }
675
+ .suggestbox .hd { width:100%; }
676
+ .suggestbox .verdictwrap { padding:5px 8px; }
677
+ .suggestbox .verdictwrap .musterwahl { font-size:13px; }
678
+
679
+ .feldlabel { font-size:8.5px; letter-spacing:.06em; text-transform:uppercase;
680
+ font-weight:700; color:var(--ink-3); }
681
+ .feld { display:flex; flex-direction:column; gap:3px; }
682
+ /* Oberkante ausgerichtet: die Beschriftungen stehen auf einer Linie,
683
+ die Felder darunter auch - und Marken, die unter dem Musterfeld
684
+ dazukommen, wachsen nach unten, ohne die Zeile zu verschieben.
685
+ (Unterkanten-Ausrichtung schob genau dann das Feld nach oben.) */
686
+ .suggestbox .acts { display:flex; gap:18px; align-items:flex-start; flex-wrap:wrap; width:100%; }
687
+ /* Ein Feld ohne Beschriftung (der Knopf) startet um deren Hoehe tiefer,
688
+ damit es auf der Feldlinie liegt. */
689
+ .suggestbox .acts .knoepfe { margin-top:16px; }
690
+ /* Vorlage und Ausgang teilen ein Aussehen - dieselbe Schrift und
691
+ dieselben Ecken wie die uebrigen Felder. */
692
+ .suggestbox .acts select.tx {
693
+ font-family:var(--mono); font-size:12px; padding:3px 6px;
694
+ border:1px solid var(--line-strong); border-radius:var(--r-sm);
695
+ background-color:var(--surface); color:var(--ink); max-width:270px;
696
+ padding-right:24px;
697
+ }
698
+ .suggestbox .verdictwrap {
699
+ border:0; background:none; padding:0; gap:3px; align-items:stretch;
700
+ }
701
+ /* Gleiche Strichstaerke wie Vorlage und Ausgang daneben - halbfett
702
+ wirkte wie eine andere Schrift in der Zeile. */
703
+ .suggestbox .verdictwrap .musterwahl { font-weight:400; width:250px; max-width:250px; }
704
+ .suggestbox .vmeta { font-size:10.5px; color:var(--ink-3); gap:6px; }
705
+ .suggestbox .luecke { flex:1 1 20px; }
706
+ .suggestbox .knoepfe { display:flex; gap:7px; align-items:flex-end; }
707
+ button.btn.schmal { font-size:11px; padding:3px 9px; }
708
+ /* NACH der schmal-Regel, sonst ueberschreibt deren Kurzform-padding
709
+ den Platz fuer den Ring und er liegt auf dem Text (Ricardo,
710
+ 25.08.2026 - „einfach mal ueber dem Wort"). */
711
+ button.btn.laedt { padding-right:30px; }
712
+
713
+ /* Punktliste der MQTT-Karte: Pillen und Knoepfe fuellen ihre Spalte -
714
+ alle gleich breit, Knoepfe einzeilig. */
715
+ .mchip .chip { width:100%; justify-content:center; }
716
+ .mknopf .btn { width:100%; white-space:nowrap; }
717
+ .leise { color:var(--ink-3); }
718
+
719
+ /* Alle Auswahlfelder der Zeile gleich hoch, sonst sitzen sie versetzt. */
720
+ /* Alle Felder der Zeile gleich hoch - Dropdown wie Eingabefeld. */
721
+ .suggestbox .acts select, .suggestbox .acts .musterwahl {
722
+ height:26px; box-sizing:border-box; font-size:12px;
723
+ }
724
+ .suggestbox .acts .feld, .suggestbox .acts .verdictwrap { justify-content:flex-start; }
725
+
726
+ .enumbar { margin-top:5px; }
727
+ /* Das Angebot, eine Zuordnung zu uebernehmen. Es steht in der Zeile,
728
+ nicht als Fenster davor - wer es nicht will, uebersieht es folgenlos. */
729
+ /* Das Angebot steht unter dem Feld, an dem gerade gearbeitet wurde -
730
+ eine eigene Zeile, damit es nicht in der Leiste untergeht. */
731
+ .uebernahme {
732
+ grid-column:1 / -1;
733
+ display:flex; align-items:center; gap:8px;
734
+ margin:0;
735
+ }
736
+ .uebernahme .zq { color:var(--ink-2); font-size:11.5px; }
737
+ .btn.mini { padding:2px 9px; font-size:11px; line-height:1.6; }
738
+ .btn.mini.wichtig {
739
+ background:var(--accent); border-color:var(--accent); color:#fff; font-weight:600;
740
+ }
741
+ .btn.mini.wichtig:hover { filter:brightness(1.08); }
742
+ /* Leise Fassung: mit passender Vorlage ist Raten nur ein Nebenweg.
743
+ Der Rahmen bleibt (schwache Linienfarbe) - ganz ohne laese sich der
744
+ Knopf wie eine Beschriftung (Ricardo, 25.08.2026). */
745
+ button.btn.mini.leise { border-color:var(--line); background:transparent; color:var(--ink-3); }
746
+ button.btn.mini.leise:hover:not(:disabled) { background:var(--surface-2); color:var(--ink); }
747
+ /* Ein Angebot, das gerade erschienen ist, pocht dreimal - danach ist
748
+ Ruhe. Es taucht dort auf, wo man eben getippt hat, aber der Blick
749
+ haengt am Zeichen, das man zuletzt gesetzt hat, nicht an der Zeile
750
+ darunter. Drei Sekunden reichen, um es zu bemerken; laenger waere
751
+ Zappeln. Bei jedem Neuzeichnen erneut zu pochen waere genau das,
752
+ deshalb traegt nur das frisch erschienene Angebot die Marke. */
753
+ /* Es pocht die Frage, nicht der Knopf.
754
+
755
+ Zuerst lag die Bewegung auf dem „ja“ - das liest sich als Aufforderung,
756
+ ihn zu druecken, dabei ist die Antwort offen. Neu ist die Frage, also
757
+ zieht sie den Blick auf sich, und der Knopf wartet ruhig daneben. */
758
+ .uebernahme .zq {
759
+ padding:2px 7px; border-radius:var(--r);
760
+ background:transparent; transition:background .3s;
761
+ }
762
+ @keyframes fragePochen {
763
+ 0% { background:transparent; }
764
+ 30% { background:color-mix(in srgb, var(--accent) 20%, transparent); }
765
+ 70% { background:color-mix(in srgb, var(--accent) 20%, transparent); }
766
+ 100% { background:transparent; }
767
+ }
768
+ .uebernahme.frisch .zq {
769
+ animation:fragePochen 1s ease-in-out 3;
770
+ color:var(--ink);
771
+ }
772
+ @media (prefers-reduced-motion: reduce) {
773
+ .uebernahme.frisch .zq {
774
+ animation:none;
775
+ background:color-mix(in srgb, var(--accent) 14%, transparent);
776
+ }
777
+ }
778
+ .enumbar .enumfeld { padding-right:22px; }
779
+
780
+ /* Trockenlauf: eine Zeile je Objekt, das JSON aufklappbar darunter. */
781
+ details.zeile > summary {
782
+ cursor:pointer; list-style:none; display:flex; align-items:flex-start; gap:7px;
783
+ }
784
+ details.zeile > summary::-webkit-details-marker { display:none; }
785
+ details.zeile > summary::before {
786
+ content:'\25b8'; color:var(--ink-3); font-size:11px; width:9px; flex:none;
787
+ line-height:19px;
788
+ }
789
+ details.zeile[open] > summary::before { content:'\25be'; }
790
+ /* Ziel und Quelle als zwei Zeilen, die Beschriftungen darueber
791
+ ausgerichtet: erste Spalte so breit wie das laengste Wort. */
792
+ details.zeile > summary .zpaar {
793
+ display:grid; grid-template-columns:auto minmax(0, 1fr); gap:1px 8px;
794
+ min-width:0; flex:1;
795
+ }
796
+ details.zeile > summary .zlabel {
797
+ font-size:10.5px; color:var(--ink-3); text-transform:uppercase;
798
+ letter-spacing:.03em; line-height:19px;
799
+ }
800
+ details.zeile > summary .zid, details.zeile > summary .zq {
801
+ font-family:var(--mono); line-height:19px;
802
+ white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
803
+ }
804
+ details.zeile > summary .zid { font-size:12px; font-weight:600; }
805
+ details.zeile > summary .zq { font-size:11.5px; color:var(--ink-2); }
806
+
807
+ .namzeile { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
808
+ .sprungknopf { font-family:var(--mono); font-size:11px; padding:2px 8px; flex:none; }
809
+ /* Die Musterwahl in der Werkzeugleiste: waagerecht statt untereinander,
810
+ damit sie neben die Filter passt. */
811
+ .listbar .verdictwrap.inbar {
812
+ flex-direction:row; align-items:center; gap:7px; padding:3px 7px; margin-left:auto;
813
+ }
814
+ .listbar .verdictwrap.inbar .musterwahl { font-size:12px; width:230px; max-width:230px; }
815
+ .listbar .verdictwrap.inbar .vmeta { margin:0; }
816
+
817
+ .feldwrap { position:relative; display:block; min-width:0; }
818
+ /* Das Musterfeld ist ein Eingabefeld, sieht aber aus wie das Auswahlfeld
819
+ davor - mit dem Pfeil rechts, damit erkennbar bleibt, dass sich hier
820
+ etwas aufklappt. */
821
+ input.musterwahl { cursor:pointer; }
822
+ /* Die uebliche Auswahl plus die Umschaltzeile sind neun Zeilen. Bei den
823
+ 200 px der Ordnerliste faengt genau dort das Scrollen an, und der
824
+ Umschalter steht unter der Kante — also etwas mehr Platz. */
825
+ .vorschlaege.musterliste { max-height:280px; }
826
+ /* Beim Aufklappen leert sich das Feld, damit man sofort tippen kann.
827
+ Damit dann noch erkennbar ist, was gerade gewaehlt ist, traegt die
828
+ Zeile eine eigene Marke — nicht dieselbe wie die Tastaturauswahl,
829
+ sonst waeren beim Blaettern zwei Zeilen gleich hervorgehoben. */
830
+ .vorschlaege .vz.gewaehlt { font-weight:700; color:var(--ink); }
831
+ .vorschlaege .vz.gewaehlt::before { content:'\2022\00a0'; color:var(--accent); }
832
+ input.musterwahl:focus { cursor:text; }
833
+ .vorschlaege .vz .tiefer { margin-left:auto; }
834
+ .vorschlaege {
835
+ position:absolute; top:calc(100% + 2px); left:0; z-index:40; min-width:100%;
836
+ background:var(--surface); border:1px solid var(--line-strong); border-radius:var(--r);
837
+ box-shadow:var(--shadow-hoch); max-height:200px; overflow:auto; padding:2px 0;
838
+ }
839
+ .vorschlaege .vz {
840
+ padding:4px 9px; font-family:var(--mono); font-size:11.5px;
841
+ cursor:pointer; white-space:nowrap; color:var(--ink-2);
842
+ }
843
+ .vorschlaege .vz:hover, .vorschlaege .vz.an { background:var(--accent-soft); color:var(--accent); }
844
+
845
+ .zielbar .ordnerfeld { padding-right:22px; }
846
+ #move-body .ordnerfeld { padding-right:22px; }
847
+ /* Kreuz aus zwei gedrehten Strichen statt eines Schriftzeichens —
848
+ dessen Grundlinie sitzt je nach Schriftart nicht mittig im Kreis. */
849
+ .feldx {
850
+ position:absolute; right:5px; top:50%; margin-top:-8px;
851
+ width:16px; height:16px; padding:0; border:0; border-radius:50%;
852
+ cursor:pointer; background:var(--surface-3); font-size:0; line-height:0;
853
+ }
854
+ .feldx::before, .feldx::after {
855
+ content:""; position:absolute; left:50%; top:50%;
856
+ width:9px; height:1.5px; background:var(--ink-3); border-radius:1px;
857
+ }
858
+ .feldx::before { transform:translate(-50%,-50%) rotate(45deg); }
859
+ .feldx::after { transform:translate(-50%,-50%) rotate(-45deg); }
860
+ /* Das Bild der gewaehlten Aufzaehlung. Es steht RECHTS NEBEN dem Feld,
861
+ im freien Raum vor der naechsten Beschriftung - im Feld haette es
862
+ Text verdraengt. Absolut zum Feldrahmen, damit das Spaltenraster
863
+ unberuehrt bleibt und die Zielzeile darunter buendig stehen bleibt.
864
+ `pointer-events:none`: ein Klick daneben soll nichts ausloesen. */
865
+ .feldikon {
866
+ position:absolute; left:100%; margin-left:7px; top:50%; margin-top:-11px;
867
+ width:22px; height:22px; pointer-events:none;
868
+ }
869
+ .feldikon img { width:22px; height:22px; display:block; }
870
+ .feldikon.blass img { opacity:.45; }
871
+ /* „neu" sitzt als Ecke AUF dem Bild, unten rechts - so gehoert die
872
+ Auskunft sichtbar zu diesem einen Bild und braucht keine eigene
873
+ Breite (Ricardo, 26.08.2026). */
874
+ .feldikon .ikneu {
875
+ position:absolute; right:-4px; bottom:-3px;
876
+ font-family:var(--sans); font-size:7.5px; font-weight:700;
877
+ line-height:1; letter-spacing:.02em; text-transform:lowercase;
878
+ padding:1.5px 2.5px; border-radius:var(--r-sm);
879
+ background:var(--accent); color:var(--accent-ink);
880
+ box-shadow:0 0 0 1.5px var(--surface-1);
881
+ }
882
+ .feldx:hover { background:var(--bad-soft); }
883
+ .feldx:hover::before, .feldx:hover::after { background:var(--bad); }
884
+
885
+ .vorschlaege .vz { display:flex; align-items:center; gap:8px; }
886
+ .vorschlaege .vz .tiefer { margin-left:auto; color:var(--ink-3); font-weight:700;
887
+ cursor:pointer; padding:0 5px; border-radius:var(--r-sm); }
888
+ .vorschlaege .vz .tiefer:hover { background:var(--surface-3); color:var(--ink); }
889
+ .vorschlaege .vz.zurueck { color:var(--ink-3); border-bottom:1px solid var(--line); }
890
+ /* Aufklapp-Zeilen (alle Rollen / alle Muster): sehen nach Handlung
891
+ aus, nicht nach Eintrag. */
892
+ .vorschlaege .vz.mehr { color:var(--accent); font-weight:600;
893
+ border-top:1px solid var(--line); }
894
+ .vorschlaege .vz.mehr:hover { background:var(--accent-soft); color:var(--accent); }
895
+ /* Gruppenkoepfe in Auswahllisten: Beschriftung, keine Wahlzeile.
896
+ Der Trennstrich steht ueber dem Kopf - er trennt Gruppe von Gruppe.
897
+ Unter dem Kopf trennte er ihn von seinen eigenen Eintraegen
898
+ (Ricardo, 25.08.2026). */
899
+ .vorschlaege .vz.gruppe {
900
+ cursor:default; margin-top:3px; padding-top:7px;
901
+ font-family:var(--sans); font-size:9px; font-weight:700;
902
+ letter-spacing:.06em; text-transform:uppercase; color:var(--ink-3);
903
+ border-top:1px solid var(--line);
904
+ }
905
+ .vorschlaege .vz.gruppe:first-child { border-top:0; margin-top:0; padding-top:4px; }
906
+ .vorschlaege .vz.gruppe:hover { background:none; color:var(--ink-3); }
907
+ .vorschlaege .vz.gruppe .tiefer { cursor:default; font-weight:400;
908
+ letter-spacing:0; text-transform:none; }
909
+ .vorschlaege .vz.gruppe .tiefer:hover { background:none; color:var(--ink-3); }
910
+ .vorschlaege.rollenliste { max-height:320px; min-width:300px; }
911
+ .vorschlaege .vz.gruppe .tiefer.rfrei { color:var(--ok); }
912
+ .vorschlaege .vz.gruppe .tiefer.rfrei:hover { color:var(--ok); }
913
+ .vorschlaege .vz.gruppe .tiefer.rbelegt { color:var(--bad); }
914
+ .vorschlaege .vz.gruppe .tiefer.rbelegt:hover { color:var(--bad); }
915
+ .vorschlaege .vz.zurueck:hover { background:var(--surface-2); color:var(--ink); }
916
+