/* ═══════════════════════════════════════════
   DAW UI  —  flat dark design
   ═══════════════════════════════════════════ */

/* ── Reset ── */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; background: #0a0d10; overflow: hidden; }
body { font-family: var(--font-sans); color: var(--fg); }
button { font-family: inherit; }
input, textarea { font-family: inherit; }

/* ── Root ── */
.daw {
  width: 100vw;
  height: 100vh;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: 13px;
  line-height: 1.4;
  letter-spacing: -0.005em;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  /* reset any old .app grid */
  grid-template-columns: none !important;
  grid-template-rows: none !important;
}

/* ── Utilities ── */
.daw .uplabel {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.daw .num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.daw .hidden { display: none !important; }

/* ═══════════════════════════════════
   TOPBAR
   ═══════════════════════════════════ */
.daw-topbar {
  /* Was a flat 77px. The panel-toggle row under the composer needs a second
     line, and auto height means a translation that wraps grows the bar rather
     than being clipped. */
  min-height: 77px;
  padding-top: 10px;
  padding-bottom: 10px;
  flex-shrink: 0;
  background: var(--bg-2);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  padding: 0 16px;
  gap: 14px;
}

/* Brand */
.daw-brand {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-shrink: 0;
}
.daw-brand img { height: 30px; width: auto; display: block; }
.daw-brand-name {
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1;
}
.daw-brand-name .fg    { color: var(--fg); }
.daw-brand-name .accent{ color: var(--accent); }

.daw-version {
  display: none !important; /* version shown in notification panel instead */
}

/* Topbar separator */
.daw-sep {
  width: 1px;
  height: 28px;
  background: var(--border);
  flex-shrink: 0;
}

/* ── Composer pill ── */
.daw-composer {
  flex: 1;
  min-width: 0;
  height: 50px;
  display: flex;
  align-items: stretch;
  background: var(--panel);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.02), 0 1px 8px rgba(0,0,0,0.3);
  overflow: hidden;
}

/* URL zone */
.daw-url-zone {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  flex: 1;
  min-width: 0;
  cursor: text;
}
/* Hide decorative SVG icons in the topbar */
.daw-url-zone > svg { display: none; }
.daw-process-btn > svg { display: none; }
.daw-url-zone svg { flex-shrink: 0; }

/* Keyed off the id, not the type. This input is type="text" so a search
   query is not marked invalid; an attribute selector here silently drops
   every rule the moment that changes. */
.daw-url-zone #url {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  outline: none;
  color: var(--fg-2);
  font-size: 14px;
  font-family: inherit;
  letter-spacing: -0.005em;
}
.daw-url-zone #url::placeholder { color: var(--muted); }

/* Upload button inside URL zone */
.daw-upload-btn {
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--muted);
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.daw-upload-btn:hover { background: var(--panel-2); color: var(--fg-2); border-color: var(--border-strong); }

/* File pill (shown when file selected) */
.file-pill {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 8px;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--panel-2);
  color: var(--fg-2);
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
}
.file-pill.hidden { display: none !important; }
.file-name { overflow: hidden; text-overflow: ellipsis; max-width: 140px; }
.file-size { color: var(--muted); flex-shrink: 0; }
.file-clear {
  width: 16px; height: 16px;
  background: none; border: none;
  color: var(--muted); cursor: pointer;
  font-size: 14px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  border-radius: 3px; flex-shrink: 0; padding: 0;
}
.file-clear:hover { color: var(--fg); background: var(--panel-3); }

/* url-wrap alias (JS uses .url-wrap for drag events) */
.daw-url-zone { position: relative; }
.daw-url-zone.drag-over {
  background: rgba(244,183,64,0.06);
  box-shadow: inset 0 0 0 1px rgba(244,183,64,0.3);
}
.daw-url-zone.has-file #url { display: none; }

/* Composer vertical divider */
.daw-composer-sep {
  width: 1px;
  background: var(--border);
  align-self: stretch;
  margin: 6px 0;
  flex-shrink: 0;
}

/* Stem section */
.daw-stem-section {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  flex-shrink: 0;
}
.daw-extract-label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.daw-stem-chips { display: flex; gap: 4px; }

/* Stem choice buttons */
.stem-choice {
  height: 30px;
  padding: 0 11px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: none;
  color: var(--muted-2);
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  letter-spacing: -0.005em;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.stem-choice[aria-pressed="true"] {
  border-color: color-mix(in srgb, var(--color) 60%, transparent);
  background: color-mix(in srgb, var(--color) 14%, transparent);
  color: var(--color);
}
.stem-dot {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.85;
}
.stem-choice[aria-pressed="false"] .stem-dot { opacity: 0.4; }
/* Automatic song-structure detection. It sits at the end of the composer next
   to Split stems and matches its footprint, so the pair reads as two segments
   of one bar rather than a chip loose beside a button. Colour still separates
   them: the timeline blue, never the amber the primary action owns. */
.structure-toggle {
  --color: #4a7fff;
  min-width: var(--composer-action-w);
  height: auto;
  align-self: stretch;
  margin-left: 0;
  justify-content: center;
  border-radius: 0;
  border: none;
  border-left: 1px solid var(--border-strong);
  flex-direction: column;
  gap: 2px;
  line-height: 1.15;
}
.structure-toggle-main { display: inline-flex; align-items: center; gap: 6px; }
/* Says what the feature is, quietly and where the choice is actually made,
   rather than as a badge on the results after the fact. */
.structure-toggle-note {
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.62;
}

/* "All" toggle */
.stem-choice-all {
  border-color: var(--border-strong);
  color: var(--fg-2);
  font-size: 12px;
}
.stem-choice-all[aria-pressed="true"] {
  border-color: var(--accent);
  background: rgba(244,183,64,0.12);
  color: var(--accent);
}

/* Vocals: All / Lead + Backing (on-demand split, #275) */
.vocal-mode-toggle {
  display: inline-flex;
  height: 30px;
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
}
.vocal-mode-toggle.hidden { display: none; }
.vocal-mode-btn {
  height: 100%;
  padding: 0 10px;
  border: none;
  background: none;
  color: var(--muted-2);
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}
.vocal-mode-btn + .vocal-mode-btn { border-left: 1px solid var(--border); }
.vocal-mode-btn[aria-pressed="true"] {
  background: color-mix(in srgb, var(--vocals) 16%, transparent);
  color: var(--vocals);
}

/* Process button */
.daw-process-btn {
  height: auto;
  /* Shared with .structure-toggle so the two end segments are the same width.
     A min rather than a fixed width, because a longer translation must be
     allowed to grow instead of being clipped. */
  min-width: var(--composer-action-w);
  justify-content: center;
  padding: 0 20px;
  background: linear-gradient(180deg, var(--accent), var(--accent-2));
  border: none;
  border-left: 1px solid #b97f1c;
  color: #1a1206;
  font-weight: 600;
  font-size: 14px;
  font-family: inherit;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.22);
  flex-shrink: 0;
  transition: background var(--t-fast);
}
.daw-process-btn:hover { background: linear-gradient(180deg, #f8c054, #e0a032); }
.daw-process-btn:active { transform: translateY(1px); }
.daw-process-btn:disabled {
  opacity: 0.8;
  cursor: progress;
  filter: saturate(0.85);
}

/* Loading spinner on process btn */
.daw-process-btn.loading > svg { display: none; }
.daw-process-btn.loading { filter: saturate(0.85); }
.daw-process-btn.loading::before {
  content: "";
  width: 14px; height: 14px; flex: 0 0 14px;
  border-radius: 50%;
  background: conic-gradient(currentColor 0deg 270deg, transparent 270deg 360deg);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 0);
  mask: radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 0);
  animation: daw-spin 0.85s linear infinite;
}
@keyframes daw-spin { to { transform: rotate(360deg); } }

/* Icon button */
.daw-iconbtn {
  width: 30px; height: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent;
  border: 1px solid transparent;
  color: var(--fg-2);
  border-radius: 8px;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
  flex-shrink: 0;
}
.daw-iconbtn:hover { background: var(--panel-2); border-color: var(--border); color: var(--fg); }
.daw-iconbtn:active { transform: scale(0.96); }

/* Notification panel */
.daw-notif-wrap { position: relative; }
.daw-notif-panel {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 280px;
  background: var(--panel-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 8px 32px rgba(0,0,0,0.5);
  z-index: 200;
  overflow: hidden;
}
.daw-notif-wrap.open .daw-notif-panel { display: block; }
.daw-notif-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px 8px;
  border-bottom: 1px solid var(--border);
}
.daw-notif-close {
  width: 22px; height: 22px;
  background: none; border: none;
  color: var(--muted); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  border-radius: 5px;
}
.daw-notif-close:hover { background: var(--panel-3); color: var(--fg); }
/* Sits between the label and the close button; the header is space-between, so
   push it right and leave a gap before the X. */
