/* The client's own screen. Hand-written and small on purpose: it is a list, one button and a
   viewfinder, and the interesting surface is a machine's own page filling the viewport underneath.

   Every value here is a token from `design/tokens.css`, which `index.html` links ahead of this
   sheet; the faces are Geist and Geist Mono from `adi-ui/fonts`; the icons are Lucide, inlined by
   `src/ui.rs`. Nothing is named twice. The rules are `design/DESIGN.md`: dark, surfaces rather
   than boxes, hairlines between rows, mono only for machine strings, one orange — the Scan button.

   Everything tappable is at least 44px tall (Apple's own minimum), and the safe-area insets are
   what keep the list clear of a notch and the home indicator when this is installed full-bleed. */

:root { color-scheme: dark; }

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
}

body {
  /* A phone is read at arm's length: one step up from the desktop's 14px UI size. */
  font-size: 15px;
  /* A tap that also selects text feels broken on a phone; inputs opt back in below. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-text-size-adjust: 100%;
}

h1, p, ul { margin: 0; }
ul { padding: 0; list-style: none; }

button, input, textarea {
  font: inherit;
  color: inherit;
  border: 0;
  background: none;
  padding: 0;
}
button { cursor: pointer; }
button:disabled { opacity: .5; cursor: default; }

:focus-visible {
  outline: 1.5px solid var(--focus);
  outline-offset: 2px;
}

/* Machine strings only: the node key, the invite token, a dashboard's host. */
.key, textarea {
  font-family: var(--mono);
  color: var(--code);
}

.shell {
  max-width: 30rem;
  margin: 0 auto;
  padding: max(16px, env(safe-area-inset-top)) 16px max(32px, env(safe-area-inset-bottom));
}

/* --- the brand ------------------------------------------------------------------------------ */

header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0 16px;
}
/* The mark is `currentColor` at three tones, so it takes the page's ink and needs no second
   drawing. 20px beside the wordmark: the bar size, one up. */
.mark { width: 20px; height: 20px; flex: none; }
header h1 {
  font-size: 15px;
  font-weight: 600;
  line-height: 1.2;
}
header .sub {
  margin-top: 1px;
  color: var(--ink-3);
  font-size: 13px;
}

/* --- the sandbox build (ADI-SELLER-PORTAL-10) ------------------------------------------------ */

/* `--warn`, not `--err`: nothing has gone wrong, this is a standing reminder of where the reader
   is. The soft tint is the one §3 allows outside a status pill, for exactly this — a sentence
   that has to read before anything else does. */
.sandbox-banner {
  margin: 0 0 12px;
  padding: 8px 10px;
  border-radius: var(--r);
  background: var(--warn-soft);
  color: var(--warn);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.4;
}

/* --- what went wrong ------------------------------------------------------------------------ */

/* A sentence in the error colour, and nothing around it (§3). It sometimes carries a key; let it
   wrap rather than clip. */
.problem {
  padding: 8px 0 12px;
  color: var(--err);
  font-size: 13px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.empty {
  padding: 8px 0 12px;
  color: var(--ink-3);
  font-size: 13px;
  line-height: 1.5;
  max-width: 64ch;
}

/* --- the machines --------------------------------------------------------------------------- */

/* A list, not a stack of cards: one machine is a row, then whatever it runs, indented under it,
   and a hairline before the next. */
.machine { border-top: 1px solid var(--line); }
.machine .row { display: flex; align-items: stretch; }

.node {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
  padding: 12px 8px 12px 0;
  min-height: 44px;
  min-width: 0;
}
.node .name {
  font-weight: 500;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.node .meta {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-3);
}
.node:active .name { color: var(--ink-2); }

/* The row's ⋯: a 44px hit area around a 16px glyph, no frame. */
.more {
  flex: none;
  width: 44px;
  display: grid;
  place-items: center;
  color: var(--ink-3);
  border-radius: var(--r);
}
.more:active { background: var(--bg-hover); color: var(--ink-2); }
.more svg { display: block; }

/* --- what a machine runs -------------------------------------------------------------------- */

.boards { padding-bottom: 4px; }
.board {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  text-align: left;
  padding: 8px 8px 8px 16px;
  min-height: 44px;
  font-size: 14px;
  color: var(--ink-2);
  border-radius: var(--r);
}
.board:active { background: var(--bg-hover); }
.board .name {
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
}
/* Running and granted: a 6px dot, and nothing else to say (§6). */
.board .dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ok);
}
/* The one word beside a dashboard's name, only when there is one: what a tap will do first, or
   that the dashboard is not up over there. */
.board .word {
  flex: none;
  font-size: 12px;
  color: var(--ink-3);
}

/* Why a machine's rows are missing, in its own words. Quiet enough that a sleeping laptop does not
   read as a broken page. */
.quiet {
  padding: 4px 0 12px 16px;
  color: var(--ink-3);
  font-size: 13px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

/* --- adding a machine ------------------------------------------------------------------------ */

.add {
  display: grid;
  gap: 8px;
  margin-top: 24px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}

/* Scanning is the action. A 953-character token gets onto a phone through a lens, and the field
   below is the fallback — so this is the one orange thing on the screen (§2.4). */
.cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  min-height: 48px;
  border-radius: var(--r);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 15px;
  font-weight: 500;
}
.cta:active { background: var(--accent-hover); }
.cta .glyph { display: flex; }

.paste { font-size: 13px; }
.paste summary {
  color: var(--ink-3);
  cursor: pointer;
  padding: 12px 0;
  text-align: center;
  list-style: none;
}
.paste summary::-webkit-details-marker { display: none; }
.paste[open] summary { text-align: left; }
.paste > *:not(summary) { margin-top: 8px; }

