:root {
  --bg: #0b0e14;
  --panel: #141922;
  --panel-2: #1c2430;
  --line: #2a3444;
  --text: #d6dae2;
  --muted: #8b95a6;
  --accent: #5aa9e6;
  --accent-dim: #2f5f85;
  --danger: #e3675f;
  --ok: #5fd08a;
  --key-h: 44px;
  --font-size: 13px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior: none;
}

/* The app owns exactly the visible viewport. `dvh` handles browser chrome that
   shrinks and grows; the JS visualViewport handler covers the on-screen
   keyboard, which `dvh` alone does not. */
.screen {
  position: fixed;
  inset: 0;
  height: 100dvh;
  display: flex;
  flex-direction: column;
}

.screen[hidden] { display: none; }

/* --- login ---------------------------------------------------------------- */

#login { align-items: center; justify-content: center; padding: 24px; }

.login-card {
  width: min(380px, 100%);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 28px 22px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.login-card h1 { margin: 0; font-size: 22px; font-weight: 600; letter-spacing: -0.2px; }
.hint { margin: 0; color: var(--muted); font-size: 13px; }

input[type="password"], input[type="text"] {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 9px;
  color: var(--text);
  padding: 12px 13px;
  font-size: 16px; /* 16px or iOS zooms the page on focus */
  width: 100%;
}

input:focus { outline: 2px solid var(--accent-dim); outline-offset: 0; }

button {
  font: inherit;
  cursor: pointer;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--text);
  padding: 11px 14px;
  touch-action: manipulation;
}

button.primary { background: var(--accent-dim); border-color: var(--accent-dim); color: #eaf3fb; }
button.ghost { background: transparent; color: var(--muted); }
button:active { filter: brightness(1.25); }

.error { color: var(--danger); font-size: 13px; margin: 0; }

/* --- top bar -------------------------------------------------------------- */

#topbar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  flex: 0 0 auto;
  padding-top: max(4px, env(safe-area-inset-top));
}

.icon-btn {
  min-width: 38px;
  height: 34px;
  padding: 0 8px;
  font-size: 15px;
  line-height: 1;
  background: transparent;
  border-color: transparent;
  color: var(--muted);
}

.icon-btn:active { background: var(--panel-2); }

.tabs {
  flex: 1 1 auto;
  display: flex;
  gap: 4px;
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }

.tab {
  flex: 0 0 auto;
  max-width: 130px;
  padding: 6px 9px;
  font-size: 12px;
  border-radius: 8px;
  background: var(--panel-2);
  border: 1px solid transparent;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tab.active { color: var(--text); border-color: var(--accent-dim); background: #223044; }

/* Hold a tab to close it. The shrink is the only affordance telling you the
   hold registered before the confirm appears. */
.tab { transition: transform 120ms ease, opacity 120ms ease; -webkit-touch-callout: none; }
.tab.holding { transform: scale(0.93); opacity: 0.7; }
.tab .dot { color: var(--ok); margin-right: 4px; }
.tab .dot.dead { color: var(--danger); }

.topbar-actions { display: flex; gap: 2px; flex: 0 0 auto; }

/* --- terminal ------------------------------------------------------------- */

#terminal-host {
  flex: 1 1 auto;
  min-height: 0;
  position: relative;
  background: var(--bg);
  /* Vertical drags are ours: they scroll the scrollback. Everything else stays
     with the browser, so pinch to zoom still works. */
  touch-action: pan-x pinch-zoom;
}

#terminal-host .term-wrap { position: absolute; inset: 0; padding: 2px 0 0 4px; }
#terminal-host .term-wrap[hidden] { display: none; }

#size-badge {
  position: absolute;
  right: 8px;
  bottom: 8px;
  z-index: 5;
  padding: 3px 8px;
  border-radius: 10px;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  background: rgba(28, 36, 48, 0.9);
  border: 1px solid var(--line);
  pointer-events: none;
}
#size-badge[hidden] { display: none; }
/* The terminal and the PTY disagreeing is the cause of text shifting sideways
   and overwriting itself, so it gets shouted about rather than whispered. */
#size-badge.mismatch { color: #ffe9e7; background: #52201d; border-color: var(--danger); }

/* The touch input field. It has to be focusable to raise the keyboard, so it is
   transparent and out of the way rather than hidden. 16px stops iOS zooming the
   page when it takes focus. */
#softkeys {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
  padding: 0;
  border: 0;
  outline: none;
  resize: none;
  opacity: 0;
  z-index: 1;
  font-size: 16px;
  color: transparent;
  background: transparent;
  caret-color: transparent;
}

#toast {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(env(safe-area-inset-bottom) + 130px);
  z-index: 30;
  max-width: 88vw;
  padding: 10px 14px;
  border-radius: 10px;
  font-size: 13px;
  line-height: 1.35;
  color: #ffe9e7;
  background: #52201d;
  border: 1px solid var(--danger);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
}
#toast[hidden] { display: none; }