.daw-notif-clear {
  margin-left: auto; margin-right: 8px;
  background: none; border: none; padding: 0;
  color: var(--muted); cursor: pointer;
  font-family: inherit; font-size: 11px;
}
.daw-notif-clear:hover { color: var(--fg); text-decoration: underline; }
.daw-notif-list { padding: 8px; display: flex; flex-direction: column; gap: 6px; }
.daw-notif-card {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 10px 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.daw-notif-release { border-color: rgba(244,183,64,0.25); }
.daw-notif-card-icon {
  width: 28px; height: 28px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(244,183,64,0.12);
  border-radius: 6px;
  color: var(--accent);
}
/* A failure, not an announcement. The amber tint lives in the base icon rule
   rather than in .daw-notif-release, so both properties need overriding. */
.daw-notif-error { border-color: rgba(214,90,74,0.35); cursor: pointer; }
.daw-notif-error:hover { background: var(--panel-2); }
.daw-notif-error .daw-notif-card-icon {
  background: rgba(214,90,74,0.14);
  color: var(--danger);
}
.daw-notif-error:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.daw-notif-card-body { flex: 1; min-width: 0; }
.daw-notif-card-title { font-size: 12px; font-weight: 600; color: var(--fg); }
.daw-notif-card-desc { font-size: 11px; color: var(--muted); margin-top: 2px; }
.daw-notif-badge {
  position: absolute; top: 4px; right: 4px;
  width: 7px; height: 7px;
  background: #f4b740; border-radius: 50%;
  pointer-events: none;
}
.daw-notif-dismiss {
  flex-shrink: 0; align-self: flex-start;
  width: 18px; height: 18px;
  background: none; border: none; cursor: pointer;
  color: var(--muted); display: flex; align-items: center; justify-content: center;
  border-radius: 4px; padding: 0;
}
.daw-notif-dismiss:hover { background: var(--panel-3); color: var(--fg); }
.daw-notif-empty {
  font-size: 12px; color: var(--muted);
  text-align: center; padding: 16px 0; margin: 0;
}

/* Hidden collapsed strip (JS compat, not shown in new design) */
.appbar-icon-strip.hidden { display: none !important; }

/* ═══════════════════════════════════
   BODY LAYOUT
   ═══════════════════════════════════ */
.daw-body {
  flex: 1;
  display: flex;
  min-height: 0;
}

/* ═══════════════════════════════════
   SIDEBAR / CATALOG
   ═══════════════════════════════════ */
.sidebar {
  width: 390px;
  flex-shrink: 0;
  background: var(--bg-2);
  border-right: 1px solid var(--border);
  display: flex;
  overflow: hidden;
  transition: width 0.28s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Rail */
.sidebar-rail {
  width: 66px;
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 12px 0;
  gap: 4px;
  flex-shrink: 0;
}

.rail-btn {
  width: 40px; height: 40px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  border-radius: 8px;
  color: var(--muted);
  font-size: 9px;
  font-family: var(--font-sans);
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
  border: none;
  background: none;
  /* remove old pseudo-element strip */
}
.rail-btn::before { display: none !important; }
.rail-btn:hover { background: var(--panel); color: var(--fg-2); }
.rail-btn.active { color: var(--accent); background: var(--panel); }
.rail-btn svg { flex-shrink: 0; }
/* max-width + ellipsis: a translated label (e.g. Polish "Ustawienia") can run
   longer than English at this 9px size inside the fixed 40px button. The
   full text is still reachable via the button's title/aria-label; this just
   guarantees the label itself can never visually overflow the rail column. */
.rail-btn > span { white-space: nowrap; max-width: 56px; overflow: hidden; text-overflow: ellipsis; }

/* Queue rail button. Only present while something is importing, so the rail
   stays as it is today for anyone not using the queue. */
.rail-queue { position: relative; }
.rail-badge {
  position: absolute; top: 2px; right: 2px;
  min-width: 15px; height: 15px; padding: 0 4px;
  border-radius: 8px;
  background: var(--accent); color: #1a1a1a;
  font-size: 9px; font-weight: 700; line-height: 15px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}
/* "We Recommend" is wider than the other one-word rail labels, so it stacks onto
   two centered lines; let the button grow so the second line + icon aren't clipped. */
.rail-btn.rail-recommend { height: auto; min-height: 40px; padding: 3px 0; }
.rail-btn.rail-recommend span { white-space: normal; text-align: center; line-height: 1.1; }

/* Sidebar body */
.sidebar-body {
  flex: 1;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
  overflow: hidden;
  opacity: 1;
  transition: opacity 0.15s ease;
}

/* Search */
.daw-search {
  height: 32px;
  border: 1px solid var(--border);
  background: var(--panel);
  border-radius: 8px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 10px;
  color: var(--muted);
  font-size: 12px;
  flex-shrink: 0;
  position: relative;
}
.daw-search svg { flex-shrink: 0; }
.daw-search input {
  flex: 1; min-width: 0;
  border: none; outline: none;
  background: transparent;
  color: var(--fg);
  font: inherit;
}
.daw-search input::placeholder { color: var(--muted); }
.search-kbd {
  font-size: 10px;
  color: var(--muted-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0 5px;
  flex-shrink: 0;
}

/* Lib header row */
.daw-lib-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 4px;
  min-height: 22px;
  flex-shrink: 0;
}
.daw-lib-label {
  display: flex;
  align-items: center;
  gap: 4px;
}
.daw-lib-count { color: var(--muted-2); font-weight: 500; margin-left: 4px; }
.new-folder-btn {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px 3px 7px;
  background: none;
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--muted);
  font-size: 11px; font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.new-folder-btn:hover {
  background: var(--panel);
  color: var(--fg-2);
  border-color: var(--border-2, rgba(255,255,255,0.15));
}

/* Lib list (JS populates with .lib-item, .folder, .cat-item) */
.daw-lib-list {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Thin auto-hide scrollbar shared by the library list, the mixer column, the
   footer's control row and the waveform panel (both axes) — hidden until the
   area is hovered/focused, reserves no visible gutter. `.daw .wave-scroll`
   overrides the gold bar from waves.css. */
.daw-lib-list,
.mixer-column,
.footer-row-controls,
.daw .wave-scroll {
  /* Firefox: thin overlay-style bar, fades to transparent track */
  scrollbar-width: thin;
  scrollbar-color: transparent transparent;
}
.daw-lib-list:hover,
.daw-lib-list:focus-within,
.mixer-column:hover,
.mixer-column:focus-within,
.footer-row-controls:hover,
.footer-row-controls:focus-within,
.daw .wave-scroll:hover,
.daw .wave-scroll:focus-within {
  scrollbar-color: rgba(148, 163, 184, 0.4) transparent;
}
/* WebKit (Chrome/Safari/WKWebView): thin thumb, hidden until hover/scroll */
.daw-lib-list::-webkit-scrollbar,
.mixer-column::-webkit-scrollbar,
.footer-row-controls::-webkit-scrollbar,
.daw .wave-scroll::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
.daw-lib-list::-webkit-scrollbar-track,
.mixer-column::-webkit-scrollbar-track,
.footer-row-controls::-webkit-scrollbar-track,
.daw .wave-scroll::-webkit-scrollbar-track {
  background: transparent;
}
.daw-lib-list::-webkit-scrollbar-thumb,
.mixer-column::-webkit-scrollbar-thumb,
.footer-row-controls::-webkit-scrollbar-thumb,
.daw .wave-scroll::-webkit-scrollbar-thumb {
  background: transparent;
  border: 2px solid transparent;
  background-clip: padding-box;
  border-radius: 999px;
}
.daw-lib-list:hover::-webkit-scrollbar-thumb,
.daw-lib-list:focus-within::-webkit-scrollbar-thumb,
.mixer-column:hover::-webkit-scrollbar-thumb,
.mixer-column:focus-within::-webkit-scrollbar-thumb,
.footer-row-controls:hover::-webkit-scrollbar-thumb,
.footer-row-controls:focus-within::-webkit-scrollbar-thumb,
.daw .wave-scroll:hover::-webkit-scrollbar-thumb,
.daw .wave-scroll:focus-within::-webkit-scrollbar-thumb {
  background: rgba(148, 163, 184, 0.4);
  background-clip: padding-box;
}
.daw-lib-list::-webkit-scrollbar-thumb:hover,
.mixer-column::-webkit-scrollbar-thumb:hover,
.footer-row-controls::-webkit-scrollbar-thumb:hover,
.daw .wave-scroll::-webkit-scrollbar-thumb:hover {
  background: rgba(148, 163, 184, 0.6);
  background-clip: padding-box;
}

/* Library item */
.lib-item {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 8px;
  border-radius: 8px;
  cursor: pointer;
  position: relative;
  transition: background var(--t-fast);
}
.lib-item:hover { background: var(--panel); }
.lib-item.active {
  background: linear-gradient(90deg, rgba(244,183,64,0.10) 0%, var(--panel-2) 60%);
}
.lib-item.active::before {
  content: '';
  position: absolute; left: -2px; top: 6px; bottom: 6px;
  width: 3px; border-radius: 2px;
  background: var(--accent);
}
.lib-cover {
  width: 36px; height: 36px; border-radius: 6px;
  display: flex; align-items: center; justify-content: center;
  font-size: 9px; font-weight: 700; letter-spacing: 0.1em;
  color: rgba(255,255,255,0.85);
  flex-shrink: 0;
}
.lib-meta { flex: 1; min-width: 0; }
.lib-meta .t { font-size: 13px; color: var(--fg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lib-meta .s { font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lib-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }

/* cat-item (legacy catalog items JS creates) */
.cat-item {
  display: flex;
  gap: 9px;
  align-items: center;
  padding: 7px 8px;
  border: 1px solid transparent;
  border-radius: 8px;
  cursor: pointer;
  transition: background var(--t-fast), border-color var(--t-fast);
}
.cat-item:hover { background: var(--panel-2); border-color: var(--border); }
.cat-item.active { background: var(--panel-2); border-color: rgba(244,183,64,0.3); }
.cat-thumb {
  width: 36px; height: 36px;
  border-radius: 6px; flex-shrink: 0;
  overflow: hidden; border: 1px solid var(--border);
  background: var(--panel);
  display: flex; align-items: center; justify-content: center;
  color: var(--muted);
}
.cat-thumb svg, .cat-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cat-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.cat-title { color: var(--fg); font-size: 12px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cat-sub { color: var(--muted); font-size: 10.5px; display: flex; gap: 5px; white-space: nowrap; overflow: hidden; }
.cat-status { width: 6px; height: 6px; border-radius: 50%; background: #5fbc56; flex-shrink: 0; }
.cat-status.processing { background: var(--accent); animation: cat-pulse 1.4s infinite; }
.cat-status.unavailable { background: #666; }
.cat-item.unavailable { cursor: pointer; }
.cat-item.unavailable .cat-title { opacity: 0.55; }
.cat-unavailable-warning { color: var(--accent); font-weight: 600; opacity: 1; }
@keyframes cat-pulse { 0%,100%{opacity:1;} 50%{opacity:0.3;} }

/* Import queue: a waiting row and a running row must be told apart at a
   glance, so they differ in three ways -- wording, the presence of a progress
   bar, and a hollow versus filled status dot. */
.cat-queue-label { color: var(--accent); font-variant-numeric: tabular-nums; }
.cat-item.queue-waiting .cat-queue-label { color: var(--muted); }
/* Waiting rows are not loadable yet, so they read as pending rather than
   inviting a click. */
.cat-item.queue-waiting { cursor: default; }
.cat-item.queue-waiting .cat-thumb { opacity: 0.55; }
.cat-item.queue-waiting .cat-title { color: var(--muted); }
.cat-item.queue-waiting .cat-status {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--muted);
  animation: none;
}
.cat-progress {
  height: 3px; border-radius: 2px; margin-top: 4px;
  background: rgba(255, 255, 255, 0.09); overflow: hidden;
}
.cat-progress-fill {
  height: 100%; width: 0; border-radius: 2px;
  background: var(--accent);
  transition: width 260ms linear;
}

/* Queue view rows. Unlike a library row these are not loadable -- there is
   nothing to load yet -- so they get no hover affordance, just a cancel. */
.queue-row { cursor: default; }
.queue-row:hover { background: var(--panel); }
.queue-row .cat-meta { gap: 3px; }
.queue-cancel {
  width: 22px; height: 22px; border: 0; border-radius: 5px;
  background: transparent; color: var(--muted); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  padding: 0; flex-shrink: 0; opacity: 0.65;
  transition: opacity var(--t-fast), background var(--t-fast), color var(--t-fast);
}
.queue-row:hover .queue-cancel { opacity: 1; }
.queue-cancel:hover { background: rgba(217, 83, 79, 0.16); color: #e06c68; }
.queue-cancel:disabled { opacity: 0.3; cursor: default; }
.queue-section .lib-section-head { margin-bottom: 6px; }

/* Restored-from-last-session banner. Opening the app never starts separating
   on its own, so this is the only way that queue moves. */
.queue-paused-banner {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 8px; padding: 8px 10px;
  border: 1px solid rgba(232, 168, 56, 0.28);
  border-radius: 8px;
  background: rgba(232, 168, 56, 0.08);
}
.queue-paused-text { flex: 1; font-size: 11px; color: var(--fg-2); line-height: 1.4; }
.queue-start-btn {
  flex-shrink: 0; min-height: 26px; padding: 0 12px;
  border-radius: 6px; cursor: pointer;
  border: 1px solid rgba(232, 168, 56, 0.45);
  background: rgba(232, 168, 56, 0.18);
  color: var(--accent);
  font-family: var(--font-mono); font-size: 11px; font-weight: 600;
}
.queue-start-btn:hover { background: rgba(232, 168, 56, 0.28); }
.queue-start-btn:disabled { opacity: 0.5; cursor: default; }

/* Reordering. Position in a serial queue is the difference between "ready now"
   and "ready in half an hour", so waiting rows drag. */
.queue-row.queue-waiting { cursor: grab; }
.queue-row.dragging { opacity: 0.4; cursor: grabbing; }
.queue-row.drop-below { box-shadow: 0 2px 0 0 var(--accent); }
.queue-grip {
  display: flex; align-items: center; flex-shrink: 0;
  margin-right: -2px; color: var(--muted); opacity: 0;
  transition: opacity var(--t-fast);
}
.queue-row:hover .queue-grip { opacity: 0.7; }
.queue-top {
  width: 22px; height: 22px; border: 0; border-radius: 5px;
  background: transparent; color: var(--muted); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  padding: 0; flex-shrink: 0; opacity: 0;
  transition: opacity var(--t-fast), background var(--t-fast), color var(--t-fast);
}
.queue-row:hover .queue-top { opacity: 0.65; }
.queue-top:hover { background: rgba(232, 168, 56, 0.16); color: var(--accent); opacity: 1; }
.queue-top:disabled { opacity: 0.3; cursor: default; }
.cat-del {
  width: 20px; height: 20px; border: 0; border-radius: 5px;
  background: transparent; color: var(--muted); cursor: pointer;
  opacity: 0; display: flex; align-items: center; justify-content: center;
  padding: 0; flex-shrink: 0; transition: opacity var(--t-fast), background var(--t-fast);
}
.cat-item:hover .cat-del { opacity: 1; }
.cat-del:hover { background: rgba(21,31,39,0.8); color: var(--danger); }

/* Folder items (legacy catalog) */
.folder { display: flex; flex-direction: column; }
.folder-head {
  --folder-color: var(--accent);
  display: flex; align-items: center; gap: 7px;
  padding: 6px 8px; border-radius: 7px;
  cursor: pointer; color: var(--muted);
  transition: background var(--t-fast), color var(--t-fast);
  user-select: none;
}
.folder-head:hover { background: var(--panel); color: var(--fg); }
.folder-head .f-chevron { width: 11px; height: 11px; transition: transform 180ms ease; flex-shrink: 0; color: var(--muted); }
.folder.collapsed .folder-head .f-chevron { transform: rotate(-90deg); }
.folder-head .f-icon { width: 13px; height: 13px; flex-shrink: 0; color: var(--folder-color); }
.folder-head .f-name {
  font-size: 12px; font-weight: 500; color: inherit;
  flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  background: transparent; border: none; padding: 0; font-family: inherit; outline: none; cursor: inherit;
}
.folder-head .f-count { font-size: 10.5px; color: var(--muted); }
.folder-color-dot {
  width: 13px; height: 13px; border: 1px solid rgba(255,255,255,0.22);
  border-radius: 999px; background: var(--folder-color); cursor: pointer; padding: 0;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.22);
}
.folder-head .f-del,
.folder-head .f-subfolder {
  width: 18px; height: 18px; border: none; background: transparent;
  color: var(--muted); cursor: pointer; opacity: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: 4px; padding: 0; transition: opacity var(--t-fast), color var(--t-fast);
  flex-shrink: 0;
}
.folder-head:hover .f-del,
.folder-head:hover .f-subfolder { opacity: 1; }
.folder-head .f-del:hover { background: rgba(21,31,39,0.8); color: var(--danger); }
.folder-head .f-subfolder:hover { background: rgba(21,31,39,0.8); color: var(--fg-2); }
/* Drag grip */
.f-grip {
  display: none; align-items: center; justify-content: center;
  cursor: grab; color: var(--muted); flex-shrink: 0;
  padding: 2px; border-radius: 3px;
  transition: color var(--t-fast);
}
.f-grip:active { cursor: grabbing; }
.folder-head:hover .f-grip { display: flex; }
/* Drop indicators for folder reorder / nest */
.folder.drop-before > .folder-head { box-shadow: 0 -2px 0 var(--accent); border-radius: 7px 7px 0 0; }
.folder.drop-after > .folder-head { box-shadow: 0 2px 0 var(--accent); border-radius: 0 0 7px 7px; }
.folder.drop-into > .folder-head { box-shadow: 0 0 0 1px var(--accent); background: var(--panel); }
/* Folder being dragged */
.folder.folder-dragging { opacity: 0.35; pointer-events: none; }
/* Subfolder indentation */
.folder.subfolder { margin-left: 12px; }
.folder-body { display: flex; flex-direction: column; gap: 3px; padding: 3px 0 3px 14px; margin-left: 7px; border-left: 1px solid rgba(157,170,182,0.1); }
.folder.collapsed .folder-body { display: none; }
.folder-empty { color: var(--muted); font-size: 11px; padding: 5px 8px; font-style: italic; }

/* Folder editor modal */
.folder-editor-backdrop {
  position: fixed; inset: 0; z-index: 80;
  display: grid; place-items: center;
  background: rgba(3,8,13,0.42); backdrop-filter: blur(2px);
}
.folder-editor {
  width: min(300px, calc(100vw - 32px));
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: linear-gradient(180deg, rgba(28,39,48,0.98), rgba(13,21,29,0.98));
  box-shadow: var(--shadow-panel);
  padding: 12px; color: var(--fg); font-family: var(--font-mono);
}
.folder-editor-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; font-size: 13px; font-weight: 600; }
.folder-editor-close { width: 24px; height: 24px; border: 1px solid transparent; border-radius: 6px; background: transparent; color: var(--muted); cursor: pointer; display: grid; place-items: center; padding: 0; }
.folder-editor-close:hover { background: rgba(21,31,39,0.8); color: var(--fg); }
.folder-editor-field { display: grid; gap: 7px; margin-bottom: 12px; color: var(--muted); font-size: 10.5px; }
.folder-editor-name { width: 100%; min-height: 34px; border: 1px solid var(--border); border-radius: 7px; background: rgba(10,17,24,0.78); color: var(--fg); font: inherit; font-size: 12px; padding: 0 10px; outline: none; }
.folder-editor-name:focus { border-color: rgba(244,183,64,0.5); box-shadow: 0 0 0 2px rgba(244,183,64,0.12); }
.folder-editor-colors { display: flex; align-items: center; gap: 9px; }
.folder-editor-colors .folder-color-dot { width: 22px; height: 22px; }
.folder-editor-msg { color: var(--danger); font-size: 11px; margin-top: 8px; }
.folder-editor-msg:empty { display: none; }
.folder-editor-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }
.folder-editor-actions button { min-height: 30px; border-radius: 7px; font-family: var(--font-mono); font-size: 11px; cursor: pointer; padding: 0 11px; }
.folder-editor-cancel { border: 1px solid var(--border); background: rgba(21,31,39,0.52); color: var(--muted); }
.folder-editor-save { border: 1px solid rgba(244,183,64,0.3); background: rgba(244,183,64,0.16); color: var(--accent); }

/* Edit Library modal (Settings → opens this centered window) */
.library-editor-backdrop {
  position: fixed; inset: 0; z-index: 80;
  display: grid; place-items: center;
  background: rgba(3,8,13,0.42); backdrop-filter: blur(2px);
}
.library-editor {
  width: min(560px, calc(100vw - 32px));
  /* Fixed height (not max-height) so the dialog stays one size across all tabs
     -- each pane fills it via flex:1, so switching tabs never resizes it. */
  height: min(70vh, 540px);
  display: flex; flex-direction: column;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: linear-gradient(180deg, rgba(28,39,48,0.98), rgba(13,21,29,0.98));
  box-shadow: var(--shadow-panel);
  padding: 12px; color: var(--fg); font-family: var(--font-mono);
}
.library-editor-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; font-size: 13px; font-weight: 600; }
.library-editor-close { width: 24px; height: 24px; border: 1px solid transparent; border-radius: 6px; background: transparent; color: var(--muted); cursor: pointer; display: grid; place-items: center; padding: 0; }
.library-editor-close:hover { background: rgba(21,31,39,0.8); color: var(--fg); }
.library-editor-table-wrap { flex: 1; min-height: 0; overflow-y: auto; border: 1px solid var(--border); border-radius: 7px; background: rgba(10,17,24,0.5); }
.library-editor-table { width: 100%; border-collapse: collapse; font-size: 11.5px; }
.library-editor-table thead th {
  position: sticky; top: 0;
  text-align: left; font-weight: 600; font-size: 10px;
  text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--muted); background: rgba(13,21,29,0.96);
  padding: 8px 10px; border-bottom: 1px solid var(--border);
}
.library-editor-table tbody td { padding: 7px 10px; border-bottom: 1px solid rgba(148,163,184,0.07); color: var(--fg-2); vertical-align: middle; }
.library-editor-table tbody tr:last-child td { border-bottom: none; }
.library-editor-table .le-name { color: var(--fg); max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.library-editor-table .le-loc { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.library-editor-table tr.unavailable .le-name { color: var(--danger); }
.le-badge { margin-left: 7px; padding: 1px 6px; border-radius: 5px; font-size: 9px; text-transform: uppercase; letter-spacing: 0.04em; background: rgba(214,90,74,0.16); color: var(--danger); }
.library-editor-empty { color: var(--muted); text-align: center; padding: 22px 10px !important; }
/* Settings → tabs */
.settings-tabs { display: flex; gap: 2px; margin-bottom: 12px; border-bottom: 1px solid var(--border); }
.settings-tab { background: none; border: none; border-bottom: 2px solid transparent; color: var(--muted); font-family: var(--font-mono); font-size: 12px; font-weight: 600; padding: 5px 12px 9px; cursor: pointer; margin-bottom: -1px; }
.settings-tab:hover { color: var(--fg-2); }
.settings-tab.active { color: var(--fg); border-bottom-color: var(--accent); }
/* Every pane fills the fixed dialog body so all tabs are the same size; the
   General pane (the tall one, with the tracks table) scrolls within it. */
.settings-pane { display: flex; flex-direction: column; min-height: 0; flex: 1; }
.settings-pane[data-pane="general"] {
  flex: 1; overflow-y: auto;
  /* Reserve a gutter for the scrollbar so it never overlaps the right-aligned
     controls (Compute device, Out of sync tracks). padding-right insets the
     content; the equal negative margin lets that gutter sit in the card's own
     12px padding, so scrolling content stays aligned with the fixed
     header/tabs/footer. Handles overlay scrollbars (macOS/WebKit, which draw
     over the padding box) and reserves space for classic scrollbars
     (Windows/Linux). */
  scrollbar-gutter: stable;
  padding-right: 12px; margin-right: -12px;
}
.settings-pane.hidden { display: none; }
.settings-pane[data-pane="general"] .library-editor-table-wrap { flex: none; max-height: 240px; margin-bottom: 2px; }
.settings-empty { color: var(--muted); font-size: 12px; text-align: center; padding: 28px 10px; }
.settings-foot { display: flex; justify-content: flex-end; margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--border); }
.settings-done { min-height: 32px; border-radius: 7px; border: 1px solid rgba(244,183,64,0.35); background: rgba(244,183,64,0.16); color: var(--accent); font-family: var(--font-mono); font-size: 12px; font-weight: 600; padding: 0 22px; cursor: pointer; }
.settings-done:hover { background: rgba(244,183,64,0.24); }
/* Right-aligned form controls share a fixed width so they line up down the column. */
.settings-num-input, .settings-select { flex-shrink: 0; width: 84px; background: rgba(10,17,24,0.6); border: 1px solid var(--border-strong); border-radius: 7px; color: var(--fg); font-family: var(--font-mono); font-size: 12px; padding: 6px 9px; }
.settings-num-input { text-align: right; }
.settings-select { cursor: pointer; }
/* Wider variant for options whose text doesn't fit the shared 84px column --
   currently just the language picker (flag + native name, up to "Bahasa Indonesia"). */
.settings-select-wide { width: 190px; }
.settings-num-input:focus, .settings-select:focus { outline: none; border-color: rgba(244,183,64,0.5); }

/* Settings → network access section */
.settings-section { margin-bottom: 12px; }
.settings-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; }
.settings-row-text { min-width: 0; }
.settings-row-title { font-size: 12.5px; font-weight: 600; color: var(--fg); }
.settings-row-desc { font-size: 10.5px; color: var(--muted); margin-top: 3px; line-height: 1.45; }
.settings-lock-note { font-style: italic; opacity: 0.85; margin-top: 5px; }
.settings-switch { position: relative; flex-shrink: 0; width: 42px; height: 24px; cursor: pointer; }
.settings-switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.settings-switch-track { position: absolute; inset: 0; border-radius: 999px; background: rgba(148,163,184,0.22); border: 1px solid var(--border-strong); transition: background 0.15s ease; }
.settings-switch-thumb { position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: var(--fg); transition: transform 0.15s ease; }
.settings-switch input:checked + .settings-switch-track { background: rgba(244,183,64,0.55); border-color: rgba(244,183,64,0.5); }
.settings-switch input:checked + .settings-switch-track .settings-switch-thumb { transform: translateX(18px); background: var(--accent); }
.settings-switch.disabled { cursor: default; opacity: 0.7; }
.settings-switch.disabled input { cursor: default; }
/* A row whose setting only applies while another one is on. Dimmed and inert
   rather than removed, so the value stays readable: someone deciding whether to
   switch automatic deletion on can see how long tracks would be kept before
   committing to it, instead of having to turn the destructive setting on to
   find out. Note that `hidden` would not work here anyway -- base.css is not
   loaded by index.html and daw.css scopes its rule to `.daw`, while the
   settings overlay is appended to document.body. */
.settings-row.disabled { opacity: 0.45; }
.settings-row.disabled input { cursor: not-allowed; }
.settings-net { margin-top: 10px; font-size: 11px; color: var(--muted); }
.settings-net.hidden { display: none; }
.settings-net-empty { color: var(--muted); }
.settings-net-qr { display: flex; flex-direction: column; gap: 14px; margin-top: 6px; }
.qr-hint { font-size: 10px; color: var(--muted); margin: 0; line-height: 1.4; }
.qr-cards-row { display: flex; flex-wrap: wrap; gap: 28px; }
.qr-card { display: flex; flex-direction: column; align-items: center; gap: 6px; cursor: pointer; }
.qr-img-wrap { width: 130px; height: 130px; border-radius: 6px; border: 3px solid var(--accent); overflow: hidden; box-sizing: border-box; }
.qr-card img { width: 100%; height: 100%; display: block; transition: filter 0.25s ease, scale 0.25s ease; }
.qr-card.qr-blurred img { filter: blur(10px); scale: 1.12; }
.qr-label { font-size: 9.5px; color: var(--muted); text-align: center; max-width: 130px; word-break: break-all; }
.settings-server-note { font-size: 10.5px; color: var(--muted); margin: 0 0 12px; line-height: 1.5; }
.settings-subhead { font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); font-weight: 600; margin: 4px 0 7px; }

/* Settings → registry (read-only viewer) */
.settings-registry-refresh { flex-shrink: 0; min-height: 28px; border-radius: 6px; border: 1px solid var(--border-strong); background: rgba(10,17,24,0.6); color: var(--fg-2); font-family: var(--font-mono); font-size: 11px; padding: 0 12px; cursor: pointer; }
.settings-registry-refresh:hover { color: var(--fg); border-color: rgba(148,163,184,0.4); }
.settings-registry-view {
  flex: 1; min-height: 0; margin-top: 10px; resize: none;
  background: rgba(10,17,24,0.5); border: 1px solid var(--border); border-radius: 7px;
  color: var(--fg-2); font-family: var(--font-mono); font-size: 11px; line-height: 1.5;
  padding: 10px 12px; white-space: pre; overflow: auto;
}
.settings-registry-view:focus { outline: none; }

/* Settings → General → danger zone (reset app data) */
.settings-danger-zone { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }
.settings-danger-subhead { color: var(--danger); }
.settings-reset-btn {
  flex-shrink: 0; min-height: 30px; border-radius: 7px;
  border: 1px solid rgba(214,90,74,0.35); background: rgba(214,90,74,0.12);
  color: var(--danger); font-family: var(--font-mono); font-size: 11px; font-weight: 600;
  padding: 0 12px; cursor: pointer;
}
.settings-reset-btn:hover { background: rgba(214,90,74,0.2); }

/* Reset app data — confirm dialog (nested above the Settings dialog) */
.reset-confirm-backdrop {
  position: fixed; inset: 0; z-index: 150;
  display: grid; place-items: center;
  background: rgba(3,8,13,0.55); backdrop-filter: blur(2px);
}
.reset-confirm-card {
  width: min(340px, calc(100vw - 32px));
  border: 1px solid rgba(214,90,74,0.4);
  border-radius: 10px;
  background: linear-gradient(180deg, rgba(28,39,48,0.98), rgba(13,21,29,0.98));
  box-shadow: var(--shadow-panel);
  padding: 16px; color: var(--fg); font-family: var(--font-mono);
}
.reset-confirm-title { font-size: 13px; font-weight: 700; color: var(--danger); margin-bottom: 8px; }
.reset-confirm-body { font-size: 11.5px; color: var(--fg-2); line-height: 1.5; margin: 0 0 10px; }
.reset-confirm-hint { font-size: 10.5px; color: var(--muted); margin: 0 0 7px; }
.reset-confirm-hint strong { color: var(--fg); letter-spacing: 0.04em; }
.reset-confirm-input {
  width: 100%; min-height: 34px; border: 1px solid var(--border-strong); border-radius: 7px;
  background: rgba(10,17,24,0.78); color: var(--fg); font: inherit; font-size: 12px;
  padding: 0 10px; outline: none; box-sizing: border-box;
}
.reset-confirm-input:focus { border-color: rgba(214,90,74,0.5); box-shadow: 0 0 0 2px rgba(214,90,74,0.14); }
.reset-confirm-msg { color: var(--danger); font-size: 11px; margin-top: 8px; min-height: 1em; }
.reset-confirm-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }
.reset-confirm-actions button { min-height: 30px; border-radius: 7px; font-family: var(--font-mono); font-size: 11px; cursor: pointer; padding: 0 12px; }
.reset-confirm-cancel { border: 1px solid var(--border); background: rgba(21,31,39,0.52); color: var(--muted); }
.reset-confirm-go { border: 1px solid rgba(214,90,74,0.4); background: rgba(214,90,74,0.18); color: var(--danger); font-weight: 600; }
.reset-confirm-go:disabled { opacity: 0.4; cursor: not-allowed; }
/* Playlist import reuses the confirm shell, but it is a normal action rather
   than a destructive one, so it drops the danger colouring. */
.playlist-confirm-title { color: var(--fg); }
.playlist-confirm .playlist-name { color: var(--accent); }
.playlist-confirm-go {
  min-height: 30px; border-radius: 7px; padding: 0 12px; cursor: pointer;
  font-family: var(--font-mono); font-size: 11px; font-weight: 600;
  border: 1px solid rgba(232, 168, 56, 0.45);
  background: rgba(232, 168, 56, 0.16);
  color: var(--accent);
}
.playlist-confirm-go:disabled { opacity: 0.4; cursor: not-allowed; }

.library-editor-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 11px; }
.library-editor-status { font-size: 10.5px; color: var(--muted); }
.library-editor-status.out-of-sync { color: var(--danger); font-weight: 600; }
.library-editor-sync { min-height: 30px; border-radius: 7px; border: 1px solid rgba(244,183,64,0.3); background: rgba(244,183,64,0.16); color: var(--accent); font-family: var(--font-mono); font-size: 11px; padding: 0 13px; cursor: pointer; }
.library-editor-sync:disabled { opacity: 0.55; cursor: default; }

