:root{
  --bg:#14151a; --panel:#1e2027; --ink:#e8e6df; --sub:#9aa0a6;
  --gold:#d4af37; --gold-soft:#e7c96b; --line:#2c2f38; --cyan:#4dd7ff;
  --transport-h:200px; /* JS keeps this in sync with the real overlay height */
}
*{box-sizing:border-box}
html,body{margin:0}
body{background:var(--bg);color:var(--ink);
  font:15px/1.45 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
  -webkit-text-size-adjust:100%;
  /* reserve room so the fixed transport overlay never covers page content
     (incl. the singscope's now-line) when scrolled to the bottom */
  padding-bottom:calc(var(--transport-h) + 12px)}

/* ---------- header (compact on mobile) ---------- */
/* Calm Surface (#73/§9): the app name only. The tagline paragraph (redundant
   with the #64 coach-marks) and the "SATB prototype" tag were deleted; the live
   piece title lives in the More pane's #currentPiece. */
.app-head{padding:10px 14px 4px;display:flex;align-items:center;gap:8px}
.app-head h1{margin:0;font-size:16px;font-weight:650;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0}

/* "?" help affordance (header, right). Opens a small menu: the guided tour, or
   the written guide (tutorial.html). The tour itself lives in js/tour.js. */
.help-wrap{position:relative;flex:0 0 auto}
.help-btn{width:32px;height:32px;border-radius:50%;flex:0 0 auto;
  background:#20232c;border:1px solid var(--line);color:var(--sub);
  font-size:16px;font-weight:700;line-height:1;cursor:pointer;touch-action:manipulation}
.help-btn:hover{color:var(--gold-soft);border-color:var(--gold-soft)}
.help-menu{position:absolute;top:38px;right:0;z-index:130;min-width:196px;
  display:flex;flex-direction:column;gap:2px;padding:6px;
  background:rgba(24,26,33,.98);border:1px solid var(--line);border-radius:12px;
  box-shadow:0 10px 30px rgba(0,0,0,.55)}
.help-menu[hidden]{display:none}
.help-item{display:block;text-align:left;text-decoration:none;
  background:none;border:none;color:var(--ink);font-size:14px;
  padding:10px 12px;border-radius:8px;cursor:pointer;touch-action:manipulation}
