/* =====================================================================
   openbi.Studio — Designsystem
   Grundfassung „Tageslicht", Nachtmodus „Stellwerk".
   Eine Datei, alle Werte als Variablen. Kein Stil in Seiten und Vorlagen.

   Fassung 1 · 24.08.2026 · Rolle openbistudio-neu
   Version im Dateinamen, weil auf Webdateien kein Cache-Control liegt.
   Alle eigenen Klassen tragen das Präfix obs-. Ohne Präfix bleiben nur
   die Klassen der globalen Systemvorlagen (btn, btn-primary, btn-ghost,
   obs-konto) — siehe Abschnitt 10.
   ===================================================================== */

/* ============================================================
   openbi.Studio — Designsystem
   Grundfassung „Tageslicht": kühles Porzellan, Tinte, Ultramarin.
   Nachtmodus „Stellwerk": lackiertes Petrol, Emailschild-Elfenbein,
   Signalbernstein. Gleiche Typografie, gleiche Radien, gleiche Dichte —
   nur andere Farbwerte. Ein System, zwei Fassungen.
   ============================================================ */
:root{
  --ground:#ECF0F2; --ground-2:#E2E8EB;
  --panel:#FFFFFF; --panel-2:#F4F7F8; --panel-3:#E7EDF0;
  --line:#D5DEE2; --line-2:#B9C6CC;
  --ink:#0F1A20; --ink-2:#4C5D66; --ink-3:#7B8C95;
  --accent:#2A3BE0; --accent-ink:#FFFFFF; --accent-soft:rgba(42,59,224,.09);
  --ok:#0E8A5F; --ok-soft:rgba(14,138,95,.11);
  --warn:#B4740A; --warn-soft:rgba(180,116,10,.12);
  --crit:#C0392B; --crit-soft:rgba(192,57,43,.10);
  --info:#0F6E92; --info-soft:rgba(15,110,146,.11);
  --lock:#7B8C95;
  --rail-bg:#FFFFFF; --frame-bg:#DCE4E8;
  --shadow-card:0 1px 2px rgba(19,40,55,.05);
  --lift:0 14px 34px rgba(19,40,55,.13);
  --scrim:rgba(23,44,58,.42);
  --grid-line:rgba(19,40,55,.07);
  --c1:#2A3BE0; --c2:#0F6E92; --c3:#6A4FCF; --c4:#B4740A; --c5:#8A97A0;

  --f-display:'Bricolage Grotesque','Instrument Sans',system-ui,sans-serif;
  --f-ui:'Instrument Sans',system-ui,sans-serif;
  --f-label:'Instrument Sans',system-ui,sans-serif;
  --f-mono:'Spline Sans Mono',ui-monospace,monospace;

  --label-tt:none; --label-ls:.005em; --label-fw:600; --label-fs:12px;
  --display-ls:-0.028em; --display-fw:700;
  --r-card:13px; --r-sm:8px; --r-pill:999px; --bw:1px;
  --pad:18px; --pad-lg:24px; --row-h:40px; --gap:16px;
}
/* Nachtmodus — nur Farben. Ungestempelte Dokumente folgen dem System. */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --ground:#132126; --ground-2:#0E1A1E;
    --panel:#1A2C33; --panel-2:#213A43; --panel-3:#294652;
    --line:#2C4551; --line-2:#3D5D6B;
    --ink:#EFE9DC; --ink-2:#A6BBC2; --ink-3:#76919B;
    --accent:#F3A536; --accent-ink:#1A1206; --accent-soft:rgba(243,165,54,.15);
    --ok:#46B87C; --ok-soft:rgba(70,184,124,.15);
    --warn:#F3A536; --warn-soft:rgba(243,165,54,.15);
    --crit:#E2573F; --crit-soft:rgba(226,87,63,.16);
    --info:#67AEDA; --info-soft:rgba(103,174,218,.16);
    --lock:#8C9EA6;
    --rail-bg:#0E1A1E; --frame-bg:#0A1215;
    --shadow-card:inset 0 1px 0 rgba(255,255,255,.055);
    --lift:0 10px 30px rgba(0,0,0,.45);
    --scrim:rgba(6,14,17,.66);
    --grid-line:rgba(255,255,255,.06);
    --c1:#F3A536; --c2:#67AEDA; --c3:#9B87E8; --c4:#E0C36A; --c5:#8FA6AE;
  }
}
:root[data-theme="dark"]{
  --ground:#132126; --ground-2:#0E1A1E;
  --panel:#1A2C33; --panel-2:#213A43; --panel-3:#294652;
  --line:#2C4551; --line-2:#3D5D6B;
  --ink:#EFE9DC; --ink-2:#A6BBC2; --ink-3:#76919B;
  --accent:#F3A536; --accent-ink:#1A1206; --accent-soft:rgba(243,165,54,.15);
  --ok:#46B87C; --ok-soft:rgba(70,184,124,.15);
  --warn:#F3A536; --warn-soft:rgba(243,165,54,.15);
  --crit:#E2573F; --crit-soft:rgba(226,87,63,.16);
  --info:#67AEDA; --info-soft:rgba(103,174,218,.16);
  --lock:#8C9EA6;
  --rail-bg:#0E1A1E; --frame-bg:#0A1215;
  --shadow-card:inset 0 1px 0 rgba(255,255,255,.055);
  --lift:0 10px 30px rgba(0,0,0,.45);
  --scrim:rgba(6,14,17,.66);
  --grid-line:rgba(255,255,255,.06);
  --c1:#F3A536; --c2:#67AEDA; --c3:#9B87E8; --c4:#E0C36A; --c5:#8FA6AE;
}

*{box-sizing:border-box}
body{
  margin:0; background:var(--frame-bg); color:var(--ink);
  font-family:var(--f-ui); font-size:14px; line-height:1.45;
  -webkit-font-smoothing:antialiased;
}
button,input,select,textarea{font:inherit;color:inherit}
:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
@media (prefers-reduced-motion: no-preference){
  .obs-tr{transition:background-color .14s ease,color .14s ease,border-color .14s ease,transform .14s ease}
}
.obs-mono{font-family:var(--f-mono); font-variant-numeric:tabular-nums}
.obs-num{font-variant-numeric:tabular-nums}
.obs-lbl{
  font-family:var(--f-label); font-size:var(--label-fs); font-weight:var(--label-fw);
  letter-spacing:var(--label-ls); text-transform:var(--label-tt); color:var(--ink-3);
}

/* ---------- App-Gerüst ---------- */
.obs-app{display:grid; grid-template-columns:206px 1fr; min-height:760px}
.obs-rail{
  background:var(--rail-bg); border-right:1px solid var(--line);
  padding:16px 12px; display:flex; flex-direction:column; gap:22px;
}
.obs-logo{display:flex; align-items:center; gap:9px; padding:0 4px}
.obs-logo-mark{
  width:26px; height:26px; border-radius:var(--r-sm); background:var(--accent); color:var(--accent-ink);
  display:grid; place-items:center; font-family:var(--f-display); font-weight:700; font-size:14px;
}
.obs-logo b{font-family:var(--f-display); font-weight:var(--display-fw); letter-spacing:var(--display-ls); font-size:15px}
.obs-navgroup{display:flex; flex-direction:column; gap:2px}
.obs-navgroup .obs-lbl{padding:0 6px 6px}
.obs-nav{
  display:flex; align-items:center; gap:9px; padding:7px 9px; border-radius:var(--r-sm);
  background:none; border:0; width:100%; text-align:left; cursor:pointer; color:var(--ink-2);
  font-size:13px; font-weight:500; position:relative;
}
.obs-nav:hover{background:var(--panel); color:var(--ink)}
.obs-nav[aria-current="page"]{background:var(--accent-soft); color:var(--accent); font-weight:600}
.obs-nav .obs-ic{width:16px; height:16px; flex:none; opacity:.9}
.obs-nav .obs-cnt{margin-left:auto; font-family:var(--f-mono); font-size:11px; color:var(--ink-3)}
.obs-rail-foot{margin-top:auto; display:flex; flex-direction:column; gap:8px; padding:0 4px}

.obs-workspace{display:flex; flex-direction:column; min-width:0}
.obs-topbar{
  display:flex; align-items:center; gap:14px; padding:11px 18px;
  border-bottom:1px solid var(--line); background:var(--panel);
}
.obs-org{
  display:flex; align-items:center; gap:8px; background:var(--panel-2); border:1px solid var(--line);
  border-radius:var(--r-sm); padding:5px 10px; cursor:pointer; font-size:12.5px; font-weight:500;
}
.obs-org svg{opacity:.6}
.obs-topbar-right{margin-left:auto; display:flex; align-items:center; gap:14px}
.obs-credit{display:flex; flex-direction:column; align-items:flex-end; line-height:1.15}
.obs-credit b{font-family:var(--f-mono); font-size:13px; font-weight:500}
.obs-avatar{
  width:30px; height:30px; border-radius:var(--r-pill); background:var(--panel-3);
  border:1px solid var(--line-2); display:grid; place-items:center;
  font-family:var(--f-label); font-size:11px; font-weight:700; letter-spacing:.04em;
}

/* ---------- Screen-Grundlagen ---------- */
.obs-screen{display:none; padding:22px 24px 34px; min-width:0}
.obs-screen.obs-on{display:block}
.obs-screen.obs-flush{padding:0}
.obs-head{display:flex; align-items:flex-end; gap:16px; flex-wrap:wrap; margin-bottom:20px}
.obs-head h1{
  margin:0; font-family:var(--f-display); font-weight:var(--display-fw);
  letter-spacing:var(--display-ls); font-size:30px; line-height:1.08; text-wrap:balance;
}
.obs-head p{margin:5px 0 0; color:var(--ink-2); font-size:13px; max-width:62ch}
.obs-head .obs-grow{margin-left:auto; display:flex; gap:8px; align-items:center}

/* ---------- Knöpfe ---------- */
.btn{
  display:inline-flex; align-items:center; gap:7px; border-radius:var(--r-sm); cursor:pointer;
  border:1px solid var(--line-2); background:var(--panel-2); color:var(--ink);
  padding:0 13px; height:32px; font-size:13px; font-weight:600; font-family:var(--f-label);
  letter-spacing:.005em; white-space:nowrap;
}
.btn:hover{background:var(--panel-3)}
.btn.obs-pri{background:var(--accent); border-color:var(--accent); color:var(--accent-ink)}
.btn.obs-pri:hover{filter:brightness(1.07)}
.btn.obs-ghost{background:transparent; border-color:transparent; color:var(--ink-2)}
.btn.obs-ghost:hover{background:var(--panel-2); color:var(--ink)}
.btn.obs-danger{border-color:var(--crit); color:var(--crit); background:var(--crit-soft)}
.btn.obs-sm{height:26px; padding:0 9px; font-size:12px}
.btn[disabled]{opacity:.45; cursor:not-allowed}
.btn.obs-busy{background:var(--warn-soft); border-color:var(--warn); color:var(--warn); cursor:progress; opacity:1}
.btn.obs-busy .obs-sq{width:8px; height:8px; background:currentColor; border-radius:1px}
.btn.obs-arm{background:var(--warn-soft); border-color:var(--warn); color:var(--warn)}

/* ---------- Plaketten ---------- */
.obs-pill{
  display:inline-flex; align-items:center; gap:6px; border-radius:var(--r-pill);
  padding:2px 9px; font-family:var(--f-label); font-size:11.5px; font-weight:600;
  border:1px solid transparent; letter-spacing:.005em; white-space:nowrap;
}
.obs-pill .obs-dot{width:6px; height:6px; border-radius:50%; background:currentColor; flex:none}
.obs-pill.obs-ok{background:var(--ok-soft); color:var(--ok); border-color:color-mix(in srgb,var(--ok) 35%,transparent)}
.obs-pill.obs-warn{background:var(--warn-soft); color:var(--warn); border-color:color-mix(in srgb,var(--warn) 35%,transparent)}
.obs-pill.obs-crit{background:var(--crit-soft); color:var(--crit); border-color:color-mix(in srgb,var(--crit) 35%,transparent)}
.obs-pill.obs-info{background:var(--info-soft); color:var(--info); border-color:color-mix(in srgb,var(--info) 35%,transparent)}
.obs-pill.obs-mute{background:var(--panel-2); color:var(--ink-3); border-color:var(--line)}
.obs-pill.obs-lock{background:var(--panel-2); color:var(--lock); border-color:var(--line)}

/* ---------- Karten / Platten ---------- */
.obs-card{
  background:var(--panel); border:1px solid var(--line); border-radius:var(--r-card);
  box-shadow:var(--shadow-card);
}
.obs-card-h{
  display:flex; align-items:center; gap:10px; padding:var(--pad) var(--pad-lg);
  border-bottom:1px solid var(--line);
}
.obs-card-h h2{margin:0; font-family:var(--f-display); font-size:15px; font-weight:var(--display-fw); letter-spacing:var(--display-ls)}
.obs-card-h .obs-grow{margin-left:auto; display:flex; gap:8px; align-items:center}
.obs-card-b{padding:var(--pad-lg)}

/* ---------- Kennzahlen ---------- */
.obs-kpis{display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:var(--gap); margin-bottom:var(--gap)}
.obs-kpi{
  background:var(--panel); border:1px solid var(--line); border-radius:var(--r-card);
  padding:var(--pad) var(--pad-lg) calc(var(--pad) + 2px); box-shadow:var(--shadow-card);
  display:flex; flex-direction:column; gap:5px; min-width:0;
}
.obs-kpi b{
  font-family:var(--f-display); font-weight:var(--display-fw); letter-spacing:var(--display-ls);
  font-size:33px; line-height:1; font-variant-numeric:tabular-nums;
}
.obs-kpi small{font-size:11.5px; color:var(--ink-3)}
.obs-kpi.obs-unmeasured{
  background:
    repeating-linear-gradient(135deg,transparent 0 7px,color-mix(in srgb,var(--line) 55%,transparent) 7px 8px),
    var(--panel);
}
.obs-kpi.obs-unmeasured b{color:var(--ink-3); font-weight:400}
.obs-kpi.obs-unmeasured small{color:var(--ink-3)}
.obs-kpi .obs-why{
  align-self:flex-start; font-family:var(--f-label); font-size:10.5px; letter-spacing:.04em;
  text-transform:var(--label-tt); color:var(--info); border:1px dashed color-mix(in srgb,var(--info) 45%,transparent);
  border-radius:var(--r-pill); padding:1px 7px; background:var(--info-soft);
}

/* ---------- Balken ---------- */
.obs-bar{height:6px; border-radius:var(--r-pill); background:var(--panel-3); overflow:hidden; display:flex}
.obs-bar i{display:block; height:100%; background:var(--accent)}
.obs-bar i.obs-ok{background:var(--ok)} .obs-bar i.obs-warn{background:var(--warn)} .obs-bar i.obs-crit{background:var(--crit)}
.obs-bar i.obs-rest{background:color-mix(in srgb,var(--accent) 30%,transparent)}
.obs-barwrap{display:flex; flex-direction:column; gap:6px; min-width:0}
.obs-barwrap .obs-row{display:flex; align-items:baseline; gap:8px; font-size:12px; color:var(--ink-2)}
.obs-barwrap .obs-row b{font-family:var(--f-mono); font-weight:500; color:var(--ink); font-size:12.5px}
.obs-barwrap .obs-row .obs-grow{margin-left:auto}

