/* JACKMN Beat Counter — Jackman People Solutions Pty Limited.
   Dark by design: this is meant to be read in a dim booth without lighting up
   the room, and to stay legible at arm's length on a phone propped by the mixer. */

/* ===== Reset & base ===== */
* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior: none;   /* no pull-to-refresh from an enthusiastic tap */
}

body { user-select: none; -webkit-user-select: none; }

button {
  font-family: inherit;
  color: inherit;
  border: none;
  background: none;
  cursor: pointer;
}

.hidden { display: none !important; }
/* Several of the new elements are display:flex, which would otherwise win
   against the hidden attribute. */
[hidden] { display: none !important; }

:root {
  --bg: #0d1117;
  --panel: #161c26;
  --panel-hi: #1e2735;
  --ink: #e8eef5;
  --ink-dim: #8d9bad;
  --line: #2a3444;
  --a: #2fb8a6;          /* left deck */
  --a-glow: rgba(47, 184, 166, 0.32);
  --b: #f0a13a;          /* right deck */
  --b-glow: rgba(240, 161, 58, 0.32);
  --radius: 16px;
  /* Safe areas keep the layout clear of the notch and the home indicator. */
  --pad-top: max(10px, env(safe-area-inset-top));
  --pad-bottom: max(10px, env(safe-area-inset-bottom));
  --pad-left: max(12px, env(safe-area-inset-left));
  --pad-right: max(12px, env(safe-area-inset-right));
}

#app {
  height: 100vh;
  height: 100dvh;        /* excludes the mobile browser chrome */
  display: flex;
  flex-direction: column;
  padding: var(--pad-top) var(--pad-right) var(--pad-bottom) var(--pad-left);
  gap: 10px;
}

