/* voice2midi.

   One accent, one surface, one border colour, and a type scale with four steps
   in it. Everything on the page is built from those, which is why it holds
   together — a tool with thirty controls goes wrong by giving each of them its
   own treatment, not by being plain.

   Both themes are defined here rather than one being derived from the other,
   because the roll is drawn in a canvas and has to read the same values. */

:root {
  color-scheme: dark light;

  --bg:        #0d0f13;
  --bg-2:      #12151b;
  --surface:   #161a21;
  --surface-2: #1c212a;
  --line:      #262c37;
  --line-soft: #1e232c;

  --ink:       #e8ecf3;
  --ink-2:     #a7b0c0;
  --ink-3:     #6d7787;

  --accent:      #6ea8fe;
  --accent-ink:  #08111f;
  --accent-soft: rgba(110, 168, 254, 0.14);
  --rec:         #ff5c67;
  --rec-soft:    rgba(255, 92, 103, 0.14);
  --ok:          #57d9a3;
  --warn:        #ffc46b;

  --r-sm: 7px;
  --r:    11px;
  --r-lg: 16px;

  --pad:  18px;
  --gap:  14px;

  --font: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Inter,
          Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px -12px rgba(0,0,0,.6);

  /* Names the scripts use.

     app.js sets a handful of colours inline — the tuner needle turning green
     when a note is in tune, the note name changing while a preview plays — and
     it should not have to know which of the palette entries above happens to
     mean "good" this week. These are the semantic names; the palette is the
     implementation. */
  --good:  var(--ok);
  --play:  var(--ok);
  --faint: var(--ink-3);
}

@media (prefers-color-scheme: light) {
  :root {
    --bg:        #f7f8fa;
    --bg-2:      #ffffff;
    --surface:   #ffffff;
    --surface-2: #f1f3f7;
    --line:      #e0e4ec;
    --line-soft: #eceff5;

    --ink:       #131720;
    --ink-2:     #545d6e;
    --ink-3:     #8a93a3;

    --accent:      #2f6fe4;
    --accent-ink:  #ffffff;
    --accent-soft: rgba(47, 111, 228, 0.10);
    --rec:         #dc3545;
    --rec-soft:    rgba(220, 53, 69, 0.10);
    --ok:          #17916a;
    --warn:        #a86b12;

    --shadow: 0 1px 2px rgba(16,24,40,.06), 0 8px 24px -14px rgba(16,24,40,.18);
  }
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 14px/1.55 var(--font);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

b, strong { font-weight: 600; }

/* ── top bar ───────────────────────────────────────────── */

.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap);
  padding: 12px 22px;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: saturate(160%) blur(12px);
  border-bottom: 1px solid var(--line-soft);
}

.brand {
  display: flex;
  align-items: center;
  gap: 11px;
  text-decoration: none;
  color: inherit;
}

.mark {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: linear-gradient(145deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #a78bfa));
  color: var(--accent-ink);
}
.mark svg { width: 19px; height: 19px; }

.brand-text { display: flex; flex-direction: column; line-height: 1.2; }
.brand-text b { font-size: 15px; letter-spacing: -0.01em; }
.brand-text small { color: var(--ink-3); font-size: 11.5px; }

.topbar-end { display: flex; align-items: center; gap: 10px; min-width: 0; }

/* On a narrow screen the status line is the thing that overflows, because it is
   the only element on the bar whose width is content rather than design. It gets
   its own row rather than a smaller font: a status that has to be squinted at is
   not a status. */
@media (max-width: 620px) {
  .topbar { flex-wrap: wrap; padding: 10px 16px; }
  .topbar-end { width: 100%; order: 3; justify-content: space-between; }
  .status { max-width: none; flex: 1 1 auto; }
}

.status {
  min-width: 0;
  font-size: 12.5px;
  color: var(--ink-2);
  padding: 5px 11px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--line-soft);
  max-width: 46ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.status.is-error { color: var(--rec); border-color: color-mix(in srgb, var(--rec) 40%, transparent); }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  color: var(--ink-3);
  padding: 4px 9px;
  border-radius: 999px;
  border: 1px solid var(--line-soft);
}
.badge svg { width: 12px; height: 12px; }

/* ── layout ────────────────────────────────────────────── */

.layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: 22px;
  align-items: start;
  max-width: 1560px;
  margin: 0 auto;
  padding: 22px;
}

@media (max-width: 620px) { .layout { padding: 14px; gap: 14px; } }

@media (max-width: 1080px) {
  .layout { grid-template-columns: minmax(0, 1fr); }
}