/* ---------- Landschaftskarten ---------- */
.obs-lands{display:grid; gap:var(--gap); grid-template-columns:repeat(auto-fit,minmax(430px,1fr)); align-items:start}
.obs-land{
  background:var(--panel); border:1px solid var(--line); border-radius:var(--r-card);
  box-shadow:var(--shadow-card); display:flex; flex-direction:column; overflow:hidden;
}
.obs-land-h{display:flex; align-items:flex-start; gap:10px; padding:var(--pad) var(--pad-lg) 12px}
.obs-land-h h3{
  margin:0; font-family:var(--f-display); font-size:16.5px; font-weight:var(--display-fw);
  letter-spacing:var(--display-ls); line-height:1.2; font-size:18px;
}
.obs-land-h .obs-sub{margin-top:3px; font-size:12px; color:var(--ink-3); display:flex; gap:7px; align-items:center; flex-wrap:wrap}
.obs-land-h .obs-grow{margin-left:auto; display:flex; gap:6px; align-items:center; flex:none}
.obs-sys{
  display:grid; grid-template-columns:118px 1fr 92px auto; align-items:center; gap:12px;
  padding:9px var(--pad-lg); border-top:1px solid var(--line); min-height:var(--row-h);
}
.obs-sys:hover{background:var(--panel-2)}
.obs-sys-name{display:flex; align-items:center; gap:7px; min-width:0}
.obs-sys-tag{
  width:8px; height:8px; border-radius:50%; background:var(--info); flex:none;
}
.obs-sys[data-role="entwicklung"] .obs-sys-tag{background:var(--info)}
.obs-sys[data-role="qs"] .obs-sys-tag{background:var(--warn)}
.obs-sys[data-role="produktiv"] .obs-sys-tag{background:var(--ok)}
.obs-sys-name b{font-family:var(--f-label); font-size:12px; font-weight:600; letter-spacing:.01em}
.obs-sys-host{font-family:var(--f-mono); font-size:11.5px; color:var(--ink-2); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.obs-sys-visits{display:flex; align-items:center; gap:8px; justify-content:flex-end}
.obs-sys-visits b{font-family:var(--f-mono); font-size:12px; font-variant-numeric:tabular-nums}
.obs-spark{display:block; flex:none}
.obs-sys-acts{display:flex; gap:5px; opacity:.72}
.obs-sys:hover .obs-sys-acts{opacity:1}
.obs-land-f{
  margin-top:auto; padding:11px var(--pad-lg); border-top:1px solid var(--line);
  background:var(--panel-2); display:flex; align-items:center; gap:12px;
}
.obs-land-f .obs-barwrap{flex:1}

/* Bereitstellungskette in der Karte */
.obs-chainwrap{padding:13px var(--pad-lg) 14px; border-top:1px solid var(--line); display:flex; flex-direction:column; gap:8px}
.obs-chain{display:flex; align-items:center; gap:3px}
.obs-chain i{flex:1; height:5px; border-radius:2px; background:var(--panel-3); display:block; min-width:6px}
.obs-chain i.obs-done{background:var(--ok)}
.obs-chain i.obs-now{background:var(--warn); box-shadow:0 0 0 2px var(--warn-soft)}
.obs-chaincap{display:flex; align-items:baseline; gap:8px; font-size:12px; color:var(--ink-2); flex-wrap:wrap}
.obs-chaincap b{font-family:var(--f-mono); font-size:12px; color:var(--ink)}
.obs-chaincap .obs-rest{margin-left:auto; color:var(--ink-3)}
.obs-waitbox{
  margin:0 var(--pad-lg) var(--pad); padding:9px 12px; border-radius:var(--r-sm);
  background:var(--info-soft); border:1px solid color-mix(in srgb,var(--info) 30%,transparent);
  font-size:12.5px; color:var(--ink); display:flex; gap:9px; align-items:flex-start;
}
.obs-waitbox b{color:var(--info); font-family:var(--f-label); font-weight:700; font-size:11px; letter-spacing:.06em; text-transform:uppercase; flex:none; padding-top:2px}

/* ---------- Leerzustand ---------- */
.obs-empty{
  border:1px dashed var(--line-2); border-radius:var(--r-card); padding:22px 24px;
  display:flex; flex-wrap:wrap; align-items:center; gap:10px 26px; background:var(--panel-2);
}
.obs-empty > .obs-t{display:flex; flex-direction:column; gap:7px; align-items:flex-start; min-width:0; flex:1}
.obs-empty .obs-acts{display:flex; gap:8px; flex:none; margin-left:auto}
.obs-empty h4{margin:0; font-family:var(--f-display); font-size:15px; font-weight:var(--display-fw)}
.obs-empty p{margin:0; color:var(--ink-2); font-size:13px; max-width:56ch}

/* ---------- Builder ---------- */
.obs-builder{display:grid; grid-template-columns:minmax(360px,432px) 1fr; min-height:718px}
.obs-bl{border-right:1px solid var(--line); display:flex; flex-direction:column; min-width:0; background:var(--panel)}
.obs-br{display:flex; flex-direction:column; min-width:0; background:var(--ground)}
.obs-ctx{
  display:flex; align-items:center; gap:10px; padding:10px 16px; border-bottom:1px solid var(--line);
  flex-wrap:wrap; background:var(--panel-2);
}
.obs-ctx .obs-grow{margin-left:auto; display:flex; gap:8px; align-items:center}
.obs-feat{
  display:inline-flex; align-items:center; gap:8px; border:1px solid var(--accent);
  background:var(--accent-soft); border-radius:var(--r-sm); padding:4px 10px; font-size:12.5px;
}
.obs-feat .obs-id{font-family:var(--f-mono); font-weight:500; color:var(--accent)}
.obs-feat.obs-locked{border-color:var(--line-2); background:var(--panel-3); color:var(--ink-2)}
.obs-feat.obs-locked .obs-id{color:var(--lock)}

.obs-chat{flex:1; overflow-y:auto; padding:16px; display:flex; flex-direction:column; gap:16px}
.obs-msg{display:flex; flex-direction:column; gap:7px; max-width:100%}
.obs-msg .obs-who{display:flex; align-items:center; gap:7px}
.obs-msg .obs-who .obs-lbl{color:var(--ink-2)}
.obs-msg.obs-me .obs-bubble{
  background:var(--panel-3); border:1px solid var(--line); border-radius:var(--r-card);
  padding:10px 13px; font-size:13.5px;
}
.obs-msg.obs-ai .obs-bubble{font-size:13.5px; line-height:1.55; color:var(--ink)}
.obs-msg.obs-ai .obs-bubble p{margin:0 0 8px}
.obs-msg.obs-ai .obs-bubble p:last-child{margin:0}
.obs-aimark{
  font-family:var(--f-label); font-size:9.5px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--ink-3); border:1px solid var(--line); border-radius:var(--r-pill); padding:1px 6px;
}
.obs-tools{display:flex; flex-direction:column; gap:4px; margin-top:2px}
.obs-tool{
  display:flex; align-items:center; gap:8px; padding:5px 10px; border-radius:var(--r-sm);
  background:var(--panel-2); border:1px solid var(--line); font-size:12px; min-width:0;
}
.obs-tool .obs-tick{color:var(--ok); flex:none}
.obs-tool b{font-weight:600}
.obs-tool .obs-obj{font-family:var(--f-mono); font-size:11.5px; color:var(--ink-2); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.obs-tool .obs-ms{margin-left:auto; font-family:var(--f-mono); font-size:11px; color:var(--ink-3); flex:none}

.obs-ask{
  border:1px solid var(--accent); border-left-width:3px; background:var(--accent-soft);
  border-radius:var(--r-sm); padding:12px 14px; display:flex; flex-direction:column; gap:10px;
}
.obs-ask p{margin:0; font-size:13.5px}
.obs-ask .obs-opts{display:flex; gap:8px; flex-wrap:wrap}

.obs-runstrip{
  border-top:1px solid var(--line); background:var(--panel-2); padding:9px 16px;
  display:flex; align-items:center; gap:11px; flex-wrap:wrap;
}
.obs-clock{
  display:inline-flex; align-items:center; gap:8px; border-radius:var(--r-sm); padding:3px 10px;
  border:1px solid color-mix(in srgb,var(--warn) 45%,transparent); background:var(--warn-soft); color:var(--warn);
  font-family:var(--f-mono); font-size:12px; font-variant-numeric:tabular-nums;
}
.obs-clock.obs-idle{border-color:var(--line); background:var(--panel-3); color:var(--ink-3)}
.obs-clock .obs-sq{width:8px; height:8px; background:currentColor; border-radius:1px; flex:none}
.obs-runstrip .obs-what{font-size:12.5px; color:var(--ink-2); min-width:0}
.obs-runstrip .obs-what b{color:var(--ink); font-weight:600}
.obs-steps{margin-left:auto}
.obs-steplist{
  border-top:1px solid var(--line); background:var(--ground-2); padding:8px 16px;
  display:none; flex-direction:column; gap:3px;
}
.obs-steplist.obs-on{display:flex}
.obs-steplist div{font-family:var(--f-mono); font-size:11.5px; color:var(--ink-2); display:flex; gap:8px}
.obs-steplist div span{color:var(--ink-3); flex:none}

.obs-composer{border-top:1px solid var(--line); padding:12px 16px 14px; background:var(--panel); display:flex; flex-direction:column; gap:10px}
.obs-inputrow{display:flex; gap:9px; align-items:flex-end}
.obs-inputrow textarea{
  flex:1; resize:none; min-height:76px; border-radius:var(--r-sm); border:1px solid var(--line-2);
  background:var(--panel-2); padding:9px 11px; font-size:13.5px; color:var(--ink);
}
.obs-inputrow textarea:disabled{background:var(--ground-2); color:var(--ink-3)}
.obs-inputrow textarea::placeholder{color:var(--ink-3)}
.obs-meter{display:flex; gap:16px; align-items:center; flex-wrap:wrap}
.obs-meter .obs-barwrap{flex:1; min-width:190px}

/* rechte Spalte */
.obs-tabs{display:flex; gap:2px; padding:8px 14px 0; border-bottom:1px solid var(--line); background:var(--panel); overflow-x:auto}
.obs-tab{
  background:none; border:0; border-bottom:2px solid transparent; cursor:pointer; padding:8px 12px 9px;
  font-family:var(--f-label); font-size:12.5px; font-weight:600; color:var(--ink-3); white-space:nowrap;
  display:flex; align-items:center; gap:6px; border-radius:var(--r-sm) var(--r-sm) 0 0;
}
.obs-tab:hover{color:var(--ink); background:var(--panel-2)}
.obs-tab[aria-selected="true"]{color:var(--ink); border-bottom-color:var(--accent)}
.obs-tab .obs-cnt{
  font-family:var(--f-mono); font-size:10.5px; background:var(--accent); color:var(--accent-ink);
  border-radius:var(--r-pill); padding:0 5px;
}
.obs-panelbar{
  display:flex; align-items:center; gap:9px; padding:9px 14px; border-bottom:1px solid var(--line);
  background:var(--panel-2); flex-wrap:wrap;
}
.obs-panelbar .obs-grow{margin-left:auto; display:flex; gap:8px; align-items:center}
.obs-tabpanel{display:none; flex:1; min-height:0; overflow:auto}
.obs-tabpanel.obs-on{display:flex; flex-direction:column}

/* Quelltext */
.obs-editor{display:grid; grid-template-columns:236px 1fr; flex:1; min-height:0}
.obs-tree{border-right:1px solid var(--line); overflow:auto; padding:8px; background:var(--panel)}
.obs-tnode{
  display:flex; align-items:center; gap:7px; padding:5px 8px; border-radius:var(--r-sm); cursor:pointer;
  font-size:12.5px; color:var(--ink-2);
}
.obs-tnode:hover{background:var(--panel-2); color:var(--ink)}
.obs-tnode.obs-sel{background:var(--accent-soft); color:var(--ink); font-weight:600; box-shadow:inset 2px 0 0 var(--accent)}
.obs-tnode .obs-cnt{margin-left:auto; font-family:var(--f-mono); font-size:10.5px; color:var(--ink-3)}
.obs-tnode.obs-d1{padding-left:20px} .obs-tnode.obs-d2{padding-left:34px}
.obs-code{overflow:auto; padding:14px 16px; background:var(--ground-2); font-family:var(--f-mono); font-size:12.5px; line-height:1.65}
.obs-code pre{margin:0; white-space:pre}
.obs-c-tag{color:var(--info)} .obs-c-att{color:var(--accent)} .obs-c-str{color:var(--ok)} .obs-c-com{color:var(--ink-3)}

/* Skills / Dateien / Notizen */
.obs-list{display:flex; flex-direction:column}
.obs-li{
  display:flex; align-items:center; gap:12px; padding:11px 16px; border-bottom:1px solid var(--line);
  min-height:var(--row-h);
}
.obs-li:hover{background:var(--panel-2)}
.obs-li .obs-main{min-width:0; display:flex; flex-direction:column; gap:2px}
.obs-li .obs-main b{font-size:13.5px; font-weight:600}
.obs-li .obs-main span{font-size:12px; color:var(--ink-3)}
.obs-li .obs-grow{margin-left:auto; display:flex; gap:8px; align-items:center; flex:none}
.obs-files{display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:12px; padding:16px}
.obs-file{border:1px solid var(--line); border-radius:var(--r-sm); overflow:hidden; background:var(--panel); cursor:pointer}
.obs-file .obs-thumb{height:88px; background:linear-gradient(135deg,var(--panel-3),var(--line)); display:block}
.obs-file .obs-meta{padding:8px 10px}
.obs-file .obs-meta b{display:block; font-family:var(--f-mono); font-size:11.5px; font-weight:500; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.obs-file .obs-meta span{font-size:11px; color:var(--ink-3)}
.obs-dropzone{margin:0 16px 16px; border:1px dashed var(--line-2); border-radius:var(--r-sm); padding:16px; text-align:center; color:var(--ink-3); font-size:12.5px}
.obs-todo{display:flex; align-items:flex-start; gap:11px; padding:11px 16px; border-bottom:1px solid var(--line)}
.obs-todo input{margin-top:3px; accent-color:var(--accent); width:15px; height:15px}
.obs-todo .obs-t{display:flex; flex-direction:column; gap:3px; min-width:0}
.obs-todo .obs-t b{font-size:13.5px; font-weight:500}
.obs-todo .obs-t span{font-size:11.5px; color:var(--ink-3)}
.obs-todo.obs-done .obs-t b{text-decoration:line-through; color:var(--ink-3)}

/* Schutzhinweis */
.obs-guard{
  margin:14px 16px; padding:13px 15px; border-radius:var(--r-sm); display:flex; gap:12px; align-items:flex-start;
  background:var(--panel-2); border:1px solid var(--line); border-left:3px solid var(--lock);
}
.obs-guard b{display:block; font-family:var(--f-label); font-size:11px; letter-spacing:.08em; text-transform:uppercase; color:var(--lock); margin-bottom:4px}
.obs-guard p{margin:0; font-size:12.5px; color:var(--ink-2); max-width:60ch}

/* ---------- Datenmodell ---------- */
.obs-dm{display:grid; grid-template-columns:minmax(300px,364px) 1fr; min-height:718px}
.obs-dmbar{
  display:flex; align-items:center; gap:8px; padding:10px 16px; border-bottom:1px solid var(--line);
  background:var(--panel-2); flex-wrap:wrap;
}
.obs-chipset{display:flex; gap:6px; flex-wrap:wrap; align-items:center}
.obs-chip{
  display:inline-flex; align-items:baseline; gap:6px; border:1px solid var(--line); background:var(--panel);
  border-radius:var(--r-pill); padding:3px 10px; font-size:12px; color:var(--ink-2);
}
.obs-chip b{font-family:var(--f-mono); font-size:12.5px; color:var(--ink); font-weight:500}
.obs-chip.obs-accent{border-color:color-mix(in srgb,var(--accent) 45%,transparent); background:var(--accent-soft)}
.obs-dmcanvas{position:relative; flex:1; overflow:auto; padding:22px; background:var(--ground-2)}
.obs-dmwrap{position:relative; display:flex; gap:42px; align-items:flex-start; min-width:max-content}
.obs-dmtier{display:flex; flex-direction:column; gap:14px; width:190px; position:relative; z-index:2}
#hhform[hidden]{display:none}
#dmsvg{position:absolute; inset:0; width:100%; height:100%; pointer-events:none; z-index:1; overflow:visible}
.obs-ent{background:var(--panel); border:1px solid var(--line); border-radius:var(--r-card); box-shadow:var(--shadow-card); overflow:hidden}
.obs-ent.obs-mand{border-color:color-mix(in srgb,var(--accent) 50%,var(--line))}
.obs-ent-h{display:flex; align-items:center; gap:7px; padding:9px 11px; cursor:pointer; background:var(--panel-2)}
.obs-ent-h b{font-family:var(--f-mono); font-size:12.5px; font-weight:500; flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis}
.obs-ent-h .obs-chev{transition:transform .15s ease; color:var(--ink-3); flex:none}
.obs-ent.obs-open .obs-ent-h .obs-chev{transform:rotate(90deg)}
.obs-ent-h .obs-badge{
  width:16px; height:16px; border-radius:3px; display:grid; place-items:center; flex:none;
  background:var(--accent-soft); color:var(--accent); font-family:var(--f-label); font-size:9px; font-weight:700;
}
.obs-ent-b{display:none; border-top:1px solid var(--line)}
.obs-ent.obs-open .obs-ent-b{display:block}
.obs-fld{
  display:flex; align-items:center; gap:7px; padding:5px 11px; font-size:12px; cursor:pointer;
  border-bottom:1px solid color-mix(in srgb,var(--line) 55%,transparent);
}
.obs-fld:last-child{border-bottom:0}
.obs-fld:hover{background:var(--accent-soft)}
.obs-fld .obs-n{font-family:var(--f-mono); font-size:11.5px; flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis}
.obs-fld .obs-t{font-family:var(--f-label); font-size:10px; letter-spacing:.05em; text-transform:uppercase; color:var(--ink-3); flex:none}
.obs-fld.obs-ref .obs-n{color:var(--info)}
.obs-refgroup{border-bottom:1px solid var(--line)}
.obs-refgroup summary{
  padding:5px 11px; font-size:11.5px; color:var(--info); cursor:pointer; list-style:none;
  display:flex; align-items:center; gap:6px; font-family:var(--f-label); font-weight:600;
}
.obs-refgroup summary::-webkit-details-marker{display:none}
.obs-refgroup summary:hover{background:var(--info-soft)}
.obs-ent-f{display:flex; gap:6px; padding:7px 9px; background:var(--panel-2); border-top:1px solid var(--line)}
.obs-ent-add{
  border:1px dashed var(--line-2); border-radius:var(--r-card); background:transparent; cursor:pointer;
  padding:16px 12px; color:var(--ink-3); font-size:12.5px; display:flex; flex-direction:column; gap:4px; align-items:center;
  font-family:var(--f-label); font-weight:600;
}
.obs-ent-add:hover{border-color:var(--accent); color:var(--accent); background:var(--accent-soft)}
.obs-stock{
  position:sticky; bottom:0; margin-top:20px; background:var(--panel); border:1px solid var(--line-2);
  border-left:3px solid var(--warn); border-radius:var(--r-sm); padding:12px 14px; display:flex; gap:14px;
  align-items:flex-start; flex-wrap:wrap; z-index:3; box-shadow:var(--lift);
}
.obs-stock .obs-t{min-width:0}
.obs-stock .obs-t b{display:block; font-family:var(--f-label); font-size:11px; letter-spacing:.07em; text-transform:uppercase; color:var(--warn); margin-bottom:3px}
.obs-stock .obs-t p{margin:0; font-size:12.5px; color:var(--ink-2); max-width:52ch}
.obs-stock .obs-items{display:flex; gap:6px; flex-wrap:wrap; margin-left:auto}

/* ---------- Overlay ---------- */
.obs-scrim{
  position:fixed; inset:0; background:var(--scrim); z-index:80; display:none;
  align-items:center; justify-content:center; padding:24px; backdrop-filter:blur(2px);
}
.obs-scrim.obs-on{display:flex}
.obs-sheet{
  width:100%; max-width:520px; background:var(--panel); border:1px solid var(--line-2);
  border-radius:var(--r-card); box-shadow:var(--lift); overflow:hidden;
}
.obs-sheet-h{display:flex; align-items:center; gap:10px; padding:14px 18px; border-bottom:1px solid var(--line)}
.obs-sheet-h h3{margin:0; font-family:var(--f-display); font-size:16px; font-weight:var(--display-fw); letter-spacing:var(--display-ls)}
.obs-sheet-h .obs-grow{margin-left:auto}
.obs-sheet-b{padding:18px; display:flex; flex-direction:column; gap:16px}
.obs-sheet-f{padding:13px 18px; border-top:1px solid var(--line); background:var(--panel-2); display:flex; gap:9px; align-items:center}
.obs-sheet-f .obs-grow{margin-left:auto}
.obs-grid6{display:grid; grid-template-columns:repeat(6,1fr); gap:12px}
.obs-fw{display:flex; flex-direction:column; gap:5px; min-width:0}
.obs-fw.obs-s2{grid-column:span 2} .obs-fw.obs-s3{grid-column:span 3} .obs-fw.obs-s4{grid-column:span 4} .obs-fw.obs-s6{grid-column:span 6}
.obs-fw label{font-family:var(--f-label); font-size:11px; font-weight:600; letter-spacing:.02em; color:var(--ink-2); text-transform:var(--label-tt)}
.obs-fw input,.obs-fw select{
  height:36px; border-radius:var(--r-sm); border:1px solid var(--line-2); background:var(--panel-2);
  padding:0 10px; font-size:13px;
}
.obs-fw .obs-hint{font-size:11.5px; color:var(--ink-3)}
fieldset{border:1px solid var(--line); border-radius:var(--r-sm); padding:14px; margin:0}
legend{padding:0 7px; font-family:var(--f-label); font-size:11px; font-weight:700; letter-spacing:.07em; text-transform:uppercase; color:var(--ink-3)}

/* ---------- Designsystem-Screen ---------- */
.obs-sysgrid{display:grid; gap:var(--gap); grid-template-columns:repeat(auto-fit,minmax(430px,1fr)); align-items:start}
.obs-swatches{display:grid; grid-template-columns:repeat(auto-fill,minmax(96px,1fr)); gap:9px}
.obs-sw{border:1px solid var(--line); border-radius:var(--r-sm); overflow:hidden}
.obs-sw i{display:block; height:46px}
.obs-sw span{display:block; padding:5px 7px; font-family:var(--f-mono); font-size:10px; color:var(--ink-3); background:var(--panel-2)}
.obs-specimen{display:flex; flex-direction:column; gap:12px}
.obs-specimen .obs-l1{font-family:var(--f-display); font-weight:var(--display-fw); letter-spacing:var(--display-ls); font-size:34px; line-height:1.05}
.obs-specimen .obs-l2{font-family:var(--f-display); font-weight:var(--display-fw); letter-spacing:var(--display-ls); font-size:20px}
.obs-specimen .obs-l3{font-size:14px; color:var(--ink-2); max-width:60ch}
.obs-specimen .obs-l4{font-family:var(--f-mono); font-size:12.5px; color:var(--ink-2)}
.obs-row{display:flex; gap:9px; align-items:center; flex-wrap:wrap}
.obs-stack{display:flex; flex-direction:column; gap:12px}
.obs-rules{display:flex; flex-direction:column; gap:0}
.obs-rule{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.25fr); gap:18px; padding:14px 0; border-top:1px solid var(--line)}
.obs-rule:first-child{border-top:0}
.obs-rule h4{margin:0 0 4px; font-family:var(--f-display); font-size:14.5px; font-weight:var(--display-fw); letter-spacing:var(--display-ls)}
.obs-rule .obs-src{font-family:var(--f-mono); font-size:11px; color:var(--ink-3)}
.obs-rule p{margin:0; font-size:13px; color:var(--ink-2)}
.obs-tbl{width:100%; border-collapse:collapse; font-size:13px}
.obs-tbl th{
  text-align:left; padding:7px 10px; border-bottom:1px solid var(--line-2);
  font-family:var(--f-label); font-size:var(--label-fs); font-weight:var(--label-fw);
  letter-spacing:var(--label-ls); text-transform:var(--label-tt); color:var(--ink-3);
}
.obs-tbl td{padding:8px 10px; border-bottom:1px solid var(--line)}
.obs-tbl td.obs-n{font-family:var(--f-mono); font-variant-numeric:tabular-nums; text-align:right}
.obs-tbl tr:hover td{background:var(--panel-2)}


.obs-ctxbar{
  display:flex; align-items:center; gap:12px; padding:9px 18px; flex-wrap:wrap;
  border-bottom:1px solid var(--line); background:var(--panel-2);
}
.obs-ctxbar[hidden]{display:none}
.obs-ctxbar .obs-grow{margin-left:auto; display:flex; gap:9px; align-items:center}
.obs-crumbs{display:flex; align-items:center; gap:5px; min-width:0; flex-wrap:wrap}
.obs-crumbs button{
  background:none; border:0; padding:3px 7px; border-radius:var(--r-sm); cursor:pointer;
  color:var(--ink-2); font-size:12.5px; font-weight:500;
}
.obs-crumbs button:hover{background:var(--panel-3); color:var(--ink)}
.obs-crumbs .obs-sep{color:var(--ink-3); font-size:12px}
.obs-crumbs .obs-cur{color:var(--ink); font-weight:600; font-size:12.5px; padding:3px 4px}
.obs-railhint{
  font-size:11.5px; color:var(--ink-3); line-height:1.45; padding:8px 10px;
  border:1px dashed var(--line-2); border-radius:var(--r-sm); background:var(--panel-2);
}
.obs-nav[hidden]{display:none}
.obs-insthead{
  display:flex; align-items:flex-end; gap:16px; flex-wrap:wrap; padding:20px 24px 16px;
}
.obs-insthead h1{
  margin:0; font-family:var(--f-display); font-weight:var(--display-fw); letter-spacing:var(--display-ls);
  font-size:26px; line-height:1.08;
}
.obs-insthead p{margin:5px 0 0; color:var(--ink-2); font-size:13px}
.obs-insthead .obs-grow{margin-left:auto; display:flex; gap:8px; align-items:center}

/* ---------- Feature-Kanban ---------- */
.obs-kanban{display:grid; grid-template-columns:repeat(3,1fr); gap:var(--gap); align-items:start}
.obs-kcol{
  background:var(--panel-2); border:1px solid var(--line); border-radius:var(--r-card);
  display:flex; flex-direction:column; min-height:300px;
}
.obs-kcol-h{display:flex; align-items:center; gap:9px; padding:13px 16px 11px}
.obs-kcol-h .obs-tag{width:8px; height:8px; border-radius:50%; flex:none}
.obs-kcol[data-role="entwicklung"] .obs-tag{background:var(--info)}
.obs-kcol[data-role="qs"] .obs-tag{background:var(--warn)}
.obs-kcol[data-role="produktiv"] .obs-tag{background:var(--ok)}
.obs-kcol-h b{font-family:var(--f-display); font-weight:var(--display-fw); letter-spacing:var(--display-ls); font-size:15px}
.obs-kcol-h .obs-grow{margin-left:auto; display:flex; gap:7px; align-items:center}
.obs-kcol-note{padding:0 16px 11px; font-size:12px; color:var(--ink-3)}
.obs-kcol-b{padding:0 12px 12px; display:flex; flex-direction:column; gap:10px; flex:1}
.obs-kcol.obs-can{outline:2px dashed var(--accent); outline-offset:-3px; background:var(--accent-soft)}
.obs-kcol.obs-no{opacity:.5}
.obs-fcard{
  background:var(--panel); border:1px solid var(--line); border-radius:var(--r-sm);
  padding:12px 13px; display:flex; flex-direction:column; gap:8px; cursor:grab;
  box-shadow:var(--shadow-card);
}
.obs-fcard:active{cursor:grabbing}
.obs-fcard.obs-drag{opacity:.4}
.obs-fcard .obs-top{display:flex; align-items:center; gap:8px}
.obs-fcard .obs-fid{font-family:var(--f-mono); font-size:12px; font-weight:500; color:var(--accent)}
.obs-fcard .obs-grip{margin-left:auto; color:var(--ink-3); flex:none}
.obs-fcard h4{margin:0; font-size:14px; font-weight:600; line-height:1.3}
.obs-fcard .obs-meta{display:flex; gap:6px; flex-wrap:wrap; align-items:center; font-size:11.5px; color:var(--ink-3)}
.obs-fcard.obs-fixed{cursor:default; opacity:.92}
.obs-fcard.obs-fixed .obs-grip{display:none}
.obs-reportsec{display:flex; flex-direction:column; gap:8px}
.obs-reportsec > .obs-lbl{display:flex; align-items:center; gap:7px}
.obs-objlist{display:flex; flex-direction:column; gap:1px; max-height:150px; overflow:auto;
  border:1px solid var(--line); border-radius:var(--r-sm); background:var(--panel-2)}
.obs-objlist div{display:flex; gap:9px; padding:5px 10px; font-size:12px; align-items:center}
.obs-objlist div + div{border-top:1px solid var(--line)}
.obs-objlist .obs-k{font-family:var(--f-label); font-size:10.5px; letter-spacing:.04em; text-transform:uppercase; color:var(--ink-3); flex:none; width:118px}
.obs-objlist .obs-v{font-family:var(--f-mono); font-size:11.5px; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.obs-warnrow{
  display:flex; gap:10px; padding:9px 11px; border-radius:var(--r-sm); font-size:12.5px;
  background:var(--warn-soft); border:1px solid color-mix(in srgb,var(--warn) 32%,transparent);
}
.obs-warnrow b{color:var(--warn); flex:none; font-family:var(--f-label); font-size:10.5px; letter-spacing:.06em; text-transform:uppercase; padding-top:2px}
.obs-toast{
  position:fixed; left:50%; bottom:26px; transform:translateX(-50%); z-index:120;
  background:var(--panel); border:1px solid var(--line-2); border-radius:var(--r-sm);
  padding:11px 16px; box-shadow:var(--lift); font-size:13px; display:none; gap:10px; align-items:center;
}
.obs-toast.obs-on{display:flex}

/* ---------- Projekt / Gantt ---------- */
.obs-projgrid{display:grid; grid-template-columns:1fr minmax(300px,382px); gap:var(--gap); align-items:start}
.obs-gantt{--cols:11; overflow-x:auto}
.obs-gr{display:grid; grid-template-columns:250px repeat(var(--cols),minmax(52px,1fr)); align-items:center; min-width:640px}
.obs-gr.obs-weeks{position:sticky; top:0; background:var(--panel); z-index:2; border-bottom:1px solid var(--line-2)}
.obs-gr.obs-weeks .obs-wk{
  font-family:var(--f-label); font-size:10.5px; letter-spacing:.05em; color:var(--ink-3);
  text-align:center; padding:7px 0; border-left:1px solid var(--grid-line);
}
.obs-gr.obs-weeks .obs-wk.obs-mon{color:var(--ink-2); font-weight:600}
.obs-grow-lbl{padding:7px 12px 7px 0; display:flex; align-items:center; gap:8px; min-width:0}
.obs-grow-lbl .obs-id{font-family:var(--f-mono); font-size:11px; color:var(--ink-3); flex:none}
.obs-grow-lbl span.obs-n{font-size:13px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.obs-gr.obs-phase .obs-grow-lbl span.obs-n{font-weight:700; font-family:var(--f-display); letter-spacing:var(--display-ls)}
.obs-gr .obs-cell{height:34px; border-left:1px solid var(--grid-line)}
.obs-gr:hover .obs-cell{background:var(--panel-2)}
.obs-gbar{
  height:16px; border-radius:4px; background:var(--accent); position:relative; align-self:center;
  margin:0 2px; display:flex; align-items:center; overflow:hidden;
}
.obs-gbar .obs-fill{position:absolute; inset:0 auto 0 0; background:color-mix(in srgb,#000 26%,var(--accent))}
:root[data-theme="dark"] .obs-gbar .obs-fill{background:color-mix(in srgb,#fff 34%,var(--accent))}
.obs-gbar .obs-pct{position:relative; font-family:var(--f-mono); font-size:9.5px; color:var(--accent-ink); padding-left:5px; z-index:1}
.obs-gbar.obs-phasebar{height:9px; border-radius:2px; background:var(--ink-3); opacity:.5}
.obs-gbar.obs-late{background:var(--crit)}
.obs-mstone{width:0; height:0; align-self:center; justify-self:start; margin-left:-6px}
.obs-mstone i{display:block; width:13px; height:13px; background:var(--ink); transform:rotate(45deg); border-radius:2px}
.obs-today{position:relative}
.obs-todayline{
  position:absolute; top:0; bottom:0; width:2px; background:var(--crit); opacity:.6; z-index:4; pointer-events:none;
}
.obs-todayline span{
  position:absolute; top:34px; left:5px; border:1px solid var(--crit); font-family:var(--f-label); font-size:9.5px; letter-spacing:.07em;
  text-transform:uppercase; color:var(--crit); background:var(--panel); padding:0 4px; border-radius:3px;
}
#garrows{position:absolute; inset:0; pointer-events:none; z-index:3; overflow:visible}
.obs-assign{display:grid; grid-template-columns:1fr 1fr; gap:0}
.obs-assign > div{padding:var(--pad-lg)}
.obs-assign > div + div{border-left:1px solid var(--line)}
@media (max-width:1180px){ .obs-assign{grid-template-columns:1fr} .obs-assign > div + div{border-left:0; border-top:1px solid var(--line)} }

/* ---------- Verwaltung ---------- */
.obs-usebars{display:flex; flex-direction:column; gap:3px}
.obs-useday{display:grid; grid-template-columns:74px 1fr 96px; gap:12px; align-items:center; padding:4px 0}
.obs-useday .obs-lbl{font-size:11.5px}
.obs-usebar{display:flex; gap:2px; height:16px; align-items:stretch}
.obs-usebar i{display:block; border-radius:2px}
.obs-useday b{font-family:var(--f-mono); font-size:12px; text-align:right; font-variant-numeric:tabular-nums}
.obs-legend{display:flex; gap:14px; flex-wrap:wrap; font-size:11.5px; color:var(--ink-2)}
.obs-legend span{display:flex; align-items:center; gap:6px}
.obs-legend i{width:9px; height:9px; border-radius:2px; display:block}
.obs-threshold{
  display:flex; gap:11px; align-items:flex-start; padding:12px 14px; border-radius:var(--r-sm);
  background:var(--warn-soft); border:1px solid color-mix(in srgb,var(--warn) 32%,transparent); font-size:12.5px;
}
.obs-threshold b{color:var(--warn); font-family:var(--f-label); font-size:10.5px; letter-spacing:.06em; text-transform:uppercase; flex:none; padding-top:2px}

/* ---------- Marketing ---------- */
.obs-app.obs-public{grid-template-columns:1fr}
.obs-app.obs-public .obs-rail,.obs-app.obs-public .obs-topbar{display:none}
.obs-pubnav{
  display:flex; align-items:center; gap:22px; padding:16px 34px; border-bottom:1px solid var(--line);
  background:var(--panel); position:sticky; top:0; z-index:10; flex-wrap:wrap;
}
.obs-pubnav .obs-brand{display:flex; align-items:center; gap:9px; margin-right:14px}
.obs-pubnav .obs-brand b{font-family:var(--f-display); font-weight:var(--display-fw); letter-spacing:var(--display-ls); font-size:17px}
.obs-pubnav a{color:var(--ink-2); text-decoration:none; font-size:13.5px; font-weight:500}
.obs-pubnav a:hover{color:var(--ink)}
.obs-pubnav .obs-grow{margin-left:auto; display:flex; gap:9px; align-items:center}
.obs-mk{padding:0 0 40px}
.obs-hero{padding:66px 34px 44px; display:grid; grid-template-columns:minmax(0,1.05fr) minmax(0,1fr); gap:44px; align-items:center}
.obs-hero .obs-eyebrow{display:inline-flex; align-items:center; gap:8px; margin-bottom:18px}
.obs-hero h1{
  margin:0 0 18px; font-family:var(--f-display); font-weight:800; letter-spacing:-.035em;
  font-size:clamp(34px,4.1vw,58px); line-height:.99; text-wrap:balance;
}
.obs-hero h1 em{font-style:normal; color:var(--accent)}
.obs-hero p.obs-lead{margin:0 0 26px; font-size:16.5px; line-height:1.5; color:var(--ink-2); max-width:52ch}
.obs-hero .obs-cta{display:flex; gap:11px; align-items:center; flex-wrap:wrap}
.obs-hero .obs-cta .btn{height:44px; padding:0 20px; font-size:14.5px}
.obs-hero .obs-fine{margin:16px 0 0; font-size:12.5px; color:var(--ink-3)}
.obs-mkband{
  display:flex; gap:0; border-block:1px solid var(--line); background:var(--panel);
  flex-wrap:wrap;
}
.obs-mkband div{flex:1; min-width:180px; padding:20px 26px; border-left:1px solid var(--line)}
.obs-mkband div:first-child{border-left:0}
.obs-mkband b{display:block; font-family:var(--f-display); font-weight:var(--display-fw); letter-spacing:var(--display-ls); font-size:25px; line-height:1}
.obs-mkband span{display:block; margin-top:6px; font-size:12.5px; color:var(--ink-2)}
.obs-sec{padding:56px 34px}
.obs-sec > h2{
  margin:0 0 8px; font-family:var(--f-display); font-weight:var(--display-fw); letter-spacing:-.03em;
  font-size:31px; text-wrap:balance;
}
.obs-sec > p.obs-sub{margin:0 0 30px; color:var(--ink-2); font-size:15px; max-width:62ch}
.obs-steps3{display:grid; grid-template-columns:repeat(3,1fr); gap:var(--gap)}
.obs-step3{background:var(--panel); border:1px solid var(--line); border-radius:var(--r-card); padding:22px; display:flex; flex-direction:column; gap:9px}
.obs-step3 .obs-no{
  font-family:var(--f-mono); font-size:12px; color:var(--accent); border:1px solid var(--accent);
  border-radius:var(--r-pill); width:26px; height:26px; display:grid; place-items:center;
}
.obs-step3 h3{margin:0; font-size:16.5px; font-family:var(--f-display); font-weight:var(--display-fw); letter-spacing:var(--display-ls)}
.obs-step3 p{margin:0; font-size:13.5px; color:var(--ink-2)}
.obs-tarife{display:grid; grid-template-columns:repeat(3,1fr); gap:var(--gap); align-items:start}
.obs-tarif{background:var(--panel); border:1px solid var(--line); border-radius:var(--r-card); padding:24px; display:flex; flex-direction:column; gap:14px}
.obs-tarif.obs-best{border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft)}
.obs-tarif .obs-name{font-family:var(--f-display); font-weight:var(--display-fw); letter-spacing:var(--display-ls); font-size:19px}
.obs-tarif .obs-price{font-family:var(--f-display); font-weight:800; letter-spacing:-.03em; font-size:36px; line-height:1}
.obs-tarif .obs-price small{font-size:13px; font-weight:500; color:var(--ink-3); letter-spacing:0}
.obs-tarif ul{margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:8px}
.obs-tarif li{display:flex; gap:9px; font-size:13.5px; color:var(--ink-2)}
.obs-tarif li svg{flex:none; margin-top:3px; color:var(--ok)}
.obs-mkfoot{padding:30px 34px; border-top:1px solid var(--line); display:flex; gap:18px; flex-wrap:wrap; align-items:center; font-size:12.5px; color:var(--ink-3)}
.obs-mkfoot a{color:var(--ink-2); text-decoration:none}
.obs-mkfoot a:hover{color:var(--ink)}
.obs-mkfoot .obs-grow{margin-left:auto}
@media (max-width:1100px){
  .obs-hero{grid-template-columns:1fr; padding:44px 24px 34px}
  .obs-sec{padding:40px 24px}
  .obs-steps3,.obs-tarife{grid-template-columns:1fr}
  .obs-kanban{grid-template-columns:1fr}
  .obs-projgrid{grid-template-columns:1fr}
}

@media (max-width:1180px){
  .obs-builder,.obs-dm{grid-template-columns:1fr}
  .obs-bl{border-right:0; border-bottom:1px solid var(--line)}
  .obs-lands{grid-template-columns:1fr}
  .obs-rule{grid-template-columns:1fr; gap:6px}
}
@media (max-width:860px){
  .obs-app{grid-template-columns:1fr}
  .obs-rail{flex-direction:row; align-items:center; overflow-x:auto; border-right:0; border-bottom:1px solid var(--line)}
  .obs-navgroup{flex-direction:row}
  .obs-navgroup .obs-lbl{display:none}
  .obs-rail-foot{display:none}
  .obs-editor{grid-template-columns:1fr}
  .obs-grid6{grid-template-columns:repeat(2,1fr)}
  .obs-fw.obs-s3,.obs-fw.obs-s4,.obs-fw.obs-s6{grid-column:span 2}
}

/* =====================================================================
   10  Aliase für globale Systemvorlagen
   `obsangemeldet` und `obsanmelden` sind global und tragen den
   CSRF-Schutz (%ANTIFORGERY_NAME% / %ANTIFORGERY_TOKEN%). Sie werden
   nicht umgeschrieben — dieses Stylesheet bedient ihre Klassen mit.
   ===================================================================== */
.btn{
  display:inline-flex; align-items:center; gap:7px; border-radius:var(--r-sm); cursor:pointer;
  border:1px solid var(--line-2); background:var(--panel-2); color:var(--ink);
  padding:0 13px; height:32px; font-size:13px; font-weight:600; font-family:var(--f-label);
  text-decoration:none; white-space:nowrap;
}
.btn:hover{background:var(--panel-3)}
.btn-primary{background:var(--accent); border-color:var(--accent); color:var(--accent-ink)}
.btn-primary:hover{filter:brightness(1.07)}
.btn-ghost{background:transparent; border-color:transparent; color:var(--ink-2)}
.btn-ghost:hover{background:var(--panel-2); color:var(--ink)}
.obs-konto{display:flex; align-items:center; gap:6px; margin:0}
.obs-konto-name{font-weight:600}

/* =====================================================================
   11  Gerüst der Seitenhülle
   Was der Prototyp nicht brauchte, weil er in einem Rahmen saß:
   Vollhöhe, Innenabstand des Inhaltsbereichs, klebender Fuß und die
   Liste, die `navbar` und `footerbar` wirklich ausgeben (ul/li/a).
   ===================================================================== */
.obs-app{min-height:100vh}
.obs-workspace{flex:1; display:flex; flex-direction:column}
.obs-main{padding:22px 24px 34px; min-width:0; flex:1}
.obs-main.obs-flush{padding:0}
.obs-footer{
  margin-top:auto; padding:13px 24px; border-top:1px solid var(--line);
  background:var(--panel);
}
.obs-footer ul{margin:0; padding:0; list-style:none; display:flex; gap:16px; flex-wrap:wrap}
.obs-footer li{margin:0}
.obs-footer a{color:var(--ink-3); text-decoration:none; font-size:12.5px}
.obs-footer a:hover{color:var(--ink)}
.obs-navgroup ul{margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:2px}
.obs-navgroup li{margin:0}
.obs-navgroup a.obs-nav{text-decoration:none}
.obs-navgroup a.obs-nav.is-active{background:var(--accent-soft); color:var(--accent); font-weight:600}
.obs-crumbs a{text-decoration:none}
.obs-org:empty{display:none}
.obs-logo{text-decoration:none; color:inherit}
.obs-logo:hover b{color:var(--accent)}

/* =====================================================================
   12  Umschalter und Verweise
   Der Umschalter stand im Prototyp in der Vorführleiste und ist beim
   Herauslösen mitgegangen — er ist aber eine echte Komponente:
   Fassung, Systemrolle, Vorschaubreite. Und was im Prototyp ein Knopf
   war, ist in der Hülle ein Verweis: Verweise brauchen ihre Farbe
   ausdrücklich, sonst nimmt der Browser sein Blau.
   ===================================================================== */
.obs-seg{
  display:flex; background:var(--panel); border:1px solid var(--line);
  border-radius:var(--r-pill); padding:2px; gap:2px;
}
.obs-seg button,.obs-seg a{
  background:none; border:0; cursor:pointer; padding:6px 13px; text-decoration:none;
  border-radius:calc(var(--r-pill) - 1px); font-family:var(--f-label); font-size:12px;
  font-weight:600; color:var(--ink-2); white-space:nowrap;
}
.obs-seg button[aria-pressed="true"],.obs-seg a[aria-current="page"]{
  background:var(--accent); color:var(--accent-ink);
}
.obs-seg button:hover:not([aria-pressed="true"]),.obs-seg a:hover:not([aria-current="page"]){
  background:var(--panel-3); color:var(--ink);
}
.obs-seg button[disabled]{opacity:.4; cursor:not-allowed}
.obs-seg.obs-small button,.obs-seg.obs-small a{padding:5px 10px; font-size:11px}

.obs-crumbs a{color:var(--ink-2); text-decoration:none; padding:3px 7px; border-radius:var(--r-sm)}
.obs-crumbs a:hover{background:var(--panel-3); color:var(--ink)}
.obs-ctxbar .obs-grow{margin-left:auto; display:flex; gap:10px; align-items:center}
.obs-ctxbar .obs-mono{font-size:12px; color:var(--ink-2)}

/* =====================================================================
   13  [hidden] gegen display
   Das Attribut verliert gegen jede Klasse, die display setzt. Auf
   openbi.Studio ist diese Falle schon dreimal zugeschlagen (Kennwort-
   kasten, Technikfelder, Laufstreifen) — und beim ersten Aufruf der
   neuen Rolle ein viertes Mal: der Kontextblock der Seitenleiste stand
   offen, obwohl das Attribut gesetzt war. Deshalb hier ausdruecklich.
   ===================================================================== */
.obs-navgroup[hidden],
.obs-railhint[hidden],
.obs-rail-foot[hidden],
.obs-card[hidden],
.obs-empty[hidden],
.obs-kpis[hidden],
.obs-seg[hidden],
.obs-crumbs[hidden],
.obs-app [hidden]{display:none}

/* =====================================================================
   14  Brücke zu den Stylesheets des Bestands
   Die Dateien der laufenden App färben zu 369 Stellen über Variablen und
   nur an 115 Stellen über feste Werte. Deshalb baut die neue Fassung sie
   nicht nach, sondern legt die 29 alten Variablennamen auf die neuen
   Tokens um. Damit wechselt der ganze Bestand die Fassung mit — Nachtmodus
   eingeschlossen — ohne dass eine Zeile im Bestand angefasst wird.

   Reihenfolge in der Hülle: erst `openbi-studio.css`, dann diese Datei.
   Bei gleicher Gewichtung gewinnt die spätere; wo der Bestand feste Werte
   trägt, braucht die Übersteuerung einen Vorfahren (`.obs-app .x`).

   Das ist ein Zwischenzustand: sobald jede Seite eigene Klassen der neuen
   Fassung hat, fällt der Verweis auf die alte Datei aus der Hülle.
   ===================================================================== */
:root{
  /* Flaechen und Linien */
  --color-surface:var(--panel);
  --color-bg:var(--panel-2);
  --color-line:var(--line);
  --color-divider:var(--line);
  --color-neutral-100:var(--panel-2);
  --color-neutral-200:var(--panel-3);
  --color-neutral-300:var(--line);
  --shell-dark:var(--ground-2);

  /* Text */
  --color-text:var(--ink);
  --color-text-muted:var(--ink-3);
  --color-still:var(--ink-3);
  --color-neutral-700:var(--ink-2);
  --color-neutral-800:var(--ink-2);
  --color-neutral-900:var(--ink);
  --obs-farbe-gedaempft:var(--ink-3);

  /* Akzent — die alte Datei staffelt in 100/300/500/600/700/900.
     Die neue Fassung hat einen Akzent und Abstufungen ueber color-mix. */
  --color-accent:var(--accent);
  --color-accent-100:var(--accent-soft);
  --color-accent-300:color-mix(in srgb,var(--accent) 45%,var(--panel));
  --color-accent-500:var(--accent);
  --color-accent-600:var(--accent);
  --color-accent-700:var(--accent);
  --color-accent-900:color-mix(in srgb,var(--accent) 65%,var(--ink));

  /* Zweiter Akzent war Gruen — das ist in der neuen Fassung der ok-Zustand. */
  --color-accent-2-100:var(--ok-soft);
  --color-accent-2-500:var(--ok);
  --color-accent-2-700:var(--ok);

  /* Fehlerfarben */
  --color-fehler-100:var(--crit-soft);
  --color-fehler-500:var(--crit);
  --color-fehler-700:var(--crit);

  /* Schrift. Die alte Datei erwartet Archivo — die Schriftdateien fehlen im
     Container, es greift system-ui. Die Umlegung heilt das mit. */
  --font-heading:var(--f-display);
  --font-body:var(--f-ui);
}
/* Die Bestandsdateien werden nach dieser Datei geladen — bei gleicher
   Gewichtung gewinnt die spaetere. Deshalb tragen die drei Uebersteuerungen
   einen Vorfahren: `.obs-app .x` (0,2,0) schlaegt `.x` (0,1,0).
   Ohne das bleibt der feste Farbwert im Nachtmodus stehen; genau so ist es
   beim ersten Messen passiert. */
.obs-app .obs-ls-neuinstanz{border-top-color:var(--line)}
.obs-app .obs-ls-neuinstanz-melder{color:var(--ink-2)}
.obs-app .obs-ls-neuinstanz-melder.ist-fehler{color:var(--crit)}

/* Ein einzelnes System soll nicht ueber die ganze Breite laufen. Der Bestand
   setzt `flex: 1 1 12rem`, was bei einem System die ganze Zeile fuellt — in
   der neuen Fassung sind die Systemkaesten begrenzt und die Kette liest sich
   als Kette, nicht als Balken. Bewusste Abweichung vom Bestand. */
.obs-app .obs-ls-system{flex:0 1 26rem}

/* Lange Kennzahltexte: das Kontingent schreibt "4 von 99 Instanzen · 1 gekauft"
   in dasselbe Feld, in dem sonst eine Zahl steht. */
.obs-kpi.obs-lang b{font-size:21px; line-height:1.2}

/* Klassen, die aus JavaScript des Bestands kommen und deshalb nicht
   umbenennbar sind: Eingabefelder und die zwei Knopfvarianten. */
.form-control{
  height:36px; border-radius:var(--r-sm); border:1px solid var(--line-2);
  background:var(--panel-2); color:var(--ink); padding:0 10px; font-size:13px;
}
.form-control:focus-visible{outline:2px solid var(--accent); outline-offset:1px}
select.form-control{height:36px}
.btn-sm{height:26px; padding:0 9px; font-size:12px}
.btn-secondary{background:var(--panel-2); border-color:var(--line-2); color:var(--ink)}
.btn-secondary:hover{background:var(--panel-3)}

/* Die Kachelkette bekommt die Radien und Kanten der neuen Fassung.
   Mehr nicht — Aufbau und Umbruchverhalten bleiben, wie der Bestand
   sie meint. */
.obs-ls-karte{border-radius:var(--r-card); box-shadow:var(--shadow-card)}
.obs-ls-system{border-radius:var(--r-sm)}
.obs-ls-titel{font-family:var(--f-display); letter-spacing:var(--display-ls); font-size:18px}
.obs-ls-freizeile,.obs-ls-leer{border-radius:var(--r-sm)}

/* =====================================================================
   15  Bestandsmarkup der Navigation
   `navbar` gibt nicht aus, was der Prototyp annahm. Gemessen am
   24.08.2026 an app-neu: ul.navbar-nav > li.nav-item > a.nav-link —
   die Bootstrap-Namen des Bestands, ohne obs-nav. Abschnitt 11 traf
   damit nichts, und die Rail zeigte blaue Standardverweise. Selektor
   auf das echte Markup, Aussehen wie .obs-nav.
   ===================================================================== */
.obs-navgroup ul.navbar-nav{
  margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:2px;
}
.obs-navgroup .nav-item{margin:0}
.obs-navgroup a.nav-link{
  display:flex; align-items:center; gap:9px; padding:7px 9px; border-radius:var(--r-sm);
  color:var(--ink-2); font-size:13px; font-weight:500; text-decoration:none;
}
.obs-navgroup a.nav-link:hover{background:var(--panel); color:var(--ink)}
.obs-navgroup a.nav-link.is-active,
.obs-navgroup a.nav-link[aria-current="page"]{
  background:var(--accent-soft); color:var(--accent); font-weight:600;
}

/* Dasselbe im Fuss: `footerbar` gibt ebenfalls nav-link aus. */
.obs-footer a.nav-link{color:var(--ink-3); text-decoration:none; font-size:12.5px}
.obs-footer a.nav-link:hover{color:var(--ink)}
.obs-footer ul.navbar-nav{flex-direction:row; gap:16px; flex-wrap:wrap}

/* =====================================================================
   16  Breite in der Huelle
   Der Prototyp sass in einem Rahmen von 1180px. In der Huelle laeuft der
   Inhalt ueber die ganze Bildschirmbreite: gemessen am 24.08.2026 in einem
   2596px breiten Fenster stand die Kachelreihe mittig in einem leeren Band,
   weil vier Kacheln von je 328px in 2596px zentriert werden. Das sieht wie
   ein Layoutfehler aus und ist nur eine fehlende Begrenzung.
   ===================================================================== */
.obs-main{max-width:1320px; margin-inline:auto; width:100%}

/* Feste Farbe aus obs-ls-kontingent.css auf die Tafel legen, damit die
   Meldung in der Nachtfassung nicht schwarzrot bleibt. */
.obs-app .obs-ls-neuinstanz-melder.ist-fehler{color:var(--crit)}

/* =====================================================================
   17  Drei Handgriffe am laufenden Auftritt
   Alle drei am 24.08.2026 an app-neu gemessen, nicht angenommen.
   ===================================================================== */

/* a) Die Paketauswahl im Anlegen-Feld nahm sich 1.272px und schob den
      Knopf in die dritte Zeile. Die Eingabe darf wachsen, die Auswahl
      wird begrenzt - dann liest die Zeile als Zeile. */
.obs-ls-neu{flex-wrap:wrap; align-items:center}
.obs-ls-neu input.form-control{flex:1 1 18rem; min-width:0}
.obs-ls-neu select.form-control{flex:0 1 22rem; min-width:0}

/* b) Eine Navigationsgruppe ohne Verweise ist nur noch eine Ueberschrift.
      Fuer einen nicht angemeldeten Besucher blendet `navbar` jede Seite
      mit REQUIRES_LOGIN aus - dann stand "Organisation" allein in der
      Rail. Aeltere Browser ohne :has() ignorieren die Regel; dort bleibt
      es beim alten Bild, kaputt geht nichts. */
.obs-navgroup:not(:has(a)):not(:has(.obs-railhint)){display:none}

/* c) Der feste Graustich der Meldezeile aus obs-ls-kontingent.css. */
.obs-app .obs-ls-neuinstanz-melder{color:var(--ink-2)}

/* =====================================================================
   18  Reiter und Kennzahlen des Bestands
   ===================================================================== */

/* a) DER BLOCKER auf /verwaltung. Der Bestand schaltet Reiterinhalte
      ueber das Attribut `hidden`; dieses Stylesheet erwartete die Klasse
      `obs-on` und setzte display:none als Standard. Ergebnis: sechs
      Reiter und darunter nichts - auch der ausgewaehlte Panel war
      unsichtbar, mit vollem Inhalt im DOM. Fuenftes Mal, dass `hidden`
      und `display` in diesem Projekt aneinandergeraten, diesmal in der
      anderen Richtung: sichtbar ist jetzt der Standard.
      Gemessen am 24.08.2026: sechs Panels, eines ohne `hidden`, alle
      display:none, Hoehe 0. */
.obs-tabpanel:not([hidden]){display:flex; flex-direction:column}
.obs-tabpanel[hidden]{display:none}

/* b) Die Kennzahlenkacheln des Bestands tragen eigene Kindklassen statt
      b und small. Dieselbe Typografie, aber 26px statt 33px und
      umbruchfaehig: auf /verwaltung steht im Guthabenfeld ein
      Gleitkomma-Artefakt mit 17 Stellen. */
.obs-kpi-label{
  font-family:var(--f-label); font-size:var(--label-fs); font-weight:var(--label-fw);
  letter-spacing:var(--label-ls); text-transform:var(--label-tt); color:var(--ink-3);
}
.obs-kpi-value{
  font-family:var(--f-display); font-weight:var(--display-fw); letter-spacing:var(--display-ls);
  font-size:26px; line-height:1.05; font-variant-numeric:tabular-nums; color:var(--ink);
  overflow-wrap:anywhere;
}
.obs-kpi-note{font-size:11.5px; color:var(--ink-3)}

/* =====================================================================
   19  Zwei Artefakte, von Kai gesehen (24.08.2026)
   ===================================================================== */

/* a) Die Reiterleiste steht auf overflow-x:auto, damit viele Reiter
      rollen koennen. Windows zeichnet dafuer eine Rollleiste mit
      Pfeilen an den rechten Rand der Karte - sie sah wie ein defektes
      Element aus. Rollen bleibt, die Leiste verschwindet. */
.obs-tabs{overflow-y:hidden; scrollbar-width:none; -ms-overflow-style:none}
.obs-tabs::-webkit-scrollbar{width:0; height:0}

/* b) Der Hinweiskasten am Fuss der Rail ist aus der Huelle genommen. Er
      gehoert zum Kontextblock (Builder, Datenmodell, Transport) und
      stand auf jeder Seite, weil noch keine Seite ihren Kontext
      mitschickt - unten links ein grauer Zettel ohne Anlass. Er kommt
      zurueck, sobald die Instanzseiten data-obs-ctx tragen. Die Regel
      bleibt als Netz, falls die Huelle den Kasten je wieder enthaelt. */
.obs-rail-foot:empty{display:none}

/* =====================================================================
   20  Ab hier unter festem Namen: /CMS/css/obs.css
   Zehn Fassungen in einem Nachmittag sind kein Weg. Ab jetzt derselbe
   Pfad, geaendert ueber delete_webfile und neu anlegen - die Huelle
   bleibt unangetastet. Der Browser braucht dann Strg+Shift+R.
   ===================================================================== */

/* Das Guthabenfeld schnitt seinen Wert ab: openbi-studio.css setzt
   white-space:nowrap und wird NACH dieser Datei geladen, gewinnt also bei
   gleicher Gewichtung. Mit Vorfahren davor sticht die neue Regel.
   (Der 17-stellige Wert selbst ist ein Gleitkomma-Artefakt in den Daten
   und gehoert dort behoben, nicht hier.) */
.obs-app .obs-kpi-value{white-space:normal}

/* =====================================================================
   21  Die Rail ist eine Vorlage, keine navbar
   Abschnitt 11 und 15 formatierten die Liste, die `navbar` ausgab
   (ul.navbar-nav / li / a.nav-link). Seit dem 24.08.2026 kommt die Rail
   aus der Vorlage obsneu-railnav: feste Verweise mit den Zeichen des
   Entwurfs, zwei Gruppen (Organisation, Werkstatt) und der Kontextblock.
   Die Gruppe selbst muss den Stapel deshalb bilden - vorher tat das die
   Liste. Beide Wege bleiben stehen, damit eine Seite mit `navbar` nicht
   auf einmal anders aussieht.
   ===================================================================== */
.obs-navgroup{display:flex; flex-direction:column; gap:2px; min-width:0}
.obs-navgroup > .obs-lbl{margin:0 0 5px 5px}
.obs-navgroup a.obs-nav{text-decoration:none}
.obs-rail .obs-nav .obs-ic{flex:none}
.obs-rail .obs-nav{gap:9px}

/* =====================================================================
   22  Drei Namen, die der Bruecke fehlten
   Gemessen am 24.08.2026 quer ueber 18 Seiten und 9 Bestands-Stylesheets:
   die Seiten benutzen drei Variablennamen, die Abschnitt 14 nicht kennt.
   Jeder unbekannte Name faellt auf seinen Ersatzwert zurueck — und der
   ist ein fester Hellwert. Sichtbar geworden an den Projektmarken auf
   /team: hellgraue Flaeche, helle Schrift, unlesbar in der Nachtfassung.
   ===================================================================== */
:root,[data-theme="light"],[data-theme="dark"]{
  --color-border:var(--line);
  --color-border-stark:var(--line-2);
  --font-mono:var(--f-mono);
}

/* =====================================================================
   23  Die Bausteine, die der Bestand benutzt und der Entwurf nicht kannte
   Gemessen am 24.08.2026 ueber 18 Seiten: 96 Klassen ohne Regel in dieser
   Datei. Die meisten gehoeren zu einer Seitenfamilie und haben ihr eigenes
   Stylesheet (obs-skl-, obs-adm-, obs-plgs-, obs-pj-, obs-bn-). Neun sind
   dagegen Bausteine, die auf vielen Seiten stehen - und auf Seiten ohne
   openbi-studio.css standen sie GANZ ohne Regel da (auf /administration
   gemessen: kein Rahmen, kein Abstand, Ueberschrift in der Textschrift).
   Sie bekommen hier die Werte des Entwurfs. Der Vorfahre .obs-app steht
   davor, weil die Bestandsdateien nach dieser geladen werden.
   ===================================================================== */

/* Zuerst der stille Fehler: obs-visually-hidden hatte keine Regel. Eine
   Beschriftung, die versteckt sein soll, stand damit sichtbar neben dem
   Feld ("Name der neuen Landschaft"). Kein Design, sondern ein Defekt. */
.obs-visually-hidden{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%);
  white-space:nowrap; border:0;
}

/* Der Seitenkopf des Bestands ist der Kopf des Entwurfs. */
.obs-app .obs-page-head{
  display:flex; align-items:flex-end; gap:16px; flex-wrap:wrap;
  margin:0 0 var(--gap); padding:0; background:none; border:0;
}
.obs-app .obs-page-head h1{
  margin:0; font-family:var(--f-display); font-weight:var(--display-fw);
  letter-spacing:var(--display-ls); font-size:26px; line-height:1.08;
}
.obs-app .obs-page-head p{margin:5px 0 0; color:var(--ink-2); font-size:13px}
.obs-app .obs-page-head .obs-grow{margin-left:auto; display:flex; gap:8px; align-items:center}

/* Eine Platte ist eine Karte. */
.obs-app .obs-section{
  background:var(--panel); border:1px solid var(--line); border-radius:var(--r-card);
  box-shadow:var(--shadow-card); padding:var(--pad-lg); margin:0 0 var(--gap);
}
.obs-app .obs-section > h2,.obs-app .obs-section > h3{
  margin:0 0 10px; font-family:var(--f-display); font-weight:var(--display-fw);
  letter-spacing:var(--display-ls); font-size:16px; line-height:1.2;
}

/* Tabellen tragen die Tabelle des Entwurfs (obs-tbl). */
.obs-app .obs-table{width:100%; border-collapse:collapse; font-size:13px}
.obs-app .obs-table th{
  text-align:left; padding:7px 10px; border-bottom:1px solid var(--line-2);
  font-family:var(--f-label); font-size:var(--label-fs); font-weight:var(--label-fw);
  letter-spacing:var(--label-ls); text-transform:var(--label-tt); color:var(--ink-3);
}
.obs-app .obs-table td{padding:8px 10px; border-bottom:1px solid var(--line)}
.obs-app .obs-table tr:hover td{background:var(--panel-2)}

/* Die starke und die leise Zelle, und die Etikette ueber der Ueberschrift. */
.obs-app .obs-cell-strong{font-weight:600; color:var(--ink)}
.obs-app .obs-cell-sub{font-size:11.5px; color:var(--ink-3)}
.obs-app .obs-kicker-muted{
  font-family:var(--f-label); font-size:var(--label-fs); font-weight:var(--label-fw);
  letter-spacing:var(--label-ls); text-transform:var(--label-tt); color:var(--ink-3);
}
.obs-app .obs-hero-lead{color:var(--ink-2); font-size:14px; line-height:1.5}
.obs-app .obs-kpis-5{display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:var(--gap)}

/* =====================================================================
   24  Nackte Eingabefelder
   Der Bestand setzt nicht ueberall eine Klasse: openbi:shopproducts baut
   sein Formular selbst, mit blanken input- und textarea-Elementen. Ohne
   Regel nimmt der Browser Weiss - auf /administration in der Nachtfassung
   drei weisse Loecher im Formular "Neues Paket anlegen". Deshalb gilt das
   Aussehen von .form-control fuer jedes Feld im Rahmen, unabhaengig von
   der Klasse. Knoepfe und Schalter sind ausgenommen: die haben eigene.
   ===================================================================== */
.obs-app input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]):not([type=submit]):not([type=button]):not([type=reset]):not([type=image]):not([type=color]),
.obs-app select,
.obs-app textarea{
  background:var(--panel); color:var(--ink); border:1px solid var(--line);
  border-radius:var(--r-sm); padding:7px 9px; font:inherit; font-size:13px;
  box-sizing:border-box;
}
.obs-app textarea{min-height:70px; resize:vertical}
.obs-app input:focus-visible,.obs-app select:focus-visible,.obs-app textarea:focus-visible{
  outline:2px solid var(--accent); outline-offset:1px; border-color:var(--accent);
}
.obs-app ::placeholder{color:var(--ink-3); opacity:1}

/* Und die Beschriftungen davor: der Bestand schreibt sie als Fliesstext
   neben das Feld. Als Etikette gelesen wird daraus eine Zeile. */
.obs-app form label{color:var(--ink-2); font-size:12.5px}

/* =====================================================================
   25  Nackte Knoepfe im Inhalt
   Auf /profile stand die Reiterleiste als blanke <button>-Elemente mit der
   Klasse nav-link, ohne Regel: Chrome zeichnet dafuer seinen eigenen
   Knopf (rgb(240,240,240)) und erbte die helle Schrift des Rahmens -
   hellgrau auf creme, unlesbar. Gemessen am 24.08.2026 in der
   Nachtfassung ueber 17 Seiten.
   Nur im Inhalt (.obs-main): die Knoepfe des Rahmens (Fassungsumschalter,
   Organisation) haben ihre eigenen Regeln und bleiben unberuehrt.
   ===================================================================== */
.obs-main button:not([class*="btn"]):not(.obs-tab):not(.obs-nav){
  background:var(--panel-2); color:var(--ink); border:1px solid var(--line);
  border-radius:var(--r-sm); padding:6px 11px; font:inherit; font-size:12.5px;
  font-weight:500; cursor:pointer;
}
.obs-main button:not([class*="btn"]):not(.obs-tab):not(.obs-nav):hover{
  background:var(--panel-3);
}
.obs-main button:not([class*="btn"]):not(.obs-tab):not(.obs-nav).active,
.obs-main button:not([class*="btn"]):not(.obs-tab):not(.obs-nav)[aria-current="page"]{
  background:var(--accent-soft); color:var(--accent); border-color:transparent;
}

/* =====================================================================
   26  Bootstrap-Markup des Bestands
   Zwei Muster, die aus der Zeit vor dem Entwurf stammen und ohne Regel
   sichtbar falsch aussehen. Gemessen am 24.08.2026 auf /profile.
   ===================================================================== */

/* a) Die Reiterleiste ist ein ul.nav-tabs mit role=tablist. Ohne Regel
      setzt der Browser Aufzaehlungspunkte davor - zwei Knoepfe mit
      Bullet. Aussehen wie die Reiterleiste des Entwurfs. */
.obs-main [role="tablist"]{
  list-style:none; margin:0 0 var(--gap); padding:0 0 0 0;
  display:flex; gap:2px; flex-wrap:wrap; border-bottom:1px solid var(--line);
}
.obs-main [role="tablist"] > li{margin:0; list-style:none}

/* b) Die Formularzeilen tragen die Beschriftung inline VOR dem Feld. Weil
      jede Beschriftung anders lang ist, entsteht eine Treppe - auf
      /profile ueber neun Zeilen sichtbar. Der Entwurf setzt die
      Beschriftung ueber das Feld. */
.obs-main form.form label,
.obs-main form:not([class]) label{
  display:block; margin:9px 0 3px; color:var(--ink-2); font-size:12.5px;
}
.obs-main form.form input:not([type=submit]):not([type=button]):not([type=checkbox]):not([type=radio]),
.obs-main form.form select,
.obs-main form.form textarea,
.obs-main form:not([class]) input:not([type=submit]):not([type=button]):not([type=checkbox]):not([type=radio]),
.obs-main form:not([class]) select,
.obs-main form:not([class]) textarea{
  display:block; width:100%; max-width:26rem;
}

/* =====================================================================
   27  Zwei Berichtigungen an 24 und 26
   ===================================================================== */

/* a) Abschnitt 24 hat durch die Kette von :not() eine hoehere Gewichtung
      als Abschnitt 26 - sein max-width:100% stach die 26rem aus, und die
      Felder liefen ueber die ganze Spalte. Mit .obs-app davor gewinnt die
      Formularbreite. (Gemessen: max-width kam als 100% heraus.) */
.obs-app .obs-main form.form input:not([type=submit]):not([type=button]):not([type=checkbox]):not([type=radio]),
.obs-app .obs-main form.form select,
.obs-app .obs-main form.form textarea,
.obs-app .obs-main form:not([class]) input:not([type=submit]):not([type=button]):not([type=checkbox]):not([type=radio]),
.obs-app .obs-main form:not([class]) select,
.obs-app .obs-main form:not([class]) textarea{max-width:26rem}

/* b) In der Reiterleiste des Bestands steht aria-selected="true" an BEIDEN
      Knoepfen - gemessen auf /profile. Das ist ein Fehler im Markup (und
      auch fuer Vorleseprogramme einer), aber solange er dort steht, darf
      das Aussehen sich nicht darauf stuetzen. Aktiv ist, was Bootstrap
      markiert: .active. */
.obs-main [role="tablist"] button[aria-selected="true"]:not(.active){
  background:var(--panel-2); color:var(--ink-2); border-color:var(--line);
}
.obs-main [role="tablist"] button.active{
  background:var(--accent-soft); color:var(--accent); border-color:transparent; font-weight:600;
}

/* Lehre aus 24 bis 27, damit es nicht noch einmal passiert:
   eine Kette von :not() erhoeht die Gewichtung wie eine Kette von Klassen.
   Abschnitt 24 kam damit auf (0,10,1) und stach jede spaetere Regel aus -
   die Formularbreite aus 26 und die Reitermarkierung aus 27 blieben ohne
   Wirkung, obwohl sie weiter unten standen. Korrigiert wird deshalb AN DER
   QUELLE, nicht mit einer weiteren Regel dahinter. */


/* =====================================================================
   28  Meine Landschaften nach Vorlage
   ===================================================================== */

/* Kai, 25.08.2026: "im design sind da grafiken drin". Stimmt - der Entwurf
   zeigt auf dieser Seite drei Bilder, die im Bestand fehlten: die
   Rollenfarbe je Systemzeile, die Verlaufskurve neben der Aufrufzahl und
   den Kontingentbalken. Zwei davon stehen jetzt hier; die Kurve zeichnet
   obs-landschaften.js nur dann, wenn der Endpunkt einen Tagesverlauf
   mitschickt (siehe verlaufLesen dort).

   Der Umbau ist wieder ein Stylesheet-Tausch: das Markup bleibt bis auf
   drei Zusaetze dasselbe, und die alte Fassung sieht unveraendert aus.
   Aus der waagerechten Kette mit Pfeilen wird hier eine Zeilenliste -
   der Entwurf stellt die Systeme untereinander, weil eine Zeile Host,
   Zahl und Handlung in eine Blickachse bringt, was die Kette nicht kann.
   Die Richtung, die der Pfeil trug, steht in der Rollenfarbe und in der
   Reihenfolge. */

/* Das Schlosszeichen des Entwurfs, einmal deklariert. */
:root,[data-theme="light"],[data-theme="dark"]{
  --zeichen-schloss:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 13"><path d="M2 5.5V3.6a3.5 3.5 0 0 1 7 0v1.9" fill="none" stroke="black" stroke-width="1.4"/><rect x=".6" y="5.4" width="9.8" height="7.1" rx="1.6" fill="black"/></svg>');
}

/* --- Die Liste: zwei Spalten, wie im Entwurf ------------------------- */
.obs-app #obs-ls-liste{
  display:grid; gap:var(--gap); align-items:start;
  grid-template-columns:repeat(auto-fit,minmax(27rem,1fr));
}

/* --- Die Karte: der Rand traegt nichts mehr, die Zeilen tragen ihn --- */
.obs-app .obs-ls-karte{
  padding:0; overflow:hidden; display:flex; flex-direction:column;
  background:var(--panel); border:1px solid var(--line);
  border-radius:var(--r-card); box-shadow:var(--shadow-card);
}
.obs-app .obs-ls-kopf{padding:var(--pad) var(--pad-lg) 12px; align-items:flex-start; gap:10px}
.obs-app .obs-ls-titel{
  font-family:var(--f-display); font-size:18px; font-weight:var(--display-fw);
  letter-spacing:var(--display-ls); line-height:1.2; color:var(--ink);
}
.obs-app .obs-ls-zahlen{margin-top:3px; font-size:12px; color:var(--ink-3); gap:4px 7px}
.obs-app .obs-ls-beschreibung{margin:0; padding:0 var(--pad-lg) 10px; font-size:13px; color:var(--ink-2)}

/* Die Statusplakette. Gruen ist hier kein Zustandsurteil, sondern die
   Farbe von "laeuft" - und "aktiv" ist der Normalfall. */
.obs-app .obs-ls-status{
  display:inline-flex; align-items:center; gap:6px;
  padding:1px 9px 1px 7px; border-radius:var(--r-pill);
  background:var(--ok-soft); color:var(--ok);
  font-family:var(--f-label); font-size:11.5px; font-weight:600; letter-spacing:.01em;
}
.obs-app .obs-ls-status::before{
  content:""; width:5px; height:5px; border-radius:50%; background:currentColor; flex:none;
}

/* --- Aus der Kette wird eine Zeilenliste ---------------------------- */
.obs-app .obs-ls-kette{display:block; margin:0; gap:0}
.obs-app .obs-ls-pfeil{display:none}

/* flex-direction:row MUSS hier stehen: obs-landschaften.css setzt an
   .obs-ls-system ein flex-direction:column, und das erbt eine Regel, die
   nur display:flex sagt. Beim ersten Wurf stand es nicht da - die Zeilen
   waren dann drei hohe, mittig gesetzte Bloecke statt einer Zeile.
   Am Bild gesehen, nicht am Quelltext. */
.obs-app .obs-ls-system{
  display:flex; flex-direction:row; align-items:center; gap:12px; flex:none; min-width:0;
  min-height:var(--row-h); padding:9px var(--pad-lg);
  background:transparent; border:0; border-top:1px solid var(--line); border-radius:0;
}
.obs-app .obs-ls-system:hover{background:var(--panel-2)}

/* Die Rollenzeile mit dem Punkt in der Rollenfarbe: Entwicklung blau,
   QS ocker, Produktiv gruen - dieselbe Zuordnung wie ueberall im Entwurf.
   Der Punkt haengt an data-rolle und nicht am Text: eine Regel kann keinen
   Text lesen. Bis zum 25.08. gab es das Attribut nicht, deshalb der
   Zusatz in obs-landschaften.js. */
.obs-app .obs-ls-rolle{
  flex:0 0 8rem; display:flex; align-items:center; gap:7px;
  font-family:var(--f-label); font-size:12px; font-weight:600;
  letter-spacing:.01em; text-transform:none; color:var(--ink);
}
.obs-app .obs-ls-rolle::before{
  content:""; width:8px; height:8px; border-radius:50%; background:var(--ink-3); flex:none;
}
.obs-app .obs-ls-system[data-rolle="entwicklung"] .obs-ls-rolle::before{background:var(--info)}
.obs-app .obs-ls-system[data-rolle="qs"]          .obs-ls-rolle::before{background:var(--warn)}
.obs-app .obs-ls-system[data-rolle="produktiv"]   .obs-ls-rolle::before{background:var(--ok)}

/* Der Betonungsrand des Entwicklungssystems entfaellt in der Zeilenform -
   in einer Liste ist ein einzelner farbiger Rahmen Unruhe, und die
   Betonung leistet der Punkt. */
.obs-app .obs-ls-system-entwicklung{border-color:var(--line)}

/* Der Name gibt zuerst nach, der Host zuletzt: am Bild gemessen war es
   umgekehrt, und dann steht dort "sportlerverwaltu..." - eine Kennung, die
   man nicht mehr lesen kann, waehrend der Name daneben ausgeschrieben ist. */
.obs-app .obs-ls-systemname{
  flex:0 1 auto; min-width:0; max-width:9rem; font-size:13px; font-weight:600; color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.obs-app .obs-ls-host{
  flex:1 1 12rem; min-width:0; font-family:var(--f-mono); font-size:11.5px;
  color:var(--ink-2); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; word-break:normal;
}

/* Die Aufrufzahl: Kurve und Zahl, der Wortlaut steckt im Titel. Die
   Farbe kommt aus der Rolle - die Kurve zeichnet mit currentColor. */
.obs-app .obs-ls-aufrufe{
  flex:none; margin:0 0 0 auto; display:flex; align-items:center; gap:8px;
  font-size:12px; color:var(--ink-3);
}
.obs-app .obs-ls-system[data-rolle="entwicklung"] .obs-ls-aufrufe{color:var(--info)}
.obs-app .obs-ls-system[data-rolle="qs"]          .obs-ls-aufrufe{color:var(--warn)}
.obs-app .obs-ls-system[data-rolle="produktiv"]   .obs-ls-aufrufe{color:var(--ok)}
.obs-app .obs-ls-kurve{display:block; flex:none}
.obs-app .obs-ls-aufrufzahl{
  font-family:var(--f-mono); font-size:12px; font-weight:500; color:var(--ink);
  font-variant-numeric:tabular-nums;
}
/* Der Wortlaut ("Aufrufe · N Sitzungen (7 T)") bleibt im Markup und im
   Titel, aber nicht in der Zeile: in der Zeilenform ist kein Platz fuer
   zwei Saetze, und die Einheit steht in der Spaltenbedeutung. */
.obs-app .obs-ls-aufrufwort{display:none}
.obs-app .obs-ls-aufrufe.ist-still{font-style:normal; opacity:1; color:var(--ink-3); font-size:11.5px}

/* --lock ist eine FARBE und kein Zeichen - beim ersten Wurf stand hier
   mask:var(--lock), und das faerbt nichts, es loescht. Das Schloss ist
   deshalb ein eingebettetes SVG als Maske, die Farbe kommt aus --lock. */
.obs-app .obs-ls-schloss{
  flex:none; font-size:0; line-height:0; color:var(--lock);
  display:inline-flex; align-items:center;
}
.obs-app .obs-ls-schloss::before{
  content:""; width:11px; height:13px; flex:none; background:currentColor;
  -webkit-mask:var(--zeichen-schloss) center/contain no-repeat;
          mask:var(--zeichen-schloss) center/contain no-repeat;
}

.obs-app .obs-ls-systemlinks{flex:none; margin-top:0; gap:5px; opacity:.75}
.obs-app .obs-ls-system:hover .obs-ls-systemlinks{opacity:1}

/* --- Die Fusszeile der Karte: "Instanz hinzufuegen" ------------------ */
.obs-app .obs-ls-neuinstanz{
  margin:auto 0 0; padding:11px var(--pad-lg); border-top:1px solid var(--line);
  background:var(--panel-2); gap:8px;
}

/* --- Der Kontingentbalken ------------------------------------------- */
/* Ocker, wenn voll: dann kostet die naechste Instanz Geld, und das ist
   der Moment, in dem jemand hinsehen soll. Sonst gruen - "es ist Platz"
   ist kein Erfolg, aber auch kein Hinweis. */
.obs-app .obs-kontingent-balken{
  margin-top:6px; height:5px; border-radius:3px; background:var(--panel-3);
  overflow:hidden; display:block; width:100%;
}
.obs-app .obs-kontingent-balken i{display:block; height:100%; border-radius:3px}
.obs-app .obs-kontingent-balken i.ist-frei{background:var(--ok)}
.obs-app .obs-kontingent-balken i.ist-voll{background:var(--warn)}

/* --- Instanzen ohne Landschaft -------------------------------------- */
.obs-app .obs-ls-freizeile{
  border:1px solid var(--line); border-radius:var(--r-card); background:var(--panel);
  padding:12px var(--pad-lg); margin-bottom:10px; gap:8px;
}
.obs-app .obs-ls-freiname{font-size:13.5px; font-weight:600; color:var(--ink)}
.obs-app .obs-ls-leer{
  border:1px dashed var(--line-2); border-radius:var(--r-card);
  background:var(--panel-2); color:var(--ink-2); padding:var(--pad-lg);
}

@media (max-width:46rem){
  .obs-app .obs-ls-system{flex-wrap:wrap}
  .obs-app .obs-ls-rolle{flex:0 0 100%}
  .obs-app .obs-ls-aufrufe{margin-left:0}
}

/* Nachtrag zu 28, am Bild gemessen: die Kachelliste steckt in einer
   .obs-section - also in einer Karte. Karten in einer Karte sind der
   haeufigste Grund, warum eine Seite gedraengt aussieht; der Entwurf legt
   die Kacheln auf den Grund. Die Platte verliert deshalb ihr Aussehen,
   wenn sie diese Liste enthaelt. Das Anlegeformular bekommt dafuer eine
   eigene, flache Karte - ein Eingabefeld ohne Flaeche sieht aus wie ein
   Rest. */
.obs-app .obs-section:has(#obs-ls-liste){
  background:none; border:0; box-shadow:none; padding:0; margin:0;
}
.obs-app .obs-ls-neu{
  background:var(--panel); border:1px solid var(--line); border-radius:var(--r-card);
  box-shadow:var(--shadow-card); padding:11px var(--pad-lg); margin:0 0 var(--gap);
}


/* =====================================================================
   29  Der Organisationsumschalter in der Kopfleiste
   ===================================================================== */

/* Kai, 25.08.2026: "openbi im Kopf kannst du den switcher einbauen um die
   Organisation zu aendern - openbi:changeorga".

   Ohne Skript gebaut: die Liste ist ein <details>, jeder Eintrag ein
   Absendeknopf desselben Formulars (cms_item=openbi:changeorga,
   action=changeDefaultOrga, orgaId=...). Ein Wechsel muss die Seite
   ohnehin neu laden - alles darauf gilt fuer die alte Organisation. Ein
   Overlay mit Zustand im Browser waere mehr Code und weniger wahr. */

.obs-orgawahl{position:relative}

/* Das Dreieck, das der Browser vor ein <summary> setzt, ist hier falsch -
   der Chip traegt seinen eigenen Pfeil, den obs-shell einsetzt. */
.obs-orgawahl > summary{list-style:none; cursor:pointer}
.obs-orgawahl > summary::-webkit-details-marker{display:none}
.obs-orgawahl > summary::marker{content:""}

.obs-orgawahl .obs-chev{
  opacity:.55; margin-left:2px; transition:transform .12s ease; flex:none;
}
.obs-orgawahl[open] .obs-chev{transform:rotate(180deg)}
.obs-orgawahl[open] > summary{background:var(--panel-3)}

.obs-orgaliste{
  position:absolute; z-index:40; top:calc(100% + 6px); left:0; min-width:15rem; max-width:22rem;
  display:flex; flex-direction:column; gap:1px; padding:7px;
  background:var(--panel); border:1px solid var(--line-2); border-radius:var(--r-card);
  box-shadow:0 10px 28px rgba(0,0,0,.16);
}
.obs-orgaliste > .obs-lbl{margin:2px 4px 5px}

.obs-orgaeintrag{
  display:block; width:100%; text-align:left; cursor:pointer;
  padding:7px 9px; border:0; border-radius:var(--r-sm);
  background:transparent; color:var(--ink); font:inherit; font-size:13px;
}
.obs-orgaeintrag:hover{background:var(--panel-2)}

/* Die laufende Organisation bekommt einen Haken und keinen Farbklecks:
   sie ist der Zustand, nicht das Angebot. %SELECTED% liefert dafuer
   "selected", sonst einen leeren Wert - deshalb das Attributselektor-
   Paar und nicht [data-aktiv]. */
.obs-orgaeintrag[data-aktiv="selected"]{
  background:var(--accent-soft); color:var(--accent); font-weight:600;
}
.obs-orgaeintrag[data-aktiv="selected"]::after{content:" \2713"}


/* =====================================================================
   30  Die Buchungsseite
   ===================================================================== */

/* Kai, 25.08.2026: "mach man den Buchen und instanz anlegen teil weiter".

   Zwei Dinge fehlten, und beide sind keine Zierde:

   a) Die Summe. Wer Paket und Zusaetze anhakt, sah nirgends, was das
      zusammen kostet. Gerechnet wird in /CMS/js/obs-buchen.js aus den
      Preisen der Zeilen - kein Nachladen, keine Annahme.
   b) Die getroffene Wahl war unsichtbar. Ein Radioknopf von 13 Pixeln in
      einer Zeile mit vier Spalten sagt zu wenig; die Zeile selbst muss es
      sagen. Deshalb faerbt die gewaehlte Zeile, und die ganze Zeile ist
      anklickbar (das macht dasselbe Skript). */

.obs-app .obsbu-summe{
  display:flex; align-items:baseline; flex-wrap:wrap; gap:6px 12px;
  margin:0 0 12px; padding:11px var(--pad-lg);
  background:var(--panel-2); border:1px solid var(--line);
  border-radius:var(--r-card);
}
.obs-app .obsbu-summe-wert{
  font-family:var(--f-mono); font-size:18px; font-weight:500; color:var(--ink);
  font-variant-numeric:tabular-nums;
}
.obs-app .obsbu-summe-teile{flex:1 1 100%; font-size:12px; color:var(--ink-3)}

/* Kein lesbarer Preis: ockerfarben und ohne Zahl. Eine Summe, die eine
   Position verschweigt, ist schlimmer als keine. */
.obs-app .obsbu-summe.ist-unklar{
  background:var(--warn-soft); border-color:color-mix(in srgb,var(--warn) 30%,transparent);
}
.obs-app .obsbu-summe.ist-unklar .obsbu-summe-wert{color:var(--warn)}
.obs-app .obsbu-summe.ist-unklar .obsbu-summe-teile{color:var(--ink-2)}

/* Die gewaehlte Zeile. Auf den Zellen und nicht auf der Zeile, weil die
   Hoverregel aus Abschnitt 23 auf den Zellen sitzt und sonst gewinnt. */
.obs-app .obs-main tbody tr:has(input:checked) > td{
  background:var(--accent-soft);
}
.obs-app .obs-main tbody tr:has(input:checked) > td:first-child{
  box-shadow:inset 2px 0 0 var(--accent);
}
.obs-app .obs-main tbody tr:has(input[type="radio"]),
.obs-app .obs-main tbody tr:has(input[type="checkbox"]){cursor:pointer}

/* Das Wertfeld des Zusatzes (Domain) bleibt ein Feld und kein Zielgebiet. */
.obs-app .obsbu-wert input{min-width:11rem}


/* =====================================================================
   31  Anlegen: Kopfknoepfe und die aufklappbare Fusszeile
   ===================================================================== */

/* Die Fusszeile der Landschaftskachel ist jetzt ein <details>. Zu: eine
   Handlung. Auf: das Formular. Vorher stand es in jeder Kachel offen und
   drueckte die Systemzeilen nach oben - das Haeufigste (hinsehen) hatte
   weniger Platz als das Seltenste (anlegen). */

.obs-app details.obs-ls-neuinstanz{
  margin:auto 0 0; padding:0; border-top:1px solid var(--line);
  background:var(--panel-2); display:block;
}

.obs-app .obs-ls-neuinstanz-kopf{
  list-style:none; cursor:pointer; display:flex; align-items:center; gap:8px;
  padding:10px var(--pad-lg);
  font-family:var(--f-label); font-size:12px; font-weight:600; color:var(--ink-2);
}
.obs-app .obs-ls-neuinstanz-kopf::-webkit-details-marker{display:none}
.obs-app .obs-ls-neuinstanz-kopf::marker{content:""}

/* Das Plus dreht sich zum Minus. Zwei Striche als Rahmen, damit kein Zeichen
   aus einer Schrift geladen werden muss. */
.obs-app .obs-ls-neuinstanz-kopf::before{
  content:""; width:13px; height:13px; flex:none; border-radius:3px;
  background:
    linear-gradient(var(--ink-2),var(--ink-2)) center/7px 1.5px no-repeat,
    linear-gradient(var(--ink-2),var(--ink-2)) center/1.5px 7px no-repeat;
  border:1px solid var(--line-2);
  transition:transform .12s ease;
}
.obs-app details.obs-ls-neuinstanz[open] .obs-ls-neuinstanz-kopf::before{
  background:linear-gradient(var(--ink-2),var(--ink-2)) center/7px 1.5px no-repeat;
}
.obs-app .obs-ls-neuinstanz-kopf:hover{color:var(--ink)}

/* Der Inhalt: die Zeile, die vorher die ganze Fusszeile war. */
.obs-app details.obs-ls-neuinstanz > :not(summary){margin:0}
.obs-app details.obs-ls-neuinstanz[open]{padding-bottom:11px}
.obs-app details.obs-ls-neuinstanz > input,
.obs-app details.obs-ls-neuinstanz > select,
.obs-app details.obs-ls-neuinstanz > button{margin:0 0 0 var(--pad-lg)}
.obs-app details.obs-ls-neuinstanz > input{width:calc(100% - 2 * var(--pad-lg)); margin-bottom:6px}
.obs-app details.obs-ls-neuinstanz > select{margin-bottom:6px}
.obs-app .obs-ls-neuinstanz-melder{
  padding:4px var(--pad-lg) 0; margin:0; font-size:12px; color:var(--ink-2);
}
.obs-app .obs-ls-neuinstanz-melder.ist-fehler{color:var(--crit)}

/* Zwei Hauptknoepfe auf einer Seite sind einer zu viel: gebucht wird selten,
   angelegt oft. Der Kopfknopf tritt deshalb zurueck - Aussehen im Entwurf:
   "Instanz buchen" ruhig, "Landschaft anlegen" betont. */
.obs-app .obs-page-head a[href="/instanz-buchen"].btn-primary{
  background:var(--panel); color:var(--ink); border:1px solid var(--line-2);
  box-shadow:none;
}
.obs-app .obs-page-head a[href="/instanz-buchen"].btn-primary:hover{
  background:var(--panel-2); border-color:var(--ink-3);
}


/* =====================================================================
   32  Der Builder: ganze Breite, ganze Hoehe
   ===================================================================== */

/* Kai, 25.08.2026: "den builder fände ich erstmal wichtiger".

   Der Befund war nicht Gestaltung, sondern eine fehlende Datei: die 151
   Regeln fuer obs-bld-* stehen in openbi-studio.css, die alte Seitenhuelle
   lud sie global, die neue nicht. Der Builder stand deshalb ohne jedes
   Layout da - alles in einer Spalte. Die Vorlage obsbuilder holt die Datei
   jetzt selbst (siehe den Kommentar dort).

   Was danach blieb: der Builder ist ein WERKZEUG und keine Textseite. Der
   Entwurf zeigt ihn randlos ueber die ganze Flaeche, mit zwei Spalten, die
   in sich rollen - nicht als Seite, die nach unten waechst. Abschnitt 16
   gibt dem Inhalt 1320 px und mittet ihn; bei 2644 px Fensterbreite stand
   der Builder deshalb in einer Insel mit 1372 px Rand. */

.obs-app:has(.obs-bld) .obs-workspace{
  height:100dvh; min-height:0; overflow:hidden;
}

.obs-app .obs-main:has(.obs-bld){
  flex:1 1 auto; min-height:0; overflow:hidden;
  max-width:none; width:100%; padding:0;
}

/* Die zwei Spalten: der Chat bleibt lesbar schmal, die Werkstatt nimmt den
   Rest. Feste Pixel fuer beide Spalten (so kommt es aus dem Bestand)
   verschenken auf einem breiten Schirm die halbe Flaeche. */
/* height:100% ging NICHT: zwischen .obs-main und .obs-bld steht der
   Container des organisationprofile-Items (#obs-orga) mit automatischer
   Hoehe - 100 Prozent von "auto" ist auto, und dann gewann wieder
   height:calc(100vh - 64px) aus dem Bestand. Die 64 waren die Kopfhoehe der
   ALTEN Huelle; die neue ist 106 hoch, und genau die 51 Pixel Unterschied
   fehlten unten am Schreibfeld. Deshalb kein Prozentwert, sondern eine
   Kette aus Flex: der Zwischencontainer wird zur Spalte, der Builder
   nimmt den Rest. */
.obs-app .obs-main:has(.obs-bld) > div{
  height:100%; min-height:0; display:flex; flex-direction:column;
}

.obs-app .obs-bld{
  flex:1 1 auto; height:auto; min-height:0;
  grid-template-columns:minmax(22rem,26rem) 1fr;
}

.obs-app .obs-bld > *{min-height:0; min-width:0}

/* Der Fuss gehoert nicht in ein Werkzeug: er kostet eine Zeile Hoehe und
   sagt auf dieser Seite nichts. Die Verweise stehen auf jeder anderen. */
.obs-app:has(.obs-bld) .obs-footer{display:none}

/* Die Auswahlliste der Entwicklungssysteme im Rail-Block. Sie ersetzt dort
   den Hostnamen als Text - aus einer Auskunft wird eine Handlung. Schmal,
   ruhig, und in der Schriftfamilie der Beschriftungen: sie steht zwischen
   einer Etikette und zwei Verweisen und darf keinen von beiden erschlagen. */
.obs-app .obs-rail-wahl{
  width:100%; margin:2px 0 6px; padding:5px 7px;
  background:var(--panel); color:var(--ink); border:1px solid var(--line);
  border-radius:var(--r-sm); font:inherit; font-size:12.5px;
}
.obs-app .obs-rail-wahl:focus-visible{
  outline:2px solid var(--accent); outline-offset:1px; border-color:var(--accent);
}

/* Die Baumspalte, wenn die Auswahlliste ihre Ordnung uebernommen hat. Sie
   bleibt im Markup - die Knoepfe darin sind die Schnittstelle, ueber die
   /CMS/js/obs-bld-baum.js die Hierarchie liest. Verborgen, nicht entfernt. */
.obs-app .obs-bld-baum.ist-verborgen{display:none}

/* Die Liste traegt jetzt eine Ordnung und darf dafuer breiter sein. */
.obs-app #obsbld-objekt{max-width:26rem}


/* =====================================================================
   33  Die Anmeldeseite
   ===================================================================== */

/* Kai, 25.08.2026: "/login sieht nicht richtig aus."

   Derselbe Grund wie beim Builder, andere Entscheidung. Die Seite ist die
   Anmeldung aus dem openbicms-Bestand, unveraendert in die neue Rolle
   kopiert, und ihre Bausteine (.wrapper.content-sm, .centered, .card,
   .row/.col-12, .input-container, .animated-border) stehen in
   openbi-studio.css - die die neue Huelle nicht laedt.

   Beim Builder war es richtig, die Bestandsdatei nachzuladen: 151 Regeln
   Aufbau, die niemand neu schreiben will. Hier waere es falsch. Die
   Anmeldung ist das ERSTE, was ein Kunde sieht; sie soll den neuen Entwurf
   zeigen und nicht den alten in neuen Farben. Und sie ist klein: eine
   Karte, zwei Felder, ein Knopf.

   Alles haengt an body.page-centered - der Klasse, die das Element selbst
   setzt (data-body-class). Damit greift keine dieser Regeln auf einer
   anderen Seite: .card, .row und .col-12 sind Namen aus dem Bootstrap-Erbe
   und kommen anderswo genauso vor. Eine ungescopte Regel darauf waere eine
   Fernwirkung quer durch die Anwendung. */

body.page-centered .obs-main{
  display:flex; align-items:center; justify-content:center;
  min-height:min(70vh, 44rem);
}

body.page-centered .wrapper.content-sm{
  width:100%; max-width:25rem; margin-inline:auto;
}

body.page-centered .centered{display:flex; flex-direction:column; gap:14px}

body.page-centered .centered > header{margin:0}
body.page-centered .centered > header h2{
  margin:0; font-family:var(--f-display); font-weight:var(--display-fw);
  letter-spacing:var(--display-ls); font-size:24px; line-height:1.1; color:var(--ink);
}

body.page-centered .card{
  background:var(--panel); border:1px solid var(--line);
  border-radius:var(--r-card); padding:var(--pad-lg);
}
body.page-centered .card.shadow{box-shadow:var(--shadow-card)}

/* Das Gitter des Bestands wird hier zur Spalte: bei einer Feldbreite hat
   eine 12-Spalten-Reihe nichts zu verteilen. */
body.page-centered .row{display:block}
body.page-centered .col-12{width:100%}
body.page-centered .col-12:empty{display:none}

body.page-centered .input-container{
  display:flex; flex-direction:column; gap:4px; margin-bottom:12px;
}
body.page-centered .form-label{font-size:12.5px; color:var(--ink-2)}
body.page-centered .form-control{width:100%}

/* .animated-border ist ein Unterstrich, der beim Tippen wandert - Zierrat
   aus der alten Fassung. Der Entwurf markiert das Feld ueber den
   Fokusrahmen; zwei Markierungen fuer dieselbe Sache sind eine zu viel. */
body.page-centered .animated-border{display:none}

body.page-centered .card .btn{width:100%; justify-content:center; margin-top:2px}


/* ==========================================================================
   §34  SEITENWAHL IN DER VORSCHAU                              25.08.2026
   --------------------------------------------------------------------------
   Kai: "ich will das in einer Dropdown schon graphisch" und "ich kann ja
   mehrere ebenen haben da ist dein Konzept mist".
   Beides trifft ein <select> mit Leerzeichen-Einrueckung: es kann nur eine
   Zeile pro Eintrag, keine Linien, kein Zuklappen, und ab der dritten Ebene
   zaehlt man Leerzeichen. Darum hier ein Baum in einer Klapptafel:
   Einrueckung ueber echte Fuehrungslinien, Zweige zuklappbar, Filter oben,
   Pfad je Zeile mitgeschrieben.
   ========================================================================== */

.obs-app .obs-bld-sw{position:relative; display:flex; align-items:center; gap:.4rem;}

.obs-app .obs-bld-sw-etikett{
  font-family:var(--f-ui); font-size:var(--label-fs); font-weight:var(--label-fw);
  text-transform:var(--label-tt); letter-spacing:var(--label-ls); color:var(--ink-3);
}

.obs-app .obs-bld-sw-knopf{
  display:inline-flex; align-items:center; gap:.5rem;
  min-width:15rem; max-width:24rem;
  padding:.35rem .6rem;
  border:var(--bw) solid var(--line); border-radius:var(--r-sm);
  background:var(--panel); color:var(--ink);
  font-family:var(--f-ui); font-size:.875rem; cursor:pointer;
}
.obs-app .obs-bld-sw-knopf:hover{border-color:var(--accent);}
.obs-app .obs-bld-sw-knopf .obs-bld-sw-wname{
  flex:1 1 auto; min-width:0; text-align:left;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.obs-app .obs-bld-sw-knopf .obs-bld-sw-wpfad{
  font-family:var(--f-mono); font-size:.75rem; color:var(--ink-3);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:9rem;
}
.obs-app .obs-bld-sw-knopf::after{
  content:""; flex:0 0 auto; width:.4rem; height:.4rem;
  border-right:2px solid currentColor; border-bottom:2px solid currentColor;
  transform:rotate(45deg) translateY(-1px); opacity:.55;
}
.obs-app .obs-bld-sw-knopf[aria-expanded="true"]::after{transform:rotate(225deg) translateY(2px);}

.obs-app .obs-bld-sw-tafel{
  position:absolute; top:calc(100% + .35rem); left:0; z-index:60;
  min-width:24rem; max-width:34rem;
  max-height:min(60vh, 26rem); overflow:auto;
  padding:.5rem;
  background:var(--panel); color:var(--ink);
  border:var(--bw) solid var(--line); border-radius:var(--r-card);
  box-shadow:var(--shadow-card);
}

.obs-app .obs-bld-sw-suche{
  width:100%; margin:0 0 .45rem; padding:.35rem .5rem;
  border:var(--bw) solid var(--line); border-radius:var(--r-sm);
  background:var(--ground); color:var(--ink);
  font-family:var(--f-ui); font-size:.8125rem;
}

.obs-app .obs-bld-sw-tafel ul{list-style:none; margin:0; padding:0;}

/* Die Fuehrungslinie: eine Ebene tiefer heisst eine Linie mehr links.
   Das traegt jede Tiefe, ohne dass die Regel etwas von ihr wissen muss. */
.obs-app .obs-bld-sw-tafel ul ul{
  margin-left:.9rem; padding-left:.7rem; border-left:1px solid var(--line);
}

.obs-app .obs-bld-sw-kopf{display:flex; align-items:center; gap:.1rem;}

.obs-app .obs-bld-sw-klappe{
  flex:0 0 auto; width:1.15rem; height:1.15rem; padding:0;
  display:grid; place-items:center;
  border:0; background:none; color:var(--ink-3); cursor:pointer;
}
.obs-app .obs-bld-sw-klappe::before{
  content:""; width:.35rem; height:.35rem;
  border-right:2px solid currentColor; border-bottom:2px solid currentColor;
  transform:rotate(45deg) translate(-1px,-1px);
}
.obs-app .obs-bld-sw-tafel li.ist-zu > .obs-bld-sw-kopf .obs-bld-sw-klappe::before{
  transform:rotate(-45deg) translate(-1px,1px);
}
.obs-app .obs-bld-sw-tafel li.ist-zu > ul{display:none;}
.obs-app .obs-bld-sw-leer{flex:0 0 auto; width:1.15rem;}

.obs-app .obs-bld-sw-zeile{
  flex:1 1 auto; min-width:0;
  display:flex; align-items:center; gap:.45rem;
  padding:.3rem .45rem;
  border:0; border-radius:var(--r-sm);
  background:none; color:var(--ink);
  font-family:var(--f-ui); font-size:.8125rem; text-align:left; cursor:pointer;
}
.obs-app .obs-bld-sw-zeile:hover{background:var(--panel-2);}
.obs-app .obs-bld-sw-zeile:focus-visible{outline:2px solid var(--accent); outline-offset:1px;}
.obs-app .obs-bld-sw-zeile.ist-gewaehlt{background:var(--accent-soft);}
.obs-app .obs-bld-sw-zeile.ist-gewaehlt .obs-bld-sw-name{font-weight:600;}
.obs-app .obs-bld-sw-zeile[disabled]{opacity:.5; cursor:default;}

.obs-app .obs-bld-sw-name{overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.obs-app .obs-bld-sw-pfad{
  margin-left:auto; padding-left:.6rem;
  font-family:var(--f-mono); font-size:.6875rem; color:var(--ink-3);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.obs-app .obs-bld-sw-haken{flex:0 0 auto; color:var(--accent); font-size:.8125rem;}

/* Zwei Zeichen, damit man Zweig und Blatt auf einen Blick trennt.
   Ordner heisst hier "hat Unterseiten" - nicht "ist keine Seite": im Baum
   steht dazu nichts, und geraten wird nicht. */
.obs-app .obs-bld-sw-zeichen{
  flex:0 0 auto; width:.85rem; height:.85rem;
  background:currentColor; opacity:.5;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-position:center; mask-position:center;
  -webkit-mask-size:contain; mask-size:contain;
}
.obs-app .obs-bld-sw-zeichen.ist-seite{
  -webkit-mask-image:var(--zeichen-blatt); mask-image:var(--zeichen-blatt);
}
.obs-app .obs-bld-sw-zeichen.ist-zweig{
  -webkit-mask-image:var(--zeichen-zweig); mask-image:var(--zeichen-zweig);
}
.obs-app .obs-bld-sw{
  --zeichen-blatt:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 1h5l3 3v11H4z'/%3E%3C/svg%3E");
  --zeichen-zweig:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 3h5l1 2h6v9H2z'/%3E%3C/svg%3E");
}

.obs-app .obs-bld-sw-tafel li.ist-verborgen{display:none;}
.obs-app .obs-bld-sw-nichts{
  padding:.5rem .45rem; font-family:var(--f-ui); font-size:.8125rem; color:var(--ink-3);
}

/* ==========================================================================
   §35  DIE WERKSTATT WIE DER WEBSITE-BUILDER                     25.08.2026
   --------------------------------------------------------------------------
   Kai: "baue den Plugin builder wie den website builder".

   Ausgangslage, gemessen an /plugin?id=... bei 1568 px Fenster: die Werkstatt
   sass als Karte in der Leseseite. Arbeitsflaeche 1222 px breit, die Spalten
   512 px HOCH (Chat 416, Editor 518, Baum 256), der Editor selbst 70 px — und
   unter der Karte blieben ueber 700 px Fenster leer. Ursache steht weiter oben
   in dieser Datei: max-height:32rem auf Chat und Baum, min-height:26rem auf
   den Editor, und die Seite scrollt.

   Der Builder macht es umgekehrt (obs.css §32): die Werkstatt IST die Seite.
   Volle Hoehe, kein Seitenscrollen, jede Spalte scrollt fuer sich, Fusszeile
   weg. Genau das hier, mit denselben Mitteln.

   Der Abschnitt stand zwischen 18:18 und 18:30 Uhr in obs-plugin.css, weil der
   Browserweg zum MCP-Endpunkt sein Zugriffstoken verloren hatte (401
   "invalid_token") und obs.css ueber den Connector 104 KB durch den Kontext getragen
   haette. Sobald der Weg wieder trug, ist er hierher gewandert: das Layout der neuen
   Fassung steht an EINER Stelle, und obs-plugin.css ist wieder Bestand.

   Eine Falle, die diese Datei oben selbst beschreibt und die hier wieder
   zuschlagen wuerde: "Das hidden-Attribut verliert gegen eine Klassenregel mit
   display." Jede display-Regel unten steht deshalb an :not([hidden]) — sonst
   stehen alle drei Werktafeln gleichzeitig offen.
   ========================================================================== */

/* ---- Der Rahmen: volle Hoehe, kein Seitenscrollen, keine Fusszeile ---- */

.obs-app:has(.obs-plg) .obs-workspace{height:100dvh; min-height:0; overflow:hidden;}
.obs-app:has(.obs-plg) .obs-footer{display:none;}

.obs-app .obs-main:has(.obs-plg){
  flex:1 1 auto; min-height:0; overflow:hidden;
  max-width:none; width:100%; padding:0;
  display:flex; flex-direction:column;
}

/* ---- Der Kopf: eine Zeile statt eines Blocks ---- */

.obs-app .obs-main:has(.obs-plg) > .obs-page-head{
  flex:0 0 auto; margin:0; padding:.55rem 1rem;
  display:flex; align-items:center; gap:1rem;
  border-bottom:var(--bw) solid var(--line);
}
.obs-app .obs-main:has(.obs-plg) > .obs-page-head > div{
  display:flex; align-items:baseline; gap:.6rem; flex-wrap:wrap; min-width:0;
}
.obs-app .obs-main:has(.obs-plg) > .obs-page-head .obs-eyebrow{display:none;}
.obs-app .obs-main:has(.obs-plg) > .obs-page-head h1{margin:0; font-size:1.05rem; line-height:1.2;}
.obs-app .obs-main:has(.obs-plg) > .obs-page-head p{margin:0;}
.obs-app .obs-main:has(.obs-plg) > .obs-page-head > .btn{margin-left:auto; flex:0 0 auto;}

/* ---- Die Werkstatt selbst: keine Karte mehr, sondern die Flaeche ---- */

.obs-app .obs-main .obs-section.obs-plg{
  flex:1 1 auto; min-height:0;
  display:flex; flex-direction:column;
  max-width:none; width:100%; margin:0; padding:.6rem 1rem .8rem;
  border:0; border-radius:0; background:none; box-shadow:none;
}

.obs-app .obs-plg .obs-plg-leiste{flex:0 0 auto; margin-bottom:.5rem;}

/* ---- Drei Spalten, volle Hoehe, jede scrollt fuer sich ----
   flex-wrap:nowrap statt des Umbruchs von oben: umbrechen hiesse hier, dass
   eine Spalte unter die anderen rutscht und die Hoehe sprengt. Bei engem
   Fenster wird der Chat schmaler (clamp) und der Baum faellt weg. */

.obs-app .obs-plg .obs-plg-spalten{
  flex:1 1 auto; min-height:0; flex-wrap:nowrap; align-items:stretch; gap:.75rem;
}
.obs-app .obs-plg .obs-plg-chat{
  flex:0 0 clamp(19rem, 24vw, 30rem); min-width:0; min-height:0; max-height:none;
  border-color:var(--line); border-radius:var(--r-card);
}
.obs-app .obs-plg .obs-plg-mitte{flex:1 1 auto; min-width:0; min-height:0;}
.obs-app .obs-plg .obs-plg-baum{
  flex:0 0 17rem; min-height:0; max-height:none; overflow:hidden;
  border-color:var(--line); border-radius:var(--r-card);
  display:flex; flex-direction:column;
}
.obs-app .obs-plg .obs-plg-baum .obs-plg-baumkopf{flex:0 0 auto;}
.obs-app .obs-plg .obs-plg-baum .obs-plg-liste{flex:1 1 auto; min-height:0; overflow:auto;}

/* ---- Die Mitte: Reiterleiste oben, Tafel darunter fuellt den Rest ---- */

.obs-app .obs-plg .obs-plg-werkreiter{flex:0 0 auto;}
.obs-app .obs-plg .obs-plg-werkpanel:not([hidden]){
  flex:1 1 auto; min-height:0; display:flex; flex-direction:column; overflow:hidden;
}
.obs-app .obs-plg .obs-plg-werkpanel[data-werk-panel="aufgaben"]{min-height:0;}
.obs-app .obs-plg .obs-plg-werkpanel > div:not([hidden]):not(.obs-plg-dateireiter){
  flex:1 1 auto; min-height:0; overflow:auto;
}
.obs-app .obs-plg .obs-plg-dateireiter{flex:0 0 auto;}

.obs-app .obs-plg .obs-plg-editorbereich{
  flex:1 1 auto; min-height:0; display:flex; flex-direction:column; overflow:hidden;
}
.obs-app .obs-plg .obs-plg-editorkopf{flex:0 0 auto;}
.obs-app .obs-plg .obs-plg-editor{
  flex:1 1 auto; min-height:0; height:auto; resize:none;
  border-color:var(--line); border-radius:var(--r-sm);
}
.obs-app .obs-plg .CodeMirror{flex:1 1 auto; height:auto; min-height:0;}

/* ---- Der Streifen unten: Meldungen und Versionen, gedeckelt ----
   Er darf nicht mitwachsen: ein langes Bauprotokoll wuerde sonst die Spalten
   zusammendruecken. Feste Obergrenze, eigener Scroller. */

.obs-app .obs-plg .obs-plg-unten{
  flex:0 0 auto; margin-top:.6rem; padding-top:.3rem;
  max-height:13rem; display:flex; flex-direction:column; min-height:0;
  border-top:var(--bw) solid var(--line);
}
.obs-app .obs-plg .obs-plg-unten > .obs-tabs{flex:0 0 auto;}
.obs-app .obs-plg .obs-plg-unten > .obs-tabpanel:not([hidden]){
  flex:1 1 auto; min-height:0; overflow:auto;
}

/* ---- Enges Fenster: der Baum ist das erste, was man opfern kann ---- */

@media (max-width:1200px){
  .obs-app .obs-plg .obs-plg-baum{display:none;}
}
@media (max-width:900px){
  .obs-app .obs-plg .obs-plg-chat{flex:0 0 16rem;}
}

/* ---- Dokumente und Aufgaben: die Tafel fuellen, nicht in ihr scrollen ----

   Kai, 25.08.2026: "der dokumenteninhalt ist abgeschnitten man muss scrollen
   obwohl nach unten platz ist". Gemessen in der Dokumententafel: Tafel 1042 px
   hoch, .obs-nz darin 416 px, .obs-nz-text mit max-height:416px aus
   obs-notizen.css und einem Inhalt von 3355 px. Also ein kleiner Scroller in
   einer halbleeren Flaeche - genau der Fehler, den §35 oben beseitigen sollte,
   nur eine Ebene tiefer.

   Die Deckelung von .obs-nz-liste auf 9rem gilt nur in der Spaltenfassung
   (max-width:1500px) aus obs-plugin.css. Sie wird deshalb erst ab 1501 px
   aufgehoben - sonst waere sie ueberschrieben, weil diese Regeln vier Klassen
   tief haengen und damit auch innerhalb der Medienabfrage gewinnen. */

.obs-app .obs-plg .obs-plg-werkpanel > div:not([hidden]):not(.obs-plg-dateireiter){
  display:flex; flex-direction:column;
}
.obs-app .obs-plg .obs-plg-werkpanel .obs-nz{
  flex:1 1 auto; min-height:0; align-items:stretch;
}
.obs-app .obs-plg .obs-plg-werkpanel .obs-nz-text{
  flex:1 1 auto; min-height:0; max-height:none; overflow:auto;
}
.obs-app .obs-plg .obs-plg-werkpanel .obs-nz-af{flex:1 1 auto; min-height:0; overflow:auto;}
.obs-app .obs-plg .obs-plg-werkpanel .obs-nz-neu{flex:0 0 auto;}

@media (min-width:1501px){
  .obs-app .obs-plg .obs-plg-werkpanel .obs-nz-liste{
    max-height:none; min-height:0; overflow:auto;
  }
}


/* ==========================================================================
   §36  PROFILSEITE UND TOTE BESTANDSREITER                       25.08.2026
   --------------------------------------------------------------------------
   /profile ist die letzte Seite im Bestandsmarkup: die Vorlage
   openbicmsprofile des Items openbi:contactinformation bringt
   "wrapper userprofile / card shadow has-tabs / nav nav-tabs / tab-pane fade"
   mit — alles Bootstrap-Namen, und die neue Huelle laedt kein Bootstrap.

   Gemessen am 25.08.2026: bootstrap.css nicht geladen, window.bootstrap
   undefined, BEIDE Reitertafeln gleichzeitig sichtbar (520 px und 123 px),
   aria-selected="true" an beiden Knoepfen. Die Reiter waren also nicht haesslich,
   sie waren TOT. Reihenfolge der Reparatur: erst wieder EINE Tafel, dann Aussehen.

   Das Umschalten kann CSS nicht leisten (Knoepfe, kein :checked). Es steht in
   obs-shell.2.js und haengt an data-bs-toggle="tab" — generisch, damit jede
   Bestandsseite mit Reitern davon lebt, nicht nur diese.

   .form-control braucht hier nichts: obs.css gestaltet es schon, gemessen
   identisch mit den Feldern der Verfuegbarkeitstafel darunter (Rand
   rgb(213,222,226), Polster 7px 9px, Radius 8px).
   ========================================================================== */

/* ---- Genau eine Tafel. Gilt fuer jede Bestandsseite in der neuen Huelle ---- */

.obs-app .tab-content > .tab-pane{display:none;}
.obs-app .tab-content > .tab-pane.active{display:block;}

/* ---- Die Karte ---- */

.obs-app .userprofile{max-width:62rem;}
.obs-app .userprofile > header{margin:0 0 .8rem;}
.obs-app .userprofile > header h2{margin:0; font-family:var(--f-display, var(--f-ui)); font-size:1.5rem;}

.obs-app .userprofile .card{
  background:var(--panel); color:var(--ink);
  border:var(--bw) solid var(--line); border-radius:var(--r-card);
  box-shadow:var(--shadow-card); overflow:hidden; padding:0;
}

/* ---- Die Reiterleiste: wie im Builder, nicht wie Bootstrap ---- */

.obs-app .userprofile .nav-tabs{
  display:flex; gap:.15rem; list-style:none; margin:0;
  padding:.5rem .9rem 0; border-bottom:var(--bw) solid var(--line);
}
.obs-app .userprofile .nav-tabs .nav-item{margin:0;}
/* Die Knopfoptik kommt aus dem Haus, nicht von hier. obs.css hat schon
   .obs-main button:not([class*="btn"]):not(.obs-tab):not(.obs-nav) und dieselbe
   Regel mit .active — das ist 0,5,1 und damit spezifischer als jede
   .nav-link-Regel hier (0,5,0), wegen des Elementteils "button". Mein erster
   Entwurf wollte einen Unterstrich und hat verloren: gemessen blieb der
   Hintergrund rgba(42,59,224,.09). Statt die Spezifitaet hochzuschrauben gilt
   hier die Hausregel — sie ist genau fuer Bestandsknoepfe im Hauptbereich
   gebaut. Von hier nur noch die LEISTE und der Abstand. */
.obs-app .userprofile .nav-tabs .nav-link{padding:.4rem .8rem; cursor:pointer;}

.obs-app .userprofile .tab-content{padding:1rem 1.1rem;}

/* ---- Die Felder: zwei Spalten statt einer schmalen Reihe ----
   .row und .col-6 sind Bootstrap-Altnamen und kommen auch anderswo vor. Alles
   haengt deshalb an .userprofile - keine Fernwirkung. */

.obs-app .userprofile .row{
  display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:0 1.75rem;
}
.obs-app .userprofile .col-6{min-width:0;}
/* Die verschachtelte Reihe ist PLZ und Stadt - schmal und breit, nicht halbe-halbe. */
.obs-app .userprofile .row .row{grid-template-columns:7rem minmax(0, 1fr); gap:0 .75rem;}

.obs-app .userprofile .input-container{margin:0 0 .75rem;}
.obs-app .userprofile .input-container label,
.obs-app .userprofile .form-label{
  display:block; margin:0 0 .2rem;
  font-family:var(--f-ui); font-size:var(--label-fs); font-weight:var(--label-fw);
  letter-spacing:var(--label-ls); text-transform:var(--label-tt); color:var(--ink-3);
}
.obs-app .userprofile .form-control{width:100%; max-width:26rem;}

.obs-app .userprofile .card-footer{
  padding:.75rem 1.1rem; border-top:var(--bw) solid var(--line);
  display:flex; justify-content:flex-end;
}

/* ---- Abstand zur Verfuegbarkeitstafel darunter ---- */

.obs-app .userprofile + .wrapper{margin-top:1.5rem;}


/* ==========================================================================
   §37  KENNZAHLENKACHELN, KACHELBREITE, TABELLENUEBERSCHRIFT     25.08.2026
   --------------------------------------------------------------------------
   Aufgefallen auf /meine-skills, gilt aber ueberall — gemessen auch auf
   /meine-landschaften:

   Eine .obs-kpi war 226 px hoch bei 61 px Inhalt. Grund: die Kachel ist eine
   Flexspalte, und Absatzraender kollabieren im Flexlayout NICHT. Die drei <p>
   brachten je oben und unten ihren Standardrand mit, dazu die 5 px gap —
   gemessen lagen die Kinder bei top 31 / 91 / 161 statt 18 / 40 / 72.
   Eine Zeile raeumt das in jeder Kachel der Anwendung auf.

   Zweitens die Breite: .obs-kpis ist ein auto-fit-Raster mit minmax(180px,1fr).
   Bei zwei Kacheln nehmen sie die ganze Zeile — auf /meine-skills 628 px je
   Kachel fuer eine einstellige Zahl. Eine Obergrenze je Spur laesst wenige
   Kacheln links stehen und aendert bei vielen nichts (bei vier auf
   /meine-landschaften bleibt es bei 314 px, weil 314 < 22rem).

   Drittens die Tabellenueberschrift: <caption> steht im Browser zentriert. Auf
   /meine-skills stand "Skills dieser Organisation" mittig ueber der Tabelle und
   sah aus wie ein verrutschter Titel. Ueberschriften stehen links.
   ========================================================================== */

.obs-app .obs-kpi > p{margin:0;}

/* 18rem, nicht 22: auto-fit zaehlt die Spuren am MAXIMUM, nicht am Minimum
   (floor((Breite+gap)/(max+gap))). Mit 22rem ergab das bei 1272 px genau drei
   Spalten — die vier Kacheln auf /meine-landschaften brachen 3+1 um, gemessen.
   Mit 18rem sind es vier Spuren: vier Kacheln bleiben in einer Zeile (je 288),
   zwei stehen links und schmal. Der Preis: ab fuenf Kacheln wird umgebrochen.
   Bekannter Hoechststand heute sind vier. */
.obs-app .obs-kpis{grid-template-columns:repeat(auto-fit, minmax(11rem, 18rem));}

.obs-app .obs-table > caption{
  text-align:left; caption-side:top;
  padding:0 0 .5rem;
  font-family:var(--f-ui); font-size:.9375rem; font-weight:600; color:var(--ink);
}

/* ---- Gespraechswahl in der Skill-Werkstatt ----
   .obs-bld-sitzungen ist die Klasse aus dem Builder und dort in einer breiteren
   Spalte zuhause. In der Skillwerkstatt ist die Chatspalte 440 px, und weil der
   Block display:block ist, rutschte der Knopf "Neu" unter die Auswahlliste
   (gemessen: Liste 369 px, Knopf 43 px, zusammen mehr als die 406 px Innenmass).
   Eine Zeile, Liste schrumpfbar. Steht hier und nicht in obs-skill.css: das ist
   eine Kopie des Bestands, das hier ist eine Korrektur der neuen Fassung. */

.obs-app .obs-skl-chat .obs-bld-sitzungen{display:flex; align-items:center; gap:.4rem;}
.obs-app .obs-skl-chat .obs-bld-sitzungen select{flex:1 1 auto; min-width:0;}


/* ==========================================================================
   §38  SKILL-WERKSTATT UEBER DIE GANZE SEITE                     25.08.2026
   --------------------------------------------------------------------------
   Kai: "der sollte aber auch ueber die ganze seite gehen, und der chat sollte
   so aussehen wie die anderen".

   Gemessen vorher bei 2865 px Fenster: .obs-main 1320 breit (Lesebreite), das
   Raster mit festen 440px + 1fr und align-items:start, der Chat mit
   min-height:520px — also drei Vorgaben, die alle "so hoch wie der Inhalt"
   sagen, auf einer Seite, die eine Werkstatt ist.

   Dieselben Mittel wie §32 (Builder) und §35 (Plugin-Werkstatt): die Werkstatt
   IST die Seite. Und dieselbe Spaltenbreite wie der Builder —
   minmax(22rem, 26rem) statt fester 440px, damit die Chatspalte in beiden
   Werkstaetten gleich aussieht.

   Der Chat braucht darueber hinaus nur eine Aenderung: im Builder hat NUR die
   Nachricht des Menschen eine Sprechblase, der Assistent schreibt blank
   (.obs-bld-nachricht.ist-kunde .obs-bld-text hat den Hintergrund, sonst
   keiner). Hier hatte jede Nachricht eine, und die des Assistenten zusaetzlich
   --color-accent-100 — der olivgruene Kasten im Bild. Also blank.
   ========================================================================== */

.obs-app:has(.obs-skl-werkstatt) .obs-workspace{height:100dvh; min-height:0; overflow:hidden;}
.obs-app:has(.obs-skl-werkstatt) .obs-footer{display:none;}

.obs-app .obs-main:has(.obs-skl-werkstatt){
  flex:1 1 auto; min-height:0; overflow:hidden;
  max-width:none; width:100%; padding:0;
  display:flex; flex-direction:column;
}

/* Zwischen main und Werkstatt liegt der Container des Items (#obs-orga). Ohne
   diese Zeile bleibt er auf Inhaltshoehe und die Kette reisst. */
.obs-app .obs-main:has(.obs-skl-werkstatt) > div{
  flex:1 1 auto; min-height:0; display:flex; flex-direction:column;
}

.obs-app .obs-skl-werkstatt{
  flex:1 1 auto; min-height:0; display:flex; flex-direction:column;
  padding:.6rem 1rem .8rem;
}
.obs-app .obs-skl-werkstatt > .obs-page-head{flex:0 0 auto; margin:0 0 .5rem;}
.obs-app .obs-skl-werkstatt > .obs-skl-meldung{flex:0 0 auto;}

.obs-app .obs-skl-raster{
  flex:1 1 auto; min-height:0;
  grid-template-columns:minmax(22rem, 26rem) 1fr;
  gap:.75rem;
  align-items:stretch;
}

.obs-app .obs-skl-chat{min-height:0;}
.obs-app .obs-skl-verlauf{min-height:0;}
.obs-app .obs-skl-arbeit{min-height:0; overflow:auto;}

/* Der Assistent schreibt blank, wie im Builder. */
.obs-app .obs-skl-nachricht.obs-skl-von-assistent{
  background:none; padding-left:0; padding-right:0;
}

/* Enges Fenster: das Bestandsblatt stellt das Raster auf eine Spalte. Dann darf
   die Seite wieder scrollen, sonst ist der Chat 40 px hoch. */
@media (max-width:1100px){
  .obs-app:has(.obs-skl-werkstatt) .obs-workspace{height:auto; overflow:visible;}
  .obs-app .obs-main:has(.obs-skl-werkstatt){overflow:visible;}
  .obs-app .obs-skl-chat{min-height:26rem;}
}

/* ---- Die Arbeitsflaeche: Reiter oben, Tafel darunter, Formulare mit Lesebreite ----
   Bei 2865 px Fenster ist die Tafel 2165 px breit. Fuer den Editor ist das
   richtig, fuer ein Eingabefeld nicht: "Katalogsatz" war 1590 px breit. Also
   Lesebreite fuer die Formulare, volle Breite und Hoehe fuer den Inhalt — derselbe
   Gedanke wie in der Plugin-Werkstatt, wo der Editor die Tafel fuellt und die
   Listen daneben nicht mitwachsen. */

.obs-app .obs-skl-arbeit{display:flex; flex-direction:column;}
.obs-app .obs-skl-arbeit > .obs-tabs{flex:0 0 auto;}
.obs-app .obs-skl-arbeit > .obs-tabpanel:not([hidden]){
  flex:1 1 auto; min-height:0; overflow:auto;
  display:flex; flex-direction:column;
}
.obs-app .obs-skl-arbeit .obs-skl-felder,
.obs-app .obs-skl-arbeit .obs-skl-pform{max-width:74rem;}
.obs-app .obs-skl-arbeit .obs-skl-inhalt{flex:1 1 auto; min-height:0;}


/* ==========================================================================
   §39  PROJEKTSEITE ALS WERKSTATT                                25.08.2026
   --------------------------------------------------------------------------
   Kai: "bau das projekt management weiter" — und auf die Rueckfrage: volle
   Seite, Chat links wie in den anderen Werkstaetten.

   Vorher gemessen bei 2865 px Fenster: .obs-main 1320 (Lesebreite), das Raster
   mit festen "846px 352px", also Plan links und Chat RECHTS — gespiegelt zu
   Builder, Plugin-Werkstatt und Skill-Werkstatt, die den Chat alle links haben.
   Der Gantt sass mit height:352px und min-height:352px aus obs-projekt.css in
   einer Seite, die scrollt.

   Vier Werkstaetten, ein Aufbau: Chat links in derselben Breite
   (minmax(22rem,26rem)), Arbeit rechts, volle Hoehe, kein Seitenscrollen,
   Fusszeile weg.

   Der Chat wandert per order:-1 nach links, nicht durch Umbau der Vorlage.
   Das Markup bleibt Plan-dann-Chat; die Reihenfolge ist Gestaltung.

   Die Einwaende bleiben UEBER dem Plan stehen und werden nicht zum Reiter —
   so steht es in claude/projektmanagement-gantt.md: "deshalb sind die
   Warnungen Pflichtbestandteil der Ansicht und nicht ein Reiter".
   ========================================================================== */

.obs-app:has(.obs-pj-raum) .obs-workspace{height:100dvh; min-height:0; overflow:hidden;}
.obs-app:has(.obs-pj-raum) .obs-footer{display:none;}

.obs-app .obs-main:has(.obs-pj-raum){
  flex:1 1 auto; min-height:0; overflow:hidden;
  max-width:none; width:100%; padding:0;
  display:flex; flex-direction:column;
}
.obs-app .obs-main:has(.obs-pj-raum) > div{
  flex:1 1 auto; min-height:0; display:flex; flex-direction:column;
}

/* Der Kopf: eine Zeile. Die Vorzeile bleibt — sie traegt die Projektnummer
   (P-0001), und die benutzt man im Gespraech. */
.obs-app .obs-main:has(.obs-pj-raum) .obs-page-head{
  flex:0 0 auto; margin:0; padding:.55rem 1rem;
  display:flex; align-items:center; gap:1rem;
  border-bottom:var(--bw) solid var(--line);
}
.obs-app .obs-main:has(.obs-pj-raum) .obs-page-head > div{
  display:flex; align-items:baseline; gap:.6rem; flex-wrap:wrap; min-width:0;
}
.obs-app .obs-main:has(.obs-pj-raum) .obs-page-head h1{margin:0; font-size:1.05rem; line-height:1.2;}
.obs-app .obs-main:has(.obs-pj-raum) .obs-page-head p{margin:0;}
.obs-app .obs-main:has(.obs-pj-raum) .obs-page-head > .btn{margin-left:auto; flex:0 0 auto;}

.obs-app .obs-main:has(.obs-pj-raum) .obs-section{
  flex:1 1 auto; min-height:0;
  display:flex; flex-direction:column;
  max-width:none; width:100%; margin:0; padding:.6rem 1rem .8rem;
  border:0; border-radius:0; background:none; box-shadow:none;
}
.obs-app #obs-pj-meldung{flex:0 0 auto;}

.obs-app .obs-pj-raum{
  flex:1 1 auto; min-height:0;
  grid-template-columns:minmax(22rem, 26rem) 1fr;
  gap:.75rem; align-items:stretch;
}

/* Chat nach links, ohne die Vorlage anzufassen. */
.obs-app .obs-pj-chat{
  order:-1; min-height:0; height:auto;
  /* obs-projekt.css deckelt den Chat auf max-height:640px — gemessen genau das:
     Chat 640 hoch, Plan daneben 1062. Fuer eine scrollende Seite richtig, hier nicht. */
  max-height:none;
  display:flex; flex-direction:column;
}
.obs-app .obs-pj-chat-kopf{flex:0 0 auto;}
.obs-app .obs-pj-chat-verlauf{flex:1 1 auto; min-height:0; overflow:auto;}
.obs-app .obs-pj-chat-fuss{flex:0 0 auto;}

.obs-app .obs-pj-plan{min-height:0; display:flex; flex-direction:column;}
.obs-app .obs-pj-plan > .obs-pj-werkzeuge,
.obs-app .obs-pj-plan > .obs-pj-kopf,
.obs-app .obs-pj-plan > #obs-pj-einwaende,
.obs-app .obs-pj-plan > #obs-pj-vorschlag{flex:0 0 auto;}

/* Der Gantt nimmt, was uebrig ist. Die 352 px aus obs-projekt.css waren fuer
   eine scrollende Seite gedacht. */
.obs-app .obs-pj-gantt{flex:1 1 auto; height:auto; min-height:14rem;}

/* Die Featureliste darf den Plan nicht zusammendruecken — gedeckelt mit
   eigenem Scroller, wie der Meldungsstreifen in der Plugin-Werkstatt. */
.obs-app .obs-pj-featurestelle{flex:0 0 auto; max-height:16rem; overflow:auto;}

/* Enges Fenster: eine Spalte, und dann darf die Seite wieder scrollen. */
@media (max-width:1100px){
  .obs-app:has(.obs-pj-raum) .obs-workspace{height:auto; overflow:visible;}
  .obs-app .obs-main:has(.obs-pj-raum){overflow:visible;}
  .obs-app .obs-pj-raum{grid-template-columns:1fr;}
  .obs-app .obs-pj-chat{min-height:26rem;}
  .obs-app .obs-pj-gantt{min-height:22rem;}
}


/* ---- §39a  Der Projektchat wie die anderen Chats ----             25.08.2026
   Kai: "pass das chatfenstern gemaess den anderen chats an".

   Gemessen im Vergleich:

     Builder     Kunde  var(--color-neutral-100) als Blase, Assistent BLANK
                 Verfassen: Feld, darunter eine schmale Leiste mit dem Knopf
     Skill       ebenso (obs.css §38 hat den Assistenten dort blank gemacht)
     Projekt     Kunde  rgba(42,59,224,.09), max-width 90%
                 Assistent  rgb(213,222,226) — eine volle graue Blase, hier
                            2454 px hoch, weil die Antworten des Planers lang sind
                 Verfassen: Feld 385 breit, Knopf 385 breit darunter, kraeftig blau

   Der graue Kasten um eine 2454 px lange Antwort ist das Auffaellige: im Builder
   traegt nur der Mensch eine Blase, damit der Blick die eigene Zeile findet und
   die Antwort einfach Text ist. Genau das hier.
   -------------------------------------------------------------------------- */

.obs-app .obs-pj-nachricht-kunde{
  background:var(--color-neutral-100); max-width:none;
}
.obs-app .obs-pj-nachricht-assistent{
  background:none; padding-left:0; padding-right:0;
}

/* Verfassen: Feld und Knopf in einer Zeile, wie in der Skill-Werkstatt. Der
   Knopf ueber die ganze Spaltenbreite sah aus wie eine Fusszeile der Seite.
   Die Obergrenze fuer das Feld ist die des Builders (180 px), damit ein langer
   Entwurf den Verlauf nicht wegdrueckt. */
.obs-app .obs-pj-chat-fuss{
  /* flex-direction MUSS mit: obs-projekt.css stellt den Fuss auf column. Ohne
     die Zeile wirkte mein align-items:flex-end auf die Querachse und hat Feld
     und Knopf nach rechts geschrumpft — gemessen Feld 179 px statt 300. */
  display:flex; flex-direction:row; align-items:flex-end; gap:.5rem;
}
.obs-app .obs-pj-chat-fuss #obs-pj-eingabe{
  flex:1 1 auto; min-width:0; max-height:180px;
}
.obs-app .obs-pj-chat-fuss #obs-pj-senden{flex:0 0 auto; width:auto;}


/* ==========================================================================
   §41  DER EJ2-GANTT NACH DER VORLAGE — zweite Fassung            25.08.2026
   --------------------------------------------------------------------------
   Kai zur ersten Fassung: "am gantt sehe ich noch nicht wirklich was ausser
   das der nachtmodus nicht lesbar ist". Beides hat einen Grund.

   1. WARUM DIE ERSTE FASSUNG KAUM WIRKTE. Die Reihenfolge der Blaetter auf
      /projekt ist: Schriften, obs.css, obs-marke.css, ej2-gantt-34.2.4.min.css,
      obs-projekt.css. EJ2 kommt also NACH obs.css — es steckt im Element, nicht
      in der Huelle. Bei gleicher Spezifitaet gewinnt das spaetere Blatt, und
      EJ2 hat reichlich Selektoren mit drei Klassen. Meine ".obs-app .e-gantt
      .e-rowcell" (0,3,0) war damit oft nur gleichwertig, nicht staerker.
      Gezaehlt: 2.638 Hexfarben, aber nur 6 !important auf background und 6 auf
      color — es ist also KEIN !important-Problem, sondern Spezifitaet.

      Deshalb haengt jetzt alles an der ID #obs-pj-gantt: (1,1,0) schlaegt jede
      Klassenkette ohne Ausnahme, und die Datei bleibt ohne !important.

   2. WARUM DER NACHTMODUS UNLESBAR WAR. EJ2 ist ein Hellthema mit fest
      eingebauten Farben. Die Flaechen kamen aus meinen Regeln (dunkel), die
      SCHRIFT blieb EJ2s dunkles Grau — dunkel auf dunkel. Farbe wird deshalb
      jetzt an jeder Textstelle gesetzt, die EJ2 anfasst, und zwar aus den
      Marken. Damit folgt der Gantt Tageslicht und Nacht von selbst; ein
      eigener Dunkelfall ist nicht noetig.

   Die Vorlage (Prototyp, Ansicht "Projekt"): Wochenspalten, graue Phasenbalken,
   Akzentbalken mit Prozentchip links, rote HEUTE-Linie, duenne graue Winkel.
   ========================================================================== */

#obs-pj-gantt,
#obs-pj-gantt .e-gantt,
#obs-pj-gantt .e-gantt-splitter,
#obs-pj-gantt .e-gantt-tree-grid-pane,
#obs-pj-gantt .e-gantt-chart-pane{border-color:var(--line); background:var(--panel); color:var(--ink);}

#obs-pj-gantt *{font-family:var(--f-ui);}

#obs-pj-gantt .e-gridcontent,
#obs-pj-gantt .e-content,
#obs-pj-gantt .e-table,
#obs-pj-gantt .e-row,
#obs-pj-gantt .e-chart-rows-container{background:var(--panel);}

#obs-pj-gantt .e-split-bar{background:var(--line); border-color:var(--line);}

/* ---- Kopfzeilen ---- */

#obs-pj-gantt .e-gridheader,
#obs-pj-gantt .e-headercontent,
#obs-pj-gantt .e-timeline-header-container,
#obs-pj-gantt .e-timeline-header-table-container,
#obs-pj-gantt .e-headercell,
#obs-pj-gantt .e-timeline-top-header-cell,
#obs-pj-gantt .e-timeline-single-header-cell{
  background:var(--panel); border-color:var(--line); color:var(--ink-3);
}
#obs-pj-gantt .e-headertext,
#obs-pj-gantt .e-header-cell-label,
#obs-pj-gantt .e-gantt-top-cell-text{
  color:var(--ink-3); font-size:.75rem; font-weight:600; letter-spacing:.02em;
}

/* ---- Tabellenzeilen. Die erste Spalte traegt die Nummer: Schreibmaschine. ---- */

#obs-pj-gantt .e-rowcell,
#obs-pj-gantt .e-treecell{
  color:var(--ink); font-size:.8125rem; border-color:var(--line); background:var(--panel);
}
#obs-pj-gantt .e-rowcell:first-child{font-family:var(--f-mono); font-size:.75rem; color:var(--ink-3);}
#obs-pj-gantt .e-row:hover .e-rowcell{background:var(--panel-2);}

/* Aufklapppfeile und alle uebrigen Zeichen: EJ2 setzt sie dunkel. */
#obs-pj-gantt .e-icons,
#obs-pj-gantt .e-treegridexpand,
#obs-pj-gantt .e-treegridcollapse,
#obs-pj-gantt .e-btn.e-flat{color:var(--ink-2);}

/* ---- Der Balkenteil ---- */

#obs-pj-gantt .e-chart-row-cell,
#obs-pj-gantt .e-chart-row-border,
#obs-pj-gantt .e-chart-row{border-color:var(--line);}
#obs-pj-gantt .e-weekend,
#obs-pj-gantt .e-weekend-header-cell{background:var(--ground-2);}

/* Schrittbalken: der ganze Balken hell, der erledigte Teil satt — wie die
   Vorlage. EJ2 legt beides uebereinander (taskbar / progressbar). */
#obs-pj-gantt .e-gantt-child-taskbar,
#obs-pj-gantt .e-gantt-child-taskbar-inner-div{
  background:var(--accent-soft); border:0; border-radius:5px;
}
#obs-pj-gantt .e-gantt-child-progressbar,
#obs-pj-gantt .e-gantt-child-progressbar-inner-div{
  background:var(--accent); border:0; border-radius:5px;
}
#obs-pj-gantt .e-task-label{
  color:var(--accent-ink); font-family:var(--f-mono); font-size:.6875rem; font-weight:600;
}

