/* Admin · Network (federation F1). Page-specific styles layered on the shared
   admin shell (admin-shell.css) and global tokens (app.css). Follows the
   card-list conventions of admin-sources.css. */

/* ── Shared panel look ──────────────────────────────────────────────────────── */
.net-self,
.net-import {
  margin: var(--space-5) 0;
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.net-subhead {
  margin: 0 0 var(--space-3);
  font-size: 1rem;
  font-weight: 600;
  color: var(--text);
}

/* ── Disabled note ──────────────────────────────────────────────────────────── */
.net-disabled {
  margin: var(--space-5) 0;
  padding: var(--space-4);
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  color: var(--text-muted);
}
.net-disabled code { color: var(--text); }

/* Inbound-path health warning: the node's single netstack inbound reader looks
   down, so friends are unreachable until it recovers/restarts (issue #398). */
.net-inbound-warn {
  margin: var(--space-5) 0;
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--warning, #b26b00);
  border-radius: var(--radius);
  color: var(--warning, #b26b00);
  font-weight: 600;
}

/* ── This node ──────────────────────────────────────────────────────────────── */
.net-self-grid { margin: 0 0 var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); }
.net-self-row { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.net-self-row dt { min-width: 8.5rem; color: var(--text-muted); font-size: 0.85rem; }
.net-self-row dd { margin: 0; display: inline-flex; align-items: center; gap: var(--space-2); min-width: 0; }
.net-self-row code { word-break: break-all; }
.net-key { font-size: 0.82rem; }
.net-self-actions { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.btn-mini { padding: 0.1rem 0.5rem; font-size: 0.75rem; }

/* ── Import form ────────────────────────────────────────────────────────────── */
.net-field { display: flex; flex-direction: column; gap: var(--space-1); font-size: 0.85rem; color: var(--text-muted); margin-bottom: var(--space-3); }
.net-field textarea {
  padding: 0.5rem 0.6rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font-family: var(--mono, monospace);
  font-size: 0.82rem;
  resize: vertical;
}
.net-field textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.net-hint { font-size: 0.8rem; color: var(--text-muted); margin: calc(var(--space-2) * -1) 0 var(--space-3); }

/* ── Peer list ──────────────────────────────────────────────────────────────── */
.net-peers { display: flex; flex-direction: column; gap: var(--space-3); }
.net-empty { color: var(--text-muted); font-style: italic; }
.peer-card {
  padding: var(--space-3) var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--radius);
}
.peer-card.is-friend   { border-left-color: var(--success); }
.peer-card.is-pending  { border-left-color: var(--accent); }
.peer-card.is-blocked  { border-left-color: var(--error); }
.peer-head { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-1); flex-wrap: wrap; }
.peer-name { font-weight: 600; color: var(--text); }
.peer-name-input {
  font: inherit;
  font-weight: 600;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  padding: 0 0.3rem;
}
.peer-rename { background: none; border: 0; cursor: pointer; color: var(--text-muted); padding: 0 0.2rem; }
.peer-rename:hover { color: var(--text); }
.peer-when { margin-left: auto; color: var(--text-muted); font-size: 0.85rem; }
.peer-key {
  display: block;
  font-size: 0.78rem;
  color: var(--text-muted);
  word-break: break-all;
  margin-bottom: var(--space-2);
  font-family: var(--mono, monospace);
}
.peer-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); font-size: 0.85rem; color: var(--text-muted); }
/* What a node calls itself, shown beside the label we chose for it. Italic so it
   reads as a quotation of the peer's claim rather than as a fact about it. */
.peer-heard { font-style: italic; }
/* The guest-only demotion checkbox (replaced the account-mapping select): one
   flag, inline with the meta line, clickable as a whole label. */
.peer-guest-label { display: inline-flex; align-items: center; gap: 0.3rem; cursor: pointer; font-size: 0.82rem; }
.peer-guest-only { accent-color: var(--accent, currentColor); }
/* What our last pairing attempt did. The whole point is that a pairing which is
   merely WAITING must not read as a fault, so a delivered request is styled as
   progress and only a real failure is coloured as one. */
