/* Material Symbols (Apache 2.0), self-hosted as a subset of the glyphs the
   app uses. A glyph outside the subset renders as its literal name; to add
   one, see fonts/README.md. */
@font-face {
  font-family: "Material Symbols Outlined";
  font-style: normal;
  font-weight: 200 400;
  font-display: block;
  src: url(/fonts/MaterialSymbolsOutlined-subset.woff2) format("woff2");
}
/* Figtree (OFL), Latin only. Other scripts fall back to the system font. */
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url(/fonts/Figtree-VariableFont_wght.woff2) format("woff2");
}
.material-symbols {
  font-family: "Material Symbols Outlined";
  font-weight: normal;
  font-style: normal;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  display: inline-block;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
  font-variation-settings: "FILL" 0;
  -webkit-font-feature-settings: "liga";
  -webkit-font-smoothing: antialiased;
  user-select: none;
}
.material-symbols.fill {
  font-variation-settings: "FILL" 1;
}

/* Soft cards on a tinted page. One blue and one red, always with white
   text on them in both themes, and one green for finished rows. */
:root {
  --bg: #f3f6fb;
  --surface: #ffffff;
  --tonal: #e9eef6;
  --line: #e3e8ef;
  --text: #1f1f1f;
  --text-2: #5f6368;
  --text-3: #9aa0a6;
  --accent: #1e90ff;
  --on-accent: #ffffff;
  --good: #228b22;
  --bad: #dc143c;
  --on-bad: #ffffff;
  --shadow: 0 1px 2px rgba(60, 64, 67, 0.08), 0 1px 3px rgba(60, 64, 67, 0.06);
  --r: 16px;
  --q-row: 32px;
  /* The type scale. Every font-size in this file is one of these seven;
     no rule sets its own px value. */
  --font-small: 12px; /* labels, numbers, dates, sizes, statuses, separators */
  --font-body: 14px; /* the page default */
  --font-title: 16px; /* titles, the Transfers status line, the big Choose phone button */
  --font-heading: 24px; /* headings on the start page and help card */
  --icon: 20px; /* icons beside text or in small buttons */
  --icon-large: 24px; /* the icon heading a pane, the copy button, a message */
  --icon-hero: 44px; /* the start-page and folder-picker marks */
  /* The spacing scale. Every gap in this file is one of these three, and every
     padding is 4, 8, 12, 16, 24 or 32px. The few that are not are computed
     from a line height, a glyph or a button's inset, and say so where they
     are: .btn, .gh, .btn.icon, .btn.big, .steps, .cols and .toast. */
  --gap-tight: 4px; /* a label and its caret */
  --gap-small: 8px; /* an icon and its label, button rows, stacked blocks */
  --gap: 12px; /* the usual one: pane headers, file rows, the queue */
  --sans: "Figtree", system-ui, sans-serif;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #131314;
    --surface: #1e1f20;
    --tonal: #2d2f31;
    --line: #3c4043;
    --text: #e3e3e3;
    --text-2: #b4b8bc;
    --text-3: #80868b;
    --shadow: none;
  }
}

* {
  box-sizing: border-box;
}
html,
body {
  margin: 0;
  padding: 0;
}
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: var(--font-body);
  line-height: 1.4;
  height: 100dvh;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}
.shell {
  height: 100dvh;
  padding: 8px 16px;
  display: flex;
  flex-direction: column;
  gap: var(--gap-small);
}
[hidden] {
  display: none !important;
}
.spacer {
  flex: 1 1 auto;
  min-width: 8px;
}

/* top bar */
.top {
  display: flex;
  align-items: center;
  gap: var(--gap-small);
}
/* GitHub mark from primer/octicons (mark-github-16). The 3px and the 18px
   line are .btn's, so the pill matches the buttons beside it. */
.gh {
  display: flex;
  align-items: center;
  gap: var(--gap-small);
  padding: 3px 12px;
  border-radius: 999px;
  font-size: var(--font-body);
  font-weight: 500;
  line-height: 18px;
  background: var(--surface);
  color: var(--text);
  text-decoration: none;
}
.gh svg {
  width: 16px;
  height: 16px;
  fill: currentColor;
}
.app-title {
  font-size: var(--font-title);
  font-weight: 600;
  line-height: 22px;
  letter-spacing: -0.015em;
  white-space: nowrap;
  padding-left: 8px;
}
.meter {
  width: 90px;
  height: 6px;
  border-radius: 99px;
  background: var(--tonal);
  overflow: hidden;
  flex: none;
}
.meter span {
  display: block;
  height: 100%;
  background: var(--accent);
  border-radius: 99px;
}

