/* Qin Studio: tokens and components, shared by the prototype and the component library.
   Layout idea: a scholar's desk seen from above. The lacquered qin lies across the top of every screen and
   never moves; the score unrolls beneath it like a handscroll past a fixed playhead. Paper and ink carry the
   interface; cinnabar is a seal (identity, credits, the one primary action, the playhead). */
:root{
  --paper:#DADDD4; --paper-2:#CFD2C8; --paper-3:#E2E4DB; --smoke:246 248 252; --smoke-a:.42;
  --ink:#1C1F1B; --ink-2:#4A4F47; --ink-3:#757B71; --rule:#B7BBAE;
  --lacquer:#2B1F19; --lacquer-hi:#4A372C; --silk:#D8C79C; --pearl:#EDE6D2;
  --cinnabar:#B3352B; --on-cinnabar:#FBF3EE; --cinnabar-tint:rgba(179,53,43,.12);
  --jade:#4F8270; --jade-tint:rgba(79,130,112,.16);
  --azurite:#3B5A86; --azurite-tint:rgba(59,90,134,.12);
  --f-da:#E8B64C; --f-shi:#57C2B0; --f-zhong:#EE7E62; --f-ming:#AE92E6;   /* fingers: drawn on the lacquer */
  --fx-da:#9A6C0E; --fx-shi:#1D7F70; --fx-zhong:#B44A2C; --fx-ming:#7457B5;   /* the same fingers as text on paper */
  --scrim:rgba(20,22,19,.42);
  --shadow:0 1px 0 rgba(28,31,27,.06),0 10px 28px -14px rgba(28,31,27,.3);
  --f-display:"Marcellus","Cormorant Garamond",Georgia,serif;
  --f-zh:"LXGW WenKai TC","Kaiti TC","STKaiti","KaiTi","BiauKai",serif;
  --f-body:"Alegreya Sans","Gill Sans","Segoe UI",system-ui,sans-serif;
  --f-data:"IBM Plex Mono",ui-monospace,"SF Mono",Menlo,monospace;
  --gutter:max(16px,env(safe-area-inset-left,0px));
}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){
  --fx-da:#E8B64C; --fx-shi:#57C2B0; --fx-zhong:#EE7E62; --fx-ming:#AE92E6;
  --smoke:196 202 212; --smoke-a:.36; --paper:#141613; --paper-2:#1C1F1B; --paper-3:#23271F; --ink:#E6E6DC; --ink-2:#B4B6AB; --ink-3:#8B8F82; --rule:#343930;
  --lacquer:#2E2119; --lacquer-hi:#55402F; --silk:#CDBB8E; --pearl:#E6DCC2; --cinnabar:#D4493D; --on-cinnabar:#FFF6F1; --cinnabar-tint:rgba(212,73,61,.16);
  --jade:#78AE99; --jade-tint:rgba(120,174,153,.18); --azurite:#7C9DCF; --azurite-tint:rgba(124,157,207,.16); --scrim:rgba(0,0,0,.6);
  --shadow:0 1px 0 rgba(0,0,0,.3),0 12px 30px -12px rgba(0,0,0,.7); color-scheme:dark}}
:root[data-theme="dark"]{
  --fx-da:#E8B64C; --fx-shi:#57C2B0; --fx-zhong:#EE7E62; --fx-ming:#AE92E6;
  --smoke:196 202 212; --smoke-a:.36; --paper:#141613; --paper-2:#1C1F1B; --paper-3:#23271F; --ink:#E6E6DC; --ink-2:#B4B6AB; --ink-3:#8B8F82; --rule:#343930;
  --lacquer:#2E2119; --lacquer-hi:#55402F; --silk:#CDBB8E; --pearl:#E6DCC2; --cinnabar:#D4493D; --on-cinnabar:#FFF6F1; --cinnabar-tint:rgba(212,73,61,.16);
  --jade:#78AE99; --jade-tint:rgba(120,174,153,.18); --azurite:#7C9DCF; --azurite-tint:rgba(124,157,207,.16); --scrim:rgba(0,0,0,.6);
  --shadow:0 1px 0 rgba(0,0,0,.3),0 12px 30px -12px rgba(0,0,0,.7); color-scheme:dark}

*{box-sizing:border-box}
body{background:var(--paper);color:var(--ink);font:16px/1.55 var(--f-body);margin:0;
  padding-left:max(16px,env(safe-area-inset-left,0px));padding-right:max(16px,env(safe-area-inset-right,0px));padding-block:0}
button{font:inherit;color:inherit}
:focus-visible{outline:2px solid var(--cinnabar);outline-offset:2px}
.zh{font-family:var(--f-zh)}
.mono{font-family:var(--f-data);font-variant-numeric:tabular-nums}
.eyebrow{font-family:var(--f-data);font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);margin:0}
.sp{flex:1}
[hidden]{display:none!important}

/* ---- seal, header ---- */
.seal{display:inline-grid;place-items:center;grid-template-rows:1fr 1fr;width:30px;height:30px;padding:3px;background:var(--cinnabar);color:var(--on-cinnabar);
  font:700 12px/.95 var(--f-zh);border-radius:2px;box-shadow:inset 0 0 0 1.5px var(--cinnabar),inset 0 0 0 2.5px var(--on-cinnabar)}
