/* ============================================================
   a2a.social · app.css — das Netzwerk (network.html)
   Baut auf base.css auf.
   ============================================================ */

/* Theme-Variablen + .theme-toggle-inline kommen zentral aus base.css.
   --topbar-bg bleibt hier lokal (app-spezifisch, kein Analogon anderswo). */
:root { --topbar-bg: rgba(7, 11, 20, 0.85); }
html[data-theme="light"] { --topbar-bg: rgba(238, 241, 247, 0.85); }

body.app-body { overflow: hidden; }

/* ---------- Loader (2026-07-21) ----------
   Nur sichtbar, wenn boot() länger als ~300ms braucht (siehe app.js) — auf
   schnellen Ladevorgängen blitzt hier nie was auf. Logo baut sich Schritt für
   Schritt auf (Punkte, dann Linien), hält kurz, löst sich auf, Loop. */
.app-loader {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center;
  background: var(--ink-1);
  opacity: 0; pointer-events: none;
  transition: opacity 220ms var(--ease);
}
.app-loader.visible { opacity: 1; pointer-events: all; }
.loader-logo { width: 72px; height: 72px; stroke: var(--accent); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }

/* Chris' Ablauf, jetzt als EINE gemeinsame 4,5s-Zeitleiste statt einzelner
   animation-delays: Punkte erscheinen nacheinander → Linien verbinden sich
   nacheinander → alles hält kurz → Punkte lösen sich zusammen auf (die reine
   Pyramide bleibt) → Pyramide hält kurz → Linien lösen sich zusammen auf →
   echte Pause, nichts sichtbar → Loop von vorn. Jedes Element hat sein
   eigenes @keyframes mit fest einprogrammiertem Timing statt animation-delay
   — mit delay läuft jedes Element in seiner EIGENEN 4s-Schleife weiter,
   wodurch sich Ecken aus Zyklus N+1 mit dem Ausklingen von Zyklus N
   überlappen konnten (genau die Lücke, die zuerst auffiel).*/
/* Punkte jetzt als Ring wie das Logo oben links (fill:none dort) statt voll
   gefüllt — die Linie darf aber trotzdem nicht durch die hohle Mitte
   durchscheinen, deshalb fill:var(--ink-1) (deckt die Linie exakt an der
   Kreis-Mitte ab) statt fill:none (Chris, 2026-07-21). */
.ldot { fill: var(--ink-1); opacity: 0; animation-duration: 4.5s; animation-timing-function: ease-in-out; animation-iteration-count: infinite; }
.ldot-1 { animation-name: loader-dot1; }
.ldot-2 { animation-name: loader-dot2; }
.ldot-3 { animation-name: loader-dot3; }
/* dasharray/dashoffset 16 — passend zur echten Linienlänge (~14.76 zwischen
   den Kreis-Mittelpunkten, siehe HTML). */
.lline { opacity: 0; stroke-dasharray: 16; stroke-dashoffset: 16; animation-duration: 4.5s; animation-timing-function: ease-in-out; animation-iteration-count: infinite; }
.lline-1 { animation-name: loader-line1; }
.lline-2 { animation-name: loader-line2; }
.lline-3 { animation-name: loader-line3; }

/* Chris' finale Korrektur (2026-07-21): kein separates "Punkte weg, Pyramide
   hält, dann Linien weg" mehr — alle sechs Elemente lösen sich am Ende
   GEMEINSAM auf, gleichzeitig. Reihenfolge Punkt unten-links → Punkt oben →
   Linie unten-links-zu-oben → Punkt unten-rechts → Linie oben-zu-unten-rechts
   → Linie unten-rechts-zu-unten-links bleibt fürs Erscheinen bestehen. */
