/* The accent IS the playhead colour, so the thing you follow while a song plays
   and the thing you click are the same. --btn sits a step off --bg so a bordered
   button reads as a raised surface rather than a painted outline. */
:root{
  --bg:#E8EBE9; --surface:#F4F6F4; --paper:#FCFCFA; --paper-edge:#D9DEDA;
  --btn:#FFFFFF; --btn-edge:#C1C9C5;
  --ink:#141D1B; --ink-2:#4F5C58; --ink-3:#5C6862;
  --line:#C7CFCB; --accent:#0F6E64; --accent-soft:rgba(15,110,100,.12);
  --accent-on:#FFFFFF; --cursor:#0F6E64; --radius:4px;
  --chev:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%234F5C58' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.6 6 6.4 11 1.6'/%3E%3C/svg%3E");
}
/* Day is the default; Dusk is opt-in via the toggle, never via the OS setting.
   Dusk is a LIGHT warm low-blue-light mode -- amber paper, near-black warm ink.
   Nothing here is blue-dominant, the accent included: a blue accent would defeat
   the point of the mode. */
:root[data-theme="dusk"]{
  --bg:#F6EEDA; --surface:#FBF5E6; --paper:#FCF7EA; --paper-edge:#E3D5B8;
  --btn:#FAF4E4; --btn-edge:#D8C8A6;
  --ink:#241A0B; --ink-2:#584427; --ink-3:#6E5930;
  --line:#E5D8BD; --accent:#9A4E06; --accent-soft:rgba(154,78,6,.13);
  --accent-on:#FCF7EA; --cursor:#9A4E06;
  --chev:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%23584427' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.6 6 6.4 11 1.6'/%3E%3C/svg%3E");
}
*{box-sizing:border-box}
html,body{margin:0}
body{background:var(--bg); color:var(--ink);
  font:400 15px/1.6 Archivo,"Helvetica Neue",Arial,sans-serif; -webkit-font-smoothing:antialiased}
.wrap{max-width:980px; margin:0 auto; padding-inline:16px; padding-block:32px 64px}

/* ---------- masthead ---------- */
/* One line, always: nothing here wraps, and the title is the only thing that
   gives ground when the window narrows. */
.masthead{display:flex; align-items:center; gap:14px; flex-wrap:nowrap;
  border-bottom:1px solid var(--line); padding-bottom:16px}
h1{font-family:"Playfair Display",Georgia,"Times New Roman",serif; font-weight:600;
  font-size:clamp(24px,4.4vw,42px); line-height:1.1; margin:0; letter-spacing:-.01em;
  /* The site name never shrinks. It and .count were both flex:0 1 auto, so a
     crowded masthead ate 'Sheets' into 'Sh...'. The count is the one that can
     afford to ellipsise -- and since this one cannot shrink, its own overflow
     clipping had nothing left to do except cut the tail off the italic f, whose
     descender hangs 3px below the line box. */
  flex:0 0 auto; min-width:0; white-space:nowrap}
/* The forte marking is just an italic f, which is what the printed dynamic is.
   Set rather than drawn: a hand-built path came out stiff next to Playfair, and
   the real italic already has the thick-and-thin and the long descender. The
   italic axis is requested in the font link so this is a true italic, not a
   browser-synthesised slant. */
/* The italic f's ink starts LEFT of its origin -- about 2px at this size -- so
   sitting first in the line put its tail outside the content box and against the
   page edge, where anything clipping the document cut the tail flat. The left
   margin buys the overhang its own room. */
/* Georgia, NOT the Playfair Display the rest of the title is set in. A forte
   mark is mostly tail -- a descender that swings left and curls back under the
   baseline -- and Playfair's italic f has no curl at all: its descender stops in
   a blunt angled stub, which reads exactly like a letter whose bottom has been
   cut off. No amount of overflow, margin or size fixes a glyph that was never
   drawn with the hook. Georgia's italic f has it, Times' does too, and this is
   the same stack favicon.svg uses, so the logo and the tab icon are one letter. */
