/*
 * Hallmark · Cobalt theme · Supabase-inspired professional admin UI
 */

* { box-sizing: border-box; }

html, body {
    margin: 0; padding: 0;
    overflow-x: clip;
    background: var(--color-paper);
    color: var(--color-ink);
    font-family: var(--font-body);
    font-size: var(--text-base);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}

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

*:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
    border-radius: var(--radius);
}

/* ── Application shell ──────────────────────────────────────────────────── */

.app-shell { display: flex; min-height: 100vh; }

.sidebar {
    width: 240px;
    background: var(--color-sidebar);
    border-right: 1px solid var(--color-border);
    padding: var(--space-4) var(--space-2);
    display: flex; flex-direction: column; gap: 2px;
    flex-shrink: 0;
    transition: width var(--dur-med) var(--ease-out);
    overflow: hidden;
}

.sidebar.collapsed { width: 56px; }

.sidebar-brand {
    display: flex; align-items: center; gap: var(--space-3);
    padding: 0 var(--space-3) var(--space-4);
    font-size: var(--text-sm); font-weight: 700;
    color: var(--color-ink);
    line-height: 1.3;
    white-space: nowrap;
}

.sidebar-collapsed-icon {
    display: flex; justify-content: center;
    padding: 0 0 var(--space-4);
}
.sidebar-collapsed-icon svg { width: 28px; height: 28px; }

.sidebar-brand svg { width: 28px; height: 28px; flex-shrink: 0; }
.sidebar-brand-text { display: flex; flex-direction: column; }
.sidebar-brand-name { font-size: var(--text-sm); font-weight: 700; }
.sidebar-brand-sub { font-size: 10px; color: var(--color-ink-3); font-weight: 500; }

.sidebar-spacer { flex: 1; }

.collapse-toggle { margin-top: var(--space-2); }

.nav-label { white-space: nowrap; }

.hidden { display: none !important; }

.main-area { flex: 1; display: flex; flex-direction: column; min-width: 0; }

.topbar {
    height: 52px;
    background: var(--color-paper-2);
    border-bottom: 1px solid var(--color-border);
    display: flex; align-items: center; justify-content: space-between;
    padding: 0 var(--space-6);
    flex-shrink: 0;
}

.topbar-title { font-size: var(--text-md); font-weight: 600; color: var(--color-ink); }
.topbar-right { display: flex; align-items: center; gap: var(--space-2); }

.content {
    flex: 1;
    padding: var(--space-5) var(--space-6);
    max-width: 1280px;
    overflow-x: auto;
}

/* ── Nav links ──────────────────────────────────────────────────────────── */

.nav-link {
    display: flex; align-items: center; gap: var(--space-2);
    padding: 7px var(--space-3);
    border-radius: var(--radius);
    color: var(--color-ink-2);
    text-decoration: none;
    font-size: var(--text-sm); font-weight: 500;
    cursor: pointer; border: none; background: none;
    width: 100%; text-align: left;
    transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.nav-link:hover { background: var(--color-paper-3); color: var(--color-ink); }
.nav-link.active {
    background: var(--color-accent-light);
    color: var(--color-accent);
    font-weight: 600;
}
.nav-icon { width: 18px; height: 18px; opacity: 0.7; flex-shrink: 0; }
.nav-link.active .nav-icon { opacity: 1; }

/* ── KPI cards ──────────────────────────────────────────────────────────── */

.kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.kpi-card {
    background: var(--color-paper-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-3) var(--space-4);
}

.kpi-label {
    font-size: 11px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--color-ink-3);
    margin-bottom: 2px;
}

.kpi-value {
    font-size: var(--text-lg); font-weight: 700;
    color: var(--color-ink);
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}
.kpi-value.ok { color: var(--color-ok); }
.kpi-value.warn { color: var(--color-warn); }
.kpi-value.err { color: var(--color-err); }

/* ── Tables ──────────────────────────────────────────────────────────────── */

.table-wrap {
    background: var(--color-paper-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    overflow: hidden;
}

.tbl { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }

.tbl th {
    padding: 8px var(--space-3);
    text-align: left;
    font-size: 11px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--color-ink-3);
    background: var(--color-paper-3);
    border-bottom: 1px solid var(--color-border);
}

.tbl td {
    padding: 7px var(--space-3);
    border-bottom: 1px solid var(--color-border);
    color: var(--color-ink);
}