/* Phasenbalken: schmaler grauer Riegel statt EJ2s dunklem Block. */
#obs-pj-gantt .e-gantt-parent-taskbar,
#obs-pj-gantt .e-gantt-parent-taskbar-inner-div{
  background:var(--line-2); border:0; border-radius:3px;
}
#obs-pj-gantt .e-gantt-parent-progressbar,
#obs-pj-gantt .e-gantt-parent-progressbar-inner-div{
  background:var(--ink-3); border:0; border-radius:3px;
}

/* Meilenstein: Raute im Akzent. EJ2 baut sie aus zwei Rahmenhaelften. */
#obs-pj-gantt .e-milestone-top{border-bottom-color:var(--accent);}
#obs-pj-gantt .e-milestone-bottom{border-top-color:var(--accent);}

/* Abhaengigkeiten */
#obs-pj-gantt .e-line{background:var(--line-2); border-color:var(--line-2);}
#obs-pj-gantt .e-connector-line-right-arrow{border-left-color:var(--line-2);}
#obs-pj-gantt .e-connector-line-left-arrow{border-right-color:var(--line-2);}

/* Beschriftung neben dem Balken */
#obs-pj-gantt .e-right-label-container,
#obs-pj-gantt .e-left-label-container,
#obs-pj-gantt .e-right-label-container span,
#obs-pj-gantt .e-left-label-container span{color:var(--ink-2); font-size:.75rem;}