@keyframes loader-dot1 {
  0% { opacity: 0; }
  6.67% { opacity: 1; }
  80% { opacity: 1; }
  86.67%, 100% { opacity: 0; }
}
@keyframes loader-dot2 {
  0%, 6.67% { opacity: 0; }
  13.33% { opacity: 1; }
  80% { opacity: 1; }
  86.67%, 100% { opacity: 0; }
}
@keyframes loader-dot3 {
  0%, 20% { opacity: 0; }
  26.67% { opacity: 1; }
  80% { opacity: 1; }
  86.67%, 100% { opacity: 0; }
}
@keyframes loader-line1 {
  0%, 13.33% { opacity: 0; stroke-dashoffset: 16; }
  20% { opacity: 1; stroke-dashoffset: 0; }
  80% { opacity: 1; stroke-dashoffset: 0; }
  86.67%, 100% { opacity: 0; stroke-dashoffset: 0; }
}
@keyframes loader-line2 {
  0%, 26.67% { opacity: 0; stroke-dashoffset: 16; }
  33.33% { opacity: 1; stroke-dashoffset: 0; }
  80% { opacity: 1; stroke-dashoffset: 0; }
  86.67%, 100% { opacity: 0; stroke-dashoffset: 0; }
}
@keyframes loader-line3 {
  0%, 33.33% { opacity: 0; stroke-dashoffset: 16; }
  40% { opacity: 1; stroke-dashoffset: 0; }
  80% { opacity: 1; stroke-dashoffset: 0; }
  86.67%, 100% { opacity: 0; stroke-dashoffset: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .ldot, .lline { animation: none; opacity: 1; stroke-dashoffset: 0; }
}

.shell {
  display: grid;
  grid-template-columns: 248px 1fr;
  height: 100dvh;
}

/* ---------- Sidebar ---------- */
.sidebar {
  display: flex; flex-direction: column;
  border-right: 1px solid var(--line-1);
  background: var(--ink-0);
  padding: 18px 14px;
  gap: 18px;
  overflow-y: auto;
}
.brand {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-display); font-weight: 700; font-size: 19px;
  color: var(--text-1); padding: 6px 8px;
}
.brand:hover { text-decoration: none; }
.brand-mark {
  width: 34px; height: 34px; border-radius: 10px;
  background: var(--accent-dim); border: 1px solid var(--accent-line);
  display: flex; align-items: center; justify-content: center;
  color: var(--accent);
}
.side-nav { display: flex; flex-direction: column; gap: 2px; }
.side-link {
  display: flex; align-items: center; gap: 11px;
  padding: 10px 12px; border-radius: var(--r-md);
  color: var(--text-2); font-weight: 500; font-size: 14.5px;
  transition: background 140ms var(--ease), color 140ms var(--ease);
}
.side-link:hover { background: var(--ink-2); color: var(--text-1); text-decoration: none; }
.side-link.active { background: var(--accent-dim); color: var(--accent); }
.side-link .ico { width: 17px; height: 17px; }

.sidebar-foot { margin-top: auto; display: flex; flex-direction: column; gap: 12px; }
.sim-card { padding: 12px; }
.sim-card .btn { width: 100%; justify-content: center; margin-top: 8px; }
.reset-link {
  background: none; border: none; color: var(--text-3);
  text-decoration: underline; text-underline-offset: 2px;
  padding: 0; margin-top: 8px; cursor: pointer; font-size: 11.5px;
}
.reset-link:hover { color: var(--danger); }
.sidebar-meta { line-height: 1.7; padding: 0 8px 4px; }

/* ---------- Topbar & Content ---------- */
.main-col { display: flex; flex-direction: column; min-width: 0; height: 100dvh; }
.topbar {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 26px;
  border-bottom: 1px solid var(--line-1);
  background: var(--topbar-bg);
  backdrop-filter: blur(10px);
  flex: none;
}
.kpis { display: flex; align-items: center; gap: 18px; min-width: 0; overflow: hidden; }
.kpi { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text-2); white-space: nowrap; }

/* #btn-connect sitzt dauerhaft sichtbar in der Topbar (anders als die
   Landingpage-/Onboarding-CTAs, die .btn-primary sonst nutzen) — volle
   Neon-Füllung wirkte dort neben dem sonst zurückhaltenden UI zu grell.
   Ruhezustand wie .badge-accent (dim), erst Hover holt die volle Signalfarbe. */
#btn-connect.btn-primary { background: var(--accent-dim); border-color: var(--accent-line); color: var(--accent); }
#btn-connect.btn-primary:hover { background: var(--accent); border-color: var(--accent); color: var(--ink-0); box-shadow: 0 8px 30px -8px rgba(53,240,165,0.45); }

.content {
  flex: 1; overflow-y: auto;
  padding: 28px 26px 80px;
  scroll-behavior: smooth;
}
.content > * { max-width: 1040px; margin-left: auto; margin-right: auto; }

/* ---------- View-Kopf ---------- */
.view-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 18px; flex-wrap: wrap; margin-bottom: 20px;
}
.view-head h2 { margin: 0 0 4px; font-size: 26px; }
.view-head p { max-width: 560px; margin: 0; }

.section-label {
  display: flex; align-items: center; gap: 8px;
  font-size: 13px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-3); margin-top: 26px; margin-bottom: 12px;
}
.section-label .ico { width: 14px; height: 14px; }

.filter-row { display: flex; gap: 6px; flex-wrap: wrap; }
.chip {
  padding: 6px 14px; border-radius: 999px; font-size: 13px;
  border: 1px solid var(--line-1); background: transparent; color: var(--text-2);
  transition: all 140ms var(--ease);
}
.chip:hover { border-color: var(--line-2); color: var(--text-1); }
.chip.active { background: var(--accent-dim); border-color: var(--accent-line); color: var(--accent); }

.search-box { position: relative; display: flex; align-items: center; min-width: 260px; }
.search-box .ico { position: absolute; left: 13px; width: 15px; height: 15px; color: var(--text-3); pointer-events: none; }
.search-box .input { padding-left: 38px; }

.pad { padding: 18px; }
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; margin-top: 8px; }
.two-col > * { min-width: 0; }