.tbl tbody tr:nth-child(even) { background: var(--color-paper); }
.tbl tbody tr:hover { background: var(--color-accent-light); }
.tbl tbody tr:last-child td { border-bottom: none; }

/* ── Search bar ──────────────────────────────────────────────────────── */

.table-toolbar {
    display: flex; align-items: center; gap: var(--space-3);
    padding: var(--space-3);
    border-bottom: 1px solid var(--color-border);
}

.search-bar {
    position: relative;
    display: flex; align-items: center;
    flex: 1; max-width: 320px;
}

.search-icon {
    position: absolute; left: 10px;
    width: 14px; height: 14px;
    color: var(--color-ink-3);
    pointer-events: none;
}

.search-input {
    width: 100%;
    padding: 6px 10px 6px 32px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    font-size: var(--text-sm);
    font-family: var(--font-body);
    color: var(--color-ink);
    background: var(--color-paper-2);
    outline: none;
    transition: border-color var(--dur-fast) var(--ease-out);
}

.search-input:focus {
    border-color: var(--color-accent);
}

.search-input::placeholder { color: var(--color-ink-3); }

/* ── Pagination ──────────────────────────────────────────────────────── */

.pagination-bar {
    display: flex; align-items: center; justify-content: space-between;
    padding: var(--space-2) var(--space-3);
    border-top: 1px solid var(--color-border);
    font-size: 12px; color: var(--color-ink-3);
}

/* "1–20 of 137". Secondary to the controls beside it: it is orientation, not
   something to act on. */
.pagination-info {
    font-size: var(--text-sm);
    color: var(--color-ink-3);
    font-variant-numeric: tabular-nums;
}
.pagination-controls { display: flex; align-items: center; gap: var(--space-2); }
.pagination-page { font-variant-numeric: tabular-nums; min-width: 60px; text-align: center; }

/* ── Status pills ──────────────────────────────────────────────────────── */

.pill {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 2px 8px;
    border-radius: 99px;
    font-size: 11px; font-weight: 600;
    white-space: nowrap;
    background: var(--color-paper-3); color: var(--color-ink-2);
}
.pill-ok   { background: var(--color-ok-bg);   color: var(--color-ok); }
.pill-warn { background: var(--color-warn-bg); color: var(--color-warn); }
.pill-err  { background: var(--color-err-bg);  color: var(--color-err); }
.pill-info { background: var(--color-info-bg); color: var(--color-info); }
.pill::before {
    content: ''; width: 5px; height: 5px;
    border-radius: 50%; background: currentColor; flex-shrink: 0;
}

/* ── Buttons ──────────────────────────────────────────────────────────── */

.btn {
    display: inline-flex; align-items: center; gap: var(--space-2);
    padding: 7px var(--space-3);
    border-radius: var(--radius);
    border: 1px solid var(--color-border-strong);
    background: var(--color-paper-2);
    color: var(--color-ink);
    font-family: var(--font-body); font-size: var(--text-sm); font-weight: 500;
    cursor: pointer;
    transition: all var(--dur-fast) var(--ease-out);
}
.btn:hover { background: var(--color-paper-3); border-color: var(--color-ink-3); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.4; cursor: not-allowed; transform: none; }

.btn-sm { padding: 4px 8px; font-size: 12px; min-width: 28px; justify-content: center; }

.btn-primary {
    background: var(--color-accent); color: white;
    border-color: var(--color-accent); font-weight: 600;
}
.btn-primary:hover { filter: brightness(1.1); }

/* Row action cluster: keeps a table cell's buttons from stacking or stretching
   the row height. */
.row-actions {
    display: flex;
    gap: var(--space-2);
    justify-content: flex-end;
    white-space: nowrap;
}

/* Destructive action. Outlined rather than filled: retiring a node is
   irreversible, so it should read as a deliberate choice, not the obvious
   default sitting next to a harmless one. */
.btn-danger {
    color: var(--color-err);
    border-color: var(--color-err);
    background: var(--color-paper-2);
}
.btn-danger:hover { background: var(--color-err-bg); }
.btn-danger:disabled { opacity: 0.5; cursor: not-allowed; }

/* ── Skeleton ─────────────────────────────────────────────────────────── */

.skeleton {
    display: block; height: 20px;
    border-radius: var(--radius);
    background: linear-gradient(90deg, var(--color-paper-3) 25%, var(--color-border) 50%, var(--color-paper-3) 75%);
    background-size: 200% 100%;
    animation: shimmer 1.5s infinite;
}
@keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) {
    .skeleton { animation: none; }
    .btn, .nav-link { transition: none; }
}

