/* components.css — geteilte Bausteine (Spec §4): Karte, Feed-Zeile, Chips,
   Inbox, Sektions-Label. Wiederverwendet von Puls (S5-A), Projekt (S5-B). */
/* .card background/border come from app.css (theme-aware var(--panel)/var(--line));
   only override the radius/padding here so dark theme is not clobbered. */
.card { border-radius: 10px; padding: var(--sp-3) var(--sp-4); }
/* font-family: als h2 (Entitätsseite) erbte das Label sonst Sora (Review RC). */
.sec-label { font-family: var(--font-sans); font-size: 11px; text-transform: uppercase;
  letter-spacing: .05em; color: var(--muted, #888); margin: var(--sp-4) 0 var(--sp-2); }
.chips { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.chip { display: inline-block; padding: var(--sp-1) var(--sp-3); min-height: 28px;
  border: 1px solid var(--border, #ccc); border-radius: 999px; font-size: 13px;
  text-decoration: none; color: inherit; max-width: 32ch; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.chip.is-active { background: var(--accent, #6b46ff); color: #fff;
  border-color: var(--accent, #6b46ff); }
/* Projekt-Farbleiter (Puls v2.2, Idee 2): pjb-N setzt EINE lokale Variable
   --pj-cur (erbt an Kinder), die Farbkante + Chip-Punkt gemeinsam lesen. So
   trägt dieselbe Klasse den 3px-Feed-Rand UND den 2px-Selector-Balken. */
.pjb-0 { --pj-cur: var(--pj-0); } .pjb-1 { --pj-cur: var(--pj-1); }
.pjb-2 { --pj-cur: var(--pj-2); } .pjb-3 { --pj-cur: var(--pj-3); }
.pjb-4 { --pj-cur: var(--pj-4); }
/* Projekt-Chip bleibt neutral (kein weißer Text auf Farbe) + farbiger Punkt
   davor; Farbe erbt via --pj-cur von der Feed-Zeile. */
.pj-dot { color: var(--pj-cur, var(--muted, #888)); font-size: 9px; line-height: 1;
  margin-right: 3px; }
.btn-ok, .btn-no { min-width: 44px; min-height: 44px; border-radius: 8px;
  border: 0; font-weight: 700; cursor: pointer; }
.btn-ok { background: #dff3e9; color: #067a52; }
.btn-no { background: #fbe5e5; color: #b03030; }
.statsfoot { display: flex; flex-wrap: wrap; gap: var(--sp-4); justify-content: center;
  font-size: 12px; color: var(--muted, #888); padding: var(--sp-4) 0;
  border-top: 1px solid var(--border, #e2e0dc); margin-top: var(--sp-5); }
.inbox-empty { color: var(--muted, #888); font-size: 13px; margin-top: var(--sp-2); }
.filterbar { margin: var(--sp-4) 0; }
.filterbar .sec-label { margin: var(--sp-3) 0 var(--sp-1); }

/* Spec §5.5: Touch-Targets ≥ 44 px auf Touch-Viewports. Chips sind desktop
   kompakt (28 px), auf Mobil aber Fingerziele. */
@media (max-width: 767px) {
  /* 44px Fingerziel OHNE inline-flex: ein Flex-Container hebt text-overflow:
     ellipsis auf (die Ellipsis braucht einen Inline-/Block-Kontext, kein
     Flex-Item). Also inline-block (aus der Basis) behalten und die Höhe über
     line-height füllen; die vertikale Padding wird genullt, damit die Zeile
     mittig sitzt und die Ellipsis (Basis: overflow/white-space/text-overflow)
     weiter greift. */
  .chip { min-height: 44px; line-height: 44px; padding-top: 0; padding-bottom: 0; }
  /* Token bleibt ein Fingerziel (§5.5), auch wenn er desktop kompakter ist. */
  .fa-token { min-height: 44px; }
  /* Filterhinweis der Triage (?projekt=, Abnahme a43): zwei Text-Links im
     Satz — erst inline-flex macht sie zu 44-px-Zielen (Review a43). */
  .tri-filter a { display: inline-flex; align-items: center; min-height: 44px; }
}

/* ---- Puls v2.1: Projekt-Selector + Aktive-Filter-Tokens -------------------
   Selector nach dem .acct-menu-Vorbild (nav.js-Muster): Desktop absolutes
   Dropdown, Mobil fixed Bottom-Sheet (Override in layout.css, neben .acct-menu).
   Die Filterbar liegt NICHT in der sticky Topnav → das Panel trägt seinen eigenen
   z-index (> Bottom-Nav 40), sonst verschwände es mobil hinter der Leiste. */
.filterbar-sel { position: relative; display: inline-block; }
.sel-btn { display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 44px; padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border, #ccc); border-radius: 999px;
  background: var(--surface, #fff); color: inherit; font: inherit; font-size: 13px;
  font-weight: 600; cursor: pointer; }
.sel-chev { color: var(--muted, #888); flex: none; }
.sel-panel { position: absolute; left: 0; top: calc(100% + 6px); z-index: 45;
  width: 360px; max-width: calc(100vw - 2 * var(--sp-4)); max-height: 70vh;
  overflow-y: auto; padding: var(--sp-2); background: var(--panel, #fff);
  border: 1px solid var(--line, #e2e0dc); border-radius: 12px;
  box-shadow: var(--shadow, 0 4px 14px rgba(0,0,0,.12)); }
/* Zeile als festes Grid: Punkt | Titel (ellipsis) | Zähler | Zeit — Spalten
   fluchten über alle Zeilen (Grid-Regel; Zeit-Spalte fix, damit Zähler eine
   Spalte bilden). .sel-name darf KEIN Flex sein: text-overflow greift nur
   auf Block-Containern (gleiche Falle wie der Chip-Ellipsis-Fix). */
.sel-item, .sel-item:visited { display: grid;
  grid-template-columns: 14px minmax(0, 1fr) auto 72px;
  column-gap: var(--sp-2); align-items: center; min-height: 44px;
  padding: var(--sp-2) var(--sp-3); border-radius: 8px;
  text-decoration: none; color: inherit;
  /* Projekt-Farbleiter (Idee 2): schmaler Farbbalken links, Farbe via pjb-N →
     --pj-cur; der Frische-Punkt (sel-dot) bleibt separat erhalten. */
  border-left: 2px solid var(--pj-cur, transparent); }
.sel-dot { text-align: center; font-size: 11px; line-height: 1; }
.sel-item:hover { background: var(--raised, #f3f2f0); }
.sel-item.is-active { background: var(--accent-soft, #efe7ff); font-weight: 600; }
.sel-name { display: block; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sel-cnt { justify-self: end; background: var(--raised, #eee); border-radius: 9px;
  padding: 0 var(--sp-2); font-size: 11px; color: var(--muted, #555); }
.sel-rel { justify-self: end; font-size: 11px; color: var(--muted, #888);
  white-space: nowrap; }

/* Aktive-Filter-Zeile: entfernbare Tokens im Grid-Token-Stil (--sp-* Abstände). */
.filter-active { display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--sp-2); margin: 0 0 var(--sp-4); }
.fa-label { font-size: 12px; color: var(--muted, #888); }
.fa-token { display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 32px; padding: var(--sp-1) var(--sp-3); border-radius: 8px;
  background: var(--accent-soft, #efe7ff);
  border: 1px solid var(--accent-border, #c9b8ff);
  color: var(--link, #4a2fbf); text-decoration: none; font-size: 13px; }
.fa-token:hover { filter: brightness(.97); }

/* ---- S5-B: Projekt-Kopf und Frische (Board-Seite; Liste und Detail seit a43
   in explorer.css) ---- */
.pj-head { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.dot-fresh { color: #067a52; } .dot-days { color: #b07500; } .dot-stale { color: var(--muted, #999); }
/* Badge scoped to the project surfaces: the global `.badge` (app.css) is reused
   by the entities browser via v1_badge — an unscoped override would regress it. */
.pj-head .badge { font-size: 11px; font-weight: 500; border: 1px solid var(--border, #ddd);
  border-radius: 4px; padding: 0 var(--sp-1); color: var(--muted, #666); letter-spacing: 0; }
.cta { display: inline-flex; align-items: center; gap: var(--sp-2); min-height: 44px;
  padding: var(--sp-2) var(--sp-4); margin: var(--sp-3) 0; border-radius: 8px;
  background: var(--accent, #4a5f6b); color: #fff; text-decoration: none; font-weight: 600; }
.kindtag { font-size: 11px; color: var(--muted, #888); margin-left: var(--sp-2); }

/* Rhythmus (Spec §5.1-Feedback): Seitentitel sitzen auf jeder Seite konsistent
   unter der sticky Topnav. Die Detailseite trägt ihren h1 in .pj-head (Flex,
   baseline) statt als direktes .shell>h1 — derselbe Rhythmus, ohne die Badges
   aus der Baseline zu kippen (Margin am h1, nicht am Flex-Container). */
.shell > h1, .shell > .pj-head > h1 { margin: var(--sp-5) 0 var(--sp-4); }

/* ---- S5-P2: /proposals Triage — Gruppen, Confidence-Balken, Bulk ---- */
.tri-group { margin: var(--sp-4) 0; }
.tri-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
  gap: var(--sp-3); background: var(--accent-soft, #efe7ff);
  border: 1px solid var(--accent-border, #c9b8ff); border-radius: 12px;
  padding: var(--sp-3) var(--sp-4); }
.tri-title { display: block; }
.tri-explain { margin: var(--sp-1) 0 0; font-size: 13px; color: var(--muted, #666); }
.tri-bulk { display: flex; gap: var(--sp-2); flex-wrap: wrap; justify-content: flex-end; }
.btn-bulk { min-width: auto; padding: 0 var(--sp-3); font-size: 13px; white-space: nowrap; }
.tri-card { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
  gap: var(--sp-3); background: var(--surface, #fff); border: 1px solid var(--border, #e2e0dc);
  border-radius: 8px; padding: var(--sp-2) var(--sp-3); margin-top: var(--sp-2); }
.tri-card form { display: inline; }
.tri-card-explain { grid-column: 1 / -1; margin: 0; }
.tri-card-conf { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.tri-conf { font-size: 12px; color: var(--muted, #666); }
.tri-by { font-size: 11px; color: var(--muted, #888); }
.tri-card-actions { display: flex; gap: var(--sp-2); flex-wrap: nowrap; justify-self: end; }
.conf-bar { width: 120px; max-width: 40vw; height: 6px; border-radius: 999px;
  background: var(--border, #e2e0dc); overflow: hidden; }
.conf-fill { display: block; height: 100%; border-radius: 999px; background: var(--accent, #6b46ff); }
.conf-0 { width: 0; } .conf-5 { width: 5%; } .conf-10 { width: 10%; } .conf-15 { width: 15%; }
.conf-20 { width: 20%; } .conf-25 { width: 25%; } .conf-30 { width: 30%; } .conf-35 { width: 35%; }
.conf-40 { width: 40%; } .conf-45 { width: 45%; } .conf-50 { width: 50%; } .conf-55 { width: 55%; }
.conf-60 { width: 60%; } .conf-65 { width: 65%; } .conf-70 { width: 70%; } .conf-75 { width: 75%; }
.conf-80 { width: 80%; } .conf-85 { width: 85%; } .conf-90 { width: 90%; } .conf-95 { width: 95%; }
.conf-100 { width: 100%; }

/* Puls v2.1: Projekt-Selector mobil als Bottom-Sheet. Lebt HIER (nicht in
   layout.css), weil components.css als letztes lädt — sonst gewinnt die
   absolute-Dropdown-Basisregel oben die Kaskade und top+bottom quetschen das
   Panel auf einen Streifen (gefunden per Playwright-DoD, 2026-08-01). */
@media (max-width: 767px) {
  .sel-panel { position: fixed; left: 0; right: 0; bottom: 0; top: auto;
    width: auto; max-width: none; max-height: 70vh; overflow: auto; z-index: 45;
    border-radius: 16px 16px 0 0; box-shadow: 0 -6px 24px rgba(0,0,0,.25); }
}

/* ============================================================================
   Puls v2.2 — Grafisches System: Prozent-Schritt-Utilities. Das Aktivitätsband
   (Idee 1) ist mit Puls v3 entfallen (ADR N1), die Tages-Summary-Balken (Idee
   3) mit a43; die Sparklines leben in puls.css und nutzen die h-N-Klassen unten.
   CSP: alle Höhen/Breiten/Positionen über 5%-Schritt-Klassen, kein Inline-Style.
   ============================================================================ */

/* Segment eines Task-Balkens (Kachel, Projektliste, Projektseite). */
.segbar-seg { height: 100%; }

/* --- Prozent-Schritt-Utilities (5er) — Höhen (Sparklines), Breiten (Balken),
   Positionen. Muster wie conf-N; getrennte Eigenschaften pro Set. --- */
.h-0 { height: 0; } .h-5 { height: 5%; } .h-10 { height: 10%; } .h-15 { height: 15%; } .h-20 { height: 20%; }
.h-25 { height: 25%; } .h-30 { height: 30%; } .h-35 { height: 35%; } .h-40 { height: 40%; } .h-45 { height: 45%; }
.h-50 { height: 50%; } .h-55 { height: 55%; } .h-60 { height: 60%; } .h-65 { height: 65%; } .h-70 { height: 70%; }
.h-75 { height: 75%; } .h-80 { height: 80%; } .h-85 { height: 85%; } .h-90 { height: 90%; } .h-95 { height: 95%; }
.h-100 { height: 100%; }
.w-0 { width: 0; } .w-5 { width: 5%; } .w-10 { width: 10%; } .w-15 { width: 15%; } .w-20 { width: 20%; }
.w-25 { width: 25%; } .w-30 { width: 30%; } .w-35 { width: 35%; } .w-40 { width: 40%; } .w-45 { width: 45%; }
.w-50 { width: 50%; } .w-55 { width: 55%; } .w-60 { width: 60%; } .w-65 { width: 65%; } .w-70 { width: 70%; }
.w-75 { width: 75%; } .w-80 { width: 80%; } .w-85 { width: 85%; } .w-90 { width: 90%; } .w-95 { width: 95%; }
.w-100 { width: 100%; }
.pos-0 { left: 0; } .pos-5 { left: 5%; } .pos-10 { left: 10%; } .pos-15 { left: 15%; } .pos-20 { left: 20%; }
.pos-25 { left: 25%; } .pos-30 { left: 30%; } .pos-35 { left: 35%; } .pos-40 { left: 40%; } .pos-45 { left: 45%; }
.pos-50 { left: 50%; } .pos-55 { left: 55%; } .pos-60 { left: 60%; } .pos-65 { left: 65%; } .pos-70 { left: 70%; }
.pos-75 { left: 75%; } .pos-80 { left: 80%; } .pos-85 { left: 85%; } .pos-90 { left: 90%; } .pos-95 { left: 95%; }
.pos-100 { left: 100%; }

/* ── S5-C Task 5: strukturierte Attribute + Verbindungs-Bottom-Sheet ──────── */

/* Attribut-Zeilen (dt/dd) ersetzen den JSON-<pre>-Dump. Label-Spalte fest,
   Wert bricht um. Roh-Keys (unbekannt) stehen monospace. */
.attr-list { display: grid; grid-template-columns: minmax(120px, max-content) 1fr;
  gap: var(--sp-1) var(--sp-4); margin: 0; align-items: baseline; }
.attr-key { font-size: 12px; font-weight: 600; color: var(--muted, #888); }
.attr-key-raw { font-family: var(--font-mono, monospace); font-weight: 500;
  text-transform: none; }
.attr-val { font-size: 13.5px; color: var(--fg); overflow-wrap: anywhere; margin: 0; }
@media (max-width: 767px) {
  .attr-list { grid-template-columns: 1fr; gap: 0; }
  .attr-key { margin-top: var(--sp-2); }
}

/* ⓘ-Button je Verbindungs-Zeile — 44px Fingerziel, öffnet das Bottom-Sheet. */
.sheet-trigger { flex: none; margin-left: auto; width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: var(--muted, #888); border: 1px solid transparent;
  border-radius: var(--r-sm, 7px); font-size: 15px; cursor: pointer; }
.sheet-trigger:hover { color: var(--link); border-color: var(--line);
  background: var(--accent-soft, #efe7ff); }

/* <dialog class="sheet">: Desktop zentriert, Mobil unten angedockt. Kein
   Padding auf dem Dialog selbst → ein Klick, der ihn trifft, ist der Backdrop
   (das .sheet-panel fängt seine eigenen Klicks). */
dialog.sheet { padding: 0; border: none; border-radius: var(--r, 12px);
  max-width: 460px; width: calc(100vw - 2 * var(--sp-4));
  background: var(--panel); color: var(--fg);
  box-shadow: 0 18px 48px rgba(0,0,0,.28); }
dialog.sheet::backdrop { background: rgba(8,19,32,.46); }
.sheet-panel { position: relative; padding: var(--sp-5) var(--sp-5) var(--sp-4); }
.sheet-close { position: absolute; top: var(--sp-2); right: var(--sp-2);
  width: 44px; height: 44px; display: inline-flex; align-items: center;
  justify-content: center; background: transparent; color: var(--muted, #888);
  border: none; border-radius: var(--r-sm, 7px); font-size: 22px; cursor: pointer; }
.sheet-close:hover { color: var(--fg); }
.sheet-title { font-size: 1.05rem; font-weight: 700; margin: 0 44px 0 0;
  line-height: 1.3; overflow-wrap: anywhere; }
.sheet-meta { font-size: 0.78rem; color: var(--faint, var(--muted));
  margin: var(--sp-2) 0 0; }
.sheet-excerpt { font-size: 0.9rem; color: var(--muted, #888); line-height: 1.5;
  margin: var(--sp-3) 0 0; overflow-wrap: anywhere; }
.sheet-loading, .sheet-error { font-size: 0.9rem; color: var(--muted, #888);
  margin: 0; }
.sheet-open { display: inline-block; margin-top: var(--sp-4); font-weight: 600; }

@media (max-width: 767px) {
  dialog.sheet { width: 100%; max-width: 100%; margin: 0 0 0 0;
    top: auto; bottom: 0; border-radius: var(--r, 12px) var(--r, 12px) 0 0; }
  .sheet-panel { padding-bottom: var(--sp-5); }
}

/* ── Ego-Graph (S5-C): radiales, touch-first Modul; ego.js baut das SVG. ──────
   Kind-Farben aus der geteilten kind_palette (--kc je .k-<kind>), Projekt-Ring
   aus dem Farbrad (pjb-N → --pj-cur). Keine Inline-styles (CSP). */
.ego { margin: var(--sp-2) 0 0; }
.ego > summary { cursor: pointer; min-height: 44px; display: flex; align-items: center;
  font-family: var(--font-display); font-size: 13px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--muted, #888); }
.ego-body { padding-top: var(--sp-2); }
.ego-svg { display: block; width: 100%; max-width: 420px; height: auto;
  margin: 0 auto; touch-action: manipulation; }
/* Projekt-Desktop: die rechte Spalte hält die Nachbarschaft immer offen. */
@media (min-width: 768px) {
  .ego-pin > summary { pointer-events: none; list-style: none; cursor: default; }
  .ego-pin > summary::-webkit-details-marker { display: none; }
}

/* Knoten: unsichtbares 44px-Hit-Ziel, sichtbarer Disc kleiner (dataviz-Regel). */
.ego-node { cursor: pointer; }
.ego-node:focus { outline: none; }
.ego-hit { fill: transparent; }
/* Deckende, getönte Fläche (Kanten enden darunter statt durch die Initiale
   zu laufen); Ring und Initiale in abgedunkelter (hell) bzw. aufgehellter
   (dunkel) Kind-Farbe: Initiale ≥ 5:1 zur Fläche, Ring ≥ 6:1 zur Karte. */
.ego-node { --ego-ink: color-mix(in oklab, var(--kc, var(--muted)) 70%, #000); }
:root[data-theme="dark"] .ego-node {
  --ego-ink: color-mix(in oklab, var(--kc, var(--muted)) 55%, #fff); }
.ego-disc { fill: color-mix(in oklab, var(--kc, var(--muted)) 20%, var(--panel));
  stroke: var(--ego-ink); stroke-width: 2; }
/* Initialen lesbar (Abnahme a43/a44, ≥ 12 px wie gerendert): das SVG (viewBox
   360) steht am Desktop 314–318 px breit, 15 Einheiten rendern dort ≥ 13 px;
   am Handy ist es Viewport − 98 bis − 102 px breit, 17 Einheiten halten
   ≥ 12 px ab 360 px. Eine Regel für Projekt- und Entitätsseite (vorher 11). */
.ego-initial { fill: var(--ego-ink); font-family: var(--font-display);
  font-weight: 700; font-size: 15px; }
@media (max-width: 767px) { .ego-initial { font-size: 17px; } }
.ego-node.is-focus .ego-disc { stroke-width: 3; }
.ego-node[data-selected="1"] .ego-disc,
.ego-node:focus-visible .ego-disc { stroke: var(--accent); stroke-width: 3; }
.ego-edge { stroke: var(--faint, #ccc); stroke-width: 1.2; stroke-opacity: .5; }
.ego-pj { fill: none; stroke: var(--pj-cur, var(--line)); stroke-width: 2; }
/* kind_palette (Hex-Spiegel von kind_palette.py; CSS kann es nicht importieren). */
.ego-node.k-concept{--kc:#4a7a9b}.ego-node.k-fact{--kc:#7a4a9b}
.ego-node.k-decision{--kc:#9b7a4a}.ego-node.k-template{--kc:#4a9b7a}
.ego-node.k-secret{--kc:#9b4a4a}.ego-node.k-config{--kc:#6b7a9b}
.ego-node.k-project{--kc:#4a7a4a}.ego-node.k-task{--kc:#9b9b4a}
.ego-node.k-document{--kc:#5a6a8a}.ego-node.k-note{--kc:#8a8a5a}
.ego-node.k-inbox_item{--kc:#7a8a9a}.ego-node.k-user{--kc:#9a7a7a}
.ego-node.k-tag{--kc:#7a9a8a}.ego-node.k-skill{--kc:#c97a3a}.ego-node.k-commit{--kc:#6a8a6a}

/* Info-Zeile unter dem SVG (Tap = Auswahl) + Überlauf-/Voll-Graph-Links. */
.ego-info { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2);
  min-height: 44px; margin: var(--sp-2) 0 0; font-size: 13px; color: var(--muted, #888); }
.ego-info-title { font-weight: 600; color: var(--fg); overflow-wrap: anywhere; }
.ego-info-kind { font-size: 11px; color: var(--faint, var(--muted)); }
.ego-info-open, .ego-more-link, .ego-full { display: inline-flex; align-items: center;
  min-height: 44px; color: var(--link); text-decoration: none; font-weight: 600; }
.ego-info-open { margin-left: auto; }
.ego-more { margin: var(--sp-1) 0 0; font-size: 12px; }
.ego-full { font-size: 12px; margin-top: var(--sp-1); }

/* ============================================================================
   S5-F Board — Read-only Task-Board (Projekt-Detailseite) + Listen-Segbar.
   Statusfarben als --st-*-Tokens (app.css, Light+Dark); Kante links im
   pjb-Muster (--st-cur erbt an Kinder). Farbe nie alleiniger Träger — die
   Gruppen-Header tragen den Klartext.
   ============================================================================ */
.st-blocked { --st-cur: var(--st-blocked); }
.st-in_progress { --st-cur: var(--st-progress); }
.st-open { --st-cur: var(--st-open); }
.st-done { --st-cur: var(--st-done); }
.st-closed { --st-cur: var(--st-closed); }
.st-none { --st-cur: transparent; }
/* Segmentfarben der Task-Balken (Task 3). */
.bs-blocked { background: var(--st-blocked); } .bs-in_progress { background: var(--st-progress); }
.bs-open { background: var(--st-open); } .bs-done { background: var(--st-done); }

/* ============================================================================
   S5-G Board-Seite (Nicos Abnahme-Befund 2026-08-17: „mehr als Board
   visualisieren"): echte Status-Spalten auf /projekte/{id}/board. Der
   Scroll-Container hält den Body H-scroll-frei (Haus-Regel breite Inhalte);
   auf schmalen Viewports wird die Fläche zum swipebaren Board (scroll-snap).
   Die Spalte trägt den Zustand (Top-Kante über --st-cur), die Karten bleiben
   ruhige Surfaces; Blockiert-Karten behalten die Soft-Fläche als Eskalations-
   Nachdruck. Die Detailseite verweist nur noch per Summary-Karte hierher.
   ============================================================================ */
.boardp-scroll { overflow-x: auto; scroll-snap-type: x proximity;
  padding-bottom: var(--sp-3); }
.boardp { display: grid; grid-auto-flow: column;
  grid-auto-columns: minmax(250px, 1fr); gap: var(--sp-4); align-items: start; }
.boardp-col { border-top: 3px solid var(--st-cur, var(--border, #ddd));
  padding-top: var(--sp-2); scroll-snap-align: start; min-width: 0; }
.boardp-h { font-size: 12px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted, #888); margin: 0 0 var(--sp-2); }
.boardp-card { background: var(--surface, #fff); border-radius: 8px;
  padding: var(--sp-2) var(--sp-3); }
.boardp-card + .boardp-card { margin-top: var(--sp-2); }
.boardp-title { display: flex; align-items: center; min-height: 44px; }
.boardp-col.st-blocked .boardp-card { background: var(--st-blocked-soft); }
.boardp-empty { font-size: 12px; color: var(--muted, #888); margin: var(--sp-2) 0; }

/* ============================================================================
   S5-D: /einstellungen — eine Seite, vier Sektionen (Passkeys · Sessions ·
   Tokens · OAuth-Clients) mit Anker-Navigation. Kein JS (reine #-Anker).
   Desktop: Anker-Zeile sticky unter der Topnav; mobil: gestapelte Sektionen,
   Anker-Zeile horizontal scrollbar. CSP: nur Klassen, keine Inline-Styles.
   ============================================================================ */
.set-anchors { position: sticky; top: var(--topnav-h, 56px); z-index: 30;
  display: flex; gap: var(--sp-2); margin: var(--sp-4) 0; padding: var(--sp-2) 0;
  overflow-x: auto; background: var(--surface, #fff);
  border-bottom: 1px solid var(--border, #e2e0dc); }
.set-anchor, .set-anchor:visited { display: inline-flex; align-items: center;
  min-height: 44px; padding: var(--sp-2) var(--sp-3); border-radius: 999px;
  white-space: nowrap; text-decoration: none; color: inherit;
  border: 1px solid var(--border, #ccc); font-size: 13px; font-weight: 600; }
.set-anchor:hover { background: var(--raised, #f3f2f0); }
/* Sprungziel darf nicht unter Topnav + sticky Anker-Zeile landen. */
.set-section { scroll-margin-top: calc(var(--topnav-h, 56px) + var(--sp-6) + var(--sp-6)); }
.set-section + .set-section { margin-top: var(--sp-5); }
.set-section > h2:first-child { margin-top: 0; }
/* §5.5: keine Tabelle ohne Scroll-Container — die Credential-Tabellen sind
   breit und dürfen mobil nicht die Seite horizontal aufreißen. */
.set-tbl { overflow-x: auto; }
/* Tabellen im Scroll-Wrapper dürfen nicht unter ihre Lesbarkeit schrumpfen:
   unterhalb von 48rem scrollt der Wrapper, statt dass Spalten zerbrechen
   (Befund Screenshot 390px: Sessions-Tabelle unlesbar zerquetscht). */
.set-tbl table, .tbl-scroll table { min-width: 48rem; }
.set-tbl th, .tbl-scroll th { white-space: nowrap; }

/* ============================================================================
   S5-D Task 3: Admin-Tabellen responsive (Spec §5.4/§5.5, Audit-Finding
   „keine Tabelle ohne Scroll-Container"). Lebt am Dateiende — components.css
   lädt zuletzt; keine konkurrierenden Regeln vor diesen. CSP: nur Klassen.
   ============================================================================ */

/* Scroll-Container um JEDE verbleibende Admin-Tabelle: die Tabelle scrollt in
   ihrem Wrapper, der Body reißt nie horizontal auf. Auch von shares.html (T2)
   genutzt (Tabelle in .card) — dort trägt die Karte Rahmen/Radius, der Wrapper
   nur den Scroll. Radius passend zu .card (10px). */
.tbl-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch;
  margin: var(--sp-3) 0; border-radius: 10px; }

/* Mobile Card-Liste als Alternative zu den breitesten Tabellen (Users,
   Webhooks): Desktop zeigt die Tabelle, mobil die Karten. BEIDE speisen sich
   aus derselben Jinja-Row-Liste (zwei Schleifen über users/sources) — kein
   Handler-seitiges Verdoppeln. Nur die mit .tbl-cards markierten Tabellen
   verschwinden mobil; audit/auth_audit behalten ihre scrollbare Tabelle. */
.acard-list { display: none; list-style: none; margin: var(--sp-3) 0; padding: 0; }
.acard { border: 1px solid var(--border, #e2e0dc); border-radius: 10px;
  padding: var(--sp-3) var(--sp-4); margin-bottom: var(--sp-3);
  background: var(--surface, #fff); }
.acard.muted { opacity: .6; }
.acard-head { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2);
  font-weight: 600; margin-bottom: var(--sp-2); }
/* Label-Spalte fest, Wert bricht um (dt/dd — dasselbe Muster wie .attr-list). */
.acard-dl { display: grid; grid-template-columns: minmax(72px, max-content) 1fr;
  gap: var(--sp-1) var(--sp-3); margin: 0; align-items: baseline; }
.acard-dl dt { font-size: 12px; font-weight: 600; color: var(--muted, #888); }
.acard-dl dd { margin: 0; font-size: 13.5px; overflow-wrap: anywhere; }
.acard-actions { display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-2); margin-top: var(--sp-3); }
/* §5.5: Aktionen in der Karte bleiben Fingerziele (≥44px). */
.acard-actions button, .acard-actions .btn { min-height: 44px; }
/* Karten-Aktionen können reine Links sein (/webhooks: „GitHub-App →“). */
.acard-actions a { min-height: 44px; display: inline-flex; align-items: center; }

@media (max-width: 767px) {
  .tbl-scroll.tbl-cards { display: none; }   /* breite Tabelle mobil ausblenden */
  .acard-list { display: block; }            /* Karten übernehmen */
}

/* ============================================================================
   GitHub-App-Admin-Seite (/integrations/github, Plan Task 9): App-Kopf,
   Owner-Checkliste, Zuordnungs-Formulare in Tabellenzellen, Fremd-Markierung.
   CSP: nur Klassen. Touch-Ziele ≥ 44px (Muster .acard-actions).
   ============================================================================ */
.gh-head { display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-2) var(--sp-4); }
.gh-head h2 { margin: 0; }
.gh-ok { color: var(--ok, #168a7f); font-weight: 600; }
.gh-warn { color: #9b7a4a; font-weight: 600; }
.gh-check { list-style: none; margin: var(--sp-3) 0; padding: 0; }
.gh-check li { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  min-height: 44px; padding: var(--sp-1) 0; border-bottom: 1px solid var(--line, #e2e0dc); }
.gh-check .btn { min-height: 44px; display: inline-flex; align-items: center; }
.gh-assign { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  margin-right: var(--sp-2); }
.gh-assign select { min-height: 44px; max-width: 18rem; }
.gh-assign button { min-height: 44px; white-space: nowrap; }
.gh-manifest { margin: var(--sp-4) 0; }
.gh-manifest button { min-height: 44px; }
.gh-remove { margin-top: var(--sp-5); }
.gh-remove summary { cursor: pointer; min-height: 44px; display: flex; align-items: center;
  color: var(--muted, #888); }
/* §5.5: Secret-Form und „App entfernen“ sind ebenfalls Fingerziele (≥44px). */
.gh-secret button, .gh-remove form button { min-height: 44px; }
tr.is-foreign td { background: rgba(155, 122, 74, 0.08); }
