body {
  margin: 0;
  min-height: 100vh;
  box-sizing: border-box;
  padding: var(--ui-space-5) var(--ui-space-4) var(--ui-space-7);
}
[hidden] {
  display: none !important;
}

.top {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--ui-space-3);
  max-width: 560px;
  margin: 0 auto var(--ui-space-5);
}
.home {
  display: flex;
  align-items: center;
  gap: var(--ui-space-3);
  color: inherit;
  text-decoration: none;
}
.prefs {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--ui-space-2);
  margin-left: auto;
}
.theme,
.icon-btn.ui-btn--sm {
  width: var(--ui-size-control-sm);
  padding: 0;
}
.icon-btn {
  width: var(--ui-size-control);
  padding: 0;
  flex: none;
}
.grow {
  flex: 1;
}
.theme svg {
  display: none;
}
.theme[data-state="auto"] .i-auto,
.theme[data-state="light"] .i-light,
.theme[data-state="dark"] .i-dark {
  display: block;
}
.lang {
  width: auto;
  height: var(--ui-size-control-sm);
  padding-block: 0;
}
.logo-dark {
  display: none;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .logo-light {
    display: none;
  }
  :root:not([data-theme="light"]) .logo-dark {
    display: inline;
  }
}
:root[data-theme="dark"] .logo-light {
  display: none;
}
:root[data-theme="dark"] .logo-dark {
  display: inline;
}
.brand {
  font: 600 var(--ui-text-lg)/1 var(--ui-font-mono);
}
.brand-app {
  color: var(--ui-accent);
}

main.ui-card {
  max-width: 560px;
  margin: 0 auto;
  box-sizing: border-box;
}
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--ui-space-4);
}
.stack > p {
  margin: 0;
}
.field {
  display: flex;
  flex-direction: column;
  gap: var(--ui-space-2);
}
.row {
  display: flex;
  gap: var(--ui-space-3);
  flex-wrap: wrap;
}
.row > .ui-input {
  flex: 1;
  min-width: 0;
}
.join {
  margin-top: var(--ui-space-5);
  padding-top: var(--ui-space-5);
  border-top: 1px solid var(--ui-border);
}
.mono {
  font-family: var(--ui-font-mono);
  font-size: var(--ui-text-sm);
}
.keys {
  margin-top: var(--ui-space-3);
}
summary {
  cursor: pointer;
  font-size: var(--ui-text-sm);
}

.drop {
  display: flex;
  flex-direction: column;
  gap: var(--ui-space-1);
  align-items: center;
  text-align: center;
  padding: var(--ui-space-6) var(--ui-space-4);
  border: 2px dashed var(--ui-border);
  border-radius: var(--ui-radius-card);
  cursor: pointer;
  transition:
    border-color 0.15s,
    background-color 0.15s;
}
.drop:hover,
.drop.is-over {
  border-color: var(--ui-accent);
  background: color-mix(in srgb, var(--ui-accent) 8%, transparent);
}
.drop:focus-within {
  outline: 2px solid var(--ui-fg);
  outline-offset: 2px;
}
.drop.is-disabled {
  cursor: not-allowed;
  opacity: 0.55;
}
.drop-title {
  font: 600 var(--ui-text-md)/1.3 var(--ui-font-mono);
}
.xfer {
  display: flex;
  flex-direction: column;
  gap: var(--ui-space-2);
}
.xfer-head {
  display: flex;
  gap: var(--ui-space-2);
  align-items: baseline;
  min-width: 0;
}
.xfer-name {
  font-weight: 600;
}
.xfer-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--ui-space-3);
  font-size: var(--ui-text-sm);
}
.xfer-track {
  display: flex;
  position: relative;
}
.xfer progress {
  width: 100%;
  height: 8px;
  appearance: none;
  border: 0;
  border-radius: var(--ui-radius-pill);
  overflow: hidden;
  background: var(--ui-input-bg);
  box-shadow: inset 0 0 0 1px var(--ui-border);
}
.xfer progress::-webkit-progress-bar {
  background: transparent;
}
.xfer progress::-webkit-progress-value {
  background: var(--ui-accent);
  border-radius: var(--ui-radius-pill);
}
.xfer progress::-moz-progress-bar {
  background: var(--ui-accent);
  border-radius: var(--ui-radius-pill);
}
.spell {
  display: none;
}