.hdr{display:flex;align-items:center;gap:14px;height:60px;max-width:1280px;margin-inline:auto}
.logo{display:flex;align-items:center;gap:10px;font:20px var(--f-display);background:none;border:0;padding:0;cursor:pointer;color:var(--ink)}
.icon-btn{width:38px;height:38px;display:grid;place-items:center;border:0;background:none;border-radius:2px;color:var(--ink-2);font-size:18px;cursor:pointer}
.icon-btn:hover{background:var(--paper-2);color:var(--ink)}
.credit{display:inline-grid;place-items:center;min-width:28px;height:28px;padding:0 6px;border:1.5px solid var(--cinnabar);color:var(--cinnabar);font:500 13px var(--f-data);border-radius:2px;background:none;cursor:pointer}
.avatar{width:30px;height:30px;border-radius:50%;background:var(--paper-2);border:1px solid var(--rule);display:grid;place-items:center;font-size:12.5px;color:var(--ink-2)}

/* ---- the qin stage (fixed place on every screen) ---- */
.stage{position:relative;background:transparent;margin-inline:calc(-1 * max(16px,env(safe-area-inset-left,0px)));padding:6px max(16px,env(safe-area-inset-left,0px))}
.stage-in{max-width:1240px;margin-inline:auto;position:relative}
.qin-svg{display:block;width:100%;height:auto;aspect-ratio:1000/170}
.listen{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);background:var(--paper-3);color:var(--ink);border:1px solid var(--rule);border-radius:999px;padding:8px 16px;font-size:14px;box-shadow:var(--shadow);cursor:pointer;white-space:nowrap}
.listen:hover{border-color:var(--ink)}

/* ---- buttons, chips, segmented, inputs ---- */
.btn{font:500 15px/1 var(--f-body);border-radius:2px;padding:11px 16px;border:1px solid var(--ink);background:transparent;color:var(--ink);cursor:pointer;display:inline-flex;gap:8px;align-items:center;justify-content:center;white-space:nowrap;min-height:40px}
.btn:hover{background:var(--paper-2)}
.btn.primary{background:var(--cinnabar);border-color:var(--cinnabar);color:var(--on-cinnabar)}
.btn.primary:hover{filter:brightness(1.06);background:var(--cinnabar)}
.btn.quiet{border-color:transparent;color:var(--ink-2);padding-inline:8px}
.btn.small{font-size:13.5px;padding:7px 12px;min-height:34px}
.btn .cost{font:12px var(--f-data);opacity:.85;border-left:1px solid currentColor;padding-left:8px}
.btn[disabled]{opacity:.45;cursor:not-allowed}
.link{background:none;border:0;padding:0;color:var(--ink-2);cursor:pointer;text-decoration:underline;text-decoration-color:var(--rule);text-underline-offset:3px}
.link:hover{color:var(--ink);text-decoration-color:var(--ink)}
.chip{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;padding:3px 9px;border:1px solid var(--rule);border-radius:2px;color:var(--ink-2);white-space:nowrap;background:none}
.chip.jade{border-color:var(--jade);color:var(--jade)}
.chip.az{border-color:var(--azurite);color:var(--azurite)}
.chip.red{border-color:var(--cinnabar);color:var(--cinnabar)}
button.chip{cursor:pointer}
.dot{width:8px;height:8px;border-radius:50%;display:inline-block;flex:none}
.seg{display:inline-flex;border:1px solid var(--rule);border-radius:2px;overflow:hidden}
.seg button{border:0;background:none;padding:6px 11px;font-size:13px;color:var(--ink-2);cursor:pointer}
.seg button.on{background:var(--ink);color:var(--paper)}
.seg button[disabled]{opacity:.4;cursor:not-allowed}
.input,textarea.input,input.input,select.input{width:100%;background:var(--paper-3);border:1px solid var(--rule);border-radius:2px;padding:10px 12px;font:15px/1.45 var(--f-body);color:var(--ink)}
textarea.input{min-height:110px;resize:vertical}
.input:focus{outline:none;border-color:var(--ink)}
.field{display:grid;gap:6px}
.field label{font-size:13px;color:var(--ink-2)}
.range{width:100%;accent-color:var(--ink)}
.play{width:44px;height:44px;border-radius:50%;background:var(--ink);color:var(--paper);display:grid;place-items:center;border:0;flex:none;cursor:pointer;font-size:14px}
.playbig{width:84px;height:84px;border-radius:50%;background:var(--cinnabar);color:var(--on-cinnabar);border:0;font-size:26px;display:grid;place-items:center;flex:none;box-shadow:0 0 0 8px var(--cinnabar-tint);cursor:pointer}
.playsm{width:32px;height:32px;border-radius:50%;border:1px solid var(--ink);background:transparent;display:grid;place-items:center;font-size:10px;flex:none;cursor:pointer;color:var(--ink)}
.pin{display:inline-grid;place-items:center;width:20px;height:20px;background:var(--azurite);color:var(--paper-3);font:500 11px/1 var(--f-data);border-radius:2px}