/* ============================================================================
 * §42  EJ2 ausserhalb des Gantt: Dialoge, Kurzhinweise, Auswahllisten
 *      25.08.2026
 *
 * Gemessen auf /projekt in der Nachtfassung: der Dialog bleibt WEISS
 * (background rgb(255,255,255) aus ej2-gantt-34.2.4.min.css) und erbt dabei
 * meine helle Schrift (--ink = rgb(239,233,220)). Kopf und Fuss sind damit
 * unlesbar; nur der Inhalt behaelt EJ2s dunkle Schrift und ist ein heller
 * Kasten mitten in einer dunklen Oberflaeche.
 *
 * Zwei Dinge zur Bauweise:
 * 1) EJ2 haengt Dialoge, Kurzhinweise und Auswahllisten an den KOERPER,
 *    nicht in den Gantt. Der Anker aus §41 (#obs-pj-gantt) greift dort also
 *    nicht. Darum hier "body" plus doppelte Klasse: (0,2,1) schlaegt alles,
 *    was EJ2 mit zwei Klassen schreibt -- und ej2-...css laedt NACH obs.css,
 *    bei gleicher Gewichtung gewinnt sonst EJ2.
 * 2) Kein !important. Die Gewichtung reicht, und !important nimmt einer
 *    einzelnen Seite die Moeglichkeit, einen Dialog anders zu setzen.
 * ==========================================================================*/