.history {
  gap: var(--ui-space-2);
}
.history h2 {
  margin: 0;
}
.history-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--ui-space-2);
}
.hist {
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
  min-height: var(--ui-size-control-sm);
  font-size: var(--ui-text-sm);
}
.hist-name {
  flex: 1;
  min-width: 0;
  font-weight: 600;
}
.hist-state {
  color: var(--ui-muted);
}
.hist--done .hist-state {
  color: var(--ui-success-fg);
}
.hist--failed .hist-state {
  color: var(--ui-danger);
}
.hist-check {
  display: none;
}

.status-row {
  display: flex;
  align-items: center;
  gap: var(--ui-space-3);
}
.status-row > .ui-alert {
  flex: 1;
  min-width: 0;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.dialog {
  max-width: min(440px, calc(100vw - 2 * var(--ui-space-4)));
  box-sizing: border-box;
  color: var(--ui-fg);
}
.dialog::backdrop {
  background: color-mix(in srgb, var(--ui-bg) 60%, transparent);
}
.room-info {
  font-size: var(--ui-text-sm);
}
.room-info-row {
  align-items: center;
}
.room-info-row > .room-info {
  margin: 0;
}
.hint {
  margin: 0;
  font-size: var(--ui-text-sm);
}
.room-hints {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--ui-space-1);
  font-size: var(--ui-text-sm);
}
#set-room.ui-alert {
  gap: var(--ui-space-2);
}
#set-room.ui-alert .room-hints {
  font-size: inherit;
  list-style: disc;
  padding-left: 1.25em;
  margin: 0;
}
#set-room-lead[hidden] + .room-hints {
  list-style: none;
  padding-left: 0;
}
.dialog h3.ui-label {
  margin: 0;
}
.notify-card {
  display: flex;
  flex-direction: column;
  gap: var(--ui-space-3);
}
.notify-card p {
  margin: 0;
}
.check {
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
  cursor: pointer;
}
.check input {
  accent-color: var(--ui-accent);
  width: 1.125rem;
  height: 1.125rem;
  margin: 0;
  flex: none;
}
.qr-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--ui-space-3);
}
.invite-qr svg {
  display: block;
  width: 224px;
  height: 224px;
  max-width: 100%;
  border-radius: var(--ui-radius-card);
}
.qr-box:not(.is-open) {
  display: none;
}
.scan-video {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--ui-radius-card);
  background: #000;
}
.devices {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--ui-space-2);
}
.devices:empty {
  display: none;
}
.device {
  width: 100%;
  justify-content: space-between;
  gap: var(--ui-space-3);
  overflow-wrap: anywhere;
}
.compare-code {
  margin: 0;
  font-family: var(--ui-font-mono);
  font-size: 2.5rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-align: center;
}
.offer-name {
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* The footer and the line under Create Room that an assets folder's legal links go in. */
.legal-footer {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ui-space-4);
  max-width: 560px;
  margin: var(--ui-space-5) auto 0;
  font-size: var(--ui-text-sm);
}
.legal-footer a {
  color: var(--ui-muted);
  text-underline-offset: 3px;
}
.legal-footer a:hover {
  color: var(--ui-fg);
}
.legal-note {
  margin: 0;
  font-size: var(--ui-text-sm);
}
.legal-note a {
  color: inherit;
}

/* Fun mode: everything under .fun on <html>; one-shot classes come from burst() in fun.ts. */
/* A dragged file charges the drop zone (marching ants drawn as four animated background strips, since a
   dashed border cannot move its dashes) and a send fires sparks down toward the sending bar. */
