/* Shared palette (--bg, --bg-panel, --accent, --text, --text-dim, --warn, …)
   comes from /theme.css, linked before this file. --seg-off is Wavelets-only. */
:root {
  --seg-off: #23252f;  /* unlit meter segment */
}

* {
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
}

html, body {
  height: 100%;
  margin: 0;
  overscroll-behavior: none;
}

/* Mobile-portrait-first: don't let the OS inflate text on rotation/zoom. */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  user-select: none;
}

/* Phone-portrait column: fills the screen on a phone, and on wider screens
   stays a centred column instead of stretching edge-to-edge (Matkompis-style). */
.app {
  min-height: 100dvh; /* fills the viewport in portrait, but can grow taller (landscape) so the page scrolls to reach everything instead of clipping */
  max-width: 640px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
}

.topbar {
  padding: env(safe-area-inset-top, 16px) 16px 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.topbar h1 {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.tabs {
  display: flex;
  gap: 8px;
  flex-wrap: wrap; /* five tabs: wrap to a second row rather than overflow on a narrow phone */
  justify-content: center;
}

.tab-btn {
  appearance: none;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-dim);
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
}

.tab-btn.active {
  color: var(--accent);
  border-color: var(--accent-dim);
  background: var(--bg-panel);
}

.content {
  flex: 1 0 auto; /* grow to center the graph when there's room (portrait); never shrink below its content, so in landscape the app grows and the page scrolls rather than clipping the text above the graph */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  padding: 24px;
}

.view {
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  width: 100%;
}

.view.active {
  display: flex;
}

.meters {
  display: flex;
  gap: 32px;
}

.meter-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.meter {
  display: flex;
  flex-direction: column-reverse;
  gap: 6px;
  background: var(--bg-panel);
  padding: 12px 20px;
  border-radius: 14px;
}

.seg {
  width: 48px;
  height: 18px;
  border-radius: 4px;
  background: var(--seg-off);
  transition: background-color 0.05s linear;
}

/* Horizontal variant (Amp mode): lamps run left (quiet) to right (loud),
   filling the width evenly, under the scope. */
.meter.horizontal {
  flex-direction: row;
  width: min(100%, 560px);
  padding: 12px 16px;
}

.meter.horizontal .seg {
  width: auto;
  flex: 1;
  height: 22px;
}

.seg.lit[data-i="0"], .seg.lit[data-i="1"], .seg.lit[data-i="2"],
.seg.lit[data-i="3"], .seg.lit[data-i="4"], .seg.lit[data-i="5"],
.seg.lit[data-i="6"] {
  background: var(--accent);
}

.seg.lit[data-i="7"], .seg.lit[data-i="8"] {
  background: var(--warn);
}

.seg.lit[data-i="9"] {
  background: var(--danger);
}

.meter-label {
  font-size: 0.8rem;
  letter-spacing: 0.15em;
  color: var(--text-dim);
  text-transform: uppercase;
}

.db-now-display {
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1;
}

.db-now-value {
  font-size: 2.4rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}

/* Secondary readout: the spectrogram's auto-level top (dBFS). Smaller + white
   so it reads as an aside, not the headline teal "now" value. */
.auto-level-display {
  margin-top: 4px;
}
.auto-level-display .db-now-value {
  font-size: 1.05rem; /* match .db-stat-value (min/avg/max) — reuse an existing size, not a new one */
  color: var(--text);
}

.db-now-label {
  margin-top: 4px;
  font-size: 0.75rem;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.db-stats {
  display: flex;
  gap: 12px;
  width: min(100%, 440px);
}

.db-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1; /* three equal columns so a wide value like "-100.0 dB" gets its share */
  min-width: 0;
}

.db-stat-value {
  font-size: 1.05rem; /* small enough that "-100.0 dB" fits one line in all three columns at once */
  white-space: nowrap;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text); /* white like BPM's stats; teal is reserved for the live "now" value */
}

.db-stat-label {
  font-size: 0.75rem;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.hint {
  color: var(--text-dim);
  font-size: 0.9rem;
  max-width: 26em;
  text-align: center;
  margin: 0;
  /* Always reserve a line, even when empty, so the status text appearing
     ("Listening.") / disappearing doesn't change .content's height and
     re-center the whole (vertically centered) view. */
  min-height: 1.3em;
}

.tuner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  width: 100%;
}

