/* ═══ Song Structure — visual system ═══════════════════════════════
   Light: warm paper, ink-black chords, strong barlines.
   Dark:  true-dark panels, same structure, contrast held ≥ 4.5:1.
   Icons are SVG (never emoji), every icon-only control has a tooltip
   and an aria-label, and all motion respects prefers-reduced-motion.
   ================================================================= */
:root{
  /* surfaces */
  --bg:#eeece6; --panel:#fffdf9; --sunk:#f5f3ee;
  /* ink */
  --ink:#14141a; --ink-2:#3d3d47; --muted:#63636f;
  /* lines — the barlines are structural, so they are dark enough to read */
  --line:#dedbd2; --line-strong:#c3bfb3; --bar:#7d7a70;
  --accent:#1f5fb0; --accent-soft:#e6eefb; --accent-ink:#fff;
  --danger:#b3261e;
  --shadow:0 1px 2px rgba(20,20,26,.05),0 4px 14px rgba(20,20,26,.06);
  --shadow-lift:0 2px 6px rgba(20,20,26,.09),0 12px 28px rgba(20,20,26,.10);
  --r:10px; --r-sm:6px;
  --font:'Inter',-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,monospace;
  --t:170ms cubic-bezier(.2,.6,.3,1);
}
/* Dark. Two blocks with the same values: the media query is what the system
   asks for, the attribute is what he picked in the app and it wins. Keep them
   identical — if you edit one, edit the other. */
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --bg:#0e0e11; --panel:#191920; --sunk:#141419;
    --ink:#f2f1f5; --ink-2:#cfced8; --muted:#9d9caa;
    --line:#2a2a33; --line-strong:#3c3c48; --bar:#6a6a7a;
    --accent:#6ea8f0; --accent-soft:#17253a; --accent-ink:#0b0b0f;
    --danger:#ef6f68;
    --shadow:0 1px 2px rgba(0,0,0,.4),0 4px 14px rgba(0,0,0,.3);
    --shadow-lift:0 2px 6px rgba(0,0,0,.5),0 14px 32px rgba(0,0,0,.45);
  }
}
:root[data-theme="dark"]{
    --bg:#0e0e11; --panel:#191920; --sunk:#141419;
    --ink:#f2f1f5; --ink-2:#cfced8; --muted:#9d9caa;
    --line:#2a2a33; --line-strong:#3c3c48; --bar:#6a6a7a;
    --accent:#6ea8f0; --accent-soft:#17253a; --accent-ink:#0b0b0f;
    --danger:#ef6f68;
    --shadow:0 1px 2px rgba(0,0,0,.4),0 4px 14px rgba(0,0,0,.3);
    --shadow-lift:0 2px 6px rgba(0,0,0,.5),0 14px 32px rgba(0,0,0,.45);
}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{background:var(--bg);color:var(--ink);font-family:var(--font);font-size:14px;line-height:1.5;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
button,input,select{font:inherit;color:inherit}
button{cursor:pointer;touch-action:manipulation}
[hidden]{display:none!important}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}
::selection{background:var(--accent);color:var(--accent-ink)}

/* screen-reader-only, and the skip link that reveals itself on focus */
.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}
.skip-link{position:absolute;left:-9999px;top:0;z-index:300;background:var(--accent);color:var(--accent-ink);
  padding:10px 16px;border-radius:0 0 8px 0;font-weight:600;text-decoration:none}
.skip-link:focus{left:0}
.req{color:var(--danger);font-weight:700}

/* ── top bar ────────────────────────────────────────────── */
.topbar{position:sticky;top:0;z-index:40;display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:9px 20px;background:color-mix(in srgb,var(--panel) 88%,transparent);
  backdrop-filter:saturate(1.6) blur(10px);border-bottom:1px solid var(--line)}
.brand{display:flex;align-items:center;gap:9px;font-weight:650;letter-spacing:-.015em;font-size:14.5px}
.logo{display:grid;place-items:center;color:var(--accent)}
.topbar-actions{display:flex;gap:2px;flex-wrap:wrap}

.btn{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--line-strong);background:var(--panel);
  border-radius:8px;padding:7px 12px;font-size:13px;font-weight:500;color:var(--ink-2);
  transition:background var(--t),border-color var(--t),color var(--t),box-shadow var(--t),transform 80ms}
.btn:hover{background:var(--sunk);border-color:var(--muted);color:var(--ink)}
.btn:active{transform:translateY(1px)}
.btn.primary{background:var(--accent);border-color:var(--accent);color:var(--accent-ink);font-weight:600;
  box-shadow:0 1px 2px rgba(31,95,176,.3)}
.btn.primary:hover{filter:brightness(1.1);border-color:var(--accent);color:var(--accent-ink)}
.btn.ghost{border-color:transparent;background:transparent}
.btn.ghost:hover{background:var(--sunk);border-color:var(--line)}
.btn.big{padding:10px 18px;font-size:14px}
.btn.saved{color:#2b7a4b;border-color:#2b7a4b}
.btn.saved:hover{color:#2b7a4b;border-color:#2b7a4b;background:color-mix(in srgb,#2b7a4b 10%,transparent)}
#btn-save[disabled]{opacity:.7}

/* small icon-only control */
.ibtn{display:grid;place-items:center;border:1px solid transparent;background:transparent;color:var(--muted);
  border-radius:6px;width:24px;height:22px;padding:0;transition:background var(--t),color var(--t),border-color var(--t)}
.ibtn:hover{background:var(--panel);color:var(--ink);border-color:var(--line-strong)}
.ibtn.danger:hover{color:var(--danger);border-color:var(--danger)}

/* ── sheet ──────────────────────────────────────────────── */
.sheet{max-width:1080px;margin:0 auto;padding:26px 20px 160px}
.song-head{margin-bottom:18px}
.title-in{width:100%;border:none;background:transparent;font-size:30px;font-weight:700;letter-spacing:-.025em;
  padding:2px 0;outline:none;border-bottom:1px solid transparent}
.title-in:hover{border-bottom-color:var(--line)}
.title-in:focus{border-bottom-color:var(--accent)}
.title-in:empty::before{color:var(--line-strong)}
.artist-in:empty::before{color:var(--line-strong)}
.artist-in{width:100%;border:none;background:transparent;color:var(--muted);font-size:13.5px;padding:3px 0;outline:none;
  border-bottom:1px solid transparent}
.artist-in:hover{border-bottom-color:var(--line)}
.artist-in:focus{border-bottom-color:var(--accent);color:var(--ink-2)}
.meta-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:14px}
.meta{display:flex;align-items:center;gap:7px;font-size:11px;font-weight:600;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);background:var(--panel);border:1px solid var(--line);
  border-radius:8px;padding:4px 8px 4px 10px;transition:border-color var(--t)}
.meta:hover{border-color:var(--line-strong)}
/* Every pill in this row is the same height. The others are sized by the
   field inside them; the pulse holds only a word and some dots, so without
   this it sits visibly shorter than the ones either side of it. */
.meta{min-height:34px}
.meta input,.meta select,.meta .key-in{width:58px;border:none;background:transparent;padding:2px 0;font-size:13.5px;
  font-weight:600;letter-spacing:0;text-transform:none;color:var(--ink);outline:none}
.meta select{width:auto;cursor:pointer}
.stat{font-size:12px;font-weight:500;color:var(--muted);background:transparent;border:1px dashed var(--line-strong);
  border-radius:99px;padding:4px 12px}

/* Visual metronome. Silent on purpose — it is a count-in cue, not a click
   track, so it has to be readable out of the corner of an eye while both
   hands are busy. The first dot is the downbeat and is drawn in the accent
   so "one" is findable without counting the row. */
.pulse{gap:9px;padding-right:9px}
/* Tap tempo. Reads like the pills beside it because it is the same kind of
   thing — a fact about the song — except you play it in rather than type it. */
.tap-btn{cursor:pointer;font-family:inherit;-webkit-appearance:none;-webkit-tap-highlight-color:transparent;
  gap:8px;padding-right:10px}
.tap-btn b{font-size:13.5px;font-weight:600;letter-spacing:0;text-transform:none;color:var(--ink);
  font-variant-numeric:tabular-nums;min-width:44px;text-align:left}
.tap-btn.counting{border-color:var(--accent);background:var(--accent-soft)}
.tap-btn.counting b{color:var(--accent)}
.tap-btn:active{transform:scale(.97)}
.pulse-dots{display:flex;align-items:center;gap:5px}
.pdot{width:7px;height:7px;border-radius:99px;background:var(--bar);opacity:.16;flex:none;
  transform:scale(.68);will-change:opacity,transform}