/* Color picker popover */
.color-picker-popover {
  position: absolute; z-index: 90;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  border-radius: 8px; padding: 8px; display: flex; gap: 6px;
  box-shadow: var(--shadow-panel);
}

/* Collapsed sidebar strip */
.cat-collapsed-strip { display: none; }
.daw.cat-collapsed .sidebar { width: 66px; }
.daw.cat-collapsed .sidebar-body { opacity: 0; pointer-events: none; visibility: hidden; }
.daw.cat-collapsed .cat-collapsed-strip { display: flex; flex-direction: column; gap: 8px; align-items: center; padding: 8px 0; overflow-y: auto; }

/* ═══════════════════════════════════
   MAIN AREA (#lanes)
   ═══════════════════════════════════ */
.daw-main-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}
.daw-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}

/* ── Job progress overlay ── */
.job {
  position: absolute;
  inset: 0;
  z-index: 20;
  background: rgb(7, 13, 19);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 32px;
}
/* Gold ambient glow -- matches the wave-loading-overlay aesthetic */
.job::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 44%, rgba(216, 168, 74, 0.13), transparent 55%);
  pointer-events: none;
}
.job > * { position: relative; z-index: 1; }
.job.hidden { display: none !important; }
.job .title { font-size: 15px; font-weight: 600; color: var(--fg); text-align: center; }
.job .stage { font-size: 12px; color: var(--muted); text-align: center; }
.job progress {
  width: 280px; max-width: 100%;
  height: 4px;
  border-radius: 2px;
  appearance: none; border: none;
  background: var(--panel-3);
  overflow: hidden;
}
.job progress::-webkit-progress-bar { background: var(--panel-3); border-radius: 2px; }
.job progress::-webkit-progress-value { background: var(--accent); border-radius: 2px; }
.job progress::-moz-progress-bar { background: var(--accent); border-radius: 2px; }
.job .job-detail { font-size: 11px; color: var(--muted-2); text-align: center; }
.cancel-btn {
  height: 30px; padding: 0 16px;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  color: var(--fg-2); border-radius: 8px; font-size: 12px;
  font-family: inherit; cursor: pointer;
  transition: background var(--t-fast);
}
.cancel-btn:hover { background: var(--panel-3); color: var(--fg); }
.cancel-btn.hidden { display: none !important; }

/* Error banner */
.error {
  position: absolute;
  top: 64px; left: 260px; right: 0;
  z-index: 15;
  padding: 12px 20px;
  background: rgba(214,90,74,0.12);
  border-bottom: 1px solid rgba(214,90,74,0.3);
  color: #ff9090;
  font-size: 13px;
}
.error.hidden { display: none !important; }

/* ── Track header ── */
.daw-track-header {
  display: flex;
  flex-direction: column;
  border-bottom: 1px solid var(--border);
  background: var(--bg-2);
  flex-shrink: 0;
}

/* Row 1. A grid rather than a flex row so its column edges land on exactly
   the same pixels as the presence grid below it -- flex and grid round
   fractional track widths differently, which left the two rows a pixel out of
   step at most window widths. */
.daw-info-row {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  border-bottom: 1px solid var(--border);
}

/* Track card */
.daw-track-card {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 4px 16px;
  flex-shrink: 0;
  width: 340px;
  border-right: 1px solid var(--border);
}

/* Metadata cards.
   Two lines, not three: the qualifier (Natural Minor, Peak 3.5 dB, High) sits
   on the value's own line rather than under it. Six stems only fit on a
   1366x768 laptop if the panels above the mixer stop taking a third of the
   window (#480), and a third text row here cost more height than it carried
   information. */
