/* a-v3.css */
/* design/demos/v3/v3.css as it is (the desktop's look); the app's own rules follow in canvas.css. */
/* Deneb, third design (DESIGN.md §3): soft, friendly, light first.
   White cards on a pale grey well, pill buttons, glossy colored tiles for
   devices (colored by owner), and one bright thing: the light flowing
   along each connection. */

:root,
[data-theme='light'] {
  color-scheme: light;
  --page: #e9e9ed;
  --bg: #ffffff;
  --well: #f4f4f6;
  --well-2: #ececef;
  --line: rgba(9, 9, 11, 0.07);
  --line-2: rgba(9, 9, 11, 0.1);
  --ink: #18181b;
  --ink-2: #71717a;
  --ink-3: #a1a1aa;
  --primary: #2f6bff;
  --primary-2: #2457e0;
  --ok: #22c55e;
  --warn: #f59e0b;
  --track: rgba(9, 9, 11, 0.09);
  --shadow-sm: 0 1px 2px rgba(9, 9, 11, 0.06), 0 1px 1px rgba(9, 9, 11, 0.04);
  --shadow-md: 0 10px 28px rgba(9, 9, 11, 0.09), 0 2px 6px rgba(9, 9, 11, 0.05);
  --win-shadow: 0 0 0 1px rgba(9, 9, 11, 0.06), 0 30px 70px rgba(9, 9, 11, 0.16), 0 8px 22px rgba(9, 9, 11, 0.07);
  --ring: #ffffff;
  --ball-1: #ffffff;
  --ball-2: #f1f2f4;
  --ball-3: #d6d8de;
}
[data-theme='dark'] {
  color-scheme: dark;
  --page: #08080a;
  --bg: #111113;
  --well: #19191c;
  --well-2: #222226;
  --line: rgba(255, 255, 255, 0.07);
  --line-2: rgba(255, 255, 255, 0.1);
  --ink: #fafafa;
  --ink-2: #a1a1aa;
  --ink-3: #6b6b74;
  --primary: #4c82ff;
  --primary-2: #3b6ff0;
  --ok: #34d399;
  --warn: #fbbf24;
  --track: rgba(255, 255, 255, 0.085);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.04);
  --shadow-md: 0 14px 34px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.06);
  --win-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 30px 80px rgba(0, 0, 0, 0.6);
  --ring: #111113;
  --ball-1: #6a6a73;
  --ball-2: #44444b;
  --ball-3: #2b2b30;
}

* {
  box-sizing: border-box;
}
html,
body {
  margin: 0;
  height: 100%;
  background: var(--page);
  font-family: -apple-system, 'SF Pro Text', 'PingFang SC', 'Microsoft YaHei UI', sans-serif;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  font-feature-settings: 'tnum';
}
button {
  font: inherit;
  color: inherit;
}

/* ---- Window ---- */
.win {
  position: absolute;
  width: 1180px;
  height: 740px;
  border-radius: 16px;
  background: var(--bg);
  box-shadow: var(--win-shadow);
  overflow: hidden;
}
.side {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 232px;
  background: var(--well);
  padding: 16px 12px 12px;
  display: flex;
  flex-direction: column;
}
.lights {
  display: flex;
  gap: 8px;
  padding: 2px 6px;
}
.lights i {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.12);
}
.lights i:nth-child(1) {
  background: #ff5f57;
}
.lights i:nth-child(2) {
  background: #febc2e;
}
.lights i:nth-child(3) {
  background: #28c840;
}
.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 22px 8px 20px;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
}
.brand svg {
  color: var(--primary);
}
.group {
  margin: 0 8px 6px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
}
.nav {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 36px;
  padding: 0 10px;
  border-radius: 10px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
  cursor: default;
  transition: background 0.16s ease-out, color 0.16s ease-out;
}
.nav:hover {
  background: var(--well-2);
}
.nav.on {
  background: var(--bg);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}
.nav .count {
  margin-left: auto;
  font-size: 12px;
  color: var(--ink-3);
}
.nav svg {
  flex: none;
  color: var(--ink-3);
}
.nav.on svg {
  color: var(--ink-2);
}
.nav .dots {
  display: flex;
  flex: none;
  width: 18px;
}
.nav .dots .ball {
  width: 10px;
  height: 10px;
  margin-right: -4px;
  box-shadow: 0 0 0 1.5px var(--well);
}
.nav.on .dots .ball {
  box-shadow: 0 0 0 1.5px var(--bg);
}
.side .gap {
  height: 18px;
}
.me {
  margin-top: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 6px 4px 8px;
  font-size: 13px;
  font-weight: 500;
}
.me .icon-btn {
  margin-left: auto;
}

/* ---- Buttons ---- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 34px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: transform 0.18s cubic-bezier(0.3, 1.5, 0.5, 1), background 0.16s, box-shadow 0.16s;
}
.btn:active {
  transform: scale(0.96);
}
.btn.primary {
  color: #fff;
  background: var(--primary);
  box-shadow: 0 1px 2px rgba(47, 107, 255, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.btn.primary:hover {
  background: var(--primary-2);
}
.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
  transition: background 0.16s, transform 0.18s cubic-bezier(0.3, 1.5, 0.5, 1);
}
.icon-btn:hover {
  background: var(--well-2);
}
.icon-btn:active {
  transform: scale(0.92);
}

/* ---- Glossy balls: people and colors ---- */
.ball {
  position: relative;
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  background: radial-gradient(circle at 34% 28%, color-mix(in oklab, var(--c) 55%, white) 0%, var(--c) 52%, color-mix(in oklab, var(--c) 82%, black) 100%);
  box-shadow: inset 0 -1.5px 3px rgba(0, 0, 0, 0.14), 0 2px 6px color-mix(in srgb, var(--c) 30%, transparent);
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.18);
}
/* Refused (DESIGN.md §6.5): the ball greys, a slash draws out from its
   middle, and the initial fades, all over 200ms. The grey is a layer over
   the person's color, so it can fade in rather than switch. */
.ball {
  transition: color 0.2s ease-out, text-shadow 0.2s ease-out, box-shadow 0.2s ease-out;
}
.ball.off {
  color: transparent;
  text-shadow: none;
  box-shadow: inset 0 -1.5px 3px rgba(0, 0, 0, 0.14), 0 2px 6px rgba(161, 161, 170, 0.3);
}
.chip .ball::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 28%, color-mix(in oklab, #a1a1aa 55%, white) 0%, #a1a1aa 52%, color-mix(in oklab, #a1a1aa 82%, black) 100%);
  box-shadow: inset 0 -1.5px 3px rgba(0, 0, 0, 0.14);
  opacity: 0;
  transition: opacity 0.2s ease-out;
}
.chip .ball::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 8%;
  width: 2px;
  height: 84%;
  margin-left: -1px;
  border-radius: 1px;
  background: var(--bg);
  transform: rotate(-45deg) scaleY(0);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--ink) 25%, transparent);
  transition: transform 0.2s ease-out;
}
.chip .ball.off::before {
  opacity: 1;
}
.chip .ball.off::after {
  transform: rotate(-45deg) scaleY(1);
}

/* ---- Main ---- */
.main {
  position: absolute;
  left: 232px;
  top: 0;
  right: 0;
  bottom: 0;
  /* The canvas slides aside for the card; what slides past the edge is
     clipped here instead of drawing over the sidebar. */
  overflow: hidden;
}
/* A node being dragged is lifted into this layer, over the card, the tray
   and the toasts (DESIGN.md §6.1). It lies exactly over the canvas. */
.drag-layer {
  position: absolute;
  left: 232px;
  top: 76px;
  right: 0;
  bottom: 0;
  pointer-events: none;
  z-index: 40;
}
.head {
  position: absolute;
  left: 28px;
  right: 24px;
  top: 22px;
  display: flex;
  align-items: center;
  gap: 16px;
}
.title {
  font-size: 20px;
  font-weight: 600;
  letter-spacing: 0.005em;
}
.sub {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  font-size: 13px;
  color: var(--ink-2);
}
.dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 18%, transparent);
}
.head .right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 14px;
}
.stack {
  display: flex;
}
.stack .ball {
  width: 30px;
  height: 30px;
  font-size: 12px;
  margin-left: -6px;
  box-shadow: 0 0 0 2px var(--bg), inset 0 -1.5px 3px rgba(0, 0, 0, 0.14);
}
.stack .ball:first-child {
  margin-left: 0;
}

/* ---- Canvas ---- */
.canvas {
  position: absolute;
  left: 0;
  top: 76px;
  right: 0;
  bottom: 0;
  /* Everything on the canvas stays under the card's layer. */
  z-index: 0;
}
.links {
  position: absolute;
  left: 0;
  top: 0;
  pointer-events: none;
}

/* ---- Device tiles: glossy, colored by owner ---- */
.dev {
  position: absolute;
  width: 60px;
  height: 60px;
  margin: -30px 0 0 -30px;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
}
.tile {
  position: absolute;
  inset: 0;
  border-radius: 18px;
  display: grid;
  place-items: center;
  background: linear-gradient(180deg, color-mix(in oklab, var(--c) 80%, white) 0%, var(--c) 58%, color-mix(in oklab, var(--c) 90%, black) 100%);
  box-shadow: inset 0 1px 0.5px rgba(255, 255, 255, 0.45), inset 0 -2px 6px rgba(0, 0, 0, 0.12), 0 8px 18px color-mix(in srgb, var(--c) 30%, transparent), 0 1px 2px rgba(0, 0, 0, 0.1);
  transition: transform 0.4s cubic-bezier(0.3, 1.35, 0.5, 1), box-shadow 0.3s ease-out;
}
.tile::before {
  content: '';
  position: absolute;
  left: 9px;
  top: 4px;
  width: 30px;
  height: 14px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0));
  pointer-events: none;
}
.tile svg {
  position: relative;
  fill: #fff;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.16));
}
.dev:hover .tile {
  transform: translateY(-2px);
  box-shadow: inset 0 1px 0.5px rgba(255, 255, 255, 0.45), inset 0 -2px 6px rgba(0, 0, 0, 0.12), 0 12px 24px color-mix(in srgb, var(--c) 36%, transparent), 0 2px 4px rgba(0, 0, 0, 0.1);
}
.dev:active .tile {
  transform: scale(0.96);
}
.dev.sel .tile {
  box-shadow: 0 0 0 4px var(--bg), 0 0 0 6px var(--primary), inset 0 1px 0.5px rgba(255, 255, 255, 0.45), 0 8px 18px color-mix(in srgb, var(--c) 30%, transparent);
}
.dev.off .tile {
  --c: #b4b4bb;
}
.dev.off .tile svg {
  opacity: 0.7;
}
.dev .name {
  position: absolute;
  left: 50%;
  top: 70px;
  transform: translateX(-50%);
  white-space: nowrap;
  text-align: center;
  font-size: 13px;
  font-weight: 500;
  line-height: 17px;
}
.dev .name small {
  display: block;
  font-size: 12px;
  font-weight: 400;
  color: var(--ink-2);
}
.dev.dragging .tile {
  transform: scale(1.06) rotate(-3deg);
  /* Lifted: a soft, slightly deeper neutral shadow. Not the owner's color
     spread wide, which reads as a smudge under the tile. */
  box-shadow: inset 0 1px 0.5px rgba(255, 255, 255, 0.45), inset 0 -2px 6px rgba(0, 0, 0, 0.12), 0 12px 24px rgba(9, 9, 11, 0.16), 0 3px 8px rgba(9, 9, 11, 0.1);
}
[data-theme='dark'] .dev.dragging .tile {
  box-shadow: inset 0 1px 0.5px rgba(255, 255, 255, 0.45), inset 0 -2px 6px rgba(0, 0, 0, 0.12), 0 12px 24px rgba(0, 0, 0, 0.45), 0 3px 8px rgba(0, 0, 0, 0.3);
}

/* Relay: a white glossy ball */
.relay {
  position: absolute;
  width: 40px;
  height: 40px;
  margin: -20px 0 0 -20px;
}
.relay .orb {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: var(--ink-2);
  background: radial-gradient(circle at 34% 28%, var(--ball-1) 0%, var(--ball-2) 52%, var(--ball-3) 100%);
  box-shadow: inset 0 -1.5px 3px rgba(0, 0, 0, 0.08), 0 6px 14px rgba(9, 9, 11, 0.12), 0 1px 2px rgba(9, 9, 11, 0.1);
  transition: box-shadow 0.25s ease-out;
}
.relay.pass .orb {
  box-shadow: inset 0 -1.5px 3px rgba(0, 0, 0, 0.08), 0 0 0 3px color-mix(in srgb, var(--c) 30%, transparent), 0 6px 18px color-mix(in srgb, var(--c) 40%, transparent);
  transition-duration: 0.08s;
}
/* The relay's name sits to its left: tracks leave it above and below. */
.relay .name {
  position: absolute;
  right: 52px;
  top: 3px;
  white-space: nowrap;
  text-align: right;
  font-size: 12px;
  font-weight: 500;
  line-height: 16px;
  color: var(--ink);
}
.relay .name small {
  display: block;
  font-weight: 400;
  color: var(--ink-2);
}

/* ---- Tray: my other devices, drag them in ---- */
.tray {
  position: absolute;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  height: 56px;
  padding: 0 10px 0 18px;
  border-radius: 999px;
  background: var(--bg);
  box-shadow: var(--shadow-md);
  font-size: 13px;
  color: var(--ink-2);
  white-space: nowrap;
}
.tray .mini {
  position: relative;
  width: 40px;
  height: 40px;
  cursor: grab;
}
.tray .mini .tile {
  border-radius: 13px;
}
.tray .mini .tile::before {
  left: 6px;
  width: 20px;
  height: 10px;
}
.tray .mini.ghost {
  opacity: 0.25;
}