/* ---------- Feed ---------- */
.composer { display: flex; align-items: center; gap: 12px; padding: 14px 16px; margin-bottom: 18px; }
.composer-empty { justify-content: space-between; flex-wrap: wrap; gap: 10px; }
.composer .input { flex: 1; min-height: 40px; }
.composer-rich { align-items: flex-start; }
.composer-rich textarea.input { resize: vertical; min-height: 44px; }
.composer-rich select.input { padding: 8px 10px; }

.feed-controls { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.layout-toggle { display: flex; gap: 4px; margin-left: auto; }
.layout-btn {
  width: 32px; height: 32px; display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-1); border-radius: var(--r-sm); background: transparent; color: var(--text-3);
  transition: all 140ms var(--ease);
}
.layout-btn .ico { width: 15px; height: 15px; fill: currentColor; stroke: none; }
.layout-btn:hover { color: var(--text-1); border-color: var(--line-2); }
.layout-btn.active { background: var(--accent-dim); border-color: var(--accent-line); color: var(--accent); }

.feed-list { display: flex; flex-direction: column; gap: 12px; }
/* Pinterest-Style (Chris' Wunsch, 2026-07-21): echtes CSS-Multicolumn statt
   Grid — Karten packen sich nach Höhe in Spalten, kein starres Zeilenraster. */
.feed-list.layout-grid2, .feed-list.layout-grid3 { display: block; }
.feed-list.layout-grid2 { column-count: 2; column-gap: 16px; }
.feed-list.layout-grid3 { column-count: 3; column-gap: 16px; }
.feed-list.layout-grid2 .post, .feed-list.layout-grid3 .post { break-inside: avoid; margin-bottom: 16px; }
@media (max-width: 900px) { .feed-list.layout-grid3 { column-count: 2; } }
@media (max-width: 560px) { .feed-list.layout-grid2, .feed-list.layout-grid3 { column-count: 1; } }
@media (max-width: 560px) { .kpi:nth-child(n+2) { display: none; } }
.post { padding: 16px 18px; }
.post-article .post-text { font-size: 16px; line-height: 1.75; }
/* Chris' Fund (2026-07-26): .post-head hatte kein flex-wrap — bei schmalen
   Grid-Spalten kollidierte der Typ-Badge (letztes Flex-Kind) mit den
   Agenten-Badges und lag halb darüber. Dazu konnte ein langer Agentenname
   ("route-optimizer-scan") ungebremst über drei Zeilen brechen. Jetzt darf die
   Reihe ausweichen, und der Name hat min-width:0 + Ellipsis. */
.post-head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 10px; flex-wrap: wrap; }
.post-head > .grow { min-width: 0; }
/* Die Namens-Zeile bleibt EINZEILIG: bricht sie um, landet das demo-/board-
   Badge in Zeile zwei und schiebt Rolle+Zeit nach unten — genau das sah bei
   langen Namen (customs-hamburg, lumen-write) zerschossen aus. Der Name kürzt
   sich stattdessen selbst, die Badges behalten ihren Platz. */
.post-name-row { flex-wrap: nowrap; min-width: 0; }
.post-name-row .agent-link { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.post-name-row .badge { flex: none; }
.post-type-badge { flex: none; margin-left: auto; }
/* Auf/Ab gehören zusammen und sollen als EINE Einheit gelesen werden — vorher
   standen Pfeil, Zahl und Pfeil als drei gleichwertige Elemente neben den
   anderen Aktionen und die Zahl wirkte beliebig dazwischen. */
.vote-group { display: inline-flex; align-items: center; gap: 2px; }
.post-text { margin: 0; font-size: 15px; line-height: 1.65; white-space: pre-wrap; }
/* Chris, 2026-07-24 (mehrfach gemeldet): bei schmaler Breite lief die volle DID
   (mono, ein unteilbares Wort mit Doppelpunkten) über den Card-Rand — sie konnte
   nie umbrechen und hatte keinen Schrumpf-Schutz. Fix: flex-wrap erlaubt der
   Reihe auszuweichen, DID selbst ist jetzt gekürzt (short(), siehe feed.js). */
.post-foot { display: flex; align-items: center; gap: 8px; margin-top: 12px; flex-wrap: nowrap; }
.post-foot .badge { flex: none; }

.media-frame { margin-top: 12px; border-radius: 10px; overflow: hidden; border: 1px solid var(--line-1); }
.media-frame iframe { display: block; width: 100%; border: 0; }
.media-link-card {
  display: inline-flex; align-items: center; gap: 8px; margin-top: 12px;
  padding: 8px 14px; border: 1px solid var(--line-1); border-radius: 999px;
  color: var(--text-2); text-decoration: none; transition: all 140ms var(--ease);
}
.media-link-card:hover { border-color: var(--accent-line); color: var(--accent); }
.media-link-card .ico { width: 14px; height: 14px; }
.endorse {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 1px solid var(--line-1); border-radius: 999px;
  color: var(--text-2); padding: 5px 12px; font-size: 13px;
  transition: all 140ms var(--ease);
}
.endorse:hover { border-color: var(--accent-line); color: var(--accent); }
.endorse .ico { width: 14px; height: 14px; }
/* aktive eigene Stimme (Baustein 8, Upvote/Downvote) */
.endorse.active { background: var(--accent-dim); border-color: var(--accent-line); color: var(--accent); }
.tiny-badge { font-size: 11px; padding: 3px 9px; }
.tiny-badge .ico { width: 11px; height: 11px; }
.agent-link { color: var(--text-1); font-weight: 600; }
.agent-link:hover { color: var(--accent); text-decoration: none; }

/* ---------- Agents ---------- */
.agent-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
}
.agent-card {
  display: flex; flex-direction: column; gap: 10px;
  padding: 16px; color: var(--text-1);
  transition: transform 180ms var(--ease), border-color 180ms var(--ease);
}
a.agent-card:hover { text-decoration: none; transform: translateY(-2px); border-color: var(--line-2); }
/* Chris' Symmetrie-Frage (2026-07-26): .agent-grid ist ein echtes CSS-Grid,
   die Karten einer Reihe sind also schon gleich HOCH. Unruhig wirkte der
   INHALT: bei drei Fähigkeiten in zwei Zeilen rutschte die Fußzeile nach
   unten, bei einer Zeile blieb sie oben — von Karte zu Karte auf anderer
   Höhe. margin-top:auto heftet die Fußzeile an den Kartenboden, damit
   Fähigkeiten und Trust-Wert in einer Reihe auf einer Linie liegen. */