/* controls */
button {
  font-family: var(--sans);
}
.btn {
  /* Buttons with this class are 24px tall: the 18px line-height plus the padding. The
     exceptions are the start page's Choose phone (.big) and the 32px Refresh (.reload). */
  padding: 3px 12px;
  border-radius: 999px;
  border: 0;
  background: var(--tonal);
  color: var(--text);
  font-size: var(--font-body);
  font-weight: 500;
  line-height: 18px;
  cursor: pointer;
  white-space: nowrap;
}
.btn:disabled {
  opacity: 0.45;
  cursor: default;
}
.btn.primary {
  background: var(--accent);
  color: var(--on-accent);
}
.btn.danger {
  background: var(--bad);
  color: var(--on-bad);
}
.btn.install {
  background: var(--accent);
  color: var(--on-accent);
  text-decoration: none;
}
/* No pill, like the Refresh button: the glyph carries it, and the 20px glyph in
   place of the 18px line of text keeps the height at 24px. */
.btn.icon {
  padding: 2px 6px;
  display: grid;
  place-items: center;
  background: transparent;
  color: var(--text-2);
}
.btn.icon .material-symbols {
  font-size: var(--icon);
}
/* 11px around the 18px line: a 40px button. */
.btn.big {
  padding: 11px 32px;
  font-size: var(--font-title);
  font-weight: 600;
}

/* help */
.help-card {
  max-width: 520px;
  border: 0;
  border-radius: 28px;
  padding: 24px 32px;
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow);
}
.help-card::backdrop {
  background: rgba(0, 0, 0, 0.35);
}
.help-card h2 {
  margin: 0 0 12px;
  font-size: var(--font-heading);
  font-weight: 700;
  letter-spacing: -0.02em;
  text-align: center;
}
.help-card .btn {
  display: block;
  margin: 0 auto;
}
.help-card ul {
  margin: 0 0 24px;
  padding-left: 24px;
  display: flex;
  flex-direction: column;
  gap: var(--gap-small);
  color: var(--text-2);
}
.help-card b {
  color: var(--text);
  font-weight: 600;
}
.help-card .version {
  margin: 12px 0 0;
  text-align: center;
  font-size: var(--font-small);
  color: var(--text-3);
}

/* connect */
.connect {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  overflow-y: auto;
  /* Runs to the window edge, so a cut-off card leaves no strip of page
     background below it. The shell's 8px bottom padding moves inside. */
  margin-bottom: -8px;
  padding: 8px 0;
}
/* A spacer under the card lifts it above true centre, which reads as
   centred. It gives way first when the window is short, so it never
   causes a scrollbar on its own. */
.connect::after {
  content: "";
  flex: 0 1 12dvh;
}
.connect-card {
  /* Auto margins centre the card, and drop to zero when it is taller
     than the window, so it starts at the top and scrolls instead of
     being cut off at both ends. */
  margin: auto 0;
  max-width: 480px;
  width: 100%;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  align-items: center;
  background: var(--surface);
  border-radius: 28px;
  box-shadow: var(--shadow);
  padding: 24px 32px;
}
/* The start screen mark: the Mac and the phone the two panes show, with
   the USB cable between them. */
.hero {
  display: flex;
  align-items: center;
  gap: var(--gap);
  color: var(--text);
}
.hero .material-symbols {
  font-size: var(--icon-hero);
}
.connect-card h1 {
  font-size: var(--font-heading);
  font-weight: 700;
  margin: 0;
  letter-spacing: -0.025em;
  line-height: 1.15;
  text-wrap: balance;
}
.connect-card p {
  margin: 0;
  color: var(--text-2);
  font-size: var(--font-body);
  text-wrap: balance;
}
/* Shown instead of the steps in a browser that cannot run the app. */
.notice {
  background: var(--bad);
  color: var(--on-bad);
  border-radius: 16px;
  padding: 12px 16px;
  font-size: var(--font-body);
  font-weight: 600;
  margin: 4px 0;
  white-space: pre-line; /* the text carries its own line break */
}
.steps {
  list-style: none;
  margin: 8px 0 6px;
  padding: 0;
  text-align: left;
  font-size: var(--font-body);
  color: var(--text-2);
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  width: 100%;
}
.steps li {
  display: grid;
  grid-template-columns: 26px 1fr;
  gap: var(--gap);
  align-items: start;
}
.steps li > span:first-child {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--on-accent);
  font-size: var(--font-small);
  font-weight: 700;
  display: grid;
  place-items: center;
}
.steps li > span:last-child {
  /* Centres the first line of text on the 26px number. */
  padding-top: 3px;
}
.steps b {
  color: var(--text);
  font-weight: 600;
}
.steps code {
  font-family: var(--sans);
  font-size: var(--font-body);
  font-weight: 600;
  color: var(--text);
  background: var(--tonal);
  /* Inline, so the 1px pads the chip without moving the lines apart. */
  padding: 1px 8px;
  border-radius: 6px;
}

