/* Shared chrome for every wire page.
 *
 * Deliberately spare: these are instrument panels for prototypes, not a
 * product. `color-scheme: light dark` lets the OS decide, and every colour
 * below is either derived from currentColor or one of four semantic tokens —
 * so there is one palette to keep honest rather than two.
 */

:root {
  color-scheme: light dark;
  --edge: color-mix(in srgb, currentColor 18%, transparent);
  --dim: color-mix(in srgb, currentColor 45%, transparent);
  --ok: #2a7;
  --fail: #d44;
  --warn: #c8811f;
  --pane: min(960px, 100%);
}

body {
  font: 13px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace;
  margin: 0;
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .75rem;
}

:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* ---- header ------------------------------------------------------------ */

/* Everything sits in one column of the same width. `main` is a flex column so
 * that a narrower child — a paragraph with a readable measure — aligns to the
 * left edge rather than centring itself against the board. */
header, main { width: var(--pane); }
main { display: flex; flex-direction: column; gap: 1rem; }
#stage, #log, form { width: 100%; }

header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem 1.5rem;
  flex-wrap: wrap;
  padding-bottom: .75rem;
  border-bottom: 1px solid var(--edge);
}

h1 { font-size: .95rem; font-weight: 600; margin: 0; letter-spacing: .01em; }
h1 a { color: inherit; text-decoration: none; opacity: .45; }
h1 a:hover { opacity: 1; }
h1 .slash { opacity: .3; margin: 0 .15em; }
h1 .sub { font-weight: 400; color: var(--dim); margin-left: .6rem; }

/* ---- the status line --------------------------------------------------- */

#stats { display: flex; gap: 1.1rem; flex-wrap: wrap; color: var(--dim); }
#stats span:empty { display: none; }

/* The connection indicator, and the only moving thing on any of these pages.
 * These prototypes exist to prove datagrams arrive; whether they are arriving
 * right now is worth showing without being asked. A live link breathes, a
 * stalled one holds still — a stopped light is the whole signal. */
#link { display: inline-flex; align-items: center; gap: .45rem; color: inherit; }
#link::before {
  content: "";
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  background: var(--dim);
}
#link[data-state="connecting"]::before { animation: breathe .9s ease-in-out infinite; }
#link[data-state="live"] { color: var(--ok); }
#link[data-state="live"]::before { background: var(--ok); animation: breathe 1.6s ease-in-out infinite; }
#link[data-state="stalled"] { color: var(--warn); }
#link[data-state="stalled"]::before { background: var(--warn); }
/* Marked down in the registry — never connected, rather than lost. */
#link[data-state="unavailable"] { color: var(--warn); }
#link[data-state="unavailable"]::before { background: var(--warn); }
#link[data-state="lost"] { color: var(--fail); }
#link[data-state="lost"]::before { background: var(--fail); }

@keyframes breathe { 50% { opacity: .3; } }
@media (prefers-reduced-motion: reduce) {
  #link::before { animation: none; }
}

/* ---- the board --------------------------------------------------------- */

.howto { color: var(--dim); margin: 0; max-width: 78ch; }

#stage {
  display: block;
  aspect-ratio: 960 / 600;
  border: 1px solid var(--edge);
  border-radius: 6px;
  touch-action: none;
}

#log { min-height: 3.5rem; color: var(--dim); white-space: pre-wrap; }

.fail { color: var(--fail); }
.ok { color: var(--ok); }

/* ---- the landing page and echo ----------------------------------------- */

ul { list-style: none; padding: 0; margin: 0; display: grid; gap: .75rem; }

/* Not `a.card`: a prototype that is down is rendered as a div, because there is
   nothing at the other end to link to. */
.card {
  display: grid;
  gap: .15rem;
  padding: .9rem 1.1rem;
  text-decoration: none;
  color: inherit;
  border: 1px solid var(--edge);
  border-radius: 6px;
  transition: border-color .12s;
}
a.card:hover, a.card:focus-visible { border-color: currentColor; }
.card .name { font-weight: 600; }
.card .desc { color: var(--dim); }
/* The UDP port is not decoration — it is what identifies a prototype, and what
   you need to reach one from anything other than this page. */
.card .where { color: var(--dim); font-size: .85em; opacity: .75; }

/* Off, but still listed: that a prototype exists and is down is worth knowing,
   and is different from it never having existed. Dashed rather than merely
   faint, so it reads as unavailable and not as low-priority. */
.card[data-down] { opacity: .6; border-style: dashed; }
.card .note { color: var(--warn); font-size: .85em; margin-top: .15rem; }

.note { color: var(--dim); max-width: 62ch; margin: 0; }

form { display: flex; gap: .5rem; flex-wrap: wrap; }
input, button {
  font: inherit;
  padding: .45rem .6rem;
  color: inherit;
  background: transparent;
  border: 1px solid var(--edge);
  border-radius: 4px;
}
input { flex: 1 1 24rem; min-width: 0; }
button { padding-inline: 1.1rem; cursor: pointer; }
button:hover { border-color: currentColor; }