.note-display {
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1;
}

.note-name {
  font-size: 2.5rem; /* fixed: never rescale on rotation (was clamp(...,10vw,...)) */
  font-weight: 700;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.note-name.locked {
  text-decoration: underline;
  text-underline-offset: 6px;
  text-decoration-thickness: 2px;
}

/* Held: the last real reading, kept on screen through silence instead of
   blanking, dimmed to mark it as not currently sounding. Never set at the
   same time as .locked — a lock's own freeze-through-distractions display
   stays full color. */
.note-name.stale,
.note-freq.stale {
  opacity: 0.4;
}

.note-freq {
  margin-top: 4px;
  font-size: 0.9rem;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

.mode-switch {
  display: flex;
  align-items: center;
  gap: 8px;
}

.mode-flip {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-dim);
  font-size: 1.1rem;
  line-height: 1;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mode-flip:active {
  background: var(--surface-active);
  color: var(--text);
}

.pitch-graph {
  /* Full width up to a 400px cap. Portrait fills the phone's width; landscape
     (wider column) tops out at 400px — so it shifts a bit on flip but not
     dramatically. Height follows the canvas's own aspect ratio. (The canvas is
     a bitmap, so the whole thing — labels included — rescales with the width.) */
  width: 100%;
  max-width: 400px;
  height: auto;
  flex-shrink: 0; /* keep the canvas at its intrinsic (aspect-ratio) height; never let a flex column squeeze it out of shape */
  background: var(--bg-panel);
  border-radius: 14px;
}

#pitchGraph,
#chordsGraph {
  touch-action: pan-y; /* horizontal drag = swipe-to-review (handled here); vertical drag = let the page scroll, so the canvas isn't a dead zone in landscape */
}

/* Scope trigger controls: a Sync toggle + a rising/falling slope button,
   styled like the mode tabs. Sits above the scope canvas. */
.scope-controls {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Chords view controls (wide + spectrum/score/combs) and Scout overlay controls
   (LEAD / CHORDS) share the same centered row style. */
.chords-controls,
.scout-controls {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  width: 100%;
  max-width: 400px;
  margin: 0 auto 10px;
}
.scout-controls.hidden {
  display: none;
}

.scope-btn {
  appearance: none;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-dim);
  padding: 6px 16px;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
}

.scope-btn.active {
  color: var(--accent);
  border-color: var(--accent-dim);
  background: var(--bg-panel);
}

/* The slope button carries a ↑ / ↓ glyph rather than text. */
.scope-btn.slope {
  min-width: 44px;
  padding: 6px 0;
  font-size: 1rem;
  line-height: 1;
}

.scope-btn:disabled {
  opacity: 0.3;
  cursor: default;
}

.scope-btn:active:not(:disabled) {
  background: var(--surface-active);
}

/* Tuner Auto/Manual toggle + note/octave spinners. Same row treatment as
   .scout-controls; hidden unless the Tuner tab is active. */
.tuner-controls {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: nowrap;
  gap: 10px;
  width: 100%;
  max-width: 400px;
  margin: 0 auto;
  height: 60px; /* fixed (matches .wheel) so the graph never shifts between Auto and Manual */
}
.tuner-controls.hidden {
  display: none;
}
.tuner-pickers {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.tuner-pickers[hidden] {
  display: none;
}
/* iOS-style picker wheel: a 3-row 3D cylinder you swipe up/down. Rows are
   rotated around X and pushed out along Z in JS (see createWheel); the mask
   fades the top/bottom edges so rows curve out of sight. `contain: layout paint`
   plus the fixed height pins the box to 60px and clips the 3D rows, so iOS
   Safari can't inflate the layout around the projection (which used to shove the
   graph down in Manual). Only 3 rows are rendered, so nothing leaks far. */
.wheel {
  position: relative;
  width: 68px;
  height: 60px; /* 3 rows of 20px (JS item height H) */
  perspective: 480px;
  overflow: hidden;
  contain: layout paint;
  touch-action: none; /* vertical swipe drives the wheel, never the page */
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 32%, #000 68%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 32%, #000 68%, transparent 100%);
}
/* Interactive (draggable) only in Manual — in Auto the wheels spin themselves. */
.tuner-controls.manual .wheel { cursor: grab; }
.tuner-controls.manual .wheel:active { cursor: grabbing; }
.wheel-stage {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}
.wheel-item {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 20px;
  line-height: 20px;
  text-align: center;
  color: var(--text);
  font-size: 0.75rem; /* match the Auto/Manual button (.scope-btn) */
  font-weight: 600;
  letter-spacing: 0.05em;
  font-variant-numeric: tabular-nums;
  transform-origin: center center;
  backface-visibility: hidden;
  will-change: transform, opacity;
}
/* The selection band = the "limiters". Gray when idle (Auto — the wheel spins
   on its own), teal when it's your active selection (Manual). */
.wheel-band {
  position: absolute;
  left: 4px;
  right: 4px;
  top: 50%;
  height: 22px;
  transform: translateY(-50%);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  pointer-events: none;
}
.tuner-controls.manual .wheel-band {
  border-top-color: var(--accent-dim);
  border-bottom-color: var(--accent-dim);
}

.scrub-bar {
  padding: 0 16px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.scrub-bar.hidden {
  display: none;
}

.scrub-track {
  position: relative;
  flex: 1;
  height: 28px;
  background: var(--bg-panel);
  border-radius: 999px;
  touch-action: none; /* the drag gesture owns this, not page scroll */
}

.scrub-thumb {
  position: absolute;
  top: 3px;
  bottom: 3px;
  right: 3px; /* live default: pinned to the right edge */
  width: 22px;
  border-radius: 999px;
  background: var(--accent);
}

.live-btn {
  appearance: none;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-dim);
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
}

.live-btn.active {
  border-color: var(--accent);
  color: var(--accent);
}

.controls {
  padding: 16px 16px calc(16px + env(safe-area-inset-bottom, 0px));
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
}

.start-btn {
  appearance: none;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-dim);
  padding: 12px 40px;
  border-radius: 999px;
  font-size: 1.1rem; /* play/stop glyph */
  line-height: 1;
  font-weight: 600;
  cursor: pointer;
}

.start-btn.active {
  color: var(--accent);
  border-color: var(--accent-dim);
}

.start-btn:active {
  background: var(--surface-active);
  color: var(--text);
}

.icon-btn {
  appearance: none;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-dim);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  font-size: 1.1rem;
  font-weight: 600;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.icon-btn:active {
  background: var(--surface-active);
  color: var(--text);
  border-color: var(--accent-dim);
}

.overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  z-index: 10;
}