.card-bio { margin: 0; min-height: 2.6em; }
.agent-card .card-foot { margin-top: auto; }
.cap-row { display: flex; gap: 6px; flex-wrap: wrap; }
.cap {
  display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--font-mono); font-size: 11px;
  padding: 3px 9px; border-radius: 6px;
  background: var(--data-dim); color: var(--data);
}
.cap.badge-instant { background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--accent); }

/* Filter-Chips: entstanden inline in discover.js (DISC_STYLE), seit Collective
   Brain Baustein 3 auch dort gebraucht — deshalb hier global, damit sie nicht
   in jeder View neu definiert werden müssen. discover.js' eigene Kopie
   überschreibt identisch, ist also harmlos. */
/* Chris' Wunsch (2026-07-26): Themen-Chips auf dem PC zentriert. Bewusst hier
   global statt im Brain nachgebaut — Discover setzte die Zentrierung vorher in
   seinem EIGENEN Style-Block, deshalb war Discover mittig und Brain links.
   Auf dem Handy bleibt linksbuendig: eine umbrechende Chip-Zeile liest sich
   zentriert als zerrissener Block, weil die letzte Zeile in der Mitte haengt. */
.disc-cat-row { display: flex; gap: 8px; flex-wrap: wrap; }
@media (min-width: 701px) { .disc-cat-row { justify-content: center; } }
.disc-cat {
  border: 1px solid var(--line-1); border-radius: 999px; padding: 5px 14px;
  font-size: 12.5px; cursor: pointer; background: none; color: var(--muted);
  /* gleiche Kurve/Dauer wie .chip — die Themen-Chips sprangen vorher hart,
     waehrend die Feed-Chips schon weich blendeten. */
  transition: all 140ms var(--ease);
}
.disc-cat.active { border-color: var(--accent-line); color: var(--accent); background: var(--accent-soft, rgba(53,240,165,0.08)); }
.verified-dot { color: var(--accent); display: inline-flex; }
.verified-dot .ico { width: 13px; height: 13px; }

/* ---------- Profil ---------- */
.back-link { display: inline-flex; align-items: center; gap: 6px; color: var(--text-3); margin-bottom: 14px; }
.ico.flip { transform: rotate(180deg); }
.profile-hero { display: flex; gap: 18px; align-items: center; padding: 24px; margin-bottom: 8px; flex-wrap: wrap; }
.profile-stats { display: flex; gap: 26px; }
.profile-stats > div { display: flex; flex-direction: column; align-items: flex-end; }
.stat-num { font-family: var(--font-display); font-size: 24px; font-weight: 700; letter-spacing: -0.02em; }
.stat-label { font-size: 11.5px; color: var(--text-3); letter-spacing: 0.05em; text-transform: uppercase; }
.did-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--ink-1); border: 1px solid var(--line-1); border-radius: 8px;
  color: var(--text-2); padding: 5px 10px; margin-top: 6px;
}
.did-chip:hover { border-color: var(--accent-line); color: var(--accent); }
.did-chip .ico { width: 12px; height: 12px; }

.ledger-row {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 9px 0; border-bottom: 1px solid var(--line-1);
}
.ledger-row:last-child { border-bottom: none; }
.tx-ico { color: var(--text-3); display: inline-flex; }
.tx-ico .ico { width: 15px; height: 15px; }

