/* Honeypot XRPL – Cluster-Drilldown-Modal
   Designbasis: Astra 6 (siehe style.css) — weiße Fläche, 1px Tintenrand,
   feine Linien, klare Radien, Mono für Daten. Bestehende --a6-Tokens und
   Komponentenklassen (.cluster-label, .risk-badge, .role-chip, .swatch,
   .chain-node, .graph-note, …) werden mitbenutzt; keine globalen
   .card/.btn-Regeln. */

/* Körper sperren, solange das Modal offen ist */
body.cluster-modal-open {
  overflow: hidden;
}

/* ---------------- Shell ---------------- */

.cluster-modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: 16px;
}

.cluster-modal[hidden] { display: none; }

.cluster-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(20, 20, 22, 0.45);
}

.cluster-modal-surface {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(1440px, 100%);
  max-height: 100%;
  background: var(--a6-surface);
  border: 1px solid var(--a6-line-strong);
  border-radius: var(--a6-r-lg);
  box-shadow: var(--a6-e2);
  overflow: hidden;
  /* Entry-Übergang (Design-Audit, Progressive Enhancement): das Modal wird per
     hidden-Attribut getoggelt — @starting-style gibt dem Eintritt eine kurze
     Fahrt, ohne dass JS Klassen setzen muss. Ohne Support (Chrome <117 o. ä.)
     erscheint das Modal wie zuvor sofort; die globale reduced-motion-*-Regel
     in style.css schneidet den Übergang ab. Nur opacity/transform, 240 ms. */
  opacity: 1;
  transform: none;
  transition: opacity 240ms var(--a6-ease), transform 240ms var(--a6-ease);
}

@starting-style {
  .cluster-modal-surface {
    opacity: 0;
    transform: translateY(8px);
  }
}

/* ---------------- Kopf ---------------- */

.cluster-modal-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--a6-line);
  background: var(--a6-surface);
}

.cluster-modal-title-wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
  min-inline-size: 0;
}

.cluster-modal-badge { display: inline-flex; align-items: center; }

.cluster-modal-metrics {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 14px;
  margin-left: auto;
}

/* .cluster-times in der Metrik-Zeile (Design-Audit): die Basisregel
   (style.css) zieht margin-top:10px — im Kopf würde der Zeitblock 10 px unter
   der Metrik-Baseline hängen; hier in der Flex-Zeile gehört er auf die
   gemeinsame Baseline. */
.cluster-modal-metrics .cluster-times {
  margin-top: 0;
}

/* Alterungshinweis (Freeze): Werte aus dem bisherigen Inline-Style im Markup
   (drilldown.js) — Markup-Klasse unverändert, Stil jetzt hier. */
.cluster-modal-stale {
  margin: 0;
  padding: 10px 18px;
  border-bottom: 1px solid var(--a6-line);
  background: var(--a6-surface-alt);
}

/* Close-Button: mindestens 44×44 px, Stil konsistent zu .download-btn */
.cluster-modal-close {
  min-width: 44px;
  min-height: 44px;
  padding: 0 14px;
  background: var(--a6-surface);
  border: 1px solid var(--a6-control-line);
  border-radius: var(--a6-r-pill);
  color: var(--a6-ink);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--a6-e1);
  transition: transform var(--a6-ui) var(--a6-ease), background-color var(--a6-fast);
}

@media (hover: hover) and (pointer: fine) {
  .cluster-modal-close:hover { background: var(--a6-surface-alt); transform: translateY(-2px); }
}

.cluster-modal-close:active { transform: translateY(0); }

/* ---------------- Körper: 3D-Bühne + Diagramm-Spalte ---------------- */

.cluster-modal-body {
  display: grid;
  grid-template-columns: minmax(55%, 1fr) minmax(300px, 45%);
  gap: 16px;
  padding: 16px 18px 18px;
  overflow: auto;
  min-height: 0;
}

.cluster-modal-graph {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-inline-size: 0;
}