.daw-meta-card {
  padding: 4px 16px;
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  min-width: 0;
}
.daw-meta-card:last-child { border-right: none; }
.meta-card-label {
  font-size: 10px;
  line-height: 1;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
.meta-card-main {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}
.meta-card-value {
  font-size: 17px;
  font-weight: 700;
  color: var(--fg);
  line-height: 1;
  font-family: var(--font-mono);
  flex-shrink: 0;
}
.meta-card-value.accent { color: var(--accent); }
.meta-card-value.stability-high { color: #4caf7d; }
.meta-card-sub {
  font-size: 11px;
  line-height: 1;
  color: var(--muted);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.daw-cover {
  width: 64px; height: 64px;
  border-radius: 8px;
  background: var(--panel-2);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; color: var(--muted);
  position: relative; overflow: hidden;
}
.np-art-placeholder { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; }
.np-art-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: none;
}
.np-art-img[src]:not([src=""]) { display: block; }

.daw-track-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.daw-track-title { font-size: 16px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* One compact line -- duration · stems · source · quality · extracted date --
   instead of a duration/stems row plus three further label:value rows below
   it. The four-line version was still the pre-redesign layout; this row was
   the one part of the footer rebuild (#269 follow-up) I'd described matching
   the reference but never actually rebuilt. */
.daw-track-meta-line {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: 11px; color: var(--muted);
  min-width: 0; overflow: hidden;
}
.daw-track-meta-line .num { color: var(--fg-2); }
.daw-track-sep { color: var(--border); font-size: 12px; flex-shrink: 0; }
#t-stems-chip {
  display: inline-flex; align-items: center; gap: 4px;
}
#t-stems-chip::before {
  content: '';
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: #4caf7d;
  flex-shrink: 0;
}
.daw-fav-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--muted);
  padding: 2px;
  display: flex;
  align-items: center;
  transition: color 150ms;
}
.daw-fav-btn:hover { color: var(--fg); }
.daw-fav-btn.active { color: #e54e4e; }
.daw-fav-btn.active svg { fill: #e54e4e; stroke: #e54e4e; }
.daw-chip {
  display: inline-flex; align-items: center;
  padding: 2px 8px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--panel-2);
  font-size: 11px;
  color: var(--fg-2);
  font-family: var(--font-mono);
}

/* Energy panel */
.daw-energy-panel {
  padding: 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.daw-energy-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.daw-playhead-label { color: var(--accent); display: flex; align-items: center; gap: 4px; }
.daw-energy-bars { flex: 1; display: flex; flex-direction: column; justify-content: space-between; gap: 4px; }

/* Energy rows (JS-driven) */
.energy-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.energy-row span {
  font-size: 11px;
  font-weight: 500;
  width: 44px;
  flex-shrink: 0;
}
.energy-row.vocals span { color: var(--vocals); }
.energy-row.drums  span { color: var(--drums); }
.energy-row.bass   span { color: var(--bass); }
.energy-row.guitar span { color: var(--guitar); }
.energy-row.piano  span { color: var(--piano); }
.energy-row.other  span { color: var(--other); }
.energy-row.original span { color: var(--fg-2); }

.energy-row b {
  flex: 1;
  height: 6px;
  border-radius: 3px;
  background: var(--bg);
  overflow: hidden;
  position: relative;
  display: block;
}
.energy-row b::after {
  content: '';
  position: absolute; inset: 0;
  width: var(--v, 0%);
  border-radius: 3px;
  transition: width 160ms;
}
.energy-row.vocals b::after { background: var(--vocals); }
.energy-row.drums  b::after { background: var(--drums); }
.energy-row.bass   b::after { background: var(--bass); }
.energy-row.guitar b::after { background: var(--guitar); }
.energy-row.piano  b::after { background: var(--piano); }
.energy-row.other  b::after { background: var(--other); opacity: 0.5; }
.energy-row.original b::after { background: var(--fg-2); }

.energy-row em {
  font-style: normal;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-2);
  width: 36px;
  text-align: right;
  flex-shrink: 0;
}

/* Stem presence cards — row 2. One line each: the label and its percentage
   read as a pair, and stacking them doubled the row's height for no gain
   (#480). */
.stem-presence-panel {
  display: grid;
  /* Seven, matching the seven metadata cards above, so the two rows share
     their dividers instead of interleaving them. Six presence stems fill
     seven columns because Vocals takes two; a completed lead/backing split
     replaces that one card with two and the row becomes a plain 7x1. */
  grid-template-columns: repeat(7, minmax(0, 1fr));
}
.stem-card[data-stem="vocals"] { grid-column: span 2; }
.stem-card {
  padding: 8px 12px;
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: row;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  min-width: 0;
}
.stem-card:last-child { border-right: none; }
.stem-card-label {
  font-size: 10px;
  line-height: 1;
  font-weight: 600;
  /* Tighter than the metadata labels above: on a side-by-side row these
     compete with the percentage for width, and 0.07em truncated
     "VOCAL PRESENCE" at 1366px. */
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--muted);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.stem-card-pct {
  font-size: 18px;
  font-weight: 700;
  font-family: var(--font-mono);
  line-height: 1;
  color: var(--fg);
  transition: color 200ms;
  flex-shrink: 0;
}
.stem-card:not(.inactive)[data-stem="vocals"] .stem-card-pct { color: var(--vocals); }
.stem-card:not(.inactive)[data-stem="drums"]  .stem-card-pct { color: var(--drums); }
.stem-card:not(.inactive)[data-stem="bass"]   .stem-card-pct { color: var(--bass); }
.stem-card:not(.inactive)[data-stem="guitar"] .stem-card-pct { color: var(--guitar); }
.stem-card:not(.inactive)[data-stem="piano"]  .stem-card-pct { color: var(--piano); }
.stem-card:not(.inactive)[data-stem="other"]  .stem-card-pct { color: var(--other); }
.stem-card.inactive .stem-card-pct { color: var(--muted); }

/* Analysis panel */
.daw-analysis-panel {
  padding: 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  display: flex;
  gap: 16px;
  flex-shrink: 0;
}
.daw-analysis-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 80px;
}
.daw-analysis-val { display: flex; align-items: center; gap: 8px; margin-top: 2px; }
.daw-analysis-num {
  font-size: 22px;
  font-weight: 600;
  line-height: 1.1;
  color: var(--fg);
}
.daw-analysis-num.accent { color: var(--accent); }
.daw-analysis-sub { font-size: 10px; color: var(--muted); margin-top: 2px; }
.daw-analysis-divider { width: 1px; background: var(--border); align-self: stretch; }
.daw-camelot-ring {
  width: 20px; height: 20px; border-radius: 50%;
  border: 1.5px solid var(--accent);
  display: flex; align-items: center; justify-content: center;
  align-self: center;
  flex-shrink: 0;
  font-size: 9px; font-weight: 700; color: var(--accent);
  background: rgba(244,183,64,0.08);
  font-family: var(--font-mono);
}

/* ── Section ribbon ── */
.daw-section-ribbon {
  display: flex;
  flex-shrink: 0;
  border-bottom: 1px solid var(--border);
}
.daw-mixer-label {
  width: 300px;
  flex-shrink: 0;
  background: var(--bg-2);
  border-right: 1px solid var(--border);
  padding: 6px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.daw-label-title { font-size: 12px; font-weight: 600; }
.daw-label-sub { font-size: 9px; }
.daw-sections-header { justify-content: space-between; }
.daw-sections-title-group { display: inline-flex; align-items: center; gap: 7px; min-width: 0; }
/* Clear and Add belong together. The header is space-between, so without this
   group each control drifts to its own corner and Clear ends up marooned. */
.sections-header-actions { display: inline-flex; align-items: center; gap: 6px; }
.daw-sections-area {
  flex: 1;
  position: relative;
  height: 36px;
  background: var(--bg-2);
  overflow: hidden;
  user-select: none;
}

/* Section blocks (sections.js populates) */
.section-block {
  position: absolute;
  top: 4px; bottom: 4px;
  box-sizing: border-box;
  border: 1px solid var(--sc, #4a7fff);
  border-radius: 4px;
  display: flex;
  align-items: center;
  overflow: hidden;
  cursor: grab;
  transition: filter 80ms;
}
.section-block:hover { filter: brightness(1.15); }
.section-block.sec-dragging { cursor: grabbing; filter: brightness(1.2); z-index: 10; }
.section-block.sec-resizing { filter: brightness(1.2); z-index: 10; }

.section-label {
  flex: 1;
  padding: 0 6px 0 10px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--sc, #4a7fff);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: auto;
}

.section-del {
  display: none;
  flex-shrink: 0;
  width: 16px; height: 16px;
  margin-right: 4px;
  border: none; background: none;
  color: var(--sc, #4a7fff);
  font-size: 13px; line-height: 1;
  cursor: pointer; border-radius: 3px;
  align-items: center; justify-content: center;
  opacity: 0.7;
}
.section-del:hover { opacity: 1; background: rgba(0,0,0,0.3); }
.section-block:hover .section-del { display: flex; }

.section-handle {
  position: absolute;
  top: 0; bottom: 0;
  width: 6px;
  cursor: col-resize;
  z-index: 2;
  flex-shrink: 0;
}
.section-handle-l { left: 0; }
.section-handle-r { right: 0; }
.section-handle:hover { background: rgba(255,255,255,0.12); }

.section-rename-input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: none;
  outline: none;
  font: inherit;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--sc, #4a7fff);
  padding: 0 6px 0 10px;
  caret-color: var(--sc, #4a7fff);
}

/* Sections save indicator */
.sections-save-indicator {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10px;
  color: var(--muted);
  white-space: nowrap;
  transition: opacity 400ms;
}
.sections-save-indicator.hidden { display: none; }
.sections-save-indicator.saved { color: #4caf7d; }
.sections-save-indicator::before {
  content: "";
  display: block;
  width: 8px; height: 8px;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  border-top-color: transparent;
  animation: sections-spin 600ms linear infinite;
}
.sections-save-indicator.saved::before {
  animation: none;
  border: none;
  width: auto; height: auto;
  content: "✓";
  font-size: 11px;
}
@keyframes sections-spin {
  to { transform: rotate(360deg); }
}

/* Add section button — lives in the Sections label column */
.sections-add-btn-label {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px 3px 6px;
  background: none;
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--muted);
  font-size: 10px; font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.sections-add-btn-label:hover {
  background: var(--panel-2);
  color: var(--fg);
  border-color: rgba(255,255,255,0.18);
}

/* Clear-all sections. Neutral until it is armed, then it states plainly that
   the next click destroys something, because nothing here can be undone. */
.sections-clear-btn[data-armed="1"] {
  border-color: color-mix(in srgb, var(--vocals) 55%, transparent);
  background: color-mix(in srgb, var(--vocals) 14%, transparent);
  color: var(--vocals);
}

/* Wave label (left column in wave header — Mixer label) */
.daw-wave-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 14px;
}

/* ── Panel toggles (#480) ── */
/* A second row under the composer, aligned to its right-hand end so it reads as
   belonging to the two controls above it. Collapse to nothing, not to a stub:
   the whole point is the height back, and a stub tall enough to hold a control
   is most of what the smaller panels are worth. That is only possible because
   the controls live up here, where the way back is always in the same place.

   This row costs the topbar about 19px, against up to 202px it can return. */
.daw-composer-stack {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.daw-composer-stack > .daw-composer { flex: none; }
/* Exactly as wide as the two controls above it, and sharing their right edge:
   the same --composer-action-w they are each sized from, so a longer
   translation widens all three together instead of leaving this one ragged.
   margin-left:auto does the alignment, since the stack is the composer's width. */
.daw-panel-toggles {
  width: calc(var(--composer-action-w) * 2);
  margin-left: auto;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2px;
  padding: 2px 7px;
  background: var(--panel);
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  min-width: 0;
}
.daw-panel-toggles-label,
.daw-panel-toggles-sep {
  font-size: 8px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--muted);
  line-height: 1;
  white-space: nowrap;
}
.daw-panel-toggle {
  padding: 2px 3px;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--fg-2);
  font-family: inherit;
  font-size: 8.5px; font-weight: 600; letter-spacing: 0.03em;
  text-transform: uppercase;
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--t-fast), background var(--t-fast), opacity var(--t-fast);
}
.daw-panel-toggle:hover { background: var(--panel-2); }
/* Legible means the panel is there, struck through means it is put away. The
   other way round -- highlighting the hidden ones -- inverts what a pressed
   toggle normally looks like, and makes the default state the loud one. */
.daw-panel-toggle[aria-pressed="true"] { color: var(--fg-2); }
.daw-panel-toggle[aria-pressed="false"] {
  color: var(--muted);
  opacity: 0.6;
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}

.app.panel-analysis-off .daw-track-header { display: none; }
.app.panel-sections-off .daw-section-ribbon { display: none; }
.app.panel-timeline-off .footer-wave-region { display: none; }

/* ── Waveform header ── */
.daw-wave-header {
  display: flex;
  flex-shrink: 0;
  border-bottom: 1px solid var(--border);
}
.daw-wave-label {
  width: var(--daw-col-w);
  flex-shrink: 0;
  background: var(--bg-2);
  border-right: 1px solid var(--border);
  min-height: 32px;
}
.daw-ruler-area {
  flex: 1;
  background: var(--bg-2);
  min-height: 32px;
  /* Clip the horizontally-scrolled ruler spill. overflow-x: clip (not hidden)
     keeps overflow-y visible so the vertical playhead line still extends down
     over the waveform lanes. */
  overflow-x: clip;
}

/* Ruler */
.lanes-ruler { position: relative; height: 18px; }
.lanes-ruler-time {
  position: absolute; inset: 0;
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--muted);
}
/* Match the zoomed waveform width so ticks/playhead stay aligned; JS translates
   it by scrollLeft. Left-anchored (right: auto) so width drives the size. */
.daw .lanes-ruler-time {
  right: auto;
  width: calc(100% * var(--zoom, 1));
}
.playhead-marker {
  position: absolute;
  top: -1px;
  transform: translateX(-50%);
  pointer-events: none;
}

/* ── Content area (mixer + waveform) ── */
.daw-content {
  flex: 1;
  display: flex;
  min-height: 0;
  overflow: hidden;
}

/* ── Stems panel (the studio's left column) ── */
.daw-stems-panel {
  width: var(--daw-col-w);
  flex-shrink: 0;
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg-2);
}

/* Stem list rows — kept in DOM for JS hook (.stem-mute/.stem-solo toggling, hidden visually) */
.stem-list {
  position: absolute;
  width: 0; height: 0; overflow: hidden;
  visibility: hidden; pointer-events: none;
  opacity: 0;
}
/* Also update the --lane-h var to match waveform lane height */
:root { --lane-h: 72px; } /* 70px wave + 2px separator */
.stem-icon { width: 14px; height: 14px; flex-shrink: 0; }
.stem-mute, .stem-solo { display: none; }
.stem-monitor { display: none; }
.drag-handle { display: none; }
.mini-meter { display: none; }

/* ── Mixer column (JS-built horizontal lanes) ── */
.mixer-column {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

/* Each mixer row height is driven by --lane-h (set dynamically in JS to fill available space) */
.lane-header.mx-row {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 0 10px;
  height: var(--lane-h, 72px);
  min-height: 72px;
  max-height: none;
  border-bottom: 2px solid var(--border);
  background: var(--bg-2);
  flex-shrink: 0;
  position: relative;
  transition: opacity var(--t-base);
  box-sizing: border-box;
}
.lane-header.mx-row.muted { opacity: 0.45; }
.lane-header.mx-row.hidden { display: none !important; }

.lane-stripe { display: none; }

/* Name + VU stacked vertically */
/* The name and its meter share a fixed column, and the fader takes whatever is
   left of the row. So this width is the fader's length: every pixel taken off
   here is a pixel the fader gains. 76px left the fader badly compressed once
   the key stepper joined the row. */
.lane-name-vu {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--lane-name-vu-gap, 5px);
  width: 58px;
  flex-shrink: 0;
  /* Centres the NAME on the row, not the name-and-meter pair. The row centres
     its children, so a stacked pair puts the name above the centre line by half
     the meter plus the gap -- and the waveform beside it is centred on that
     line, so the label reads as sitting too high. A top margin is centred with
     the item, so this offsets the pair by exactly half of it and the name comes
     level with its own waveform. Cheap and reversible: the meter simply moves
     down with it. */
  margin-top: calc(var(--lane-vu-h, 10px) + var(--lane-name-vu-gap, 5px));
}

/* Stem icon — hidden per user preference */
.mx-icon { display: none; }