.peer-pairing { font-size: 0.82rem; margin-top: var(--space-2); color: var(--text-muted); }
.peer-pairing.is-good { color: var(--text); }
.peer-pairing.is-bad  { color: var(--error); }

.peer-actions { display: flex; gap: var(--space-2); margin-top: var(--space-3); flex-wrap: wrap; }

/* ── Contradicted claims (F6) ────────────────────────────────────────────────
   Findings this node made by checking a peer's advertised fingerprints against
   bytes it holds itself. Styled as a warning, not an alarm: it sits quietly
   above the actions until an admin decides something. */
.peer-claims {
  margin-top: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--danger, var(--border));
  border-radius: var(--radius);
  background: var(--danger-bg, transparent);
  font-size: 0.85rem;
}
.peer-claims-head { font-weight: 600; color: var(--danger, var(--text)); }
.peer-claims-note { font-weight: 400; color: var(--text-muted); }
.peer-claim { margin-top: var(--space-3); }
.peer-claim-what { color: var(--text); }
/* The measurement and its provenance — monospace, because it is data an admin
   may want to compare character by character. */
.peer-claim-evidence {
  margin-top: var(--space-1);
  font-family: var(--font-mono, monospace);
  font-size: 0.78rem;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
.peer-claim-actions { display: flex; gap: var(--space-2); margin-top: var(--space-2); flex-wrap: wrap; }

/* ── State badge ────────────────────────────────────────────────────────────── */
.peer-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.peer-badge.is-friend  { color: var(--success); border: 1px solid var(--success); }
.peer-badge.is-pending { color: var(--accent); border: 1px solid var(--accent); }
.peer-badge.is-blocked { color: var(--error); border: 1px solid var(--error); }

/* ── Block modal: the reason a distrust mark carries ────────────────────────── */
/* Blocking publishes a mark network-wide, so the modal warns and takes a
   reason. The note is the warning; the field is what the network reads. */
.modal-note {
  margin: var(--space-3) 0;
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--error);
  background: var(--bg);
  border-radius: var(--radius);
  font-size: 0.85rem;
  color: var(--text-muted);
}
.modal-label {
  display: block;
  margin-bottom: var(--space-1);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text);
}
.modal-reason {
  width: 100%;
  font: inherit;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-2);
}
.modal-reason:focus { outline: none; border-color: var(--accent); }

/* ── Accept modal key display ───────────────────────────────────────────────── */
.modal-key {
  display: block;
  margin: var(--space-2) 0;
  padding: var(--space-2);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-family: var(--mono, monospace);
  font-size: 0.78rem;
  word-break: break-all;
  color: var(--text);
}

/* ── Network map (F6) ───────────────────────────────────────────────────────── */
/* The gossiped graph drawn as a node-link diagram. Nodes sit on rings by hop
   distance, so how far a claim travelled is legible at a glance rather than
   buried in a tooltip. */
.net-map { margin-top: var(--space-6); }

.map-toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
  flex-wrap: wrap;
}
.map-search {
  flex: 1 1 16rem;
  min-width: 0;
  font: inherit;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-2);
}
.map-search:focus { outline: none; border-color: var(--accent); }
.map-stats { font-size: 0.82rem; color: var(--text-muted); }

/* Search results (F7 item 7). They come from the WHOLE community, not from what
   the view radius is drawing, so this list is routinely the only place a distant
   node appears — it floats over the map rather than pushing it down. */
.map-find { position: relative; flex: 1 1 18rem; min-width: 0; }
.map-find .map-search { width: 100%; }
.map-hits {
  position: absolute;
  z-index: 5;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  max-height: 18rem;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgb(0 0 0 / 0.28);
}
.map-hit {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  border-bottom: 1px solid var(--border);
}
.map-hit:last-child { border-bottom: none; }
.map-hit:hover, .map-hit:focus-visible { background: var(--bg); outline: none; }
.map-hit-name { font-weight: 600; color: var(--text); }
.map-hit-why  { font-size: 0.72rem; color: var(--text-muted); }
.map-hit-key  { font-size: 0.72rem; color: var(--text-muted); }
.map-hit-dist { margin-left: auto; font-size: 0.75rem; color: var(--text-muted); }
.map-hit-branch { flex-shrink: 0; }
.map-hits-empty { margin: 0; padding: var(--space-3); font-size: 0.85rem; color: var(--text-muted); }