.stage { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.inspector { display: flex; flex-direction: column; gap: 14px; position: sticky; top: 74px; }
@media (max-width: 1080px) { .inspector { position: static; } }

/* ── cards ─────────────────────────────────────────────── */

.card {
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  padding: var(--pad);
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.card-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.card-head h2 {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* ── buttons ───────────────────────────────────────────── */

.btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 13px;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background .13s, border-color .13s, color .13s, transform .06s;
  white-space: nowrap;
}
.btn:hover:not(:disabled) { background: color-mix(in srgb, var(--surface-2) 70%, var(--ink) 6%); }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:disabled { opacity: .4; cursor: default; }
.btn.small { padding: 5px 10px; font-size: 12px; }
.btn.ghost { background: transparent; border-color: var(--line-soft); color: var(--ink-2); }
.btn.ghost:hover:not(:disabled) { background: var(--surface-2); color: var(--ink); }

.btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.btn.primary:hover:not(:disabled) { background: color-mix(in srgb, var(--accent) 88%, #fff); }

.btn .icon { width: 14px; height: 14px; fill: currentColor; flex: none; }
.btn.is-playing { border-color: var(--accent); color: var(--accent); }

:where(button, select, input, a):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ── transport ─────────────────────────────────────────── */

.transport {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-wrap: wrap;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
}
.transport-gap { flex: 1 1 12px; }

.record {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 9px 17px 9px 14px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.record:hover:not(:disabled) { border-color: color-mix(in srgb, var(--rec) 55%, var(--line)); }
.record:disabled { opacity: .5; cursor: default; }
.record .dot {
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--rec);
  flex: none;
  box-shadow: 0 0 0 0 var(--rec-soft);
}
.record.recording { background: var(--rec-soft); border-color: var(--rec); color: var(--rec); }
.record.recording .dot { animation: pulse 1.5s ease-out infinite; }

@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--rec) 55%, transparent); }
  70%  { box-shadow: 0 0 0 9px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .record.recording .dot { animation: none; }
}

.toggle-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 11px;
  font-size: 12.5px;
  color: var(--ink-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  cursor: pointer;
  user-select: none;
}
.toggle-chip:has(input:checked) { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, transparent); background: var(--accent-soft); }
.toggle-chip input { accent-color: var(--accent); margin: 0; }

/* ── counters ──────────────────────────────────────────── */

.counters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
}
.counters > div {
  flex: 1 1 96px;
  padding: 10px 13px;
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--r);
}
.counters dt {
  font-size: 10.5px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.counters dd {
  margin: 2px 0 0;
  font: 600 19px/1.15 var(--mono);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.counters dd.dim { color: var(--ink-3); font-weight: 500; }
.counters .pos dd { color: var(--accent); }

/* ── piano roll ────────────────────────────────────────── */

/* The roll keeps its own dark surface in both themes.

   It is a canvas, so its colours are drawn rather than inherited, and every DAW
   a person will paste this MIDI into shows a dark piano roll. Making the frame
   match what is drawn inside it is less jarring than a white card wrapped around
   a black picture. */
.roll-wrap {
  position: relative;
  background: #0b0f15;
  --ink-2: #a7b0c0;
  --ink-3: #6d7787;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--shadow);
}

#roll {
  display: block;
  width: 100%;
  height: 460px;
  touch-action: none;
}
@media (max-width: 700px) { #roll { height: 320px; } }

.roll-empty {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  text-align: center;
  gap: 5px;
  pointer-events: none;
  padding: 20px;
}
.roll-empty-title { margin: 0; font-size: 16px; font-weight: 600; color: var(--ink-2); }
.roll-empty-sub { margin: 0; font-size: 13px; color: var(--ink-3); }
.roll-empty[hidden] { display: none; }

/* transcription progress */
.busy {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(11, 15, 21, .74);
  backdrop-filter: blur(3px);
}
.busy[hidden] { display: none; }
.busy-inner { width: min(340px, 76%); display: flex; flex-direction: column; gap: 9px; }
.busy-label { display: flex; justify-content: space-between; font-size: 12.5px; color: var(--ink-2); }
.busy-label b { font-variant-numeric: tabular-nums; color: var(--ink); }

.progress {
  height: 5px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .12);
  overflow: hidden;
}
.progress-bar {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--accent);
  transition: width .18s ease-out;
}

/* ── roll tools ────────────────────────────────────────── */

.rolltools {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.rolltool-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.selcount { font-size: 12.5px; color: var(--ink-3); }

.legend {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  font-size: 11.5px;
  color: var(--ink-3);
}
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.swatch { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }
.swatch.origin  { background: var(--accent); }
.swatch.note    { background: #7c8ba1; }
.swatch.live    { background: var(--rec); }
.swatch.playing { background: var(--ok); }
.swatch.trace   { background: var(--warn); }

.help { font-size: 12.5px; color: var(--ink-3); }
.help summary { cursor: pointer; color: var(--ink-2); width: fit-content; }
.help p { margin: 8px 0 0; line-height: 1.7; max-width: 78ch; }

kbd {
  font: 500 11px/1 var(--mono);
  padding: 2px 5px;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 4px;
  background: var(--surface-2);
  color: var(--ink-2);
}

/* ── fields ────────────────────────────────────────────── */

.field { display: flex; flex-direction: column; gap: 6px; }
.field-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink-2);
}
.field-head b { font: 600 12px/1 var(--mono); color: var(--ink); font-variant-numeric: tabular-nums; }