body .e-dlg-container.e-dlg-container{font-family:var(--f-ui);}
body .e-dlg-overlay.e-dlg-overlay{background:rgba(6,16,20,.55);}

body .e-dialog.e-dialog{
  background:var(--panel); color:var(--ink);
  border:var(--bw) solid var(--line); border-radius:var(--r-card);
  box-shadow:0 18px 48px rgba(6,16,20,.28);
  font-family:var(--f-ui);
}
body .e-dialog.e-dialog *{font-family:inherit;}

body .e-dialog.e-dialog .e-dlg-header-content{
  background:var(--panel-2); color:var(--ink);
  border-bottom:1px solid var(--line);
  border-radius:var(--r-card) var(--r-card) 0 0;
  padding:.7rem var(--pad);
}
body .e-dialog.e-dialog .e-dlg-header,
body .e-dialog.e-dialog .e-dlg-header *{
  color:var(--ink); font-size:.9375rem; font-weight:600;
}
body .e-dialog.e-dialog .e-dlg-content{
  background:var(--panel); color:var(--ink); font-size:.8125rem; line-height:1.5;
}
body .e-dialog.e-dialog .e-footer-content{
  background:var(--panel-2); border-top:1px solid var(--line);
  border-radius:0 0 var(--r-card) var(--r-card);
  padding:.6rem var(--pad);
}