/* 3D-Bühne (Design P3.1, 2026-10-06): Das WebGL-Canvas läuft mit transparentem
   Clear (drilldown.js setzt backgroundColor 'rgba(0,0,0,0)' — am gepinnten
   Bundle 3d-force-graph@1.80.0 Browser-verifiziert: der Renderer wird mit
   alpha:true konstruiert, die Farbe wird inkl. Alpha-Anteil an
   setClearColor gereicht). Darunter ein sparsames Punkt-Substrat statt
   Voll-Partikel-Meer: feines 24-px-Raster plus versetztes Sekundär-Raster
   (96 px) als Tiefenebene, darunter die Token-Bühnenfläche. Die Vignette
   (inset, sehr dezent) gibt Raumtiefe OHNE Glow — reines CSS, 0 GPU-Kosten,
   keine render-blockierende Ressource. Höhe über die gemeinsame Leiter
   --a6-stage-height (style.css-Token-Block: 720/640/560/480 px). Rand in
   --a6-line-strong als Bühnen-Anschluss; forced-colors nimmt die Vignette
   mit box-shadow:none zurück (Block unten). */
.cluster-3d {
  position: relative;
  width: 100%;
  height: var(--a6-stage-height, 520px);
  background:
    radial-gradient(var(--a6-graph-grid) 1px, transparent 1px) 0 0 / 24px 24px,
    radial-gradient(var(--a6-graph-grid) 1px, transparent 1px) 12px 12px / 96px 96px,
    var(--a6-graph-canvas);
  border: 1px solid var(--a6-line-strong);
  border-radius: var(--a6-r-md);
  overflow: hidden;
  box-shadow: inset 0 -40px 80px -60px rgba(20, 20, 22, 0.06);
}

/* Hover-Fokus (Design P3.4): drilldown.js setzt .is-hover-node über dem
   Knoten (onNodeHover). Nur der Cursor — Farb-/Breitenwechsel laufen in den
   Material-Accessoren (reduced-motion-neutral; unter prefers-reduced-motion
   stellt drilldown.js den Farb-Fokus ganz ab, der Cursor bleibt). */
.cluster-3d.is-hover-node canvas {
  cursor: pointer;
}

.cluster-3d .graph-note { padding: 16px; margin: 0; }

.cluster-graph-note { margin: 0; }

/* 3D-Beschriftungen (Knoten-/Kanten-Tooltip): 3d-force-graph rendert sie als
   div.float-tooltip-kap im Bundle-Default (dunkler Scrim, sans-serif,
   width:max-content) und injiziert sein Stylesheet zur Laufzeit — deshalb
   containerspezifisch mit höherer Spezifität. Adressen brechen so um, bevor
   sie an der Bühnenkante (.cluster-3d hat overflow:hidden) abgeschnitten
   werden (Befund 2026-09-29; Klasse im gepinnten Bundle 3d-force-graph@1.80.0
   verifiziert: nodeLabel/linkLabel sind nur API-Accessoren, keine CSS-Klassen). */
.cluster-3d .float-tooltip-kap {
  max-width: min(300px, 70vw);
  width: auto;
  white-space: normal;
  overflow-wrap: anywhere;
  word-break: break-all;
  font-family: var(--a6-mono);
  font-size: 12px;
  color: var(--a6-ink);
  background: var(--a6-surface);
  border: 1px solid var(--a6-line-strong);
  border-radius: var(--a6-r-sm);
  padding: 6px 9px;
}

.cluster-modal-side {
  display: flex;
  flex-direction: column;
  gap: 18px;
  min-inline-size: 0;
}

.cluster-modal-h {
  margin: 0 0 8px;
  font-size: 14px; /* 13 → 14 px (Design-Audit): Abschnittstitel über Body */
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--a6-ink);
}

/* ---------------- Rollen-Balken ---------------- */

.role-bars {
  display: grid;
  gap: 8px;
}

.role-bar-row {
  display: grid;
  grid-template-columns: minmax(96px, auto) 1fr auto;
  align-items: center;
  gap: 10px;
  font-size: 12px;
}

.role-bar-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--a6-body);
  white-space: nowrap;
}

