:root {
  --bg: #f4f6fb;
  --card: #ffffff;
  --text: #0f172a;
  --muted: #5b6b82; /* 5:1 on --bg, the darker of the two it is drawn on; text needs 4.5:1 */
  --border: #e2e8f0;
  --primary: #2563eb;
  --primary-text: #ffffff;
  --accent: #16a34a;
  --danger: #c81e1e; /* 5.3:1 on --bg, where the network check draws its ✗ */
  /* The network check's ✓ and !, text on --bg as well: --accent and an amber are 3:1 there. */
  --ok: #15803d;
  --warn: #b45309;
  /* What white text sits on: a primary button, an error toast. The dark scheme's --primary and
     --danger are lighter, to stand out on a dark page, and white on them is 3.7:1 and 2.8:1, under
     the 4.5:1 text needs; so these are set apart, and the button's blue is the same in both. */
  --primary-fill: #2563eb;
  --danger-fill: #dc2626;
  --track: #e2e8f0;
  --shadow: 0 1px 2px rgba(15, 23, 42, 0.06), 0 4px 16px rgba(15, 23, 42, 0.04);
  --radius: 14px;
  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0b1220;
    --card: #131c2e;
    --text: #e5e9f2;
    --muted: #94a3b8;
    --border: #243049;
    --primary: #3b82f6;
    --accent: #22c55e;
    --danger: #f87171;
    --ok: #22c55e;
    --warn: #d97706;
    --danger-fill: #b91c1c;
    --track: #243049;
    --shadow: none;
  }
}

* { box-sizing: border-box; }

[hidden] { display: none !important; }

html, body { margin: 0; padding: 0; }

body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.45;
  -webkit-text-size-adjust: 100%;
  padding-bottom: env(safe-area-inset-bottom);
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: calc(10px + env(safe-area-inset-top)) 16px 10px;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}

/* During a transfer the pill's speeds, and Install where the browser offers it, leave a phone's top bar
   short of room. The title gives way first, down to the icon, then the pill, to an ellipsis; Install
   and Settings never do, and nothing is drawn over anything else. */
.brand { display: flex; align-items: center; gap: 10px; flex: 1 1 0; min-width: 28px; }
.brand img { flex: none; }
.brand h1 { font-size: 1.1rem; margin: 0; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar-right { display: flex; align-items: center; gap: 8px; min-width: 0; }
.topbar-right > * { flex: none; }
.topbar-right > .pill { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

.pill {
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 3px 10px;
  white-space: nowrap;
}

.container {
  max-width: 760px;
  margin: 0 auto;
  padding: 16px 16px 48px;
  display: grid;
  gap: 16px;
}

/* A grid item is as wide as its widest unbreakable content by default, and a text input's is its
   intrinsic width: on a 320px screen that alone made the page scroll sideways. */
.container > * { min-width: 0; }

.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px;
}

.card h2 { margin: 0 0 12px; font-size: 1rem; }

.add-card.dragover { outline: 2px dashed var(--primary); outline-offset: 2px; }

.add-row { display: flex; gap: 8px; margin-bottom: 10px; }
.add-row input[type="text"], .add-row input[type="url"] {
  flex: 1;
  min-width: 0;
  font: inherit;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
}
.add-row input[type="text"]:focus, .add-row input[type="url"]:focus { outline: 2px solid var(--primary); outline-offset: 1px; }

.btn {
  font: inherit;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 16px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--text);
  cursor: pointer;
  touch-action: manipulation;
  min-height: 44px;
}
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn.primary { background: var(--primary-fill); border-color: var(--primary-fill); color: var(--primary-text); }
.btn.ghost { background: transparent; }
.btn.danger { border-color: var(--danger); color: var(--danger); background: transparent; }
.btn.small { padding: 6px 12px; min-height: 36px; font-size: 0.85rem; }
.file-btn { width: 100%; position: relative; overflow: hidden; }
.file-btn input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
/* The input is invisible, and so is the ring a keyboard's focus draws around it: its label shows it
   instead. Only for the keyboard (focus-visible), and on an engine without :has, for any focus. */