/* ---- menus, popovers, dialogs, sheets, toast ---- */
.menu{position:absolute;z-index:40;min-width:220px;background:var(--paper-3);border:1px solid var(--rule);box-shadow:var(--shadow);padding:6px 0;display:grid}
.menu button,.menu .mi{display:flex;align-items:center;gap:10px;text-align:left;border:0;background:none;padding:9px 16px;font-size:14.5px;color:var(--ink);cursor:pointer}
.menu button:hover{background:var(--paper-2)}
.menu .sep{height:1px;background:var(--rule);margin:6px 0}
.menu .mh{padding:6px 16px 2px}
.pop{position:absolute;z-index:40;background:var(--paper-3);border:1px solid var(--rule);box-shadow:var(--shadow);padding:16px;display:grid;gap:12px;font-size:14px;min-width:300px}
.pop .row{display:flex;justify-content:space-between;align-items:center;gap:16px}
.pop .row > span:first-child{color:var(--ink-2)}
.scrim{position:fixed;inset:0;background:var(--scrim);z-index:50;display:grid;place-items:center;padding:16px}
.dlg{background:var(--paper);border:1px solid var(--rule);box-shadow:var(--shadow);padding:28px;width:min(560px,100%);max-height:calc(100% - 32px);overflow:auto;display:grid;gap:16px}
.dlg h3{font:400 26px/1.15 var(--f-display);margin:0}
.dlg p{margin:0;color:var(--ink-2)}
.dlg .acts{display:flex;gap:10px;justify-content:flex-end;flex-wrap:wrap}
.sheet{position:fixed;left:0;right:0;bottom:0;z-index:45;background:var(--paper-3);border-top:1px solid var(--rule);box-shadow:0 -14px 30px -18px rgba(0,0,0,.4);border-radius:14px 14px 0 0;padding:10px max(20px,env(safe-area-inset-left,0px)) calc(22px + env(safe-area-inset-bottom,0px));max-width:620px;margin-inline:auto}
.sheet .grab{width:38px;height:4px;border-radius:2px;background:var(--rule);margin:0 auto 14px}
.term-pop{position:absolute;z-index:42;width:290px;background:var(--paper-3);border:1px solid var(--rule);box-shadow:var(--shadow);padding:14px 16px;font-size:14px;line-height:1.45;color:var(--ink-2)}
.term-hd{display:flex;align-items:center;gap:12px;margin-bottom:6px}
.term-hd .c{font:34px/1 var(--f-zh);color:var(--ink)}
.term-hd .p{font-style:italic;color:var(--ink);font-size:17px}
.speak{margin-left:auto;width:34px;height:34px;border-radius:50%;border:1px solid var(--rule);background:transparent;color:var(--ink);display:grid;place-items:center;cursor:pointer;flex:none}
.toast{position:fixed;left:50%;bottom:calc(24px + env(safe-area-inset-bottom,0px));transform:translateX(-50%);z-index:60;background:var(--ink);color:var(--paper);padding:11px 18px;font-size:14.5px;border-radius:2px;box-shadow:var(--shadow);max-width:calc(100% - 32px)}

/* ---- score strip ---- */
.strip{position:relative;overflow:hidden;height:172px;touch-action:pan-y;user-select:none;-webkit-user-select:none;cursor:crosshair}
.strip-track{position:absolute;top:0;bottom:0;left:0;will-change:transform}
.strip-head{position:absolute;top:0;bottom:0;left:30%;width:2px;background:var(--cinnabar);pointer-events:none}
.strip-head::before{content:"";position:absolute;top:0;left:-5px;border:6px solid transparent;border-top-color:var(--cinnabar)}
.jn{position:absolute;top:16px;width:32px;margin-left:-16px;display:grid;grid-template-rows:22px 8px 30px 10px 20px 16px;justify-items:center;cursor:pointer}
.jn .tq{font:14px/22px var(--f-zh);color:var(--ink-2);white-space:nowrap}
.jn .orn{font-weight:400;color:var(--jade);margin-left:1px}
.jn .od{font-size:9px;line-height:8px;letter-spacing:-1px;color:var(--ink)}
.jn .num{font:500 21px/30px var(--f-data);color:var(--ink);position:relative}
.jn .acc{position:absolute;left:-8px;top:-2px;font-size:11px;font-style:normal}
.jn .chord{position:absolute;top:-2px;left:22px;font:12px var(--f-data);color:var(--ink-3)}
.jn .lhs{font:12px/20px var(--f-zh);color:var(--ink-3);white-space:nowrap}
.jn .st{font:10.5px/16px var(--f-zh);color:var(--ink-3)}
.jn.slide .num{color:var(--ink-3);font-size:16px}
.jn.harm .num{color:var(--jade)}
.jn.cur .num,.jn.cur .tq{color:var(--cinnabar)}
.jn.sel{background:var(--azurite-tint);box-shadow:0 0 0 1px var(--azurite)}
.jn [data-term]:hover{text-decoration:underline dotted;text-underline-offset:3px}
.strip-label{position:absolute;bottom:7px;font-size:11.5px;color:var(--ink-3);white-space:nowrap;border-left:1px solid var(--rule);padding-left:6px;max-width:320px;overflow:hidden;text-overflow:ellipsis}
.strip-loop{position:absolute;top:0;bottom:0;background:var(--jade-tint);border-inline:2px solid var(--jade);pointer-events:none}
/* the practice range's ends: grab handles (wider for fingers) */
.strip-loop .h{position:absolute;top:0;bottom:0;width:16px;margin-left:-8px;cursor:ew-resize;pointer-events:auto;touch-action:none}
.strip-loop .h[data-edge=a]{left:0}.strip-loop .h[data-edge=b]{left:100%}
.strip-loop .h::after{content:"";position:absolute;left:5px;top:50%;width:6px;height:28px;margin-top:-14px;border-radius:3px;background:var(--jade)}
@media (pointer:coarse){ .strip-loop .h{width:28px;margin-left:-14px}.strip-loop .h::after{left:11px} }
.scrub .lp .h{position:absolute;top:-5px;width:14px;height:16px;margin-left:-7px;cursor:ew-resize;touch-action:none}
.scrub .lp .h::after{content:"";position:absolute;left:5px;top:0;width:4px;height:16px;border-radius:2px;background:var(--jade)}
.scrub .lp .h[data-edge=a]{left:0}.scrub .lp .h[data-edge=b]{left:100%}
@media (pointer:coarse){ .scrub .lp .h{width:26px;margin-left:-13px}.scrub .lp .h::after{left:11px} }
.strip-sel{position:absolute;top:0;bottom:0;background:var(--azurite-tint);border-inline:1px solid var(--azurite);pointer-events:none}
.strip-pins .pin{position:absolute;top:auto;bottom:0;width:16px;height:16px;font-size:10px;cursor:pointer}
.strip-pins .pin-range{position:absolute;bottom:0;height:3px;background:var(--azurite)}