/* ── Login ────────────────────────────────────────────────────────────── */

.login-screen {
    display: flex; align-items: center; justify-content: center;
    min-height: 100vh; background: var(--color-paper);
}
.login-card {
    background: var(--color-paper-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-6) var(--space-5);
    text-align: center;
    max-width: 340px;
}
.login-brand { margin: 0 auto var(--space-3); width: 48px; height: 48px; }
.login-title { font-size: var(--text-md); font-weight: 700; margin: 0 0 2px; }
.login-subtitle { font-size: var(--text-sm); color: var(--color-ink-3); margin: 0 0 var(--space-4); }

/* One button per configured identity provider. The buttons carry the provider
   names, which vary in length, so they stack rather than sit in a row. */
.login-error {
    font-size: var(--text-sm);
    color: var(--color-danger, #b3402f);
    text-align: left;
    margin: 0 0 var(--space-4);
    line-height: 1.45;
}
.login-providers { display: flex; flex-direction: column; gap: var(--space-2); }
.login-provider {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: var(--space-2);
    padding: 10px var(--space-3);
    text-align: left;
}
/* A fixed slot, present whether or not we ship a mark for the provider, so
   every label starts at the same x and the buttons read as a column rather
   than three separately centred rows. */
.login-provider-logo {
    flex: 0 0 22px;
    width: 22px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
/* The marks are full-colour and some are near-black, so they sit on a white
   chip; directly on the accent fill they would not read. */
.login-provider-logo img {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    padding: 2px;
    background: #fff;
    border-radius: var(--radius-sm, 4px);
    object-fit: contain;
}
.login-provider-label { flex: 1 1 auto; }

/* ── Empty state ────────────────────────────────────────────────────────── */

.empty-state {
    padding: var(--space-6) var(--space-4);
    text-align: center; color: var(--color-ink-3);
    font-size: var(--text-sm);
}

/* ── Responsive ──────────────────────────────────────────────────────────── */

@media (max-width: 768px) {
    .app-shell { flex-direction: column; }
    .sidebar { width: 100%; flex-direction: row; overflow-x: auto; border-right: none; border-bottom: 1px solid var(--color-border); padding: var(--space-2); }
    .sidebar-brand { display: none; }
    .nav-link { white-space: nowrap; width: auto; }
    .content { padding: var(--space-3); }
    .table-toolbar { flex-wrap: wrap; }
    .search-bar { max-width: 100%; }
}

/* ── Sort headers ──────────────────────────────────────────────────────── */

.sort-header {
    display: inline-flex; align-items: center; gap: 4px;
    background: none; border: none; cursor: pointer;
    font-size: 11px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.04em;
    color: inherit; padding: 0;
    transition: color var(--dur-fast) var(--ease-out);
}
.sort-header:hover { color: var(--color-accent); }
.sort-arrow { font-size: 10px; opacity: 0; transition: opacity var(--dur-fast); }
.sort-arrow.visible { opacity: 1; color: var(--color-accent); }

/* ── Collapse button ────────────────────────────────────────────────────── */

.collapse-btn {
    display: flex; align-items: center; justify-content: center;
    width: 32px; height: 32px;
    border: 1px solid var(--color-border); border-radius: var(--radius);
    background: var(--color-paper-2); color: var(--color-ink-2);
    cursor: pointer; flex-shrink: 0;
    transition: all var(--dur-fast) var(--ease-out);
    align-self: flex-end; margin-left: auto; margin-top: var(--space-2);
}
.collapse-btn:hover { background: var(--color-paper-3); color: var(--color-ink); border-color: var(--color-ink-3); }

/* ── Brand image ────────────────────────────────────────────────────────── */

.brand-img { width: 28px; height: 28px; border-radius: var(--radius); flex-shrink: 0; object-fit: contain; }
.login-brand { width: 56px; height: 56px; border-radius: var(--radius-lg); margin: 0 auto var(--space-3); display: block; }

/* ── Button fix: dark grey primary ────────────────────────────────────── */

.btn-primary {
    background: #2d333b !important;
    color: #ffffff !important;
    border-color: #2d333b !important;
}
.btn-primary:hover { background: #3d444c !important; border-color: #3d444c !important; }
.btn-primary:disabled { background: #6a737d !important; border-color: #6a737d !important; }

/* ============================================================
   Modal dialog
   Reuses the .table-wrap card recipe so it matches the rest of
   the surface treatment.
   ============================================================ */

.modal-overlay {
  position: fixed;
  inset: 0;
  background: oklch(20% 0.02 260 / 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  z-index: 100;
}

.modal-card {
  background: var(--color-paper-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  width: min(640px, 100%);
  max-height: 85vh;
  overflow-y: auto;
}

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4);
  border-bottom: 1px solid var(--color-border);
}

.modal-title {
  font-size: var(--text-lg);
  font-weight: 600;
  margin: 0;
}

/* Topbar identity. A button rather than a span because it copies the full
   subject on click — the label itself is elided. */
.identity-chip {
  background: none;
  border: none;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius);
  color: var(--color-ink-2);
  font-size: var(--text-sm);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out);
}

.identity-chip:hover {
  background: var(--color-paper-3);
  color: var(--color-ink);
}

/* Which customer the console is acting on.
   Given a border and its own background rather than styled as another quiet
   chip: every destructive action on these pages lands on somebody's production
   network, so this is the one control in the bar that should read as a mode,
   not as metadata. */
.tenant-select {
  background: var(--color-paper-3);
  border: 1px solid var(--color-line);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius);
  color: var(--color-ink);
  font-size: var(--text-sm);
  cursor: pointer;
  max-width: 16rem;
  transition: border-color var(--dur-fast) var(--ease-out);
}

.tenant-select:hover,
.tenant-select:focus-visible {
  border-color: var(--color-accent, var(--color-ink-2));
}

.modal-close {
  background: none;
  border: none;
  color: var(--color-ink-2);
  cursor: pointer;
  font-size: var(--text-lg);
  line-height: 1;
  padding: var(--space-1);
  border-radius: var(--radius);
  transition: background var(--dur-fast) var(--ease-out);
}

.modal-close:hover {
  background: var(--color-paper-3);
  color: var(--color-ink);
}

.modal-body {
  padding: var(--space-4);
}

/* Secret / command blocks inside the dialog */
.token-field {
  display: flex;
  gap: var(--space-2);
  align-items: stretch;
  margin-bottom: var(--space-3);
}

.token-value {
  flex: 1;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: var(--text-sm);
  background: var(--color-paper-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-2);
  overflow-wrap: anywhere;
  min-width: 0;
}

.command-block {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: var(--text-sm);
  background: var(--color-paper-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-3);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  margin: 0 0 var(--space-3);
}

.modal-label {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-ink-2);
  margin-bottom: var(--space-2);
}