/* ---- Sheet: one device, in plain words ---- */
.sheet {
  position: absolute;
  top: 88px;
  right: 20px;
  width: 300px;
  padding: 16px;
  border-radius: 20px;
  background: var(--bg);
  box-shadow: var(--shadow-md);
  /* It grows out of its top right corner and shrinks back into it. */
  transform-origin: 100% 0;
  overflow: hidden;
  /* Its own layer, over the devices as it comes and goes (DESIGN.md §6.3). */
  z-index: 20;
  transition: opacity 0.22s ease-out;
}
/* Stepped aside while something is on the move; back once all is still. */
.sheet.away {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.14s ease-in;
}
.sheet .top {
  display: flex;
  align-items: center;
  gap: 12px;
}
.sheet .top .tile-s {
  position: relative;
  width: 40px;
  height: 40px;
  flex: none;
}
.sheet .top .tile-s .tile {
  border-radius: 13px;
}
.sheet .top .tile-s .tile::before {
  left: 6px;
  width: 20px;
  height: 10px;
}
.sheet .top b {
  display: block;
  font-size: 15px;
  font-weight: 600;
}
.sheet .top span {
  font-size: 12px;
  color: var(--ink-2);
}
.open-btn {
  margin-left: auto;
  height: 28px;
  padding: 0 12px;
  border: 0;
  border-radius: 999px;
  background: var(--bg);
  box-shadow: var(--shadow-sm);
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  transition: transform 0.18s cubic-bezier(0.3, 1.5, 0.5, 1);
}
.open-btn:active {
  transform: scale(0.94);
}
.row.na {
  color: var(--ink-3);
}
.row.na em {
  margin-left: auto;
  font-style: normal;
  font-size: 12px;
}
.sheet .top .icon-btn {
  margin-left: auto;
  align-self: flex-start;
  background: var(--well);
}
.status {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 14px;
  padding: 12px;
  border-radius: 14px;
  background: var(--well);
  font-size: 13px;
  font-weight: 500;
}
.status small {
  display: block;
  font-size: 12px;
  font-weight: 400;
  color: var(--ink-2);
}
.status .badge {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  flex: none;
  color: #fff;
  background: radial-gradient(circle at 34% 28%, color-mix(in oklab, var(--c) 55%, white), var(--c) 55%, color-mix(in oklab, var(--c) 85%, black));
}
/* "Through a relay" is not a warning: the badge is the relay's own white
   ball, not a color that could be read as someone's. */
.status .badge.relay-badge {
  color: var(--ink-2);
  background: radial-gradient(circle at 34% 28%, var(--ball-1) 0%, var(--ball-2) 52%, var(--ball-3) 100%);
  box-shadow: inset 0 -1px 2px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(9, 9, 11, 0.12);
}
.status .badge.relay-badge svg {
  fill: currentColor;
}
.label {
  margin: 18px 4px 8px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
}
.rows {
  border-radius: 14px;
  background: var(--well);
  padding: 0 12px;
}
.row {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 44px;
  font-size: 13px;
  font-weight: 500;
}
.row + .row {
  border-top: 1px solid var(--line);
}
.row svg {
  color: var(--ink-2);
  flex: none;
}
.row .sw {
  margin-left: auto;
}
.people {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding: 0 12px 0 4px;
  border: 0;
  border-radius: 999px;
  background: var(--well);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: transform 0.2s cubic-bezier(0.3, 1.5, 0.5, 1), color 0.2s ease-out;
}
.chip:active {
  transform: scale(0.95);
}
.chip .ball {
  width: 26px;
  height: 26px;
  font-size: 11px;
}
.chip.blocked {
  color: var(--ink-3);
}
.hint {
  margin: 8px 4px 0;
  font-size: 12px;
  color: var(--ink-3);
}
.more {
  display: flex;
  align-items: center;
  gap: 2px;
  margin: 14px 4px 2px;
  padding: 0;
  border: 0;
  background: none;
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
}
.more svg {
  transition: transform 0.25s ease-out;
}
.more.open svg {
  transform: rotate(90deg);
}
.detail {
  overflow: hidden;
  height: 0;
  transition: height 0.3s cubic-bezier(0.3, 1.1, 0.5, 1);
}
.detail p {
  margin: 8px 4px 0;
  font-size: 12px;
  line-height: 1.7;
  color: var(--ink-2);
}

/* ---- Switch ---- */
.sw {
  position: relative;
  width: 38px;
  height: 22px;
  flex: none;
  border: 0;
  padding: 0;
  border-radius: 999px;
  background: var(--line-2);
  cursor: pointer;
  transition: background 0.2s ease-out;
}
.sw::after {
  content: '';
  position: absolute;
  left: 2px;
  top: 2px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 2px 6px rgba(0, 0, 0, 0.08);
  transition: transform 0.32s cubic-bezier(0.3, 1.45, 0.5, 1);
}
.sw.on {
  background: var(--primary);
}
.sw.on::after {
  transform: translateX(16px);
}

/* ---- Toast (DESIGN.md §6.5): a light chip like the tray and the card ---- */
.toast {
  position: absolute;
  left: 50%;
  bottom: 22px;
  z-index: 6;
  display: flex;
  align-items: center;
  height: 44px;
  padding: 0 16px 0 8px;
  border-radius: 999px;
  background: var(--bg);
  box-shadow: 0 0 0 1px var(--line), 0 12px 32px rgba(9, 9, 11, 0.1), 0 2px 6px rgba(9, 9, 11, 0.06);
  color: var(--ink);
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  transform: translateX(-50%);
}
[data-theme='dark'] .toast {
  box-shadow: 0 0 0 1px var(--line-2), 0 14px 34px rgba(0, 0, 0, 0.5);
}
.toast.has-undo {
  padding-right: 6px;
}
.toast-body {
  display: flex;
  align-items: center;
  gap: 10px;
}
.toast-tile {
  position: relative;
  width: 28px;
  height: 28px;
  flex: none;
}
.toast-tile .tile {
  border-radius: 9px;
  box-shadow: inset 0 1px 0.5px rgba(255, 255, 255, 0.45), 0 2px 6px color-mix(in srgb, var(--c) 30%, transparent);
}
.toast-tile .tile::before {
  left: 4px;
  top: 2px;
  width: 14px;
  height: 7px;
}
.toast button {
  height: 32px;
  padding: 0 12px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--primary);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 0.12s ease-out, transform 0.18s cubic-bezier(0.3, 1.5, 0.5, 1);
}
.toast button:hover {
  background: color-mix(in srgb, var(--primary) 10%, transparent);
}
.toast button:active {
  transform: scale(0.94);
}

/* ---- Page controls (outside the window, demo only) ---- */
.page-ctl {
  position: fixed;
  right: 16px;
  bottom: 16px;
  display: flex;
  gap: 8px;
}
.page-ctl .icon-btn {
  background: var(--bg);
  box-shadow: var(--shadow-sm);
}

/* Recording only: the visible pointer drawn by shared/demo.js. */
.fake-cursor {
  position: fixed;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  pointer-events: none;
  z-index: 10000;
}
.fake-cursor svg {
  position: absolute;
  left: -5px;
  top: -3px;
  filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, 0.35));
}
.fake-cursor .press {
  position: absolute;
  left: -16px;
  top: -16px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.28);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.4);
  opacity: 0;
  transform: scale(0.5);
}
.fake-cursor {
  opacity: 0;
}
.fake-cursor.seen {
  opacity: 1;
}

/* ---- Shared frame additions (app.js) ---- */
:root,
[data-theme='light'] {
  --dots: rgba(9, 9, 11, 0.32);
}
[data-theme='dark'] {
  --dots: rgba(255, 255, 255, 0.34);
}
.side-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.side-list .group {
  margin-top: 2px;
}
.nav-label {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
}
.nav .sw {
  margin-left: auto;
}
.sw.sm {
  width: 32px;
  height: 19px;
}
.sw.sm::after {
  width: 15px;
  height: 15px;
}
.sw.sm.on::after {
  transform: translateX(13px);
}
.sub .dot[data-tone='warn'] {
  background: var(--warn);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--warn) 18%, transparent);
}
.sub .dot[data-tone='off'] {
  background: var(--ink-3);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ink-3) 18%, transparent);
}
.dev .name .nm {
  display: block;
}
.relay .name.below {
  right: auto;
  left: 50%;
  top: 48px;
  transform: translateX(-50%);
  text-align: center;
}
.relay .name.right {
  right: auto;
  left: 52px;
  text-align: left;
}

/* Status chip on a link */
.pill {
  position: absolute;
  z-index: 3;
  transform: translate(-50%, -50%);
  height: 26px;
  padding: 0 10px;
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  background: var(--bg);
  box-shadow: var(--shadow-sm), 0 0 0 1px var(--line);
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-2);
  white-space: nowrap;
}
.pill[data-tone='ok'] {
  color: var(--ok);
}
.pill[data-tone='bad'] {
  color: var(--ink-2);
}

/* Demo bar (not product UI): under the window */
.demo-bar {
  position: fixed;
  left: 50%;
  bottom: 14px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 4px;
  height: 40px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--bg);
  box-shadow: var(--shadow-sm), 0 0 0 1px var(--line);
  font-size: 13px;
  color: var(--ink-2);
  white-space: nowrap;
  z-index: 50;
}
.demo-bar .icon-btn {
  width: 28px;
  height: 28px;
}
.bar-title {
  padding: 0 6px;
  color: var(--ink);
  font-weight: 500;
}
.bar-sep {
  width: 1px;
  height: 18px;
  margin: 0 4px;
  background: var(--line-2);
}
.bar-btn {
  height: 28px;
  padding: 0 12px;
  border: 0;
  border-radius: 999px;
  background: var(--well);
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
}
.bar-btn:active {
  transform: scale(0.96);
}
.seg {
  display: inline-flex;
  padding: 2px;
  border-radius: 999px;
  background: var(--well);
}
.seg button {
  height: 24px;
  padding: 0 10px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  font-size: 12.5px;
  color: var(--ink-2);
  cursor: pointer;
  transition: background 0.18s, color 0.18s;
}
.seg button.on {
  background: var(--bg);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}

/* ---- Relay tray (scene 2) ---- */
.tray .rchip {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 44px;
  padding: 0 12px 0 6px;
  border-radius: 999px;
  background: var(--well);
  cursor: grab;
  transition: opacity 0.2s, transform 0.2s cubic-bezier(0.3, 1.5, 0.5, 1);
}
.tray .rchip:active {
  transform: scale(0.96);
}
.tray .rchip.ghost {
  opacity: 0.3;
}
.tray .rchip .orb {
  position: relative;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  color: var(--ink-2);
  background: radial-gradient(circle at 34% 28%, var(--ball-1) 0%, var(--ball-2) 52%, var(--ball-3) 100%);
  box-shadow: inset 0 -1.5px 3px rgba(0, 0, 0, 0.08), 0 2px 6px rgba(9, 9, 11, 0.12);
}
.tray .rchip .orb svg {
  fill: currentColor;
}
.tray .rchip b {
  display: block;
  font-size: 13px;
  font-weight: 500;
  line-height: 16px;
  color: var(--ink);
}
.tray .rchip small {
  display: block;
  font-size: 11.5px;
  line-height: 14px;
  color: var(--ink-2);
}
.tray.target {
  box-shadow: var(--shadow-md), 0 0 0 2px var(--primary);
}
.relay.dragging .orb {
  transform: scale(1.08) rotate(-3deg);
  box-shadow: inset 0 -1.5px 3px rgba(0, 0, 0, 0.08), 0 14px 26px rgba(9, 9, 11, 0.18), 0 3px 8px rgba(9, 9, 11, 0.12);
}
.relay .orb {
  transition: transform 0.3s cubic-bezier(0.3, 1.4, 0.5, 1), box-shadow 0.25s ease-out;
}
.relay svg {
  fill: currentColor;
}
.relay {
  cursor: grab;
}

/* ---- Groups on the canvas (scene 3): a soft grey area per LAN ---- */
.area {
  position: absolute;
  border-radius: 24px;
  background: var(--well);
  transition: opacity 0.3s ease-out;
}
.area .area-title {
  position: absolute;
  left: 16px;
  top: 14px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}
.area .area-title .dots {
  display: flex;
}
.area .area-title .ball {
  width: 12px;
  height: 12px;
  margin-right: -4px;
  box-shadow: 0 0 0 1.5px var(--well);
}
.area .paused {
  position: absolute;
  right: 14px;
  top: 12px;
  height: 22px;
  padding: 0 9px;
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  background: var(--bg);
  box-shadow: var(--shadow-sm);
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-2);
  opacity: 0;
  transform: scale(0.9);
  transition: opacity 0.2s, transform 0.25s cubic-bezier(0.3, 1.4, 0.5, 1);
}
.area.is-paused .paused {
  opacity: 1;
  transform: none;
}
.dev,
.relay {
  cursor: grab;
  /* translate: a crowded node leaning out of the way (DESIGN.md §6.3). */
  transition: opacity 0.3s ease-out, translate 0.3s cubic-bezier(0.3, 1.3, 0.5, 1);
}
.relay:not(.dragging):hover .orb {
  transform: translateY(-2px);
}
.relay:not(.dragging):active .orb {
  transform: scale(0.96);
}
.relay.dragging {
  cursor: grabbing;
}
.area {
  transition: opacity 0.3s ease-out, box-shadow 0.16s ease-out, background-color 0.16s ease-out;
}
/* A drop target lights up as the pointer comes near (DESIGN.md §6.1). */
/* An area can be picked up and moved with its devices (DESIGN.md §6.2). */
.area {
  cursor: grab;
}
.area.lifted {
  cursor: grabbing;
  box-shadow: 0 18px 40px rgba(9, 9, 11, 0.12), 0 4px 10px rgba(9, 9, 11, 0.06);
}
[data-theme='dark'] .area.lifted {
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.06);
}
.area.target {
  background: color-mix(in srgb, var(--primary) 6%, var(--well));
  box-shadow: inset 0 0 0 2px var(--primary);
}
.nav.target {
  background: var(--bg);
  color: var(--ink);
  box-shadow: 0 0 0 2px var(--primary);
}
/* The device every link leaves from has its name above (DESIGN.md §4). */
.dev.up .name {
  top: auto;
  bottom: 70px;
}
.dev .name {
  border-radius: 8px;
  transition: opacity 0.15s ease-out, background-color 0.15s ease-out, box-shadow 0.15s ease-out;
}
/* Held over another node, the lifted name would print over that node's
   name. While held it sits on the window's color (a spread shadow, so its
   size does not change), readable over whatever is below. */
.dev.dragging .name,
.relay.dragging .name {
  background-color: var(--bg);
  box-shadow: 0 0 0 4px var(--bg);
}
.relay .name {
  border-radius: 8px;
  transition: background-color 0.15s ease-out, box-shadow 0.15s ease-out;
}
.dev.dragging {
  z-index: 30;
  cursor: grabbing;
}
/* Lifted, a device shows in full color even if its LAN is paused. */
.dev.dragging .tile {
  filter: none;
  opacity: 1;
}

.dim {
  opacity: 0.32;
}
.dev.paused-dev:not(.dragging) .tile {
  filter: saturate(0.25);
  opacity: 0.55;
}