/* panes */
.work {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: var(--gap-small);
}
.pane {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--surface);
  border-radius: var(--r);
  box-shadow: var(--shadow);
  overflow: hidden;
}
/* The pane icon, the refresh button and the row icons share one 32px column
   with a 12px gap, so icons and text line up down the pane. */
.pane-top {
  padding: 8px 16px;
  display: flex;
  flex-direction: column;
  gap: var(--gap-small);
}
.pane-label {
  display: flex;
  align-items: center;
  gap: var(--gap);
  /* Holds the row at the button height even before the Mac side has a folder
     and its buttons, so both panes' headers line up. */
  min-height: 24px;
}
.pane-label > .material-symbols {
  width: 32px;
  text-align: center;
  font-size: var(--icon-large);
  color: var(--accent);
  flex: none;
}
.pane-name {
  min-width: 0;
  font-size: var(--font-title);
  font-weight: 600;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pane-label .btn {
  flex: none;
}
/* The icon buttons are one group, so they sit tighter than the 12px that
   separates them from the pane's own button. */
.pane-tools {
  display: flex;
  flex: none;
  gap: var(--gap-tight);
}
.crumbs {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  font-size: var(--font-body);
  min-height: 32px;
}
.reload {
  width: 32px;
  height: 32px;
  padding: 0;
  /* With the crumb's 8px padding, the path text starts 12px after it. */
  margin-right: 4px;
  display: grid;
  place-items: center;
  background: transparent;
  color: var(--text-2);
}
.reload .material-symbols {
  font-size: var(--icon);
}
.reload.busy .material-symbols {
  animation: spin 1.4s linear infinite;
}
.crumb {
  background: none;
  border: 0;
  height: 28px;
  padding: 0 8px;
  border-radius: 999px;
  font: inherit;
  line-height: 28px;
  color: var(--text-2);
  cursor: pointer;
}
.crumb.here {
  color: var(--accent);
  font-weight: 600;
  cursor: default;
}
.sep {
  color: var(--text-3);
  user-select: none;
  font-size: var(--font-small);
}

.cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 80px 140px;
  gap: var(--gap);
  margin: 0 16px;
  /* Starts "Name" where the row names start: 16px + 32px icon + 12px gap. */
  padding: 4px 8px 4px 44px;
  border-bottom: 1px solid var(--line);
}
.col {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-size: var(--font-small);
  font-weight: 500;
  color: var(--text-3);
  text-align: left;
  display: flex;
  align-items: center;
  gap: var(--gap-tight);
}
.col.on {
  color: var(--text);
}
.col .caret {
  font-size: var(--icon);
  margin: -2px -3px;
}
.col.n {
  justify-content: flex-end;
}

.list {
  outline: none;
  flex: 1 1 auto;
  overflow-y: auto;
  min-height: 0;
  padding: 4px 8px;
}
.row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 80px 140px;
  gap: var(--gap);
  align-items: center;
  min-height: 34px;
  padding: 0 16px 0 8px;
  border-radius: 12px;
  cursor: default;
  user-select: none;
}
.row.on {
  background: var(--accent);
  color: var(--on-accent);
}
.row.on .size,
.row.on .date,
.row.on .name .material-symbols {
  color: var(--on-accent);
}
.name {
  display: flex;
  align-items: center;
  gap: var(--gap);
  min-width: 0;
}
.name .material-symbols {
  width: 32px;
  text-align: center;
  font-size: var(--icon);
  flex: none;
  color: var(--text-2);
}
.row.dir:not(.on) .name .material-symbols {
  color: var(--accent);
}
.name span {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: var(--font-body);
}
.row.dir .name span {
  font-weight: 500;
}
.size,
.date {
  font-size: var(--font-small);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: right;
}
/* Sits where the first row would be. */
.empty {
  padding: 32px 16px 24px;
  text-align: center;
  color: var(--text-3);
  font-size: var(--font-body);
}
.empty > p {
  margin: 0;
}
.pick {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gap);
}
.pick > .material-symbols {
  font-size: var(--icon-hero);
  color: var(--accent);
}
.pick p {
  margin: 0;
  max-width: 44ch;
  color: var(--text-2);
  text-wrap: balance;
}
.empty.busy {
  color: var(--text-2);
}
.pane-foot {
  padding: 4px 24px;
  /* 32px like the breadcrumb row, which also holds the height when the
     footer has nothing to say, so both panes line up with or without a
     folder. */
  min-height: 32px;
  display: flex;
  align-items: center;
  gap: var(--gap-small);
  font-size: var(--font-small);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}