.file-btn:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 2px; }
@supports not selector(:has(*)) {
  .file-btn:focus-within { outline: 2px solid var(--primary); outline-offset: 2px; }
}
.file-btn:has(input:disabled) { opacity: 0.45; }
.file-btn input:disabled { cursor: not-allowed; }

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.icon-btn:hover { background: var(--bg); color: var(--text); }

.hint { color: var(--muted); font-size: 0.85rem; margin: 6px 0 0; }
.hint code { font-family: ui-monospace, monospace; }

.empty { text-align: center; color: var(--muted); padding: 24px 8px; }

.torrents { display: grid; gap: 16px; }

.torrent-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.torrent-title { min-width: 0; }
.torrent .name { margin: 0; font-size: 1rem; overflow-wrap: anywhere; }
.torrent .meta { color: var(--muted); font-size: 0.8rem; margin-top: 2px; }

.progress {
  height: 8px;
  border-radius: 999px;
  background: var(--track);
  overflow: hidden;
  margin: 12px 0 6px;
}
.progress .bar { height: 100%; width: 0%; background: var(--primary); transition: width 0.3s ease; }
.torrent.done .progress .bar { background: var(--accent); }

.stats {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  font-size: 0.8rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.stats .pct { color: var(--text); font-weight: 600; }

/* Five buttons do not fit on one line of a narrow card at any width, so the row always wraps. */
.actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 8px; }
.actions .zip-btn { flex: 1; }