/* the SVG score */
.sv{display:block}
.sv text{font-family:var(--f-zh)}
.sv .sv-num{font:500 21px var(--f-data);fill:var(--ink);text-anchor:middle}
.sv .sv-num.small{font:italic 500 15px var(--f-data);fill:var(--ink-3)}
.sv .sv-num.rest{fill:var(--ink-3)}
.sv .harm .sv-num{fill:var(--jade)}
.sv .cur .sv-num{fill:var(--cinnabar)}
.sv .sel .sv-num{fill:var(--azurite)}
.sv .sel .sv-hit{fill:var(--azurite-tint)}
.sv .sv-hit{fill:transparent;cursor:pointer}
.sv .sv-rh{font-size:13px;text-anchor:middle;font-weight:700}
.sv .sv-lh{font-size:11.5px;fill:var(--ink-3);text-anchor:middle}
.sv .sv-lh.long{font-size:10px}
.sv .sv-vib{font:700 20px var(--f-body);fill:var(--jade);cursor:help}
.sv .sv-orn{stroke:var(--ink);stroke-width:1.4;fill:none;stroke-linecap:round}
.sv .sv-curve{stroke:var(--ink-3);stroke-width:1.2;fill:none}
.sv .sv-dot{fill:var(--ink)}
.sv .sv-diamond{fill:none;stroke:var(--jade);stroke-width:1.1}
.sv .sv-bar{stroke:var(--rule);stroke-width:1}
.sv .sv-mn{font:10.5px var(--f-data);fill:var(--ink-3)}
.sv .sv-sec-line{stroke:var(--rule);stroke-dasharray:2 3}
.sv .sv-sec{font:11.5px var(--f-body);fill:var(--ink-3)}
.sv-sec.stuck{paint-order:stroke;stroke:var(--paper);stroke-width:5px;stroke-linejoin:round}
.sv .sv-sec{font-family:var(--f-body)}
.sv .sv-mark{font-size:12px;fill:var(--cinnabar);font-weight:700}
.sv .sv-dyn{font:italic 700 15px Georgia,"Times New Roman",serif;fill:var(--ink)}
.strip.staff{height:232px}
/* 五線: the staff, heads, stems and beams (studio.css .sv-* rows carry on below for the fingering) */
:is(.sv,.pst) .st-line,.strip-clef .st-line{stroke:var(--ink-3);stroke-width:.8}
:is(.sv,.pst) .st-ledger{stroke:var(--ink-3);stroke-width:.9}
:is(.sv,.pst) .st-h{fill:var(--ink)}
:is(.sv,.pst) .st-h.open{fill:none;stroke:var(--ink);stroke-width:1.4}
:is(.sv,.pst) .st-stem{stroke:var(--ink);stroke-width:1.1}
:is(.sv,.pst) .st-flag,:is(.sv,.pst) .st-beam,:is(.sv,.pst) .st-tie,:is(.sv,.pst) .st-dot{fill:var(--ink)}
:is(.sv,.pst) .st-gliss{stroke:var(--ink-3);stroke-width:1.2}
.st-acc{fill:none;stroke:var(--ink);stroke-width:1.2;stroke-linecap:butt}.st-acc.sh{stroke-width:1}
.sv .st-acc.sh,.strip-clef .st-acc.sh{stroke-width:1.1}
:is(.sv,.pst) .st-rest{font:22px "Noto Music","Apple Symbols","Segoe UI Symbol",serif;fill:var(--ink);text-anchor:middle}
.strip-clef .st-clef,.pst .st-clef{font:42px "Noto Music","Apple Symbols","Segoe UI Symbol",serif;fill:var(--ink)}
.strip-clef .st-8,.pst .st-8{font:10px var(--f-data);fill:var(--ink);text-anchor:middle}
.sv .st-word{font-size:15px;fill:var(--ink)}
.sv .harm .st-h{fill:var(--jade)}.sv .harm .st-h.open{fill:none;stroke:var(--jade)}
:is(.sv,.pst) .st-h.sl{opacity:.75}
.sv .cur .st-h{fill:var(--cinnabar)}.sv .cur .st-h.open{fill:none;stroke:var(--cinnabar)}.sv .cur .st-stem{stroke:var(--cinnabar)}.sv .cur .st-flag{fill:var(--cinnabar)}
.sv .sel .st-h{fill:var(--azurite)}.sv .sel .st-h.open{fill:none;stroke:var(--azurite)}.sv .sel .st-stem{stroke:var(--azurite)}
.strip-clef{position:absolute;left:0;z-index:2;overflow:hidden;pointer-events:none;background:linear-gradient(to right,var(--paper) 82%,transparent)}
.strip-clef svg{display:block}
.strip-lines{position:absolute;left:0;top:0;pointer-events:none}
.strip-lines .st-line{stroke:var(--ink-3);stroke-width:.8}
.sv .sv-hp{stroke:var(--ink-2);stroke-width:1.1;fill:none}
.sv [data-term]{cursor:help}
/* ---- transport ---- */
.transport{display:flex;align-items:center;gap:18px;min-height:64px;flex-wrap:wrap;padding-block:8px}
.time{font:13px var(--f-data);color:var(--ink-2);white-space:nowrap;font-variant-numeric:tabular-nums}
.scrub{position:relative;flex:1 1 160px;height:20px;cursor:pointer;min-width:120px}
.scrub::before{content:"";position:absolute;left:0;right:0;top:9px;height:2px;background:var(--rule)}
.scrub > i{position:absolute;left:0;top:9px;height:2px;background:var(--ink)}
.scrub > b{z-index:3;position:absolute;top:4px;width:12px;height:12px;border-radius:50%;background:var(--ink);transform:translateX(-6px)}
.scrub .mk{z-index:1;position:absolute;top:2px;width:2px;height:16px;margin-left:-1px;background:var(--ink-3);border:0;padding:0;cursor:pointer}
.scrub .mk:hover{background:var(--cinnabar)}
.scrub .mk span{position:absolute;bottom:calc(100% + 2px);left:0;transform:translateX(-50%);font:11.5px var(--f-zh);color:var(--ink-3);white-space:nowrap;pointer-events:none}
.scrub .mk:hover span{color:var(--ink)}
.scrub{margin-top:14px}
.bar-btn{font:13px var(--f-data);color:var(--ink-2);background:none;border:0;padding:4px 2px;cursor:pointer;white-space:nowrap;text-decoration:underline dotted var(--rule);text-underline-offset:4px}
.seal-svg{display:block}
.scrub .lp{position:absolute;top:7px;height:6px;background:var(--jade-tint);border-inline:2px solid var(--jade)}
.qa{font-size:14px;color:var(--ink-2);white-space:nowrap;background:none;border:0;padding:6px 4px;cursor:pointer}
.qa:hover{color:var(--ink)}