/* Stem name */
.mx-name {
  font-size: 13px; font-weight: 500;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Fader (horizontal, native range input) */
.lane-knob.mx-fader {
  flex: 1;
  display: flex;
  align-items: center;
  min-width: 0;
}
.lane-knob-indicator { display: none; }
.mx-fader-input {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 22px;
  background: transparent;
  cursor: ew-resize;
  outline: none;
  margin: 0;
}
.mx-fader-input::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(
    to right,
    var(--fader-color, #888) 0%,
    var(--fader-color, #888) calc(var(--lane-pos, 0.5) * 100%),
    rgba(255,255,255,0.08) calc(var(--lane-pos, 0.5) * 100%)
  );
}
.mx-fader-input::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--fader-color, #888);
  margin-top: -5px;
  border: 2px solid rgba(0,0,0,0.35);
  box-shadow: 0 0 0 1px rgba(255,255,255,0.18);
  cursor: ew-resize;
}
.mx-fader-input::-moz-range-track {
  height: 4px; border-radius: 2px;
  background: rgba(255,255,255,0.08);
}
.mx-fader-input::-moz-range-thumb {
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--fader-color, #888);
  border: 2px solid rgba(0,0,0,0.35);
  cursor: ew-resize;
}

/* VU meter — sits below stem name in .lane-left-col, spans full column width */
/* 5px read as a hairline rather than a meter: at that height the gradient had
   nowhere to show and a moving level was hard to see at a glance. */
/* Height shared with .lane-name-vu's centring offset, so the two cannot drift. */
:root { --lane-vu-h: 10px; }
.lane-vu.mx-meter {
  position: relative;
  height: var(--lane-vu-h, 10px);
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 3px;
  overflow: hidden;
  --vu-level: 0%;
  --vu-peak: 0%;
}
.lane-vu-bar {
  display: none;
}
.lane-vu-bar.mx-meter-fill {
  display: block;
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--vu-level, 0%);
  background: linear-gradient(90deg, #22c55e 0%, #86efac 80%, #f97316 95%, #ef4444 100%);
  border-radius: 2px;
  transition: width 40ms linear;
}

/* dB value */
.mx-val {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  color: var(--fg);
  width: 36px;
  text-align: right;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}

/* M/S buttons (JS-built) */
.lane-icon-toggle.mx-btn,
.ms-btn.mx-btn,
.lane-dl.mx-btn {
  width: 22px; height: 20px;
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: 5px;
  color: var(--muted);
  font-size: 10px; font-weight: 700;
  font-family: var(--font-mono);
  letter-spacing: 0.05em;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
  flex-shrink: 0;
  text-decoration: none;
  padding: 0;
  opacity: 1;
}
.lane-icon-toggle.mx-btn:hover,
.ms-btn.mx-btn:hover { color: var(--fg); border-color: #3a4550; }

/* Mute button: "active" = NOT muted (normal). Engaged (muted) lights up blue,
   mirroring the solo button's own lit-up treatment below. */
.lane-icon-toggle.mx-btn.mute.active { color: var(--fg-2); border-color: var(--border-strong); }
.lane-icon-toggle.mx-btn.mute:not(.active) {
  background: rgba(59,130,246,0.18);
  color: #60a5fa;
  border-color: rgba(59,130,246,0.4);
}

/* Solo button: "active" = soloed */
.ms-btn.mx-btn.active { background: rgba(244,183,64,0.18); color: var(--accent); border-color: rgba(244,183,64,0.4); }

/* Download button */
.lane-dl.mx-btn {
  color: var(--muted);
  border-color: transparent;
}
.lane-dl.mx-btn:hover { color: var(--fg); border-color: var(--border); }
.lane-dl.mx-btn svg { width: 13px; height: 13px; }

/* Unavailable stems — gray entire mixer row and waveform row */
.lane-header.unavailable { opacity: 0.25; pointer-events: none; }
.stem-waveform-row.unavailable { opacity: 0.2; pointer-events: none; }
.mx-fader-input { touch-action: pan-y; }

/* ── Waveform panel (right) ── */
/* Layout only — waves.css handles all visual styling inside (.wave-scroll bg,
   golden scrollbar, .loop-region, .waves-grid, .stem-waveform-layer etc.) */
.daw-wave-panel {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  position: relative;
}

/* waves.css gives .wave-editor padding + border-radius for the old rounded panel
   style. In the flat DAW layout those are unwanted — strip them. */
.daw .wave-editor,
.app:not(.is-import) .daw-wave-panel.wave-editor {
  padding: 0 !important;
  min-height: 0 !important;
  border-radius: 0 !important;
}

/* Our zoom toolbar sits outside .wave-editor (in .daw-wave-header), so
   the wave-scroll should fill the full panel height instead of calc(100% - 32px).
   Also remove the rounded corners waves.css adds in active state. */
.daw .wave-scroll {
  flex: 1 !important;
  height: auto !important;
  border-radius: 0 !important;
  border: none !important;
  overflow-y: auto;
  /* waves.css sets scroll-behavior: smooth. In the studio the mixer column and
     the wave lanes mirror each other's scrollTop (wireLaneScrollSync), and a
     smooth programmatic scroll turns that mirror into a feedback loop: each
     echo re-targets the in-flight animation, so a vertical wheel-scroll to the
     middle oscillates instead of settling, i.e. the lanes shake (#182). Instant
     scrolling makes the mirror a no-op once both panes match. */
  scroll-behavior: auto;
}

/* Canvas fills the panel when lanes fit, but grows with the track stack when
   they overflow (#159) so .wave-scroll can scroll the extra lanes vertically. */
.daw .wave-canvas { min-height: 100%; height: auto; }

/* In the original layout a 48px stem-icon strip lived INSIDE the wave panel,
   offsetting waves-column/multitrack/waveform-layer by 48px. In our layout the
   mixer is a separate 300px panel, so all those 48px offsets must be zero. */
.daw .waves-column,
.app:not(.is-import) .daw-wave-panel .waves-column {
  padding-left: 0 !important;
  --wave-gutter: 0px !important;
}
/* Show WaveSurfer native bar rendering; hide the SVG overlay layer */
.daw #multitrack-container {
  opacity: 1 !important;
  pointer-events: all !important;
  position: relative !important;  /* in flow → waves-column height driven by WaveSurfer */
  inset: 0 !important;             /* waves.css sets inset: 0 0 0 48px; zero left offset */
}
/* The wavesurfer-multitrack bundle wraps its tracks in its own
   `<div style="overflow-x: scroll">`, which renders a permanently visible
   horizontal scrollbar — an empty light bar when the content fits (the "white
   bar" bug). We fit the bundle to its container and let the outer .wave-scroll
   own horizontal scrolling, so suppress the bundle's wrapper scrollbar. */
.daw #multitrack-container > div {
  overflow-x: hidden !important;
}
/* Zero waves.css 48px left offsets that assumed an icon strip inside the wave panel */
.daw .waves-grid { left: 0 !important; }
.daw .lanes-ruler { margin-left: 0 !important; }
.daw .stem-waveform-layer {
  display: none !important;
  /* waves.css offsets this layer by left:48px for the legacy icon-strip layout.
     The DAW layout has no in-panel strip, so it must start at 0 like .waves-grid
     and #multitrack-container above; otherwise the overview waveform is shifted
     48px right of the ruler/playhead, so t=0 in the audio lands ~48px before the
     drawn waveform begins (a constant gap that scales with track length, #189). */
  left: 0 !important;
  right: 0 !important;
}
/* When the Web Audio engine owns playback, the multitrack is mounted with null
   URLs and never decodes audio, so the WaveSurfer canvas is empty. Show the SVG
   overview layer (rendered from peaks.json) as the visual source instead. */
.daw.engine-waveforms .stem-waveform-layer {
  display: flex !important;
}
/* The column is exactly the stack _applyLaneHeight computed, never whatever the
   multitrack happens to be. Letting the multitrack size it looks reasonable and
   is where the misalignment came from: its lane height is fixed when the tracks
   are created, so after a resize the column keeps the old size while the mixer
   rows beside it follow the new one, and the two walk apart down the stack.
   Measured at 1600x768 after a resize from 900: the column stayed 498px against
   a 432px stack, so waveform rows sat 83px apart against the mixer's 72 and the
   last pair was 55px out of line.

   The mixer stack is count * --lane-h and this is count * --lane-h, so they
   agree by construction rather than by coincidence. */
.daw .waves-column {
  height: var(--wave-widget-track-stack-h, auto) !important;
  min-height: var(--wave-widget-track-stack-h, 0) !important;
}

.loop-region.hidden { display: none !important; }


/* Wave loading overlay */
.wave-loading-overlay {
  position: absolute; inset: 0; z-index: 10;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 16px;
  background: rgb(11, 15, 18);
}
.wave-loading-overlay.hidden { display: none !important; }
.wave-loading-glow {
  width: 80px; height: 80px; border-radius: 50%;
  background: radial-gradient(circle, rgba(244,183,64,0.2) 0%, transparent 70%);
  animation: daw-pulse 2s ease-in-out infinite;
}
@keyframes daw-pulse { 0%,100%{opacity:0.5;transform:scale(0.9);} 50%{opacity:1;transform:scale(1.1);} }
.wave-loading-lines {
  display: flex; gap: 3px; align-items: center;
}
.wave-loading-lines i {
  display: block; width: 3px; height: 20px;
  background: var(--accent); border-radius: 2px;
  animation: daw-bar 1.2s ease-in-out infinite;
}
.wave-loading-lines i:nth-child(2) { animation-delay: 0.1s; }
.wave-loading-lines i:nth-child(3) { animation-delay: 0.2s; }
.wave-loading-lines i:nth-child(4) { animation-delay: 0.3s; }
.wave-loading-lines i:nth-child(5) { animation-delay: 0.4s; }
.wave-loading-lines i:nth-child(6) { animation-delay: 0.5s; }
@keyframes daw-bar { 0%,100%{transform:scaleY(0.4);opacity:0.5;} 50%{transform:scaleY(1.4);opacity:1;} }
.wave-loading-msg { font-size: 12px; color: var(--muted); }

/* Presence panel (hidden, JS compat) */
.presence-panel { display: none; }

/* ── Transport footer ── */

.daw-footer {
  /* No height of its own: the two tiers inside decide it, and every pixel not
     spent here goes to the mixer, which is the panel actually short of room
     (#480). This used to carry min-height: 200px, from when the click-track
     cluster could wrap onto a second line and a rigid height would have
     clipped it. The controls row no longer wraps, so the floor only padded the
     footer past its content -- 30px of it, which pooled as a gap wherever the
     tiers were not pushed. */
  flex-shrink: 0;
  border-top: 1px solid var(--border);
  background: var(--bg-2);
  /* Two columns on the studio's own grid: the track identity sits under the
     stems/mixer panel and carries its width, everything time-related sits
     under the lanes and starts exactly where the lane waveforms start, so a
     position reads at the same x in both. The top border still spans the full
     width -- that edge belongs to the footer/lanes boundary, not the grid. */
  display: flex !important;
  flex-direction: row;
  align-items: stretch;
}

.daw-footer-left {
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-width: 140px;
  flex: 1;
}
.daw-time-big {
  font-size: 20px; font-weight: 600; letter-spacing: -0.01em;
}
.daw-time-total { font-size: 13px; color: var(--muted); }
.daw-footer-right {
  display: flex; align-items: center; gap: 8px;
  min-width: 140px; justify-content: flex-end;
  flex: 1;
}
.daw-master-fader { accent-color: var(--accent); cursor: pointer; }
.daw-btn {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  color: var(--fg); border-radius: 8px; font-size: 12px;
  font-family: inherit; cursor: pointer;
  transition: background var(--t-fast);
}
.daw-btn:hover { background: var(--panel-3); }

/* Transport controls */
.daw-transport-controls {
  display: flex; align-items: center; justify-content: center; gap: 8px;
}
.daw-play-btn {
  background: var(--accent);
  color: #1a1206;
  width: 56px; height: 56px;
  border-radius: 50%; border: none;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  box-shadow: 0 2px 10px rgba(244,183,64,0.35), inset 0 1px 0 rgba(255,255,255,0.18);
  transition: transform var(--t-fast), box-shadow var(--t-fast), background var(--t-fast);
  flex-shrink: 0;
}
.daw-play-btn:hover { box-shadow: 0 2px 16px rgba(244,183,64,0.5), inset 0 1px 0 rgba(255,255,255,0.22); }
.daw-play-btn:active { transform: scale(0.96); }
/* Playing = green (go); idle/ready stays gold. */
.daw-play-btn.playing {
  background: #4caf7d;
  box-shadow: 0 2px 12px rgba(76,175,125,0.45), inset 0 1px 0 rgba(255,255,255,0.2);
}
.daw-play-btn.playing:hover { box-shadow: 0 2px 18px rgba(76,175,125,0.6), inset 0 1px 0 rgba(255,255,255,0.24); }

/* JS toggles these to show play vs pause icon */
.btn-transport.playing .pause-icon { display: block !important; }
.btn-transport.playing > svg:first-child { display: none; }

/* Stop/loop buttons inside the footer transport row */
.daw-footer .daw-iconbtn.btn-transport {
  width: 40px; height: 40px;
  border-radius: 9px;
  display: inline-flex; align-items: center; justify-content: center;
}

/* Loop active state */
.daw-iconbtn.loop.active,
.btn-transport.loop.active { color: var(--accent); }

/* Export buttons in footer */
.daw-footer .footer-btn {
  padding: 0 14px;
  height: 36px;
  border-radius: 8px;
  gap: 6px;
  white-space: nowrap;
}
.daw-footer .footer-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

/* ── Footer redesign ── */

/* ── Footer layout: three tiers (design 1b) ── */
/* Tier 1 -- what is loaded and what leaves the app (track identity, favourite,
   Export Mix). Tier 2 -- every playback and click control, in labelled clusters
   separated by hairline dividers. Tier 3 -- the timeline those clusters act on.
   Each tier owns its own full-width budget instead of everything competing for
   room in one line. */

.footer-main {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
}

/* ── Track identity, in the footer's timeline gutter ── */
.track-panel-head {
  display: flex; align-items: flex-start; gap: 10px; min-width: 0;
}
/* Favourite belongs with what it marks, so it rides the title line rather than
   sitting with Export Mix. Boxed, because a bare icon beside the cover art
   reads as decoration. */
.track-panel-head .daw-fav-btn {
  flex: none; margin-left: auto;
  width: 28px; height: 28px; padding: 0;
  justify-content: center;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  border-radius: 8px;
  transition: background var(--t-fast), color var(--t-fast);
}
.track-panel-head .daw-fav-btn:hover { background: var(--panel-3); }
/* Hairline cluster separator: fades out at both ends so it reads as a seam
   between groups rather than a hard rule across the footer. Every one of these
   separates something now that .footer-row-controls never wraps -- the
   is-orphan state that used to hide a divider stranded at the end of a wrapped
   line went with the wrapping. */
.footer-divider {
  width: 1px; flex: none;
  background: linear-gradient(
    180deg, transparent, var(--border-strong) 22%, var(--border-strong) 78%, transparent
  );
}
.footer-row-controls .footer-divider { height: 44px; }
/* Starts at the footer's own left edge. The track identity that used to sit in
   front of it now lives in the library sidebar, and leaving its 300px gutter
   behind pushed every control into the right of the window with a void beside
   it.

   One line, always. Wrapping rearranged the band into a different shape at
   every window width -- clusters piling onto a second row, the click track
   splitting its own options in half -- so the footer never looked like itself
   twice. Nothing here shrinks either (.footer-group is flex: none), so when
   the window is too narrow the row scrolls sideways rather than reflowing. */
.footer-row-controls {
  display: flex; align-items: flex-start; flex-wrap: nowrap;
  gap: 16px;
  padding: 12px 18px 14px;
}
/* The clusters, and only the clusters, scroll. Favourite and Export Mix sit
   outside this box so a window too narrow for the row cannot carry them off
   the right-hand edge. */