/* ===== Top bar ===== */
.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 0 0 auto;
}
.brand-logo {
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}
.brand-home-link {
  border-radius: 6px;
  outline-offset: 4px;
}
.brand-home-link:hover { color: #ffffff; }
.brand-logo-svg { display: block; }
.app-title {
  margin: 0;
  font-size: clamp(15px, 2.4vw, 20px);
  font-weight: 600;
  letter-spacing: 0.2px;
  color: var(--ink-dim);
  flex: 1 1 auto;
}
.icon-btn {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  font-size: 17px;
  background: var(--panel);
  border: 1px solid var(--line);
  display: grid;
  place-items: center;
}
.icon-btn:hover { background: var(--panel-hi); }

/* ===== Decks ===== */
.decks {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  gap: 10px;
}
.deck {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.tap-zone {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  border-radius: var(--radius);
  background: var(--panel);
  border: 2px solid var(--line);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(2px, 1vh, 10px);
  padding: 12px;
  text-align: center;
  /* The readout scales to the panel, not the viewport — opening the audio input
     bar shrinks these panels, and viewport units cannot see that. */
  container-type: size;
  overflow: hidden;
  /* Kills the 300ms delay and, with it, double-tap-to-zoom on the panel. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 60ms linear, border-color 120ms linear, transform 60ms ease-out;
}
.tap-zone:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }

.deck-a .tap-zone.has-reading { border-color: var(--a); }
.deck-b .tap-zone.has-reading { border-color: var(--b); }

.deck-a .tap-zone.tapped { background: var(--panel-hi); box-shadow: inset 0 0 90px var(--a-glow); transform: scale(0.995); }
.deck-b .tap-zone.tapped { background: var(--panel-hi); box-shadow: inset 0 0 90px var(--b-glow); transform: scale(0.995); }

.tap-zone.idle { opacity: 0.6; }

.deck-label {
  font-size: clamp(10px, min(1.7vw, 2.6vh), 14px);
  letter-spacing: 2.4px;
  text-transform: uppercase;
  font-weight: 700;
}
.deck-a .deck-label { color: var(--a); }
.deck-b .deck-label { color: var(--b); }

.readout {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(2px, 0.9vh, 8px);
  width: 100%;
}

.bpm-block { display: flex; align-items: baseline; gap: 8px; }
.bpm {
  font-size: clamp(34px, min(12vw, 19vh), 116px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -2px;
  font-variant-numeric: tabular-nums;
}
.deck-a .settled .bpm { color: var(--a); }
.deck-b .settled .bpm { color: var(--b); }
.bpm-unit {
  font-size: clamp(11px, min(2vw, 3vh), 18px);
  font-weight: 700;
  color: var(--ink-dim);
  letter-spacing: 1px;
}

.beats-block { display: flex; align-items: baseline; gap: 7px; }
.beats {
  font-size: clamp(19px, min(5.6vw, 8vh), 46px);
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.beats-unit { font-size: clamp(10px, min(1.7vw, 2.6vh), 15px); color: var(--ink-dim); letter-spacing: 1px; }

.bar-line { font-size: clamp(10px, min(1.7vw, 2.6vh), 15px); color: var(--ink-dim); font-variant-numeric: tabular-nums; }

.phase { display: flex; gap: 7px; }
.pip {
  width: clamp(7px, min(1.7vw, 2.4vh), 13px);
  height: clamp(7px, min(1.7vw, 2.4vh), 13px);
  border-radius: 50%;
  background: var(--line);
}
.deck-a .pip.on { background: var(--a); }
.deck-b .pip.on { background: var(--b); }

.halfdouble {
  font-size: clamp(9px, min(1.5vw, 2.2vh), 13px);
  color: var(--ink-dim);
  font-variant-numeric: tabular-nums;
  min-height: 1em;
}
.hint {
  font-size: clamp(9px, min(1.5vw, 2.2vh), 13px);
  color: var(--ink-dim);
  min-height: 1.2em;
}

/* ===== Listening ===== */
.deck-head {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
}
.src-chip {
  font-size: clamp(8px, min(1.2vw, 1.8vh), 10px);
  letter-spacing: 1.2px;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--ink-dim);
  white-space: nowrap;
}
.deck-a .src-chip.live { color: var(--a); border-color: var(--a); }
.deck-b .src-chip.live { color: var(--b); border-color: var(--b); }

.meter {
  display: block;
  width: 55%;
  max-width: 200px;
  height: 4px;
  border-radius: 2px;
  background: var(--line);
  overflow: hidden;
}
.meter-fill {
  display: block;
  height: 100%;
  width: 0;
  background: var(--ink-dim);
  transition: width 80ms linear;
}
.deck-a .listening .meter-fill { background: var(--a); }
.deck-b .listening .meter-fill { background: var(--b); }

.deck-actions {
  width: 100%;
  display: flex;
  align-items: stretch;
  gap: 8px;
}
.deck-actions .reset-btn,
.deck-actions .listen-btn { flex: 1 1 0; min-width: 0; }
.deck-actions .mic-settings-btn {
  flex: 0 0 clamp(38px, 8vw, 46px);
  align-self: stretch;
}

.listen-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: clamp(8px, 1.6vh, 13px) 10px;
  border-radius: 12px;
  background: var(--panel);
  border: 1px solid var(--line);
  font-size: clamp(12px, 1.8vw, 15px);
  font-weight: 600;
  color: var(--ink-dim);
  touch-action: manipulation;
}
.listen-btn:hover:not(:disabled) { background: var(--panel-hi); color: var(--ink); }
.listen-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.listen-btn.on { color: var(--ink); background: var(--panel-hi); }
.deck-a .listen-btn.on { border-color: var(--a); }
.deck-b .listen-btn.on { border-color: var(--b); }

.mic-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--line);
  flex: 0 0 auto;
}
.listen-btn.on .mic-dot { background: #ff5f57; animation: mic-pulse 1.4s ease-in-out infinite; }
@keyframes mic-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

/* ===== Audio input bar ===== */
.audio-bar {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px;
  border-radius: 12px;
  background: var(--panel);
  border: 1px solid var(--line);
}
.audio-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.audio-label {
  font-size: 10px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--ink-dim);
  flex: 0 0 auto;
}
.audio-select {
  flex: 1 1 160px;
  min-width: 0;
  max-width: 100%;
  padding: 7px 8px;
  border-radius: 8px;
  background: #0f141c;
  color: var(--ink);
  border: 1px solid var(--line);
  font-family: inherit;
  font-size: 12px;
}
.chan {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1 1 210px;
  min-width: 0;
  max-width: 340px;
  font-size: 11px;
  color: var(--ink-dim);
}
#input-select { max-width: 420px; }
.audio-stop {
  flex: 0 0 auto;
  padding: 7px 14px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--panel-hi);
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-dim);
}
.audio-stop:hover { color: var(--ink); }
.audio-note-row {
  display: flex;
  align-items: center;
}
.audio-note-row[hidden] { display: none; }
.audio-note {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-dim);
}
.audio-note:empty { display: none; }
.audio-note.warn { color: var(--b); }
.audio-note.good { color: var(--a); }
.mic-settings-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  padding: 0;
  border-radius: 12px;
  border: 1px solid rgba(240, 161, 58, 0.7);
  background: rgba(240, 161, 58, 0.13);
  color: var(--ink);
  font-size: 18px;
  font-weight: 700;
  line-height: 1;
  touch-action: manipulation;
}
.mic-settings-btn:hover {
  border-color: var(--b);
  background: rgba(240, 161, 58, 0.22);
}
.mic-settings-icon {
  display: block;
  width: 20px;
  height: 20px;
  fill: currentColor;
}

/* Container query units let every line shrink together as the panel does.
   Where they are unsupported the whole declaration is invalid and the
   viewport-based sizes above stand, which is the correct fallback. */