h1 .mark{font-family:Georgia,"Times New Roman",serif;
  /* 1em, not the 1.5em it wore while the curl was missing: that size was an
     attempt to make an absent hook legible by enlarging it, and once the font
     had the hook the f just dwarfed the word. Georgia's ascender already rises
     a little above Playfair's cap height, so at 1em the mark still reads as a
     mark and the lockup reads as one word. */
  font-style:italic; font-weight:700; font-size:1em;
  margin-left:.08em; margin-right:.22em; letter-spacing:0;
  line-height:0}
.masthead .btn{flex:0 0 auto}
/* Favourites sits in the Categories modal header: the same icon-and-count
   shape as a category card, shrunk to header scale, so it reads as a
   shortcut to one more category without taking a whole card slot. */
.favcard{flex:0 0 auto; display:inline-flex; align-items:center; gap:9px;
  background:var(--btn); border:1px solid var(--line); border-radius:var(--radius);
  padding:7px 12px 7px 9px; cursor:pointer; color:var(--ink);
  font:600 14px/1.2 inherit; transition:border-color .15s,background .15s}
.favcard:hover{border-color:var(--accent)}
.favcard[aria-current="true"]{border-color:var(--accent); background:var(--accent-soft)}
.favcard .fi{flex:0 0 auto; width:24px; height:24px; display:inline-flex;
  align-items:center; justify-content:center; border-radius:7px;
  background:var(--accent-soft); color:var(--accent)}
.favcard .fi svg{width:15px; height:15px; display:block; fill:currentColor; stroke:none}
.favcard:hover .fi,.favcard[aria-current="true"] .fi{background:var(--accent); color:var(--accent-on)}
.favcard .fn{font-family:"IBM Plex Mono",ui-monospace,monospace; font-size:11px;
  font-weight:400; color:var(--ink-3)}
.favcard[aria-current="true"] .fn{color:var(--accent)}
/* Sits directly after the Browse button, because it says what that button last
   did. It used to carry margin-left:auto and float off to the right next to the
   theme switch, where it read as a third control rather than as the answer to
   the second one. The auto margin moves to the theme switch, which is what
   actually wants the right edge. */