/* ---- Invite card (scene 3) ---- */
/* A notification, so it sits in the window's top corner, over the
   header's empty right side, clear of the canvas. */
.invite {
  position: absolute;
  top: 18px;
  right: 20px;
  width: 300px;
  padding: 16px;
  border-radius: 20px;
  background: var(--bg);
  box-shadow: var(--shadow-md);
}
.invite .who {
  display: flex;
  align-items: center;
  gap: 12px;
}
.invite .who .ball {
  width: 40px;
  height: 40px;
  font-size: 15px;
}
.invite b {
  display: block;
  font-size: 15px;
  font-weight: 600;
}
.invite span.s {
  font-size: 12px;
  color: var(--ink-2);
}
.invite .acts {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 16px;
}
.btn.ghost {
  background: var(--well);
  color: var(--ink);
}
.nav.flash {
  animation: k-flash 1.4s ease-out;
}
@keyframes k-flash {
  0% {
    background: color-mix(in srgb, var(--primary) 18%, transparent);
  }
  100% {
    background: transparent;
  }
}

/* ---- The tray's states (DESIGN.md §6.5): what it says follows the hand ---- */
.tray {
  border: 1.5px solid var(--bg);
  transition: background-color 0.2s ease-out, border-color 0.2s ease-out, transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.3s ease-out, box-shadow 0.2s ease-out;
}
[data-theme='dark'] .tray {
  border-color: var(--line);
}
.tray .tray-label {
  display: inline-block;
  overflow: hidden;
  white-space: nowrap;
  flex: none;
  transition: color 0.2s ease-out;
}
/* One of mine is near: it can go in here. */
.tray.offer {
  border-color: color-mix(in srgb, var(--primary) 40%, transparent);
}
.tray.offer .tray-label,
.tray.armed .tray-label {
  color: var(--primary);
  font-weight: 500;
}
/* It is over the tray (or on its way in). */
.tray.armed {
  background: color-mix(in srgb, var(--primary) 7%, var(--bg));
  border-color: var(--primary);
}
/* Empty and nothing in the hand: it sinks away. */
.tray.away {
  opacity: 0;
  transform: translate(-50%, 24px);
  pointer-events: none;
}
/* The room the tray opens at its end for a device coming in. */
.tray .slot {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--primary) 8%, transparent);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--primary) 30%, transparent);
}
/* A tray tile whose device is out: its place shows faintly (§6.1). */
.tray .mini.ghost,
.tray .rchip.ghost {
  opacity: 0.3;
}
/* Scene 3: why someone else's device stops at its LAN's edge. */
.area-note {
  position: absolute;
  z-index: 2;
  height: 26px;
  padding: 0 10px;
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  background: var(--bg);
  box-shadow: 0 0 0 1px var(--line), var(--shadow-sm);
  font-size: 12px;
  color: var(--ink-2);
  white-space: nowrap;
  transform: translate(-50%, -50%);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.16s ease-out;
}
.area-note.show {
  opacity: 1;
}

/* The card's last row: "更多" on the left; for my own devices, the click
   that takes one out of the LAN on the right (DESIGN.md §6.4). */
.card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 14px 4px 2px;
}
.card-foot .more {
  margin: 0;
}
.out-btn {
  height: 28px;
  padding: 0 10px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
  transition: background-color 0.12s ease-out, transform 0.18s cubic-bezier(0.3, 1.5, 0.5, 1);
}
.out-btn:hover {
  background: var(--well);
}
.out-btn:active {
  transform: scale(0.96);
}

/* account.css */
/* The account (M7, DESIGN §6.15, §14.13): as the desktop's. */
.side .me {
  border-radius: 12px;
  cursor: pointer;
  transition: background 0.12s;
}
.side .me:hover,
.side .me.on {
  background: var(--well-2);
}
.acct-card {
  position: absolute;
  z-index: 40;
  width: 300px;
  padding: 16px 16px 10px;
  border-radius: 20px;
  background: var(--bg);
  box-shadow: var(--shadow-md);
  transform-origin: 0 100%;
}
.acct-who {
  display: flex;
  align-items: center;
  gap: 12px;
}
.acct-who .ball {
  width: 40px;
  height: 40px;
  font-size: 16px;
}
.acct-who b {
  display: block;
  font-size: 15px;
  font-weight: 600;
}
.acct-who span:not(.ball) {
  font-size: 12px;
  color: var(--ink-2);
}
.acct-rule {
  height: 1px;
  margin: 12px 0;
  background: var(--line-2);
}
.acct-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: calc(100% + 16px);
  margin: -6px -8px;
  padding: 6px 8px;
  border: 0;
  border-radius: 10px;
  background: none;
  color: var(--ink);
  text-align: left;
  text-decoration: none;
  font: inherit;
  cursor: pointer;
  transition: background 0.12s;
}
.acct-item:hover {
  background: var(--well);
}
.acct-item svg {
  color: var(--ink-3);
  flex: none;
}
.acct-words {
  flex: 1;
  min-width: 0;
}
.acct-words b {
  display: block;
  font-size: 13px;
  font-weight: 500;
}
.acct-words span {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  line-height: 1.45;
  color: var(--ink-3);
}
.acct-item.danger b {
  color: #ef4444;
}

/* 注销账号: the page over the window. */
.acct-del {
  position: absolute;
  inset: 0;
  z-index: 50;
  overflow-y: auto;
  background: var(--bg);
}
.acct-back {
  position: absolute;
  top: 18px;
  left: 20px;
  display: inline-flex;
  align-items: center;
  gap: 2px;
  height: 30px;
  padding: 0 10px 0 6px;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--ink-2);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.acct-back:hover {
  background: var(--well);
}
.acct-col {
  width: 420px;
  margin: 84px auto 56px;
}
.acct-col h1 {
  margin: 0;
  font-size: 22px;
  font-weight: 600;
}
.acct-wait {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 240px;
  font-size: 13px;
  color: var(--ink-2);
}
.acct-wait.trouble {
  color: #ef4444;
}
.spin {
  width: 16px;
  height: 16px;
  border: 2px solid color-mix(in srgb, var(--ink-3) 25%, transparent);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: acct-spin 1s linear infinite;
}
.spin.white {
  border-color: rgba(255, 255, 255, 0.3);
  border-top-color: #fff;
}
@keyframes acct-spin {
  to {
    transform: rotate(360deg);
  }
}
.acct-sub {
  margin: 8px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-2);
}
.acct-goes {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 20px;
  padding: 14px 16px;
  border-radius: 16px;
  background: var(--well);
}
.acct-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.acct-ico {
  display: grid;
  place-items: center;
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: var(--bg);
  color: var(--ink-2);
}
.acct-row > span:last-child {
  padding-top: 4px;
}
.acct-row b {
  display: block;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.4;
}
.acct-row b + span {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-2);
}
.acct-label {
  display: block;
  margin: 22px 0 10px;
  font-size: 13px;
  font-weight: 500;
}
.acct-lan {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
  font-size: 13px;
}
.acct-lan .n {
  font-size: 12px;
  color: var(--ink-3);
}
.acct-choices {
  display: flex;
  gap: 12px;
  margin-top: 12px;
}
.acct-choice {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  width: 204px;
  padding: 14px;
  border: 1.5px solid var(--line-2);
  border-radius: 14px;
  background: var(--bg);
  color: var(--ink);
  text-align: left;
  font: inherit;
  cursor: pointer;
  transition: border-color 0.14s, background 0.14s, transform 0.18s cubic-bezier(0.3, 1.5, 0.5, 1);
}
.acct-choice:active {
  transform: scale(0.98);
}
.acct-choice b {
  display: block;
  font-size: 14px;
  font-weight: 600;
}
.acct-choice b + span {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-2);
}
.acct-choice .radio {
  flex: none;
  display: grid;
  place-items: center;
  width: 16px;
  height: 16px;
  margin-top: 1px;
  border: 1.5px solid color-mix(in srgb, var(--ink-3) 60%, transparent);
  border-radius: 50%;
}
.acct-choice.on .radio::after {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
}
.acct-choice.transfer.on {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 6%, var(--bg));
}
.acct-choice.transfer.on .radio {
  border-color: var(--primary);
  color: var(--primary);
}
.acct-choice.delete.on {
  border-color: #ef4444;
  background: color-mix(in srgb, #ef4444 6%, var(--bg));
}
.acct-choice.delete.on .radio {
  border-color: #ef4444;
  color: #ef4444;
}
.acct-owned-line {
  min-height: 20px;
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--ink-2);
}
.acct-inuse {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-top: 16px;
  padding: 12px 14px;
  border-radius: 14px;
  background: color-mix(in srgb, #f59e0b 10%, var(--bg));
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-2);
}
.acct-inuse .dot {
  flex: none;
  width: 7px;
  height: 7px;
  margin-top: 6px;
  border-radius: 50%;
  background: #f59e0b;
}
.acct-col .acct-label[for] {
  margin-top: 26px;
  margin-bottom: 8px;
}
.acct-email {
  box-sizing: border-box;
  width: 100%;
  height: 46px;
  padding: 0 16px;
  border: 0;
  border-radius: 12px;
  outline: none;
  background: var(--well);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
}
.acct-email:focus {
  box-shadow: 0 0 0 1.5px var(--primary);
}
.acct-email::placeholder {
  color: var(--ink-3);
}
.acct-trouble {
  margin: 10px 0 0;
  font-size: 12px;
  color: #ef4444;
}
.acct-go {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  height: 44px;
  margin-top: 14px;
  border: 0;
  border-radius: 999px;
  background: #ef4444;
  box-shadow: 0 1px 2px rgba(239, 68, 68, 0.3);
  color: #fff;
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.16s, color 0.16s, transform 0.18s cubic-bezier(0.3, 1.5, 0.5, 1);
}
.acct-go:hover:not(:disabled) {
  background: #dc2626;
}
.acct-go:active:not(:disabled) {
  transform: scale(0.98);
}
.acct-go:disabled:not(.sending) {
  background: var(--well);
  box-shadow: none;
  color: var(--ink-3);
  cursor: default;
}
.acct-go.sending {
  background: color-mix(in srgb, #ef4444 85%, var(--bg));
}
.acct-note {
  margin: 10px 0 0;
  text-align: center;
  font-size: 11px;
  color: var(--ink-3);
}
.acct-later {
  display: block;
  height: 32px;
  margin: 8px auto 0;
  padding: 0 12px;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--ink-2);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.acct-later:hover {
  background: var(--well);
}
.acct-refused {
  margin: 18px 0 20px;
  padding: 14px 16px;
  border-radius: 14px;
  background: var(--well);
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-2);
}
.ghost-btn {
  background: var(--well);
  color: var(--ink);
}
.ghost-btn:hover {
  background: var(--well-2);
}

/* 删除这台设备, in a card's 更多. */
.del-row {
  margin-top: 10px;
}
.del-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 4px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: #ef4444;
  font: inherit;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
}
.del-btn:hover {
  background: var(--well);
}
.del-row p {
  margin: 2px 4px 0;
  font-size: 11px;
  line-height: 1.45;
  color: var(--ink-3);
}

/* The login page: the privacy notes; an account just deleted. */
.join-privacy {
  margin: 10px 0 0;
  text-align: center;
  font-size: 12px;
}
.join-privacy a {
  color: var(--ink-3);
  text-decoration: none;
}
.join-privacy a:hover {
  color: var(--ink-2);
  text-decoration: underline;
}
.join-gone {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin: 0 0 14px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ok);
}
.join-gone-relays {
  box-sizing: border-box;
  width: 100%;
  max-width: 400px;
  margin: 20px auto 0;
  padding: 14px 16px;
  border-radius: 16px;
  background: var(--well);
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-2);
}
.join-gone-relays p {
  margin: 0;
}
.join-gone-relays pre {
  margin: 10px 0;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--bg);
  color: var(--ink);
  font-size: 11px;
  font-weight: 500;
  line-height: 1.6;
  white-space: pre-wrap;
}
.join-gone-relays .r {
  display: flex;
  justify-content: flex-end;
}
.acct-lan .dots {
  display: flex;
  flex: none;
  width: 26px;
}
.acct-lan .dots .ball {
  width: 12px;
  height: 12px;
  margin-right: -4px;
  box-shadow: 0 0 0 1.5px var(--bg);
}

/* canvas.css */
/* The app's own look on top of the design's (a-v3.css): the frame filling
   the page, scene 4's console (as design/demos/04-device-share.html), the
   dashed "this computer", the download card and the relays page (as
   design/demos/web). Colors come from tokens.css, generated from cmd/deneb. */

body {
  background: var(--bg);
}
:root,
[data-theme='light'],
[data-theme='dark'] {
  --ball-1: var(--ball-hi);
  --ball-2: var(--ball-mid);
  --ball-3: var(--ball-lo);
}
/* The frame fills the page; the sidebar's contents sit where the desktop's
   do (measured against cmd/deneb's frames, design/plan/m3/web.md §6). */
.win.full {
  position: fixed;
  inset: 0;
  width: auto;
  height: auto;
  border-radius: 0;
  box-shadow: none;
}
.win.full .side .lights {
  display: none;
}
.win.full .side .brand {
  margin: 12px 8px 15px;
}
.win.full .side .gap {
  height: 11px;
}
.win.full .nav {
  cursor: pointer;
}
.sub .dot[data-tone='none'] {
  display: none;
}
.win.full .canvas .well-card {
  top: 24px;
}

/* ---- Scene 4's console ---- */
.well-card {
  position: absolute;
  top: 100px;
  border-radius: 20px;
  background: var(--well);
  padding: 14px 14px 16px;
}
.well-card .card-label {
  display: flex;
  justify-content: space-between;
  margin: 0 4px 12px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
}
.devs {
  left: 28px;
  width: 344px;
}
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  row-gap: 10px;
}
.cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  padding: 6px 0 4px;
  font-size: 13px;
  font-weight: 500;
  cursor: grab;
  user-select: none;
  transition: opacity 0.2s ease-out;
}
.cell .dev-s {
  position: relative;
  width: 60px;
  height: 60px;
}
.cell:hover .tile {
  transform: translateY(-2px);
}
.cell:active .tile {
  transform: scale(0.97);
}
/* A picked-up cell or row leaves its place empty (the list makes
   room for it), never a faded copy of itself (DESIGN.md §6.1). */