@supports (height: 1cqh) {
  .tap-zone {
    gap: clamp(1px, 1.4cqh, 10px);
    padding: clamp(4px, 3cqh, 12px);
  }
  .readout { gap: clamp(1px, 1.2cqh, 8px); }
  .deck-label { font-size: clamp(9px, min(1.7vw, 5cqh), 14px); }
  .src-chip { font-size: clamp(8px, min(1.2vw, 4cqh), 10px); }
  .bpm { font-size: clamp(24px, min(12vw, 30cqh), 116px); }
  .bpm-unit { font-size: clamp(10px, min(2vw, 6cqh), 18px); }
  .beats { font-size: clamp(15px, min(5.6vw, 13cqh), 46px); }
  .beats-unit { font-size: clamp(9px, min(1.7vw, 4.5cqh), 15px); }
  .bar-line { font-size: clamp(9px, min(1.7vw, 4.5cqh), 15px); }
  .halfdouble { font-size: clamp(8px, min(1.5vw, 4cqh), 13px); }
  .hint { font-size: clamp(8px, min(1.5vw, 4cqh), 13px); }
  .pip {
    width: clamp(5px, min(1.7vw, 4cqh), 13px);
    height: clamp(5px, min(1.7vw, 4cqh), 13px);
  }
  .meter { height: clamp(3px, 1.5cqh, 5px); }
}

.reset-btn {
  flex: 0 0 auto;
  padding: clamp(8px, 1.6vh, 13px) 10px;
  border-radius: 12px;
  background: var(--panel);
  border: 1px solid var(--line);
  font-size: clamp(12px, 1.8vw, 15px);
  font-weight: 600;
  color: var(--ink-dim);
  touch-action: manipulation;
}
.reset-btn:hover { background: var(--panel-hi); color: var(--ink); }
.deck-a .reset-btn:active { border-color: var(--a); }
.deck-b .reset-btn:active { border-color: var(--b); }

/* ===== Controls ===== */
.controls {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.diff {
  font-size: clamp(11px, 1.7vw, 14px);
  color: var(--ink-dim);
  font-variant-numeric: tabular-nums;
  min-height: 1.2em;
}
.diff.matched { color: var(--a); font-weight: 600; }

.reset-all-btn {
  padding: clamp(9px, 1.6vh, 13px) 24px;
  border-radius: 12px;
  background: #24202b;
  border: 1px solid #4a3550;
  color: #e6d8ee;
  font-size: clamp(12px, 1.8vw, 15px);
  font-weight: 700;
  letter-spacing: 0.4px;
  touch-action: manipulation;
}
.reset-all-btn:hover { background: #322a3c; }

/* ===== Footer ===== */
.footer {
  flex: 0 0 auto;
  text-align: center;
  font-size: 11px;
  line-height: 1.6;
  color: #66738a;
  border-top: 1px solid var(--line);
  padding-top: 8px;
}
.footer a { color: #7fb6c8; }
.footer-brand { margin-top: 2px; }

/* On a short screen the small print costs beats-per-inch; keep only the line
   that carries the copyright and the links. */
@media (max-height: 620px) {
  .footer-note, .footer-links, .footer-support { display: none; }
  .app-title { display: none; }
}

/* Landscape on a phone: the panels get everything. */
@media (max-height: 460px) and (orientation: landscape) {
  .topbar { display: none; }
  .footer { font-size: 10px; padding-top: 4px; }
  #app { gap: 6px; }
  .tap-zone { padding: 6px; }
}

/* Short screens: the input bar tightens up so the decks keep their height. */
@media (max-height: 620px) {
  .audio-bar { padding: 7px 9px; gap: 5px; }
  .audio-row { gap: 6px; }
  .audio-select { padding: 5px 7px; font-size: 11px; }
  .audio-stop { padding: 5px 10px; font-size: 11px; }
  .audio-note { font-size: 10px; line-height: 1.4; }
  .deck-actions .mic-settings-btn { flex-basis: 36px; }
}

/* Narrow portrait: the small print is the first thing to give up room. */
@media (max-width: 560px) {
  .footer { font-size: 10px; }
  .footer-note { display: none; }
}

/* ===== Help overlay ===== */
.overlay {
  position: fixed;
  inset: 0;
  background: rgba(5, 8, 12, 0.82);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 20;
}
.overlay-panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px;
  max-width: 560px;
  width: 100%;
  max-height: 88vh;
  overflow-y: auto;
  font-size: 14px;
  line-height: 1.65;
  user-select: text;
  -webkit-user-select: text;
}
.overlay-panel h2 { margin: 0 0 10px; font-size: 19px; }
.overlay-panel ul { margin: 0 0 18px; padding-left: 20px; color: #c4cfdd; }
.overlay-panel li { margin-bottom: 8px; }
.overlay-panel kbd {
  background: var(--panel-hi);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 1px 6px;
  font-size: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.primary-btn {
  width: 100%;
  padding: 13px;
  border-radius: 12px;
  background: var(--a);
  color: #06231f;
  font-weight: 700;
  font-size: 15px;
}
.primary-btn:hover { background: #37cdb9; }

/* ===== Motion ===== */
@media (prefers-reduced-motion: reduce) {
  .tap-zone { transition: none; }
  .tap-zone.tapped { transform: none; }
  .meter-fill { transition: none; }
  .listen-btn.on .mic-dot { animation: none; }
}