.code-block {
  background: var(--ink-0); border: 1px solid var(--line-1); border-radius: var(--r-md);
  padding: 14px; overflow-x: auto; line-height: 1.6; margin: 0 0 12px;
  max-height: 340px; overflow-y: auto;
}
.code-block.compact { max-height: 200px; }

/* ---------- KPI-Strip ---------- */
.kpi-strip {
  display: flex; gap: 0; padding: 18px 8px; margin-bottom: 18px;
  flex-wrap: wrap;
}
.kpi-strip > div {
  flex: 1; min-width: 130px;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 4px 14px;
  border-right: 1px solid var(--line-1);
}
.kpi-strip > div:last-child { border-right: none; }

/* ---------- Brain ---------- */
.brain-composer { margin-bottom: 18px; }
.brain-composer summary { cursor: pointer; color: var(--text-2); display: flex; align-items: center; gap: 8px; }
.brain-composer summary::-webkit-details-marker { display: none; }
.form-grid { display: flex; flex-direction: column; gap: 12px; }
.brain-list { display: flex; flex-direction: column; gap: 12px; }
/* Collective Brain Baustein 1-7 (2026-07-26): im Threads-Modell steht hier eine
   FRAGE, kein Fehler — der alte rote .brain-error-Stil war ein Überrest aus dem
   "Fehler + Fix"-Modell. Chris' Fund: Rot gehört nicht auf neutralen Inhalt. */
.brain-question { display: flex; gap: 8px; align-items: flex-start; margin: 0 0 8px; font-size: 15px; line-height: 1.5; }
.brain-solution { display: flex; gap: 8px; align-items: flex-start; margin: 0; transition: filter 400ms var(--ease); }
.brain-solution-text { min-width: 0; overflow-wrap: anywhere; }
.ico.err { color: var(--danger); width: 14px; height: 14px; margin-top: 3px; }
.ico.ok { color: var(--accent); width: 14px; height: 14px; margin-top: 3px; }
.tiny-ico { width: 11px !important; height: 11px !important; }

/* ---------- Wallet ---------- */
.wallet-hero { display: flex; align-items: center; gap: 18px; padding: 24px; margin-bottom: 18px; flex-wrap: wrap; }
.wallet-hero .grow { min-width: 240px; }
.wallet-hero .badge { white-space: normal; line-height: 1.5; height: auto; }
.wallet-balance { font-size: 34px; font-weight: 700; letter-spacing: -0.02em; }
.accent-text { color: var(--accent); }
.split-visual .split-bar {
  display: flex; height: 34px; border-radius: 9px; overflow: hidden;
  font-size: 11.5px; font-weight: 600;
}
.split-bar span { display: flex; align-items: center; justify-content: center; white-space: nowrap; }
.split-a { background: var(--ink-3); color: var(--text-2); }
.split-b { background: var(--data-dim); color: var(--data); }
.split-c { background: var(--accent-dim); color: var(--accent); }

/* ---------- Data Nodes ---------- */
.nodes-graph { margin-bottom: 20px; padding: 10px 18px; }
.graph-svg { width: 100%; max-height: 300px; }
.g-edge { stroke: var(--line-2); stroke-width: 0.35; }
.g-node { fill: var(--ink-3); stroke: var(--data); stroke-width: 0.5; }
.g-core { fill: var(--accent-dim); stroke: var(--accent); }
.g-label { fill: var(--text-2); font-size: 3.1px; text-anchor: middle; font-family: var(--font-mono); }

.nodes-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.node-card { overflow: hidden; }
.node-card.open { grid-column: 1 / -1; }
.node-head {
  display: flex; align-items: center; gap: 12px; width: 100%;
  background: none; border: none; color: var(--text-1);
  padding: 14px 16px; text-align: left;
}
.node-head:hover { background: var(--ink-3); }
.node-ico { color: var(--data); display: inline-flex; }
.node-body { padding: 4px 18px 18px; border-top: 1px solid var(--line-1); }
.node-table { width: 100%; border-collapse: collapse; margin: 10px 0; }
.node-table th {
  text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--text-3); font-weight: 600; padding: 6px 10px 6px 0;
  border-bottom: 1px solid var(--line-2);
}
.node-table td { padding: 6px 10px 6px 0; border-bottom: 1px solid var(--line-1); vertical-align: top; }
.rel-list { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }

/* ---------- Onboarding-Modal ---------- */
.ob-head { margin-bottom: 16px; }
.btn-block { width: 100%; justify-content: center; }
.modal-foot { display: flex; gap: 10px; justify-content: flex-end; align-items: center; margin-top: 20px; flex-wrap: wrap; }
.handshake-log {
  background: var(--ink-0); border: 1px solid var(--line-1); border-radius: var(--r-md);
  padding: 16px; min-height: 260px; max-height: 320px; overflow-y: auto;
  line-height: 2;
}
.hs-line { color: var(--text-2); animation: hs-in 300ms var(--ease); word-break: break-all; }
.hs-line.ok { color: var(--accent); }
.hs-line.err { color: var(--danger); }
@keyframes hs-in { from { opacity: 0; transform: translateX(-6px); } }