.footer-clusters {
  flex: 1; min-width: 0;
  display: flex; align-items: flex-start; flex-wrap: nowrap;
  overflow-x: auto;
  gap: 16px;
}
/* Acts on the track, not on playback, so it is pinned opposite the clusters
   rather than filed among them. Nudged down to sit on the controls' own line
   instead of the labels above them. */
.footer-track-actions {
  flex: none;
  display: flex; align-items: center; gap: 8px;
  margin-top: 18px;
}
.footer-track-actions .track-chip { height: 32px; }
/* Opens toward the middle of the window: anchored left, a 260px menu on the
   footer's right edge would hang off it. */
.footer-track-actions .track-chip-panel { left: auto; right: 0; }
/* Natural width, never squeezed: a cluster that shrinks re-wraps its own
   controls, which is the pile-up the row-level nowrap exists to prevent. */
.footer-group {
  display: flex; flex-direction: column; gap: 6px;
  flex: none;
}
.footer-group-label {
  display: flex; align-items: center; gap: 7px;
  font-size: 10px; font-weight: 600; letter-spacing: 0.11em; text-transform: uppercase;
  color: var(--muted);
}
/* One control height across every cluster, so the row reads as a single band
   of controls rather than a ragged stack. */
.footer-group-body {
  display: flex; align-items: center; flex-wrap: nowrap; gap: 8px;
  min-height: 34px;
}
.alpha-badge {
  padding: 1px 5px; border-radius: 4px;
  background: rgba(74,140,255,0.16); border: 1px solid rgba(74,140,255,0.4);
  color: #4a8cff; font-size: 8.5px; font-weight: 700; letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* Tier 3: the timeline. Full-bleed rather than an inset rounded panel -- its
   left edge has to land exactly on the lane waveforms' left edge, and a side
   border would offset the canvas by its own width. Top and bottom rules only,
   the way the ruler area above the lanes is drawn. */
/* Bottom tier: the gutter, then the timeline. Two columns rather than one, so
   the timeline's left edge lands exactly on the lane waveforms' left edge and
   a position reads at the same x in both -- while the 300px that alignment
   costs carries Export Mix instead of standing empty. */
.footer-wave-region {
  display: flex; align-items: stretch;
  padding: 0 18px 14px 0; flex-shrink: 0;
}
/* Exactly the mixer column's width: that offset is what puts the timeline
   beside it on the lanes' x, so the alignment and the block that fills the
   gutter are one fact rather than two numbers that have to agree. */
.footer-track-slot {
  width: var(--daw-col-w); flex: none;
  box-sizing: border-box;
  padding: 0 18px 0 18px;
  display: flex; flex-direction: column; justify-content: center; gap: 5px;
  min-width: 0;
  overflow: hidden;
}
.footer-wave-col {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
}
.footer-wave-panel {
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  /* Closes the strip's open left edge and lands on the same x as the mixer
     panel's right border, so that seam runs on down the page. Drawn as an
     outset shadow rather than a border: a border would sit inside the box and
     push the canvas a pixel off the lane waveforms it has to line up with. */
  box-shadow: -1px 0 0 var(--border);
  background: var(--panel);
  overflow: hidden;
}
/* Ticks at the same times as the lanes ruler (buildFooterWaveTicks shares its
   step), positioned by percentage so both rulers mark a time at the same x. */
.footer-wave-ticks {
  height: 18px; position: relative;
}
/* No track, no timeline to label -- an empty ruler strip above the placeholder
   waveform would be measuring nothing. */
.footer-wave-ticks:empty { display: none; }
.footer-wave-ticks .tick {
  position: absolute; top: 0; bottom: 0;
  border-left: 1px solid var(--border-strong);
  padding-left: 4px;
  display: flex; align-items: flex-start;
  pointer-events: none;
}
.footer-wave-ticks .tick-label {
  font-family: var(--font-mono); font-size: 9px; line-height: 1.6;
  color: var(--muted-2);
  font-variant-numeric: tabular-nums;
}
.footer-wave-bar {
  height: 31px; flex-shrink: 0;
  position: relative; overflow: hidden;
}
#footer-waveform {
  position: absolute; inset: 0;
  width: 100%; height: 100%; display: block;
}
.footer-scrub {
  position: absolute; inset: 0;
  cursor: pointer; z-index: 2;
  background: transparent;
}
.footer-scrub-fill { display: none; }

.track-panel-info {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; gap: 3px;
}
/* Two lines, then clipped: a column this narrow would otherwise cut most
   titles after three or four words. */
.track-panel-title {
  min-width: 0;
  font-size: 13px; font-weight: 600; line-height: 1.35;
  /* Overrides the nowrap/ellipsis on .daw-track-title, which is written for
     single-line contexts. */
  white-space: normal;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere;
  color: var(--fg);
}
.track-panel-cover {
  width: 40px !important; height: 40px !important;
  border-radius: 7px;
  flex-shrink: 0;
}
/* Wraps freely here -- the gutter is narrow and the block is stacked, so the
   meta reads as a short paragraph rather than a clipped line. */