.help-item:hover{background:#20232c;color:var(--gold-soft)}

/* status line — Calm Surface (#73/§6) relocated it into the transport handle
   row (.handle-row below). It stays the single #status text node setStatus()
   writes and setBusy() decorates with the .busy spinner. */
.status{flex:1;min-width:0;color:var(--sub);font-size:12px;line-height:1.35;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.status.busy{display:flex;align-items:center;gap:8px}
.status.busy::before{content:"";width:12px;height:12px;flex:0 0 auto;border-radius:50%;
  border:2px solid rgba(212,175,55,.3);border-top-color:var(--gold);
  animation:spin .7s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
/* retry affordance for a failed initial load — sits inline next to #status */
#retryStart{flex:0 0 auto}
#retryStart[hidden]{display:none}

/* ---------- shared control bits ---------- */
.row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.group{display:flex;align-items:center;gap:6px}
.label{font-size:10px;color:var(--sub);text-transform:uppercase;letter-spacing:.05em;white-space:nowrap}
select,input[type=number]{background:#12141a;color:var(--ink);border:1px solid var(--line);
  border-radius:8px;padding:8px 8px;font-size:15px}
/* wide enough for 3-digit measure numbers (section jumps set these) incl. the
   desktop number-input spinner arrows */
.mnum{width:60px;text-align:center}
.dash{color:var(--sub)}
input[type=range]{accent-color:var(--gold);flex:1;min-width:90px;height:28px}
.chk{display:flex;align-items:center;gap:5px;color:var(--sub);font-size:13px;white-space:nowrap}
.chk input{width:18px;height:18px}

.voice-picker{display:flex;gap:8px;flex:1}
.vbtn{flex:1;min-width:48px;height:48px;border-radius:12px;border:1px solid var(--line);
  background:#12141a;color:var(--ink);font-weight:700;font-size:18px;cursor:pointer;
  transition:all .12s;touch-action:manipulation}
.vbtn:hover{border-color:var(--gold-soft)}
.vbtn.active{background:var(--gold);color:#161616;border-color:var(--gold);
  box-shadow:0 0 0 3px rgba(212,175,55,.25)}

.btn{background:#20232c;border:1px solid var(--line);color:var(--ink);
  padding:12px 16px;border-radius:12px;cursor:pointer;font-weight:600;font-size:16px;
  min-height:48px;touch-action:manipulation}
.btn.primary{background:var(--gold);color:#161616;border-color:var(--gold)}
.btn.mic{min-width:84px}
.btn.mic.on{background:var(--cyan);color:#0c2530;border-color:var(--cyan)}
.btn:active{transform:translateY(1px)}

/* ---------- transport overlay (fixed, bottom) ---------- */
.transport{position:fixed;left:0;right:0;bottom:0;z-index:50;
  background:rgba(24,26,33,.96);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  border-top:1px solid var(--line);
  box-shadow:0 -8px 28px rgba(0,0,0,.5);
  padding:0 10px calc(8px + env(safe-area-inset-bottom))}
/* handle row (Calm Surface #73/§6): status text (flex) + expand chevron. The
   whole row is the collapse/expand target (transport.initOverlay), a bigger hit
   area than the bare chevron; status keeps its own #74 triple-tap gesture. */
.handle-row{display:flex;align-items:center;gap:8px;padding:4px 2px 2px;
  cursor:pointer;min-height:26px}
.handle{flex:0 0 auto;background:none;border:none;color:var(--sub);
  padding:2px 6px;cursor:pointer;font-size:15px;line-height:1;min-height:24px;
  touch-action:manipulation}
.handle .chev{display:inline-block;transition:transform .25s ease}
.transport.collapsed .chev{transform:rotate(180deg)}

.mini-row{display:flex;align-items:center;gap:8px;padding:2px 0 6px}
.btn.big{flex:1;font-size:17px;min-height:52px;min-width:96px}
/* mini-row § shortcut (Calm Surface #73/§2): compact icon button, gold glyph */
.btn.sec-mini{flex:0 0 auto;min-width:44px;padding-left:12px;padding-right:12px;
  color:var(--gold-soft);font-weight:800}
.btn.sec-mini[hidden]{display:none}
.pos{color:var(--sub);font-size:13px;font-variant-numeric:tabular-nums;
  min-width:40px;text-align:center;white-space:nowrap}
/* voice chip shrinks + ellipsizes before it can starve Play on a 390px row */
.chip{background:var(--gold);color:#161616;font-weight:700;border:none;border-radius:999px;
  padding:9px 12px;font-size:14px;cursor:pointer;white-space:nowrap;touch-action:manipulation;
  min-width:0;max-width:48vw;overflow:hidden;text-overflow:ellipsis}

.full{display:flex;flex-direction:column;gap:8px;padding-bottom:4px;
  overflow:hidden;max-height:78vh;opacity:1;
  transition:max-height .3s ease,opacity .22s ease,padding .3s ease}
.transport.collapsed .full{max-height:0;opacity:0;padding-bottom:0}

/* tabbed control panes (Calm Surface #73/§3) — reuse the .seg/.segbtn look;
   each pane is BOUNDED + scrollable so no row is ever clipped unreachable
   (the measured Sections-row defect). Default pane = Practice, set in markup. */
.pane-strip{display:flex;border:1px solid var(--line);border-radius:10px;
  overflow:hidden;margin-top:2px}
.pane-strip .segbtn{flex:1;min-height:44px;font-size:13.5px;font-weight:600}
.pane{display:none;flex-direction:column;gap:8px;
  max-height:min(46vh,420px);overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;padding:2px 2px 4px}
.pane.active{display:flex}

/* ---------- in-app practice recording (issue #67) ---------- */
.row-record{gap:10px}
.btn.rec{flex:0 0 auto;min-width:124px}
.btn.rec.recording{background:#3a1414;border-color:#c0392b;color:#ffd7d0}
.btn.rec.recording::before{content:"";display:inline-block;width:9px;height:9px;border-radius:50%;
  background:#ff4b3e;margin-right:8px;vertical-align:middle;animation:recpulse 1.1s ease-in-out infinite}
@keyframes recpulse{0%,100%{opacity:1}50%{opacity:.2}}
.rec-time{color:#ff8a7a;font-size:13px;font-variant-numeric:tabular-nums;min-width:44px;
  white-space:nowrap}
.rec-time[hidden]{display:none}
.chip.rec-save{background:var(--gold);color:#161616;text-decoration:none;
  display:inline-flex;align-items:center;font-size:13px;padding:8px 12px}
.chip.rec-save[hidden]{display:none}
.row-recbal{gap:10px}
.row-recbal[hidden]{display:none}
.recbal-end{flex:0 0 auto;color:var(--sub);font-size:12px;white-space:nowrap}
/* Calm Surface (#73/§9-8): recHint no longer shares the deleted .mic-note class,
   so it carries its own compact-paragraph styling. */
.rec-hint{margin:0;padding:0 2px;color:var(--gold-soft);font-size:11px}
.rec-hint[hidden]{display:none}

/* library trigger (replaces the raw combobox as the primary selector) */
.row-piece{gap:10px}
.btn.lib{flex:0 0 auto;background:#20232c;border-color:var(--line);white-space:nowrap;
  padding:11px 14px;font-size:15px}
.piece-info{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;gap:1px}
.current-piece{min-width:0;color:var(--ink);font-size:13px;font-weight:600;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:.92}
/* subtle attribution line (composer — source book) for library pieces that
   carry manifest attribution; stays hidden/empty otherwise (see setCurrentPiece) */
.piece-attrib{min-width:0;color:var(--sub);font-size:10px;letter-spacing:.01em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:.8}
.piece-attrib[hidden]{display:none}

/* visually-hidden but still actionable — keeps #pieceSelect for the headless
   tests (Playwright selectOption needs a non-empty box, not visibility:hidden) */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

.seg{display:flex;border:1px solid var(--line);border-radius:10px;overflow:hidden;flex:1}
.segbtn{flex:1;background:#12141a;border:none;color:var(--sub);padding:9px 4px;
  font-size:13px;cursor:pointer;min-height:40px;touch-action:manipulation}
.segbtn+.segbtn{border-left:1px solid var(--line)}
.segbtn.active{background:var(--gold);color:#161616;font-weight:700}

/* ---------- singscope ---------- */
.scope-wrap{position:relative;margin:6px 10px 10px;border:1px solid var(--line);
  border-radius:12px;overflow:hidden;background:#14161c}
#scope{display:block;width:100%;height:38vh;max-height:340px;min-height:200px}
body.view-split #scope{height:27vh;min-height:150px;max-height:300px}
body.view-score #scope{height:96px;min-height:96px;max-height:96px}
body.view-score .scope-hint{display:none}
.scope-readout{position:absolute;top:8px;right:10px;font-size:20px;font-weight:700;
  color:var(--cyan);text-shadow:0 1px 4px rgba(0,0,0,.7);pointer-events:none}
.scope-readout.hit{color:#ffd95e}
.scope-readout.idle{color:var(--sub);font-size:14px;font-weight:500}
.scope-hint{position:absolute;left:0;right:0;bottom:6px;text-align:center;
  color:var(--sub);font-size:11px;pointer-events:none;opacity:.85}

/* ---------- score (internal scroll only; JS adapts max-height to the
              rendered system height + view mode) ---------- */
/* .score-area is the positioning context for the busy overlay + windowed
   footer; the margins moved here so those overlays align to the score box. */
.score-area{position:relative;margin:0 10px 16px}
.score{position:relative;background:#fbfbf7;border-radius:12px;padding:6px;
  overflow:auto;max-height:42vh;-webkit-overflow-scrolling:touch;
  overscroll-behavior:contain}

/* load/render progress overlay over the score box */
.score-busy{position:absolute;inset:0;z-index:5;display:flex;align-items:center;
  justify-content:center;gap:10px;border-radius:12px;
  background:rgba(20,21,26,.55);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);
  color:var(--ink);font-size:13px;font-weight:600;pointer-events:none}
.score-busy[hidden]{display:none}
.score-busy .spinner{width:20px;height:20px;flex:0 0 auto;border-radius:50%;
  border:3px solid rgba(212,175,55,.25);border-top-color:var(--gold);
  animation:spin .7s linear infinite}

/* windowed-render footer pill (bottom of the score box) */
.score-more{position:absolute;left:50%;bottom:10px;transform:translateX(-50%);z-index:4;
  display:flex;align-items:center;gap:10px;max-width:calc(100% - 20px);
  padding:6px 8px 6px 12px;border-radius:999px;
  background:rgba(24,26,33,.94);border:1px solid var(--line);
  box-shadow:0 4px 16px rgba(0,0,0,.45);color:var(--sub);font-size:11px}
.score-more[hidden]{display:none}
.score-more.working{color:var(--gold-soft)}
.score-more-text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.btn-mini{flex:0 0 auto;background:#20232c;border:1px solid var(--line);color:var(--ink);
  border-radius:999px;padding:6px 12px;font-size:12px;font-weight:600;cursor:pointer;
  min-height:32px;touch-action:manipulation;white-space:nowrap}
.btn-mini:hover{border-color:var(--gold-soft)}
.btn:disabled,.btn-mini:disabled{opacity:.5;cursor:default}

code{background:#12141a;padding:1px 5px;border-radius:5px}

/* ---------- post-lap score report (issue #55) ---------- *
 * A small dismissible strip (not a modal) — sits inline near the top so it's
 * visible without scrolling right after a scored lap/Stop. Reuses the panel/
 * line/pill vocabulary already established by .score-more and .lib-panel.
 * Calm Surface (#73/§4): floats FIXED just above the transport — directly above
 * the Play/loop controls that react to it.
 * --transport-h already incorporates the safe-area inset (no double
 * count). Desktop (≥1000px, wave B2) re-lays this same node as a rail card. */
.score-report{position:fixed;left:8px;right:8px;bottom:calc(var(--transport-h) + 8px);
  z-index:55;padding:9px 11px;border-radius:12px;
  background:var(--panel);border:1px solid var(--line);
  box-shadow:0 8px 24px rgba(0,0,0,.5)}
.score-report[hidden]{display:none}
.score-report-head{display:flex;align-items:center;gap:8px}
.score-report-totals{flex:1;min-width:0;font-size:12px;font-weight:600;color:var(--ink);
  line-height:1.35}
.score-report-close{flex:0 0 auto;width:28px;height:28px;border-radius:8px;
  border:1px solid var(--line);background:#12141a;color:var(--sub);font-size:13px;
  cursor:pointer;touch-action:manipulation}
.score-report-close:hover{color:var(--gold-soft);border-color:rgba(212,175,55,.35)}
.score-report-close:active{transform:translateY(1px)}
.score-report-spots{display:flex;flex-direction:column;gap:5px;margin-top:8px}
.spot-row{display:flex;align-items:center;gap:10px;width:100%;background:#12141a;
  border:1px solid var(--line);border-radius:8px;padding:8px 10px;color:var(--ink);
  text-align:left;cursor:pointer;touch-action:manipulation;font-size:12px;min-height:34px}
.spot-row:hover{border-color:var(--gold-soft)}
.spot-row:active{transform:translateY(1px)}
.spot-row.spot-empty{color:var(--sub);cursor:default}
.spot-row.spot-empty:hover{border-color:var(--line);transform:none}
.spot-m{flex:0 0 auto;min-width:40px;color:var(--gold-soft);font-weight:700;
  font-variant-numeric:tabular-nums}
.spot-detail{flex:1;min-width:0;color:var(--sub);overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}

/* ---------- per-note score coloring toggle (issue #79) ---------- *
 * A "Show on score" chip in the report strip: on, it tints this lap's scored
 * noteheads by verdict on the notation. The legend (dots straight from
 * VERDICT_TINTS) appears only while the overlay is on. */
.score-report-color{display:flex;align-items:center;flex-wrap:wrap;gap:8px 12px;margin-top:8px}
.score-report-color:empty{display:none}
.score-color-toggle{flex:0 0 auto;background:#12141a;border:1px solid var(--line);
  color:var(--ink);font-size:12px;font-weight:600;border-radius:999px;padding:6px 12px;
  min-height:32px;cursor:pointer;touch-action:manipulation}
.score-color-toggle[hidden]{display:none}
.score-color-toggle:hover{border-color:var(--gold-soft)}
.score-color-toggle:active{transform:translateY(1px)}
.score-color-toggle.on{background:var(--gold);color:#161616;border-color:var(--gold)}
.score-color-key{display:flex;align-items:center;flex-wrap:wrap;gap:4px 12px;
  font-size:11px;color:var(--sub)}
.score-color-key[hidden]{display:none}
.ck-item{display:inline-flex;align-items:center;gap:5px;white-space:nowrap}
.ck-dot{width:11px;height:11px;border-radius:50%;flex:0 0 auto;
  box-shadow:0 0 0 1px rgba(255,255,255,.15)}
.ck-lbl{color:var(--sub)}

/* ---------- scoring strictness control (issue #55) ---------- */
.row-strictness .seg{flex:0 0 auto;min-width:150px}

/* ---------- instrument sound: Synth / Voices (issue #66) ---------- */
.row-instrument .seg{flex:0 0 auto;min-width:150px}

/* ---------- master accompaniment volume (issue #74 F5) ---------- *
 * Reuses the shared .row/.label/input[type=range] look (same vocabulary as
 * the Tempo slider in row-fine) — no bespoke control needed. The label wraps
 * the live %-readout <output> exactly like Tempo's bpmOut. */
.row-volume{gap:10px}
.row-volume .label{white-space:nowrap}

/* ---------- desktop ---------- */
/* ---------- tablet (760–999px) ---------- *
 * Calm Surface (#73): the tabbed transport is kept — the tablet layer is just a
 * roomier phone. (Desktop's stacked right-rail arrives in the ≥1000px block,
 * wave B2.) */
@media (min-width: 760px){
  .app-head{padding:16px 20px 6px}
  .app-head h1{font-size:20px}
  .score-report{left:20px;right:20px}
  .scope-wrap{margin:8px 20px 12px}
  #scope{height:200px;min-height:160px}
  body.view-split #scope{height:180px;min-height:140px;max-height:220px}
  body.view-score #scope{height:96px;min-height:96px}
  .score-area{margin:0 20px 24px}
  .score{padding:10px;max-height:48vh}

  .transport{padding-left:20px;padding-right:20px}
  .btn{min-height:44px;padding:9px 14px}
  .mini-row{gap:12px}
  .pos{font-size:14px}
  /* a touch more pane room on a taller tablet viewport */
  .pane{max-height:min(52vh,460px)}
  /* keep the tabbed controls from stretching edge-to-edge on a wide tablet */
  .handle-row,.mini-row,.full{max-width:820px;margin-left:auto;margin-right:auto;width:100%}
}

/* ---------- library browser overlay ---------- */
.library{position:fixed;inset:0;z-index:100;display:flex;
  background:rgba(10,11,15,.92);
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}
.library[hidden]{display:none}
.lib-panel{display:flex;flex-direction:column;width:100%;height:100%;
  max-width:920px;margin:0 auto;background:var(--bg);
  border-left:1px solid var(--line);border-right:1px solid var(--line)}

.lib-head{display:flex;gap:8px;align-items:center;
  padding:calc(10px + env(safe-area-inset-top)) 12px 8px;
  border-bottom:1px solid var(--line)}
.lib-search-wrap{position:relative;flex:1;display:flex;align-items:center;min-width:0}
.lib-search-icon{position:absolute;left:12px;font-size:14px;opacity:.6;pointer-events:none}
#libSearch{width:100%;background:#12141a;color:var(--ink);border:1px solid var(--line);
  border-radius:10px;padding:12px 12px 12px 36px;font-size:16px;min-height:48px}
#libSearch:focus{outline:none;border-color:var(--gold-soft)}
.lib-close{flex:0 0 auto;width:48px;height:48px;border-radius:10px;border:1px solid var(--line);
  background:#20232c;color:var(--ink);font-size:18px;cursor:pointer;touch-action:manipulation}
.lib-close:active{transform:translateY(1px)}

.lib-facets{display:flex;flex-direction:column;gap:6px;padding:8px 12px;
  border-bottom:1px solid var(--line)}
.facet-group{display:flex;align-items:center;gap:8px;min-width:0}
.facet-label{flex:0 0 auto;width:62px;font-size:10px;text-transform:uppercase;
  letter-spacing:.05em;color:var(--sub)}
.facet-strip{display:flex;gap:6px;overflow-x:auto;padding-bottom:2px;
  scrollbar-width:none;-webkit-overflow-scrolling:touch}
.facet-strip::-webkit-scrollbar{display:none}
.chip-f{flex:0 0 auto;background:#12141a;border:1px solid var(--line);color:var(--sub);
  border-radius:999px;padding:7px 12px;font-size:12px;cursor:pointer;white-space:nowrap;
  min-height:34px;touch-action:manipulation}
.chip-f.on{background:var(--gold);color:#161616;border-color:var(--gold);font-weight:700}

.lib-count{padding:7px 14px;color:var(--sub);font-size:12px;
  font-variant-numeric:tabular-nums;border-bottom:1px solid var(--line)}

/* windowed list: viewport is a tall spacer; only in-view rows are in the DOM,
   each absolutely positioned at its precomputed offset */
.lib-list{position:relative;flex:1;overflow-y:auto;overflow-x:hidden;
  -webkit-overflow-scrolling:touch;overscroll-behavior:contain}

/* unobtrusive footer strip — provenance/licensing, opens in a new tab */
.lib-foot{flex:0 0 auto;padding:8px 14px calc(8px + env(safe-area-inset-bottom));
  border-top:1px solid var(--line);text-align:center}
.lib-foot a{color:var(--sub);font-size:11px;text-decoration:none}
.lib-foot a:hover{color:var(--gold-soft)}
.lib-viewport{position:relative;width:100%}
/* group section header — collapsible ones (Menaion, Theotokia) are tappable
   and show a chevron + piece count */
.lib-group{position:absolute;left:0;right:0;display:flex;align-items:center;gap:10px;
  padding:0 14px;background:linear-gradient(180deg,#1b1d24,#15161c);
  border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.lib-group-name{font-size:13px;font-weight:800;letter-spacing:.02em;color:var(--gold-soft);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.lib-group-count{flex:1 1 auto;font-size:11px;color:var(--sub);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.lib-group.collapsible{cursor:pointer;touch-action:manipulation}
.lib-group.collapsible:hover .lib-group-name{color:var(--gold)}
.lib-group.collapsible:active{background:#20222b}
.lib-group-chev{flex:0 0 auto;color:var(--gold-soft);font-size:13px;
  transition:transform .18s ease;transform:rotate(90deg)}
.lib-group.collapsed .lib-group-chev{transform:rotate(0deg)}

/* sub-header inside a group (tone / month / service moment / bookName) */
.lib-sub{position:absolute;left:0;right:0;display:flex;align-items:center;
  padding:0 14px 0 20px;font-size:11px;text-transform:uppercase;letter-spacing:.05em;
  color:var(--sub);font-weight:700;background:var(--bg);
  border-bottom:1px solid rgba(44,47,56,.6)}

.lib-hint{position:absolute;left:0;right:0;padding:14px;color:var(--sub);
  font-size:13px;line-height:1.4}
.lib-hint code{font-size:12px}
.lib-row{position:absolute;left:0;right:0;display:flex;flex-direction:column;
  justify-content:center;gap:3px;padding:8px 78px 8px 14px;width:100%;
  background:none;border:0;border-bottom:1px solid var(--line);
  color:var(--ink);text-align:left;cursor:pointer;touch-action:manipulation}
.lib-pdf{position:absolute;right:10px;top:50%;transform:translateY(-50%);
  padding:8px 10px;border:1px solid var(--line);border-radius:8px;
  color:var(--sub);font-size:12px;text-decoration:none;white-space:nowrap;
  touch-action:manipulation}
.lib-pdf:hover{color:var(--gold-soft);border-color:rgba(212,175,55,.35)}
.pdf-link{flex:0 0 auto;padding:8px 10px;border:1px solid var(--line);border-radius:8px;
  color:var(--sub);font-size:12px;text-decoration:none;white-space:nowrap;
  touch-action:manipulation}
.pdf-link:hover{color:var(--gold-soft);border-color:rgba(212,175,55,.35)}
.pdf-link[hidden]{display:none}
.lib-row:hover{background:#191b22}
.lib-row:active{background:#1d1f28}
.lib-row-title{font-size:15px;font-weight:600;line-height:1.25;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lib-row-meta{display:flex;align-items:center;gap:6px;flex-wrap:nowrap;
  overflow:hidden;color:var(--sub);font-size:12px}
.lib-row-meta .composer{flex:0 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lib-row-meta .arr{flex:0 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:.85}
.lib-row-meta .book{flex:0 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:.7;font-style:italic}
/* tone label (issue #76) — quiet, plain-text like composer/book/arr rather
   than the old gold "badge" pill; same flex/ellipsis treatment as its
   neighbors so it shrinks gracefully alongside them instead of hogging
   fixed width on long rows. */
.lib-row-meta .tone{flex:0 1 auto;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;opacity:.85}
/* key signature label (issue #85) — only rendered on the rare row where
   title+composer alone still collide (see library.js computeKeyVisibility);
   ultra-muted (dimmer + smaller than tone/book/arr) since it's the least
   important thing on a row when it does show — a tiebreaker, not a headline. */
.lib-row-meta .key{flex:0 1 auto;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;opacity:.55;font-size:11px}

body.lib-lock{overflow:hidden}

@media (min-width:760px){
  .lib-close{width:44px;height:44px}
  .lib-row-title{font-size:16px}
  .lib-row-meta{font-size:13px}
}

/* ---------- verse toggle (multi-verse lyrics) ---------- */
.row-verse[hidden]{display:none}

/* ---------- interactive guided tour (js/tour.js) ---------- *
 * The layer itself is inert (pointer-events:none) so the highlighted control
 * stays usable and automated clicks are never blocked; only #tourCard is
 * interactive. #tourSpot is a transparent box positioned over the target whose
 * huge box-shadow dims everything else (the classic coach-mark "hole"); on
 * welcome/finish steps (.no-target) it becomes a plain full-screen dim. Both
 * the spot and the card carry a transition so re-placement after the transport
 * expands (0.3s) glides rather than snaps. */
.tour{position:fixed;inset:0;z-index:500;pointer-events:none}
.tour[hidden]{display:none}
.tour-spot{position:fixed;border-radius:12px;pointer-events:none;
  box-shadow:0 0 0 100vmax rgba(8,9,12,.66), 0 0 0 2px var(--gold-soft) inset,
    0 0 22px 3px rgba(212,175,55,.45);
  transition:left .2s ease,top .2s ease,width .2s ease,height .2s ease}
.tour-spot.no-target{border-radius:0;
  box-shadow:0 0 0 100vmax rgba(8,9,12,.66)}
.tour-card{position:fixed;pointer-events:auto;
  width:min(340px,calc(100vw - 24px));
  background:rgba(24,26,33,.98);border:1px solid rgba(212,175,55,.4);
  border-radius:14px;padding:14px 16px 12px;
  box-shadow:0 14px 40px rgba(0,0,0,.6);
  transition:left .2s ease,top .2s ease;
  animation:tourIn .2s ease}
.tour-card-head{display:flex;flex-direction:column;gap:2px;margin-bottom:6px}
.tour-step{font-size:10px;font-weight:800;letter-spacing:.09em;
  text-transform:uppercase;color:var(--gold-soft)}
.tour-title{margin:0;font-size:16px;font-weight:650;color:var(--ink)}
.tour-body{margin:0 0 12px;font-size:13.5px;line-height:1.5;color:var(--ink)}
.tour-guide-link{display:inline-block;margin-top:8px;color:var(--gold-soft);
  font-size:13px;text-decoration:none}
.tour-guide-link:hover{text-decoration:underline}
.tour-actions{display:flex;align-items:center;gap:8px}
.tour-actions-spacer{flex:1}
.tour-btn{background:#20232c;border:1px solid var(--line);color:var(--ink);
  padding:9px 14px;border-radius:10px;font-size:14px;font-weight:600;
  cursor:pointer;touch-action:manipulation;min-height:40px}
.tour-btn:hover{border-color:var(--gold-soft)}
.tour-btn:active{transform:translateY(1px)}
.tour-btn.tour-next{background:var(--gold);color:#161616;border-color:var(--gold)}
.tour-btn.tour-skip{color:var(--sub);padding-left:6px;padding-right:6px;
  background:none;border:none}
.tour-btn.tour-skip:hover{color:var(--gold-soft)}
@keyframes tourIn{from{transform:translateY(6px);opacity:0}to{transform:translateY(0);opacity:1}}

/* ---------- timing calibration wizard (js/calibrate.js) ---------- *
 * A centered dialog (not a bottom sheet) mirroring the .library scrim + lock
 * pattern. z-index sits above the tour (500), below audio-debug (9999). */
.calib{position:fixed;inset:0;z-index:520;display:flex;align-items:center;justify-content:center;
  padding:20px;background:rgba(10,11,15,.72);
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}
.calib[hidden]{display:none}
body.calib-lock{overflow:hidden}
.calib-panel{width:100%;max-width:420px;background:var(--panel);border:1px solid var(--line);
  border-radius:16px;box-shadow:0 18px 50px rgba(0,0,0,.6);
  padding:16px 18px 14px;max-height:calc(100vh - 40px);overflow-y:auto}
.calib-head{display:flex;align-items:flex-start;gap:10px;margin-bottom:8px}
.calib-title{flex:1;min-width:0;margin:0;font-size:18px;font-weight:650}
.calib-body{font-size:14.5px;line-height:1.5;color:var(--ink)}
.calib-body p{margin:0 0 10px}
.calib-sub{color:var(--sub);font-size:13px}
.calib-run{font-size:16px;font-weight:600}
.calib-progress{height:8px;border-radius:6px;background:#12141a;border:1px solid var(--line);
  overflow:hidden;margin:6px 0 10px}
.calib-bar{height:100%;width:0;background:var(--gold);transition:width .1s linear}
.calib-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:12px;flex-wrap:wrap}
.calib-actions .btn{min-height:44px}

/* ---------- jump-to-section (transport control + bottom sheet) ---------- */
.row-sections[hidden]{display:none}
.sec-btn{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:8px;
  background:#20232c;border:1px solid var(--line);color:var(--ink);
  padding:11px 12px;border-radius:12px;font-size:15px;min-height:48px;cursor:pointer;
  touch-action:manipulation}
.sec-btn:hover{border-color:var(--gold-soft)}
.sec-btn:active{transform:translateY(1px)}
.sec-icon{flex:0 0 auto;color:var(--gold-soft);font-weight:800;font-size:16px}
.sec-label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;text-align:left;font-weight:600}
.sec-caret{flex:0 0 auto;color:var(--sub);font-size:11px}
.btn-sec-nav{flex:0 0 auto;width:44px;min-height:48px;background:#12141a;
  border:1px solid var(--line);color:var(--ink);border-radius:12px;font-size:20px;
  line-height:1;cursor:pointer;touch-action:manipulation}
.btn-sec-nav:hover{border-color:var(--gold-soft)}
.btn-sec-nav:active{transform:translateY(1px)}
.btn-sec-nav:disabled{opacity:.4;cursor:default;border-color:var(--line);transform:none}

/* bottom sheet: slides up from the bottom edge, dims the rest */
.sec-sheet{position:fixed;inset:0;z-index:120;display:flex;align-items:flex-end;
  background:rgba(10,11,15,.6);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
.sec-sheet[hidden]{display:none}
.sec-sheet-panel{width:100%;max-width:720px;margin:0 auto;
  background:var(--panel);border:1px solid var(--line);border-bottom:none;
  border-radius:16px 16px 0 0;box-shadow:0 -12px 40px rgba(0,0,0,.6);
  display:flex;flex-direction:column;max-height:70vh;
  padding-bottom:env(safe-area-inset-bottom);animation:secSheetUp .22s ease}
@keyframes secSheetUp{from{transform:translateY(28px);opacity:.3}to{transform:none;opacity:1}}
.sec-sheet-head{display:flex;align-items:center;gap:8px;padding:14px 14px 10px;
  border-bottom:1px solid var(--line)}
.sec-sheet-title{flex:1;font-size:15px;font-weight:700;color:var(--gold-soft)}
.sec-sheet-list{flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch;
  overscroll-behavior:contain;padding:4px 0}
.sec-item{display:flex;align-items:center;gap:12px;width:100%;
  background:none;border:0;border-bottom:1px solid rgba(44,47,56,.6);
  color:var(--ink);text-align:left;padding:13px 16px;cursor:pointer;
  touch-action:manipulation;font-size:15px}
.sec-item:hover{background:#191b22}
.sec-item:active{background:#1d1f28}
.sec-item-m{flex:0 0 auto;min-width:56px;color:var(--sub);font-size:12px;
  font-variant-numeric:tabular-nums;letter-spacing:.02em}
.sec-item-t{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;font-weight:600}
.sec-item.active{background:rgba(212,175,55,.12)}
.sec-item.active .sec-item-t,.sec-item.active .sec-item-m{color:var(--gold-soft)}

body.sec-lock{overflow:hidden}

@media (min-width:760px){
  .row-sections{flex:1 1 auto;min-width:260px}
  .btn-sec-nav{min-height:44px}
  .sec-btn{min-height:44px}
  .sec-item-t{white-space:normal}
}

/* ---------- iOS audio diagnostics overlay (issue #74) ---------- *
 * Read-only field tool, hidden and inert unless ?audiodebug=1 or a triple-tap
 * on the status line reveals it. Fixed top-left, monospace, scrollable; never
 * part of the normal UI. See docs/IOS-AUDIO-TEST.md. */
.audio-debug{position:fixed;top:0;left:0;z-index:9999;
  width:min(440px,94vw);max-height:60vh;display:flex;flex-direction:column;
  background:rgba(10,11,15,.94);color:#d6f5c8;border:1px solid #3a3d47;
  border-radius:0 0 10px 0;box-shadow:0 6px 24px rgba(0,0,0,.5);
  font:11px/1.4 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
.audio-debug[hidden]{display:none}
.ad-head{display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:6px 8px;border-bottom:1px solid #2c2f38;flex:0 0 auto}
.ad-title{color:#ffd95e;font-weight:600;font-size:11px}
.ad-sub{color:var(--sub);font-weight:400}
.ad-actions{display:flex;gap:6px}
.ad-btn{background:#20232c;color:#e8e6df;border:1px solid #3a3d47;border-radius:6px;
  padding:5px 9px;font:inherit;cursor:pointer;touch-action:manipulation;min-height:30px}
.ad-btn:active{background:#2b2f3a}
.ad-stats{margin:0;padding:8px;white-space:pre-wrap;word-break:break-word;
  color:#bfe0ff;border-bottom:1px solid #2c2f38;flex:0 0 auto}
.ad-log{margin:0;padding:8px;white-space:pre-wrap;word-break:break-word;
  overflow:auto;flex:1 1 auto;color:#c8ccd4;opacity:.95}

/* ======================================================================= *
 * Calm Surface (#73/§5, issue #72) — DESKTOP TWO-COLUMN SHELL, >=1000px.
 * Wave B2's seam: APPEND-ONLY from here down. Nothing above this fence was
 * modified — every rule below only wins because it is later in the cascade
 * (equal-or-matching specificity to what it overrides), never via
 * !important. Same DOM as mobile (§7.1) — no index.html body changes.
 *
 * Two-column technique: FLOATS, not CSS Grid. Grid's row auto-placement
 * couples row heights ACROSS columns (the header's row would stretch to
 * match the rail's ~600px content unless every element got its own
 * exclusive row, which then stacks columns vertically instead of side by
 * side). Floats stack same-side siblings purely by their own content
 * height, independent of the other side — exactly what a header+scope+
 * score column and a separately-tall rail column need, with zero wrapper
 * elements (which would require restructuring the body — out of B2's seam).
 * ======================================================================= */
@media (min-width:1000px){
  body{padding-bottom:0}                 /* fixed-overlay reservation is mobile/tablet-only */
  body::after{content:"";display:table;clear:both}   /* contain the floats below */

  /* ---- left column: header + singscope + score (document order unchanged) */
  .app-head{float:left;clear:left;width:calc(100% - 380px)}
  /* scope-wrap/score-area carry their own 20px L/R margin (>=760px block
     above) — subtract the rail's 380px AND that 40px so the two floated
     columns sum to exactly 100% instead of overflowing/wrapping. */
  .scope-wrap{float:left;clear:left;width:calc(100% - 420px)}
  .score-area{float:left;clear:left;width:calc(100% - 420px)}

  /* ---- right column: report card, then the rail (#transport) ----
   * DOM order is #scoreReport THEN #transport (see index.html — the report
   * strip sits just above the transport section) — floats preserve that
   * document order, so the (usually-hidden, only-after-a-scored-lap) report
   * card lands at the TOP of the rail with the transport rail beneath it.
   * Both are exactly 380px, so neither can float beside the other;
   * clear:right on #transport makes that explicit rather than relying on
   * the width fit alone. */
  #scoreReport{
    position:static;float:right;clear:right;width:380px;
    left:auto;right:auto;bottom:auto;z-index:auto;margin:0 0 10px;
  }
  #transport{
    position:static;float:right;clear:right;width:380px;
    left:auto;right:auto;bottom:auto;z-index:auto;
    max-height:100vh;overflow-y:auto;
    border-top:none;border-left:1px solid var(--line);
    box-shadow:none;
    padding:14px 14px calc(14px + env(safe-area-inset-bottom));
  }

  /* Collapse mechanics neutralized VISUALLY ONLY (§5): the rail never
   * covers the score, so auto-collapse is unnecessary. setOverlay() keeps
   * firing (Play still toggles .collapsed on #transport, Pause/Stop still
   * clear it) — JS behavior is untouched — but both states below compute to
   * the identical box, so the toggle has zero visible effect. */
  .full,.transport.collapsed .full{max-height:none;opacity:1;padding-bottom:8px;overflow:visible}

  /* Tab strip hidden; all three panes stack open (§5 — "stacking means the
   * tab JS is mobile-only sugar, not a load-bearing dependency"): the strip
   * click handler in transport.js keeps running, just unreachable. Small-caps
   * group labels reuse the existing data-pane attribute B1 already put on
   * each pane div, styled like the mockup's gold-soft .glabel. */
  #paneStrip{display:none}
  .pane{display:flex}
  .pane::before{
    content:attr(data-pane);display:block;
    font-size:10px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;
    color:var(--gold-soft);
  }

  /* Handle row (§6): the chevron is meaningless once collapse has no visual
   * effect; the status line stays — "on desktop the handle row is the
   * rail's status row." */
  #expandHandle{display:none}

  /* Mini-row (Play/Stop/pos/§/chip) pinned at the rail's scrolled top (per
   * the build brief: "mini-row pinned at the rail top") so it stays
   * reachable even when Practice+Sound+More push the rail past the
   * viewport and #transport scrolls internally. */
  .mini-row{position:sticky;top:0;z-index:2;background:rgba(24,26,33,.96);
    padding-top:4px;padding-bottom:8px}

}
/* ===================== end Calm Surface desktop fence ==================== */