.count{font-family:"IBM Plex Mono",ui-monospace,monospace; font-size:14px; color:var(--ink-2);
  font-variant-numeric:tabular-nums; flex:0 1 auto; min-width:0;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.ctl.theme{font-size:12px; color:var(--ink-3); gap:8px; flex:0 0 auto; margin-left:auto}
.btn.browse{padding:10px 18px; font-size:14.5px; font-weight:600}
.seg{display:inline-flex; border:1px solid var(--btn-edge); border-radius:var(--radius);
  overflow:hidden; background:var(--btn)}
.seg input{position:absolute; opacity:0; width:0; height:0; pointer-events:none}
.seg label{padding:6px 11px; font-size:12px; font-weight:500; cursor:pointer; color:var(--ink-2);
  border-right:1px solid var(--btn-edge); line-height:1.2; user-select:none; white-space:nowrap}
.seg label:last-child{border-right:0}
.seg label:hover{color:var(--accent)}
.seg input:checked + label{background:var(--accent); color:var(--accent-on)}
.seg input:focus-visible + label{outline:2px solid var(--accent); outline-offset:-2px}

button{font:inherit; color:inherit; cursor:pointer; background:none; border:none}
.btn{border:1px solid var(--btn-edge); border-radius:var(--radius); background:var(--btn);
  padding:7px 13px; font-size:13px; font-weight:500; white-space:nowrap;
  transition:border-color .15s,color .15s; text-decoration:none; display:inline-block}
.btn:hover{border-color:var(--accent); color:var(--accent)}
.btn:disabled{opacity:.4; cursor:default}
.btn:disabled:hover{border-color:var(--btn-edge); color:inherit}
.btn[aria-pressed="true"]{border-color:var(--accent); color:var(--accent); background:var(--accent-soft)}
.btn.ghost{padding:6px 11px; font-size:12.5px}
select{font:inherit; font-size:13px; color:var(--ink);
  border:1px solid var(--btn-edge); border-radius:var(--radius); cursor:pointer;
  /* The UA draws its chevron hard against the right border and there is no way to
     move it, so we draw our own and give it room. */
  -webkit-appearance:none; -moz-appearance:none; appearance:none;
  background-color:var(--btn); background-image:var(--chev);
  background-repeat:no-repeat; background-position:right 12px center;
  background-size:11px 7px; padding:7px 34px 7px 11px}
select::-ms-expand{display:none}
select:hover{border-color:var(--accent)}
:focus-visible{outline:2px solid var(--accent); outline-offset:2px}

/* ---------- song picker ---------- */
.picker{display:flex; align-items:center; gap:10px; margin-top:18px; flex-wrap:wrap}
.picker .nav{min-width:66px; font-size:20px; line-height:1; padding:10px 22px; font-weight:600}
.picker .nav.shuffle{min-width:52px; padding:10px 13px; display:inline-flex;
  align-items:center; justify-content:center}
.picker .nav.shuffle svg{width:20px; height:20px; display:block}
.picker .nav.shuffle[aria-pressed="true"]{background:var(--accent); border-color:var(--accent);
  color:var(--accent-on)}
.picker .nav.shuffle[aria-pressed="true"]:hover{color:var(--accent-on)}
/* ---------- song picker ----------
   A combobox rather than a <select>, because a native one can neither filter as
   you type nor right-align the bar count. The button mimics the select's look so
   the picker row is unchanged at rest; the popup is an absolutely positioned
   panel so it does not push the score down when it opens. */
.songbox{position:relative; flex:1 1 320px; min-width:0}
.songbtn{width:100%; display:flex; align-items:center; gap:10px; text-align:left;
  font:500 15px/1.35 inherit; color:var(--ink); background:var(--btn);
  border:1px solid var(--line); border-radius:var(--radius);
  padding:9px 12px; cursor:pointer}
.songbtn:hover{border-color:var(--ink-3)}
.songbtn:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.songname{flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap}
/* The bar count is the thing being right-aligned: it sits in its own column,
   pushed over by the title's flex-grow, and never shrinks. */
.songbars{flex:0 0 auto; font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:11.5px; color:var(--ink-3); letter-spacing:.03em; white-space:nowrap}
.songcaret{flex:0 0 auto; width:16px; height:16px; color:var(--ink-3)}
.songbtn[aria-expanded="true"]{border-bottom-left-radius:0; border-bottom-right-radius:0}
.songbtn[aria-expanded="true"] .songcaret{transform:rotate(180deg)}

/* Same trap as .songrow below: an author `display` beats the UA sheet's
   [hidden]{display:none}, so without this the popup never closes. */
.songpop[hidden]{display:none}
/* Hung off the button's own bottom edge, pulled up by its border width so the
   two borders sit on each other rather than stacking into a double line. */
.songpop{position:absolute; z-index:40; top:calc(100% - 1px); left:0; right:0;
  background:var(--paper); border:1px solid var(--line);
  border-radius:0 0 var(--radius) var(--radius); box-shadow:0 10px 30px rgba(0,0,0,.18);
  overflow:hidden; display:flex; flex-direction:column; max-height:min(62vh,460px)}
.songfilter{flex:0 0 auto; margin:8px; padding:9px 11px; font:400 14px/1.3 inherit;
  color:var(--ink); background:var(--bg); border:1px solid var(--line);
  border-radius:8px; -webkit-appearance:none; appearance:none}
.songfilter:focus{outline:none; border-color:var(--accent)}
.songfilter[hidden]{display:none}
.songlist{flex:1 1 auto; overflow:auto; padding:0 4px 6px;
  overscroll-behavior:contain}
/* The set headings in a multi-set collection. They were --ink-3 at 10.5px,
   which put the one piece of structure in the list below the songs it was
   organising. In the accent, a size up and a weight heavier, they read as
   headings at a glance. */
/* 700 here is a REAL weight, and was not always: the font request used to load
   IBM Plex Mono at 400 and 500 only, so asking for 700 got a synthesised bold --
   the 500 outline smeared thicker -- which at 12px uppercase with letter-spacing
   reads as soft and slightly out of focus rather than as bold. `.readout b` a
   few rules down still carries the old workaround for the same problem, stepping
   its weight DOWN to 500 to stay on a real face. 600 and 700 are requested now,
   and an unused weight costs nothing: the browser downloads only the faces it
   actually needs. */
.songgroup{padding:9px 10px 3px; font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:12px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  color:var(--accent)}
.songrow{display:flex; align-items:baseline; gap:12px; width:100%;
  padding:4px 10px; border-radius:6px; cursor:pointer; text-align:left;
  background:none; border:0; color:var(--ink); font:400 14.5px/1.25 inherit}
.songrow .t{flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap}
.songrow .b{flex:0 0 auto; font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:11px; color:var(--ink-3); white-space:nowrap}
/* An author `display` beats the UA sheet's [hidden]{display:none}, so a row
   the filter marks hidden stays on screen unless this says otherwise. */
.songrow[hidden],.songgroup[hidden]{display:none}
.songrow[aria-selected="true"]{color:var(--accent); font-weight:600}
.songrow[aria-selected="true"] .b{color:var(--accent)}
/* Hover and the keyboard highlight are one state, and it fills with the accent.
   These must stay AFTER the aria-selected rules above: the current song draws
   its text in the accent, which on an accent fill would be invisible, and equal
   specificity means the later rule is the one that wins. */
.songrow:hover,.songrow.on{background:var(--accent); color:var(--accent-on)}
.songrow:hover .b,.songrow.on .b{color:var(--accent-on)}
.songnone{margin:0; padding:14px 12px 18px; text-align:center;
  color:var(--ink-3); font-size:13px; font-style:italic}
.where{font-family:"IBM Plex Mono",ui-monospace,monospace; font-size:11.5px;
  color:var(--ink-3); letter-spacing:.04em; white-space:nowrap}

/* ---------- transport ---------- */
.transport{position:sticky; top:0; z-index:20; margin-top:14px;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--radius);
  padding:11px 13px; display:flex; flex-direction:column; gap:11px}