.fun .drop {
  position: relative;
}
.fun .drop.is-over {
  border-color: transparent;
  background-color: color-mix(in srgb, var(--ui-accent) 10%, transparent);
  background-image:
    repeating-linear-gradient(90deg, var(--ui-accent) 0 8px, transparent 8px 16px),
    repeating-linear-gradient(90deg, var(--ui-accent) 0 8px, transparent 8px 16px),
    repeating-linear-gradient(0deg, var(--ui-accent) 0 8px, transparent 8px 16px),
    repeating-linear-gradient(0deg, var(--ui-accent) 0 8px, transparent 8px 16px);
  background-size:
    100% 2px,
    100% 2px,
    2px 100%,
    2px 100%;
  background-position:
    0 0,
    0 100%,
    0 0,
    100% 0;
  background-repeat: no-repeat;
  background-origin: border-box;
  background-clip: border-box;
  box-shadow:
    0 0 0 2px var(--ui-accent),
    0 0 26px color-mix(in srgb, var(--ui-accent) 70%, transparent);
  animation:
    fun-ants 0.45s linear infinite,
    fun-charge 1s ease-in-out infinite alternate;
}
.fun .drop.is-fire::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 10px;
  width: 4px;
  height: 4px;
  margin-left: -2px;
  border-radius: 50%;
  background: var(--ui-accent);
  pointer-events: none;
  box-shadow:
    0 0 6px 2px var(--ui-accent),
    6px 7px 0 -0.5px var(--hot),
    -7px 5px 0 -1px var(--ui-accent),
    3px 13px 0 -0.5px var(--hot),
    -3px 17px 0 -1px var(--ui-accent),
    9px 19px 0 -1.5px var(--hot);
  animation: fun-fire 0.6s cubic-bezier(0.35, 0.8, 0.5, 1) forwards;
}
.fun .xfer progress {
  box-shadow:
    inset 0 0 0 1px var(--ui-border),
    0 0 10px color-mix(in srgb, var(--ui-accent) 60%, transparent);
}
/* Warm particle color: warning-fg is a bright peach on dark but a brown text color on light. */
.fun {
  --hot: var(--ui-danger);
}
@media (prefers-color-scheme: dark) {
  :root.fun:not([data-theme="light"]) {
    --hot: var(--ui-warning-fg);
  }
}
:root.fun[data-theme="dark"] {
  --hot: var(--ui-warning-fg);
}
/* A spell beam from a wand dot to the fill's edge: white core, twisting coils, a small sparking impact
   orb. It stays still while the offer waits for the receiver's answer. */