/* ---- notes, steps, tiles, rows ---- */
.note{border-bottom:1px solid var(--rule);padding:12px 0;display:grid;gap:6px;cursor:pointer}
.note .w{display:flex;align-items:center;gap:8px;font:12.5px var(--f-data);color:var(--ink-3)}
.note p{margin:0;font-size:14.5px}
.note.sel{background:var(--azurite-tint);box-shadow:inset 3px 0 0 var(--azurite);padding-left:10px}
.reply{font-size:13px;color:var(--ink-2);border-left:2px solid var(--rule);padding-left:10px}
.steps{display:grid}
.step{display:grid;grid-template-columns:28px 1fr auto;gap:12px;padding:14px 0;border-bottom:1px solid var(--rule);align-items:start}
.step .st{width:20px;height:20px;border-radius:50%;border:1.5px solid var(--ink-3);display:grid;place-items:center;font-size:11px;margin-top:2px}
.step.done .st{background:var(--jade);border-color:var(--jade);color:var(--paper-3)}
.step.now .st{border-color:var(--cinnabar);box-shadow:0 0 0 4px var(--cinnabar-tint)}
.step.now .st::after{content:"";width:8px;height:8px;border-radius:50%;background:var(--cinnabar);animation:pulse 1.2s infinite}
@keyframes pulse{50%{opacity:.3}}
.step b{font-weight:500}
.step .d{font-size:13.5px;color:var(--ink-2)}
.step .t{font:12px var(--f-data);color:var(--ink-3)}
.step.todo{color:var(--ink-3)}
.tiles{display:flex;gap:14px;flex-wrap:wrap;align-items:flex-end}
.tile{margin:0;display:grid;gap:5px;justify-items:center;position:relative;font:12px var(--f-data);color:var(--ink-3)}
.tile .pg{width:64px;height:84px;background:var(--pearl) center/cover no-repeat;border:1px solid var(--rule);display:flex;gap:4px;padding:6px;justify-content:center;writing-mode:vertical-rl;font:8px/1.1 var(--f-zh);color:#3a2f26;overflow:hidden}
.tile.on .pg{outline:2px solid var(--ink);outline-offset:2px}
.tile .x{position:absolute;top:-7px;right:-7px;width:20px;height:20px;border-radius:50%;background:var(--ink);color:var(--paper);border:0;font-size:12px;line-height:1;display:grid;place-items:center;cursor:pointer}
.tile.add .pg{background:transparent;border:1.5px dashed var(--ink-3);writing-mode:horizontal-tb;align-items:center;text-align:center;font:12px/1.2 var(--f-body);color:var(--ink-2);cursor:pointer}
.drop{border:1.5px dashed var(--ink-3);border-radius:2px;padding:18px;background:var(--paper-3);display:grid;gap:12px}
.drop.over{border-color:var(--cinnabar);background:var(--cinnabar-tint)}
.tabs{display:flex;gap:26px;border-bottom:1px solid var(--rule)}
.tabs button{border:0;background:none;padding:10px 0;color:var(--ink-3);font-size:16px;cursor:pointer}
.tabs button.on{color:var(--ink);box-shadow:0 2px 0 var(--cinnabar)}
.row-list .r{display:grid;grid-template-columns:2.2fr 1.2fr .7fr 1fr .9fr;gap:16px;padding:14px 0;border-bottom:1px solid var(--rule);align-items:center;font-size:14.5px;cursor:pointer}
.row-list .r:hover{background:var(--paper-2)}
.row-list .r.h{font:11px var(--f-data);letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);cursor:default;background:none}
.pack{border:1px solid var(--rule);padding:16px;display:grid;gap:4px;background:var(--paper-3);cursor:pointer;text-align:left}
.pack.on{border-color:var(--ink);box-shadow:inset 0 0 0 1px var(--ink)}
.pack .n{font:30px var(--f-display)}