.row{display:flex; align-items:center; gap:9px; flex-wrap:wrap}
.play{min-width:104px; display:inline-flex; align-items:center; justify-content:center;
  gap:8px; background:var(--accent); border-color:var(--accent); color:var(--accent-on)}
/* The extra right padding is deliberate: the glyph sits left of the word, so the
   button's ink is left-heavy and equal padding reads as a tight right edge.
   `.btn.play` and not `.play`, because the pointer:coarse block further down
   re-sets `.btn`'s padding shorthand -- at equal specificity that later rule
   would win, and this would quietly do nothing on the touch screens it is for. */
.btn.play{padding-right:19px}
.play:hover{color:var(--accent-on); filter:brightness(1.08)}
.play:disabled{filter:none}
/* The button must not change width when it is pressed, and two things in it
   did: the glyph (a triangle becomes two bars -- narrower, as it happens) and
   the word. The glyph gets a fixed box. The word gets a zero-height copy of the
   longer label sitting under it, so the label is always at least as wide as
   "Pause" at whatever font size the breakpoint is using -- no measured number to
   go stale, and it stays right if either word is ever changed. */
.play .glyph{font-size:11px; line-height:1; flex:0 0 auto; width:10px; text-align:center}
#playlab{display:block}
#playlab::after{content:"Pause"; display:block; height:0; overflow:hidden;
  visibility:hidden; font-weight:inherit}
a.dl{color:var(--ink)} a.dl:hover{color:var(--accent)}
#pdf{margin-left:auto}   /* pushed to the end of its row */
a.dl .arrow{color:var(--accent); font-weight:600}
/* .btn is inline-block, which would leave the icon sitting on the text baseline
   instead of centred against it. */
.btn.share{display:inline-flex; align-items:center; gap:6px}
.btn.share svg{flex:0 0 auto; width:15px; height:15px; color:var(--accent)}
.btn.share:hover svg{color:inherit}
.ctl{display:inline-flex; align-items:center; gap:8px; font-size:12.5px; color:var(--ink-2)}
.ctl input[type=range]{accent-color:var(--accent); width:118px}
.keygrp{gap:5px}
.keygrp select{min-width:112px; text-align:center; padding-left:34px}
.octgrp{gap:5px}
.octgrp #octnow{font-family:"IBM Plex Mono",ui-monospace,monospace; font-size:12.5px;
  color:var(--ink); font-weight:500; min-width:22px; text-align:center}