.fun .spell {
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 28px;
  margin-top: -14px;
  pointer-events: none;
}
.fun .xfer.is-waiting .spell {
  display: none;
}
.fun .spell-beam {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  clip-path: inset(-20px calc((1 - var(--p, 0)) * 100%) -20px 0);
}
.fun .spell-core {
  stroke: #fff;
  stroke-width: 2.4;
  fill: none;
  filter: drop-shadow(0 0 2px #fff) drop-shadow(0 0 4px var(--ui-accent));
}
.fun .spell-coil {
  fill: none;
  stroke-width: 1.4;
  stroke-linecap: round;
  animation: spell-flow 0.9s linear infinite;
}
.fun .spell-coil.a {
  stroke: color-mix(in srgb, var(--ui-accent) 55%, #fff);
}
.fun .spell-coil.b {
  stroke: var(--hot);
  opacity: 0.85;
  animation-duration: 0.7s;
}
.fun .spell-coil.c {
  stroke: #fff;
  opacity: 0.7;
  stroke-width: 0.9;
  animation-duration: 1.2s;
}
.fun .spell-wand {
  position: absolute;
  left: -3px;
  top: 50%;
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-radius: 50%;
  background: #fff;
  box-shadow:
    0 0 4px 1px #fff,
    0 0 10px 3px var(--ui-accent);
}
.fun .spell-head {
  position: absolute;
  left: calc(var(--p, 0) * 100%);
  top: 50%;
  width: 13px;
  height: 13px;
  margin: -6.5px 0 0 -6.5px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff 0 22%, color-mix(in srgb, var(--ui-accent) 70%, #fff) 40%, transparent 70%);
  box-shadow: 0 0 9px 3px color-mix(in srgb, var(--ui-accent) 70%, transparent);
  animation: spell-pulse 0.6s ease-in-out infinite alternate;
}
.fun .spell-head::before,
.fun .spell-head::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 3px;
  height: 3px;
  margin: -1.5px;
  border-radius: 50%;
  background: #fff;
  box-shadow:
    6px -5px 0 0 var(--hot),
    8px 3px 0 -0.5px #fff,
    4px 6px 0 0 var(--ui-accent),
    -3px -8px 0 -0.5px #fff,
    10px -1px 0 0.5px var(--hot);
  animation: spell-sparks 0.72s steps(3) infinite;
}
.fun .spell-head::after {
  box-shadow:
    7px 6px 0 0 #fff,
    10px -4px 0 -0.5px var(--hot),
    3px -8px 0 0 var(--ui-accent),
    12px 2px 0 -0.5px #fff;
  animation-delay: -0.36s;
}
.fun .xfer.is-done .spell,
.fun .xfer.is-fizzle .spell {
  display: none;
}
@keyframes spell-flow {
  to {
    transform: translateX(20px);
  }
}
@keyframes spell-pulse {
  from {
    transform: scale(0.9);
  }
  to {
    transform: scale(1.08);
  }
}
@keyframes spell-sparks {
  0% {
    transform: translate(0, 0) scale(1);
    opacity: 1;
  }
  50% {
    transform: translate(3px, -1.5px) scale(1.2);
  }
  100% {
    transform: translate(5px, 1px) scale(0.4);
    opacity: 0;
  }
}
/* Accept keeps its click synchronous; the package zips into the receiving bar instead of animating the dialog. */
.fun .xfer.is-zip {
  animation: fun-zip 0.45s cubic-bezier(0.2, 0.9, 0.3, 1.1);
}
.fun .xfer.is-done {
  animation: fun-shake 0.55s ease-out;
}
.fun .xfer.is-done progress {
  box-shadow:
    inset 0 0 0 1px var(--ui-accent),
    0 0 22px var(--ui-accent);
}
.fun .xfer.is-fizzle {
  animation: fun-fizzle 0.7s ease-in forwards;
}
.fun .xfer.is-fizzle progress {
  box-shadow: inset 0 0 0 1px var(--ui-border);
}
.fun .xfer.is-fizzle progress::-webkit-progress-value {
  background: var(--ui-muted);
}
.fun .xfer.is-fizzle progress::-moz-progress-bar {
  background: var(--ui-muted);
}
.fun main.is-pop {
  animation: fun-pop 0.45s cubic-bezier(0.3, 1.6, 0.5, 1);
}
.fun main.is-boom {
  animation: fun-boom 0.7s ease-out;
}
/* The offer slides in; each finished file lands in the history, a done check drawing itself. */
.fun dialog.is-arrive {
  animation: fun-arrive 0.55s cubic-bezier(0.22, 0.9, 0.32, 1.1);
}
.fun .hist-check {
  display: block;
  width: 1rem;
  height: 1rem;
  flex: none;
  stroke-width: 2.5;
  color: var(--ui-success-fg);
  overflow: visible;
}
.fun .hist-check path {
  stroke-dasharray: 24;
  stroke-dashoffset: 0;
}
.fun .hist.is-land {
  animation: fun-land 0.5s cubic-bezier(0.3, 1.3, 0.5, 1);
}
.fun .hist--done.is-land {
  animation-name: fun-land-pop;
}
.fun .hist--done.is-land .hist-check path {
  animation: fun-check 0.42s ease-out;
}
.fun .hist--declined.is-land {
  animation-name: fun-land-toss;
}
.fun .hist--cancelled.is-land,
.fun .hist--failed.is-land {
  animation-name: fun-land-grey;
}

/* Entering a room and your own Leave: a quick swell with a few particles, no blur. */
.fun main.is-assemble,
.fun main.is-bye {
  position: relative;
}
.fun main.is-assemble::before,
.fun main.is-bye::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 4px;
  height: 4px;
  margin: -2px;
  border-radius: 50%;
  pointer-events: none;
}
.fun main.is-assemble {
  animation: fun-swell 0.35s ease-out;
}
.fun main.is-assemble > section {
  animation: fun-materialize 0.35s ease-out;
}
.fun main.is-assemble::before {
  animation: fun-gather 0.35s ease-out forwards;
}
.fun main.is-bye {
  animation: fun-settle 0.35s ease-in-out;
}
.fun main.is-bye > section {
  animation: fun-dim 0.35s ease-in-out;
}
.fun main.is-bye::before {
  animation: fun-drift 0.35s ease-out forwards;
}
@keyframes fun-materialize {
  0%,
  35% {
    opacity: 0;
    transform: scale(0.96);
  }
  100% {
    opacity: 1;
    transform: none;
  }
}
@keyframes fun-gather {
  0% {
    opacity: 0;
    box-shadow:
      180px -40px 0 1px var(--ui-accent),
      140px 90px 0 0 var(--hot),
      -120px 120px 0 1px var(--ui-accent),
      -190px -50px 0 0 var(--hot),
      20px -160px 0 1px var(--ui-accent);
  }
  25% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    box-shadow:
      24px -18px 0 0 var(--ui-accent),
      -16px 22px 0 0 var(--hot),
      12px 20px 0 0 var(--ui-accent),
      -28px -12px 0 0 var(--hot),
      4px -24px 0 0 var(--ui-accent);
  }
}
@keyframes fun-swell {
  0% {
    transform: scale(0.98);
  }
}
@keyframes fun-settle {
  40% {
    transform: scale(0.99);
  }
}
@keyframes fun-dim {
  40% {
    opacity: 0.55;
  }
}
@keyframes fun-drift {
  0% {
    opacity: 0;
    box-shadow:
      -80px -60px 0 1px var(--ui-accent),
      90px 40px 0 0 var(--ui-muted),
      -60px 90px 0 1px var(--ui-accent),
      70px -80px 0 0 var(--ui-muted);
  }
  20% {
    opacity: 0.9;
  }
  100% {
    opacity: 0;
    box-shadow:
      -140px -120px 0 0 var(--ui-accent),
      150px 90px 0 0 var(--ui-muted),
      -110px 150px 0 0 var(--ui-accent),
      130px -140px 0 0 var(--ui-muted);
  }
}