.files { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.file {
  display: grid;
  grid-template-columns: 1fr auto auto;
  grid-template-areas:
    "check size save"
    "prog  prog save";
  gap: 4px 10px;
  align-items: center;
  padding: 8px 4px;
  border-top: 1px solid var(--border);
}
.file-check { grid-area: check; display: flex; align-items: center; gap: 10px; min-width: 0; cursor: pointer; }
.file-check input { width: 20px; height: 20px; margin: 0; accent-color: var(--primary); flex: none; }
.file-name { font-size: 0.9rem; overflow-wrap: anywhere; }
.file-size { grid-area: size; font-size: 0.8rem; color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.file-progress { grid-area: prog; height: 4px; border-radius: 999px; background: var(--track); overflow: hidden; }
.file-progress .bar { height: 100%; width: 0%; background: var(--primary); transition: width 0.3s ease; }
.file.done .file-progress .bar { background: var(--accent); }
.file.deselected { opacity: 0.55; }
.save-btn { grid-area: save; }

.dialog {
  border: none;
  border-radius: var(--radius);
  padding: 0;
  background: var(--card);
  color: var(--text);
  width: min(92vw, 520px);
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
}
.dialog::backdrop { background: rgba(0, 0, 0, 0.5); }
.dialog-body { padding: 20px; display: grid; gap: 14px; }
.dialog-body h2 { margin: 0; font-size: 1.1rem; }
.field { display: grid; gap: 6px; }
.field > span:not(.hint) { font-weight: 600; font-size: 0.9rem; }
.field textarea {
  font: 0.85rem ui-monospace, monospace;
  padding: 10px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  resize: vertical;
}
.dialog-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }

.toasts {
  position: fixed;
  left: 50%;
  bottom: calc(16px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  display: grid;
  gap: 8px;
  width: min(92vw, 480px);
  z-index: 10;
  pointer-events: none;
}
.toast {
  background: var(--text);
  color: var(--bg);
  padding: 12px 16px;
  border-radius: 12px;
  font-size: 0.9rem;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.25);
  animation: toast-in 0.2s ease;
}
.toast.error { background: var(--danger-fill); color: #fff; }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.notice.error { color: var(--danger); }
.tab-panel > .notice { margin: 0 0 12px; font-size: 0.9rem; }

@media (max-width: 480px) {
  .actions .zip-btn { flex-basis: 100%; }
  .actions .ghost { flex: 1; }
}

/* ---- tabs ---- */
.tabs { display: flex; gap: 4px; background: var(--bg); border-radius: 10px; padding: 4px; margin-bottom: 14px; }
.tab {
  flex: 1; font: inherit; font-weight: 600; padding: 9px 12px; border-radius: 8px; border: none;
  background: transparent; color: var(--muted); cursor: pointer; min-height: 40px; min-width: 0;
}
/* Three tabs on a 320px screen (an iPhone SE, or any iPhone with Display Zoom) are wider than the
   card at the usual padding, and the whole page would scroll sideways. */
@media (max-width: 360px) {
  .tab { padding: 9px 4px; font-size: 0.9rem; }
}
.tab.active { background: var(--card); color: var(--text); box-shadow: var(--shadow); }

/* ---- torrent head actions ---- */
.head-actions { display: flex; gap: 2px; flex: none; }
.torrent .ic-play { display: none; }
.torrent.paused .ic-play { display: block; }
.torrent.paused .ic-pause { display: none; }
.torrent.paused .progress .bar { background: var(--muted); }
.torrent.seeding .progress .bar { background: var(--accent); }

/* ---- details ---- */
.details { border-top: 1px solid var(--border); margin-top: 10px; padding-top: 12px; display: grid; gap: 12px; }
.kv { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px; margin: 0; font-size: 0.85rem; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; overflow-wrap: anywhere; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.8rem; }
.details-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.log { list-style: none; margin: 0; padding: 8px 10px; background: var(--bg); border-radius: 8px; font-size: 0.75rem; color: var(--muted); display: grid; gap: 2px; max-height: 140px; overflow: auto; }
.log li { overflow-wrap: anywhere; }

.toggle { display: flex; align-items: center; gap: 10px; font-size: 0.9rem; cursor: pointer; }
.toggle input { width: 20px; height: 20px; margin: 0; accent-color: var(--primary); flex: none; }
.field .hint { margin: 0; }

@media (max-width: 480px) {
  .actions .ghost { flex: 1; }
}

/* seeding cards: the files are already on this device */
.torrent.seeding .zip-btn,
.torrent.seeding .select-all-btn,
.torrent.seeding .select-none-btn,
.torrent.seeding .file-progress,
.torrent.seeding .save-btn { display: none; }
.torrent.seeding .file { grid-template-areas: "check size"; grid-template-columns: 1fr auto; }
.torrent.seeding .file-check input { display: none; }
/* Sharing is not only for what you seed: a torrent you are downloading is one
   more peer for whoever you send it to. */
.share-link-btn { flex: 1; }

/* ---- settings extras ---- */
.field input[type="url"], .field input[type="text"], .field input[type="number"], .field select {
  font: inherit; padding: 10px 12px; border-radius: 10px; border: 1px solid var(--border);
  background: var(--bg); color: var(--text); min-width: 0; width: 100%;
}
.two-col { grid-template-columns: 1fr 1fr; }
@media (max-width: 420px) { .two-col { grid-template-columns: 1fr; } }
#install-btn { min-height: 34px; padding: 6px 12px; }

/* ---- no peers hint ---- */
.nopeers { margin-top: 10px; padding: 10px 12px; border-radius: 10px; background: var(--bg); border: 1px dashed var(--border); display: grid; gap: 8px; }
.nopeers .hint { margin: 0; }

/* ---- simple / expert ---- */
.mode-switch { display: flex; gap: 6px; padding: 4px; background: var(--bg); border-radius: 10px; }
.mode-switch .tab { flex: 1; }

/* ---- sharing: the link itself, not a message about it ---- */
.share-panel { margin-top: 10px; padding: 10px 12px; border-radius: 10px; background: var(--bg); border: 1px solid var(--border); display: grid; gap: 10px; }
.share-row { display: grid; gap: 4px; font-size: 0.85rem; color: var(--muted); }
.share-panel .hint { margin: 0; }
.share-field { display: flex; gap: 6px; align-items: center; }
/* width: 0, and flex: 1 fills the row: at its own width, twenty characters (more at the 16px an
   iPhone gets), the field set how narrow its card could be, and at 320px that was wider than the screen. */
.share-field input {
  flex: 1; min-width: 0; width: 0; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--card); color: var(--text); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.8rem;
}

/* ---- cloud library ---- */
.cloud-library { display: grid; gap: 10px; }
.cloud-library h2 { margin: 0; font-size: 1rem; }
.cloud-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.cloud-item { display: grid; gap: 8px; padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px; background: var(--bg); }
.cloud-item.ready { border-color: var(--accent); }
.cloud-item-head { display: flex; gap: 10px; align-items: flex-start; justify-content: space-between; }
.cloud-item-name { font-weight: 600; overflow-wrap: anywhere; }
.cloud-item-meta { color: var(--muted); font-size: 0.85rem; }
.cloud-item-files { display: grid; gap: 8px; }
.cloud-file { display: grid; gap: 6px; padding: 8px 0; border-top: 1px solid var(--border); }
.cloud-file-name { overflow-wrap: anywhere; }
.cloud-file-size { color: var(--muted); font-size: 0.85rem; }
.cloud-file-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.cloud-file-actions a { text-decoration: none; }
.cloud-player video, .cloud-player audio { width: 100%; border-radius: 8px; background: #000; }

/* ---- cloud fetch ---- */
.cloud { margin-top: 10px; padding: 10px 12px; border-radius: 10px; background: var(--bg); border: 1px solid var(--border); display: grid; gap: 8px; }
.cloud .hint { margin: 0; }
.cloud-files { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.cloud-files a { display: block; text-align: left; overflow-wrap: anywhere; text-decoration: none; }

/* ---- network check ---- */
.netcheck { list-style: none; margin: 0; padding: 8px 10px; background: var(--bg); border-radius: 8px; font-size: 0.8rem; display: grid; gap: 4px; }
.netcheck li { display: grid; grid-template-columns: 1.2em 1fr; gap: 6px; overflow-wrap: anywhere; }
.netcheck .ok { color: var(--ok); }
.netcheck .bad { color: var(--danger); }
.netcheck .warn { color: var(--warn); }

/* ---- iOS: second tap to share a prepared file ---- */
.save-ready {
  position: fixed; left: 50%; bottom: calc(16px + env(safe-area-inset-bottom)); transform: translateX(-50%);
  display: flex; gap: 8px; align-items: center; width: min(92vw, 480px); padding: 10px;
  background: var(--card); border: 1px solid var(--border); border-radius: 14px; box-shadow: 0 8px 30px rgba(0,0,0,0.25); z-index: 11;
}
/* The button names the file, and a release name (The.Show.S01E01.1080p.WEB.h264-GROUP.mkv) has
   nowhere to break: it wraps anywhere rather than push Cancel off the screen. */
.save-ready .primary { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.save-ready .ghost { flex: none; }

/* ---- settings: a field that cannot be saved says so next to Save ---- */
#settings-error { margin: 0; color: var(--danger); }

/* ---- iOS zooms into a text field under 16px as it takes focus, and stays zoomed. Set here for
   iOS alone and always, not on :focus, so nothing jumps in size under the finger. ---- */
@supports (-webkit-touch-callout: none) {
  .field input, .field textarea, .field select, .share-field input { font-size: 16px; }
}

/* ---- The installed app on an iPhone gets its status bar drawn over the top of the page
   (black-translucent in index.html, which lets the top bar reach under it), and that status bar is
   always white. In light mode the strip under the clock and battery is dark, or they vanish into the
   top bar. Everywhere else the inset is 0, and so is the strip. ---- */
@supports (-webkit-touch-callout: none) {
  @media (prefers-color-scheme: light) {
    .topbar { padding-top: 10px; border-top: env(safe-area-inset-top) solid #0f172a; }
  }
}