/* --- compose ---------------------------------------------------------------
   Controls pinned to the top. On a phone the on-screen keyboard covers the
   bottom third, so anything important down there is unreachable. */

#compose {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: stretch;
  justify-content: center;
}
#compose[hidden] { display: none; }

.compose-panel {
  width: min(680px, 100%);
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--line);
  padding-top: max(8px, env(safe-area-inset-top));
}

.compose-bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
}

.compose-bar .compose-spacer { flex: 1; }
.compose-bar button { padding: 10px 16px; }

#compose-text {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  background: var(--bg);
  border: none;
  color: var(--text);
  padding: 12px;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 16px; /* 16px or iOS zooms on focus */
  line-height: 1.45;
  resize: none;
}
#compose-text:focus { outline: none; }

.compose-hint {
  flex: 0 0 auto;
  margin: 0;
  padding: 8px 12px max(8px, env(safe-area-inset-bottom));
  font-size: 11px;
  color: var(--muted);
  border-top: 1px solid var(--line);
}

.xterm .xterm-viewport { overscroll-behavior: contain; }

.empty {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--muted);
}
.empty[hidden] { display: none; }

/* --- key bar -------------------------------------------------------------- */

#keybar {
  flex: 0 0 auto;
  background: var(--panel);
  border-top: 1px solid var(--line);
  padding: 5px 5px max(5px, env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 5px;
}

/* Chips scroll: there are many, they are wide, and they are tapped rarely
   enough that tap detection (attachTap) is the right trade. */
.chips {
  display: flex;
  gap: 5px;
  overflow-x: auto;
  scrollbar-width: none;
}
.chips::-webkit-scrollbar { display: none; }

/* Keys share the row instead of scrolling. They fire on pointerdown so they
   feel like a real keyboard, which means a scrolling row would activate
   whichever key the scroll gesture started on.

   So they shrink to fit rather than overflow: the main row is sized to stay on
   one line on any phone down to 320px wide. flex-wrap is the safety net for
   narrower than that, and for the second row, which has too many keys to fit
   however they are sized. Wrapping is ugly; clipped keys would be unusable. */
.keyrow {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.keyrow[hidden] { display: none; }

.key {
  flex: 1 1 auto;
  min-width: 26px;
  height: var(--key-h);
  padding: 0 6px;
  white-space: nowrap;
  font-size: 14px;
  background: var(--panel-2);
  color: var(--text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  user-select: none;
  -webkit-user-select: none;
}

.key.mod.armed { background: var(--accent); color: #06121d; border-color: var(--accent); }

#dpad svg { width: 18px; height: 18px; fill: currentColor; }
#dpad.active { background: var(--accent); color: #06121d; border-color: var(--accent); }

/* The ring floats above the key bar rather than under the thumb. It is a
   read-out of which direction the gesture has selected, not a target you aim
   at: the gesture is measured relative to wherever the press landed. Putting it
   under the thumb would hide it behind the thumb, and near the bottom of a
   phone screen half of it would fall off the viewport. It never takes pointer
   events - the pad holds pointer capture for the whole gesture. */
#dpad-ring {
  position: fixed;
  left: var(--dpad-x, 50%);
  top: var(--dpad-y, 50%);
  transform: translate(-50%, -50%);
  width: 150px;
  height: 150px;
  border-radius: 50%;
  z-index: 60;
  pointer-events: none;
  background: rgba(12, 20, 28, 0.82);
  border: 1px solid var(--line);
  backdrop-filter: blur(2px);
}
#dpad-ring[hidden] { display: none; }

.dpad-dir {
  position: absolute;
  width: 46px;
  height: 46px;
  margin: -23px 0 0 -23px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  color: var(--text);
  background: var(--panel-2);
  border: 1px solid var(--line);
}
.dpad-dir[data-dir="ArrowUp"] { left: 50%; top: 27%; }
.dpad-dir[data-dir="ArrowDown"] { left: 50%; top: 73%; }
.dpad-dir[data-dir="ArrowLeft"] { left: 27%; top: 50%; }
.dpad-dir[data-dir="ArrowRight"] { left: 73%; top: 50%; }
.dpad-dir.on { background: var(--accent); color: #06121d; border-color: var(--accent); }

/* Read mode. The pill is both the indicator and the way out, because a mode you
   cannot see you are in, and cannot leave, is a trap. */
#reading-pill {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(var(--key-h) * 2 + 34px);
  z-index: 55;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 12px;
  background: var(--accent);
  color: #06121d;
  border: 0;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
}
#reading-pill[hidden] { display: none; }

/* Links are only worth marking when they can be tapped without the tap being
   taken for "give me the keyboard". */
body.reading .xterm .xterm-link-layer { cursor: pointer; }
body.reading #terminal-host { outline: 1px solid var(--accent-dim); outline-offset: -1px; }

/* Pinned open by a tap rather than held open by a drag, so now the arrows are
   real buttons and have to take pointer events. */
#dpad-ring.sticky { pointer-events: auto; border-color: var(--accent-dim); }
#dpad-ring.sticky .dpad-dir:active { background: var(--accent); color: #06121d; }

.chip {
  flex: 0 0 auto;
  height: 32px;
  padding: 0 11px;
  font-size: 12px;
  border-radius: 16px;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--muted);
  white-space: nowrap;
}

/* --- drawer --------------------------------------------------------------- */

#drawer {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  z-index: 20;
  display: flex;
}
#drawer[hidden] { display: none; }