/* Copy Link confetti, the connection path and the theme swap. */
.fun #copy.is-confetti {
  position: relative;
}
.fun #copy.is-confetti::before,
.fun #copy.is-confetti::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 5px;
  height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: 1px;
  background: var(--ui-accent);
  pointer-events: none;
  animation: fun-confetti-a 0.7s ease-out forwards;
}
.fun #copy.is-confetti::after {
  animation-name: fun-confetti-b;
  animation-duration: 0.85s;
  animation-delay: 0.04s;
}
@keyframes fun-confetti-a {
  0% {
    opacity: 0;
    transform: translate(0, 0);
    box-shadow:
      0 0 0 0 var(--ui-accent),
      0 0 0 0 var(--hot),
      0 0 0 0 var(--ui-success-fg),
      0 0 0 0 var(--ui-accent),
      0 0 0 0 var(--hot),
      0 0 0 0 var(--ui-accent);
  }
  15% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate(0, 24px);
    box-shadow:
      -34px -20px 0 0 var(--ui-accent),
      27px -31px 0 1px var(--hot),
      -16px -40px 0 0 var(--ui-success-fg),
      12px -35px 0 1px var(--ui-accent),
      39px -13px 0 0 var(--hot),
      -41px -7px 0 1px var(--ui-accent);
  }
}
@keyframes fun-confetti-b {
  0% {
    opacity: 0;
    transform: translate(0, 0);
    box-shadow:
      0 0 0 0 var(--hot),
      0 0 0 0 var(--ui-accent),
      0 0 0 0 var(--ui-success-fg),
      0 0 0 0 var(--hot),
      0 0 0 0 var(--ui-accent);
  }
  15% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate(0, 30px);
    box-shadow:
      31px -24px 0 0 var(--hot),
      -29px -35px 0 1px var(--ui-accent),
      8px -43px 0 0 var(--ui-success-fg),
      -7px -19px 0 1px var(--hot),
      21px -41px 0 0 var(--ui-accent);
  }
}