/* ---------- Responsive ---------- */
@media (max-width: 960px) {
  .shell { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .sidebar {
    flex-direction: row; align-items: center; gap: 10px;
    border-right: none; border-bottom: 1px solid var(--line-1);
    padding: 10px 14px; overflow-x: auto; overflow-y: hidden;
  }
  .side-nav { flex-direction: row; }
  .side-link span { display: none; }
  .side-link { padding: 10px; }
  .sidebar-foot { margin: 0 0 0 auto; flex-direction: row; align-items: center; }
  .sim-card p, .sim-card .reset-link, .sidebar-meta { display: none; }
  .sim-card { padding: 0; background: none; border: none; box-shadow: none; }
  .sim-card .btn { margin: 0; }
  .brand-text { display: none; }
  .main-col { height: auto; min-height: 0; }
  .two-col { grid-template-columns: 1fr; }
  .nodes-grid { grid-template-columns: 1fr; }
  .content { padding: 20px 16px 60px; }
  .topbar { padding: 10px 16px; }
  /* Chris' Fund (2026-07-26): .kpis hat overflow:hidden — bei schmaler Breite
     wurde die letzte Zahl MITTEN drin abgeschnitten ("… settled 0."), was wie
     ein Fehler aussieht. Statt zu beschneiden lieber bewusst weglassen: die
     Geld-Kennzahlen (settled, foundation) treten zurück, "online now" und die
     Agenten-Zahl bleiben — die sagen einem Besucher am schmalen Gerät am
     meisten. Ganz schmal bleibt nur noch "online now". */
  .kpis { gap: 12px; }
  .kpi:nth-child(n+3) { display: none; }
  .profile-stats { gap: 18px; }
}


/* Chris' Wunsch (2026-07-26, "machs smooth"): Feed und Discover tauschen beim
   Filterwechsel die komplette Liste aus — ohne Übergang liest sich das als
   Sprung. Gleiche Konvention wie hs-in: kurz, flach, var(--ease). */
@keyframes list-in { from { opacity: 0; transform: translateY(4px); } }
/* Chris' Fund (2026-07-26): "man sieht dass es aktualisiert oder zittert".
   Die Ansicht rendert bei Simulations-Ticks komplett neu (gemessen: 2x in 10 s)
   — die Animation machte dieses ohnehin vorhandene Neuzeichnen erst sichtbar,
   als Flackern. Sie laeuft jetzt NUR noch bei einer Handlung des Nutzers
   (Filterwechsel, erster Aufbau), nie bei Hintergrund-Aktualisierung. */
.feed-list.list-enter, .disc-masonry.list-enter { animation: list-in 220ms var(--ease); }


/* Ganze Karte klickbar (Chris, 2026-07-26: "discover und feed sollte man wie bei
   agenten die kacheln jeweils klicken können"). Bewusst KEIN <a> um die ganze
   Karte: darin liegen Knöpfe (Like, Save, Vote, Kommentare) und der Autor-Link
   — verschachtelte klickbare Elemente sind ungültiges HTML und würden genau das
   brechen, was funktionieren muss. Stattdessen eine unsichtbare Fläche darunter,
   alles Bedienbare darüber. */
.tile-host { position: relative; }
/* z-index 1 UND letztes Kind: bei Gleichstand gewinnt das spaetere Element im
   DOM. Damit deckt der Link Text und Bild ab (Chris 2026-07-27: Klick aufs Bild
   tat nichts — .disc-photo braucht position:relative fuer die Quellenangabe und
   lag dadurch ueber einem Link mit z-index 0). Knoepfe und Links IM Text stehen
   auf 2 und bleiben darueber. */
.tile-link { position: absolute; inset: 0; z-index: 1; border-radius: inherit; }
.tile-host .post-head, .tile-host .post-foot, .tile-host .post-body { position: relative; z-index: 2; }
/* Profil-Kacheln: der Textblock liegt ueber der Flaeche, Links darin nochmal darueber.
   BEWUSST eng gefasst: eine Regel auf ".tile-host > p" hob am 2026-07-26 jeden
   Absatz einer Feed-Karte ueber den Flaechen-Link — die Karten verloren dadurch
   ihre Klickbarkeit. Nur benannte Textbereiche werden gehoben, nichts pauschal. */
.tile-host .pt-snippet, .tile-host > .faint { position: relative; z-index: 1; }
.tile-host .pt-snippet a, .tile-host .post-text a { position: relative; z-index: 2; }
.tile-host button, .tile-host .post-head a, .tile-host .post-foot a { position: relative; z-index: 2; }


/* Beitragstext, einheitlich (ui/posttext.js). Vorher rendierte jede Ansicht
   anders — im Profil stand roher Markdown mit Rauten und Sternchen. */
.pt-h1 { font-size: 22px; line-height: 1.28; margin: 0 0 12px; font-weight: 700; }
.pt-h2 { font-size: 17px; margin: 22px 0 7px; font-weight: 650; }
.pt-h3 { font-size: 15.5px; margin: 18px 0 5px; font-weight: 600; }
.pt-p { margin: 0 0 13px; }
.pt-p:last-child, .pt-list:last-child { margin-bottom: 0; }
.pt-list { margin: 0 0 13px; padding-left: 20px; }
.pt-list li { margin: 0 0 4px; }
.pt-quote { margin: 0 0 13px; padding: 2px 0 2px 14px; border-left: 2px solid var(--accent-line);
  color: var(--text-2); font-style: italic; }
.pt-p code, .pt-snippet code { font-family: var(--mono, ui-monospace, monospace); font-size: 0.92em;
  background: var(--line-soft, rgba(127,140,158,0.12)); padding: 1px 5px; border-radius: 5px; }
/* Ein Link im Beitrag darf sichtbar sein, ohne den Absatz zu zerreissen. */
.pt-p a, .pt-snippet a, .post-text a { color: var(--accent); text-decoration: none;
  border-bottom: 1px solid var(--accent-line); word-break: break-word; }
.pt-p a:hover, .pt-snippet a:hover, .post-text a:hover { border-bottom-color: var(--accent); }
/* Vollansicht eines Beitrags — gemessen 2026-07-27, zwei Maengel behoben:
   (1) Die Ueberschrift stand bei 22px gegen 16,5px Fliesstext. Das ist kaum ein
       Unterschied. Diese Regel existierte bereits, aber die Klasse .post-full
       wurde nirgends gesetzt — sie lag tot im CSS.
   (2) 77 Zeichen pro Zeile. Angenehm lesbar sind 60-75; bei einem 2.000-Zeichen-
       Essay verliert das Auge beim Zeilensprung den Anschluss. max-width in ch
       begrenzt genau das, unabhaengig von der Schriftgroesse. */
/* Etwas zurueckgenommen (Chris, 2026-07-27: "h1 bissl zu gross"). 30px wirkten
   am Rechner passend, auf dem Handy in der schmalen Spalte zu wuchtig — dieselbe
   Zahl liest sich je nach Zeilenbreite anders. clamp() loest das: 24px auf dem
   Handy, bis 27px am grossen Bildschirm, dazwischen fliessend. */
.post-full .pt-h1 { font-size: clamp(24px, 2.2vw + 16px, 27px); line-height: 1.24;
  margin: 0 0 15px; letter-spacing: -0.01em; }
.post-full .pt-h2 { font-size: 19px; margin: 30px 0 8px; }
.post-full .pt-h3 { font-size: 16.5px; margin: 22px 0 6px; }
/* 58ch, nicht 68: ch misst die Breite der Null, die in dieser Schrift breiter
   ist als ein Durchschnittszeichen. 68ch rechneten sich zu 708px — breiter als
   der Container, die Regel war wirkungslos. Gemessen: 58ch ≈ 68 Zeichen. */
.post-full .post-body { max-width: 58ch; }
.post-full .pt-p { margin: 0 0 17px; }
/* Ein Bild darf ueber die Lesebreite hinausgehen — es liest sich nicht Zeile fuer Zeile. */
.post-full .pt-figure { max-width: none; }

/* Zusammenklappbarer Rohdaten-Block (agent.json auf dem Profil). */
.json-fold summary { list-style: none; display: inline-flex; align-items: center; gap: 5px; }
.json-fold summary::-webkit-details-marker { display: none; }
.json-fold summary::before { content: "▸"; font-size: 10px; transition: transform 140ms var(--ease); }
.json-fold[open] summary::before { transform: rotate(90deg); }
.json-fold summary:hover { color: var(--text-1); }
/* Explizit, nicht auf das Browser-Standardverhalten von <details> verlassen:
   gemessen 2026-07-26 stand das <pre> mit 200px Hoehe da, obwohl open=false.
   Eine Regel, die man selbst schreibt, kann man auch selbst nachpruefen. */
.json-fold:not([open]) > pre, .json-fold:not([open]) > *:not(summary) { display: none !important; }

/* Bild im Beitragstext (ui/posttext.js). Volle Breite des Textblocks, Unterschrift
   direkt darunter — der alt-Text dient Screenreader UND Leser, eine Zeile fuer beide. */
.pt-figure { margin: 0 0 15px; }
.pt-figure img { width: 100%; height: auto; display: block; border-radius: 10px; border: 1px solid var(--line-1); }
.pt-caption { display: block; margin-top: 6px; color: var(--text-3); text-align: center; }

/* Beitragsbilder — global, nicht view-lokal (Chris, 2026-07-27: "das obere auch
   border radius passend"). Die Regeln standen nur im <style>-Block von
   discover.js, wurden aber auch von der Feed-Karte und der Post-Ansicht benutzt.
   Ergebnis: das Aufmacher-Bild hatte dort weder Radius noch Rahmen, ausser man
   hatte vorher zufaellig Discover geoeffnet. Dieselbe Falle wie bei den
   Themen-Chips ein paar Stunden vorher. */
.disc-media { border-radius: 10px; border: 1px solid var(--line-1); overflow: hidden; margin: 0 0 8px; }
.disc-media img { width: 100%; height: auto; display: block; }
.disc-photo { position: relative; }
/* Quellenangabe (Chris, 2026-07-27): NICHT als Plakette im Bild und gar nicht
   in den Kacheln — dort ist sie Störung. Im Beitrag steht sie als leise graue
   Zeile unter dem Bild, in derselben Form wie die Bildunterschrift eines
   Bildes im Fließtext. Eine Gestaltung für beide Fälle. */

/* Herkunfts-Nachweis am Service (Markt-Brücke). Bewusst leise und nicht als
   Werbeplakette: es ist ein Beleg, kein Verkaufsargument — und er führt zu einer
   Lösung, die frei lesbar bleibt. Genau das macht ihn glaubwürdig. */
.brain-proof { display: flex; align-items: center; gap: 7px; margin: 0 0 8px;
  padding: 7px 10px; border-radius: 9px; text-decoration: none;
  border: 1px solid var(--accent-line); background: var(--accent-dim);
  color: var(--accent); font-size: 12.5px; line-height: 1.35; }
.brain-proof span { flex: 1; }
.brain-proof strong { font-weight: 650; }
.brain-proof:hover { border-color: var(--accent); }

/* Weiterlesen-Karten unter einem Beitrag. Ganze Karte klickbar — hier gibt es
   keine Knöpfe darin, also reicht ein echtes <a> ohne Flächen-Link-Konstruktion. */
/* PC: drei nebeneinander (Chris, 2026-07-27). Untereinander las es sich als
   Fortsetzung des Artikels; nebeneinander als "hier sind drei Wege weiter".
   Handy: waagerecht wischbar mit Einrasten — dieselbe Geste, die man von
   jedem Karussell kennt, statt einer vierten Bildschirmlänge Liste. */
.related-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; align-items: stretch; }
.related-card { display: flex; flex-direction: column; text-decoration: none; color: inherit;
  transition: border-color 140ms var(--ease), transform 140ms var(--ease); }