.role-bar-track {
  display: block;
  height: 10px;
  background: var(--a6-surface-alt);
  border: 1px solid var(--a6-line);
  border-radius: var(--a6-r-pill);
  overflow: hidden;
}

.role-bar-fill {
  display: block;
  height: 100%;
  border-radius: var(--a6-r-pill);
}

.role-bar-source { background: var(--a6-role-source); }
.role-bar-drainer { background: var(--a6-role-drainer); }
.role-bar-collector { background: var(--a6-role-collector); }
.role-bar-relay { background: var(--a6-role-relay); }
/* Unknown-Füllung muss sich vom leeren Track (--a6-surface-alt) UND von der
   Relay-Rolle (--a6-role-relay #62626b) abheben — bisher war die Füllung
   farbidentisch mit dem Track und der Balken praktisch unsichtbar
   (Befund 2026-09-29). Mittleres Grau der Kontrolllinien. */
.role-bar-unknown { background: var(--a6-control-line); }

.role-bar-count {
  font-family: var(--a6-mono);
  font-variant-numeric: tabular-nums;
  color: var(--a6-muted);
}

/* ---------------- Zeitachse (SVG) ---------------- */

.cluster-timeline {
  display: block;
  width: 100%;
  height: 46px;
}

.cluster-timeline .timeline-axis {
  stroke: var(--a6-graph-line);
  stroke-width: 1;
}

.cluster-timeline-labels {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px;
  margin-top: 4px;
  font-family: var(--a6-mono);
  font-size: 12px;
  color: var(--a6-muted);
  font-variant-numeric: tabular-nums;
}

/* ---------------- Konten-Tabelle ---------------- */

/* Volle Modal-Breite (Layout-Fix 2026-10-06): Die Konten-Tabelle ist kein Kind
   der Side-Spalte mehr (drilldown.js hängt sie als letztes direktes Kind an
   .cluster-modal-body) — grid-column:1/-1 spannt beide Grid-Spalten, die
   Tabelle läuft über die volle Body-Breite statt über 45 % Seitenbreite mit
   horizontalem Scroll (gemessen: Naturbreite 1283 px auf 606 px Client-Breite;
   verifiziert 1600/1440/1280 VP ohne Overflow). min-inline-size:0 hält das
   Grid-Kind schrumpffähig. Folgekosten bewusst akzeptiert und dokumentiert:
   Das Modal wird höher als der Viewport (3D-Bühne 720 px + Tabelle darunter),
   .cluster-modal-body scrollt vertikal (overflow:auto siehe Body-Regel oben);
   unter 900 VP bleibt der Body einspaltig und der bestehende
   overflow-x:auto-Fallback des Wrappers aktiv. */
.cluster-modal-table {
  grid-column: 1 / -1;
  min-inline-size: 0;
}

.cluster-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--a6-line);
  border-radius: var(--a6-r-md);
  background: var(--a6-surface);
  padding-inline: 2px; /* letzte Spalte klebt nicht am Scroll-Rand */
}

/* Fokuslücke (Design-Audit): der Wrapper ist scrollbare Region
   (tabindex="0" role="region", drilldown.js) — derselbe Ring wie für
   Steuerlemente (style.css :where-Regel erfasst ihn nicht). */
.cluster-table-wrap:focus-visible {
  outline: 3px solid var(--a6-focus);
  outline-offset: 3px;
}