.hint { font-size: 11.5px; line-height: 1.6; color: var(--ink-3); }

input[type="number"], select {
  appearance: none;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 7px 10px;
  width: 100%;
}
select {
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%),
                    linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
  background-position: right 13px center, right 8px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 28px;
}
input[type="number"] { font-family: var(--mono); font-variant-numeric: tabular-nums; }

input[type="range"] {
  appearance: none;
  width: 100%;
  height: 20px;
  background: transparent;
  cursor: pointer;
}
input[type="range"]::-webkit-slider-runnable-track {
  height: 4px; border-radius: 999px; background: var(--surface-2); border: 1px solid var(--line-soft);
}
input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  width: 15px; height: 15px; margin-top: -6.5px;
  border-radius: 50%;
  background: var(--ink);
  border: 3px solid var(--surface);
  box-shadow: 0 0 0 1px var(--line);
}
input[type="range"]::-moz-range-track {
  height: 4px; border-radius: 999px; background: var(--surface-2); border: 1px solid var(--line-soft);
}
input[type="range"]::-moz-range-thumb {
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--ink); border: 3px solid var(--surface);
}

.check { display: flex; align-items: flex-start; gap: 9px; font-size: 13px; cursor: pointer; }
.check input { accent-color: var(--accent); margin: 2px 0 0; flex: none; }
.check .dim { color: var(--ink-3); font-family: var(--mono); font-size: 12px; }

.row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 460px) { .row-2 { grid-template-columns: 1fr; } }

.inline { display: flex; gap: 5px; align-items: center; }
.inline input[type="number"] { width: 4.6em; }

.apply { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* what the analysis found */
.analysis {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 3px 12px;
  padding-top: 12px;
  border-top: 1px solid var(--line-soft);
  font-size: 11.5px;
  color: var(--ink-3);
}
.analysis[hidden] { display: none; }
.analysis dt { color: var(--ink-3); }
.analysis dd { margin: 0; font-family: var(--mono); color: var(--ink-2); font-variant-numeric: tabular-nums; }

/* ── file panel ────────────────────────────────────────── */

.file-panel { border-color: color-mix(in srgb, var(--accent) 30%, var(--line-soft)); }
.file-panel[hidden] { display: none; }
.file-panel .card-head b { font-size: 14px; }
.file-panel .card-head .hint { margin-left: 8px; }
.file-range { display: flex; gap: 9px; align-items: flex-end; flex-wrap: wrap; }
.file-range .field { flex: 0 1 110px; }

/* ── live card ─────────────────────────────────────────── */

.live-card { transition: opacity .25s; }
.live-card.idle { opacity: .55; }

.now { display: flex; align-items: baseline; gap: 11px; }
.now-note {
  font: 600 34px/1 var(--font);
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.now-freq { font: 400 13px/1 var(--mono); color: var(--ink-3); }

.tuner { display: flex; flex-direction: column; gap: 6px; }
.tuner-track {
  position: relative;
  height: 28px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  border: 1px solid var(--line-soft);
  overflow: hidden;
}
.tuner-tick { position: absolute; top: 7px; bottom: 7px; width: 1px; background: var(--line); }
.tuner-center { position: absolute; left: 50%; top: 3px; bottom: 3px; width: 1px; background: var(--ink-3); }
.tuner-needle {
  position: absolute;
  top: 4px; bottom: 4px;
  left: 50%;
  width: 3px;
  margin-left: -1.5px;
  border-radius: 2px;
  background: var(--accent);
  transition: left .07s linear, background .12s;
}
.tuner-needle.near { background: var(--ok); }
.tuner-scale {
  display: flex;
  justify-content: space-between;
  font: 11px/1 var(--mono);
  color: var(--ink-3);
}
.cents { color: var(--ink-2); font-variant-numeric: tabular-nums; }

.meters { display: flex; flex-direction: column; gap: 7px; }
.meter-row { display: grid; grid-template-columns: 78px 1fr; align-items: center; gap: 10px; }
.meter-label { font-size: 11px; color: var(--ink-3); }
.meter {
  height: 5px;
  border-radius: 999px;
  background: var(--surface-2);
  overflow: hidden;
}
.bar { display: block; height: 100%; width: 0; background: var(--accent); border-radius: 999px; transition: width .08s linear; }
.bar.level { background: var(--ok); }

/* ── footer ────────────────────────────────────────────── */

.foot {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 20px;
  max-width: 1560px;
  margin: 0 auto;
  padding: 20px 22px 36px;
  font-size: 11.5px;
  color: var(--ink-3);
  border-top: 1px solid var(--line-soft);
}
.foot b { color: var(--ink-2); font-family: var(--mono); }

/* ── drop zone ─────────────────────────────────────────── */

.dropzone {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: blur(4px);
}
.dropzone[hidden] { display: none; }
.dropzone > div {
  padding: 40px 56px;
  border: 2px dashed var(--accent);
  border-radius: var(--r-lg);
  background: var(--surface);
  font-size: 17px;
  font-weight: 600;
  color: var(--ink);
}