.cell.ghost {
  visibility: hidden;
}
.members {
  left: 388px;
  width: 264px;
}
.mrows {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.mrow {
  border-radius: 14px;
  background: var(--bg);
  box-shadow: var(--shadow-sm);
  cursor: grab;
  transition: box-shadow 0.16s ease-out, opacity 0.2s ease-out;
}
.mrow.target {
  box-shadow: 0 0 0 2px var(--primary), var(--shadow-sm);
}
.mtop {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 52px;
  padding: 0 12px 0 10px;
  font-size: 13px;
  font-weight: 500;
}
.mtop .cnt {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 12px;
  font-weight: 400;
  color: var(--ink-2);
}
/* The count rolls: the old number leaves upward, the new comes in. */
.num {
  position: relative;
  display: inline-block;
  height: 16px;
  min-width: 7px;
  overflow: hidden;
  line-height: 16px;
  text-align: right;
}
.num i {
  display: block;
  font-style: normal;
}
.mtop > svg {
  color: var(--ink-3);
  transition: transform 0.25s ease-out;
}
.mrow.open .mtop > svg {
  transform: rotate(90deg);
}
.mchips {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 6px;
  height: 0;
  overflow: hidden;
  padding: 0 10px;
  transition: height 0.32s cubic-bezier(0.25, 0.4, 0.2, 1);
}
.mchip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 4px 0 4px;
  border-radius: 999px;
  background: var(--well);
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
}
.mchip .tile-xs {
  position: relative;
  width: 22px;
  height: 22px;
}
.mchip .tile {
  border-radius: 7px;
}
.mchip .tile::before {
  left: 3px;
  top: 2px;
  width: 12px;
  height: 6px;
}
.mchip .x {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
}
.mchip .x:hover {
  background: var(--well-2);
  color: var(--ink);
}
.empty-note {
  font-size: 12px;
  color: var(--ink-3);
  line-height: 30px;
  padding-left: 4px;
}
.mrow:active {
  transform: scale(0.985);
}
.mrow.ghost {
  visibility: hidden;
}
.cell.target .tile {
  box-shadow: 0 0 0 4px var(--well), 0 0 0 6px var(--primary), inset 0 1px 0.5px rgba(255, 255, 255, 0.45), 0 8px 18px color-mix(in srgb, var(--c) 30%, transparent);
}
/* A member being dragged: the person, as a small lifted pill. */
.mpill {
  position: absolute;
  z-index: 30;
  transform: translate(-50%, -50%) rotate(-2deg);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 14px 0 4px;
  border-radius: 999px;
  background: var(--bg);
  box-shadow: var(--shadow-md), 0 0 0 1px var(--line);
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  pointer-events: none;
}
/* "Already has it", said in the row itself, where the count was. */
.mtop .note {
  margin-left: auto;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-2);
  white-space: nowrap;
}
.mtop .note + .cnt {
  display: none;
}

/* ---- "This computer", not in yet (§14.4): a dashed tile, as a device
   waiting for approval is drawn (§6.7). ---- */
.dev.pending .tile {
  background: none;
  box-shadow: none;
}
.dev.pending .tile::before {
  display: none;
}
.dev.pending .tile svg {
  fill: color-mix(in srgb, var(--c) 55%, transparent);
  filter: none;
}
.dev.pending .tile svg.dash {
  position: absolute;
  inset: 0;
  fill: none;
  color: var(--c);
}
.dev.pending:hover .tile {
  box-shadow: none;
}
.dev.pending.sel .tile {
  box-shadow: 0 0 0 4px var(--bg), 0 0 0 6px var(--primary);
}
.dev.pending .name small {
  color: var(--ink-2);
}
/* Offline: the desktop's grey (offlineGrey in cmd/deneb/model.go), its
   glyph faint (§3.4). */
.dev.off .tile {
  --c: var(--offline-grey) !important;
}

/* ---- The download card (§14.7), in the device card's place ---- */
.dl-head {
  display: flex;
  align-items: center;
  gap: 12px;
}
.dl-mark {
  width: 40px;
  height: 40px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  background: linear-gradient(180deg, color-mix(in srgb, var(--primary) 82%, #fff), color-mix(in srgb, var(--primary) 92%, #000));
  box-shadow: 0 6px 14px color-mix(in srgb, var(--primary) 30%, transparent), 0 1px 2px rgba(0, 0, 0, 0.1);
}
.dl-text {
  margin: 14px 2px 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-2);
}
.dl-btn {
  width: 100%;
  justify-content: center;
  margin-top: 16px;
}
.dl-more {
  display: block;
  margin: 10px auto 0;
  border: 0;
  background: none;
  font-size: 12px;
  color: var(--ink-3);
  cursor: pointer;
}
.dl-after {
  margin: 14px 2px 0;
  padding: 10px 12px;
  border-radius: 14px;
  background: var(--well);
  font-size: 12px;
  line-height: 1.55;
  color: var(--ink-2);
}


/* The others I know, under the members (a device for them alone). */
.members .out-label {
  margin-top: 14px;
}
.mrow.full .mtop {
  box-shadow: inset 0 0 0 1.5px var(--line-2);
}

/* ---- Narrow screens (§14.6): the console and the relays page stack their
   wells; the sidebar steps aside (the LAN itself is the phone's list). ---- */
@media (max-width: 767px) {
  .win.full .side {
    display: none;
  }
  .win.full .main,
  .win.full .drag-layer {
    left: 0;
  }
  .win.full .head {
    left: 16px;
    right: 16px;
  }
  .win.full .canvas {
    overflow-y: auto;
  }
  .win.full .canvas .well-card,
  .win.full .canvas .rwell {
    position: relative;
    top: auto;
    left: auto;
    width: auto;
    margin: 16px 16px 0;
  }
  .win.full .canvas .share-page,
  .win.full .canvas .relays-page {
    padding-bottom: 120px;
  }
}

/* ---- 我的设备 and 共享给我 (DESIGN.md §14.11) ---------------------------------------- */
/* A device's LANs in its card: one it is in has the LAN's dots, as the
   sidebar's row; one it is not in is dashed, with a "+". */
.sheet .lan-chips .chip {
  padding: 0 12px 0 10px;
  gap: 7px;
}
.sheet .lan-chips .dots {
  display: flex;
  flex: none;
  padding-right: 4px;
}
.sheet .lan-chips .dots .ball {
  width: 10px;
  height: 10px;
  margin-right: -4px;
  box-shadow: 0 0 0 1.5px var(--well);
}
.sheet .lan-chips .chip.lan-add {
  background: transparent;
  color: var(--ink-3);
  border: 1.5px dashed color-mix(in srgb, var(--ink) 22%, transparent);
  padding: 0 12px 0 8px;
}
.sheet .lan-chips .chip.lan-add:hover {
  color: var(--ink);
}
/* Whom it is shared with: the console's chips, open. */
.sheet .mchips.open {
  height: auto;
  overflow: visible;
  padding: 0;
}
.sheet .mchip .ball {
  width: 22px;
  height: 22px;
  font-size: 10px;
}
.sheet .hint.one-way {
  margin-top: 10px;
}

/* ---- M3 on the web, filled in (DESIGN.md §6.7, §6.8, §6.11; 11-11) --------------------------- */

/* The header's stack, live: a ball each, dashed for someone waiting or
   invited (§6.7), the × on the pointer; it spreads for a held device of
   mine, the balls it cannot go to faint, the one under the hand ringed. */
.head .right {
  position: relative;
}
.head .title.clickable {
  cursor: pointer;
}
.stack.live {
  align-items: center;
}
.sball {
  position: relative;
  display: inline-grid;
  margin-left: -6px;
  border-radius: 50%;
  transition: margin-left 0.42s cubic-bezier(0.3, 1.15, 0.5, 1), opacity 0.16s ease-out, transform 0.22s cubic-bezier(0.3, 1.3, 0.5, 1);
}
.sball:first-child {
  margin-left: 0;
}
.sball[data-how='member']:not(.me) {
  cursor: pointer;
}
.stack .sball .ball {
  margin-left: 0;
}
.stack.spread .sball {
  margin-left: 8px;
}
.stack.spread .sball:first-child {
  margin-left: 0;
}
.sball.faint {
  opacity: 0.4;
}
.sball.aim {
  transform: scale(1.15);
}
.sball.aim .ball {
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 3.5px var(--primary), inset 0 -1.5px 3px rgba(0, 0, 0, 0.14);
}
.sball.ghost {
  opacity: 0.35;
}
/* Waiting or invited: the ball's shape in a dashed line of their color,
   their initial faint, over a white ground. */
.sball .dash {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1.5px dashed color-mix(in srgb, var(--c) 80%, transparent);
  background: linear-gradient(color-mix(in srgb, var(--c) 8%, transparent), color-mix(in srgb, var(--c) 8%, transparent)), var(--bg);
  color: color-mix(in srgb, var(--c) 75%, transparent);
  font-size: 12px;
  font-weight: 600;
  transition: opacity 0.22s ease-out;
}
.sball[data-how='waits'],
.sball[data-how='invited'] {
  cursor: pointer;
}
.sball[data-how='waits']:hover {
  transform: translateY(-2px);
}
.sball .x,
.dev > .x,
.pchip .x,
.seat-ball .x {
  position: absolute;
  top: -6px;
  right: -6px;
  display: grid;
  place-items: center;
  width: 16px;
  height: 16px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--bg);
  color: var(--ink-2);
  box-shadow: 0 2px 6px rgba(9, 9, 11, 0.12);
  cursor: pointer;
  opacity: 0;
  transform: scale(0.6);
  transition: opacity 0.14s ease-out, transform 0.22s cubic-bezier(0.3, 1.3, 0.5, 1);
}
.sball[data-how='member'] .x {
  display: none;
}
.sball:hover .x,
.dev:hover > .x,
.pchip:hover .x,
.seat-ball .x {
  opacity: 1;
  transform: none;
}
.sball .x:hover,
.dev > .x:hover,
.pchip .x:hover,
.seat-ball .x:hover {
  color: var(--ink);
}
/* The line under the balls and "邀请朋友": what letting go does over a
   ball (blue when it gives it), or how many more people my seats take. */
.stack-hint {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  font-size: 12px;
  color: var(--ink-3);
  white-space: nowrap;
  pointer-events: none;
}
.stack-hint.go {
  color: var(--primary);
}
/* "邀请朋友" with my seats full: a dashed grey outline, still a button. */
.head .btn.primary.full {
  background: transparent;
  color: var(--ink-2);
  box-shadow: inset 0 0 0 1.5px transparent;
  outline: 1.5px dashed var(--ink-3);
  outline-offset: -1.5px;
  transition: background 0.2s, color 0.2s, outline-color 0.2s, transform 0.18s cubic-bezier(0.3, 1.5, 0.5, 1);
}
.head .btn.primary.full:hover {
  background: var(--well);
  transform: translateY(-1px);
}

/* A device that waits for the owner: dashed, its × on the pointer. */
.dev > .x {
  top: -6px;
  right: -6px;
  z-index: 2;
}
/* A login to renew (§6.8): an amber dot on the tile's corner; a click
   renews it. */
.dev > .renew {
  position: absolute;
  top: -3px;
  right: -3px;
  z-index: 2;
  width: 12px;
  height: 12px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #f59e0b;
  box-shadow: 0 0 0 2px var(--bg);
  cursor: pointer;
  transition: transform 0.22s cubic-bezier(0.3, 1.3, 0.5, 1);
}
.dev > .renew:hover {
  transform: scale(1.2);
}

/* Waiting to be let in: the owner's ball and a word, in the middle. */
.waiting {
  position: absolute;
  left: 50%;
  top: 42%;
  transform: translate(-50%, -50%);
  display: grid;
  justify-items: center;
  gap: 14px;
  font-size: 14px;
  color: var(--ink-2);
}
.ball.big {
  width: 40px;
  height: 40px;
  font-size: 16px;
}

/* Cards: chips of people and devices (分享给, a person's card, the LAN's
   members), the picker, what a share opens. */
.pchips,
.picker {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.picker {
  margin-top: 10px;
}
.pchip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding: 0 12px 0 4px;
  border: 0;
  border-radius: 999px;
  background: var(--well);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.16s ease-out, box-shadow 0.16s ease-out, opacity 0.16s ease-out, transform 0.2s cubic-bezier(0.3, 1.5, 0.5, 1);
}
.pchip:hover {
  background: var(--well-2);
}
.pchip:active:not(.still) {
  transform: scale(0.95);
}
.pchip.still {
  cursor: default;
}
.pchip.still:hover {
  background: var(--well);
}
.pchip.open {
  background: var(--well-2);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--primary) 50%, transparent);
}
.pchip .ball {
  width: 26px;
  height: 26px;
  font-size: 11px;
}
.pchip .pn {
  max-width: 150px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pchip.devchip {
  padding-left: 4px;
}
.pchip .tile-xs {
  position: relative;
  width: 26px;
  height: 26px;
}
.pchip .tile-xs .tile {
  border-radius: 8px;
}
.pchip .tile-xs .tile::before {
  left: 4px;
  top: 2px;
  width: 14px;
  height: 7px;
}
/* "+", or "+ 分享给别人" when it goes to no one yet: dashed. */
.pchip.plus {
  width: 34px;
  padding: 0;
  justify-content: center;
  background: transparent;
  color: var(--ink-2);
  box-shadow: inset 0 0 0 1.5px transparent;
  outline: 1.5px dashed var(--ink-3);
  outline-offset: -1.5px;
}
.pchip.plus.alone {
  width: auto;
  padding: 0 14px 0 10px;
  gap: 6px;
}
.pchip.plus:hover,
.pchip.plus.on {
  color: var(--primary);
  outline-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 8%, transparent);
}
.pchip.pick.full {
  opacity: 0.4;
}
.share-open .label {
  margin-top: 12px;
}
/* A refused person's ball on a chip: grey with a slash (§6.5), as the
   "谁能用" chips draw it. */