/* Chris' Fund (2026-07-27): base.css hat ein globales a:hover{underline}. Bei
   einer Karte, die SELBST ein Link ist, unterstreicht das den kompletten Inhalt
   — Datum, Titel, Anrisstext, alles. Das sieht kaputt aus, nicht anklickbar.
   Professionell reagiert nur der Titel; die Karte selbst antwortet über Rand
   und eine Winzigkeit Bewegung. */
.related-card:hover, .related-card:focus-visible { text-decoration: none;
  border-color: var(--accent-line); transform: translateY(-1px); }
.related-card:hover *, .related-card:focus-visible * { text-decoration: none; }
.related-card strong { transition: color 140ms var(--ease); }
.related-card:hover strong { color: var(--accent); }
.related-card:focus-visible { outline: 2px solid var(--accent-line); outline-offset: 2px; }
.related-card .small.muted { flex: 1; }

@media (max-width: 760px) {
  /* Der letzte Rand rechts sorgt dafuer, dass die dritte Karte nicht am Bildschirm
     klebt — und das Stueck der naechsten Karte am Rand zeigt, dass es weitergeht. */
  .related-row { display: flex; overflow-x: auto; scroll-snap-type: x mandatory;
    scroll-padding-left: 2px; -webkit-overflow-scrolling: touch;
    margin: 0 -14px; padding: 0 14px 4px; scrollbar-width: none; }
  .related-row::-webkit-scrollbar { display: none; }
  .related-card { flex: 0 0 78%; scroll-snap-align: start; }
}

/* Demo-Banner. Am Rechner eine Zeile, auf dem Handy gestapelt — dort quetschte
   sich der Satz vorher in sechs Zeilen neben den Knopf (Chris, 2026-07-27). */
.demo-banner { display: flex; align-items: center; gap: 10px; padding: 8px 16px;
  background: var(--accent-dim); border-bottom: 1px solid var(--accent-line); font-size: 12.5px; }

@media (max-width: 760px) {
  .demo-banner { flex-wrap: wrap; row-gap: 8px; padding: 10px 14px; }
  /* Der Zusatz faellt weg: auf schmalem Schirm zaehlt die Aussage, nicht die Praezisierung. */
  .demo-banner-more { display: none; }
  .demo-banner .spacer { display: none; }
  .demo-banner > span:not(.dot) { flex: 1 1 auto; }
  .demo-banner .btn { flex: 1 1 100%; justify-content: center; }
}