.drawer-panel {
  width: min(340px, 88vw);
  height: 100%;
  background: var(--panel);
  border-right: 1px solid var(--line);
  padding: 14px 14px max(14px, env(safe-area-inset-bottom));
  padding-top: max(14px, env(safe-area-inset-top));
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.drawer-head { display: flex; align-items: center; justify-content: space-between; }
.drawer-head h2 { margin: 0; font-size: 13px; text-transform: uppercase; letter-spacing: 0.6px; color: var(--muted); }

.drawer-actions { display: flex; gap: 8px; }
.drawer-actions button { flex: 1; }

.cwd-row, .cmd-row { display: flex; flex-direction: column; gap: 5px; }
.cwd-row label, .cmd-row label { font-size: 12px; color: var(--muted); }
.cmd-input { display: flex; gap: 6px; }
.cmd-input input { flex: 1; }

.list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }

.list li {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 9px;
  padding: 9px 10px;
}

.list .meta { flex: 1; min-width: 0; }
.list .meta .name { font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.list .meta .sub { font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.list .status { font-size: 10px; padding: 2px 6px; border-radius: 10px; border: 1px solid var(--line); color: var(--muted); }
.list .status.busy { color: var(--ok); border-color: var(--ok); }
.list button { padding: 7px 10px; font-size: 12px; }
.list .empty-note { color: var(--muted); font-size: 12px; padding: 6px 2px; }

#chips-editor { display: flex; flex-direction: column; gap: 8px; }
#chips-editor[hidden] { display: none; }
#chips-editor .hint code {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 1px 4px;
  font-size: 11px;
}

#chips-text {
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 9px;
  color: var(--text);
  padding: 10px;
  font-family: Consolas, "Roboto Mono", monospace;
  font-size: 14px;
  line-height: 1.5;
  resize: vertical;
}
#chips-text:focus { outline: 2px solid var(--accent-dim); }

.switch { display: flex; align-items: center; gap: 9px; font-size: 12px; color: var(--muted); }
.switch input { width: 18px; height: 18px; accent-color: var(--accent); flex: 0 0 auto; }

/* Which machine you are driving. Worth a permanent spot once more than one
   host exists, because running a command on the wrong box is a real mistake. */
.host-label {
  flex: 0 0 auto;
  max-width: 90px;
  padding: 3px 7px;
  border-radius: 6px;
  font-size: 11px;
  color: var(--accent);
  background: #16222f;
  border: 1px solid var(--accent-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.list li.selected { border-color: var(--accent-dim); background: #1a2431; }

#pair { position: fixed; inset: 0; z-index: 45; background: rgba(0,0,0,0.65); display: flex; align-items: flex-start; justify-content: center; }
#pair[hidden] { display: none; }

.pair-panel { height: auto; max-height: 100%; }
.pair-body { padding: 14px; display: flex; flex-direction: column; gap: 12px; }
.pair-body code {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 1px 5px;
}
#pair-code {
  font-family: Consolas, "Roboto Mono", monospace;
  font-size: 20px;
  letter-spacing: 3px;
  text-align: center;
  text-transform: uppercase;
}

#totp {
  font-family: Consolas, "Roboto Mono", monospace;
  font-size: 18px;
  letter-spacing: 4px;
  text-align: center;
}
#totp-row[hidden] { display: none; }

/* Unpaired: make unavailable controls look unavailable rather than let them
   fail on tap, which only invites the same tap again. */
body.unpaired #keybar { opacity: 0.35; pointer-events: none; }
body.unpaired .icon-btn:disabled { opacity: 0.35; }

button:disabled { opacity: 0.45; cursor: not-allowed; }

#unpaired-state { padding: 24px; text-align: center; }
#unpaired-state[hidden] { display: none; }
.unpaired-title { margin: 0; font-size: 15px; color: var(--text); }
.unpaired-title span { color: var(--accent); }
.unpaired-hint { max-width: 34ch; margin: 0; }
.unpaired-hint code {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 1px 5px;
}

/* Landscape on a phone: every vertical pixel counts, so shrink the furniture. */
@media (orientation: landscape) and (max-height: 480px) {
  :root { --key-h: 34px; }
  #topbar { padding-top: 2px; }
  .icon-btn { height: 28px; }
  .chips { display: none; }
}