.pchip .ball::before,
.pchip .ball::after {
  content: '';
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
}
.pchip .ball::before {
  inset: 0;
  background: radial-gradient(circle at 34% 28%, color-mix(in oklab, #a1a1aa 55%, white) 0%, #a1a1aa 52%, color-mix(in oklab, #a1a1aa 82%, black) 100%);
  opacity: 0;
  transition: opacity 0.2s ease-out;
}
.pchip .ball::after {
  left: 50%;
  top: 8%;
  width: 2px;
  height: 84%;
  margin-left: -1px;
  border-radius: 1px;
  background: var(--bg);
  transform: rotate(-45deg) scaleY(0);
  transition: transform 0.2s ease-out;
}
.pchip .ball.off::before {
  opacity: 1;
}
.pchip .ball.off::after {
  transform: rotate(-45deg) scaleY(1);
}

/* A person's card, the seats' card, the LAN's card. */
.sheet .person-top,
.sheet .lan-top {
  align-items: center;
}
.sheet .lan-mark {
  display: grid;
  place-items: center;
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  background: var(--well);
}
.sheet .lan-mark .dots {
  display: flex;
}
.sheet .lan-mark .ball {
  width: 16px;
  height: 16px;
  margin-left: -5px;
  box-shadow: 0 0 0 1.5px var(--well);
}
.sheet .lan-mark .ball:first-child {
  margin-left: 0;
}
.sheet .seat-top {
  align-items: center;
}
.sheet .seat-top b {
  font-size: 15px;
}
.seat-for {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--ink-2);
}
.seat-balls {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 16px;
}
.seat-ball {
  position: relative;
  display: inline-grid;
}
.seat-ball .ball {
  width: 34px;
  height: 34px;
}
.seat-ball .x {
  top: -5px;
  right: -5px;
  width: 18px;
  height: 18px;
}
.seat-foot {
  display: flex;
  justify-content: flex-end;
  margin-top: 16px;
}
.seat-foot:empty {
  display: none;
}
.btn.sm {
  height: 30px;
  padding: 0 12px;
  font-size: 13px;
}
.btn.sm svg {
  margin-left: -2px;
}
/* The status block's one thing to do (§6.8: 续上, 提醒阿杰, 问问阿杰). */
.status .st-act {
  margin-left: auto;
  flex: none;
  background: var(--bg);
}
/* A name changed in place (§6.9): the name is a button, then a field. */
.sheet .name-edit {
  display: block;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  text-align: left;
  cursor: text;
}
.sheet .name-input {
  display: block;
  width: 100%;
  max-width: 180px;
  height: 26px;
  margin: -3px 0 -1px -6px;
  padding: 0 6px;
  border: 0;
  border-radius: 8px;
  background: var(--well);
  box-shadow: inset 0 0 0 1.5px var(--primary);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  outline: none;
}

/* The capsule a held person goes with, and the word beside it. */
.mpill .rnote,
.rnote {
  position: absolute;
  left: calc(100% + 10px);
  top: 50%;
  transform: translateY(-50%) rotate(2deg);
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  white-space: nowrap;
  transition: opacity 0.16s ease-out;
}
.rnote.go {
  color: var(--primary);
}

/* The sidebar: a LAN I wait to be let into is grey, "等同意"; one of mine
   with something waiting for me has a small blue dot. */
.nav.wait .nav-label {
  color: var(--ink-3);
}
.nav .wait-tag {
  margin-left: auto;
  font-size: 12px;
  color: var(--ink-3);
}
.nav .ndot {
  flex: none;
  width: 7px;
  height: 7px;
  margin-left: auto;
  margin-right: 4px;
  border-radius: 50%;
  background: var(--primary);
}
/* The balls in a card's head are balls, not its second line (.sheet .top
   span sets that line's size and color). */
.sheet .top .ball {
  display: inline-grid;
  margin: 0;
  color: #fff;
  font-size: 13px;
  font-weight: 600;
}
.sheet .top .ball.big {
  font-size: 16px;
}
.sheet .lan-mark .ball {
  font-size: 0;
}
/* A long card (分享给 open, a picker) scrolls inside the window. */
.win.full .sheet {
  max-height: calc(100% - 108px);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
}
.win.full .sheet::-webkit-scrollbar {
  display: none;
}
/* A device's second line while it is held over somewhere it can go: what
   letting go does, in blue (§6.4). */
.dev .name small.go {
  color: var(--primary);
}
/* The word beside a device held over the sidebar (我的设备 → a LAN's row). */
.drag-layer .dnote {
  left: 0;
  transform: translateY(-50%);
  opacity: 0;
  z-index: 41;
}
.inv-foot {
  gap: 8px;
}

/* console.css */
/* The deployment's console (DESIGN.md §14.15): a column of white cards in
   the canvas, as the first page's (welcome.css); lists of people and
   devices with balls and tiles; the window's own card on the right for one
   of them. The page is white, as every page is; the column starts where
   the title does (28 from the left), as the relays page's wells do; with
   the card open it narrows, so that the card covers none of it. */
.cons {
  position: absolute;
  inset: 0;
  overflow: auto;
  padding: 20px 24px 72px 28px;
  box-sizing: border-box;
}
.cons-col {
  width: 760px;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  gap: 16px;
  transition: max-width 0.24s cubic-bezier(0.3, 0.3, 0.2, 1);
}
/* The card is 340 wide, 20 from the right; 20 more between it and the
   column. */
.cons.carded .cons-col {
  max-width: calc(100% + 24px - 380px);
}
.cons-card {
  box-sizing: border-box;
  padding: 18px 22px;
  border-radius: 16px;
  background: var(--bg);
  box-shadow: 0 0 0 1px var(--line), 0 8px 24px rgba(9, 9, 11, 0.05), 0 1px 3px rgba(9, 9, 11, 0.04);
}
[data-theme='dark'] .cons-card {
  background: var(--well);
  box-shadow: 0 0 0 1px var(--line), 0 12px 30px rgba(0, 0, 0, 0.35);
}
.cons-h {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0 0 6px;
  font-size: 14px;
  font-weight: 600;
}
.cons-hint {
  font-size: 12px;
  font-weight: 400;
  color: var(--ink-3);
}
.cons-quiet {
  font-size: 12.5px;
  color: var(--ink-3);
}
.cons-quiet.center,
.center {
  text-align: left;
}
.cons-empty {
  margin: 0;
  padding: 26px 0;
  text-align: center;
  font-size: 13.5px;
  color: var(--ink-3);
}
.cons button {
  font: inherit;
}
.cons-link {
  flex: none;
  border: 0;
  padding: 0;
  background: none;
  font-size: 13px;
  color: var(--primary);
  cursor: pointer;
  white-space: nowrap;
}
.cons-link:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.cons-link.danger {
  color: #ef4444;
}
.cons-link.quiet {
  color: var(--ink-3);
}

/* Dots: green all well, amber tight, red broken. */
.cons-dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ok);
}
.cons-dot.warn {
  background: #f59e0b;
}
.cons-dot.bad {
  background: #ef4444;
}
.cons-dot.ok {
  background: var(--ok);
}

/* 要看的事 */
.cons-alert {
  display: grid;
  grid-template-columns: 8px 1fr auto;
  gap: 12px;
  align-items: start;
  padding: 11px 0;
}
.cons-alert + .cons-alert {
  box-shadow: 0 -1px 0 var(--line);
}
.cons-alert .cons-dot {
  margin-top: 7px;
}
.cons-at-title {
  font-size: 14px;
  font-weight: 500;
  line-height: 1.5;
}
.cons-at-text {
  margin-top: 1px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-2);
}
.cons-at-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  padding-top: 2px;
}
.cons-when {
  font-size: 12px;
  color: var(--ink-3);
  white-space: nowrap;
}
.cons-alert.done .cons-at-title {
  font-weight: 400;
  color: var(--ink-2);
}
.cons-quiet + .cons-recent,
.cons-alert + .cons-quiet {
  margin-top: 4px;
}
.cons-recent {
  overflow: hidden;
}
.cons-allok {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 4px;
  font-size: 14px;
  font-weight: 500;
}
.cons-okmark {
  display: inline-grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  color: #fff;
  background: var(--ok);
}
.cons-okmark.big {
  width: 40px;
  height: 40px;
}
.cons-okmark.big svg {
  width: 22px;
  height: 22px;
}