/* The page's main action when the orange is spent on Scan: an ink fill (§6 `.strong`). */
.strong {
  width: 100%;
  min-height: 44px;
  padding: 0 16px;
  border-radius: var(--r);
  background: var(--ink);
  color: var(--bg);
  font-weight: 500;
}

.ghost {
  min-height: 44px;
  padding: 0 14px;
  border-radius: var(--r);
  color: var(--ink-2);
}
.ghost:active { background: var(--bg-hover); color: var(--ink); }

/* Destructive: red text, no frame, no tint (§3). */
.danger {
  min-height: 44px;
  padding: 0 14px;
  border-radius: var(--r);
  color: var(--err);
}
.danger:active { background: var(--bg-hover); }

textarea, input {
  width: 100%;
  padding: 9px 12px;
  border-radius: var(--r);
  border: 1px solid var(--line-strong);
  background: var(--bg-raise);
  color: var(--ink);
  line-height: 1.45;
  -webkit-user-select: text;
  user-select: text;
  /* Under 16px iOS zooms the page on focus and never zooms back out. */
  font-size: 16px;
}
textarea { resize: vertical; }
textarea::placeholder, input::placeholder { color: var(--ink-3); opacity: 1; }
textarea:focus-visible, input:focus-visible {
  outline: none;
  border-color: var(--ink-3);
}

/* Renaming: the field takes the row, the one destructive action sits after it as a word. */
.machine.editing {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
}
.machine.editing input.rename { flex: 1; min-width: 0; }

.note {
  color: var(--ink-3);
  font-size: 13px;
  line-height: 1.5;
}
.label {
  color: var(--ink-3);
  font-size: 12px;
  margin: 0 0 4px;
}

/* --- this browser ---------------------------------------------------------------------------- */

/* Closed by default, and it holds the two facts a reader needs only when something has gone wrong:
   which key a node is refusing, and where the passwords live. */
footer {
  margin-top: 32px;
  border-top: 1px solid var(--line);
  padding-top: 4px;
}
footer summary {
  color: var(--ink-3);
  font-size: 13px;
  cursor: pointer;
  padding: 12px 0;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 6px;
}
footer summary::-webkit-details-marker { display: none; }
footer summary svg { transition: none; }
footer details[open] summary svg { transform: rotate(90deg); }
footer .key {
  display: block;
  font-size: 12.5px;
  overflow-wrap: anywhere;
  -webkit-user-select: text;
  user-select: text;
  margin-bottom: 8px;
}

/* --- the camera ------------------------------------------------------------------------------ */

/* Full-bleed and black, because it is a viewfinder: everything on top of it is white on the
   picture, and the picture is the only thing being read. The one place on this screen that names
   its own colours — they are the picture's, not the palette's. */
.scanner { position: fixed; inset: 0; z-index: 10; background: #000; }
.scanner video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* The square `scan::Reader` actually decodes is the centre of the frame; this is what says so.
   The huge spread shadow is the dimming around it — one box, no second element. */
.scanner .reticle {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 70vmin;
  height: 70vmin;
  transform: translate(-50%, -50%);
  border: 2px solid rgba(255, 255, 255, .9);
  border-radius: var(--r-lg);
  box-shadow: 0 0 0 100vmax rgba(0, 0, 0, .35);
  /* A tap anywhere on the picture is the retry for a video that would not autoplay, and this sits
     over most of it. */
  pointer-events: none;
}

.scanner .scanbar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: grid;
  gap: 12px;
  justify-items: center;
  padding: 24px 16px max(16px, env(safe-area-inset-bottom));
  /* Over the picture, not over UI: it is what keeps white words readable on a bright frame. */
  background: linear-gradient(transparent, rgba(0, 0, 0, .65));
}
.scanner .hint {
  color: #fff;
  font-size: 15px;
  line-height: 1.5;
  text-align: center;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .8);
}
.scanner .scanbar button {
  min-width: 9rem;
  color: #fff;
  background: rgba(255, 255, 255, .18);
}

/* --- the deep-link confirm (ADI-MONO-171 G5) -------------------------------------------------- */

/* A link can be opened by anything, so pairing from one gets the same deliberate tap a QR scan
   already requires rather than firing the instant the page loads. A dim backdrop and a raised
   surface — no shadow (§6): the separation is the backdrop's own opacity, not a drop shadow on
   the panel sitting on it. */
.confirm-overlay {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(0, 0, 0, .5);
}
.confirm {
  width: 100%;
  max-width: 22rem;
  display: grid;
  gap: 16px;
  padding: 20px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--bg-raise);
  color: var(--ink);
  text-align: center;
}
.confirm .actions { display: grid; gap: 8px; }

/* --- a machine's page ------------------------------------------------------------------------ */

.panel { position: fixed; inset: 0; display: flex; flex-direction: column; background: var(--bg); }
.panel .bar {
  display: flex;
  align-items: center;
  gap: 4px;
  min-height: var(--bar-h);
  padding: env(safe-area-inset-top) 8px 0;
  border-bottom: 1px solid var(--line);
  background: var(--bg-side);
}
.panel .back {
  display: flex;
  align-items: center;
  gap: 4px;
  min-height: 44px;
  padding: 0 8px 0 4px;
  color: var(--ink-2);
  font-size: 14px;
  border-radius: var(--r);
}
.panel .back:active { color: var(--ink); background: var(--bg-hover); }
.panel .title {
  font-weight: 500;
  font-size: 15px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Which machine this page is running on — the fact that is not in its name. */
.panel .title .under { color: var(--ink-3); font-weight: 400; }
.panel .title .under::before { content: " · "; }
.panel iframe { flex: 1; width: 100%; border: 0; background: var(--bg); }
