/* Sovra console. Same tokens as the design proposal (platform/docs/design). */
:root {
  --bg: #F3F6F7; --surface: #FFFFFF; --surface-2: #EAF0F1; --ink: #0F1E2B; --muted: #566872; --line: #D5DEE1;
  --accent: #0B6E78; --accent-ink: #FFFFFF; --accent-soft: #DCEEEF;
  --seal: #C4860F; --seal-soft: #F6EAD0;
  --ok: #1E7F47; --ok-soft: #DDF1E5; --warn: #A86A12; --warn-soft: #F8ECD6; --bad: #B83434; --bad-soft: #F7E0E0;
  --self: #6A4BC4; --self-soft: #ECE6FA;
  --ring: var(--surface);
  --f-display: "Sora", ui-sans-serif, system-ui, sans-serif;
  --f-body: "IBM Plex Sans", ui-sans-serif, system-ui, "Segoe UI", sans-serif;
  --f-mono: "IBM Plex Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;
  --r-s: 6px; --r-m: 10px; --r-l: 16px;
  --shadow: 0 1px 2px rgba(15, 30, 43, .06), 0 10px 30px rgba(15, 30, 43, .12);
  --side-w: 248px; --gap: 16px;
  color-scheme: light;
}
/* Dark: as the system says, unless the person fixed it (Ajustes → Apariencia,
   `data-theme` on <html>). The two blocks hold the same values. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0A131A; --surface: #101C25; --surface-2: #16252F; --ink: #E4EDF0; --muted: #8FA2AC; --line: #22343F;
    --accent: #3DB5BF; --accent-ink: #04212A; --accent-soft: #11343A;
    --seal: #E5AE48; --seal-soft: #3A2B0E;
    --ok: #4CC27E; --ok-soft: #123222; --warn: #E2A84B; --warn-soft: #38290F; --bad: #EF6B6B; --bad-soft: #3A1717;
    --self: #A993F0; --self-soft: #251C40;
    --shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 12px 32px rgba(0, 0, 0, .45);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --bg: #0A131A; --surface: #101C25; --surface-2: #16252F; --ink: #E4EDF0; --muted: #8FA2AC; --line: #22343F;
  --accent: #3DB5BF; --accent-ink: #04212A; --accent-soft: #11343A;
  --seal: #E5AE48; --seal-soft: #3A2B0E;
  --ok: #4CC27E; --ok-soft: #123222; --warn: #E2A84B; --warn-soft: #38290F; --bad: #EF6B6B; --bad-soft: #3A1717;
  --self: #A993F0; --self-soft: #251C40;
  --shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 12px 32px rgba(0, 0, 0, .45);
  color-scheme: dark;
}
/* Appearance choice in the settings: the current one is marked. */
.btn[aria-current="true"] { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
* { box-sizing: border-box; }
html, body { margin: 0; }
body { background: var(--bg); color: var(--ink); font-family: var(--f-body); font-size: 15px; line-height: 1.55; }
h1, h2, h3, h4 { font-family: var(--f-display); margin: 0; letter-spacing: -.01em; text-wrap: balance; }
h1 { font-size: 1.45rem; font-weight: 600; }
h2 { font-size: 1.05rem; font-weight: 600; }
p { margin: 0; }
a { color: var(--accent); }
code, .mono { font-family: var(--f-mono); font-size: .85em; overflow-wrap: anywhere; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.muted { color: var(--muted); }
.small { font-size: .82rem; }

/* Logo: two participants joined by a channel; the amber seal is the agreement. */
.mark { display: block; color: var(--ink); flex: none; }
.mark.lg { width: 44px; height: 44px; }
.mark .s { fill: none; stroke: currentColor; stroke-width: 7; stroke-linecap: round; }
.mark .n { fill: currentColor; }
.mark .ring { fill: var(--ring); }
.mark .seal { fill: var(--seal); }

/* Buttons and forms */
/* Inputs and buttons share one height, so they line up when placed side by side. */
.btn { display: inline-flex; align-items: center; justify-content: center; height: 40px; border: 1px solid var(--line); background: var(--surface); color: var(--ink); border-radius: var(--r-s); padding: 0 16px; font: inherit; font-size: .9rem; font-weight: 500; line-height: 1; white-space: nowrap; cursor: pointer; text-decoration: none; }
.btn:hover { background: var(--surface-2); }
.btn.pri { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn.pri:hover { filter: brightness(1.07); }
/* A text button lines up with the text around it: no padding of its own. */
.btn.link { border: 0; background: none; color: var(--muted); padding: 0; height: auto; min-height: 32px; }
.field { display: grid; gap: 4px; }
.field label { font-size: .85rem; font-weight: 500; }
.field .hint { font-size: .78rem; color: var(--muted); }
/* Every field looks the same and has the same height as a button, so a
   form row lines up whatever its fields are (text, number, date, list). */
input[type=text], input[type=password], input[type=url], input[type=search], input[type=number],
input[type=email], input[type=date], input[type=datetime-local], select, textarea {
  width: 100%; border: 1px solid var(--line); background-color: var(--surface); color: var(--ink);
  border-radius: var(--r-s); padding: 0 12px; font: inherit; font-size: .95rem; margin: 0;
}
input[type=text], input[type=password], input[type=url], input[type=search], input[type=number],
input[type=email], input[type=date], input[type=datetime-local], select { height: 40px; }
input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; border-color: var(--accent); }
input::placeholder, textarea::placeholder { color: var(--muted); opacity: 1; }
/* Lists: the system arrow is replaced by one drawn in the theme's colours. */
select {
  appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 36px;
  text-overflow: ellipsis; white-space: nowrap;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 19px) 50%, calc(100% - 14px) 50%;
  background-size: 5px 5px; background-repeat: no-repeat;
}
select:hover { border-color: var(--muted); }
select option { background: var(--surface); color: var(--ink); }
/* Files: the field as the others, its button as a console button. */
input[type=file] {
  width: 100%; height: 40px; border: 1px dashed var(--line); border-radius: var(--r-s); background: var(--surface);
  color: var(--muted); font: inherit; font-size: .88rem; padding: 0 12px 0 4px; display: flex; align-items: center;
}
input[type=file]::file-selector-button {
  height: 30px; margin: 4px 12px 4px 0; border: 1px solid var(--line); border-radius: var(--r-s);
  background: var(--surface-2); color: var(--ink); font: inherit; font-size: .85rem; font-weight: 500; padding: 0 12px; cursor: pointer;
}
input[type=file]::file-selector-button:hover { border-color: var(--muted); }
textarea { padding: 10px 12px; }
textarea { min-height: 90px; font-family: var(--f-mono); font-size: .8rem; }
.code-input { font-family: var(--f-mono); font-size: 1.2rem; letter-spacing: .2em; text-align: center; }
.alert { border-radius: var(--r-s); padding: 10px 12px; font-size: .88rem; }
.alert.bad { background: var(--bad-soft); color: var(--bad); }
.alert.warn { background: var(--warn-soft); color: var(--warn); }
.alert.ok { background: var(--ok-soft); color: var(--ok); }

/* Pills */
.pill { display: inline-flex; align-items: center; gap: 6px; font-size: .75rem; font-weight: 500; padding: 2px 9px; border-radius: 999px; white-space: nowrap; background: var(--surface-2); color: var(--muted); }
.pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.pill.ok { background: var(--ok-soft); color: var(--ok); }
.pill.warn { background: var(--warn-soft); color: var(--warn); }
.pill.bad { background: var(--bad-soft); color: var(--bad); }
.pill.acc { background: var(--accent-soft); color: var(--accent); }
.pill.seal { background: var(--seal-soft); color: var(--seal); }

/* Wizard and login */
.center { min-height: 100vh; display: grid; place-items: center; gap: 16px; padding: 32px max(16px, env(safe-area-inset-left, 0px)); }
.card { width: min(480px, 100%); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-l); padding: 28px; display: grid; gap: 18px; }
.card.wide { width: min(920px, 100%); }
.card form { display: grid; gap: 14px; }
.brand { display: flex; align-items: center; gap: 10px; }
.brand .word { font-family: var(--f-display); font-weight: 600; font-size: 1.25rem; letter-spacing: -.02em; }
.steps { display: flex; gap: 6px; }
.steps span { flex: 1; height: 4px; border-radius: 2px; background: var(--line); }
.steps span.done { background: var(--accent); }
.qr { display: grid; place-items: center; background: #FFFFFF; border-radius: var(--r-m); padding: 12px; }
.qr img { width: 200px; height: 200px; }
.choices { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.choice { border: 1px solid var(--line); border-radius: var(--r-m); padding: 18px; display: grid; gap: 12px; align-content: start; }
.choice.rec { border-color: var(--accent); }
.choice form { display: grid; gap: 12px; }
@media (max-width: 760px) { .choices { grid-template-columns: 1fr; } }

/* Dashboard frame: a floating menu, fixed to the viewport, that scrolls on its own.
   It can be hidden (side-collapsed) and moved to the right (side-right); console.js
   remembers the choice in the browser. */
.app { min-height: 100vh; }
.side {
  position: fixed; z-index: 20; top: var(--gap); bottom: var(--gap); left: max(var(--gap), env(safe-area-inset-left, 0px));
  width: var(--side-w); overflow-y: auto; overscroll-behavior: contain;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-l); box-shadow: var(--shadow);
  padding: 12px; display: flex; flex-direction: column; gap: 4px;
  transition: transform .22s ease, opacity .22s ease;
}
:root.side-right .side { left: auto; right: max(var(--gap), env(safe-area-inset-right, 0px)); }
:root.side-collapsed .side { transform: translateX(calc(-100% - 2 * var(--gap))); opacity: 0; pointer-events: none; }
:root.side-collapsed.side-right .side { transform: translateX(calc(100% + 2 * var(--gap))); }
.side-tools { display: flex; justify-content: space-between; gap: 6px; margin-bottom: 4px; }
.icon-btn { display: inline-grid; place-items: center; width: 32px; height: 32px; border: 1px solid var(--line); border-radius: var(--r-s); background: var(--surface); color: var(--muted); cursor: pointer; padding: 0; }
.icon-btn:hover { background: var(--surface-2); color: var(--ink); }
.icon-btn svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* The collapse arrow points to the edge the menu hides into. */
:root.side-right .side .icon-btn.collapse svg { transform: scaleX(-1); }
.side-open {
  position: fixed; z-index: 20; top: var(--gap); left: max(var(--gap), env(safe-area-inset-left, 0px));
  display: none; width: 40px; height: 40px; box-shadow: var(--shadow); border-radius: var(--r-m);
  background: var(--accent); border-color: var(--accent); color: var(--accent-ink);
}
.side-open:hover { background: var(--accent); color: var(--accent-ink); filter: brightness(1.08); }
:root.side-right .side-open { left: auto; right: max(var(--gap), env(safe-area-inset-right, 0px)); }
:root.side-right .side-open svg { transform: scaleX(-1); }
:root.side-collapsed .side-open { display: inline-grid; }
/* The bar that holds the menu button on narrow screens; on wide ones only the
   floating button is drawn. */
.topbar { display: contents; }
.topbar-title { display: none; }
.side .who { display: flex; gap: 10px; align-items: center; padding: 6px 8px 14px; border-bottom: 1px solid var(--line); margin-bottom: 8px; }
.side .who b { font-family: var(--f-display); font-size: .92rem; font-weight: 600; display: block; }
.side .who span { font-family: var(--f-mono); font-size: .68rem; color: var(--muted); word-break: break-all; }
/* On a short screen the links scroll, and the header and the footer (session,
   language) stay in sight. */
.side nav { display: grid; gap: 2px; align-content: start; flex: 0 1 auto; min-height: 7rem; overflow-y: auto; overscroll-behavior: contain; }
.side nav a { display: block; padding: 6px 10px; border-radius: var(--r-s); font-size: .9rem; color: var(--muted); text-decoration: none; }
.side nav a:hover { background: var(--surface-2); color: var(--ink); }
.side nav a.on { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.side .foot { margin-top: auto; font-size: .78rem; color: var(--muted); padding: 10px; border-top: 1px solid var(--line); display: grid; gap: 6px; }
.main {
  padding-block: 26px 40px;
  padding-left: calc(var(--side-w) + 3 * var(--gap));
  padding-right: max(24px, env(safe-area-inset-right, 0px));
  display: grid; gap: 20px; align-content: start; min-width: 0;
  transition: padding .22s ease;
}
:root.side-right .main { padding-left: max(24px, env(safe-area-inset-left, 0px)); padding-right: calc(var(--side-w) + 3 * var(--gap)); }
:root.side-collapsed .main { padding-left: 72px; padding-right: max(24px, env(safe-area-inset-right, 0px)); }
:root.side-collapsed.side-right .main { padding-left: max(24px, env(safe-area-inset-left, 0px)); padding-right: 72px; }
.head { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }
.stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.stat { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m); padding: 14px; display: grid; gap: 4px; min-width: 0; }
.stat .k { font-size: .78rem; color: var(--muted); }
.stat .v { font-family: var(--f-display); font-size: 1.15rem; font-weight: 600; overflow-wrap: anywhere; }
/* A status in a narrow card wraps instead of spilling out of it. */
.stat .pill { white-space: normal; overflow-wrap: anywhere; max-width: 100%; justify-self: start; }
.panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m); min-width: 0; }
.panel-h { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.panel-b { padding: 16px; display: grid; gap: 12px; }
.kv { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 8px 18px; font-size: .88rem; margin: 0; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; overflow-wrap: anywhere; }
.tbl { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font-size: .86rem; }
th { font-weight: 500; color: var(--muted); text-align: left; font-size: .74rem; text-transform: uppercase; letter-spacing: .05em; padding: 10px 16px; border-bottom: 1px solid var(--line); white-space: nowrap; }
td { padding: 10px 16px; border-bottom: 1px solid var(--line); vertical-align: top; }
tr:last-child td { border-bottom: 0; }
/* In a table, identifiers stay whole: a narrow screen scrolls the table
   instead of breaking them letter by letter. Free text that may carry long
   tokens (JSON, hashes) is the one that wraps anywhere. */
td.mono, td .mono, td code { overflow-wrap: normal; }
td.detail { overflow-wrap: anywhere; min-width: 14rem; }
.chain { font-family: var(--f-mono); font-size: .74rem; color: var(--seal); white-space: nowrap; }
pre { margin: 0; background: var(--surface-2); border-radius: var(--r-s); padding: 12px; overflow-x: auto; font-family: var(--f-mono); font-size: .78rem; }
/* Each card as tall as its content: stretched to its neighbour, a short card was mostly empty. */
.two { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; align-items: start; }
.empty { text-align: center; padding: 40px 16px; display: grid; gap: 8px; justify-items: center; }
.secret { display: grid; gap: 8px; background: var(--seal-soft); border-radius: var(--r-s); padding: 14px; }
.secret textarea { background: var(--surface); }
/* Field + button in a row: the button sits on the input's baseline, not on the label's. */
.row-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: flex-end; }
.row-actions .field { flex: 1 1 220px; max-width: 360px; }
/* With fields in the row, line them up by the top, so a hint under one field does not
   lift its input above the others; whatever is not a field (a button, or a button in its own
   wrapper) skips the label line to sit beside the inputs. */