.btn.step{padding:8px 14px; font-size:17px; line-height:1; font-weight:700; min-width:40px}
.ctl output{font-family:"IBM Plex Mono",ui-monospace,monospace; font-size:12.5px;
  color:var(--ink); font-weight:500; font-variant-numeric:tabular-nums; min-width:50px}
.barrow{display:flex; align-items:center; gap:12px}
.barrow .bar-strip{flex:1 1 auto; min-width:0}
.readout{font-family:"IBM Plex Mono",ui-monospace,monospace; font-size:12.5px;
  color:var(--ink-2); font-variant-numeric:tabular-nums; white-space:nowrap; flex:0 0 auto}
/* Now that a real semibold exists, this can be the weight it always wanted --
   the bar number is the one figure on the strip you actually read. */
.readout b{color:var(--ink); font-weight:600}

/* ---------- scrub ---------- */
.bar-strip{position:relative; height:28px; cursor:pointer; touch-action:none; user-select:none}
.bar-strip.dragging{cursor:grabbing}
#track{position:absolute; inset:0; background:var(--bg); border-radius:2px; overflow:hidden}
#fill{position:absolute; left:0; top:0; bottom:0; width:0;
  background:var(--accent); opacity:.16; pointer-events:none}
.tick{position:absolute; top:0; bottom:0; width:1px; background:var(--line); pointer-events:none}
.tick.period{background:var(--ink-3); opacity:.5}
#head{position:absolute; top:-3px; bottom:-3px; width:2px; margin-left:-1px;
  background:var(--ink); pointer-events:none}
#head::after{content:""; position:absolute; left:-4px; right:-4px; top:-2px; height:6px;
  background:var(--ink); border-radius:1px}
.bar-strip:focus-visible{outline:2px solid var(--accent); outline-offset:3px}

/* ---------- score ---------- */
.sheet{position:relative; margin-top:20px; background:var(--paper);
  border:1px solid var(--paper-edge);
  border-radius:var(--radius); padding:22px 16px 28px}
/* Absolutely positioned in the sheet's top-left corner, out of the engraver's
   way: abcjs centres the title, so nothing collides, and taking the star out of
   the flow means it survives a re-render of #paper untouched. */
.favmark{position:absolute; top:8px; left:8px; z-index:2;
  width:34px; height:34px; display:inline-flex; align-items:center;
  justify-content:center; padding:0; cursor:pointer;
  background:transparent; border:0; border-radius:var(--radius);
  color:var(--ink-3); transition:color .12s, transform .12s}
.favmark svg{width:23px; height:23px; fill:none; stroke:currentColor;
  stroke-width:1.6; stroke-linejoin:round}
.favmark:hover{color:var(--accent); transform:scale(1.08)}
.favmark.on{color:var(--accent)}
.favmark.on svg{fill:currentColor}
.favmark[hidden]{display:none}
.favmark:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
/* Top right, above the title, and in normal flow rather than absolute so a long
   credit wraps instead of running over the score. The left padding clears the
   star, which is the one thing in here that IS absolute. */
.credit{margin:0 0 2px 0; padding-left:46px; text-align:right;
  font-size:10.5px; font-style:italic; line-height:1.45; color:var(--ink-3)}
.credit:empty{display:none}
#paper{color:var(--ink)}
#paper svg{max-width:100%; height:auto; display:block}
#paper svg path{fill:currentColor}
#paper svg text,#paper svg tspan{fill:currentColor}
#paper .abcjs-highlight,#paper .abcjs-highlight path,#paper .abcjs-highlight text{
  fill:var(--cursor) !important}
/* the playhead is an SVG line INSIDE the score, so it shares the score's
   coordinate system and stays put when the responsive SVG rescales */
#paper svg .playhead{stroke:var(--cursor); stroke-width:2.2; opacity:.92;
  stroke-linecap:round; pointer-events:none}
/* The wash behind the playhead while the strip is held. Low alpha on purpose:
   it has to read as a region at a glance without the notes under it turning
   into a silhouette, so it tints them rather than covering them. */
#paper svg .wake rect{fill:var(--accent); opacity:.17; pointer-events:none}
.empty{color:var(--ink-3); font-size:13px; font-style:italic; padding:44px 0; text-align:center}
#audiohost{position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden}

/* ---------- modals ---------- */
.modal{position:fixed; inset:0; z-index:60; background:rgba(0,0,0,.55);
  display:flex; align-items:center; justify-content:center; padding:20px}