/* Schliesskreuz */
body .e-dialog.e-dialog .e-dlg-closeicon-btn,
body .e-dialog.e-dialog .e-icon-dlg-close{background:none; color:var(--ink-3);}
body .e-dialog.e-dialog .e-dlg-closeicon-btn:hover{background:var(--panel-3); color:var(--ink);}

/* Knoepfe im Dialog: Haus-Optik, der bestaetigende in Akzent */
body .e-dialog.e-dialog .e-btn{
  background:var(--panel); color:var(--ink);
  border:var(--bw) solid var(--line); border-radius:var(--r-sm);
  font-family:var(--f-ui); font-size:.8125rem; font-weight:500;
  padding:.34rem .8rem; box-shadow:none; text-transform:none;
}
body .e-dialog.e-dialog .e-btn:hover{background:var(--panel-3);}
body .e-dialog.e-dialog .e-btn.e-primary{
  background:var(--accent); color:var(--accent-ink); border-color:var(--accent);
}
body .e-dialog.e-dialog .e-btn.e-flat{
  background:none; color:var(--ink-2); border-color:transparent;
}

/* Eingaben im Bearbeitungsdialog */
body .e-dialog.e-dialog .e-input-group,
body .e-dialog.e-dialog .e-input,
body .e-dialog.e-dialog input.e-control,
body .e-dialog.e-dialog textarea{
  background:var(--panel); color:var(--ink);
  border-color:var(--line); border-radius:var(--r-sm);
  font-family:var(--f-ui); font-size:.8125rem;
}
body .e-dialog.e-dialog .e-input-group::before,
body .e-dialog.e-dialog .e-input-group::after{background:var(--accent);}
body .e-dialog.e-dialog .e-float-text,
body .e-dialog.e-dialog .e-label{color:var(--ink-3);}