.pdot.one{width:9px;height:9px;background:var(--accent)}
.gig-pulse{flex:none;gap:7px;padding:0 6px}
.gig-pulse .pdot{width:10px;height:10px}
.gig-pulse .pdot.one{width:12px;height:12px}
/* Measured: at 375px the gig bar is already exactly full — the buttons leave
   nothing over, and the song title is the thing that gives. So on a phone the
   pulse wraps to its own line under the bar instead of taking width the title
   does not have. Centred, because on its own line there is nothing to align
   it to. (The setlist position no longer costs anything here: it lives inside
   the title now.) */
@media(max-width:720px){
  .gig-bar{flex-wrap:wrap;justify-content:center}
  .gig-pulse{order:9;gap:9px;padding:3px 6px 0}
  /* the speed control is a setting, not a control you reach for mid-song, so
     on a phone it goes down to the second line and gives the song title back
     the 44px it was taking out of it */
  #gig-speed-btn{order:9;margin-top:3px}
}

.roadmap-wrap{display:flex;gap:12px;align-items:flex-start;background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r);padding:11px 14px;margin-bottom:28px;box-shadow:var(--shadow)}
.roadmap-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);
  padding-top:5px;flex:none}
.roadmap{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.rm-chip{display:inline-flex;align-items:center;gap:4px;font-size:12px;font-weight:600;padding:4px 11px;
  border-radius:99px;border:1px solid;white-space:nowrap;transition:transform var(--t),box-shadow var(--t)}
.rm-chip:hover{transform:translateY(-1px);box-shadow:var(--shadow)}
.rm-x{font-weight:700;opacity:.8;font-family:var(--mono);font-size:11px}
.rm-empty{font-size:12.5px;color:var(--muted)}

/* ── region + measures ──────────────────────────────────── */
.sect{margin-bottom:30px}
.system{display:grid;grid-template-columns:repeat(4,1fr)}
.system + .system{margin-top:10px}

.markers{grid-column:1/-1;display:grid;grid-template-columns:repeat(4,1fr);align-items:end;margin-bottom:5px}
.mk-slot{display:flex;gap:5px;align-items:flex-end;padding-left:3px;min-width:0}
.marker{display:inline-flex;align-items:center;gap:5px;font-size:11px;font-weight:550;line-height:1;
  background:var(--panel);color:var(--ink);border:1px solid var(--line-strong);border-bottom:2px solid var(--sec);
  border-radius:6px 6px 2px 2px;padding:4px 8px;white-space:nowrap;max-width:100%;box-shadow:var(--shadow);
  transition:transform var(--t),box-shadow var(--t)}
.marker span{overflow:hidden;text-overflow:ellipsis}
.marker:hover{transform:translateY(-1px);box-shadow:var(--shadow-lift);border-color:var(--sec)}

.rowbox{border:1px solid var(--bar);border-radius:8px;overflow:hidden;background:var(--panel);box-shadow:var(--shadow)}

.region{position:relative;display:flex;align-items:center;height:27px;padding:0 4px;background:var(--sec);
  border-bottom:1px solid var(--bar)}
.r-caret{display:grid;place-items:center;position:absolute;left:4px;top:0;height:100%;width:20px;border:none;
  background:transparent;color:#fff;opacity:.85;padding:0;border-radius:4px}
.r-caret:hover{opacity:1;background:rgba(255,255,255,.18)}
.r-cont{opacity:.55;cursor:default;font-size:12px}
/* the caret and the tools are absolute, so the middle has to reserve their
   space itself — without this a long region name runs under both */
.r-mid{flex:1;display:flex;align-items:center;justify-content:center;gap:8px;min-width:0;padding:0 46px}
.r-name{border:none;background:transparent;outline:none;text-align:center;font-size:12.5px;font-weight:650;
  letter-spacing:.03em;color:#fff;padding:1px 4px;min-width:44px;max-width:100%;border-radius:4px;
  text-overflow:ellipsis}
.r-name:empty::before{color:rgba(255,255,255,.6)}
.r-name:hover:not([readonly]){background:rgba(255,255,255,.14)}
.r-name:focus{background:rgba(255,255,255,.22)}
.r-rep{border:1px solid rgba(255,255,255,.45);background:rgba(255,255,255,.16);color:#fff;border-radius:99px;
  font-size:10.5px;font-weight:700;font-family:var(--mono);padding:1px 7px;flex:none;transition:background var(--t)}
.r-rep:hover{background:rgba(255,255,255,.3)}
.r-note{font-size:11px;font-style:italic;color:rgba(255,255,255,.85);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.r-part{font-size:10px;color:rgba(255,255,255,.7);flex:none;letter-spacing:.04em}
.r-right{position:absolute;right:4px;top:0;height:100%;display:flex;align-items:center;gap:3px}
.r-tools{display:none;gap:1px;align-items:center;padding-left:12px}
.region:hover .r-tools,.region:focus-within .r-tools{display:flex}
.region .ibtn{color:rgba(255,255,255,.9);width:22px;height:20px}
.region .ibtn:hover{background:rgba(255,255,255,.2);color:#fff;border-color:transparent}
.region .ibtn.danger:hover{background:var(--danger);color:#fff}
.sect.collapsed .region{border-bottom:none}

.measures{display:grid;background:var(--panel)}
.measure{position:relative;height:86px;border-left:1px solid var(--bar);transition:background var(--t)}
.measure:first-child{border-left:none}
.measure:hover{background:var(--sunk)}
.measure:focus-within{background:var(--accent-soft)}
/* "add a bar" sits outside the box, so real bars keep their true width */
.add-cell{display:flex;align-items:flex-end;padding:0 0 0 8px}
.add-bar{display:grid;place-items:center;width:30px;height:30px;margin-bottom:28px;border-radius:50%;
  border:1px dashed var(--line-strong);background:transparent;color:var(--muted);padding:0;
  transition:color var(--t),border-color var(--t),background var(--t),transform var(--t)}
.add-bar:hover{color:var(--accent);border-color:var(--accent);border-style:solid;
  background:color-mix(in srgb,var(--accent) 8%,transparent);transform:scale(1.08)}
/* a full last row leaves no spare column, so the button gets a row to itself */
.add-cell.solo{align-items:flex-start;padding:0 0 0 8px}
.add-cell.solo .add-bar{margin-bottom:0}


/* remove / restore a barline */
.barline-btn,.barline-add{position:absolute;top:50%;display:grid;place-items:center;width:19px;height:19px;
  border-radius:50%;border:1px solid var(--line-strong);background:var(--panel);color:var(--muted);padding:0;
  z-index:4;opacity:0;transform:translate(-50%,-50%) scale(.8);
  transition:opacity var(--t),transform var(--t),color var(--t),border-color var(--t)}
.barline-btn{left:0}
.measure:hover .barline-btn,.measure:hover .barline-add,
.barline-btn:focus-visible,.barline-add:focus-visible{opacity:1;transform:translate(-50%,-50%) scale(1)}
.barline-btn:hover,.barline-add:hover{color:var(--accent);border-color:var(--accent);
  transform:translate(-50%,-50%) scale(1.15)}
.barline-add{transform:translate(0,-50%) scale(.8);border-style:dashed}
.measure:hover .barline-add{transform:translate(0,-50%) scale(1)}
.barline-add:hover{transform:translate(0,-50%) scale(1.15)}
.measure[style*="span 2"] .m-chords,.measure[style*="span 3"] .m-chords,.measure[style*="span 4"] .m-chords{
  border-left:none}

.m-num{position:absolute;top:3px;left:6px;font-family:var(--mono);font-size:10px;font-weight:500;color:var(--muted);
  user-select:none;padding:1px 3px;border-radius:4px;z-index:2}

/* move handle */
.m-grip{position:absolute;top:2px;right:3px;z-index:4;display:none;place-items:center;
  border:1px solid var(--line-strong);background:var(--panel);color:var(--muted);
  border-radius:6px;width:26px;height:24px;padding:0;cursor:grab;touch-action:none;
  transition:background var(--t),color var(--t),border-color var(--t)}
.measure:hover .m-grip,.measure:focus-within .m-grip{display:grid}
.m-grip:hover{background:var(--accent-soft);color:var(--accent);border-color:var(--accent)}
.m-grip:active{cursor:grabbing}
.measure.dragging{opacity:.35}
body.is-dragging{cursor:grabbing;user-select:none}
body.is-dragging .measure{cursor:grabbing}

.drag-ghost{position:fixed;z-index:210;pointer-events:none;transform:translate(-50%,-140%);
  background:var(--accent);color:var(--accent-ink);font-size:16px;font-weight:700;
  padding:6px 14px;border-radius:8px;box-shadow:var(--shadow-lift);opacity:0;transition:opacity 90ms}
.drag-ghost.on{opacity:.95}

/* where it will land */
.measure.drop-before::before,.measure.drop-after::before{content:'';position:absolute;top:0;bottom:0;width:3px;
  background:var(--accent);z-index:5;border-radius:2px}
.measure.drop-before::before{left:-2px}
.measure.drop-after::before{right:-2px}
.m-tools{position:absolute;top:2px;right:32px;display:none;gap:1px;z-index:3;background:var(--panel);
  border-radius:6px;box-shadow:var(--shadow)}
.measure:hover .m-tools,.measure:focus-within .m-tools{display:flex}

.m-chords{display:grid;place-items:center;height:100%;padding:16px 5px}
.m-chords.split{grid-template-columns:repeat(var(--beats,4),1fr)}
.beat{width:100%;border:none;background:transparent;outline:none;text-align:center;font-family:var(--font);
  font-size:19px;font-weight:600;letter-spacing:-.01em;padding:3px 0;min-width:0;
  border-bottom:1.5px solid transparent;transition:border-color var(--t)}
.beat.solo{font-size:31px;font-weight:600;letter-spacing:-.03em}
.measure:hover .beat:empty{border-bottom-color:var(--line-strong)}
.beat:focus{border-bottom-color:var(--accent)}
.m-chords.split .beat{font-size:19px}

/* These are editable divs, not inputs — see textBox() in app.js. They need
   the three things an <input> gave them for free: a caret cursor, a line's
   worth of height when empty, and one line that never wraps. */
.title-in,.artist-in,.key-in,.r-name,.beat,.m-lyric{cursor:text;white-space:pre;overflow:hidden;
  min-height:1.2em;-webkit-user-modify:read-write-plaintext-only}
.title-in:empty::before,.artist-in:empty::before,.key-in:empty::before,
.r-name:empty::before,.beat:empty::before,.m-lyric:empty::before{content:attr(data-ph)}
.beat:empty::before,.m-lyric:empty::before{content:'\200b'}      /* holds the line open, shows nothing */
.r-name{display:inline-block}
.key-in{min-width:2.2em}

/* The cue under a bar is the thing you read on stage, so it is always on —
   never hidden behind a hover. Empty ones show nothing but a rule when the
   pointer is over the bar, so a blank chart stays blank. */
.m-lyric{position:absolute;left:5px;right:5px;bottom:3px;border:none;background:transparent;outline:none;
  font-size:11.5px;font-weight:500;color:var(--ink-2);padding:1px 2px;text-align:center;border-radius:4px;
  text-overflow:ellipsis;border-bottom:1px solid transparent}
.measure:hover .m-lyric:empty{border-bottom-color:var(--line)}
.m-lyric:focus{background:var(--panel);color:var(--ink);box-shadow:0 0 0 1px var(--accent);border-bottom-color:transparent}

.m-icons{position:absolute;right:4px;bottom:4px;display:flex;gap:3px;z-index:2}
.micon{display:grid;place-items:center;width:20px;height:20px;border:1px solid var(--line-strong);
  background:var(--panel);color:var(--ink-2);border-radius:5px;padding:0;
  transition:transform var(--t),border-color var(--t),color var(--t),box-shadow var(--t)}
.micon:hover{border-color:var(--accent);color:var(--accent);transform:translateY(-1px);box-shadow:var(--shadow)}
.region .micon{width:19px;height:19px;border-color:rgba(255,255,255,.5);background:rgba(255,255,255,.18);color:#fff}
.region .micon:hover{background:#fff;color:var(--sec);border-color:#fff}

.drop-hint{outline:2px dashed var(--accent);outline-offset:4px;border-radius:10px}
.add-section-row{display:flex;align-items:center;gap:14px;margin-top:24px}
.hint{font-size:12.5px;color:var(--muted)}
.empty{text-align:center;color:var(--muted);padding:56px 16px;border:1px dashed var(--line-strong);
  border-radius:var(--r);background:var(--panel);line-height:1.8}
.empty b{color:var(--ink);font-size:15px}

/* ── tooltip ────────────────────────────────────────────── */
.tip{position:fixed;z-index:200;pointer-events:none;max-width:250px;
  background:var(--ink);color:var(--panel);font-size:12px;font-weight:500;line-height:1.4;
  padding:6px 10px;border-radius:7px;box-shadow:var(--shadow-lift);
  opacity:0;transform:translateY(3px);transition:opacity 120ms ease,transform 120ms ease}
.tip.on{opacity:1;transform:none}
.tip.below{transform:translateY(-3px)}
.tip.below.on{transform:none}

/* ── dialogs ────────────────────────────────────────────── */
dialog{border:none;border-radius:14px;padding:0;background:var(--panel);color:var(--ink);
  box-shadow:0 30px 70px rgba(0,0,0,.32);max-width:92vw}
dialog::backdrop{background:rgba(10,10,14,.5);backdrop-filter:blur(2px)}
.dlg{padding:22px;width:410px;max-width:100%;display:flex;flex-direction:column;gap:15px}
.dlg h2{margin:0;font-size:17px;letter-spacing:-.01em}
.field{display:flex;flex-direction:column;gap:6px;font-size:11.5px;font-weight:600;letter-spacing:.03em;
  color:var(--muted);flex:1}
.field input,.field select{border:1px solid var(--line-strong);background:var(--sunk);border-radius:8px;
  padding:9px 11px;font-size:14px;font-weight:500;letter-spacing:0;color:var(--ink);outline:none;width:100%;
  transition:border-color var(--t),box-shadow var(--t)}
.field input:focus,.field select:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.field-row{display:flex;gap:12px}
.dlg-actions{display:flex;justify-content:flex-end;gap:8px;margin:0;padding:0}
.swatches{display:flex;gap:7px;flex-wrap:wrap}
.sw{width:26px;height:26px;border-radius:50%;border:2px solid transparent;transition:transform var(--t)}
.sw:hover{transform:scale(1.12)}
.sw.on{border-color:var(--ink);box-shadow:inset 0 0 0 2px var(--panel)}

/* ── drawer / viewer / toast ────────────────────────────── */
/* The drawer covers the chart but the document under it is still a scroll
   box, and on iPad that showed: a drag on the dark area scrolled the page
   underneath, and once the page had taken the gesture the list itself stopped
   responding until you lifted your finger. Measured, drawer open, 834×1112:
   the document went 0 → 500.

   The page cannot simply be frozen with overflow:hidden — that is what cost
   us the scroll position on WebKit before. So the scroll is stopped at the
   source instead: nothing in the drawer but the list may pan, and the list
   keeps its scrolling to itself rather than handing the overflow on. */
.drawer{position:fixed;inset:0;z-index:60}
.drawer-scrim{position:absolute;inset:0;background:rgba(10,10,14,.45);touch-action:none}
.drawer-head,.tabs,.drawer-foot{touch-action:none}
.drawer-panel{position:absolute;top:0;left:0;bottom:0;width:340px;max-width:86vw;background:var(--panel);
  border-right:1px solid var(--line);z-index:1;display:flex;flex-direction:column;box-shadow:var(--shadow-lift)}
.drawer-head{display:flex;align-items:center;justify-content:space-between;padding:15px 16px;border-bottom:1px solid var(--line)}
.drawer-head h2{margin:0;font-size:15px}
.song-list{overflow:auto;padding:8px;overscroll-behavior:contain;touch-action:pan-y}
.song-row{display:flex;align-items:center;gap:8px;padding:10px 11px;border-radius:9px;cursor:pointer;
  transition:background var(--t)}
.song-row:hover{background:var(--sunk)}
.song-row.on{background:var(--accent-soft);box-shadow:inset 2px 0 0 var(--accent)}
.song-row .sr-main{flex:1;min-width:0}
.song-row .sr-title{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.song-row .sr-sub{font-size:11.5px;color:var(--muted)}
.song-row .sr-no{font-family:var(--mono);font-size:11px;color:var(--muted);width:16px;text-align:right;flex:none}

/* find a song — 32 charts is more than you can read down before a song starts */
.song-find{padding:2px 2px 8px}
.song-find-in{width:100%;box-sizing:border-box;border:1px solid var(--line-strong);background:var(--sunk);
  color:var(--ink);border-radius:9px;padding:9px 11px;font-size:13px;font-family:inherit}
.song-find-in:focus{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}

/* what this device is holding, and whether it will open with no signal */
.store-line{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:0 4px 9px;margin-bottom:2px;
  border-bottom:1px solid var(--line)}
.store-txt{font-size:11.5px;color:var(--muted);line-height:1.5;flex:1;min-width:140px}
.store-get{padding:5px 9px;font-size:11.5px;gap:5px;flex:none}

/* setlists are folders: a filed song lives under its gig, not in the long list */
.song-body{padding-top:8px}
.folder{border:1px solid var(--line);border-radius:10px;margin-bottom:7px;background:var(--panel);overflow:hidden}
.folder.open{border-color:var(--line-strong);box-shadow:var(--shadow)}
.folder-head{display:flex;align-items:center;gap:6px;padding:7px 8px 7px 3px}
.folder-main{flex:1;min-width:0;cursor:pointer}
.folder-name{font-weight:650;font-size:13.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.folder-sub{font-size:11.5px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.folder-go{padding:5px 10px;font-size:12px;gap:5px;flex:none}
.folder-go:disabled{opacity:.45;cursor:default}
.folder-body{border-top:1px solid var(--line);padding:5px;background:var(--sunk)}
.folder-body .song-row{padding:8px 8px}
.song-sep{font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--muted);
  padding:12px 4px 5px;border-top:1px solid var(--line);margin-top:4px}

.drawer-foot{margin-top:auto;display:flex;flex-wrap:wrap;gap:6px;padding:10px 12px;border-top:1px solid var(--line)}
.drawer-foot .btn{flex:1 1 calc(50% - 6px);justify-content:center;white-space:nowrap}

.viewer{position:fixed;inset:0;z-index:160;background:rgba(6,6,10,.78);backdrop-filter:blur(3px);
  display:flex;align-items:center;justify-content:center;padding:24px}
.viewer-inner{background:var(--panel);border-radius:14px;max-width:min(920px,94vw);max-height:90vh;display:flex;
  flex-direction:column;overflow:hidden;box-shadow:0 30px 80px rgba(0,0,0,.5)}
.viewer-head{display:flex;align-items:center;gap:8px;padding:11px 14px;border-bottom:1px solid var(--line);
  font-size:13px;font-weight:600}
.viewer-body{padding:16px;overflow:auto;display:flex;justify-content:center}
.viewer-body img,.viewer-body video{max-width:100%;max-height:70vh;border-radius:10px}
.viewer-body audio{width:min(560px,80vw)}
#viewer-remove:hover{color:var(--danger);border-color:var(--danger)}

.toast{position:fixed;bottom:26px;left:50%;transform:translateX(-50%);background:var(--ink);color:var(--panel);
  padding:10px 18px;border-radius:99px;font-size:13px;font-weight:500;z-index:90;box-shadow:var(--shadow-lift);
  display:flex;align-items:center;gap:12px;max-width:calc(100vw - 24px)}
.toast-do{border:1px solid var(--panel);background:transparent;color:var(--panel);border-radius:99px;
  padding:3px 12px;font-size:12.5px;font-weight:650;flex:none}
.toast-do:hover{background:var(--panel);color:var(--ink)}

/* the ⋯ that opens the action sheet — touch only, see the media query below */
.m-more,.r-more{display:none;place-items:center;border:1px solid var(--line-strong);background:var(--panel);
  color:var(--muted);border-radius:7px;padding:0;position:absolute;z-index:5}
.m-more{top:2px;right:2px;width:32px;height:28px}
.r-more{position:static;width:32px;height:28px;border-color:rgba(255,255,255,.5);
  background:rgba(255,255,255,.18);color:#fff}

.sheet-menu{position:fixed;inset:0;z-index:150;display:flex;flex-direction:column;justify-content:flex-end}
.sheet-scrim{position:absolute;inset:0;background:rgba(10,10,14,.5)}
.sheet-panel{position:relative;background:var(--panel);border-radius:16px 16px 0 0;padding:10px 12px;
  padding-bottom:calc(10px + env(safe-area-inset-bottom));box-shadow:var(--shadow-lift);
  max-height:78vh;overflow:auto;animation:sheet-up 160ms cubic-bezier(.2,.7,.3,1)}
@keyframes sheet-up{from{transform:translateY(14px);opacity:.6}to{transform:none;opacity:1}}
.sheet-panel h3{margin:4px 6px 10px;font-size:13px;color:var(--muted);font-weight:650;letter-spacing:.02em}
.sheet-row{display:flex;align-items:center;gap:12px;width:100%;border:none;background:transparent;color:var(--ink);
  padding:14px 10px;border-radius:10px;font-size:15px;font-weight:550;text-align:left}
.sheet-row:hover,.sheet-row:focus-visible{background:var(--sunk)}
.sheet-row.danger{color:var(--danger)}
.sheet-cancel{width:100%;justify-content:center;margin-top:6px;padding:13px;font-size:15px}
/* NOT overflow:hidden on <body>. Locking the document's scroll box is the
   classic iOS reset: WebKit drops the scroll offset while it is locked, so
   closing the sheet put you back at the top of the chart — on an iPad and in
   every WebKit browser, never in Chrome on a Mac. The sheet is a full-screen
   fixed layer already; containing the scroll inside it is enough. */
.sheet-menu{overscroll-behavior:contain}
.sheet-scrim{touch-action:none}
@media(min-width:721px){
  .sheet-menu{justify-content:center;align-items:center}
  .sheet-panel{border-radius:14px;width:320px;max-width:90vw;padding-bottom:10px;animation:none}
}


/* ── tabs + setlists in the drawer ──────────────────────── */
.tabs{display:flex;gap:4px;padding:8px 10px 0}
.tab{flex:1;border:1px solid transparent;background:transparent;color:var(--muted);border-radius:8px;
  padding:8px 10px;font-size:13px;font-weight:600;transition:background var(--t),color var(--t)}
.tab:hover{background:var(--sunk);color:var(--ink)}
.tab.on{background:var(--accent-soft);color:var(--accent);border-color:var(--accent)}

.list-new{width:100%;justify-content:center;margin-bottom:10px}
.list-empty{color:var(--muted);font-size:12.5px;line-height:1.7;padding:6px 4px;margin:0}
.list-box{border:1px solid var(--line);border-radius:10px;margin-bottom:8px;background:var(--panel);overflow:hidden}
.list-box.open{border-color:var(--line-strong);box-shadow:var(--shadow)}
.list-head{display:flex;align-items:center;gap:6px;padding:8px 8px 8px 4px}
.list-main{flex:1;min-width:0;cursor:pointer}
.list-name{font-weight:650;font-size:13.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.list-sub{font-size:11.5px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.list-go{padding:5px 10px;font-size:12px;gap:5px;flex:none}
.list-go:disabled{opacity:.45;cursor:default}
.list-body{border-top:1px solid var(--line);padding:6px}
.list-song{display:flex;align-items:center;gap:7px;padding:7px 6px;border-radius:8px}
.list-song:hover{background:var(--sunk)}
.list-song.on{background:var(--accent-soft);box-shadow:inset 2px 0 0 var(--accent)}
.ls-no{font-family:var(--mono);font-size:11px;color:var(--muted);width:16px;text-align:right;flex:none}
.ls-main{flex:1;min-width:0;cursor:pointer}
.ls-title{font-weight:600;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ls-sub{font-size:11px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ls-tools{display:flex;gap:1px;flex:none}
.list-add{padding:6px 4px 2px}
.list-select{width:100%;border:1px solid var(--line-strong);background:var(--sunk);color:var(--ink);
  border-radius:8px;padding:8px 10px;font-size:12.5px}

/* ── gig mode ───────────────────────────────────────────────
   Read-only by construction: nothing in here is an input or a button
   except the bar at the top. --gs scales the whole chart at once. */
.gig{position:fixed;inset:0;z-index:120;background:var(--bg);display:flex;flex-direction:column;--gs:1}
body.gig-on{overflow:hidden}
.gig-bar{display:flex;align-items:center;gap:6px;padding:8px 10px;padding-top:calc(8px + env(safe-area-inset-top));
  background:var(--panel);border-bottom:1px solid var(--line-strong);box-shadow:var(--shadow)}
/* The title *is* the jump control. It is a button, but it must not look like
   a chip in the middle of the bar — on stage it is the one piece of text you
   read at a glance, so it stays plain text and only the tap target is real. */
.gig-head{flex:1;min-width:0;display:flex;flex-direction:column;align-items:flex-start;text-align:left;
  line-height:1.25;border:none;background:transparent;color:var(--ink);
  padding:3px 6px 3px 4px;margin-left:-2px;border-radius:9px;font:inherit}
.gig-head:hover{background:var(--sunk)}
.gig-head.plain{background:none;cursor:default}   /* not in a setlist: nothing to jump to */
/* Must sit after the rule above, not up with the wrap rule at the top of the
   file: same specificity, and the later one wins. */
/* Only on a phone, where the bar wraps anyway. A *fixed* basis, never auto:
   the title's width must not depend on how long the artist line is, or a
   wordy credit shoves buttons onto another row and the bar rearranges
   itself between songs. */
@media(max-width:720px){ .gig-head{flex:1 1 160px} }
/* One line, always. A long title shrinks to fit (fitGigTitle) rather than
   wrapping: a bar that changes height between songs moves every button in it,
   and the buttons are what he reaches for without looking. The title is the
   only thing in here allowed to give. */
.gh-top{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  max-width:100%;height:20px;line-height:20px}   /* a fixed box: a shrunk title must not change the bar's height either */
.gh-top b{font-size:16px;font-weight:700;letter-spacing:-.01em}
/* the position rides in the title's own text flow, so it wraps with the last
   word instead of sitting in a column of its own: "At Last  2/20" */
.gh-n{font-family:var(--mono);font-size:11.5px;font-weight:700;color:var(--ink-2);margin-left:8px;
  white-space:nowrap}
.gh-n[hidden]{display:none}
/* fixed space, always: a song with no artist must not make the bar a
   different height from the song before it */
.gh-meta{display:block;font-size:11.5px;line-height:1.3;min-height:15px;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
.gig-jump{position:absolute;top:var(--gig-bar-h,calc(56px + env(safe-area-inset-top)));left:10px;z-index:3;width:260px;max-width:88vw;
  max-height:60vh;overflow:auto;background:var(--panel);border:1px solid var(--line-strong);border-radius:12px;
  box-shadow:var(--shadow-lift);padding:6px}
.gj-row{display:flex;align-items:center;gap:10px;width:100%;border:none;background:transparent;color:var(--ink);
  padding:11px 10px;border-radius:9px;font-size:14px;font-weight:550;text-align:left}
.gj-row:hover{background:var(--sunk)}
.gj-row.on{background:var(--accent-soft);color:var(--accent)}
.gj-no{font-family:var(--mono);font-size:11px;color:var(--muted);width:14px;flex:none}
.gj-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gig-btn{display:grid;place-items:center;width:44px;height:40px;border:1px solid var(--line-strong);
  background:var(--panel);color:var(--ink-2);border-radius:10px;padding:0;flex:none;font-size:14px;font-weight:700}
.gig-btn:hover{background:var(--sunk);color:var(--ink)}
.gig-btn:disabled{opacity:.3}
.gig-btn .gig-sub{font-size:11px;margin-left:1px}
.gig-x{border-color:var(--accent);color:var(--accent)}
.gig-x:hover{background:var(--accent);color:var(--accent-ink)}
/* auto-scroll strip — sits under the bar only while scrolling is armed */
.gig-scroll{display:flex;align-items:center;gap:9px;padding:7px 10px;border-bottom:1px solid var(--line);
  background:var(--sunk);flex:none}
.gig-btn.sm{width:38px;height:34px}
.gig-btn.on{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
.ga-read{font-family:var(--mono);font-size:11.5px;color:var(--ink-2);white-space:nowrap;flex:none}
.ga-slider{flex:1;min-width:90px;display:flex;align-items:center}
.ga-slider input{width:100%;accent-color:var(--accent);height:26px}
.ga-hint{font-size:11px;color:var(--muted);white-space:nowrap;flex:none}
.gig-body{flex:1;overflow:auto;padding:14px 14px 40px;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}
.gig-empty{color:var(--muted);text-align:center;padding:40px}
/* Whether the chart is scrolling itself has to be answerable from across a
   room, without reading a button: forgetting to press play is the failure
   that actually happens. Running is a filled button and a line that visibly
   travels; armed-but-stopped is a button that breathes, so an untouched gig
   mode asks to be started rather than sitting there looking finished. */
.gig-prog{height:3px;background:var(--line);flex:none;overflow:hidden}
.gig-prog[hidden]{display:none!important}
.gig-prog i{display:block;height:100%;width:0;background:var(--accent);
  transition:width .12s linear}
.gig-prog.paused i{background:var(--bar)}
.gig-btn.running{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}
.gig-btn.running:hover{background:var(--accent);color:var(--accent-ink);filter:brightness(1.08)}
.gig-btn.armed{border-color:var(--accent);color:var(--accent);animation:gig-armed 2.1s ease-in-out infinite}
@keyframes gig-armed{0%,100%{opacity:1}50%{opacity:.45}}

.g-sect{margin-bottom:calc(16px * var(--gs))}
.g-cues{display:grid;gap:5px;margin-bottom:5px;align-items:end}
.g-cue{display:inline-flex;align-items:center;gap:5px;justify-self:start;background:var(--panel);
  border:1px solid var(--line-strong);border-bottom:2px solid var(--sec);border-radius:7px 7px 3px 3px;
  padding:3px 9px;font-size:calc(12px * var(--gs));font-weight:600;max-width:100%}
.g-cue span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.g-box{border:1px solid var(--bar);border-radius:9px;overflow:hidden;background:var(--panel);
  box-shadow:var(--shadow);margin-bottom:8px}
.g-strip{display:flex;align-items:center;justify-content:center;gap:9px;min-height:calc(26px * var(--gs));
  background:var(--sec);color:#fff;padding:3px 10px;border-bottom:1px solid var(--bar)}
.g-name{font-size:calc(13px * var(--gs));font-weight:700;letter-spacing:.03em}
.g-rep{font-family:var(--mono);font-size:calc(11px * var(--gs));font-weight:700;border-radius:99px;
  background:rgba(255,255,255,.2);border:1px solid rgba(255,255,255,.45);padding:0 8px}
.g-note{font-size:calc(11px * var(--gs));font-style:italic;color:rgba(255,255,255,.9);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.g-row{display:grid;background:var(--panel)}
.g-bar{position:relative;min-height:calc(78px * var(--gs));border-left:1px solid var(--bar);
  display:flex;flex-direction:column;justify-content:center;padding:15px 4px 7px}
.g-bar:first-child{border-left:none}
.g-no{position:absolute;top:3px;left:6px;font-family:var(--mono);font-size:calc(10px * var(--gs));color:var(--muted)}
.g-chords{display:grid;place-items:center;gap:2px}
.g-chords.split{grid-template-columns:repeat(var(--beats,4),1fr);width:100%}
.g-ch{font-size:calc(32px * var(--gs));font-weight:600;letter-spacing:-.03em;line-height:1.1;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
.g-chords.split .g-ch{font-size:calc(20px * var(--gs))}
.g-ch.wrapped{white-space:normal;overflow-wrap:anywhere;line-height:1.15;text-overflow:clip}
/* the cue wraps rather than truncating — on stage a half-read cue is no cue */
.g-lyric{margin-top:5px;min-height:calc(15px * var(--gs));text-align:center;font-size:calc(11.5px * var(--gs));
  line-height:1.3;font-weight:600;color:var(--ink-2);overflow-wrap:anywhere}

@media(max-width:720px){
  .g-row{grid-template-columns:repeat(2,1fr)!important}
  .g-bar[style*="span 2"],.g-bar[style*="span 3"],.g-bar[style*="span 4"]{grid-column:span 2!important}
  .g-ch{font-size:calc(26px * var(--gs))}
  .gh-top b{font-size:14.5px}
  .gig-bar{gap:4px;padding:6px 8px}
  .gig-btn{width:40px;height:38px}
  .ga-hint{display:none}                      /* the gesture is learned once */
  .gig-scroll{gap:7px;padding:6px 8px}
  .gig-body{padding:10px 10px 30px}
}

/* ── touch: hover-only controls must stay reachable ─────── */
@media (hover:none),(pointer:coarse){
  .meta{min-height:44px}                     /* and they stay level with each other */
  .tap-btn{min-height:44px}                  /* a target you hit in time, not a label */
  /* No hover on touch — and Safari fires :hover on a tap, which used to throw
     the whole tool row over the block the moment you tried to type in it.
     Nothing opens by itself here: the ⋯ opens it, a tap anywhere closes it. */
  .tip{display:none}
  /* nothing opens by itself: two small corner controls, and ⋯ opens the sheet */
  .m-more,.r-more{display:grid}
  .m-tools,.measure:hover .m-tools,.measure:focus-within .m-tools{display:none}
  .r-tools,.region:hover .r-tools,.region:focus-within .r-tools{display:none}
  /* No drag handle on touch. It sat over the chord, and a tap on it was a
     drag: the block faded to a third and a small chip of the chord followed
     your finger. "Move this block earlier / later" is in the ⋯ sheet, where
     it cannot go off by accident. */
  .m-grip,.measure:hover .m-grip,.measure:focus-within .m-grip{display:none}
  .barline-btn,.barline-add{display:none}      /* in the sheet instead — see app.js */
  .m-lyric:empty{border-bottom:1px dotted var(--line)}
  .m-lyric:focus{border-bottom-color:transparent}
  .ibtn,.m-grip{width:36px;height:34px}
  .tab{padding:11px 10px}
  .list-go,.folder-go{padding:9px 12px}
  .song-find-in{font-size:16px}               /* under 16px and iOS zooms in on focus */
  .ga-slider input{height:34px}               /* a slider you can hit with a thumb */
  /* the title opens the setlist now, so it is a target, not a label —
     and padding is what grows a target; line-height does not */
  .gig-head{min-height:44px;justify-content:center;padding-top:5px;padding-bottom:5px}
  .gig-btn.sm{width:42px;height:38px}
  /* Safari on iOS zooms the page whenever it focuses a field smaller than
     16px, and it does not zoom back out. Every field you can type in is 16px
     for that reason, not for looks — and the block grows to make room. */
  /* everything you tap is at least ~40px; a 26px swatch or a 28px dialog
     button is a miss waiting to happen with a plectrum in your hand */
  .rm-chip{padding:8px 13px;font-size:13px}
  .sw{width:34px;height:34px}
  .dlg-actions .btn{padding:11px 16px}
  .trim-tools .btn{padding:11px 14px;font-size:13.5px}
  .choice{padding:14px}
  .measure{height:100px}
  .m-chords{padding-bottom:28px}              /* the cue line keeps its own band */
  .m-lyric{font-size:16px;bottom:5px}
  .meta input,.meta select,.meta .key-in,#song-artist,.r-name,.list-select,.song-find-in,
  .dlg input,.dlg select,.field input,.field select,.time-in,.r-rep-in{font-size:16px}
  .r-name{padding:2px 6px}
  .micon{width:30px;height:30px}
  .barline-btn,.barline-add{width:28px;height:28px}
  .region{height:40px}
  .r-caret{width:34px}
  .m-tools{top:3px;right:3px;padding:1px}
}

/* ── phones ─────────────────────────────────────────────── */
@media(max-width:720px){
  .res-embed{width:100%}
  .res-go span{max-width:150px}
  .topbar{padding:8px 12px;gap:8px}
  .topbar .lbl{display:none}                    /* icon-only; aria-label carries the name */
  .brand span:last-child{display:none}          /* the logo alone — five buttons need the room */
  .topbar .btn{padding:8px;min-width:38px;justify-content:center}
  .brand{font-size:13.5px}
  .sheet{padding:16px 12px 120px}
  .title-in{font-size:23px}
  .meta-row{gap:6px}
  .meta{padding:3px 7px 3px 9px}
  .meta input,.meta select{width:52px;font-size:13px}
  .roadmap-wrap{flex-direction:column;gap:6px;padding:9px 11px;margin-bottom:20px}
  .roadmap-label{padding-top:0}

  /* two bars of time per line — one column turns a song into an endless scroll */
  .system{grid-template-columns:1fr}
  .measures{grid-template-columns:repeat(2,1fr)!important}
  .rowbox{grid-column:1/-1!important}
  .measure{height:104px}
  .measure[style*="span 2"],.measure[style*="span 3"],.measure[style*="span 4"]{grid-column:span 2!important}
  .add-cell{padding:6px 0 0;justify-content:center}
  .add-cell.solo{padding:6px 0 0}
  .add-bar{margin-bottom:0;width:100%;height:32px;border-radius:8px}
  .beat.solo{font-size:26px}
  .beat{font-size:16px}
  .meta input{width:62px}
  .markers{display:flex;flex-wrap:wrap;gap:4px}
  .mk-slot{display:contents}
  .marker{font-size:10.5px;padding:3px 7px}
  .sect{margin-bottom:22px}
  .r-note,.r-part{display:none}

  /* dialogs become bottom sheets */
  dialog{margin:auto auto 0;width:100%;max-width:100%;border-radius:16px 16px 0 0}
  .dlg{width:100%;padding:18px 16px calc(18px + env(safe-area-inset-bottom))}
  .dlg-actions .btn{flex:1;justify-content:center;padding:11px 14px}
  .dlg-actions{gap:10px}
  .viewer{padding:0}
  .viewer-inner{max-width:100vw;max-height:100vh;height:100%;border-radius:0}
  .drawer-panel{width:100%;max-width:100%}
  .toast{bottom:calc(16px + env(safe-area-inset-bottom));width:max-content;max-width:90vw}
}
@media(max-width:340px){
  .measures{grid-template-columns:1fr!important}
  .measure{grid-column:1/-1!important}
}

/* ── reduced motion ─────────────────────────────────────── */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
}

/* ── print ──────────────────────────────────────────────── */
@media print{
  /* Paper gets the chart and nothing that only works on a screen: no audio
     player, no buttons to add or open anything, no carets on the regions. */
  .topbar,.m-tools,.r-tools,.m-more,.r-more,.m-grip,.add-cell,.add-bar,.barline-btn,.barline-add,.add-section-row,
  .drawer,.viewer,.toast,.tip,.gig,.sheet-menu,
  .track-bar,.res-bar,.fit,.score,.lyr-col,.lyr-panel,.r-caret,.micon,.m-icons,.skip-link,.pulse,.tap-btn{display:none!important}
  body.lyr-open{padding-right:0}
  .r-mid{padding:0 8px}                       /* the caret is gone, so is its gutter */
  body{background:#fff;color:#000}
  .sheet{max-width:none;padding:0}
  .sect{break-inside:avoid}
  .rowbox{box-shadow:none;border-color:#333}
  .measure{height:66px;border-color:#333}
  .region{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  .m-lyric{opacity:1}
}

/* confirm dialog + inline repeat editor */
.dlg.confirm{width:360px;gap:10px}
.dlg.confirm p{margin:0;color:var(--muted);font-size:13.5px;line-height:1.5}
.btn.danger-btn{background:var(--danger);border-color:var(--danger);color:#fff;font-weight:600}
.btn.danger-btn:hover{filter:brightness(1.1);color:#fff;border-color:var(--danger)}
.r-rep-in{width:52px;text-align:center;font-family:var(--mono);font-size:11.5px;font-weight:700;
  background:#fff;color:var(--ink);border:1px solid #fff;border-radius:99px;outline:none;padding:1px 4px}
.r-rep-in:focus{box-shadow:0 0 0 3px rgba(255,255,255,.35)}

/* ── sync / account button ──────────────────────────────── */
/* Signed out this is a real, visible call to action — not a ghost button
   with a 7px dot, which vanished entirely on a phone. */
.cloud-btn{border-color:var(--accent);color:var(--accent);font-weight:600}
.cloud-btn:hover{background:var(--accent-soft);border-color:var(--accent);color:var(--accent)}
.cloud-btn[data-state="ok"],.cloud-btn[data-state="syncing"],.cloud-btn[data-state="pending"]{
  border-color:var(--line-strong);color:var(--ink-2);font-weight:500}
.topbar .cloud-btn .lbl{display:inline}          /* never hidden, even on phones */

.cloud-btn .dot{width:7px;height:7px;border-radius:50%;background:var(--muted);flex:none;
  transition:background var(--t),box-shadow var(--t)}
.cloud-btn[data-state="out"] .dot{display:none}
.cloud-btn[data-state="ok"] .dot{background:#2b7a4b;box-shadow:0 0 0 3px color-mix(in srgb,#2b7a4b 18%,transparent)}
.cloud-btn[data-state="syncing"] .dot,.cloud-btn[data-state="pending"] .dot{background:var(--accent);
  animation:pulse 1.1s ease-in-out infinite}
.cloud-btn[data-state="error"] .dot{background:var(--danger);box-shadow:0 0 0 3px color-mix(in srgb,var(--danger) 18%,transparent)}
.cloud-btn[data-state="out"] .dot{background:var(--line-strong)}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}
.dlg-note{margin:0;font-size:13px;line-height:1.5;color:var(--muted)}
.dlg-help{font-size:11.5px;font-weight:400;letter-spacing:0;color:var(--muted);margin-top:1px}
@media (prefers-reduced-motion:reduce){.cloud-btn .dot{animation:none!important}}

/* account row in the sync dialog */
.account-row{display:flex;align-items:center;gap:12px;padding:11px 13px;border:1px solid var(--line);
  background:var(--sunk);border-radius:10px}
.acct{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.acct-email{font-size:13.5px;font-weight:650;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.acct-sub{font-size:11px;color:var(--muted)}
.btn.danger-outline{border-color:var(--line-strong);color:var(--danger);font-weight:600;flex:none}
.btn.danger-outline:hover{border-color:var(--danger);background:color-mix(in srgb,var(--danger) 8%,transparent);
  color:var(--danger)}
.dlg-msg{margin:0;font-size:12.5px;line-height:1.45;color:var(--muted);padding:8px 10px;border-radius:8px;
  background:var(--sunk);border:1px solid var(--line)}
.dlg-msg.good{color:#1f6f45;border-color:color-mix(in srgb,#2b7a4b 35%,transparent);
  background:color-mix(in srgb,#2b7a4b 9%,transparent)}
.dlg-msg.bad{color:var(--danger);border-color:color-mix(in srgb,var(--danger) 35%,transparent);
  background:color-mix(in srgb,var(--danger) 8%,transparent)}
@media (prefers-color-scheme:dark){.dlg-msg.good{color:#7fd3a3}}
.dlg-help code{font-family:var(--mono);font-size:10.5px;background:var(--sunk);padding:1px 4px;border-radius:4px}
.dlg-actions{flex-wrap:wrap}
.dlg-actions .btn{white-space:nowrap}
.dlg-actions .btn.ghost{padding:7px 10px;font-size:12.5px}
.account-row{flex-wrap:wrap}
.account-row .btn{padding:6px 10px;font-size:12.5px}
.inline-field{display:flex;gap:8px;align-items:stretch}
.inline-field input{flex:1;min-width:0}
.inline-field .btn{flex:none;padding:9px 16px}
.dlg-msg{border-left:3px solid var(--line-strong)}
.dlg-msg.good{border-left-color:#2b7a4b}
.dlg-msg.bad{border-left-color:var(--danger)}

/* ── the song's own recording ───────────────────────────── */
.track-bar{margin-bottom:14px}
.track-add{display:inline-flex;align-items:center;gap:8px;border:1px dashed var(--line-strong);background:transparent;
  color:var(--muted);border-radius:10px;padding:10px 16px;font-size:13px;font-weight:500;
  transition:color var(--t),border-color var(--t),background var(--t)}
.track-add:hover{color:var(--accent);border-color:var(--accent);background:color-mix(in srgb,var(--accent) 6%,transparent)}
.track-row{display:flex;align-items:center;gap:10px;background:var(--panel);border:1px solid var(--line);
  border-radius:10px;padding:9px 12px;box-shadow:var(--shadow);color:var(--muted)}
.track-name{font-size:13px;font-weight:600;color:var(--ink);max-width:200px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.track-meta{font-family:var(--mono);font-size:11px}
.track-audio{height:32px;flex:1;min-width:120px;max-width:420px}
.track-btn{padding:6px 11px;font-size:12.5px}

/* ── resources ─────────────────────────────── */
/* Folded away by default. None of this is wanted with a plectrum in hand,
   so it sits under the mp3 row and stays shut until it is asked for. Every
   colour here is a token, so the dark theme needs no second copy. */
.res-bar{margin:-8px 0 14px}
.res-toggle{display:inline-flex;align-items:center;gap:7px;border:1px solid transparent;
  background:transparent;color:var(--muted);border-radius:8px;padding:6px 10px;
  font-size:12.5px;font-weight:600;letter-spacing:.02em;
  transition:color var(--t),background var(--t),border-color var(--t)}
.res-toggle:hover{color:var(--ink-2);background:var(--sunk);border-color:var(--line)}
.res-toggle[aria-expanded="true"]{color:var(--ink-2)}
.res-count{font-family:var(--mono);font-size:10.5px;font-weight:700;color:var(--accent);
  background:var(--accent-soft);border-radius:99px;padding:1px 7px}
.res-panel{margin-top:8px;background:var(--panel);border:1px solid var(--line);border-radius:10px;
  padding:14px;box-shadow:var(--shadow);display:flex;flex-direction:column;gap:14px}
.res-group{display:flex;flex-direction:column;gap:9px}
.res-h{margin:0;font-size:10.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted)}
.res-chips{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.res-chip{display:inline-flex;align-items:stretch;border:1px solid var(--line-strong);
  border-radius:9px;overflow:hidden;background:var(--sunk);max-width:100%}
.res-go{display:inline-flex;align-items:center;gap:7px;border:0;background:transparent;
  color:var(--ink);padding:8px 11px;font-size:12.5px;font-weight:550;min-height:40px;min-width:0}
.res-go span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:210px}
.res-go:hover{background:var(--accent-soft);color:var(--accent)}
.res-kill{border:0;border-left:1px solid var(--line-strong);background:transparent;
  color:var(--muted);width:36px;min-height:40px;display:grid;place-items:center}
.res-kill:hover{background:var(--danger);color:#fff}
.res-add{display:inline-flex;align-items:center;gap:7px;border:1px dashed var(--line-strong);
  background:transparent;color:var(--muted);border-radius:9px;padding:8px 13px;
  font-size:12.5px;font-weight:500;min-height:40px;
  transition:color var(--t),border-color var(--t),background var(--t)}
.res-add:hover{color:var(--accent);border-color:var(--accent);background:var(--accent-soft)}
.res-hint{margin:0;font-size:11.5px;color:var(--muted);line-height:1.45;max-width:62ch}
.res-embed{width:min(860px,84vw);border:0;border-radius:10px;background:#000;display:block}
.res-note{margin:0;font-size:12px;color:var(--muted);max-width:60ch;text-align:center;line-height:1.5}
.dlg-note.res-ok{color:var(--ink-2)}
/* These live here, not up in the main touch block: the .res- rules above are
   later in the file than that block, so a min-height set up there loses on
   order. Measured at 375px — 40px, not the 44 it claimed. */
@media (hover:none),(pointer:coarse){
  .res-go,.res-add,.res-toggle{min-height:44px}
  .res-kill{min-height:44px;width:44px}
}

/* ── lyrics: the sheet, the column, the walk ──────── */
.dlg.lyrics{width:min(620px,94vw)}
.lyrics-in{border:1px solid var(--line-strong);background:var(--sunk);border-radius:8px;
  padding:11px 12px;font-size:14px;line-height:1.55;color:var(--ink);width:100%;
  font-family:var(--font);resize:vertical;outline:none;min-height:180px;
  transition:border-color var(--t),box-shadow var(--t)}
.lyrics-in:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}

/* the column beside the chart on stage */
.gig-split{flex:1;display:flex;min-height:0}
.lyr-col{width:250px;flex:none;border-left:1px solid var(--line);background:var(--panel);
  overflow:auto;padding:12px 14px 40px;-webkit-overflow-scrolling:touch;
  overscroll-behavior:contain}
.lyr-col[hidden]{display:none!important}
.lyr-h{margin:0 0 10px;font-size:calc(10.5px * var(--gs));font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
/* One region's words, then the next. The heading carries which time through
   it is when a region is played more than once. */
.lyr-sec{display:flex;justify-content:space-between;align-items:baseline;gap:6px;
  font-size:calc(9.5px * var(--gs));font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  color:var(--muted);margin:15px 0 5px;padding-bottom:2px;border-bottom:1px solid var(--line)}
.lyr-sec:first-of-type{margin-top:0}
.lyr-pass{letter-spacing:.03em;text-transform:none;font-weight:600;color:var(--accent);white-space:nowrap}
/* Each bar is one block — chord on top, its words underneath — and the blocks
   flow like a sentence, so the lyric still reads as a line and the chord sits
   over the syllable it lands on. An atomic block wraps cleanly at any width,
   which a character-aligned chord sheet does not. */
.lyr-flow{display:flex;flex-wrap:wrap;align-items:flex-end;gap:2px 7px}
.lyr-pair{display:inline-flex;flex-direction:column;min-width:0}
.lyr-ch{font-size:calc(11.5px * var(--gs));font-weight:700;color:var(--accent);
  line-height:1.25;letter-spacing:-.01em;white-space:nowrap}
.lyr-pair.bare .lyr-ch{visibility:hidden}
.lyr-wd{font-size:calc(14px * var(--gs));color:var(--ink);line-height:1.35;word-break:break-word}
.lyr-raw{margin:0;font-family:var(--font);white-space:pre-wrap;word-break:break-word;
  font-size:calc(13px * var(--gs));line-height:1.5;color:var(--ink-2)}
.lyr-hint{margin:0 0 9px;font-size:calc(11px * var(--gs));color:var(--muted);line-height:1.45}
.gig-btn.gig-lyr{width:auto;padding:0 11px;font-size:11px;font-weight:700;letter-spacing:.08em}
/* ── the resources folder ───────────────────── */
.resf{border-top:1px solid var(--line);padding-top:14px;display:flex;flex-direction:column;gap:8px}
.resf-head{display:flex;align-items:baseline;gap:9px}
.resf-head b{font-size:13px;font-weight:700;letter-spacing:.01em}
.resf-state{font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  border-radius:99px;padding:2px 9px;background:var(--sunk);color:var(--muted)}
.resf-state.on{background:color-mix(in srgb,#2b7a4b 16%,transparent);color:#2b7a4b}
.resf-state.warn{background:var(--accent-soft);color:var(--accent)}
.resf-acts{display:flex;flex-wrap:wrap;gap:8px}
.resf-acts .btn{padding:8px 13px;font-size:12.5px}
@media (hover:none),(pointer:coarse){ .resf-acts .btn{min-height:44px} }

/* ── the sheet music reader ────────────────────── */
/* Above gig mode (120) and the walk (130): it is opened from on stage, and an
   overlay you cannot see is not an overlay. */
.score{position:fixed;inset:0;z-index:140;background:var(--bg);display:flex;flex-direction:column}
.score[hidden]{display:none!important}
.score-top{display:flex;align-items:center;gap:6px;padding:8px 10px;
  padding-top:calc(8px + env(safe-area-inset-top));border-bottom:1px solid var(--line);
  background:var(--panel);flex:none}
.score-top b{font-size:14px;font-weight:700;letter-spacing:-.01em;flex:1;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.score-pos{font-family:var(--mono);font-size:11.5px;color:var(--muted);flex:none;padding:0 4px}
.score-body{flex:1;overflow:auto;padding:14px;display:flex;flex-direction:column;
  align-items:center;gap:14px;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;
  background:var(--sunk)}
/* white behind every page, in both themes: a score is ink on paper, and a
   dark card behind a transparent PDF turns the staves invisible */
.score-page{display:block;max-width:100%;background:#fff;border-radius:6px;
  box-shadow:var(--shadow);height:auto}
.score-note{margin:0;padding:30px 16px;color:var(--muted);font-size:13px;text-align:center;
  max-width:46ch;line-height:1.5}
#score-prev[hidden],#score-next[hidden]{display:none!important}
.gig-btn.gig-lyr[hidden]{display:none!important}
/* The same sheet on the normal screen. Fixed to the right rather than folded
   into the page: the chart is a scrolling document, so a panel in the flow
   would scroll away from the bars it describes. The body gives up the width
   instead of the panel covering the chart — on a wide screen there is room
   to have both, and on a narrow one there is not (see below). */
.lyr-panel{position:fixed;top:0;right:0;bottom:0;width:300px;z-index:45;
  background:var(--panel);border-left:1px solid var(--line);
  box-shadow:-10px 0 30px rgba(0,0,0,.10);display:flex;flex-direction:column}
.lyr-panel[hidden]{display:none!important}
.lyr-panel-top{display:flex;align-items:center;gap:4px;padding:9px 10px 9px 14px;
  padding-top:calc(9px + env(safe-area-inset-top));border-bottom:1px solid var(--line);flex:none}
.lyr-panel-top b{font-size:13px;font-weight:700;letter-spacing:.02em}
.lyr-act{padding:6px 10px;font-size:12px}
.lyr-act[hidden]{display:none!important}
.lyr-panel-body{flex:1;overflow:auto;padding:13px 14px 40px;
  -webkit-overflow-scrolling:touch;overscroll-behavior:contain}
.lyr-cta{margin-top:16px;width:100%;justify-content:center}
.btn.on{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}
body.lyr-open{padding-right:300px}
@media(max-width:900px){
  /* No room to hold both: the panel covers the chart and you flip between
     them, the same bargain gig mode makes on a phone. */
  body.lyr-open{padding-right:0}
  .lyr-panel{width:min(360px,100%)}
}
.gig-btn.gig-lyr[hidden]{display:none!important}

/* the walk */
.fit{position:fixed;inset:0;z-index:130;background:var(--bg);display:flex;flex-direction:column}
.fit[hidden]{display:none!important}
/* .fit-top, not .fit-bar: a bar of the chart below is also a .fit-bar, and
   its flex-direction:column was laying this header out as a stack. */
.fit-top{display:flex;align-items:center;gap:6px;padding:8px 10px;
  padding-top:calc(8px + env(safe-area-inset-top));border-bottom:1px solid var(--line);
  background:var(--panel);flex:none}
.fit-head{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.25;padding-left:2px}
.fit-head b{font-size:15px;font-weight:700;letter-spacing:-.01em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fit-head span{font-size:11.5px;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fit-count{font-family:var(--mono);font-size:11.5px;color:var(--muted);flex:none;padding:0 4px}
.gig-btn.fit-go{width:auto;padding:0 16px;font-size:13px;font-weight:650;
  background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}
.gig-btn.fit-go:hover{filter:brightness(1.08);background:var(--accent);color:var(--accent-ink)}
#fit-back,#fit-skip{width:auto;padding:0 12px;font-size:12.5px}
.fit-body{flex:1;display:flex;min-height:0}
.fit-sheet{flex:1;min-width:0;overflow:auto;padding:16px 18px 40px;font-size:17px;
  line-height:1.85;white-space:pre-wrap;word-break:break-word;color:var(--muted);
  border-right:1px solid var(--line);-webkit-overflow-scrolling:touch}
.fw{border-radius:5px;padding:2px 3px;margin:0 -1px;cursor:pointer;
  transition:background var(--t),color var(--t)}
.fw:hover{background:var(--sunk);color:var(--ink-2)}
.fw.used{color:var(--ink-2);text-decoration:underline;text-decoration-color:var(--accent);
  text-decoration-thickness:1.5px;text-underline-offset:3px}
.fw.on{background:var(--accent);color:var(--accent-ink);font-weight:600}
.fit-chart{width:340px;flex:none;overflow:auto;padding:14px 14px 40px;background:var(--sunk);
  -webkit-overflow-scrolling:touch}
.fit-strip{font-size:10.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);margin:12px 0 6px}
.fit-strip:first-child{margin-top:0}
.fit-row{display:grid;grid-template-columns:repeat(2,1fr);gap:7px}
.fit-bar{display:flex;flex-direction:column;align-items:flex-start;gap:2px;text-align:left;
  border:1px solid var(--line-strong);background:var(--panel);border-radius:9px;
  padding:7px 9px;min-height:56px;transition:border-color var(--t),background var(--t)}
.fit-bar:hover{border-color:var(--accent)}
.fit-no{font-family:var(--mono);font-size:10px;color:var(--muted)}
.fit-ch{font-size:15px;font-weight:650;color:var(--ink);line-height:1.15;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
.fit-ly{font-size:11px;color:var(--accent);line-height:1.3;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
.fit-bar.now{border-color:var(--accent);background:var(--accent-soft);
  box-shadow:0 0 0 2px var(--accent)}

@media(max-width:900px){
  /* portrait: the sheet on top, the bars underneath, the way you read them */
  .fit-body{flex-direction:column}
  .fit-sheet{flex:0 0 46%;border-right:none;border-bottom:1px solid var(--line);font-size:16px}
  .fit-chart{width:auto;flex:1}
  .fit-row{grid-template-columns:repeat(4,1fr)}
}
@media(max-width:560px){
  .fit-row{grid-template-columns:repeat(2,1fr)}
  #fit-back,#fit-skip{padding:0 9px;font-size:12px}
  /* A phone has no room to hold both. Squeezing the chart into 175px put its
     chords on the 11px floor two to a row — measured, not guessed. So here the
     column covers the chart instead of sharing with it, and you flip between
     them. It is laid over rather than swapped in so the chart keeps its real
     width underneath: auto-scroll's plan is in chart coordinates, and a chart
     measured at display:none would be measured as nothing. */
  .gig-split{position:relative}
  .lyr-col{position:absolute;inset:0;width:auto;border-left:none;z-index:4;
    background:var(--panel);padding-bottom:60px}
  /* full width, not 360 of 375: a 15px strip of half-cut chart down one side
     reads as a bug rather than as a choice */
  .lyr-panel{width:100%;border-left:none}
}
@media (hover:none),(pointer:coarse){
  /* A word is a tap target here, so the lines are set further apart than
     reading alone would need — 28px of word was not enough with a thumb. */
  /* line-height spaces the lines; it does not grow an inline box's hit area,
     which is font size plus padding. So the padding is what has to give. */
  .fit-sheet{line-height:2.4}
  .fw{padding:9px 5px;margin:0 -3px}
  .fit-bar{min-height:62px}
}

/* ── attach chooser ─────────────────────────────────────── */
.choices{display:flex;flex-direction:column;gap:8px}
.choice{display:flex;flex-direction:column;gap:2px;align-items:flex-start;text-align:left;
  border:1px solid var(--line-strong);background:var(--sunk);border-radius:10px;padding:12px 14px;
  transition:border-color var(--t),background var(--t)}
.choice:hover{border-color:var(--accent);background:var(--accent-soft)}
.choice-t{font-size:13.5px;font-weight:650;color:var(--ink)}
.choice-s{font-size:11.5px;color:var(--muted)}

/* ── trimmer ────────────────────────────────────────────── */
.dlg.trim{width:440px}
.trim-strip{position:relative;height:44px;border-radius:8px;background:var(--sunk);
  border:1px solid var(--line-strong);overflow:hidden;cursor:pointer;
  background-image:repeating-linear-gradient(90deg,var(--line) 0 1px,transparent 1px 12px)}
.trim-sel{position:absolute;top:0;bottom:0;background:color-mix(in srgb,var(--accent) 30%,transparent);
  border-left:2px solid var(--accent);border-right:2px solid var(--accent)}
.trim-play{position:absolute;top:0;bottom:0;width:2px;background:var(--danger)}
.trim-row{display:flex;gap:12px;align-items:flex-end}
.time-in{font-family:var(--mono)}
.trim-len{flex:0 0 auto}
.trim-len b{font-family:var(--mono);font-size:14px;color:var(--ink);padding:9px 0}
.slider{display:block;margin:-6px 0}
.slider input[type=range]{width:100%;accent-color:var(--accent)}
.trim-tools{display:flex;gap:8px;flex-wrap:wrap}
.trim-tools .btn{padding:7px 12px;font-size:12.5px}
#viewer-body{flex-direction:column;gap:12px;align-items:center}

@media(max-width:720px){
  .track-row{flex-wrap:wrap}
  .track-audio{width:100%;max-width:none;order:9}
  .dlg.trim{width:100%}
}
.track-warn{flex:1;min-width:140px;font-size:12px;color:var(--danger);line-height:1.4}