/* copy button */
.gutter {
  display: flex;
  align-items: center;
  justify-content: center;
}
/* The label sits at the exact centre; the icon and count centre in the
   halves above and below it. Even heights keep all three on whole pixels. */
.go {
  width: 76px;
  height: 128px;
  display: grid;
  grid-template-rows: 1fr auto 1fr;
  justify-items: center;
  align-items: center;
  padding: 0 8px;
  background: var(--tonal);
  border: 0;
  border-radius: 24px;
  cursor: pointer;
  color: var(--text-3);
}
.go-label {
  font-size: var(--font-body);
  font-weight: 600;
  line-height: 16px;
}
/* Both hold their height while empty, so the label stays put whether or
   not anything is selected. */
.go-arrow {
  display: grid;
  place-items: center;
  height: 28px;
}
.go-arrow .material-symbols {
  font-size: var(--icon-large);
}
.go-count {
  font-size: var(--font-small);
  font-weight: 500;
  line-height: 14px;
  height: 14px;
  font-variant-numeric: tabular-nums;
  opacity: 0.85;
}
.go:enabled,
.go.busy {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: 0 4px 14px color-mix(in srgb, var(--accent) 35%, transparent);
}
.go:disabled {
  cursor: default;
}
/* While copying, the arrow repeatedly slides in the copy direction. */
.go.busy .go-arrow .material-symbols {
  --dir: 1;
  animation: nudge-x 1.1s ease-in-out infinite;
}
.go.busy.to-mac .go-arrow .material-symbols {
  --dir: -1;
}
@keyframes nudge-x {
  from {
    translate: calc(-16px * var(--dir)) 0;
    opacity: 0;
  }
  35%,
  65% {
    opacity: 1;
  }
  to {
    translate: calc(16px * var(--dir)) 0;
    opacity: 0;
  }
}
@keyframes nudge-y {
  from {
    translate: 0 calc(-6px * var(--dir));
    opacity: 0;
  }
  35%,
  65% {
    opacity: 1;
  }
  to {
    translate: 0 calc(6px * var(--dir));
    opacity: 0;
  }
}

/* transfers */
.queue {
  background: var(--surface);
  border-radius: var(--r);
  box-shadow: var(--shadow);
  flex: none;
  /* The bar plus one row, so an idle card is not mostly blank. */
  min-height: 84px;
  max-height: 32dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* A 24px row like a pane label's, with the 8px above and below that gives a
   pane's buttons their room: a 40px bar. */
.q-top {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--gap);
  padding: 8px 16px 8px 24px;
}
/* The panes' hairline, inset the 16px theirs is and drawn as a layer, so it
   adds nothing to the bar's height. */