.map-radius {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.82rem;
  color: var(--text-muted);
  flex-shrink: 0;
}
.map-radius select {
  font: inherit;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.2rem 0.4rem;
}

/* Shown only while a rescan is in flight: what the button can and cannot do,
   said where it is being done rather than in a tooltip nobody opens. */
.map-note {
  font-size: 0.82rem;
  color: var(--text-muted);
  margin: calc(var(--space-3) * -1) 0 var(--space-3);
  max-width: 60ch;
}

.map-stage {
  position: relative;
  height: min(60vh, 520px);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.map-svg { width: 100%; height: 100%; cursor: grab; touch-action: none; display: block; }
.map-svg:active { cursor: grabbing; }

.map-empty {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  padding: var(--space-5);
  text-align: center;
  font-size: 0.9rem;
  color: var(--text-muted);
  pointer-events: none;
}

/* Edges. A one-sided claim is drawn faintly: it may simply be that the other
   end publishes no record, but it is weaker evidence either way. */
.map-edge { stroke: var(--border); stroke-width: 1.5; }
.map-edge.is-onesided { stroke-dasharray: 3 3; }
.map-edge.is-lit { stroke: var(--accent); stroke-width: 2; }
/* An edge on a drawn path: thicker than a hover highlight, because it is an
   answer the admin asked for rather than wherever the pointer happens to be. */
.map-edge.is-path { stroke: var(--accent); stroke-width: 3.5; opacity: 1; }
/* Everything the branch highlight reached — the set one block would forget. */
.map-node.is-branch .map-node-dot { stroke: var(--accent); stroke-width: 2; }
.map-edge.is-dim { opacity: 0.25; }

.map-node { cursor: pointer; }
.map-node.is-dim { opacity: 0.3; }
.map-node-dot { fill: var(--text-muted); stroke: var(--bg); stroke-width: 2; }
.map-node.is-self     .map-node-dot { fill: var(--accent); }
.map-node.is-friend   .map-node-dot { fill: var(--success); }
.map-node.is-pending  .map-node-dot { fill: var(--accent-dim); }
.map-node.is-blocked  .map-node-dot { fill: var(--error); }
.map-node.is-stranger .map-node-dot { fill: var(--text-muted); }
.map-node.is-selected .map-node-dot { stroke: var(--accent); stroke-width: 3; }
.map-node.is-hit      .map-node-dot { stroke: var(--accent); stroke-width: 3; }
.map-node:focus-visible { outline: none; }
.map-node:focus-visible .map-node-dot { stroke: var(--accent); stroke-width: 3; }

/* A ring for a node someone has published a distrust mark against. It is a
   prompt to look, never a verdict — blocking stays manual. */
.map-node-warn { fill: none; stroke: var(--error); stroke-width: 1.5; opacity: 0.7; }

.map-node-label {
  fill: var(--text);
  font-size: 11px;
  text-anchor: middle;
  paint-order: stroke;
  stroke: var(--bg);
  stroke-width: 3px;
  pointer-events: none;
  user-select: none;
}

/* Detail panel, over the canvas rather than beside it so the graph keeps the
   full width on a narrow screen. */
.map-detail {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  width: min(22rem, calc(100% - 2 * var(--space-3)));
  max-height: calc(100% - 2 * var(--space-3));
  overflow-y: auto;
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.35);
}
.map-detail-close { position: absolute; top: var(--space-2); right: var(--space-2); }
.map-detail-name {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  padding-right: var(--space-5);
  font-weight: 600;
  margin-bottom: var(--space-3);
}
.map-hearsay, .map-yours {
  font-size: 0.72rem;
  font-weight: 400;
  padding: 0 0.35rem;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  color: var(--text-muted);
}
.map-hearsay { border-color: var(--accent-dim); color: var(--accent-dim); }