/* Policy detail and editor. A full-width pane rather than a modal: .modal-card
   is capped at 640px, and a policy bundle is 13 KB of JSON. */
.editor { display: flex; flex-direction: column; gap: var(--space-4); }
.editor-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); }
.editor-title { margin: 0; font-size: 16px; font-weight: 600; color: var(--color-ink-1); }
.editor-sub { margin: 4px 0 0; font-size: 12px; color: var(--color-ink-3); max-width: 70ch; }
.draft-offer {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: var(--color-warn-bg); border: 1px solid var(--color-warn);
  border-radius: var(--radius-md); font-size: 13px; color: var(--color-ink-1);
}
.draft-offer-note { margin: 4px 0 0; font-size: 12px; color: var(--color-ink-2); max-width: 70ch; }
.draft-offer-actions { display: flex; align-items: center; gap: var(--space-2); flex-shrink: 0; }
@media (max-width: 640px) {
  .draft-offer { flex-direction: column; }
}

.editor-strip {
  display: flex; flex-wrap: wrap; gap: var(--space-5);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface-2); border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}
.editor-strip-label { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--color-ink-3); margin-bottom: 2px; }
.editor-area {
  width: 100%; min-height: 46vh; resize: vertical; box-sizing: border-box;
  padding: var(--space-3); font-size: 12px; line-height: 1.5;
  color: var(--color-ink-1); background: var(--color-surface-1);
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
}
.editor-area:focus { outline: none; border-color: var(--color-accent); }
.editor-area[readonly] { color: var(--color-ink-2); background: var(--color-surface-2); }
.editor-status { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.editor-hash { font-size: 12px; color: var(--color-ink-3); }
.editor-actions { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.diff-list { margin: var(--space-2) 0; padding-left: var(--space-4); font-size: 12px; color: var(--color-ink-2); }
.rollout {
  display: flex; flex-direction: column; gap: var(--space-3);
  padding: var(--space-4); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); background: var(--color-surface-2);
}
.tbl tbody tr.clickable { cursor: pointer; }

/* Structured policy form: the same bundle as the textarea, projected. */
.form-panel { display: flex; flex-direction: column; gap: var(--space-3); }
.form-tabs { display: flex; flex-wrap: wrap; gap: 4px; border-bottom: 1px solid var(--color-border); }
.form-tab {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 12px; font: inherit; font-size: 13px; cursor: pointer;
  color: var(--color-ink-2); background: none; border: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.form-tab:hover { color: var(--color-ink-1); }
.form-tab.active { color: var(--color-accent); border-bottom-color: var(--color-accent); }
.form-tab-count {
  font-size: 11px; padding: 1px 6px; border-radius: 999px;
  color: var(--color-ink-3); background: var(--color-surface-2);
}
.chip-row { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  padding: 5px 10px; font: inherit; font-size: 12px; cursor: pointer;
  color: var(--color-ink-2); background: var(--color-surface-1);
  border: 1px solid var(--color-border); border-radius: 999px;
}
.chip:hover { color: var(--color-ink-1); }
.chip-on { color: #fff; background: var(--color-accent); border-color: var(--color-accent); }
/* Explanatory prose under a field. Sits below the input it belongs to, so it
   needs the tighter leading and the quieter colour that mark it as guidance
   rather than a value. */
.form-hint {
    margin: 4px 0 0;
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--color-ink-3);
    max-width: 68ch;
}

.form-grid {
  display: grid; gap: var(--space-3);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.form-grid label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--color-ink-3);
}
.form-derived {
  padding: 8px 0; font-size: 13px; text-transform: none; letter-spacing: 0;
  color: var(--color-ink-1);
}

/* ── Topology ───────────────────────────────────────────────────────────── */

.topo-wrap { padding: var(--space-4); }

/* The legend earns its place: four stroke styles are not self-explanatory,
   and the one that matters most -- a link policy asks for and no edge
   reports -- is the one nobody would guess. */
.topo-legend {
    display: flex; flex-wrap: wrap; gap: var(--space-4);
    margin-bottom: var(--space-3);
    font-size: var(--text-sm); color: var(--color-ink-3);
}
.topo-key { display: inline-flex; align-items: center; gap: var(--space-2); }
.topo-swatch { display: inline-block; width: 22px; height: 0; border-top-width: 2px; }

.topo-canvas { width: 100%; height: auto; max-height: 70vh; display: block; }

.topo-edge { fill: none; stroke-linecap: round; }
/* The intended path: solid and confident. */
.topo-edge-preferred { stroke: var(--color-accent); stroke-width: 2.5; }
/* A fallback through a relay. Dashed, because it is a path of second resort
   and should not read as the main one. */
.topo-edge-backup {
    stroke: var(--color-ink-3); stroke-width: 2; stroke-dasharray: 7 5;
}
/* Allowed by a flow rule with no route behind it. Faint: it is a permission,
   not a path. */
.topo-edge-permitted { stroke: var(--color-border); stroke-width: 1.5; }
/* Both ends reported their peers and neither has this session, while policy
   asks for it. This is the state that has cost three afternoons, so it is the
   loudest thing on the canvas. */
.topo-edge-missing {
    stroke: var(--color-err); stroke-width: 2.5; stroke-dasharray: 3 4;
}
.topo-swatch.topo-edge-preferred { border-top: 2.5px solid var(--color-accent); }
.topo-swatch.topo-edge-backup { border-top: 2px dashed var(--color-ink-3); }
.topo-swatch.topo-edge-permitted { border-top: 1.5px solid var(--color-border); }
.topo-swatch.topo-edge-missing { border-top: 2.5px dashed var(--color-err); }

.topo-node { cursor: default; }
.topo-dot { stroke: var(--color-paper); stroke-width: 3; }
.topo-dot-ok { fill: var(--color-ok); }
.topo-dot-warn { fill: var(--color-warn); }
.topo-dot-err { fill: var(--color-err); }
.topo-dot-muted { fill: var(--color-ink-3); opacity: 0.45; }

/* A relay gets a ring rather than its own fill, so it can still show whether
   it is online -- which is the more urgent fact about it. */
.topo-relay-ring {
    fill: none; stroke: var(--color-accent); stroke-width: 1.5;
    stroke-dasharray: 4 3; opacity: 0.8;
}

.topo-label {
    text-anchor: middle;
    font-size: 13px; font-weight: 600;
    fill: var(--color-ink-1);
}