.q-top::after {
  content: "";
  position: absolute;
  inset: auto 16px 0;
  border-bottom: 1px solid var(--line);
}
.q-title {
  font-size: var(--font-title);
  font-weight: 600;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.queue.active .q-top {
  background: var(--accent);
}
/* The blue already separates the bar from the list. */
.queue.active .q-top::after {
  display: none;
}
.queue.active .q-title,
.queue.active #q-sum {
  color: var(--on-accent);
}
/* Stop is disabled only while stopping; it stays full red instead of fading. */
#q-stop:disabled {
  background: var(--bad);
  color: var(--on-bad);
  opacity: 1;
}
.q-body {
  overflow-y: auto;
  padding: 4px 0 8px;
}
.q-row {
  display: grid;
  /* The first column holds the row number; app.js sets --q-digits to
     the digit count of the batch, so every row gets the same width. */
  grid-template-columns: calc(var(--q-digits, 1) * 1ch) 20px minmax(0, 1fr) 80px 96px 56px;
  /* Fixed, so app.js can size spacers for the rows it does not draw;
     even, so the 6px bar lands on whole pixels when centred. */
  height: var(--q-row);
  gap: var(--gap);
  align-items: center;
  padding: 0 24px;
}
.q-n {
  font-size: var(--font-small);
  color: var(--text-3);
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.q-row .material-symbols {
  font-size: var(--icon);
  color: var(--text-3);
}
.q-row.live .material-symbols {
  color: var(--accent);
  animation: spin 1.4s linear var(--spin-phase, 0ms) infinite;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
.q-row.done .material-symbols {
  color: var(--good);
}
.q-row.fail .material-symbols {
  color: var(--bad);
}
.q-name {
  font-size: var(--font-body);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.q-size {
  font-size: var(--font-small);
  color: var(--text-2);
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.bar {
  height: 6px;
  border-radius: 99px;
  background: var(--tonal);
  overflow: hidden;
}
.bar span {
  display: block;
  height: 100%;
  background: var(--accent);
  border-radius: 99px;
  transition: width 0.15s linear;
}
.q-row.done .bar span {
  background: var(--good);
}
.q-row.fail .bar span {
  background: var(--bad);
}
.q-row.stopped .bar span {
  background: var(--text-3);
}
.q-stat {
  font-size: var(--font-small);
  font-weight: 500;
  color: var(--text-2);
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.q-row.done .q-stat {
  color: var(--good);
}
.q-row.fail .q-stat {
  color: var(--bad);
}

/* alerts */
.toast {
  position: fixed;
  left: 50%;
  top: 8px; /* the shell's top padding: level with the header buttons */
  transform: translateX(-50%);
  max-width: min(560px, calc(100vw - 32px));
  background: var(--bad);
  color: var(--on-bad);
  border-radius: 16px;
  box-shadow:
    0 4px 8px rgba(0, 0, 0, 0.12),
    0 12px 32px rgba(0, 0, 0, 0.22);
  /* 40px right clears the 28px close button inset 8px; the left matches. */
  padding: 16px 40px;
  display: flex;
  flex-direction: column;
  gap: var(--gap-small);
  align-items: center;
  text-align: center;
  z-index: 9;
}
.toast .material-symbols {
  font-size: var(--icon-large);
}
.toast p {
  margin: 0;
  font-size: var(--font-body);
}
.toast b {
  display: block;
  font-size: var(--font-title);
  font-weight: 600;
  margin-bottom: 2px;
}
.toast button {
  background: none;
  border: 0;
  border-radius: 999px;
  color: inherit;
  cursor: pointer;
  line-height: 1;
  width: 28px;
  height: 28px;
  position: absolute;
  top: 8px;
  right: 8px;
  padding: 0;
  display: grid;
  place-items: center;
}
.toast button .material-symbols {
  font-size: var(--icon);
}

button:focus-visible,
.row:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.row:focus-visible {
  outline-offset: -2px;
}
.list::-webkit-scrollbar,
.q-body::-webkit-scrollbar {
  width: 12px;
}
.list::-webkit-scrollbar-thumb,
.q-body::-webkit-scrollbar-thumb {
  background: var(--line);
  border-radius: 99px;
  border: 3px solid transparent;
  background-clip: content-box;
}
/* Spinners keep turning: they signal activity, which the setting doesn't mean to hide. */
@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
  }
}

/* Narrow window: the panes stack and the copy button shortens. */
@media (max-width: 768px) {
  .shell {
    padding-inline: 12px;
  }
  .work {
    grid-template-columns: 1fr;
    grid-template-rows: 1fr auto 1fr;
  }
  .gutter {
    flex-direction: row;
    justify-content: center;
  }
  .go {
    height: 88px;
  }
  .go-arrow .material-symbols {
    transform: rotate(90deg);
  }
  /* Panes are stacked here, so the copy direction is vertical. */
  .go.busy .go-arrow .material-symbols {
    animation-name: nudge-y;
  }
  .cols,
  .row {
    grid-template-columns: minmax(0, 1fr) 64px 128px;
    gap: var(--gap-small);
  }
  .q-row {
    grid-template-columns: calc(var(--q-digits, 1) * 1ch) 20px minmax(0, 1fr) 64px 64px 48px;
    gap: var(--gap-small);
    padding-inline: 16px;
  }
  .q-top {
    padding-left: 16px;
  }
  .pane-foot .meter {
    width: 56px;
  }
  .connect-card {
    padding: 24px 16px;
  }
}