.map-detail-grid { display: grid; gap: var(--space-2); font-size: 0.85rem; }
.map-detail-grid dt { color: var(--text-muted); font-size: 0.75rem; }
.map-detail-grid dd { color: var(--text); }
.map-key {
  display: block;
  font-family: var(--mono, monospace);
  font-size: 0.72rem;
  word-break: break-all;
  color: var(--text);
}

.map-marks { margin-top: var(--space-4); }
.map-marks-head { font-size: 0.85rem; font-weight: 600; color: var(--error); }
.map-marks-note { font-weight: 400; color: var(--text-muted); }
.map-mark-list { list-style: none; margin-top: var(--space-2); display: grid; gap: var(--space-2); }
.map-mark-list li {
  font-size: 0.8rem;
  padding-left: var(--space-3);
  border-left: 2px solid var(--border);
}
.map-mark-who { display: block; color: var(--text-muted); font-size: 0.72rem; }
.map-mark-why { color: var(--text); }

.map-detail-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; margin-top: var(--space-4); }
.map-note { font-size: 0.8rem; color: var(--text-muted); }
/* A note shares the action row with the buttons, and always takes its own line. */
.map-detail-actions .map-note { flex-basis: 100%; margin: 0; }

.map-legend {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-3);
  font-size: 0.78rem;
  color: var(--text-muted);
}
.map-legend li { display: flex; align-items: center; gap: var(--space-2); }
.map-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
.map-dot.is-self     { background: var(--accent); }
.map-dot.is-friend   { background: var(--success); }
.map-dot.is-pending  { background: var(--accent-dim); }
.map-dot.is-blocked  { background: var(--error); }
.map-dot.is-stranger { background: var(--text-muted); }
.map-dot.is-marked   { background: transparent; border: 2px solid var(--error); }

@media (max-width: 720px) {
  .map-stage { height: min(70vh, 420px); }
  .map-detail { inset: auto var(--space-2) var(--space-2) var(--space-2); width: auto; max-height: 60%; }
}

/* ── Paths and branches in the detail panel (F7 item 7) ─────────────────────── */
/* "How is this node connected to me, and through whom" is the question a block
   is the answer to, so it is rendered as chains of names rather than a number. */

.map-paths, .map-branch {
  border-top: 1px solid var(--border);
  padding-top: var(--space-3);
  margin-top: var(--space-3);
}
.map-paths-head, .map-branch-head {
  margin: 0 0 var(--space-2);
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text);
}
.map-path-list {
  margin: 0 0 var(--space-2);
  padding-left: 1.2rem;
  display: grid;
  gap: var(--space-1);
}
.map-path-list li {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  font-size: 0.8rem;
}
.map-path-chain { color: var(--text); word-break: break-word; }
.map-path-len   { margin-left: auto; flex-shrink: 0; color: var(--text-muted); font-size: 0.72rem; }

/* ── Underlay peerings (the Underlay subtab) ────────────────────────────────── */
/* Read-only rows, one per yggdrasil link. Same badge language as the peer
   cards, but its own classes: "up/down" is a wire fact, not a trust state. */
.ul-summary { color: var(--text-muted); font-size: 0.85rem; margin: 0 0 var(--space-3); }
.ul-summary.is-down { color: var(--error); }
.ul-list { display: flex; flex-direction: column; gap: var(--space-2); }
.ul-row {
  border: 1px solid var(--border);
  border-left: 3px solid var(--success);
  border-radius: var(--radius);
  padding: var(--space-2) var(--space-3);
  background: var(--surface);
}
.ul-row.is-down { border-left-color: var(--error); }
.ul-head { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.ul-uri  { word-break: break-all; }
.ul-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.ul-badge.is-up  { color: var(--success); border-color: var(--success); }
.ul-badge.is-off { color: var(--error); border-color: var(--error); }
.ul-meta { color: var(--text-muted); font-size: 0.8rem; margin-top: var(--space-1); word-break: break-word; }
.ul-err  { color: var(--error); font-size: 0.8rem; margin-top: var(--space-1); word-break: break-word; }