/* ---- piece cards: the selector ---- */
.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,320px),1fr));gap:16px}
/* the home selector: one horizontal strip that scrolls, cards snapping to the left edge */
.shelf-cards .cards{grid-auto-flow:column;grid-template-columns:none;grid-auto-columns:min(300px,82%);overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;scroll-padding-left:2px;padding:4px 2px 12px;scrollbar-width:none;-ms-overflow-style:none}
.shelf-cards .cards::-webkit-scrollbar{display:none}
.shelf-cards .cards > *{scroll-snap-align:start}
.pcard{display:grid;grid-template-columns:auto minmax(0,1fr);gap:14px;text-align:left;background:var(--paper-3);border:1px solid var(--rule);padding:14px 14px 12px 10px;min-height:156px;cursor:pointer;color:var(--ink);font:inherit;transition:border-color .15s,transform .15s,box-shadow .15s}
.pcard:hover{border-color:var(--ink);transform:translateY(-2px);box-shadow:var(--shadow)}
.pcard:focus-visible{outline:2px solid var(--cinnabar);outline-offset:2px}
.pc-v{writing-mode:vertical-rl;font:26px/1.05 var(--f-zh);letter-spacing:.14em;padding:2px 10px 2px 2px;border-right:1px solid var(--rule);color:var(--ink);max-height:160px;overflow:hidden}
.pcard.nov{grid-template-columns:minmax(0,1fr);padding-left:16px}
.pc-b{display:flex;flex-direction:column;gap:6px;min-width:0}
.pc-b .eyebrow{font-size:10.5px;letter-spacing:.1em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pc-t{font:17px/1.2 var(--f-display);text-wrap:balance}
.pc-m{word-break:keep-all;font-size:13px;line-height:1.45;color:var(--ink-2)}
.pc-f{display:flex;align-items:center;gap:8px;margin-top:auto;padding-top:6px;font-size:12.5px;color:var(--ink-3)}
.pc-u{font:12.5px var(--f-data);color:var(--azurite)}
.pcard .playsm{width:28px;height:28px}
.pcard.make{background:transparent;border-style:dashed}
.pcard.make .pc-v{color:var(--cinnabar)}
.p-ver{font-size:13px;color:var(--ink-3);padding:0 8px 12px}
.ver-tbl{display:grid;grid-template-columns:minmax(110px,auto) 1fr;gap:7px 18px;margin:0;font-size:14.5px}
.ver-tbl dt{color:var(--ink-3)}
.ver-tbl dd{margin:0}
@media (max-width:560px){
  .cards{grid-auto-flow:column;grid-template-columns:none;grid-auto-columns:82%;overflow-x:auto;scroll-snap-type:x mandatory;padding-bottom:8px}
  .cards > *{scroll-snap-align:start}
  .lib .cards{grid-auto-flow:row;grid-template-columns:1fr;overflow:visible}
}

/* ---- poem lines ---- */
/* the lyrics: three rows that drift upward, the sung line in the middle; soft at the edges like the sound */
.lyr{--row:50px;position:relative;height:calc(var(--row) * 3);overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none;text-align:center;margin:10px 0 4px;
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 34%,#000 66%,transparent 100%);mask-image:linear-gradient(to bottom,transparent 0,#000 34%,#000 66%,transparent 100%);
  transition:opacity 2.6s ease}
.lyr::-webkit-scrollbar{display:none}
.lyr.gone{opacity:0}
.lyr.browse{-webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 18%,#000 82%,transparent 100%);mask-image:linear-gradient(to bottom,transparent 0,#000 18%,#000 82%,transparent 100%)}
.lyr-in{padding:calc(var(--row) * 3) 16px calc(var(--row) * 1.5)}
.lyr .ln{min-height:var(--row);display:flex;align-items:center;justify-content:center;font:21px/1.5 var(--f-zh);color:var(--ink-2);letter-spacing:.14em;will-change:opacity,filter,transform;transform-origin:center}
.lyr .ln.latin{font:italic 18px/1.4 var(--f-display);letter-spacing:.02em}
.lyr .ln.cur{color:var(--ink);text-shadow:0 0 18px color-mix(in srgb,var(--jade) 35%,transparent)}
.poem rt,.lyr-ov rt{font:italic 11px var(--f-body);letter-spacing:.04em;color:var(--ink-3)}
.poem.no-py rt,.lyr-all.no-py rt{display:none}
.lyr .ln.cur rt{color:var(--jade)}
@media (prefers-reduced-motion:reduce){ .lyr .ln{filter:none!important} }
/* the whole poem over the page: no card, just the words on mist */
.lyr-scrim{background:color-mix(in srgb,var(--paper) 78%,transparent);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);animation:lyrfade .9s ease both}
.lyr-ov.dlg{background:none;border:0;box-shadow:none;text-align:center;justify-items:center;gap:6px;width:min(640px,100%);position:relative;padding:40px 16px}
.lyr-ov .lyr-t{font:30px/1.3 var(--f-zh);letter-spacing:.3em;color:var(--ink)}
.lyr-ov .lyr-e{font:15px var(--f-display);color:var(--ink-3);margin-bottom:22px}
.lyr-ov .lyr-all{display:grid;gap:14px}
.lyr-ov .ln{font:22px/1.6 var(--f-zh);letter-spacing:.14em;color:var(--ink-2);animation:lyrrise 1.6s ease both;transition:color 1.2s ease,text-shadow 1.2s ease}
.lyr-ov .ln.latin{font:italic 19px/1.5 var(--f-display);letter-spacing:.02em}
.lyr-ov .ln.cur{color:var(--ink);text-shadow:0 0 22px color-mix(in srgb,var(--jade) 45%,transparent)}
.lyr-ov .ln.cur rt{color:var(--jade)}
.lyr-x{position:absolute;top:0;right:0;width:40px;height:40px;border:0;background:none;font-size:26px;color:var(--ink-3);cursor:pointer}
.lyr-x:hover{color:var(--ink)}
@keyframes lyrfade{from{opacity:0}}
@keyframes lyrrise{from{opacity:0;filter:blur(6px);transform:translateY(10px)}}
@media (prefers-reduced-motion:reduce){ .lyr-ov .ln,.lyr-scrim{animation:none} }
.no-py rt{display:none}

/* ---- scan (an uploaded jianzi pu page) ---- */
.scan{background:#EFE7D3;border:1px solid var(--rule);position:relative;writing-mode:vertical-rl;font-family:var(--f-zh);color:#2a221b;padding:20px;display:flex;flex-wrap:wrap;gap:4px 18px;align-content:flex-start;font-size:21px;line-height:1.05;letter-spacing:.06em;overflow:hidden}
.scan .box{outline:1.5px solid var(--jade);outline-offset:2px;background:rgba(79,130,112,.08)}
.scan .low{outline:1.5px solid var(--cinnabar);outline-offset:2px;background:rgba(179,53,43,.08)}
.scan .lit{background:var(--cinnabar);color:var(--on-cinnabar);outline:2px solid var(--cinnabar);outline-offset:2px}

/* ---- reference pages ---- */
.ref{display:grid;grid-template-columns:220px minmax(0,1fr);gap:64px;padding:40px 0 64px;max-width:1120px;margin-inline:auto}
.ref-toc{display:grid;gap:9px;align-content:start;font-size:14.5px;position:sticky;top:12px}
.ref-toc button{border:0;background:none;padding:0;text-align:left;color:var(--ink-3);cursor:pointer;font-size:14.5px}
.ref-toc button.on{color:var(--ink);box-shadow:inset 2px 0 0 var(--cinnabar);padding-left:10px;margin-left:-12px}
.art{max-width:720px;min-width:0}
.art h1{font:400 42px/1.08 var(--f-display);margin:0;text-wrap:balance}
.art .lead{font-size:18.5px;color:var(--ink-2);margin:16px 0 8px}
.art h2{font:400 25px/1.2 var(--f-display);margin:38px 0 10px;display:flex;align-items:baseline;gap:12px;scroll-margin-top:12px}
.art h2 .n{font:12px var(--f-data);color:var(--ink-3)}
.art h3{font:400 19px var(--f-display);margin:0 0 8px}
.art p{margin:0 0 14px}
.formula{font:italic 21px Georgia,"Times New Roman",serif;padding:16px 20px;background:var(--paper-2);margin:6px 0 16px;overflow-x:auto}
.ptable{display:grid;grid-template-columns:minmax(150px,220px) minmax(120px,200px) 1fr;font-size:14.5px;border-top:1px solid var(--rule);margin:4px 0 14px}
.ptable > span{padding:8px 10px 8px 0;border-bottom:1px solid var(--rule)}
.ptable > span:nth-child(3n){color:var(--ink-2)}
.tryit{display:flex;align-items:center;gap:18px;flex-wrap:wrap;padding:14px 18px;border:1px solid var(--rule);background:var(--paper-3);font-size:14.5px;margin:4px 0 10px}
.tech-index{display:grid;gap:4px;align-content:start;font-size:14px;color:var(--ink-3)}
.tech-index .grp{font:11px var(--f-data);letter-spacing:.1em;text-transform:uppercase;margin-top:16px}
.tech-index button{border:0;background:none;text-align:left;padding:3px 0;color:var(--ink-3);cursor:pointer;font-size:13.5px}
.tech-index button b{font:400 18px var(--f-zh);color:var(--ink-2);margin-right:8px}
.tech-index button.on{box-shadow:inset 2px 0 0 var(--cinnabar);padding-left:10px;margin-left:-12px;color:var(--ink)}
.tech-index button.on b{color:var(--cinnabar)}
.tech-cols{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:28px;margin-top:24px;font-size:15px}
.demo{display:grid;gap:14px;padding:18px 20px;border:1px solid var(--rule);background:var(--paper-3)}
pre.code{font:13px var(--f-data);background:var(--paper-2);padding:12px 14px;margin:6px 0 8px;overflow-x:auto;white-space:pre}
code{font-family:var(--f-data);font-size:.88em;background:var(--paper-2);padding:1px 5px}

@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}

/* hover or tap on a string: string, hui position, jianpu degree and pitch at that point */
.qin-tip{position:absolute;transform:translate(-50%,calc(-100% - 8px));display:flex;gap:9px;align-items:center;white-space:nowrap;padding:5px 10px;background:var(--ink);color:var(--paper);font-size:13px;line-height:1.2;pointer-events:none;box-shadow:var(--shadow);z-index:3}
.qin-tip .zh{font-family:var(--f-zh);font-size:15px}
.qin-tip .mono{font-family:var(--f-mono,ui-monospace,monospace);font-size:12px;opacity:.75}
.qin-tip .jp{display:inline-flex;flex-direction:column;align-items:center;font:600 15px/1 var(--f-mono,ui-monospace,monospace)}
.qin-tip .jp i{font-style:normal;font-size:7px;line-height:6px;letter-spacing:-1px}
.qin-tip .hp{display:inline-flex;gap:4px;align-items:baseline}
.qin-tip .hd{font:600 14px var(--f-mono,ui-monospace,monospace)}
.qin-tip small{font-size:10.5px;margin-left:3px;opacity:.85}
.qin-tip .hm{display:inline-flex;gap:7px;align-items:center;padding-left:9px;border-left:1px solid color-mix(in srgb,var(--paper) 30%,transparent)}
:is(.sv,.pst) .st-tie{stroke:var(--ink);stroke-width:.5;stroke-linejoin:round}
:is(.sv,.pst) .sv-br,.pst .pst-br{font:700 24px Georgia,"Times New Roman",serif;fill:var(--ink)}
.pbr{font:700 18px Georgia,serif;margin-left:2px}
/* 香: smoke over everything, rising from the score's top edge; only the small source handle takes the pointer */
.incense .smoke{position:fixed;inset:0;width:100vw;height:100vh;pointer-events:none;z-index:9999}
.incense-src{position:fixed;width:28px;height:28px;z-index:9998;cursor:grab;touch-action:none;border-radius:50%;-webkit-tap-highlight-color:transparent}
.incense-src:hover,.incense-src.held{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ink-3) 45%,transparent)}
.incense-src.held{cursor:grabbing}
.incense-src:focus-visible{outline:2px solid var(--azurite);outline-offset:1px}
/* the moon's light at night, where it would be in the sky; and the slow fade between day and night */
.moonglow{position:fixed;inset:0;pointer-events:none;z-index:9997;mix-blend-mode:screen;
  background:radial-gradient(circle at var(--mx,50%) var(--my,8%),rgba(198,212,255,var(--ma,0)) 0,rgba(198,212,255,calc(var(--ma,0) * .45)) 16%,rgba(198,212,255,0) 52%)}