.modal[hidden]{display:none}
.modal-box{background:var(--surface); border:1px solid var(--line); border-radius:var(--radius);
  width:min(880px,100%); max-height:86vh; display:flex; flex-direction:column; overflow:hidden}
.modal-head{display:flex; align-items:center; gap:14px; padding:14px 16px;
  border-bottom:1px solid var(--line)}
.modal-head h2{margin:0; font-family:"Bodoni Moda",Didot,serif; font-weight:400; font-size:22px}
/* The same list glyph the Browse Categories button carries, so the button
   and the dialog it opens are visibly the same thing. Only the Close button
   takes an auto margin -- give one to the favourites card as well and the
   free space splits between them, which is what left it stranded mid-header. */
.modal-head .dirheadicon{flex:0 0 auto; width:22px; height:22px; color:var(--accent); margin-right:-4px}
.modal-head .dirheadicon svg{width:100%; height:100%; display:block}
.modal-head .btn{margin-left:auto}
#spectext{margin:0; padding:18px 20px; overflow:auto; white-space:pre-wrap; word-break:break-word;
  font-family:"IBM Plex Mono",ui-monospace,monospace; font-size:12px; line-height:1.65;
  color:var(--ink-2); tab-size:2}
.dirlist{margin:0; padding:14px; overflow:auto; display:grid; gap:10px;
  grid-template-columns:repeat(auto-fill,minmax(250px,1fr))}
.dircard{text-align:left; background:var(--bg); border:1px solid var(--line);
  border-radius:var(--radius); padding:14px 15px; cursor:pointer; display:flex;
  flex-direction:column; gap:5px; transition:border-color .15s,background .15s}
.dircard:hover{border-color:var(--accent)}
.dircard[aria-current="true"]{border-color:var(--accent); background:var(--accent-soft)}
.dircard .dt{font-weight:600; font-size:16px; display:flex; align-items:center; gap:11px}
.dircard .dicon{flex:0 0 auto; width:34px; height:34px; display:inline-flex;
  align-items:center; justify-content:center; border-radius:var(--radius);
  background:var(--accent-soft); color:var(--accent)}
.dircard .dicon svg{width:22px; height:22px; display:block}
.dircard:hover .dicon{background:var(--accent); color:var(--accent-on)}
.dircard .dn{font-family:"IBM Plex Mono",ui-monospace,monospace; font-size:11.5px; color:var(--ink-3)}

@media (max-width:620px){
  .readout{margin-left:0; width:100%}
  .ctl input[type=range]{width:96px}
}

/* Portrait tablet: the transport wraps to two or three rows, so give the rows
   room and let the song picker own a full line of its own. */
@media (max-width:980px){
  .wrap{padding-block:22px 56px}
  h1{font-size:26px}
  .masthead{gap:9px}
  /* Sized against the Browse button beside it, which at this breakpoint is
     41.6px tall and is what sets the masthead's height. At 1.1 line-height a
     37px title comes to 40.7px, so the name grows to the height of the row it
     sits in without making that row any taller. */
  .masthead h1{font-size:clamp(30px,4.8vw,37px)}
  .btn.browse{padding:9px 13px; font-size:13.5px}
  .count{font-size:13px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
         flex:0 1 auto; min-width:0}
  .picker{gap:8px; flex-wrap:nowrap}
  .picker .nav{flex:0 0 auto; min-width:84px; padding:11px 16px}
  .songbox{flex:1 1 auto; min-width:0}
  .where{flex:0 0 auto}
  .row{flex-wrap:nowrap; gap:8px}
  .play{min-width:86px}
  .keygrp,.octgrp{flex:0 0 auto}
  .keygrp select{min-width:76px}
  .ctl.tempo > span{display:none}
  .ctl input[type=range]{width:92px}
  .ctl output{min-width:46px; font-size:12px}
  #pdf{flex:0 0 auto}
}
/* Between the tablet rules and the phone rules the transport was pinned to one
   line by flex-wrap:nowrap, but its controls stop fitting at about 716px, so the
   PDF button hung off the right and put a horizontal scrollbar on the whole page.
   An overflowing line also zeroes #pdf's auto margin, since auto margins resolve
   to 0 when the free space is negative. Let it wrap again before that happens. */