.fun .theme.is-swap {
  animation: fun-turn 0.45s cubic-bezier(0.4, 0, 0.2, 1);
}
.fun .theme.is-swap svg {
  animation: fun-turn-in 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes fun-turn {
  50% {
    transform: rotate(90deg);
  }
  100% {
    transform: none;
  }
}
@keyframes fun-turn-in {
  0% {
    opacity: 0;
    transform: rotate(-150deg) scale(0.4);
  }
  70% {
    opacity: 1;
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

/* Decoration only: #conn-path and #conn-detail above it stay the accessible content. */
.conn-graph {
  display: none;
  width: 100%;
  height: auto;
  color: var(--ui-muted);
}
.fun .conn-graph.is-direct,
.fun .conn-graph.is-relay {
  display: block;
}
.conn-graph .conn-device,
.conn-graph .conn-relay {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.conn-graph .conn-relay {
  display: none;
}
.conn-graph.is-relay .conn-relay {
  display: inline;
  transform-box: fill-box;
  transform-origin: center;
  animation: fun-relay 0.45s ease-out 0.6s both;
}
.conn-graph .conn-wire {
  fill: none;
  stroke: var(--ui-accent);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-dasharray: 200;
  stroke-dashoffset: 200;
  animation: fun-draw 0.7s ease-out 0.1s forwards;
}
.conn-graph.is-lan .conn-wire {
  stroke: var(--ui-success-fg);
}
.conn-graph.is-relay .conn-wire {
  stroke: var(--ui-warning-fg);
}
.conn-graph .conn-dot {
  fill: var(--ui-accent);
  animation: fun-travel 1.15s ease-in-out 0.55s both;
}
.conn-graph.is-lan .conn-dot {
  fill: var(--ui-success-fg);
}
.conn-graph.is-relay .conn-dot {
  fill: var(--ui-warning-fg);
}
@keyframes fun-draw {
  to {
    stroke-dashoffset: 0;
  }
}
@keyframes fun-travel {
  0% {
    transform: translateX(0);
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  85% {
    opacity: 1;
  }
  100% {
    transform: translateX(188px);
    opacity: 0;
  }
}
@keyframes fun-relay {
  0% {
    opacity: 0;
    transform: scale(0.4);
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

/* Big tabular MM:SS digits beside the status; they turn red and pulse as the room's time runs out. */
.fun .countdown {
  flex: none;
  font: 700 1.75rem/1 var(--ui-font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  color: var(--ui-fg);
}
.fun .countdown.is-scared {
  color: var(--ui-danger);
  text-shadow: 0 0 10px color-mix(in srgb, var(--ui-danger) 70%, transparent);
}
.fun .countdown.is-tick {
  animation: fun-tick 0.4s ease-out;
}
.fun .countdown.is-defused {
  animation: fun-countdown-out 0.9s ease-out forwards;
}

/* Waiting pulse and reconnect plug: one glyph at a time, Fun mode only. */
.waiting {
  display: none;
  flex: none;
  width: 1.75rem;
  height: 1.75rem;
}
.fun .waiting {
  display: block;
  position: relative;
  background: radial-gradient(circle at 50% 50%, var(--ui-accent) 0 3px, transparent 3.5px);
}
.fun .waiting::before,
.fun .waiting::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 12px;
  height: 12px;
  margin: -6px;
  box-sizing: border-box;
  border: 2px solid var(--ui-accent);
  border-radius: 50%;
  opacity: 0;
  animation: fun-listen 1.8s ease-out infinite;
}
.fun .waiting::after {
  animation-delay: -0.9s;
}
.plug {
  display: none;
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  overflow: visible;
}
.fun .plug {
  display: block;
  transform-origin: 25% 60%;
  animation: fun-plug-wobble 0.6s ease-in-out infinite;
}
.plug-cord,
.plug-prong {
  fill: none;
  stroke: var(--ui-muted);
  stroke-width: 1.6;
  stroke-linecap: round;
}
.plug-body {
  fill: var(--ui-fg);
}
.plug-spark {
  fill: var(--hot);
  transform-box: fill-box;
  transform-origin: center;
  animation: fun-plug-spark 0.7s steps(2) infinite;
}

@keyframes fun-shake {
  15% {
    transform: translateX(-5px) rotate(-1deg);
  }
  30% {
    transform: translateX(5px) rotate(1deg);
  }
  45% {
    transform: translateX(-3px);
  }
  60% {
    transform: translateX(3px);
  }
  80% {
    transform: translateX(-1px);
  }
}
@keyframes fun-fizzle {
  20% {
    transform: translateX(-3px) rotate(-0.5deg);
  }
  40% {
    transform: translateX(2px);
  }
  60% {
    transform: translateX(-1px);
    opacity: 0.7;
  }
  100% {
    transform: none;
    opacity: 0.25;
    filter: grayscale(1);
  }
}
@keyframes fun-pop {
  0% {
    transform: scale(0.97);
  }
  60% {
    transform: scale(1.015);
  }
  100% {
    transform: none;
  }
}
@keyframes fun-boom {
  0% {
    box-shadow: 0 0 0 0 var(--ui-danger);
  }
  10% {
    transform: translate(-6px, 3px) rotate(-0.6deg);
  }
  25% {
    transform: translate(5px, -3px) rotate(0.5deg);
  }
  40% {
    transform: translate(-3px, 2px);
  }
  60% {
    transform: translate(2px, -1px);
  }
  100% {
    transform: none;
    box-shadow: 0 0 0 28px transparent;
  }
}
@keyframes fun-tick {
  30% {
    transform: scale(calc(1.1 + var(--panic, 0) * 0.35)) rotate(calc(var(--panic, 0) * -10deg));
  }
  65% {
    transform: rotate(calc(var(--panic, 0) * 8deg));
  }
}
@keyframes fun-fade {
  50% {
    opacity: 0.6;
  }
}
@keyframes fun-countdown-out {
  0% {
    opacity: 1;
    transform: scale(1);
  }
  35% {
    opacity: 1;
    transform: scale(1.08);
  }
  100% {
    opacity: 0;
    transform: scale(0.9);
  }
}
@keyframes fun-listen {
  0% {
    transform: scale(0.35);
    opacity: 0.9;
  }
  100% {
    transform: scale(1.9);
    opacity: 0;
  }
}
@keyframes fun-plug-wobble {
  0%,
  100% {
    transform: rotate(-3deg);
  }
  50% {
    transform: rotate(3deg) translateX(1px);
  }
}
@keyframes fun-plug-spark {
  50% {
    opacity: 0.15;
    transform: scale(0.5);
  }
}
@keyframes fun-ants {
  to {
    background-position:
      16px 0,
      -16px 100%,
      0 -16px,
      100% 16px;
  }
}
@keyframes fun-charge {
  from {
    box-shadow:
      0 0 0 1px color-mix(in srgb, var(--ui-accent) 45%, transparent),
      0 0 8px color-mix(in srgb, var(--ui-accent) 50%, transparent);
  }
  to {
    box-shadow:
      0 0 0 2px var(--ui-accent),
      0 0 26px color-mix(in srgb, var(--ui-accent) 70%, transparent);
  }
}
@keyframes fun-fire {
  0% {
    opacity: 0;
    transform: translateY(-8px) scale(0.5);
  }
  20% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translateY(52px) scale(1.2);
  }
}
@keyframes fun-zip {
  0% {
    opacity: 0;
    transform: translateY(-10px) scale(0.96);
    filter: brightness(1.5);
  }
  60% {
    opacity: 1;
  }
  100% {
    transform: none;
    filter: none;
  }
}
@keyframes fun-arrive {
  0% {
    opacity: 0;
    transform: translateY(-26px) scale(0.94) rotate(-1.2deg);
  }
  55% {
    opacity: 1;
    transform: translateY(4px) scale(1.01) rotate(0.7deg);
  }
  75% {
    transform: translateY(-2px) rotate(-0.35deg);
  }
  100% {
    transform: none;
  }
}
@keyframes fun-check {
  from {
    stroke-dashoffset: 24;
  }
  to {
    stroke-dashoffset: 0;
  }
}
@keyframes fun-land {
  0% {
    opacity: 0;
    transform: translateY(-8px);
  }
  100% {
    transform: none;
  }
}
@keyframes fun-land-pop {
  0% {
    opacity: 0;
    transform: translateY(-10px) scale(0.96);
  }
  60% {
    opacity: 1;
    transform: translateY(1px) scale(1.02);
  }
  100% {
    transform: none;
  }
}
@keyframes fun-land-grey {
  0% {
    opacity: 0;
    transform: translateX(-16px);
    filter: grayscale(1);
  }
  60% {
    opacity: 1;
  }
  100% {
    transform: none;
    filter: none;
  }
}
@keyframes fun-land-toss {
  0% {
    opacity: 0;
    transform: translate(-18px, -14px) rotate(-8deg);
    filter: grayscale(1);
  }
  60% {
    opacity: 1;
    transform: translate(3px, 2px) rotate(1.5deg);
  }
  100% {
    transform: none;
    filter: none;
  }
}

/* No shake, flicker or movement; glow and the danger color stay, and a short fade still ends each burst. */
@media (prefers-reduced-motion: reduce) {
  .drop {
    transition: none;
  }
  .fun .xfer progress {
    animation: none;
  }
  .fun .spell-coil,
  .fun .spell-head {
    animation: none;
  }
  .fun .spell-head::before,
  .fun .spell-head::after {
    content: none;
  }
  .fun .xfer.is-done,
  .fun .xfer.is-fizzle,
  .fun main.is-pop,
  .fun main.is-boom,
  .fun main.is-assemble,
  .fun main.is-bye {
    animation: fun-fade 0.3s;
  }
  .fun .countdown.is-tick,
  .fun .countdown.is-defused {
    animation: fun-fade 0.3s;
  }
  .fun main.is-assemble::before,
  .fun main.is-bye::before {
    content: none;
  }
  .fun main.is-assemble > section,
  .fun main.is-bye > section {
    animation: none;
  }
  .fun #copy.is-confetti::before,
  .fun #copy.is-confetti::after {
    content: none;
  }
  .fun .theme.is-swap,
  .fun .theme.is-swap svg {
    animation: fun-fade 0.3s;
  }
  .fun .conn-graph .conn-wire {
    stroke-dashoffset: 0;
    animation: none;
  }
  .fun .conn-graph .conn-dot {
    display: none;
  }
  .fun .conn-graph.is-relay .conn-relay {
    animation: none;
  }
  .fun .waiting::before,
  .fun .waiting::after {
    content: none;
  }
  .fun .plug,
  .plug-spark {
    animation: none;
  }
  .fun .drop.is-over,
  .fun .hist--done.is-land .hist-check path {
    animation: none;
  }
  .fun .drop.is-fire::after,
  .fun .xfer.is-zip,
  .fun dialog.is-arrive,
  .fun .hist.is-land {
    animation: fun-fade 0.3s;
  }
}