/* 服务器 */
.cons-row {
  display: grid;
  grid-template-columns: 8px 84px 1fr auto;
  gap: 12px;
  align-items: center;
  padding: 10px 0;
  font-size: 13.5px;
}
.cons-row + .cons-row,
.cons-backups + .cons-row {
  box-shadow: 0 -1px 0 var(--line);
}
.cons-k {
  color: var(--ink-2);
}
.cons-backups {
  overflow: hidden;
  margin: -2px 0 8px 104px;
}
.cons-bk {
  display: grid;
  grid-template-columns: 110px 1fr auto;
  gap: 10px;
  padding: 3px 0;
  font-size: 12.5px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.cons-bk-name {
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 12px;
  color: var(--ink-3);
}

/* 人和设备: four numbers */
.cons-nums {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  padding: 14px;
}
.cons-num {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px;
  border: 0;
  border-radius: 12px;
  background: none;
  color: inherit;
  text-align: left;
}
button.cons-num {
  cursor: pointer;
  transition: background 0.16s;
}
button.cons-num:hover {
  background: var(--well);
}
[data-theme='dark'] button.cons-num:hover {
  background: var(--well-2);
}
.cons-n {
  font-size: 13px;
  color: var(--ink-2);
}
.cons-n b {
  margin-right: 3px;
  font-size: 28px;
  font-weight: 600;
  letter-spacing: -0.3px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.cons-num small {
  font-size: 12px;
  color: var(--ink-3);
}

/* Finding: the field and the chips */
.cons-tools {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.cons-search {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 14px;
  border-radius: 999px;
  background: var(--bg);
  box-shadow: 0 0 0 1px var(--line-2);
  color: var(--ink-3);
  transition: box-shadow 0.16s;
}
[data-theme='dark'] .cons-search {
  background: var(--well);
}
.cons-search:focus-within {
  box-shadow: 0 0 0 1.5px var(--primary);
}
.cons-search input {
  flex: 1;
  min-width: 0;
  border: 0;
  outline: none;
  background: transparent;
  font: inherit;
  font-size: 14px;
  color: var(--ink);
}
.cons-search input::placeholder {
  color: var(--ink-3);
}
.cons-search input::-webkit-search-cancel-button {
  display: none;
}
.cons-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.cons-chip {
  height: 28px;
  padding: 0 12px;
  border: 0;
  border-radius: 999px;
  background: var(--well);
  color: var(--ink-2);
  font-size: 13px;
  cursor: pointer;
  transition: background 0.16s, color 0.16s;
}
[data-theme='dark'] .cons-chip {
  background: var(--well-2);
}
.cons-chip:hover {
  color: var(--ink);
}
.cons-chip.on {
  background: color-mix(in srgb, var(--primary) 14%, transparent);
  color: var(--primary);
  font-weight: 500;
}

/* The lists */
.cons-list {
  padding: 6px;
}
.cons-rows {
  overflow: hidden;
}
.cons-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 12px;
  border-radius: 12px;
  cursor: pointer;
  transition: background 0.14s;
}
.cons-item:hover {
  background: var(--well);
}
[data-theme='dark'] .cons-item:hover {
  background: var(--well-2);
}
.cons-main {
  flex: 1;
  min-width: 0;
}
.cons-name {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 500;
  line-height: 1.45;
}
.cons-sub {
  display: flex;
  align-items: center;
  gap: 6px;
  overflow: hidden;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-3);
  white-space: nowrap;
  text-overflow: ellipsis;
}
.cons-sub .ball {
  flex: none;
}
.cons-meta {
  font-size: 12.5px;
  color: var(--ink-3);
  white-space: nowrap;
}
.cons-state {
  min-width: 88px;
  font-size: 12.5px;
  color: var(--ink-3);
  text-align: right;
  white-space: nowrap;
}
.cons-state.on {
  color: var(--ok);
}
.cons-state.on::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin: 0 6px 1px 0;
  border-radius: 50%;
  background: var(--ok);
}
.cons-state.out {
  color: var(--ink-3);
}
.cons-tag {
  padding: 0 6px;
  border-radius: 6px;
  font-size: 11px;
  font-weight: 500;
  line-height: 18px;
  color: var(--primary);
  background: color-mix(in srgb, var(--primary) 12%, transparent);
}
.cons-tag.grey {
  color: var(--ink-2);
  background: var(--track);
}
.cons-tile {
  flex: none;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  color: var(--ink-2);
  background: var(--well);
}
[data-theme='dark'] .cons-tile {
  background: var(--well-2);
}
.cons-tile svg {
  fill: currentColor;
}
.cons-tile.big {
  width: 48px;
  height: 48px;
  border-radius: 13px;
}
.cons-tile.big svg {
  width: 26px;
  height: 26px;
}
.cons-more-box {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 32px;
}
.cons-more,
.cons-btn {
  height: 30px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.16s, color 0.16s, box-shadow 0.16s, transform 0.18s cubic-bezier(0.3, 1.5, 0.5, 1);
}
.cons-more {
  color: var(--ink);
  background: var(--bg);
  box-shadow: 0 0 0 1px var(--line-2);
}
[data-theme='dark'] .cons-more {
  background: var(--well);
}
.cons-btn {
  color: #fff;
  background: var(--primary);
}
.cons-btn:active,
.cons-more:active {
  transform: scale(0.96);
}
.cons-btn.ghost {
  color: var(--ink);
  background: var(--bg);
  box-shadow: 0 0 0 1px var(--line-2);
}
[data-theme='dark'] .cons-btn.ghost {
  background: var(--well-2);
}
.cons-btn.danger {
  color: #fff;
  background: #ef4444;
}
.cons-btn.ghost.danger {
  color: #ef4444;
  background: transparent;
  box-shadow: 0 0 0 1px color-mix(in srgb, #ef4444 45%, transparent);
}
.cons-btn:disabled {
  opacity: 0.45;
  cursor: default;
  transform: none;
}

/* 等着批准的登录 */
.cons-wait {
  overflow: hidden;
}
.cons-pick {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 2px 0 6px 48px;
  overflow: hidden;
}

/* The card on the right: the window's sheet, a little wider for a person
   and their devices, scrolling if the window is short. */
.sheet:has(> .cons-sheet) {
  width: 340px;
  max-height: calc(100% - 108px);
  overflow: auto;
}
.cons-sheet .top b {
  display: flex;
  align-items: center;
  gap: 6px;
}
.cons-sheet button {
  font: inherit;
}
.cons-dsub {
  margin-top: 2px;
  font-size: 12.5px;
  color: var(--ink-3);
}
.cons-owner {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
}
.cons-owner:hover {
  color: var(--ink);
}
.cons-back {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin: -4px 0 12px -4px;
  padding: 2px 6px 2px 2px;
  border: 0;
  border-radius: 8px;
  background: none;
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
}
.cons-back:hover {
  background: var(--well);
}
.cons-sec {
  margin-top: 12px;
  padding-top: 12px;
  box-shadow: 0 -1px 0 var(--line);
}
.cons-st {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 4px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
}
.cons-st .cons-link {
  font-size: 13px;
  font-weight: 400;
}
.cons-do {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding: 6px 0 4px;
}
.cons-do + .cons-do {
  margin-top: 6px;
}
.cons-why {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-3);
}
.cons-why.done {
  font-size: 13.5px;
  color: var(--ink-2);
}
.cons-pick[hidden],
.cons-recent[hidden],
.cons-backups[hidden] {
  display: none;
}
.cons-dev {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 -8px;
  padding: 5px 8px;
  border-radius: 10px;
  font-size: 13.5px;
  cursor: pointer;
}
.cons-dev:hover {
  background: var(--well);
}
[data-theme='dark'] .cons-dev:hover {
  background: var(--well-2);
}
.cons-dev .cons-tile {
  width: 30px;
  height: 30px;
  border-radius: 8px;
}
.cons-dev .cons-tile svg {
  width: 17px;
  height: 17px;
}
.cons-dev .cons-state {
  min-width: 0;
}
.cons-line {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 32px;
  font-size: 13.5px;
  line-height: 1.5;
}
.cons-line.quiet {
  color: var(--ink-3);
}
.cons-ask {
  display: flex;
  flex: 1;
  align-items: center;
  gap: 10px;
  margin: 2px -10px;
  padding: 6px 10px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--primary) 8%, transparent);
}
.cons-line + .cons-line {
  margin-top: 6px;
}
.cons-grow {
  flex: 1;
  min-width: 0;
}
.cons-grow.done {
  color: var(--ink-2);
}
.cons-step {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.cons-step button {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 50%;
  background: var(--well);
  color: var(--ink);
  font-size: 16px;
  cursor: pointer;
}
[data-theme='dark'] .cons-step button {
  background: var(--well-2);
}
.cons-step b {
  display: inline-block;
  min-width: 26px;
  text-align: center;
  font-size: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.cons-kv {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 4px 0;
  font-size: 13.5px;
}
.cons-kv span {
  color: var(--ink-2);
}
.cons-kv b {
  font-weight: 500;
  text-align: right;
}
.cons-kv b.cons-state {
  min-width: 0;
  font-size: 13.5px;
}
.mono {
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 12.5px;
}
.cons-danger {
  margin-top: 16px;
  padding-top: 14px;
  box-shadow: 0 -1px 0 var(--line);
}

/* 替人注销账号 */
.cons-del {
  padding: 24px 28px;
}
.cons-del-warn {
  margin: 0 0 16px;
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 13.5px;
  color: #b45309;
  background: rgba(245, 158, 11, 0.12);
}
[data-theme='dark'] .cons-del-warn {
  color: #fbbf24;
  background: rgba(245, 158, 11, 0.14);
}
.cons-del-list {
  margin: 4px 0 12px;
  padding-left: 18px;
  font-size: 13.5px;
  line-height: 1.9;
  color: var(--ink-2);
}
.cons-del-lan {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 2px 0 12px;
  font-size: 13.5px;
}
.cons-confirm {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 16px;
  font-size: 13px;
  color: var(--ink-2);
}
.cons-confirm input {
  height: 40px;
  padding: 0 12px;
  border: 0;
  border-radius: 10px;
  outline: none;
  background: var(--well);
  box-shadow: inset 0 0 0 1px var(--line-2);
  font: inherit;
  font-size: 14px;
  color: var(--ink);
}
[data-theme='dark'] .cons-confirm input {
  background: var(--well-2);
}
.cons-confirm input:focus {
  box-shadow: inset 0 0 0 1.5px var(--primary);
}
.cons-del-foot {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 18px;
}
.cons-del-foot .cons-btn {
  height: 36px;
  padding: 0 18px;
  font-size: 14px;
}
.cons-gone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 30px 0 26px;
  font-size: 13.5px;
}
.cons-gone b {
  font-size: 16px;
  font-weight: 600;
}

/* 记录 */
.cons-seg {
  align-self: flex-start;
  display: inline-flex;
  padding: 3px;
  border-radius: 999px;
  background: var(--well);
}
[data-theme='dark'] .cons-seg {
  background: var(--well-2);
}
.cons-seg button {
  height: 30px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-2);
  font-size: 13.5px;
  cursor: pointer;
  transition: background 0.18s, color 0.18s, box-shadow 0.18s;
}
.cons-seg button.on {
  color: var(--ink);
  font-weight: 500;
  background: var(--bg);
  box-shadow: 0 1px 3px rgba(9, 9, 11, 0.1), 0 0 0 1px var(--line);
}
[data-theme='dark'] .cons-seg button.on {
  background: var(--well);
}
.cons-pane {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.cons-recs {
  padding: 8px 18px 14px;
}
.cons-day {
  padding: 12px 0 4px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
}
.cons-rec {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
  font-size: 13.5px;
  line-height: 1.5;
}
.cons-time {
  flex: none;
  width: 40px;
  font-size: 12.5px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.cons-logcard {
  padding: 0;
  overflow: hidden;
}
.cons-earlier {
  display: block;
  margin: 10px auto 0;
}
.cons-earlier[hidden] {
  display: none;
}
.cons-cap {
  margin: 10px 0 0;
  text-align: center;
}
.cons-cap[hidden] {
  display: none;
}
/* A record done with deneb-control on the server: the command's mark in
   place of someone's ball. */
.cons-srv {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  color: var(--ink-2);
  background: var(--well);
}
[data-theme='dark'] .cons-srv {
  background: var(--well-2);
}
.cons-log {
  height: 440px;
  overflow: auto;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 28px);
  mask-image: linear-gradient(to bottom, transparent 0, #000 28px);
  padding: 10px 12px 12px;
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 12px;
  line-height: 1.75;
}
.cons-ln {
  display: flex;
  gap: 12px;
  padding: 0 6px;
  border-radius: 4px;
}
.cons-ln .t {
  flex: none;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.cons-ln .x {
  min-width: 0;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}
.cons-ln.k-alert .x {
  color: #b45309;
}
.cons-ln.k-error .x {
  color: #dc2626;
}
[data-theme='dark'] .cons-ln.k-alert .x {
  color: #fbbf24;
}
[data-theme='dark'] .cons-ln.k-error .x {
  color: #f87171;
}

/* The sidebar: 概况's red dot while an alert is on. */
.nav .adot {
  flex: none;
  width: 7px;
  height: 7px;
  margin-left: auto;
  margin-right: 4px;
  border-radius: 50%;
  background: #ef4444;
}
.nav .adot[hidden] {
  display: none;
}

/* join.css */
/* The invite page, the login card, the download card and the phone's dock
   (DESIGN.md §14.5–§14.7), on the desktop's tokens (tokens.css). Values not
   named in the desktop's code yet (shadows, radii, type sizes) are the
   design's, as design/demos/v3/v3.css has them. */

:root,
[data-theme='light'] {
  --shadow-sm: 0 1px 2px rgba(9, 9, 11, 0.06), 0 1px 1px rgba(9, 9, 11, 0.04);
  --shadow-md: 0 10px 28px rgba(9, 9, 11, 0.09), 0 2px 6px rgba(9, 9, 11, 0.05);
}
[data-theme='dark'] {
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.04);
  --shadow-md: 0 14px 34px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.06);
}
html,
body {
  margin: 0;
  height: 100%;
}
body {
  /* The login page's own: it fades out to it, and the page that comes
     fades in over it (§14.14). Every other page covers it. */
  background: var(--bg);
  color: var(--ink);
  font: var(--font-size, 13px) / 1.4 -apple-system, 'SF Pro Text', 'PingFang SC', 'Microsoft YaHei UI', 'Noto Sans SC', sans-serif;
  -webkit-font-smoothing: antialiased;
  font-feature-settings: 'tnum';
}
#app {
  height: 100%;
}
.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Pill buttons and glossy balls, as the desktop's. */
.join-page .btn,
.signin-page .btn,
.dl-card .btn,
.m-dock .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 34px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.18s cubic-bezier(0.3, 1.5, 0.5, 1), background 0.16s, box-shadow 0.16s, opacity 0.16s;
}
.join-page .btn:active,
.signin-page .btn:active,
.dl-card .btn:active,
.m-dock .btn:active {
  transform: scale(0.96);
}
.join-page .btn.primary,
.signin-page .btn.primary,
.dl-card .btn.primary,
.m-dock .btn.primary {
  color: #fff;
  background: var(--primary);
  box-shadow: 0 1px 2px rgba(47, 107, 255, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.join-page .btn.primary:hover,
.signin-page .btn.primary:hover,
.dl-card .btn.primary:hover,
.m-dock .btn.primary:hover {
  background: var(--primary-2);
}
.join-page .btn:disabled,
.signin-page .btn:disabled {
  opacity: 0.45;
  cursor: default;
  transform: none;
}
.dl-card .btn.ghost {
  color: var(--ink);
  background: var(--bg);
  box-shadow: inset 0 0 0 1px var(--line-2);
}
.join-page :focus-visible,
.signin-page :focus-visible,
.dl-card :focus-visible,
.m-dock :focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
.join-page .ball,
.dl-card .ball {
  position: relative;
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  background: radial-gradient(circle at 34% 28%, color-mix(in oklab, var(--c) 55%, white) 0%, var(--c) 52%, color-mix(in oklab, var(--c) 82%, black) 100%);
  box-shadow: inset 0 -1.5px 3px rgba(0, 0, 0, 0.14), 0 2px 6px color-mix(in srgb, var(--c) 30%, transparent);
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.18);
}

/* ---- The invite page and the login (§14.5) ---- */
.join-page {
  position: relative;
  min-height: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 72px 16px 48px;
  background: var(--well);
}
.join-page .brand {
  position: absolute;
  left: 28px;
  top: 22px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 15px;
  font-weight: 600;
}
.join-page .brand svg {
  color: var(--primary);
}
.join-card {
  position: relative;
  width: 440px;
  max-width: 100%;
  box-sizing: border-box;
  border-radius: 20px;
  background: var(--bg);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}
.jc-in {
  padding: 22px 22px 20px;
}
.jc-head {
  display: flex;
  align-items: center;
  gap: 14px;
}
.jc-head .ball,
.jc-mark {
  width: 44px;
  height: 44px;
  font-size: 17px;
  flex: none;
}
.jc-mark {
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: linear-gradient(180deg, color-mix(in srgb, var(--primary) 82%, #fff), color-mix(in srgb, var(--primary) 92%, #000));
  box-shadow: 0 6px 14px color-mix(in srgb, var(--primary) 30%, transparent);
}
.jc-title {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  line-height: 1.35;
}
.jc-sub {
  margin: 3px 0 0;
  font-size: 13px;
  color: var(--ink-2);
}
.jc-form {
  margin: 0;
}
.jc-foot {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 10px;
  margin-top: 20px;
}
.jc-foot .hint {
  margin-right: auto;
  margin-left: 58px;
  font-size: 12px;
  color: var(--ink-3);
}
.jc-foot .hint .link {
  border: 0;
  padding: 0;
  background: none;
  font: inherit;
  color: var(--primary);
  cursor: pointer;
}
.jc-error {
  min-height: 0;
  margin: 8px 0 0 58px;
  font-size: 12px;
  color: #ef4444;
}
.jc-error.ok {
  display: flex;
  align-items: center;
  gap: 5px;
  color: var(--ok);
  font-weight: 500;
}
.jc-error.tip {
  color: var(--ink-3);
}
.jc-error.wait {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--ink-2);
}
.signin .jc-error.wait {
  justify-content: center;
}
.jc-error:empty {
  display: none;
}
.code-boxes.checking .cb {
  opacity: 0.6;
  transition: opacity 0.16s ease-out;
}
.jc-hint {
  margin: 10px 0 0 58px;
  font-size: 12px;
  color: var(--ink-3);
}
.jc-hint:empty {
  display: none;
}
.jc-hint .link {
  margin-left: 0;
}
.jc-hint.bad {
  color: #ef4444;
}
.join-page .link,
.signin-page .link {
  border: 0;
  padding: 0;
  margin-left: 4px;
  background: none;
  font: inherit;
  color: var(--primary);
  cursor: pointer;
}
.join-page .link:hover,
.signin-page .link:hover {
  text-decoration: underline;
  text-underline-offset: 2px;
}
.code-boxes.ok .cb,
.code-boxes.ok .cb.at,
.code-boxes.ok .cb:focus {
  background: var(--bg);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--ok) 70%, transparent);
}
/* The button's spinner while the code goes out. */
.spin {
  width: 14px;
  height: 14px;
  box-sizing: border-box;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
  animation: spin 0.8s linear infinite;
}
.spin.grey {
  width: 12px;
  height: 12px;
  border-width: 1.6px;
  border-color: color-mix(in srgb, var(--ink-3) 45%, transparent);
  border-top-color: var(--ink-2);
}
.jc-hint .spin.grey {
  display: inline-block;
  vertical-align: -2px;
  margin-right: 5px;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
.join-note {
  max-width: 440px;
  margin: 0;
  font-size: 13px;
  color: var(--ink-2);
  text-align: center;
}
.field {
  display: flex;
  align-items: center;
  height: 44px;
  margin: 18px 0 0 58px;
  padding: 0 14px;
  border-radius: 12px;
  background: var(--well);
  box-shadow: inset 0 0 0 1px transparent;
  transition: box-shadow 0.16s ease-out, background-color 0.16s ease-out;
}
.field:focus-within {
  background: var(--bg);
  box-shadow: inset 0 0 0 1.5px var(--primary), 0 0 0 4px color-mix(in srgb, var(--primary) 14%, transparent);
}
.field input {
  flex: 1;
  min-width: 0;
  border: 0;
  outline: 0;
  padding: 0;
  background: transparent;
  font: inherit;
  font-size: 15px;
  color: var(--ink);
  caret-color: var(--primary);
}
.field input::placeholder {
  color: var(--ink-3);
}
.join-page .field :focus-visible,
.signin-page .field :focus-visible {
  outline: 0;
}
.code-boxes {
  display: flex;
  gap: 8px;
  margin: 18px 0 0 58px;
}
.code-boxes .cb {
  width: 44px;
  height: 52px;
  box-sizing: border-box;
  border: 0;
  border-radius: 12px;
  background: var(--well);
  box-shadow: inset 0 0 0 1px transparent;
  text-align: center;
  font: inherit;
  font-size: 22px;
  font-weight: 600;
  color: var(--ink);
  caret-color: transparent;
  outline: 0;
  transition: box-shadow 0.16s ease-out, background-color 0.16s ease-out;
}
.code-boxes .cb.at,
.code-boxes .cb:focus {
  background: var(--bg);
  box-shadow: inset 0 0 0 1.5px var(--primary), 0 0 0 4px color-mix(in srgb, var(--primary) 14%, transparent);
}
.jc-joined {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 26px 22px 24px;
  text-align: center;
}
.jc-joined .pair {
  display: flex;
}
.jc-joined .pair .ball {
  font-size: 18px;
  box-shadow: 0 0 0 3px var(--bg), inset 0 -2px 4px rgba(0, 0, 0, 0.14);
}
.jc-joined .pair .ball + .ball {
  margin-left: -8px;
}

/* ---- The download card (§14.7), inside the device card's frame ---- */
.dl-card .top {
  display: flex;
  align-items: center;
  gap: 12px;
}
.dl-card .top b {
  display: block;
  font-size: 15px;
  font-weight: 600;
}
.dl-card .top span {
  display: block;
  margin-top: 1px;
  font-size: 12px;
  color: var(--ink-2);
}
.dl-card .sheet-close {
  margin-left: auto;
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 999px;
  background: var(--well);
  color: var(--ink-2);
  cursor: pointer;
}
.dl-mark {
  width: 40px;
  height: 40px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  flex: none;
  background: linear-gradient(180deg, color-mix(in srgb, var(--primary) 82%, #fff), color-mix(in srgb, var(--primary) 92%, #000));
  box-shadow: 0 6px 14px color-mix(in srgb, var(--primary) 30%, transparent), 0 1px 2px rgba(0, 0, 0, 0.1);
}
.dl-text {
  margin: 14px 2px 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-2);
}
.dl-buttons {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 16px;
}
.dl-buttons .dl-btn {
  width: 100%;
  box-sizing: border-box;
}
.dl-more {
  display: block;
  margin: 2px auto 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: 12px;
  color: var(--ink-3);
  cursor: pointer;
}
.dl-after {
  margin: 14px 2px 0;
  padding: 10px 12px;
  border-radius: 14px;
  background: var(--well);
  font-size: 12px;
  line-height: 1.55;
  color: var(--ink-2);
}

/* ---- The phone's dock (§14.6) ---- */
.m-dock {
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 56px;
  padding: 0 8px 0 18px;
  border-radius: 999px;
  background: var(--bg);
  box-shadow: var(--shadow-md);
  font-size: 13px;
  color: var(--ink-2);
  z-index: 20;
}
.m-dock-text {
  flex: 1;
  min-width: 0;
  font-size: 12px;
  line-height: 1.4;
}
.m-dock .btn {
  flex: none;
  min-width: 104px;
}

/* ---- Phones ---- */
@media (max-width: 767px) {
  .join-page {
    justify-content: flex-start;
    padding-top: 120px;
  }
  .join-page .brand {
    left: 22px;
    top: 18px;
  }
  .jc-in {
    padding: 20px 18px 18px;
  }
  .field,
  .code-boxes,
  .jc-error,
  .jc-hint {
    margin-left: 0;
  }
  .jc-foot .hint {
    margin-left: 0;
  }
  .code-boxes {
    justify-content: space-between;
    gap: 6px;
  }
  .join-note {
    max-width: 300px;
  }
}

/* ---- The stand-in LAN page, until the canvas module registers its own ---- */
.standin {
  position: relative;
  min-height: 100%;
  box-sizing: border-box;
  padding: 28px;
  background: var(--bg);
}
.standin h1 {
  margin: 0;
  font-size: 20px;
}
.standin header p {
  margin: 4px 0 0;
  color: var(--ink-2);
}
.standin-devs {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 24px 0 0;
  padding: 0;
  list-style: none;
}
.standin-devs li {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 12px 14px;
  border-radius: 14px;
  background: var(--well);
}
.standin-devs small {
  color: var(--ink-2);
}
.standin-slot {
  box-shadow: inset 0 0 0 1.5px var(--primary);
}
.standin-sheet {
  position: absolute;
  top: 24px;
  right: 24px;
  width: 300px;
  padding: 16px;
  border-radius: 20px;
  background: var(--bg);
  box-shadow: var(--shadow-md);
}
/* The members' balls under the invite's head (§14.5). */
.jc-stack {
  display: flex;
  margin: 14px 0 0 58px;
}
.jc-stack .ball {
  width: 26px;
  height: 26px;
  font-size: 11px;
  margin-left: -5px;
  box-shadow: 0 0 0 2px var(--bg), inset 0 -1.5px 3px rgba(0, 0, 0, 0.14);
}
.jc-stack .ball:first-child {
  margin-left: 0;
}

/* ---- The login page (§14.14): a column in the middle, as the desktop's
   sign-in (§7.3); the app's icon over it, its sky's light round it. ---- */
.signin-page {
  position: relative;
  min-height: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: max(64px, 16vh) 24px 96px;
  background: var(--bg);
  overflow: hidden;
}
.signin-page::before {
  content: '';
  position: absolute;
  left: 50%;
  top: calc(max(64px, 16vh) - 170px);
  width: 640px;
  height: 400px;
  transform: translateX(-50%);
  background: radial-gradient(closest-side, rgba(79, 134, 255, 0.13), rgba(79, 134, 255, 0.05) 55%, transparent);
  pointer-events: none;
}
[data-theme='dark'] .signin-page::before {
  background: radial-gradient(closest-side, rgba(79, 134, 255, 0.2), rgba(79, 134, 255, 0.07) 55%, transparent);
}
.signin-page .brand {
  position: absolute;
  left: 28px;
  top: 22px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 15px;
  font-weight: 600;
}
.signin-page .brand svg {
  color: var(--primary);
}
.signin {
  position: relative;
  width: 360px;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.si-icon {
  width: 84px;
  height: 84px;
  margin-bottom: 18px;
}
.si-icon img,
.wc-icon img {
  display: block;
  width: 100%;
  height: 100%;
  user-select: none;
}
.si-step {
  position: relative;
  width: 100%;
}
.si-out {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  pointer-events: none;
}
.si-title {
  margin: 0;
  font-size: 24px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0.2px;
}
.si-sub {
  margin: 8px 0 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-2);
}
.signin .field {
  height: 48px;
  margin: 28px 0 0;
  padding: 0 16px;
  border-radius: 12px;
}
.signin .field input {
  font-size: 15px;
  text-align: left;
}
.signin .jc-error {
  margin: 10px 0 0;
  justify-content: center;
  font-size: 13px;
}
.signin .jc-hint {
  margin: 14px 0 0;
  font-size: 13px;
}
.signin .jc-foot {
  margin-top: 12px;
}
.signin .btn.primary {
  width: 100%;
  height: 48px;
  font-size: 15px;
  font-weight: 600;
  gap: 8px;
}
.signin .btn.primary:disabled {
  opacity: 0.4;
}
.signin .btn.primary.sending:disabled,
.join-page .btn.primary.sending:disabled {
  opacity: 1;
  cursor: progress;
}
/* The login link's page (login-link.md): the question, then the button,
   which ticks once in. */
.signin .ll-foot {
  margin-top: 28px;
}
.signin .btn.primary.done:disabled {
  cursor: default;
}
.signin .ll-wait {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin: 0;
}
.signin .code-boxes {
  justify-content: center;
  gap: 10px;
  margin: 28px 0 0;
}
.signin .code-boxes .cb {
  width: 48px;
  height: 56px;
  font-size: 22px;
}
.signin .join-gone {
  margin: -8px 0 18px;
}
.si-foot {
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: 28px;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 4px 14px;
  font-size: 13px;
  color: var(--ink-3);
  text-align: center;
}
.si-foot a {
  color: var(--ink-2);
  text-decoration: none;
}
.si-foot a:hover {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}
@media (max-width: 767px) {
  .signin-page {
    padding-top: 64px;
  }
  /* The icon is the mark here: none in the corner over it. */
  .signin-page .brand {
    display: none;
  }
  .si-icon {
    width: 72px;
    height: 72px;
    margin-bottom: 16px;
  }
  .signin .code-boxes {
    gap: 8px;
  }
  .signin .code-boxes .cb {
    width: 44px;
    height: 54px;
  }
  .si-foot {
    position: static;
    margin-top: 48px;
  }
}

/* phone.css */
/* A LAN on a phone (DESIGN §14.6), as design/demos/web/web.css has it. */
/* The LAN on a phone: a list, by person; a card rises from the bottom. */
.m-lan {
  position: fixed;
  inset: 0;
  overflow: auto;
  background: var(--well);
  padding-top: env(safe-area-inset-top);
}
.m-head {
  display: flex;
  align-items: center;
  padding: 14px 20px 0;
}
.m-title {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 22px;
  font-weight: 600;
}
.m-title svg {
  color: var(--ink-3);
  transform: rotate(90deg);
}
.m-head .stack {
  margin-left: auto;
}
.m-sub {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 4px 20px 0;
  font-size: 13px;
  color: var(--ink-2);
}
.m-list {
  position: absolute;
  inset: 76px 0 0 0;
  padding: 6px 16px 120px;
}
.m-gh {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 14px 4px 8px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
}
.m-gh .ball {
  width: 22px;
  height: 22px;
  font-size: 10px;
}
.m-card {
  border-radius: 20px;
  background: var(--bg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.m-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 14px;
  height: 66px;
  padding: 0 16px;
  cursor: pointer;
  transition: background 0.16s ease-out;
}
.m-row + .m-row::before {
  content: '';
  position: absolute;
  left: 70px;
  right: 0;
  top: 0;
  height: 1px;
  background: var(--line);
}
.m-row:active {
  background: var(--well);
}
.m-row .tile-m {
  position: relative;
  flex: none;
  width: 40px;
  height: 40px;
}
.m-row .tile-m .tile {
  border-radius: 12px;
}
.m-row .tile-m .tile::before {
  left: 6px;
  top: 3px;
  width: 20px;
  height: 9px;
}
.m-row b {
  display: block;
  font-size: 15px;
  font-weight: 500;
}
.m-row small {
  display: block;
  margin-top: 2px;
  font-size: 13px;
  color: var(--ink-2);
}
.m-row.pending .tile {
  background: none;
  box-shadow: none;
}
.m-row.pending .tile::before {
  display: none;
}
.m-row.pending .tile svg {
  fill: color-mix(in srgb, var(--c) 55%, transparent);
  filter: none;
}
.m-row.pending .tile svg.dash {
  position: absolute;
  inset: 0;
  fill: none;
  color: var(--c);
}
.m-scrim {
  position: absolute;
  inset: 0;
  background: rgba(9, 9, 11, 0.24);
  opacity: 0;
  pointer-events: none;
  z-index: 40;
}
.m-scrim.on {
  pointer-events: auto;
}
.m-lan .sheet.m-sheet {
  position: absolute;
  left: 0;
  right: 0;
  top: auto;
  bottom: 0;
  width: auto;
  max-height: none;
  border-radius: 20px 20px 0 0;
  padding-bottom: 34px;
  z-index: 50;
}

.m-lan .m-title {
  border: 0;
  background: none;
  padding: 0;
  color: var(--ink);
  font: inherit;
  font-size: 22px;
  font-weight: 600;
  cursor: pointer;
}
.m-lan .m-list {
  position: static;
  padding: 6px 16px 130px;
}
.m-lan .m-row .tile svg:not(.dash) {
  position: relative;
}
.m-lan .m-row em {
  margin-left: auto;
  font-style: normal;
  font-size: 13px;
  color: var(--ink-3);
}
.m-lan .m-dock {
  position: fixed;
}
.m-lan .sheet.m-sheet {
  position: fixed;
}
.m-lan .m-scrim {
  position: fixed;
}
.m-lan-row {
  width: 100%;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
}
.m-lan-row svg {
  margin-left: auto;
  color: var(--primary);
}

/* relays.css */
/* The relays pages (DESIGN.md §14.8, §14.12), from design/demos/web/
   webrelays.css: the wells of scene 4's console, a relay as the desktop's
   white glossy ball; the share bar (M4-11), the LAN chips on a cell and the
   capsule that goes with the hand (M4-12), the three buttons in the card.
   Under .relays-page (the wells; the deployment's page too) and
   .relays-card (its cards, which live in the window's card layer). */
.relays-page .rwell {
  position: absolute;
  top: 20px;
  box-sizing: border-box;
  border-radius: 20px;
  background: var(--well);
  padding: 14px 14px 16px;
  overflow: hidden;
}
.relays-page .rwell.mine {
  left: 28px;
  width: 400px;
}
.relays-page .rwell.pub {
  left: 448px;
  width: 172px;
}
.relays-page .rwell.ops {
  left: 28px;
  width: 592px;
}
.relays-page .card-label {
  display: flex;
  justify-content: space-between;
  margin: 0 4px 12px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
}
.relays-page .rgrid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  align-items: start;
  row-gap: 10px;
  column-gap: 6px;
}
.relays-page .rwell.pub .rgrid {
  grid-template-columns: 1fr;
}
.relays-page .rwell.ops .rgrid {
  grid-template-columns: repeat(4, 1fr);
}
.relays-page .rcell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 10px 6px 10px;
  border-radius: 16px;
  font-size: 13px;
  font-weight: 500;
  text-align: center;
  cursor: pointer;
  user-select: none;
  outline: none;
  transition: background 0.16s ease-out, box-shadow 0.16s ease-out, opacity 0.16s ease-out;
}
.relays-page .rcell:hover {
  background: var(--well-2);
}
/* Something in the hand: the cells it passes over do not light up. */
.carrying .relays-page .rcell:not(.sel):hover {
  background: transparent;
}
.relays-page .rcell:focus-visible {
  box-shadow: 0 0 0 2px var(--primary);
}
.relays-page .rcell.sel {
  background: var(--bg);
  box-shadow: var(--shadow-sm);
}
/* The cell whose relay is in the hand: a faint shadow of itself. */
.relays-page .rcell.ghost {
  opacity: 0.35;
}
.relays-page .rcell small {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  font-weight: 400;
  color: var(--ink-2);
}
.relays-page .rcell small.none {
  margin-top: 0;
  line-height: 1.45;
  color: var(--ink-3);
}
.relays-page .rcell.add-cell {
  color: var(--ink-2);
  font-weight: 400;
}
:is(.relays-page, .relays-card, .rpill) .orb {
  position: relative;
  width: 44px;
  height: 44px;
  flex: none;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: var(--ink-2);
  background: radial-gradient(circle at 34% 28%, var(--ball-hi) 0%, var(--ball-mid) 52%, var(--ball-lo) 100%);
  box-shadow: inset 0 -1.5px 3px rgba(0, 0, 0, 0.08), 0 6px 14px rgba(9, 9, 11, 0.12), 0 1px 2px rgba(9, 9, 11, 0.1);
}
:is(.relays-page, .relays-card, .rpill) .orb svg {
  fill: currentColor;
}
:is(.relays-page, .relays-card) .orb .on {
  position: absolute;
  right: 1px;
  bottom: 1px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 0 2px var(--well);
  transition: background 0.16s ease-out;
}
:is(.relays-page, .relays-card) .orb .on.busy {
  background: #f59e0b;
}
:is(.relays-page, .relays-card) .orb .on.off {
  background: var(--ink-3);
}
.relays-page .rcell.sel .orb .on,
.relays-card .orb .on {
  box-shadow: 0 0 0 2px var(--bg);
}
:is(.relays-page, .relays-card) .orb.add {
  background: none;
  box-shadow: none;
  color: var(--ink-3);
}
:is(.relays-page, .relays-card) .orb.add svg {
  fill: none;
}
:is(.relays-page, .relays-card) .orb.add .ring {
  position: absolute;
  inset: 0;
}
:is(.relays-page, .relays-card) .orb.wait .ring {
  animation: relays-breathe 1.2s ease-in-out infinite alternate;
}
@keyframes relays-breathe {
  from {
    opacity: 1;
  }
  to {
    opacity: 0.45;
  }
}
:is(.relays-page, .relays-card) .say {
  margin: 10px 2px 0;
  font-size: 12px;
  line-height: 1.55;
  color: var(--ink-2);
}

/* ---- The LANs a relay is in: small chips under its name, as the sidebar's rows ---- */
.relays-page .lchips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px;
}
.relays-page .lchip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 22px;
  padding: 0 8px 0 6px;
  border-radius: 999px;
  background: var(--bg);
  box-shadow: 0 0 0 1px var(--line);
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-2);
  white-space: nowrap;
  cursor: grab;
  transition: opacity 0.16s ease-out;
}
.relays-page .lchip.ghost {
  opacity: 0.3;
}
:is(.relays-page, .relays-card, .rpill) .mdots {
  display: flex;
  flex: none;
}
.relays-page .lchip .mdots {
  padding-right: 3px;
}
:is(.relays-page, .relays-card, .rpill) .mdots .ball {
  width: 8px;
  height: 8px;
  margin-right: -3px;
  box-shadow: 0 0 0 1.5px var(--bg);
}