@media (max-width:760px){ .row{flex-wrap:wrap} }

/* Phone. A single line stops being realistic here, so everything wraps on
   purpose: the masthead breaks after the title, the song dropdown takes a line
   of its own with the transport buttons beneath it, and the score gets the full
   width. Touch targets stay finger-sized. */
@media (max-width:560px){
  .wrap{padding-inline:12px; padding-block:16px 44px}
  .masthead{flex-wrap:wrap; gap:8px 10px; padding-bottom:12px}
  .masthead h1{font-size:25px; flex:1 1 auto; order:1}
  .ctl.theme{order:2; margin-left:auto}
  .btn.browse{order:3; flex:1 1 auto; padding:10px 12px; font-size:14px; text-align:center}
  /* On a phone the two list buttons share the row, so the star drops its word
     and keeps the count. */
  .favmark{top:4px; left:4px; width:40px; height:40px}
  .count{order:5; flex:1 1 100%; margin-left:0; text-align:right; font-size:12.5px}

  .picker{flex-wrap:wrap; gap:8px; margin-top:14px}
  .songbox{order:1; flex:1 1 100%}
  .songbtn{font-size:14.5px}
  .picker .nav{order:2; flex:1 1 0; min-width:0; padding:12px 8px}
  .picker .nav.shuffle{order:3; flex:0 0 auto; min-width:56px}
  .where{order:4; flex:0 0 auto; margin-left:auto}

  .transport{padding:10px; gap:9px}
  .row{flex-wrap:wrap; gap:8px}
  .play{flex:1 1 100%; min-width:0}
  .keygrp{flex:1 1 auto}
  .keygrp select{flex:1 1 auto; min-width:0}
  .ctl.tempo{flex:1 1 auto}
  .ctl.tempo input[type=range]{flex:1 1 auto; width:auto; min-width:0}
  #pdf{flex:0 0 auto}
  .barrow{gap:8px}

  .sheet{padding:14px 8px 18px; margin-top:14px}
  .modal{padding:10px}
  .dirlist{grid-template-columns:1fr}
}
/* Anything driven by a finger gets a 44px-ish target. */
@media (pointer:coarse){
  .btn{padding:11px 16px; font-size:14px}
  .btn.ghost{padding:10px 14px; font-size:13px}
  select{padding:11px 34px 11px 12px; font-size:14px}
  .ctl.theme select{padding:8px 30px 8px 10px; font-size:13px}
  .picker .nav{padding:14px 24px; font-size:22px}
  .bar-strip{height:38px}
  .ctl input[type=range]{height:28px}
  .dircard{padding:16px 17px}
}
/* ---------- give the score the screen on tablets and phones ----------
   Three things were eating the width before the staff even started: the page
   gutter (16px a side), the sheet card's own padding (another 16) and its
   border. Sixty-six pixels of a 768px tablet is nine per cent of the score,
   and a lead sheet is the one thing on the page that actually wants to be
   wide -- more width is more bars per line and fewer line breaks mid-phrase.
   On a desktop the 980px column keeps its margins; below that the gutter goes
   to 1px and the card keeps just enough padding to stop the notation touching
   its own border. Placed last so it beats the narrower breakpoints above. */
@media (max-width:1024px){
  .wrap{padding-inline:1px}
  /* The gutter goes for the score's sake, and the masthead is not the score.
     Put its own back: the title, the button and the theme switch pressed against
     the bezel read as a rendering fault rather than a decision, and nothing in
     that row competes with the notation for width. */
  .masthead{padding-inline:13px}
  /* The song picker gets the same gutter. It is the one row between the
     masthead and the transport with no padding of its own -- the transport is a
     card whose own 13px padding already holds its controls off the edge -- so
     without this the caret and the shuffle button sit against the bezel while
     everything above and below them lines up 13px in. */
  .picker{padding-inline:13px}
  .sheet{padding-left:3px; padding-right:3px}
  /* The star sits absolutely in the corner, so it has to come in with them. */
  .favmark{left:2px}
}