:root.slow-fade::view-transition-old(root),:root.slow-fade::view-transition-new(root){animation-duration:6s;animation-timing-function:ease-in-out}
@media print{ .incense,.moonglow{display:none} }
/* round play buttons: a drawn triangle, 40% of the circle, nudged right so it looks centred (the ▶
   character's size and place vary from font to font) */
.speak,.playsm{font-size:0!important;line-height:0;position:relative}
.speak::before,.playsm::before{content:"";position:absolute;left:50%;top:50%;width:32%;height:36%;transform:translate(-38%,-50%);background:currentColor;clip-path:polygon(0 0,100% 50%,0 100%)}
/* the secret day-and-time panel (Ctrl-D): floating at the foot of the window */
.timepanel{position:fixed;left:50%;bottom:calc(16px + env(safe-area-inset-bottom,0px));transform:translateX(-50%);z-index:10000;display:flex;align-items:center;gap:14px;flex-wrap:wrap;justify-content:center;
  padding:10px 14px;background:color-mix(in srgb,var(--paper-3) 88%,transparent);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border:1px solid var(--rule);border-radius:10px;box-shadow:var(--shadow);font-size:13px;color:var(--ink-2);max-width:calc(100vw - 32px)}
.timepanel label{display:flex;align-items:center;gap:8px}
.timepanel input{width:min(220px,40vw);accent-color:var(--cinnabar)}
.timepanel output{font:12.5px var(--f-data);min-width:48px;color:var(--ink)}
.timepanel button{border:1px solid var(--rule);background:none;border-radius:6px;padding:3px 9px;cursor:pointer;color:var(--ink-2)}
.timepanel [data-x]{border:0;font-size:18px;padding:0 4px}