.cluster-table {
  /* width:100% statt max-content + min-width:100% (Layout-Fix 2026-10-06):
     max-content ließ die Tabelle NIE schrumpfen — mehrwortige Header
     („Eingehende Drops“, „Kanten (in / aus)“) brachen selbst bei
     white-space:normal nie um, weil die Tabelle ihre präferierte Breite
     behielt, und der Wrapper scrollte horizontal. Mit 100 % teilt der
     Auto-Table-Layout-Algorithmus die verfügbare Breite zu: Bei Engpass
     schrumpfen die umbrechbereiten th-Spalten (siehe white-space:normal im
     th-Block) zweizeilig, Zahlen-/Aktions-Zellen bleiben nowrap; Volldressen
     bleiben einzeilig (verifiziert 1280 VP, Spalte 268.8 px, Text einzeilig).
     Bei Luft dehnt min-Verhalten 100 % die Tabelle wie bisher auf volle
     Breite (früher via min-width:100%). */
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.cluster-table caption {
  caption-side: top;
  text-align: left;
  padding: 10px 12px;
  color: var(--a6-muted);
  font-size: 12px;
}

.cluster-table th,
.cluster-table td {
  padding: 8px 12px;
  border-bottom: 1px solid var(--a6-line);
  text-align: left;
  vertical-align: baseline;
  white-space: nowrap;
}

.cluster-table tbody tr:last-child td { border-bottom: none; }

/* Zeilenverfolgung in der 12-px-Mono-Tabelle (Design-Audit): dezente
   Surface-alt-Fläche nur auf geeigneten Zeigegeräten, ohne Layoutverschiebung. */
@media (hover: hover) and (pointer: fine) {
  .cluster-table tbody tr:hover { background: var(--a6-surface-alt); }
}

.cluster-table th {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--a6-muted);
  background: var(--a6-surface-alt);
  /* Header umbrechbar (Layout-Fix 2026-10-06): überschreibt das nowrap der
     gemeinsamen th/td-Regel oben (gleiche Spezifität, spätere Quelle gewinnt)
     — mehrwortige DE/EN-Header („Eingehende Drops“, „Edges (in / out)“)
     schrumpfen zweizeilig, wenn die verfügbare Breite unter die max-content-
     Summe fällt (gemessen: Spalte „Eingehende Drops“ 161 → 135 px bei 1280
     VP). td bleiben einzeilig (Zahlen, Badges, Aktionen). Wirkt nur zusammen
     mit width:100% der Tabelle (siehe dort). */
  white-space: normal;
  /* Sticky-Kopf (Design-Audit, defensiv): bleibt beim vertikalen Scrollen im
     .cluster-table-wrap oben liegen — die opake surface-alt-Fläche deckt
     Zeilen ab; solange der Wrapper nicht höhenbeschränkt scrollt, ist die
     Regel folgenlos. */
  position: sticky;
  top: 0;
}

.cluster-td-addr {
  font-family: var(--a6-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  /* Volle Base58-Adressen kontrolliert umbrechen (anywhere statt break-all):
     Umbruch an der natürlichsten Stelle; die Adress-Aktionen daneben bleiben
     durch flex-shrink:0 (unten) stets erreichbar — die Adresse verdrängt
     sie nicht mehr. */
  overflow-wrap: anywhere;
  white-space: normal;
  /* 220 → 200 px (Layout-Fix 2026-10-06): bei Volladressen bleibt die Spalte
     inhaltsgetrieben (~269 px, bleibt einzeilig — verifiziert); die Absenkung
     wirkt nur für den Kurzform-Fall und hält die Mindestbreite eine Stufe
     unter der Nature-Breite kürzerer Anzeigewerte. */
  min-width: 200px;
  max-width: 340px;
}

.cluster-td-num {
  font-family: var(--a6-mono);
  font-variant-numeric: tabular-nums;
}

.cluster-table-dash { color: var(--a6-muted); }

/* ---------------- JSON-Export des Clusters (A1/A5) ----------------
   Der Button steht als letztes Kind in aside.cluster-modal-side (nach
   Rollen/Zeitachse/Kette). Die Konten-Tabelle ist seit dem Layout-Fix
   2026-10-06 kein Side-Kind mehr — sie liegt als letztes direktes Kind von
   .cluster-modal-body hinter der aside und spannt die volle Breite
   (grid-column:1/-1, siehe Regel im Konten-Tabelle-Abschnitt). Der Export-
   Block erbt den .download-btn-Stil aus style.css (inkl. forced-colors-Regel);
   hidden, solange kein Export-Payload existiert (drilldown.js A4). */
.cluster-modal-export {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-start;
}

.cluster-json-download { flex: 0 1 auto; }

/* PNG-Export des Cluster-Graphen (Fix 2026-10-07): Geschwister-Button des
   JSON-Buttons, erbt .download-btn aus style.css; dieselbe flex-Regel.
   Sichtbarkeit gateiert renderGraph (setPngBtnVisible) — nur bei stehendem
   exportierbarem Canvas, nie im noGraph-Zustand. */
.cluster-png-download { flex: 0 1 auto; }

.cluster-export-note { margin: 0; }

/* ---------------- Adress-Aktionen (Kopieren + XRPScan-Link) ---------- */

.addr-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 8px;
  vertical-align: middle;
}