.overlay[hidden] {
  display: none;
}

.about-panel {
  position: relative;
  background: var(--bg-panel);
  border-radius: 20px;
  padding: 28px 24px;
  max-width: 480px;
  max-height: 80vh;
  overflow-y: auto;
}

/* Image sonifier panel: a preview of the (center-cropped) image that gets
   transmitted, plus Play / Export / Another controls. */
.sonify-preview {
  display: block;
  width: 200px;
  height: 200px;
  margin: 0 auto 12px;
  border-radius: 10px;
  background: var(--bg);
}
.sonify-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  margin-top: 16px;
}

/* Annotated illustration figures in About: a cropped spectrogram with an SVG
   overlay of arrows + labels (viewBox matches the 600×591 crop, stretched to
   fit) so the annotations stay crisp and theme-independent. */
.about-fig { margin: 16px 0 4px; }
.about-fig-img { position: relative; border-radius: 10px; overflow: hidden; line-height: 0; }
.about-fig-img img { display: block; width: 100%; height: auto; }
.about-fig figcaption { margin-top: 8px; font-size: 0.85rem; color: var(--text-dim); line-height: 1.45; }

.about-panel h2 {
  margin: 0 0 16px;
  font-size: 1.25rem;
  color: var(--text);
}

.about-panel h3 {
  margin: 20px 0 6px;
  font-size: 0.95rem;
  color: var(--accent);
}

.about-panel h3:first-of-type {
  margin-top: 0;
}

.about-panel p {
  margin: 0 0 8px;
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--text-dim);
}

.about-panel strong {
  color: var(--text);
  font-weight: 600;
}

.about-panel a {
  color: var(--accent);
}

.about-close {
  position: absolute;
  top: 12px;
  right: 12px;
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-dim);
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
}

.about-close:active {
  color: var(--text);
}