.row-actions:has(> .field) { align-items: flex-start; }
.row-actions:has(> .field) > :not(.field) { margin-top: calc(.85rem * 1.55 + 4px); }
/* A row of fields only: a grid whose rows (label, input, hint) are shared by every field
   in the same line, so inputs stay level even when one label wraps or one field has a hint. */
.form-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 4px 16px; align-items: start; }
.form-grid > .field { grid-row: span 3; grid-template-rows: subgrid; gap: 4px; margin-bottom: 8px; }
.form-grid > .field > label { align-self: end; }
/* Topology of the data space */
.topo svg { width: 100%; height: auto; display: block; }
.topo .edge { stroke: var(--accent); stroke-width: 2.5; }
.topo .edge.relay { stroke: var(--seal); stroke-dasharray: 7 6; }
.topo .edge.off { stroke: var(--line); }
.topo .node.authority { fill: var(--accent); }
.topo .seal { fill: var(--seal); }
.topo .node.member { fill: var(--surface); stroke: var(--accent); stroke-width: 3; }
.topo .node.member.off { stroke: var(--muted); stroke-dasharray: 3 3; }
.topo .node.authority.off { fill: var(--surface); stroke: var(--muted); stroke-width: 3; stroke-dasharray: 5 4; }
.topo .node.member.unknown { stroke: var(--muted); }
.topo .edge.unknown { stroke: var(--line); stroke-dasharray: 2 6; }
.topo .node.member.replica { stroke: var(--seal); }
.topo .lbl, .topo .sub { text-anchor: middle; paint-order: stroke; stroke: var(--surface); stroke-width: 5px; stroke-linejoin: round; }
.topo .lbl { fill: var(--ink); font: 600 14px var(--f-body); }
.topo .sub { fill: var(--muted); font: 12px var(--f-body); }
.legend { display: flex; gap: 18px; flex-wrap: wrap; font-size: .8rem; color: var(--muted); }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.legend i { display: inline-block; width: 26px; height: 0; border-top: 3px solid var(--accent); }
.legend i.relay { border-top: 3px dashed var(--seal); }
.legend i.off { border-top: 3px solid var(--line); }
.inline { display: inline; }
.choices-list { display: grid; gap: 12px; max-width: 640px; }
.choices-list.wide-form { max-width: none; }
.checks { border: 1px solid var(--line); border-radius: var(--r-m); padding: 12px 14px; display: grid; gap: 10px; margin: 0; }
.checks legend { font-size: .85rem; font-weight: 500; padding: 0 6px; }
.matrix td:not(:first-child), .matrix th:not(:first-child) { text-align: center; }
/* Own radio and checkbox look: the browser's accent-color turns grey in dark mode. */
input[type=radio], input[type=checkbox] {
  appearance: none; width: 18px; height: 18px; margin: 0; flex: none; cursor: pointer;
  border: 2px solid var(--muted); background: var(--surface); display: inline-grid; place-content: center;
  transition: border-color .12s, background-color .12s;
}
input[type=radio] { border-radius: 50%; }
input[type=checkbox] { border-radius: 4px; }
input[type=radio]::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--accent-ink); transform: scale(0); transition: transform .12s; }
input[type=checkbox]::before { content: ""; width: 10px; height: 10px; background: var(--accent-ink); clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); transform: scale(0); transition: transform .12s; }
input[type=radio]:checked, input[type=checkbox]:checked { border-color: var(--accent); background: var(--accent); }
input[type=radio]:checked::before, input[type=checkbox]:checked::before { transform: scale(1); }
input[type=radio]:hover, input[type=checkbox]:hover { border-color: var(--accent); }
.matrix input[type=radio] { width: 18px; height: 18px; }
.btn.danger { color: var(--bad); border-color: var(--bad); }
.btn.danger:hover { background: var(--bad-soft); }
.radio { display: flex; gap: 10px; align-items: flex-start; cursor: pointer; }
.radio input { margin-top: 3px; }
.radio > span { display: grid; gap: 2px; }
/* Password fields with a show / hide button (added by console.js). */
.password { position: relative; }
.password input { padding-right: 44px; }
.reveal { position: absolute; top: 4px; right: 4px; width: 32px; height: 32px; display: grid; place-items: center; border: 0; border-radius: var(--r-s); background: none; color: var(--muted); cursor: pointer; padding: 0; }
.reveal:hover { background: var(--surface-2); color: var(--ink); }
.reveal svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.row-between { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.panel-h .row-actions { align-items: center; }
.panel-h .btn { height: 32px; }
@media (max-width: 900px) {
  /* On narrow screens the open menu floats over the content instead of pushing it. */
  :root .main, :root.side-right .main, :root.side-collapsed .main, :root.side-collapsed.side-right .main { padding-left: max(16px, env(safe-area-inset-left, 0px)); padding-right: max(16px, env(safe-area-inset-right, 0px)); padding-top: 72px; }
  /* A bar fixed to the top, with the menu button and the space's name: the
     page scrolls under it, so the button never sits on top of the content. */
  .topbar {
    display: flex; align-items: center; gap: 12px; position: fixed; z-index: 18; top: 0; left: 0; right: 0; height: 56px;
    padding: 0 max(16px, env(safe-area-inset-right, 0px)) 0 max(16px, env(safe-area-inset-left, 0px));
    background: var(--surface); border-bottom: 1px solid var(--line);
  }
  :root.side-right .topbar { flex-direction: row-reverse; }
  .topbar .side-open, :root.side-right .topbar .side-open { position: static; width: 40px; height: 40px; box-shadow: none; flex: none; }
  .topbar-title { display: block; min-width: 0; font-family: var(--f-display); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* While it is open, the page behind is shaded and a tap on it closes the menu
     (console.js) instead of reaching a link or button underneath. */
  :root:not(.side-collapsed) .app::before { content: ""; position: fixed; inset: 0; z-index: 19; background: rgb(0 0 0 / .35); }
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .two { grid-template-columns: 1fr; }

}
@media (max-width: 600px) {
  /* Name and value one under the other: side by side, the value got a sliver. */
  .kv { grid-template-columns: minmax(0, 1fr); row-gap: 2px; }
  .kv dd { margin-bottom: 8px; }
  /* A form row becomes a column: each field takes the width, and the button
     goes under them without the label space it keeps beside a field. */
  .row-actions .field { flex-basis: 100%; max-width: none; }
  .row-actions:has(> .field) > :not(.field) { margin-top: 0; }
  /* A long button label wraps instead of pushing the page sideways. */
  .btn { white-space: normal; height: auto; min-height: 40px; padding-block: 8px; line-height: 1.25; text-align: center; }
  /* Tables become cards: one per row, one "column: value" line per cell (the
     names come from console.js). The headings stay for screen readers. */
  .tbl thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .tbl table, .tbl tbody, .tbl tr, .tbl td { display: block; }
  .tbl tr { padding: 10px 16px; border-bottom: 1px solid var(--line); }
  .tbl tr:last-child { border-bottom: 0; }
  .tbl td { position: relative; padding: 4px 0 4px 7.5rem; border: 0; min-height: 1.6em; text-align: left; }
  .tbl td::before { content: attr(data-label); position: absolute; left: 0; top: 6px; width: 7rem; color: var(--muted); font: 500 .7rem/1.3 var(--f-body); text-transform: uppercase; letter-spacing: .04em; overflow-wrap: anywhere; }
  .tbl td:not([data-label]) { padding-left: 0; }
  .tbl td:not([data-label])::before { content: none; }
  .tbl td.mono, .tbl td .mono, .tbl td code { overflow-wrap: anywhere; }
  .tbl td:empty { display: none; }
  .tbl .pill { white-space: normal; max-width: 100%; }
  /* The topology keeps a readable size and scrolls sideways inside its card. */
  .topo { overflow-x: auto; }
  .topo svg { min-width: 560px; }
}
@media (prefers-reduced-motion: reduce) {
  .side, .main { transition: none; } * { transition: none !important; animation: none !important; } }
/* Destructive actions confirmed in place (no JavaScript dialogs). */
details.confirm { position: relative; display: inline-block; }
details.confirm > summary { list-style: none; cursor: pointer; }
details.confirm > summary::-webkit-details-marker { display: none; }
.confirm-box { position: absolute; right: 0; z-index: 5; margin-top: 6px; width: min(320px, 80vw); padding: 12px; display: grid; gap: 10px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m); box-shadow: var(--shadow); }
/* Revocation notice of this connector. */
.alert.revoked { margin-bottom: 18px; display: grid; gap: 4px; }
dialog.revoked-dialog { position: fixed; inset: 0; margin: auto; z-index: 50; width: min(560px, calc(100vw - 32px)); max-height: calc(100vh - 32px); overflow: auto; padding: 22px; display: grid; gap: 12px; background: var(--surface); color: var(--ink); border: 1px solid var(--bad); border-radius: var(--r-l, 14px); box-shadow: 0 0 0 100vmax rgba(0, 0, 0, .55), var(--shadow); }
dialog.revoked-dialog blockquote { margin: 0; padding: 10px 14px; border-left: 3px solid var(--bad); background: var(--bad-soft); border-radius: var(--r-s, 6px); white-space: pre-wrap; }
.confirm-box form.stack { display: grid; gap: 8px; }
.confirm-box textarea { width: 100%; min-height: 72px; resize: vertical; }

/* Space selector in the side menu (ADR 0011). */
.space-pick { display: flex; gap: 6px; align-items: center; padding: 0 8px 12px; border-bottom: 1px solid var(--line); margin-bottom: 8px; }
.space-pick select { flex: 1; min-width: 0; height: 32px; font-size: .82rem; padding: 0 30px 0 10px; background-color: transparent; color: inherit; background-position: calc(100% - 16px) 50%, calc(100% - 11px) 50%; }
.space-list { display: grid; gap: 10px; margin: 0 0 14px; padding: 0; list-style: none; }
.space-list li { border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px; }
.chain-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 12px; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.legend .diamond { display: inline-block; width: 10px; height: 10px; margin-right: 6px; border: 2px solid var(--seal); transform: rotate(45deg); vertical-align: middle; }
/* This connector in the topology: its own colour and a halo, whatever its role. */
.topo .halo { fill: none; stroke: var(--self); stroke-width: 3; stroke-dasharray: 2 4; }
.topo .node.self, .topo .node.member.self { fill: var(--self-soft); stroke: var(--self); stroke-width: 3; }
.topo .lbl.self { fill: var(--self); }
.legend .self { display: inline-block; width: 12px; height: 12px; border-radius: 50%; border: 3px solid var(--self); background: var(--self-soft); }
/* Short-lived results (connection tests): top right, they close by themselves. */
.toasts { position: fixed; top: 16px; right: 16px; z-index: 40; display: grid; gap: 10px; width: min(420px, calc(100vw - 32px)); pointer-events: none; }
.toast { pointer-events: auto; display: grid; gap: 8px; padding: 14px 16px; background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-left: 4px solid var(--accent); border-radius: var(--r-m); box-shadow: var(--shadow); animation: toast-in .18s ease-out; }
.toast.ok { border-left-color: var(--ok); }
.toast.bad { border-left-color: var(--bad); }
.toast .pill { justify-self: start; }
.toast.leaving { opacity: 0; transform: translateY(-6px); transition: opacity .25s, transform .25s; }
@keyframes toast-in { from { opacity: 0; transform: translateY(-6px); } }
/* A section reached through a link (/network#invitar) is briefly highlighted. */
.panel[id] { scroll-margin-top: 16px; }
.panel.targeted { animation: targeted 1.6s ease-out; }
@keyframes targeted { from { box-shadow: 0 0 0 3px var(--accent); } to { box-shadow: 0 0 0 3px transparent; } }
/* Notices that can be closed (and stay closed in this browser). */
.alert.row-between .icon-btn { flex: none; background: transparent; border-color: transparent; color: inherit; }
/* Waiting for something that finishes by itself (an approval, a restart). */
.spinner { display: inline-block; width: 14px; height: 14px; margin-right: 6px; vertical-align: -2px; border: 2px solid var(--line); border-top-color: var(--accent); border-radius: 50%; animation: spin .9s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
/* This connector changing its authority role: nothing else can be done meanwhile. */
.blocking { position: fixed; inset: 0; z-index: 70; display: grid; place-items: center; padding: 16px; background: rgba(0, 0, 0, .55); }
.blocking-card { width: min(560px, 100%); max-height: calc(100vh - 32px); overflow: auto; display: grid; gap: 12px; padding: 22px; background: var(--surface); color: var(--ink); border: 1px solid var(--seal); border-radius: var(--r-l); box-shadow: var(--shadow); }
.transition-steps { margin: 0; padding-left: 22px; display: grid; gap: 6px; font-size: .9rem; color: var(--muted); }
.transition-steps li.done { color: var(--ok); }
.transition-steps li.done::marker { content: "✓  "; }
.transition-steps li.now { color: var(--ink); font-weight: 600; }

/* Negotiation room (H6c): entries of both parties, ours on the right. */
.room { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.room-entry { border: 1px solid var(--line); border-radius: var(--r-m); padding: 12px 14px; background: var(--surface); max-width: 760px; display: grid; gap: 6px; }
.room-entry.own { justify-self: end; background: var(--surface-2); }
.room-entry p { margin: 0; }
.room-text { white-space: pre-wrap; overflow-wrap: anywhere; }

/* Global catalog (H6c). */
.catalog-search { align-items: end; flex-wrap: wrap; }
.catalog-item .owner { text-align: right; }

/* Modules (H6b): one card per module, installed or offered by the registry. */
.module-card { border: 1px solid var(--line); border-radius: var(--r-m); padding: 16px; display: grid; gap: 12px; margin-top: 12px; background: var(--surface); }
.module-card h3 { font-size: 1rem; font-weight: 600; }
.module-card .row-between { align-items: flex-start; gap: 16px; }
.module-actions { align-items: center; }
/* Where a dataset's data comes from, when publishing: an address or a module. */
.source-module { border-left: 3px solid var(--accent-soft); padding-left: 12px; display: grid; gap: 12px; }