.footer-track-slot .daw-track-meta-line { row-gap: 2px; line-height: 1.35; }
.footer-art {
  width: 44px; height: 44px; border-radius: 6px;
  background: var(--panel-3); flex-shrink: 0; overflow: hidden;
  display: none;
}
.footer-art.has-art { display: block; }
.footer-thumb-img {
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity 0.2s;
}
.footer-thumb-img.loaded { opacity: 1; }
.footer-info {
  display: flex; flex-direction: column; gap: 3px; min-width: 0;
}
.footer-title {
  font-size: 13px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--fg);
}
.footer-meta {
  font-size: 11px; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Position group: elapsed / total time, then the loop controls that act on
   that position (design 1b groups them together, not with the transport). */
.footer-group-position .footer-group-body { gap: 4px; }
.footer-elapsed {
  font-size: 18px; font-weight: 500; letter-spacing: -0.02em; color: var(--fg);
}
.footer-total {
  font-size: 12px; font-weight: 400; color: var(--muted-2);
}
.footer-time-sep { font-size: 12px; color: var(--muted-2); }

/* Exact loop start/end inputs (inline, right of the loop button) */
.footer-loop-times {
  display: flex; align-items: center; gap: 5px;
  margin-left: 4px; cursor: default; user-select: none;
}
.loop-times-sep { font-size: 12px; color: var(--muted); flex-shrink: 0; }
.loop-time-input {
  width: 8ch; box-sizing: content-box;
  padding: 2px 6px;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: 5px; outline: none;
  color: var(--fg); font-family: inherit; font-size: 12px; font-weight: 600;
  font-variant-numeric: tabular-nums; text-align: center;
}
.loop-time-input:focus { border-color: var(--accent); }
.loop-time-input:disabled { opacity: 0.45; cursor: not-allowed; }

/* Transport group: stop square + a play key wide enough to be the obvious
   primary, both on the shared 34px control height. */
.footer-group-transport .daw-iconbtn.btn-transport {
  width: 34px; height: 34px; border-radius: 8px;
  background: var(--panel-2);
  border-color: var(--border-strong);
  color: var(--fg-2);
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.footer-group-transport .daw-iconbtn.btn-transport:hover {
  background: var(--panel-3);
  color: var(--fg);
}
.footer-group-transport .daw-play-btn {
  width: 44px; height: 34px; border-radius: 8px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18);
}
.footer-group-transport .daw-play-btn:hover {
  box-shadow: 0 2px 12px rgba(244,183,64,0.35), inset 0 1px 0 rgba(255,255,255,0.22);
}
.footer-group-transport .daw-play-btn.playing:hover {
  box-shadow: 0 2px 12px rgba(76,175,125,0.45), inset 0 1px 0 rgba(255,255,255,0.24);
}
/* Active transport states: stop = red while stopped, loop = blue while looping. */
.footer-group-transport .btn-transport.stopped,
.footer-group-transport .btn-transport.stopped:hover {
  background: rgba(214,90,74,0.16);
  border-color: rgba(214,90,74,0.55);
  color: var(--danger);
}
/* Loop sits in the Position group and reads as a modifier on the readout next
   to it, so it is a short labelled pill rather than a full-height control. */
.footer-group-position .daw-iconbtn.btn-transport.loop {
  width: auto; height: 26px; padding: 0 9px; gap: 6px; margin-left: 6px;
  border-radius: 7px;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  color: var(--fg-2);
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.footer-group-position .btn-transport.loop:hover {
  background: var(--panel-3); color: var(--fg);
}
.loop-btn-label { font-size: 11px; font-weight: 500; white-space: nowrap; }
.footer-group-position .btn-transport.loop.active,
.footer-group-position .btn-transport.loop.active:hover {
  background: rgba(74,140,255,0.16);
  border-color: rgba(74,140,255,0.55);
  color: #4a8cff;
}

/* ── Segmented controls (Speed, click rate) ── */
/* One joined track rather than separate pills: the options are exclusive, and
   butting them together says so (design 1b). */
.footer-seg {
  display: flex; height: 34px; overflow: hidden;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: 8px;
}
.footer-seg > button {
  border: 0; background: transparent;
  padding: 0 11px; cursor: pointer;
  color: var(--muted);
  font-family: var(--font-mono); font-size: 11px; font-weight: 500; line-height: 1;
  white-space: nowrap;
  transition: background var(--t-fast), color var(--t-fast);
}
.footer-seg > button:hover { background: var(--panel-3); color: var(--fg); }
.footer-seg > button + button { border-left: 1px solid var(--border); }
.speed-btn.active,
.speed-btn.active:hover {
  background: rgba(232,200,64,0.16); color: var(--accent);
}
/* Transpose stepper (#245). Sits in a .footer-seg so it inherits the frame and
   hover behaviour of the speed and click controls beside it; only the readout
   between the two buttons is new. */
.pitch-value {
  display: flex; align-items: center; justify-content: center;
  min-width: 34px; padding: 0 6px;
  border-left: 1px solid var(--border); border-right: 1px solid var(--border);
  color: var(--muted);
  font-family: var(--font-mono); font-size: 11px; font-weight: 600; line-height: 1;
  font-variant-numeric: tabular-nums;  /* so +10 and -6 do not shift the buttons */
  transition: color var(--t-fast), background var(--t-fast);
}
/* Lit only when transposed, so "this track is not in its original key" is
   visible at a glance rather than needing the number to be read. */
.pitch-value.active {
  background: rgba(232,200,64,0.16); color: var(--accent);
}
.pitch-btn:disabled {
  opacity: 0.35; cursor: default;
}
.pitch-btn:disabled:hover { background: transparent; color: var(--muted); }

/* Reset. Outside the stepper's frame, because it does something to the whole
   mix rather than one more step: it returns every mixer lane to the key the
   recording is in, which the stepper alone cannot do once lanes have been moved
   individually. */
.pitch-reset {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0;
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  color: var(--muted);
  font-size: 15px; line-height: 1;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.pitch-reset:hover:not(:disabled) {
  background: var(--panel-3); color: var(--fg); border-color: var(--border);
}
.pitch-reset:disabled { opacity: 0.35; cursor: default; }

.metro-mult-btn.active,
.metro-mult-btn.active:hover {
  background: rgba(74,140,255,0.16); color: #4a8cff;
}

/* Click track on/off toggle. Lit gold while the click is running, so its
   state is visible without any other affordance. */
.click-toggle-btn {
  display: inline-flex; align-items: center; gap: 7px;
  height: 34px; padding: 0 10px;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: 8px; color: var(--fg-2); cursor: pointer;
  font-family: inherit; font-size: 11px; font-weight: 600; letter-spacing: 0.04em;
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.click-toggle-btn:hover:not(:disabled) { background: var(--panel-3); color: var(--fg); }
.click-toggle-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.click-toggle-btn.active,
.click-toggle-btn.active:hover {
  background: rgba(232,200,64,0.18); border-color: rgba(232,200,64,0.55); color: var(--accent);
}
.click-metro-icon { flex-shrink: 0; }

/* Beat grid editor: canvas overlay + toolbar */
.beatgrid-canvas {
  position: absolute; inset: 0; z-index: 12;
  pointer-events: none; /* enabled only while editing */
}
.beatgrid-canvas.hidden { display: none; }

.beatgrid-toolbar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 7px 10px; margin: 0 0 6px;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  border-radius: 7px;
}
.beatgrid-toolbar.hidden { display: none; }
.bg-tool-label {
  font-size: 10px; font-weight: 700; letter-spacing: 0.08em; color: var(--muted);
}
.bg-tools { display: flex; gap: 3px; }
.bg-btn {
  padding: 3px 9px;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: 5px; color: var(--fg-2); cursor: pointer;
  font-family: inherit; font-size: 11px; font-weight: 600;
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.bg-btn:hover:not(:disabled) { background: var(--panel-3); color: var(--fg); }
.bg-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.bg-btn.active {
  background: rgba(74,140,255,0.16); border-color: rgba(74,140,255,0.55); color: #4a8cff;
}
.bg-btn.bg-primary {
  background: rgba(232,200,64,0.16); border-color: rgba(232,200,64,0.5); color: var(--accent);
}
.bg-btn.bg-danger:hover { border-color: rgba(214,90,74,0.55); color: var(--danger); }
.bg-check {
  display: flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 600; color: var(--fg-2); cursor: pointer; user-select: none;
}
.bg-check input[type="checkbox"] { accent-color: var(--accent); cursor: pointer; }
.bg-meter input[type="number"] {
  width: 4ch; padding: 2px 4px;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: 4px; color: var(--fg);
  font-family: inherit; font-size: 11px; font-weight: 600; text-align: center;
}
.bg-spacer { flex: 1; min-width: 8px; }
.bg-hint { font-size: 10.5px; color: var(--muted); flex-basis: 100%; }

/* Click track options: inline in the Click track cluster, always visible once
   a track has a beat grid (#269 follow-up -- no popover, no click to reveal
   them). Everything shares the 34px control height of the clusters beside it;
   .daw-footer is min-height (not a fixed height) so a wrap never clips. */
.footer-metro-panel {
  /* display:contents removes this element's own box and promotes its
     children (the count-in switch, accent select, grid button, rate segment,
     volume) to be direct flex items of .footer-group-body, as peers of the
     on/off pill -- one flat wrap group the browser can line-break wherever
     the available width actually allows, instead of the pill being forced
     alone onto its own row and everything else confined to a second,
     artificially narrow one (#269 follow-up). .hidden below still works: it
     carries !important, which overrides this when the panel has no grid to
     show options for. */
  display: contents;
}
.footer-metro-panel.hidden { display: none; }
.metro-row { display: flex; align-items: center; gap: 9px; }
.metro-vol-row { width: 140px; }
.metro-vol-icon { color: var(--muted); flex-shrink: 0; }
.metro-label {
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.06em;
  color: var(--muted); flex-shrink: 0;
}
.metro-row input[type="range"] { flex: 1; min-width: 0; accent-color: var(--accent); }
.metro-val {
  font-family: var(--font-mono); font-size: 11px; color: var(--muted);
  width: 4ch; text-align: right;
  font-variant-numeric: tabular-nums; flex-shrink: 0;
}
/* Native select, restyled to the same pill as the buttons around it: the
   caret is drawn by the wrapper so no appearance-dependent arrow shows. */
.metro-select-wrap { position: relative; display: inline-flex; }
.metro-select-wrap::after {
  content: ""; position: absolute; right: 10px; top: 50%;
  margin-top: -2px; pointer-events: none;
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-top: 5px solid var(--muted);
}
.metro-select {
  appearance: none; -webkit-appearance: none;
  height: 34px; padding: 0 26px 0 10px; max-width: 168px;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: 8px; color: var(--fg); cursor: pointer;
  font-family: inherit; font-size: 12px; font-weight: 500; outline: none;
}
.metro-select:hover { background: var(--panel-3); }
.metro-select:focus { border-color: var(--accent); }

/* Detection confidence / unavailability note: its own line under the
   waveform, where it reads as a caption on the timeline it describes (design
   1b). Hidden until it has text, clipped to one line with the full text as a
   native tooltip. */
.metro-note {
  /* No padding of its own: .footer-wave-region insets the right and the
     export gutter the left, so the note already starts on the timeline's x. */
  margin-top: 8px;
  font-size: 11px; line-height: 1.3; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.metro-note:empty { display: none; }
.metro-note.warn { color: var(--danger); }

/* Export chip button */
.track-chip-wrap {
  position: relative; flex-shrink: 0;
  display: flex; align-items: center;
}
.track-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  color: var(--fg); border-radius: 8px; font-size: 12px; font-weight: 500;
  font-family: inherit; cursor: pointer; padding: 0 12px; height: 36px;
  white-space: nowrap;
  transition: background var(--t-fast);
}
.track-chip:hover { background: var(--panel-3); }
.track-chip-primary {
  background: var(--accent); color: #1a1206;
  border-color: transparent;
}
.track-chip-primary:hover { background: color-mix(in srgb, var(--accent) 85%, white); }
.track-chip-primary:disabled {
  background: var(--panel-2); color: var(--fg-muted);
  border-color: var(--border-strong); cursor: not-allowed; opacity: 0.5;
}

.track-chip-panel {
  /* Opens up and to the right: the button now lives in the left column, and a
     right-aligned panel would hang past the footer's left edge over the
     sidebar. */
  position: absolute; bottom: calc(100% + 6px); left: 0; z-index: 30;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  border-radius: 10px; padding: 4px;
  min-width: 120px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.4);
}
.track-chip-panel.hidden { display: none !important; }

.chip-panel-item {
  display: flex; align-items: center; gap: 8px;
  width: 100%; padding: 7px 12px;
  background: none; border: none; border-radius: 7px;
  color: var(--fg); font-size: 13px; font-family: inherit;
  cursor: pointer; text-align: left; white-space: nowrap;
}
.chip-panel-item:hover { background: var(--panel-3); }
.chip-panel-item.active { color: var(--accent); font-weight: 600; }

/* ── Export split-button dropdown ── */
/* The whole button toggles the menu, so the caret is purely a decorative
   open/close indicator (no separate hit area). */
.export-caret { opacity: 0.8; }
/* Primary button busy state: swap the download icon for a spinner. */
.export-spinner { display: none; }
.track-chip.is-busy .export-dl-icon { display: none; }
.track-chip.is-busy .export-spinner { display: inline-block; animation: sections-spin 700ms linear infinite; }

.chip-panel-export { min-width: 260px; padding: 6px; }

/* WAV / MP3 segmented toggle in the panel header */
.export-format-toggle {
  display: flex; gap: 3px; padding: 3px;
  margin-bottom: 4px;
  background: var(--bg); border: 1px solid var(--border);
  border-radius: 8px;
}
.export-fmt {
  flex: 1; padding: 5px 0; border: none; border-radius: 6px;
  background: transparent; color: var(--muted);
  font-family: var(--font-mono); font-size: 11px; font-weight: 600;
  letter-spacing: 0.04em; cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}
.export-fmt:hover { color: var(--fg-2); }
.export-fmt.active { background: var(--panel-3); color: var(--accent); }

/* Action rows — two-line: icon + (title/desc) + trailing check/count */
.export-item {
  align-items: center; gap: 11px;
  padding: 9px 10px; white-space: normal;
}
.export-item .chip-item-icon {
  flex-shrink: 0; width: 22px;
  display: flex; align-items: center; justify-content: center;
  color: var(--muted);
}
.export-item .chip-item-text {
  flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px;
}
.chip-item-title { font-size: 13px; font-weight: 500; color: var(--fg); }
.chip-item-desc { font-size: 11px; color: var(--muted); }
.chip-item-check { color: var(--accent); flex-shrink: 0; }
.export-item:hover:not([aria-disabled="true"]) { background: var(--panel-3); }
.export-item[aria-disabled="true"] { opacity: 0.4; pointer-events: none; }

/* MP4 is offered as an export format only when the job has a preserved video
   track (mp4 upload or YouTube). player.js toggles .has-video on the wrap. */
/* Opt-in rather than automatic: baking a permanent click into a bounce you
   meant to be clean is not obvious until you play it back. Applies to every
   format, audio and video alike. */
.export-click-opt {
  display: flex; align-items: center; gap: 7px;
  margin: 2px 4px 4px; padding: 5px 6px;
  border-radius: 6px; cursor: pointer; user-select: none;
  font-size: 11.5px; font-weight: 600; color: var(--fg-2);
}
.export-click-opt:hover { background: var(--panel-3); color: var(--fg); }
.export-click-opt input[type="checkbox"] { accent-color: var(--accent); cursor: pointer; }
.export-click-opt.disabled { opacity: 0.4; cursor: not-allowed; }
.export-click-opt.disabled:hover { background: none; color: var(--fg-2); }

/* ── Live search dropdown (topbar) ────────────────────────────────
   Anchored to .url-wrap, which is position:relative already for the drag
   overlay. contain:layout paint keeps a long result list from forcing the
   composer above it to re-layout while rows stream in. */
/* Lives on <body>, not in .url-wrap: the composer clips its children
   (overflow:hidden for the rounded pill), which made an absolutely positioned
   panel invisible. JS sets left/top/width from the composer's rect. */
.search-panel {
  position: fixed; z-index: 300;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,0.42);
  overflow: hidden; contain: layout paint;
}
.search-panel.hidden { display: none; }
.search-tabs { display: flex; gap: 2px; padding: 5px; border-bottom: 1px solid var(--border); }
.search-tab {
  flex: 1; border: 0; background: transparent; cursor: pointer;
  padding: 5px 8px; border-radius: 6px; color: var(--muted);
  font-size: 11px; font-weight: 600; white-space: nowrap;
  transition: background var(--t-fast), color var(--t-fast);
}
.search-tab:hover { background: var(--panel-3); color: var(--fg); }
.search-tab.active { background: var(--panel-3); color: var(--accent); }
.search-status { padding: 12px 12px; font-size: 11.5px; color: var(--muted); }
.search-status.hidden { display: none; }
.search-list {
  list-style: none; margin: 0; padding: 4px;
  max-height: 340px; overflow-y: auto; overscroll-behavior: contain;
}
.search-row {
  display: flex; flex-direction: column;
  padding: 6px; border-radius: 7px; cursor: pointer;
}
.search-row-main { display: flex; align-items: center; gap: 9px; }
.search-row:hover, .search-row.active { background: var(--panel-3); }
.search-thumb {
  flex-shrink: 0; width: 64px; height: 36px; object-fit: cover;
  border-radius: 4px; background: var(--panel-2);
}
.search-thumb-empty { display: block; }
.search-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.search-title {
  font-size: 12px; font-weight: 600; color: var(--fg);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.search-meta {
  font-size: 10.5px; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Over the duration limit the pipeline refuses the job, so the row is not
   selectable at all rather than merely warning about it. */
.search-row.too-long { cursor: not-allowed; opacity: 0.55; }
.search-row.too-long:hover { background: none; }
.search-warn {
  flex-shrink: 0; font-size: 10px; font-weight: 600; color: var(--danger);
  white-space: nowrap;
}

/* Audition controls. Hidden until the row is hovered or playing, so a list of
   eight results is not eight competing buttons. */
/* A labelled pill, not a bare glyph. An unlabelled circle on a search result
   reads as "play this result", which is the one thing it does not do: it
   auditions, it does not select. Always visible for the same reason -- a
   control you have to hover to discover is not a control most people find. */
.search-preview-btn {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 5px;
  height: 26px; padding: 0 10px 0 8px;
  border: 1px solid var(--border-strong); border-radius: 13px;
  background: var(--panel-2); color: var(--fg-2); cursor: pointer;
  font-family: inherit; font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.01em; white-space: nowrap;
  opacity: 0.75;
  transition: opacity var(--t-fast), color var(--t-fast),
              background var(--t-fast), border-color var(--t-fast);
}
.search-row:hover .search-preview-btn,
.search-row.active .search-preview-btn,
.search-preview-btn:focus-visible { opacity: 1; }
.search-preview-btn:hover { background: var(--panel-3); color: var(--fg); border-color: var(--fg-2); }
.search-preview-btn.playing {
  opacity: 1; color: var(--accent); border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

.search-player {
  display: flex; align-items: center; gap: 9px;
  margin: 7px 2px 1px; padding-left: 73px; cursor: default;
}
.search-player.loading .search-seek { opacity: 0.4; }
.search-player.failed .search-clock { color: var(--danger); }
.search-play {
  flex-shrink: 0; width: 24px; height: 24px;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%;
  background: var(--accent); color: #0b1118; cursor: pointer;
}
.search-seek {
  flex: 1; min-width: 0; height: 4px; accent-color: var(--accent);
  cursor: pointer;
}
.search-clock {
  flex-shrink: 0; font-family: var(--font-mono); font-size: 10px;
  color: var(--muted); font-variant-numeric: tabular-nums;
}

.export-fmt-video { display: none; }
#footer-export-wrap.has-video .export-fmt-video { display: block; flex: 1; }

/* Shown only when the video fetch actually failed, never when the source
   simply has no video stream. An absent MP4 button is normal; a broken one
   the user was never told about is not (#436). */
.export-video-failed { display: none; }
#footer-export-wrap.video-failed .export-video-failed {
  display: block;
  margin: 2px 4px 4px; padding: 5px 6px;
  font-size: 11px; line-height: 1.4; color: var(--muted);
}

/* In MP4 mode only "Export Mix" applies — the audio-only Stems/Region rows
   are hidden. main.js toggles .fmt-mp4 on the panel. */
#t-export-panel.fmt-mp4 #t-export-stems,
#t-export-panel.fmt-mp4 #t-export-region { display: none; }

/* ── About dialog ── */
.about-backdrop {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center;
  background: rgba(3,8,13,0.6); backdrop-filter: blur(6px);
}
.about-backdrop.hidden { display: none !important; }
.about-card {
  width: min(300px, calc(100vw - 32px));
  background: var(--panel-2); border: 1px solid var(--border-strong);
  border-radius: 18px; box-shadow: 0 24px 64px rgba(0,0,0,0.6);
  padding: 28px 24px 24px; text-align: center;
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 0;
}
.about-close {
  position: absolute; top: 12px; right: 12px;
  width: 26px; height: 26px;
  background: transparent; border: 1px solid var(--border);
  border-radius: 6px; color: var(--muted);
  cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.about-close:hover { background: var(--panel-3); color: var(--fg); }
.about-logo {
  width: 56px; height: 56px; border-radius: 14px;
  background: linear-gradient(135deg, rgba(139,92,246,0.2), rgba(244,183,64,0.15));
  border: 1px solid rgba(139,92,246,0.25);
  display: flex; align-items: center; justify-content: center;
  color: var(--accent); margin-bottom: 14px;
}
.about-card h2 { margin: 0 0 4px; font-size: 18px; font-family: var(--font-mono); font-weight: 700; }
.about-tagline { margin: 0 0 12px; font-size: 12px; color: var(--muted); }
.about-version-badge {
  display: inline-block; font-size: 11px; font-family: var(--font-mono);
  color: var(--muted); background: var(--panel); border: 1px solid var(--border);
  border-radius: 20px; padding: 2px 10px; margin-bottom: 20px;
}
.about-primary-links {
  display: flex; gap: 8px; width: 100%; margin-bottom: 16px;
}
.about-link {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 10px; border-radius: 8px; font-size: 12px;
  text-decoration: none; transition: background 0.15s;
}
.about-link-primary {
  background: var(--panel); border: 1px solid var(--border);
  color: var(--fg-2); font-weight: 600;
}
.about-link-primary:hover {
  background: var(--accent); border-color: var(--accent); color: #000;
}
.about-link-secondary {
  background: var(--panel); border: 1px solid var(--border);
  color: var(--fg-2);
}
.about-link-secondary:hover { background: var(--accent); border-color: var(--accent); color: #000; }
/* The in-app update pill: sits beside the plain Download link and is the
   recommended action, so it carries the accent fill by default rather than
   only on hover. */
.about-link-accent {
  background: var(--accent); border: 1px solid var(--accent);
  color: #000; font-weight: 600; cursor: pointer;
}
.about-link-accent:hover { filter: brightness(1.08); }
.about-link-accent:disabled { opacity: 0.55; cursor: default; filter: none; }
.about-divider {
  width: 100%; height: 1px; background: var(--border); margin-bottom: 16px;
}
.about-socials {
  display: flex; gap: 10px; align-items: center; justify-content: center;
}
.about-social-btn {
  width: 36px; height: 36px; border-radius: 8px;
  background: var(--panel); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  color: var(--muted); text-decoration: none; transition: all 0.15s;
}
.about-social-btn:hover { background: var(--accent); border-color: var(--accent); color: #000; }

/* ── Release notes dialog ── */
.release-card {
  width: min(520px, calc(100vw - 32px));
  max-height: calc(100vh - 64px);
  display: flex;
  flex-direction: column;
  align-items: center;
}
.release-notes {
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  text-align: left;
  margin: 0 0 16px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
  color: var(--fg-2);
  font-size: 12px;
  line-height: 1.5;
}
.release-notes h4 {
  margin: 12px 0 4px;
  font-size: 12px;
  font-weight: 700;
  color: var(--fg);
}
.release-notes h4:first-child { margin-top: 0; }
.release-notes p { margin: 0 0 8px; }
.release-notes ul { margin: 0 0 8px; padding-left: 18px; }
.release-notes li { margin: 2px 0; }
.release-notes a { color: var(--accent); text-decoration: none; overflow-wrap: anywhere; }
.release-notes a:hover { text-decoration: underline; }
.release-notes code {
  font-family: var(--font-mono);
  font-size: 11px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0 4px;
}
.release-notes pre {
  margin: 0 0 8px;
  padding: 8px 10px;
  overflow-x: auto;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.release-notes pre code { border: 0; background: none; padding: 0; }
.release-notes blockquote {
  margin: 0 0 8px;
  padding: 8px 12px;
  border-left: 3px solid var(--accent);
  border-radius: 0 6px 6px 0;
  background: rgba(139, 92, 246, 0.08);
}
.release-notes blockquote > :last-child { margin-bottom: 0; }
.release-callout {
  font-weight: 700;
  color: var(--accent);
  text-transform: uppercase;
  font-size: 10px;
  letter-spacing: 0.06em;
  margin: 0 0 6px !important;
}
/* Server/Docker mode: image-pull guidance in place of a desktop download. */
.release-docker {
  width: 100%;
  text-align: left;
  margin: 0 0 16px;
}
.release-docker-label {
  margin: 0 0 6px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--accent);
}
.release-docker-text { margin: 0 0 8px; font-size: 12px; color: var(--fg-2); }
.release-docker-cmd {
  margin: 0 0 8px;
  padding: 8px 10px;
  overflow-x: auto;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg);
}
.release-docker-note { margin: 0; font-size: 11px; color: var(--muted); }

/* Windows desktop: in-app download + apply, in place of a browser download. */
.release-inapp { width: 100%; text-align: left; margin: 0 0 16px; }
.release-inapp-progress-bar {
  height: 3px; border-radius: 2px; margin-bottom: 6px;
  background: rgba(255, 255, 255, 0.09); overflow: hidden;
}
.release-inapp-progress-fill {
  height: 100%; width: 0; border-radius: 2px;
  background: var(--accent);
  transition: width 260ms linear;
}
/* Indeterminate: the updater cannot listen to the Rust progress event from this
   origin (see catalog.js), so the bar shows activity rather than a percentage. */
.release-inapp-progress.indeterminate .release-inapp-progress-fill {
  width: 40%;
  animation: release-inapp-slide 1.1s ease-in-out infinite;
}
@keyframes release-inapp-slide {
  0%   { margin-left: -40%; }
  100% { margin-left: 100%; }
}
.release-inapp-progress-text { margin: 0; font-size: 11px; color: var(--muted); }
.release-inapp-error { margin: 0; font-size: 12px; color: #e54e4e; }

/* The release dialog lives outside `.daw`, so the scoped `.daw .hidden` rule
   does not reach its inner elements and base.css's global `.hidden` is not
   loaded on this page. Hide the mode-specific parts explicitly (same approach
   as `.about-backdrop.hidden`) so desktop hides the docker block and server
   hides the download button. */
.release-docker.hidden,
.release-inapp.hidden,
.release-inapp-progress.hidden,
.release-inapp-error.hidden,
.release-card .about-link.hidden {
  display: none !important;
}

/* The "New release available" card opens the dialog on click. */
.daw-notif-release { cursor: pointer; }

/* ── Failure dialog ── */
/* Same shell as the release dialog, in the danger colour, with the technical
   block the report will carry shown verbatim -- nothing is sent that the user
   has not been able to read first. */
.failure-card {
  width: min(560px, calc(100vw - 32px));
  max-height: calc(100vh - 64px);
  display: flex;
  flex-direction: column;
  align-items: center;
}
.failure-logo { color: var(--danger); }
.failure-when { color: var(--muted); }
.failure-message {
  margin: 12px 0 0;
  font-size: 13px; line-height: 1.5; color: var(--fg-2);
  white-space: pre-line; text-align: center;
}
.failure-hint {
  margin: 10px 0 0;
  font-size: 11px; line-height: 1.5; color: var(--muted);
  text-align: center;
}
.failure-tech {
  width: 100%; flex: 1 1 auto; min-height: 0;
  margin: 12px 0 0; padding: 10px 12px;
  overflow: auto; text-align: left;
  background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
}
.failure-tech code {
  font-family: var(--font-mono); font-size: 11px; line-height: 1.55;
  color: var(--fg-2); white-space: pre-wrap; overflow-wrap: anywhere;
}
/* Opt-in, not automatic: this pulls extra log content into what's about to be
   copied into a public report, so it gets its own deliberate click rather
   than firing every time the dialog opens (matches .library-editor-sync's
   amber "extra action" treatment). */
.failure-logs-btn {
  align-self: flex-start;
  min-height: 28px; margin-top: 8px; padding: 0 12px;
  border-radius: 7px; border: 1px solid rgba(244, 183, 64, 0.3);
  background: rgba(244, 183, 64, 0.16); color: var(--accent);
  font-family: var(--font-mono); font-size: 11px; cursor: pointer;
}
.failure-logs-btn:disabled { opacity: 0.55; cursor: default; }
/* Reporting is the reason this dialog exists, so it gets the app's primary
   button treatment (as Export Mix does) rather than the muted link style the
   About/release dialogs use for their several equal-weight links. */
.failure-card .about-link-primary {
  background: var(--accent); border-color: transparent; color: #1a1206;
}
.failure-card .about-link-primary:hover {
  background: color-mix(in srgb, var(--accent) 85%, white);
  color: #1a1206;
}

/* ── Library sections (Recent · Stem Collections · Tags) ── */
.lib-section {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-top: 14px;
}
.lib-section + .lib-section {
  border-top: 1px solid var(--border);
}
.lib-section-head {
  padding: 0 4px 6px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

/* Tag chips */
/* ── Tag autocomplete dropdown ── */
.tag-suggest {
  position: absolute;
  top: calc(100% + 4px);
  left: 0; right: 0;
  z-index: 50;
  background: var(--panel-2);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  padding: 4px;
  list-style: none;
  margin: 0;
  box-shadow: var(--shadow-panel);
}
.tag-suggest:empty { display: none; }
.tag-suggest-item {
  padding: 7px 10px;
  border-radius: 5px;
  font-size: 13px;
  color: var(--fg-2);
  cursor: pointer;
}
.tag-suggest-item:hover,
.tag-suggest-item.focused {
  background: var(--panel-3);
  color: var(--fg);
}

.lib-tags-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 2px 0 8px;
}
.lib-tag-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 11px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 20px;
  font-size: 12px;
  color: var(--fg-2);
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
  white-space: nowrap;
}
.lib-tag-chip:hover {
  background: var(--panel-2);
  color: var(--fg);
  border-color: rgba(255,255,255,0.15);
}
.lib-tag-chip.active {
  background: rgba(244,183,64,0.12);
  color: var(--accent);
  border-color: rgba(244,183,64,0.3);
}
.lib-tag-count { color: var(--muted); font-size: 11px; }

/* Supporters (partner tiles, shown in the TV-icon dialog) */
/* Slightly wider card so 3 tiles breathe; grid spans the card. */
.friends-card { width: min(360px, calc(100vw - 32px)); }
.friends-card .lib-friends-grid { width: 100%; margin-top: 4px; }
.lib-friends-grid {
  /* Masonry columns: each column stacks independently so a tall tile does not
     push others down. Tiles are round-robined into these columns in JS. */
  display: flex;
  align-items: flex-start;
  gap: 6px;
  padding: 2px 0 0;
}
.lib-friends-col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.lib-friend {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  min-width: 0;
  padding: 9px 5px 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--fg-2);
  text-decoration: none;
  text-align: center;
  /* deliberately-uneven "frames on a wall" tilt; per-tile angle set in JS */
  transform: rotate(var(--tilt, 0deg));
  transition: background var(--t-fast), color var(--t-fast),
    border-color var(--t-fast), transform var(--t-fast);
}
.lib-friend:hover {
  background: var(--panel-2);
  color: var(--fg);
  border-color: rgba(255,255,255,0.15);
  /* straighten the frame on hover */
  transform: rotate(0deg);
}
/* Logos are transparent wordmarks; span the tile width, keep aspect, cap height. */
.lib-friend-logo {
  width: 100%;
  height: auto;
  max-height: 30px;
  object-fit: contain;
}
/* Instagram profile photos render as round avatars */
.lib-friend-avatar {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--border);
}
/* Monogram fallback when a tile has no image (or it fails to load): matches the
   round avatar size, in the accent colour, so the grid stays on-brand. */
.lib-friend-monogram {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-sans);
  font-size: 20px;
  font-weight: 600;
  color: var(--accent);
  background: var(--panel-3);
  border: 1px solid var(--border);
}
/* Small Instagram glyph under the text on tiles that link to Instagram */
.lib-friend-ig {
  /* block + no-shrink avoids the WebKit baseline clip on small inline SVGs */
  display: block;
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  margin-top: 2px;
  fill: currentColor;
  opacity: 0.65;
}
.lib-friend:hover .lib-friend-ig {
  opacity: 1;
}
.lib-friend-name {
  width: 100%;
  font-size: 10.5px;
  line-height: 1.2;
  /* full name across up to 2 lines, then ellipsis */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.lib-friend-role {
  width: 100%;
  margin-top: 2px;
  font-size: 9px;
  line-height: 1.2;
  color: var(--fg-3, var(--fg-2));
  /* show the full role; the tile grows to fit it */
}

/* ── Clear bin bar (trash view only) ── */
.clear-bin-bar { display: none; padding: 6px 10px 4px; }
.sidebar.trash-view .clear-bin-bar { display: block; }
.sidebar.trash-view .lib-section-head .new-folder-btn { display: none; }
.sidebar.favorites-view .lib-section-head .new-folder-btn { display: none; }
.clear-bin-btn {
  display: flex; align-items: center; gap: 5px;
  width: 100%; padding: 6px 10px; border-radius: 6px;
  background: rgba(229, 78, 78, 0.12); border: 1px solid rgba(229, 78, 78, 0.28);
  color: #e54e4e; font-size: 12px; font-weight: 500; cursor: pointer;
  transition: background 150ms, border-color 150ms;
}
.clear-bin-btn:hover { background: rgba(229, 78, 78, 0.22); border-color: rgba(229, 78, 78, 0.5); }
.clear-bin-btn:active { background: rgba(229, 78, 78, 0.32); }

/* ── App state classes (set by JS) ── */
/* No track loaded: hide main waveform content */
.daw.is-import .daw-track-header,
.daw.is-import .daw-section-ribbon,
.daw.is-import .daw-wave-header,
.daw.is-import .daw-content { opacity: 0.3; pointer-events: none; }
.daw.is-import .daw-content .mixer-column { opacity: 1; pointer-events: auto; }

.daw.no-track .daw-track-header,
.daw.no-track .daw-section-ribbon,
.daw.no-track .daw-wave-header,
.daw.no-track .daw-content { opacity: 0.3; pointer-events: none; }
/* Overlay and job progress live inside .daw-content but must stay fully visible while processing */
.daw.no-track .daw-content .wave-loading-overlay,
.daw.no-track .daw-content .job { opacity: 1; pointer-events: auto; }

.app.no-track #t-export-btn,
.app.is-import #t-export-btn {
  opacity: 0.35;
  pointer-events: none;
  cursor: default;
}

/* When track is playing */
.daw-play-btn .pause-icon { display: none; }

/* ── Responsive: hide zoom in small windows ── */
@media (max-width: 900px) {
  .daw-info-row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .daw-track-card { grid-column: 1 / -1; width: 100%; border-right: none; border-bottom: 1px solid var(--border); }
  .stem-presence-panel { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .stem-card[data-stem="vocals"] { grid-column: span 1; }
}

/* Settings -> Logs. Read-only: paths, sizes and what writes each file. Log
   *contents* are deliberately not served -- a traceback can capture anything,
   and the files are on the machine the user is already sitting at. */
.settings-logs-dir {
  margin: 2px 2px 10px;
  padding: 8px 10px;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: 6px;
}
.settings-logs-path {
  font-size: 11.5px; color: var(--fg-2); word-break: break-all; user-select: all;
}
.settings-logs-list { display: flex; flex-direction: column; gap: 6px; }
.settings-log-row {
  padding: 8px 10px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 6px;
}
.settings-log-main {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
}
.settings-log-name { font-size: 12px; font-weight: 600; color: var(--fg); }
.settings-log-meta {
  font-size: 10.5px; color: var(--muted); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.settings-log-desc { margin-top: 3px; font-size: 11px; color: var(--muted); line-height: 1.4; }
.settings-logs-empty { font-size: 11.5px; color: var(--muted); padding: 6px 2px; }

.settings-export-logs {
  padding: 6px 12px;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  border-radius: 7px; color: var(--fg-2); cursor: pointer;
  font-family: inherit; font-size: 12px; font-weight: 600; white-space: nowrap;
  transition: background var(--t-fast), color var(--t-fast);
}
.settings-export-logs:hover:not(:disabled) { background: var(--panel-3); color: var(--fg); }
.settings-export-logs:disabled { opacity: 0.5; cursor: default; }

/* Stems location (#354). The path is long, so this row stacks instead of
   sitting on one line with the label. */
.settings-row-stack { display: block; }
.settings-btn {
  padding: 6px 12px;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  border-radius: 7px; color: var(--fg-2); cursor: pointer;
  font-family: inherit; font-size: 12px; font-weight: 600; white-space: nowrap;
  transition: background var(--t-fast), color var(--t-fast);
}
.settings-btn:hover:not(:disabled) { background: var(--panel-3); color: var(--fg); }
.settings-btn:disabled { opacity: 0.5; cursor: default; }
.stems-location {
  display: flex; align-items: center; gap: 8px; margin-top: 8px;
}
.stems-location-path {
  flex: 1; min-width: 0;
  padding: 6px 8px; border-radius: 6px;
  background: var(--panel); border: 1px solid var(--border);
  color: var(--fg-2); font-family: var(--font-mono); font-size: 11px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.stems-location-size {
  flex-shrink: 0; font-size: 11px; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.stems-location-msg {
  margin-top: 6px; font-size: 11px; line-height: 1.4; color: var(--muted);
}
.stems-location-msg.error { color: var(--danger); }
.stems-location-msg.ok { color: var(--accent); }

/* Cookies path field (#432). Full width rather than the 84px num input: this
   holds an absolute filesystem path, which is long and worth reading back. */
.settings-text-input {
  width: 100%; box-sizing: border-box; margin-top: 8px;
  background: rgba(10,17,24,0.6); border: 1px solid var(--border-strong);
  border-radius: 7px; color: var(--fg);
  font-family: var(--font-mono); font-size: 12px; padding: 6px 9px;
}
.settings-text-input:focus { outline: none; border-color: rgba(244,183,64,0.5); }
.cookies-file-msg {
  margin-top: 6px; font-size: 11px; line-height: 1.4; color: var(--danger);
}

/* Logs sub-navigation: Location / Application / Setup. */
.settings-subtabs {
  display: flex; gap: 2px; margin: 0 0 10px;
  border-bottom: 1px solid var(--border-strong);
}
.settings-subtab {
  padding: 5px 10px; background: none; border: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  color: var(--muted); cursor: pointer;
  font-family: inherit; font-size: 11.5px; font-weight: 600;
  transition: color var(--t-fast), border-color var(--t-fast);
}
.settings-subtab:hover { color: var(--fg-2); }
.settings-subtab.active { color: var(--accent); border-bottom-color: var(--accent); }
/* The pane is a flex column and the registry/log textareas rely on flex:1 to
   fill it, so the subpane has to be one too -- otherwise the textarea collapses
   to its default character width and the lines get cut off. */
.settings-subpane { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.settings-subpane.hidden { display: none; }
/* The tail views are monospace and taller than the registry dump: log lines
   are long and wrap badly. */
.settings-logtail-view {
  width: 100%; box-sizing: border-box;
  min-height: 260px; white-space: pre; overflow-wrap: normal; overflow-x: auto;
}

/* ── Per-lane transpose (the K stepper) ────────────────────────────────────
   Sits in the row just left of M, with its arrows stacked above and below the
   reading, and drawn from the same kit as M and S: same border, same radius,
   same mono face, same width. It reads as one more control in that cluster
   rather than as a different kind of thing parked next to it.

   Stacked rather than inline because the lane row only has about 300px, and at
   the inline width the fader collapsed to 10px. The vertical form costs 22px
   instead of 55px, and the row has the height spare. */
.lane-key {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  width: 22px;
  flex-shrink: 0;
}
/* The K is the button, and it is the same box as M and S: same size, same
   border, same radius, same mono face. Boxing the arrows instead put two
   look-alike buttons around a floating letter, which is the opposite of the
   family it belongs to -- M and S are each one box with one character in it. */
.lane-key-value {
  width: 22px;
  height: 20px;
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: 5px;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
/* Lit while the lane is off its own key, the way S lights when soloed. */
.lane-key.active .lane-key-value {
  background: rgba(244, 183, 64, 0.18);
  color: var(--accent);
  border-color: rgba(244, 183, 64, 0.4);
}

/* The arrows are the stepper around it, not two more buttons: no border, so
   they stay quiet next to the three boxes they sit beside. */
.lane-key-step {
  width: 22px;
  height: 11px;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: 3px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
  font-family: var(--font-mono);
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color var(--t-fast), background var(--t-fast);
}
.lane-key-step:hover:not(:disabled) {
  color: var(--fg);
  background: rgba(255, 255, 255, 0.07);
}
.lane-key-step:disabled { opacity: 0.3; cursor: default; }
/* Drums, and anything else that must never be resampled. */
.lane-key.locked,
.lane-key.unsupported { opacity: 0.35; }
.lane-key.locked .lane-key-step,
.lane-key.unsupported .lane-key-step { cursor: not-allowed; }