/* ---- What goes with the hand: the relay as a capsule, and what letting go does ---- */
.rpill {
  position: absolute;
  z-index: 40;
  transform: translate(-50%, -50%) rotate(-2deg);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 14px 0 4px;
  border-radius: 999px;
  background: var(--bg);
  box-shadow: var(--shadow-md), 0 0 0 1px var(--line);
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  pointer-events: none;
}
.rpill .orb {
  width: 32px;
  height: 32px;
}
.rpill.lan {
  height: 30px;
  padding: 0 12px 0 10px;
  gap: 7px;
  font-size: 12px;
}

/* ---- The share bar: how many devices go first to which relay ---------------------------- */
/* Its own block formatting context: the same height clipped or not (it is
   clipped while it opens). */
.relays-page .wbar-slot {
  display: flow-root;
}
.relays-page .wbar-wrap {
  margin: 0 2px 14px;
}
.relays-page .wbar {
  position: relative;
  height: 38px;
}
.relays-page .wseg {
  position: absolute;
  top: 0;
  height: 38px;
  box-sizing: border-box;
  border-radius: 12px;
  background: var(--bg);
  box-shadow: var(--shadow-sm), 0 0 0 1px var(--line);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  overflow: hidden;
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
  color: var(--ink);
}
.relays-page .wseg .pct {
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
  font-weight: 400;
}
/* A standby relay: dashed, at the bar's end, takes no share. */
.relays-page .wseg.spare {
  background: transparent;
  box-shadow: none;
  border: 1.5px dashed color-mix(in srgb, var(--ink) 22%, transparent);
  color: var(--ink-3);
  font-weight: 400;
}
.relays-page .whandle {
  position: absolute;
  top: 0;
  width: 14px;
  height: 38px;
  margin-left: -7px;
  cursor: col-resize;
  display: grid;
  place-items: center;
  touch-action: none;
}
.relays-page .whandle i {
  width: 4px;
  height: 18px;
  border-radius: 2px;
  background: var(--ink-3);
  opacity: 0.55;
  transition: background 0.14s ease-out, opacity 0.14s ease-out, height 0.14s ease-out;
}
.relays-page .whandle:hover i,
.relays-page .whandle.held i {
  background: var(--primary);
  opacity: 1;
  height: 24px;
}
/* A segment too narrow for its name: the name over it, on hover. */
.relays-page .wtip {
  position: absolute;
  bottom: calc(100% + 6px);
  transform: translateX(-50%);
  padding: 4px 9px;
  border-radius: 8px;
  background: var(--bg);
  box-shadow: var(--shadow-md), 0 0 0 1px var(--line);
  font-size: 12px;
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.14s ease-out;
}
.relays-page .wtip.on {
  opacity: 1;
}
.relays-page .wsay {
  margin: 10px 4px 0;
  font-size: 12px;
  line-height: 1.55;
  color: var(--ink-3);
}