/* Touch-Ziele mindestens 44x44 px (Astra-6-Regel, Befund 2026-09-29) —
   vorher 28 px hoch bzw. 28x28 px. */
.addr-copy {
  min-height: 44px;
  padding: 4px 12px; /* 4-px-Raster (Design-Audit, war 3px 14px) */
  background: var(--a6-surface);
  border: 1px solid var(--a6-control-line);
  border-radius: var(--a6-r-pill);
  color: var(--a6-ink);
  font-size: 12px;
  font-weight: 650;
  cursor: pointer;
  transition: background-color var(--a6-fast);
}

@media (hover: hover) and (pointer: fine) {
  .addr-copy:hover { background: var(--a6-surface-alt); }
}

.addr-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid var(--a6-control-line);
  border-radius: var(--a6-r-pill);
  color: var(--a6-info);
  font-size: 13px;
  text-decoration: none;
}

@media (hover: hover) and (pointer: fine) {
  .addr-link:hover { background: var(--a6-surface-alt); }
}

/* In Chain-Chips und Log-Zeilen kompakt unterbringen */
.chain-node .addr-actions { margin-left: 6px; flex-shrink: 0; }
.log-addr .addr-actions { margin-left: 6px; }

/* XRPScan-Namens-Chip (nur ergänzt): in Kette und Exchange-Spalte kompakt —
   Name zusätzlich, nie anstelle der Adresse (Basis-Look: style.css). */
.chain-node .name-chip { margin-left: 6px; flex-shrink: 0; }

/* Destination-Tag-Chip (nur ergänzt): gleiche Platzierung wie Namens-Chip. */
.chain-node .tag-chip { margin-left: 6px; flex-shrink: 0; }

/* Exchange-/Tag-Spalten der Konten-Tabelle (Layout-Fix 2026-10-05: Name- und
   Tag-Chips klebten vorher an der Adresse — eigene Spalten entlasten die
   Adress-Zelle). Chips beginnen an der Zellkante, lange Namens-Chips dürfen
   kontrolliert umbrechen. */
.cluster-td-exchange,
.cluster-td-tag {
  max-width: 260px;
  white-space: normal;
}
.cluster-td-exchange .name-chip { margin-left: 0; }
.cluster-td-tag .tag-chip { margin-left: 0; }
.cluster-td-tag .tag-chip + .tag-chip { margin-left: 6px; }

/* ---------------- Responsiv ----------------
   Die 3D-Bühnenhöhe folgt der gemeinsamen Leiter --a6-stage-height
   (style.css setzt den Token je Breakpoint neu: 640/560/480 px) — eigene
   Höhenstufen hier entfallen (zuvor fix 400/320 px ohne Anschluss). */

@media (max-width: 900px) {
  .cluster-modal-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .cluster-modal { padding: 8px; }
  .cluster-modal-head { padding: 12px 14px; }
  .cluster-modal-body { padding: 12px 14px 14px; }
  .cluster-modal-metrics { margin-left: 0; }
}

/* ---------------- Reduced Motion & Forced Colors ---------------- */

@media (prefers-reduced-motion: reduce) {
  .cluster-modal-close { transform: none !important; }
}

@media (forced-colors: active) {
  .cluster-modal-surface,
  .cluster-3d,
  .cluster-3d .float-tooltip-kap,
  .cluster-table-wrap,
  .role-bar-track,
  .addr-copy,
  .addr-link,
  .cluster-modal-close {
    border: 1px solid CanvasText;
    box-shadow: none;
  }
}