/* Reiter im Bearbeitungsdialog */
body .e-dialog.e-dialog .e-tab .e-tab-header{
  background:var(--panel-2); border-bottom:1px solid var(--line);
}
body .e-dialog.e-dialog .e-tab .e-tab-header .e-tab-text{
  color:var(--ink-2); font-size:.75rem; font-weight:var(--label-fw);
  letter-spacing:var(--label-ls); text-transform:var(--label-tt);
}
body .e-dialog.e-dialog .e-tab .e-tab-header .e-toolbar-item.e-active .e-tab-text{color:var(--ink);}
body .e-dialog.e-dialog .e-tab .e-tab-header .e-indicator{background:var(--accent);}

/* Auswahllisten und Kalender haengen ebenfalls am Koerper */
body .e-popup.e-popup-open.e-ddl,
body .e-popup.e-popup-open.e-datepicker,
body .e-popup.e-popup-open.e-timepicker{
  background:var(--panel); color:var(--ink);
  border:var(--bw) solid var(--line); border-radius:var(--r-sm);
  box-shadow:0 12px 28px rgba(6,16,20,.24);
}
body .e-popup.e-popup .e-list-item{
  background:none; color:var(--ink);
  font-family:var(--f-ui); font-size:.8125rem;
}
body .e-popup.e-popup .e-list-item.e-hover,
body .e-popup.e-popup .e-list-item.e-active{background:var(--accent-soft); color:var(--ink);}