/* ---------- tablet transport: one line, captions on top ----------
   Adding the Link button was what broke it, but the row had been close to the
   edge for a while and a real tablet is worse than it looks here: the
   pointer:coarse block above grows every button's padding by 4-5px a side, so
   the row a desktop browser draws at 768px is not the row a tablet draws.

   The labels were the cheapest thing to move. Sitting beside their controls
   'Key', 'Octave' and 'Tempo' each cost 40-55px of the row's WIDTH, which is
   the dimension that ran out. Above them they cost none, because the row's
   height is set by the Play button either way -- so this buys about 140px for
   two or three pixels of height. Everything else here is just tightening:
   smaller octave steppers, a narrower key select, a shorter slider.

   Not on phones: below 561px the row wraps on purpose and has the width for
   inline labels. */
@media (min-width:561px) and (max-width:1024px){
  .row{gap:7px; align-items:center}
  /* The song button and the two nav buttons flanking it are one control, and
     should read as one height. They did not on a touch screen: the
     pointer:coarse block pads .picker .nav to 14px a side at 22px, which makes
     them 52px tall against the song button's 40. Both get the same explicit
     height and centre their contents in it, rather than each falling into a
     height out of its own padding and line box. */
  .picker .nav,.songbtn{height:40px}
  .picker .nav{min-width:72px; padding:0 16px; font-size:20px;
    display:inline-flex; align-items:center; justify-content:center}
  .picker .nav.shuffle{min-width:50px; padding:0 12px}
  .songbtn{padding-top:0; padding-bottom:0}
  /* Grid, not a wrapping flex row. Wrapping puts the caption on its own line
     but buys no WIDTH, because a flex container is sized as though it did not
     wrap -- the group stays as wide as caption + gap + controls laid out
     inline, which is the whole problem. In a grid the columns are sized by the
     controls, and a caption spanning all of them only widens the group if it is
     wider than the controls it labels. None of these are, so the captions
     become free: the octave stepper group drops from 134px to 90. */
  .keygrp,.octgrp,.ctl.tempo{
    display:grid; justify-content:start; align-items:center; gap:0 5px}
  .keygrp{grid-template-columns:auto}
  .octgrp{grid-template-columns:auto auto auto}
  .ctl.tempo{grid-template-columns:auto auto}
  .keygrp > span,.octgrp > span,.ctl.tempo > span{
    display:block; grid-column:1/-1; margin:0 0 1px;
    font-family:"IBM Plex Mono",ui-monospace,monospace;
    font-size:9.5px; line-height:1.2; letter-spacing:.09em;
    text-transform:uppercase; color:var(--ink-3)}
  /* One height for the key select and the two octave steppers, set explicitly
     rather than fallen into: a select is sized by the UA from its padding and a
     button from its line box, so matching paddings does not match heights.
     The buttons become flex boxes so the chevron centres in the taller box. */
  .keygrp select,.octgrp .btn.step{height:34px}
  .keygrp select{min-width:0; font-size:12.5px; padding:0 25px 0 9px;
    text-align:left; background-position:right 7px center}
  .btn.step{min-width:0; padding:0 10px; font-size:13px; line-height:1;
    display:inline-flex; align-items:center; justify-content:center}
  .octgrp #octnow{min-width:16px; font-size:12px; text-align:center}
  .ctl input[type=range]{width:118px; height:20px}
  .ctl output{min-width:40px; font-size:11.5px}
  /* Play through Tempo hug the left; the two file buttons hug the right. #pdf
     already carries margin-left:auto, but an auto margin resolves to zero when
     the free space is negative -- so on an overflowing row they were simply
     trailing the tempo slider. They sit right again because the row fits again;
     this restates it so the intent is visible where the rest of the row is set. */
  #pdf{margin-left:auto}
  .btn.dl,.btn.share{padding:8px 11px; font-size:12.5px}
  .btn.share{gap:5px}
  .btn.share svg{width:13px; height:13px}
  .play{min-width:78px}
}
@media (prefers-reduced-motion:reduce){*{scroll-behavior:auto !important; transition:none !important}}
@media print{
  .masthead,.picker,.transport,.modal{display:none}
  #paper svg .wake{display:none}
  body{background:#fff} .sheet{border:none; background:#fff; margin:0; padding:0}
  #paper svg .playhead{display:none}
}