/* ---- The card ----------------------------------------------------------------- */
.relays-card .orb-s {
  position: relative;
  flex: none;
  width: 40px;
  height: 40px;
}
.relays-card .orb-s .orb {
  width: 40px;
  height: 40px;
}
.relays-card .num {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}
.relays-card .seg {
  display: flex;
  gap: 4px;
  padding: 3px;
  border-radius: 12px;
  background: var(--well);
}
.relays-card .seg button {
  flex: 1;
  height: 30px;
  border: 0;
  border-radius: 9px;
  background: transparent;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
  cursor: pointer;
  transition: background 0.16s ease-out, color 0.16s ease-out, box-shadow 0.16s ease-out;
}
.relays-card .seg button:hover {
  color: var(--ink);
}
.relays-card .seg button:disabled {
  opacity: 0.4;
  cursor: default;
}
.relays-card .seg button.on {
  background: var(--bg);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}
.relays-card .lan-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.relays-card .lan-row .lchip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 30px;
  padding: 0 6px 0 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink);
  background: var(--well);
  white-space: nowrap;
}
.relays-card .lan-row .lchip .mdots {
  padding-right: 3px;
}
.relays-card .lan-row .lchip .x {
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  margin-left: 1px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
}
.relays-card .lan-row .lchip .x:hover {
  background: var(--well-2);
  color: var(--ink);
}
.relays-card .lan-row .lchip.add {
  padding: 0 12px 0 8px;
  background: transparent;
  color: var(--ink-3);
  border: 1.5px dashed color-mix(in srgb, var(--ink) 22%, transparent);
  font: inherit;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
}
.relays-card .lan-row .lchip.add.pick {
  padding: 0 12px 0 10px;
  color: var(--ink);
}
.relays-card .chip .gb {
  margin-left: 2px;
  font-size: 12px;
  font-weight: 400;
  color: var(--ink-3);
}
.relays-card .cmd {
  margin: 2px 0 0;
  padding: 10px 12px;
  border-radius: 14px;
  background: var(--well);
  font: 12px/1.55 ui-monospace, 'SF Mono', Menlo, monospace;
  color: var(--ink);
  word-break: break-all;
  user-select: all;
}
.relays-card .cmd-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
}
.relays-card .cmd-foot .hint {
  margin: 0;
  flex: 1;
}
.relays-card .cmd-foot .btn {
  flex: none;
  min-width: 84px;
  justify-content: center;
}
.relays-card .rows .mdots {
  width: 18px;
}
/* Myself among who uses it most: there, but no one to turn away. */
.relays-card .chip:disabled {
  color: var(--ink);
  cursor: default;
  transform: none;
}

/* welcome.css */
/* A new account's first page (DESIGN.md §14.14): two cards in the middle
   of the canvas, as the device card draws one (white, rounded 16, a fine
   line, a small shadow). */
.welcome {
  position: absolute;
  inset: 0;
  overflow: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: max(40px, 9vh) 24px 64px;
  box-sizing: border-box;
}
.wc-card {
  width: 560px;
  max-width: 100%;
  box-sizing: border-box;
  overflow: hidden;
  padding: 22px 24px 22px;
  border-radius: 16px;
  background: var(--bg);
  box-shadow: 0 0 0 1px var(--line), 0 8px 24px rgba(9, 9, 11, 0.06), 0 1px 3px rgba(9, 9, 11, 0.04);
}
[data-theme='dark'] .wc-card {
  background: var(--well);
  box-shadow: 0 0 0 1px var(--line), 0 12px 30px rgba(0, 0, 0, 0.35);
}
.wc-top {
  display: flex;
  align-items: center;
  gap: 14px;
}
.wc-icon {
  flex: none;
  width: 46px;
  height: 46px;
  margin: -3px;
}
.wc-title {
  flex: 1;
  min-width: 0;
}
.wc-h {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.35;
}
.wc-sub {
  margin: 3px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-2);
}
.wc-tick {
  flex: none;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  color: #fff;
  background: var(--ok);
}
.wc-devs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
  margin: 14px 0 0 54px;
  font-size: 13px;
  font-weight: 500;
}
.wc-dev {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.wc-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--offline-grey);
}
.wc-dot.on {
  background: var(--ok);
}
.wc-done-words {
  color: var(--ink-2);
  font-weight: 400;
}
.wc-buttons {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 10px;
  margin: 18px 0 0 54px;
}
.welcome .btn.wc-dl {
  padding: 0 13px;
}
.welcome .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 36px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.18s cubic-bezier(0.3, 1.5, 0.5, 1), background 0.16s, box-shadow 0.16s, opacity 0.16s;
}
.welcome .btn:active {
  transform: scale(0.96);
}
.welcome .btn.primary {
  color: #fff;
  background: var(--primary);
  box-shadow: 0 1px 2px rgba(47, 107, 255, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.welcome .btn.primary:hover {
  background: var(--primary-2);
}
.welcome .btn.ghost {
  color: var(--ink);
  background: var(--bg);
  box-shadow: inset 0 0 0 1px var(--line-2);
}
.welcome .btn:disabled {
  opacity: 0.4;
  cursor: default;
  transform: none;
}
.wc-more {
  border: 0;
  padding: 0;
  background: none;
  font: inherit;
  font-size: 12px;
  color: var(--ink-3);
  cursor: pointer;
}
.wc-more:hover {
  color: var(--ink-2);
}
.wc-after {
  box-sizing: border-box;
  overflow: hidden;
  margin: 14px 0 0 54px;
  padding: 10px 12px;
  border-radius: 12px;
  background: var(--well);
  font-size: 12px;
  line-height: 1.55;
  color: var(--ink-2);
}
[data-theme='dark'] .wc-after {
  background: var(--well-2);
}
.wc-lan .wc-h {
  margin-bottom: 14px;
}
.wc-ways {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.wc-way {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  min-height: 112px;
  box-sizing: border-box;
  padding: 16px;
  border: 0;
  border-radius: 14px;
  background: var(--well);
  font: inherit;
  text-align: left;
  color: var(--ink);
  cursor: pointer;
  transition: box-shadow 0.16s ease-out, background-color 0.16s ease-out, transform 0.18s cubic-bezier(0.3, 1.5, 0.5, 1);
}
[data-theme='dark'] .wc-way {
  background: var(--well-2);
}
.wc-way:hover {
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--primary) 55%, transparent);
}
.wc-way:active {
  transform: scale(0.985);
}
.wc-way:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
.wc-way b {
  font-size: 14px;
  font-weight: 600;
}
.wc-way-sub {
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-2);
}
.wc-way-ico {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  margin-bottom: 6px;
  border-radius: 10px;
  color: var(--primary);
  background: var(--bg);
  box-shadow: 0 1px 2px rgba(9, 9, 11, 0.06);
}
.wc-way.busy {
  cursor: progress;
  opacity: 0.7;
}
.wc-way.open {
  cursor: default;
  justify-content: center;
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--primary) 55%, transparent);
}
.wc-way.open:active {
  transform: none;
}
.wc-join {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  margin: 0;
}
.welcome .field {
  display: flex;
  align-items: center;
  height: 40px;
  margin: 0;
  padding: 0 12px;
  border-radius: 10px;
  background: var(--bg);
  box-shadow: inset 0 0 0 1px var(--line-2);
  transition: box-shadow 0.16s ease-out;
}
.welcome .field:focus-within {
  box-shadow: inset 0 0 0 1.5px var(--primary), 0 0 0 4px color-mix(in srgb, var(--primary) 14%, transparent);
}
.welcome .field input {
  flex: 1;
  min-width: 0;
  border: 0;
  outline: 0;
  padding: 0;
  background: transparent;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  caret-color: var(--primary);
}
.welcome .field input::placeholder {
  color: var(--ink-3);
}
.wc-join .btn {
  align-self: flex-end;
}
.wc-line {
  margin: 12px 0 0;
  font-size: 12px;
  color: #ef4444;
}
.wc-line:empty {
  display: none;
}

/* The phone's (§14.6): the cards one over the other, the dock below. */
.m-welcome {
  position: fixed;
  inset: 0;
  overflow: auto;
  box-sizing: border-box;
  padding: calc(28px + env(safe-area-inset-top)) 16px 120px;
  background: var(--well);
}
[data-theme='dark'] .m-welcome .wc-card {
  background: var(--bg);
}
.m-wc-head h1 {
  margin: 0;
  font-size: 22px;
  font-weight: 600;
}
.m-wc-head p {
  margin: 6px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-2);
}
.welcome.phone {
  position: static;
  padding: 20px 0 0;
  gap: 12px;
}
.welcome.phone .wc-card {
  padding: 18px 16px;
}
.welcome.phone .wc-ways {
  grid-template-columns: 1fr;
}

/* 新建局域网 in the sidebar (§14.14), as the desktop's: the plus in the
   primary blue; naming, the row is white and lifted, a field for the name. */
.side .nav.new-lan {
  color: var(--ink-2);
}
.side .nav.new-lan svg {
  color: var(--primary);
}
.side .nav.new-lan.naming {
  color: var(--ink);
  background: var(--bg);
  box-shadow: 0 1px 2px rgba(9, 9, 11, 0.06), 0 1px 1px rgba(9, 9, 11, 0.04);
  cursor: text;
}
[data-theme='dark'] .side .nav.new-lan.naming {
  background: var(--well-2);
}
.nl-input {
  flex: 1;
  min-width: 0;
  border: 0;
  outline: 0;
  padding: 0;
  background: transparent;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
  caret-color: var(--primary);
}
.nl-input::placeholder {
  color: var(--ink-3);
  font-weight: 400;
}