/* Kurzhinweis: umgekehrt, wie im Haus ueblich. --ink auf --ground traegt in
   beiden Fassungen, weil beide Marken mitkippen. */
body .e-tooltip-wrap.e-tooltip-wrap{
  background:var(--ink); border:0; border-radius:var(--r-sm);
  box-shadow:0 10px 24px rgba(6,16,20,.30); font-family:var(--f-ui);
}
body .e-tooltip-wrap.e-tooltip-wrap .e-tip-content{
  background:none; color:var(--ground);
  font-size:.75rem; line-height:1.45; padding:.4rem .6rem;
}
body .e-tooltip-wrap.e-tooltip-wrap .e-tip-content *{
  color:inherit; border-color:rgba(127,127,127,.35);
}
body .e-tooltip-wrap.e-tooltip-wrap .e-arrow-tip-inner{color:var(--ink);}
body .e-tooltip-wrap.e-tooltip-wrap .e-arrow-tip-outer-top{border-bottom-color:var(--ink);}
body .e-tooltip-wrap.e-tooltip-wrap .e-arrow-tip-outer-bottom{border-top-color:var(--ink);}
body .e-tooltip-wrap.e-tooltip-wrap .e-arrow-tip-outer-left{border-right-color:var(--ink);}
body .e-tooltip-wrap.e-tooltip-wrap .e-arrow-tip-outer-right{border-left-color:var(--ink);}

/* Kontextmenue des Gantt */
body .e-contextmenu-wrapper ul.e-contextmenu{
  background:var(--panel); border:var(--bw) solid var(--line);
  border-radius:var(--r-sm); box-shadow:0 12px 28px rgba(6,16,20,.24);
}
body .e-contextmenu-wrapper ul.e-contextmenu li.e-menu-item{
  color:var(--ink); font-family:var(--f-ui); font-size:.8125rem;
}
body .e-contextmenu-wrapper ul.e-contextmenu li.e-menu-item.e-focused,
body .e-contextmenu-wrapper ul.e-contextmenu li.e-menu-item:hover{background:var(--accent-soft);}
body .e-contextmenu-wrapper ul.e-contextmenu li.e-separator{border-color:var(--line);}

/* ============================================================================
 * §43  Fortschritt, Verzug und die Heute-Linie (25.08.2026)
 *
 * Aus dem Entwurf: ueber dem Plan stehen zwei Zahlen, die es in der Seite
 * bisher nicht gab -- der gewichtete Fortschritt und, wenn es einen gibt, der
 * Verzug gegen das Zieldatum. Gerechnet wird in obs-projekt.js
 * (fortschrittRechnen / verzugRechnen); hier steht nur das Aussehen.
 *
 * Der Prozentwert steht als --wert am Fuellbalken. Das ist die eine Stelle,
 * an der ein Wert am Element stehen MUSS -- er kommt aus den Daten. Als
 * Variable bleibt trotzdem jede Farbe und jede Kante hier im Stylesheet.
 * ==========================================================================*/

.obs-app .obs-pj-kopf-fortschritt{
  display:flex; flex-direction:row; align-items:center; flex-wrap:wrap;
  gap:.55rem; margin:.55rem 0 0;
}
.obs-app .obs-pj-kopf-bahn{
  flex:0 1 14rem; min-width:6rem; height:6px;
  background:var(--ground-2); border-radius:var(--r-pill); overflow:hidden;
}
.obs-app .obs-pj-kopf-fuellung{
  display:block; height:100%; width:var(--wert, 0%);
  background:var(--accent); border-radius:var(--r-pill);
}
.obs-app .obs-pj-kopf-prozent{
  font-family:var(--f-mono); font-size:.8125rem; color:var(--ink);
}
.obs-app .obs-pj-kopf-verzug{
  color:var(--crit); background:color-mix(in srgb, var(--crit) 13%, transparent);
  border-radius:var(--r-pill); padding:.1rem .5rem;
  font-size:.75rem; font-weight:600;
}

/* Die Heute-Linie (EJ2 eventMarkers). EJ2 zeichnet den Strich als linken
   Rahmen von .e-event-markers und haengt die Beschriftung als .e-span-label
   daran. Die Marke bleibt eine Umrandung statt einer gefuellten Flaeche: eine
   gefuellte kritische Flaeche braucht eine Gegenfarbe, und die einzige, die in
   beiden Fassungen traegt, waere ein festes Weiss -- also eine Farbe ohne
   Marke. */
#obs-pj-gantt .e-event-markers{border-left:1px dashed var(--crit);}
#obs-pj-gantt .e-event-markers .e-span-label{
  background:var(--panel); color:var(--crit);
  border:1px solid var(--crit); border-radius:var(--r-pill);
  padding:.05rem .4rem;
  font-family:var(--f-ui); font-size:.625rem; font-weight:700;
  letter-spacing:var(--label-ls); text-transform:uppercase;
}

/* ============================================================================
 * §44  Der Projektchat wie die anderen Werkstattchats (25.08.2026)
 *
 * Gemessen gegen die Skill-Werkstatt (dieselbe Bauform wie der Builder):
 *
 *   Stelle       Projekt (vorher)              andere Chats
 *   ---------------------------------------------------------------------
 *   Karte        radius 8px, padding 0         radius 12px, padding 16px
 *   Kopf         14,4px/600, Trennlinie unten  16,8px/700, keine Linie,
 *                Padding 11/14                 12px Abstand darunter
 *   Verlauf      padding 14,4px                padding 0, flex:1 1 0
 *   Fuss         Trennlinie oben, Padding      kein Rahmen, 12px Abstand
 *   Eingabefeld  13px, Polster 7/9             14px, Polster 10
 *
 * Die anderen Chats setzen das Polster EINMAL an der Karte; die Teile darin
 * sind randlos. Der Projektchat hatte es umgekehrt: Karte ohne Polster, dafuer
 * drei Teile mit eigenem Polster und zwei Trennlinien. Daher sah er wie ein
 * Kasten mit Titelbalken aus und nicht wie eine Spalte.
 *
 * .obs-pj-chat-fuss traegt in §39a schon display/flex-direction/align-items --
 * hier stehen nur Polster, Rahmen und Abstand, damit sich die beiden Bloecke
 * nicht ins Gehege kommen.
 * ==========================================================================*/

.obs-app .obs-pj-chat{
  border-radius:var(--r-card);
  padding:var(--pad);
}
.obs-app .obs-pj-chat-kopf{
  display:flex; flex-direction:row; align-items:center; justify-content:space-between;
  gap:.75rem;
  margin:0 0 .75rem; padding:0;
  border-bottom:0;
  font-size:1.05rem; font-weight:700; color:var(--ink);
}
.obs-app .obs-pj-chat-verlauf{
  flex:1 1 0; min-height:0;
  padding:0; gap:.75rem;
}
.obs-app .obs-pj-chat-fuss{
  margin-top:.75rem; padding:0;
  border-top:0;
}
.obs-app .obs-pj-chat-fuss #obs-pj-eingabe{
  padding:10px; min-height:70px;
  font-size:.875rem;
}

/* ============================================================================
 * §45  Sitzungsleiste und Verbrauchsbalken (25.08.2026)
 *
 * Die Klassen .obs-bld-sitzungen / .obs-bld-budget kommen aus dem Bestandsblatt
 * und werden von Builder, Skill- und Plugin-Werkstatt benutzt. Der Projektchat
 * benutzt sie jetzt mit — gemessen in der neuen Fassung sind sie dort aber
 * NACKT: Leiste display:block, Balken 0 px hoch, Fuellung ohne Farbe, Text
 * 14 px mit 14 px Aussenabstand. Das Bestandsblatt liegt in dieser Rolle nicht.
 *
 * Die Werte sind die der Skill-Werkstatt (dort gemessen: Balken 6 px,
 * radius 999, Fuellung im Akzent, Text 12,8 px) — nur in Marken statt in Zahlen.
 * ==========================================================================*/

.obs-app .obs-bld-sitzungen{
  display:flex; flex-direction:row; align-items:center; gap:.4rem;
  margin:0 0 .5rem;
}
.obs-app .obs-bld-sitzungen select{flex:1 1 auto; min-width:0;}
.obs-app .obs-bld-sitzungen button{flex:0 0 auto;}

.obs-app .obs-bld-budget{margin:0 0 .75rem;}
.obs-app .obs-bld-budget-balken{
  height:6px; background:var(--panel-3);
  border-radius:var(--r-pill); overflow:hidden;
}
/* Die Fuellung ist ein span mit Breite am Element — der Wert kommt aus den
   Daten. Alles andere steht hier. */
.obs-app .obs-bld-budget-balken > span{
  display:block; height:100%; width:0;
  background:var(--accent); border-radius:var(--r-pill);
}
.obs-app .obs-bld-budget-balken > span.ist-knapp{background:var(--warn);}
.obs-app .obs-bld-budget-balken > span.ist-voll{background:var(--crit);}
.obs-app .obs-bld-budget-text{
  margin:.3rem 0 0;
  font-size:.75rem; color:var(--ink-3);
}

/* ============================================================================
 * §46  Verwaltung: die Benutzerliste auf Marken (25.08.2026)
 *
 * Kai: "http://kaistat-pc3/verwaltung das musst du noch machen."
 *
 * obs-benutzer.css (2.744 Z, Bestand) traegt 20 feste Farbwerte und keine einzige
 * Marke — es ist der Fall, den redesign-baulog-24-08.md als "naechster grosser
 * Handgriff" notiert hat: die Variablenbruecke greift dort nicht, weil es echte
 * Klassenregeln sind. Das Blatt bleibt unangetastet (es bedient auch die alte
 * Fassung); uebersteuert wird hier, mit .obs-app davor — obs-benutzer.css laedt
 * NACH obs.css, bei gleicher Gewichtung gewinnt sonst es.
 *
 * Gemessen in der Nachtfassung, bevor das hier stand:
 *   .obs-bn-person  Kontrast 1,5  (Farbe rgb(0,0,238) — der Browserstandard,
 *                   das Blatt gibt dem Verweis ueberhaupt keine Farbe)
 * Das war der einzige unlesbare Punkt. Die uebrigen Werte sind lesbar, aber
 * fremd: drei pastellfarbene Aufkleber und graue Linien aus einer hellen Welt.
 *
 * NEBENBEFUND: der Verweis von der Benutzerliste auf die Personenseite steht
 * schon (/person) — er stand in den Notizen seit Tagen als offen, war aber
 * gebaut und nur nicht zu sehen.
 * ==========================================================================*/

/* Der Verweis auf die Personenseite: eigene Zeile statt hinter dem Datum, und
   in der Akzentfarbe. Vorher klebte "Rollen und Kapazität" ohne Abstand am
   Datum ("26.8.2026Rollen und Kapazität"). */
.obs-app .obs-bn-person{
  display:block; margin-top:.15rem;
  color:var(--accent); font-size:.75rem; text-decoration:none;
}
.obs-app .obs-bn-person:hover{text-decoration:underline;}

/* Tabelle */
.obs-app .obs-bn-tabelle th{
  color:var(--ink-3); border-bottom-color:var(--line);
  font-size:var(--label-fs); font-weight:var(--label-fw);
  letter-spacing:var(--label-ls); text-transform:var(--label-tt);
}
.obs-app .obs-bn-tabelle td{
  color:var(--ink); border-bottom-color:var(--line-2);
}
.obs-app .obs-bn-mailspalte{color:var(--ink-2); font-family:var(--f-mono); font-size:.8125rem;}

/* Zustaende. Statt drei Pastellaufklebern: die Hausfarbe in 13 % als Flaeche,
   die Schrift in derselben Farbe. Traegt in beiden Fassungen, weil beide Marken
   mitkippen. */
.obs-app .obs-bn-status{
  border-radius:var(--r-pill); padding:.1rem .5rem;
  font-size:.75rem; font-weight:600;
}
.obs-app .obs-bn-status.ist-aktiv{
  background:color-mix(in srgb, var(--ok) 13%, transparent); color:var(--ok);
}
.obs-app .obs-bn-status.ist-eingeladen{
  background:color-mix(in srgb, var(--info) 13%, transparent); color:var(--info);
}
.obs-app .obs-bn-status.ist-gesperrt{
  background:color-mix(in srgb, var(--crit) 13%, transparent); color:var(--crit);
}

/* Hinweise, Meldungen, Fusszeile */
.obs-app .obs-bn-leer,
.obs-app .obs-bn-laden,
.obs-app .obs-bn-fuss,
.obs-app .obs-bn-melder{color:var(--ink-3);}
.obs-app .obs-bn-fehler,
.obs-app .obs-bn-melder.ist-fehler{color:var(--crit);}

/* Einladeformular */
.obs-app .obs-bn-einladen{border-top-color:var(--line);}
.obs-app .obs-bn-feld > span{color:var(--ink-2);}
.obs-app .obs-bn-feld em{color:var(--ink-3);}
.obs-app .obs-bn-feld input,
.obs-app .obs-bn-feld textarea{
  background:var(--panel); color:var(--ink);
  border-color:var(--line); border-radius:var(--r-sm);
  font-family:var(--f-ui);
}
.obs-app .obs-bn-feld input:focus,
.obs-app .obs-bn-feld textarea:focus{
  border-color:var(--accent); outline-color:var(--accent);
}

/* §46a  Nachtrag: die Mailspalte verlor gegen die eigene Zeilenregel.
   .obs-app .obs-bn-tabelle td ist (0,2,1) — der Elementname zaehlt mit — und
   schlaegt damit .obs-app .obs-bn-mailspalte (0,2,0). Gemessen: die Spalte stand
   auf --ink statt --ink-2. Derselbe Rechenfehler wie bei den .nav-link-Regeln am
   24.08.; die Antwort ist nicht !important, sondern eine Stelle mehr. */
.obs-app .obs-bn-tabelle td.obs-bn-mailspalte{color:var(--ink-2);}

/* ============================================================================
 * §47  Feldraster fuer Formulare (25.08.2026)
 *
 * Kai: "rechnugnsdaten sieht aber kacke aus."
 *
 * Und zwar zu Recht. Gemessen auf /verwaltung im Reiter Rechnungsdaten:
 *
 *   label.obs-skl-feld   222x18, 314x18, 347x18, 1126x53 ...   input je 185px
 *
 * Ein label ist von Haus aus INLINE. Ohne Regel umschliesst es seinen Inhalt
 * nicht (18 px hoch bei einem 35 px hohen Feld), die Breiten richten sich nach
 * der Beschriftung, und die Felder stehen alle auf ihrer Standardbreite.
 *
 * Der Grund ist eine Blattgrenze: die Regeln fuer .obs-skl-feld liegen in
 * obs-skill.css — dem Auszug aus dem Bestand, der NUR auf /skill und
 * /meine-skills geladen wird. Die Verwaltung benutzt dieselben Klassen und hat
 * das Blatt nicht. Genau der Fall aus redesign-baulog-24-08.md: "Klassen ohne
 * Entsprechung im neuen Stylesheet ... obs-skl-feld".
 *
 * Deshalb stehen sie jetzt HIER, im Hausblatt, und gelten fuer jede Seite.
 * Die Werte sind die auf /skill gemessenen (Raster 2 Spalten, Abstand 16 px,
 * Feld flex-column mit 6 px, Eingabe volle Breite, Polster 7/9, 13 px) — damit
 * sich dort nichts aendert. ZWEI SPALTEN FEST und nicht auto-fit: auto-fit mit
 * 18 rem haette auf /skill aus zwei Spalten drei gemacht.
 * ==========================================================================*/

.obs-app .obs-skl-felder{
  display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:1rem;
}
.obs-app .obs-skl-feld{
  display:flex; flex-direction:column; gap:.375rem;
  font-size:.95rem;
}
.obs-app .obs-skl-feld > span{color:var(--ink); font-weight:600;}
.obs-app .obs-skl-feld em{color:var(--ink-3); font-style:italic; font-weight:400;}

/* Ein breites Feld nimmt die ganze Zeile — Anschrift, Beschreibung, Nachricht. */
.obs-app .obs-skl-feld-breit{grid-column:1 / -1;}

.obs-app .obs-skl-feld input,
.obs-app .obs-skl-feld select,
.obs-app .obs-skl-feld textarea{
  width:100%; padding:7px 9px;
  background:var(--panel); color:var(--ink);
  border:1px solid var(--line); border-radius:var(--r-sm);
  font-family:var(--f-ui); font-size:.8125rem;
}
.obs-app .obs-skl-feld textarea{min-height:6rem; resize:vertical;}
.obs-app .obs-skl-feld input:focus,
.obs-app .obs-skl-feld select:focus,
.obs-app .obs-skl-feld textarea:focus{
  border-color:var(--accent); outline:1px solid var(--accent); outline-offset:-1px;
}

/* Eine Spalte, sobald zwei nebeneinander nicht mehr lesbar sind. */
@media (max-width: 52rem){
  .obs-app .obs-skl-felder{grid-template-columns:1fr;}
}

/* ============================================================================
 * §48  Die Frageknoepfe des Assistenten (27.08.2026)
 *
 * Kai: "wenn der chatbot rückfragen stellt klickt man die buttons. es ändert
 * sich aber nicht der style."
 *
 * Der Klick TUT das Richtige: obs-chat.js nimmt den Geschwistern 'ist-an' weg
 * und setzt es am angeklickten Chip, die Plugin-Werkstatt dasselbe mit 'plg-an'.
 * Und die Regeln dafuer stehen im Bestand:
 *
 *   obs-chat.css    .obs-ch-chip.ist-an    {background:#1f6feb; ...}   (0,2,0)
 *   obs-plugin.css  .obs-plg-chip.plg-an   {background:#1f6feb; ...}   (0,2,0)
 *
 * Sie verlieren gegen die HAUSREGEL fuer Bestandsknoepfe im Hauptbereich:
 *
 *   .obs-main button:not([class*="btn"]):not(.obs-tab):not(.obs-nav)    (0,4,1)
 *
 * Die faerbt jeden Chip gleich, gewaehlt oder nicht. Spezifitaet kommt vor
 * Blattreihenfolge — dass obs-chat.css SPAETER laedt, hilft deshalb nicht.
 * Dritter Fall derselben Rechnung nach .nav-link (§36) und der Mailspalte (§46a).
 *
 * Darum steht hier der ganze Frageblock, mit dem echten DOM-Pfad als Anker:
 * fuenf Klassen plus button sind (0,5,1) und schlagen die Hausregel um eine
 * Stelle. Kein !important.
 *
 * BEIDE FAMILIEN, obwohl sie dasselbe tun: der Builder und die Skill-Werkstatt
 * benutzen obs-chat.js (obs-ch-*), die Plugin-Werkstatt hat eine eigene Kopie in
 * ihrer Vorlage (obs-plg-*). Eine davon zu vergessen heisst, den Fehler in einer
 * der drei Werkstaetten stehenzulassen.
 * ==========================================================================*/

/* --- der Kasten um die Rueckfragen ------------------------------------------ */
.obs-app .obs-ch-fragen,
.obs-app .obs-plg-fragen{
  margin:.5rem 0; padding:.6rem .7rem;
  background:var(--panel-2);
  border:1px solid var(--line); border-radius:var(--r-sm);
}
.obs-app .obs-ch-frage,
.obs-app .obs-plg-frage{
  margin:.2rem 0 .4rem;
  color:var(--ink); font-weight:600; font-size:.86rem; line-height:1.35;
}
.obs-app .obs-ch-wahl,
.obs-app .obs-plg-wahl{
  display:flex; flex-direction:row; flex-wrap:wrap; gap:.35rem;
  margin-bottom:.5rem;
}
.obs-app .obs-ch-fuss,
.obs-app .obs-plg-fragen-fuss{
  margin:0; color:var(--ink-3); font-size:.75rem;
}

/* Abgeschickt: der Kasten tritt zurueck, bleibt aber lesbar — man will noch
   sehen, was man geantwortet hat. */
.obs-app .obs-ch-fragen.ist-erledigt,
.obs-app .obs-plg-fragen.plg-erledigt{
  opacity:.62; pointer-events:none;
}

/* --- die Chips: (0,5,1), damit die Hausregel nicht dazwischenfaehrt --------- */
.obs-app .obs-main .obs-ch-fragen .obs-ch-wahl button.obs-ch-chip,
.obs-app .obs-main .obs-plg-fragen .obs-plg-wahl button.obs-plg-chip{
  background:var(--panel); color:var(--ink);
  border:1px solid var(--line); border-radius:var(--r-pill);
  padding:.25rem .65rem;
  font-family:var(--f-ui); font-size:.8rem; font-weight:500; line-height:1.3;
  text-align:left; cursor:pointer;
}
.obs-app .obs-main .obs-ch-fragen .obs-ch-wahl button.obs-ch-chip:hover,
.obs-app .obs-main .obs-plg-fragen .obs-plg-wahl button.obs-plg-chip:hover{
  background:var(--panel-3); border-color:var(--line-2);
}

/* GEWAEHLT. Der eigentliche Auftrag: das muss man sehen, ohne zu suchen. */
.obs-app .obs-main .obs-ch-fragen .obs-ch-wahl button.obs-ch-chip.ist-an,
.obs-app .obs-main .obs-plg-fragen .obs-plg-wahl button.obs-plg-chip.plg-an{
  background:var(--accent); color:var(--accent-ink);
  border-color:var(--accent); font-weight:600;
}
.obs-app .obs-main .obs-ch-fragen .obs-ch-wahl button.obs-ch-chip.ist-an:hover,
.obs-app .obs-main .obs-plg-fragen .obs-plg-wahl button.obs-plg-chip.plg-an:hover{
  background:var(--accent); border-color:var(--accent);
}

/* "Antwort senden" — derselbe Akzent, aber als Umrandung: gefuellt sahen
   Auswahl und Absenden gleich aus, und dann klickt man das Falsche. */
.obs-app .obs-main .obs-ch-fragen .obs-ch-wahl button.obs-ch-chip.ist-senden,
.obs-app .obs-main .obs-plg-fragen .obs-plg-wahl button.obs-plg-chip.plg-senden{
  background:var(--accent-soft); color:var(--accent);
  border-color:var(--accent); font-weight:600;
}
