  /* ============ Tokens ============ */
  /* The concert-hall palette: the front page's night stage carried into the
     working app. Warm near-black surfaces, cream ink, gold as the one
     interactive accent. --brand-ink is the dark text that sits ON gold. */
  :root{
    --bg:#16110B;
    --surface:#211A12;
    --surface-2:#2A2217;
    --ink:#F2EBDE;
    --muted:#C2B6A2;
    --faint:#93876F;
    --line:#352C1F;
    --line-strong:#4A3F2D;
    --brand:#D9A62E;
    --brand-2:#F0C868;
    --brand-tint:rgba(217,166,46,.14);
    --brand-ink:#251A05;
    --good:#7FC7A4;
    --good-tint:rgba(127,199,164,.14);
    --bad:#E08A72;
    --bad-tint:rgba(224,138,114,.15);
    --amber:#D99A3C;
    --gold:#D9A62E;
    --overlay-ink:#f3ede4;   /* cream text/icons for controls that sit over the dark video overlay */
    --radius:14px;
    --radius-sm:9px;
    --shadow:0 1px 2px rgba(0,0,0,.35), 0 10px 30px -12px rgba(0,0,0,.55);
    --shadow-sm:0 1px 2px rgba(0,0,0,.4);
    --serif:'Fraunces', Georgia, 'Times New Roman', serif;
    --sans:'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    --mono:'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;
    --music:'Noto Music', 'Bravura', serif;
    --dock-h:228px;
  }
  *{box-sizing:border-box;}
  html{scroll-padding-top:76px;}   /* in-page scrolls clear the sticky masthead */
  html,body{margin:0;}
  body{
    font-family:var(--sans);
    background:var(--bg);
    color:var(--ink);
    line-height:1.5;
    -webkit-font-smoothing:antialiased;
    text-rendering:optimizeLegibility;
    padding-bottom:calc(var(--dock-h) + 18px);
  }
  body.dock-collapsed{padding-bottom:64px;}
  button{font-family:inherit;}
  ::selection{background:rgba(217,166,46,.38); color:#FFF8EA;}
  /* Film-grain wash over the whole stage, matching the front page. */
  body::before{
    content:''; position:fixed; inset:0; z-index:0; pointer-events:none; opacity:.05;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.6'/%3E%3C/svg%3E");
  }

  /* ============ Masthead & tabs ============ */
  .masthead{
    background:rgba(22,17,11,.86);
    -webkit-backdrop-filter:blur(12px) saturate(1.15);
    backdrop-filter:blur(12px) saturate(1.15);
    border-bottom:1px solid var(--line);
    position:sticky; top:0; z-index:40;
  }
  .masthead-inner{
    max-width:1040px; margin:0 auto; padding:10px 20px 0;
    display:flex; flex-wrap:wrap; align-items:center; gap:4px 18px;
  }
  .brand{display:flex; align-items:baseline; gap:10px; padding-bottom:8px;}
  .brand h1{
    font-family:var(--serif); font-weight:700; font-size:1.35rem; margin:0; letter-spacing:-.01em;
  }
  .brand h1 a{color:inherit; text-decoration:none;}
  .brand h1 .accent{color:var(--brand-2); font-style:italic;}
  /* The Q-piano brand mark (assets/logo-mark.png), inline before the name;
     vertical-align keeps the h1 baseline (the tagline aligns to it). */
  .brand-mark{height:1.5em; width:auto; vertical-align:-.34em; margin-right:3px;}
  .brand .tagline{font-size:.78rem; color:var(--muted); display:none;}
  @media(min-width:720px){ .brand .tagline{display:inline;} }
  nav.tabs{display:flex; gap:2px; margin-left:auto; overflow-x:auto; max-width:100%;}
  nav.tabs button{
    appearance:none; border:0; background:none; cursor:pointer;
    font:600 .88rem var(--sans); color:var(--muted);
    padding:10px 13px 12px; border-bottom:3px solid transparent;
    white-space:nowrap;
  }
  nav.tabs button:hover{color:var(--ink);}
  nav.tabs button.active{color:var(--brand); border-bottom-color:var(--brand);}

  main{max-width:1040px; margin:0 auto; padding:22px 20px 30px;}
  section.panel{display:none;}
  section.panel.active{display:block;}

  .card{
    background:var(--surface); border:1px solid var(--line);
    border-radius:var(--radius); box-shadow:var(--shadow-sm);
    padding:20px 22px; margin-bottom:18px;
  }
  h2{font-family:var(--serif); font-weight:600; font-size:1.5rem; margin:.2em 0 .5em; letter-spacing:-.01em;}
  h3{font-family:var(--serif); font-weight:600; font-size:1.12rem; margin:1.1em 0 .4em;}
  p{margin:.5em 0;}
  .hint{color:var(--muted); font-size:.88rem;}
  .mono{font-family:var(--mono);}

  .btn{
    appearance:none; cursor:pointer; border-radius:var(--radius-sm);
    border:1px solid var(--line-strong); background:var(--surface);
    color:var(--ink); font:600 .9rem var(--sans); padding:9px 16px;
    transition:background .12s, border-color .12s;
  }
  .btn:hover{background:var(--surface-2);}
  .btn.primary{
    background:linear-gradient(180deg, #EFC868, var(--brand));
    border-color:transparent; color:var(--brand-ink);
    box-shadow:0 6px 18px -8px rgba(217,166,46,.55);
  }
  .btn.primary:hover{background:linear-gradient(180deg, #F6D88E, var(--brand-2));}
  .btn.subtle{border-color:transparent; background:none; color:var(--muted);}
  .btn.subtle:hover{color:var(--ink); background:var(--surface-2);}
  .btn:disabled{opacity:.45; cursor:default;}
  .btn-row{display:flex; flex-wrap:wrap; gap:10px; align-items:center;}

  /* ============ Level chips ============ */
  .level-chips{display:flex; flex-wrap:wrap; gap:8px; margin:10px 0 4px;}
  .chip{
    appearance:none; cursor:pointer; border-radius:999px;
    border:1px solid var(--line-strong); background:var(--surface);
    font:600 .82rem var(--sans); color:var(--ink); padding:6px 13px;
    display:inline-flex; align-items:center; gap:6px;
  }
  .chip:hover{background:var(--surface-2);}
  .chip.sel{background:var(--brand); border-color:var(--brand); color:var(--brand-ink);}
  /* Best-test score coupled onto a practice level chip: the progression signal
     that replaced the old lockout. Tier colours track the star bands, and the
     translucent tints read on a night chip and on the gold selected chip. */
  .chip .chip-score{
    font:700 .7rem var(--mono); padding:1px 7px; border-radius:999px; line-height:1.5;
    background:var(--surface-2); color:var(--muted); border:1px solid var(--line);
  }
  .chip .chip-score.t0{background:var(--bad-tint); color:var(--bad); border-color:transparent;}
  .chip .chip-score.t1{background:var(--good-tint); color:var(--good); border-color:transparent;}
  .chip .chip-score.t2{background:rgba(217,166,46,.16); color:#E8C36A; border-color:transparent;}
  .chip .chip-score.t3{background:var(--gold); color:#3A2C05; border-color:transparent;}
  .chip .chip-score.untested{background:var(--surface); color:var(--faint);}

  /* ============ Study overview: the "Your path" ladder ============
     Rendered at the top of the Study tab (id 'learn'). The in-app Home tab that
     used to host it is gone; the site's front page is the home now. */
  .path-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); gap:12px;}
  .path-card{
    background:var(--surface); border:1px solid var(--line); border-radius:var(--radius);
    padding:14px 16px; box-shadow:var(--shadow-sm); position:relative;
    display:flex; flex-direction:column; gap:4px;
  }
  .path-card .lv{font:600 .72rem var(--sans); color:var(--brand); text-transform:uppercase; letter-spacing:.06em;}
  .path-card .nm{font-family:var(--serif); font-weight:600; font-size:1.05rem;}
  .path-card .desc{font-size:.82rem; color:var(--muted); flex:1;}
  .path-card .stars{color:var(--gold); font-size:.95rem; letter-spacing:2px;}
  .path-card .stars .off{color:var(--line-strong);}
  .path-card .best{font-size:.76rem; color:var(--faint);}
  .path-card .actions{display:flex; gap:6px; margin-top:8px;}
  .path-card .actions .btn{padding:5px 10px; font-size:.78rem;}

  /* ============ Learn ============ */
  /* The Study tab: the "Up next" card, this heading, then the course (the
     lesson list, with "Your Path", the course map, pinned as item 0). */
  .learn-head{margin:24px 2px 12px;}
  .learn-head h2{margin:0 0 .25em;}
  .learn-head .hint{max-width:72ch; margin:0;}
  .learn-layout{display:grid; grid-template-columns:230px 1fr; gap:18px; align-items:start;}

  /* ---- the course map (lesson 0, "Your Path") ---- */
  .cmap-meter{margin:0 0 18px;}
  .cmap-meter .cm-line{display:flex; align-items:baseline; gap:14px; flex-wrap:wrap;}
  .cmap-meter h2{margin:0;}
  .cmap-meter .cm-stats{font:600 .78rem var(--mono); color:var(--brand-2);}
  .cmap-meter .mastery-bar{height:7px; margin:10px 0 10px;}
  .cmap-meter .mastery-bar i{background:linear-gradient(90deg, var(--brand-2), var(--brand));}
  .cmap-act{margin:0 0 6px; border:1px solid var(--line); border-radius:var(--radius);
    overflow:hidden; background:linear-gradient(180deg, rgba(243,237,228,.03), rgba(243,237,228,0));}
  .cmap-act + .cmap-act{margin-top:14px;}
  .cmap-act.done{border-color:rgba(217,166,46,.4);}
  .cmap-act.ahead{opacity:.75;}
  .cmap-act-head{
    display:flex; align-items:center; gap:14px; padding:12px 16px;
    border-bottom:1px solid var(--line); background:rgba(217,166,46,.05);
  }
  .cmap-act.done .cmap-act-head{background:rgba(217,166,46,.12);}
  .ca-num{font:600 .74rem var(--mono); letter-spacing:.14em; text-transform:uppercase;
    color:var(--brand); white-space:nowrap;}
  .ca-name{flex:1; min-width:160px;}
  .ca-name h3{margin:0; font-size:1.05rem;}
  .ca-name p{margin:2px 0 0; font-size:.8rem; color:var(--muted);}
  .ca-band{font:600 .68rem var(--mono); letter-spacing:.1em; text-transform:uppercase;
    color:var(--faint); border:1px solid var(--line-strong); border-radius:999px; padding:3px 10px;}
  .ca-prog{font:600 .82rem var(--mono); color:var(--brand-2); white-space:nowrap;}
  .cmap-nodes{list-style:none; margin:0; padding:6px 0;}
  .cnode{
    position:relative; display:flex; align-items:center; gap:12px;
    padding:9px 16px 9px 18px;
  }
  /* The gold thread: a vertical line through the icons, lit where you've been. */
  .cnode::before{
    content:''; position:absolute; left:31px; top:0; bottom:0; width:2px;
    background:var(--line);
  }
  .cnode.done::before{background:linear-gradient(180deg, var(--brand), var(--brand-2));}
  .cnode:first-child::before{top:50%;}
  .cnode:last-child::before{bottom:50%;}
  .cn-icon{
    position:relative; z-index:1; flex:0 0 auto; width:28px; height:28px;
    display:grid; place-items:center; border-radius:50%;
    background:var(--surface-2); border:1px solid var(--line-strong);
  }
  .cn-icon svg{width:15px; height:15px; stroke:var(--muted); fill:none;
    stroke-width:1.3; stroke-linecap:round; stroke-linejoin:round;}
  .cnode.done .cn-icon{background:rgba(217,166,46,.16); border-color:var(--brand);}
  .cnode.done .cn-icon svg{stroke:var(--brand-2);}
  .cnode.here .cn-icon{
    background:linear-gradient(180deg, #EFC868, var(--brand)); border-color:var(--brand-2);
    box-shadow:0 0 0 0 rgba(240,200,104,.5); animation:herepulse 2.2s ease-out infinite;
  }
  .cnode.here .cn-icon svg{stroke:var(--brand-ink);}
  @keyframes herepulse{
    0%{box-shadow:0 0 0 0 rgba(240,200,104,.5);}
    70%{box-shadow:0 0 0 10px rgba(240,200,104,0);}
    100%{box-shadow:0 0 0 0 rgba(240,200,104,0);}
  }
  .cn-text{flex:1; min-width:0;}
  .cn-text b{font-size:.92rem;}
  .cn-text .stars-inline{margin-left:8px; font-size:.85rem;}
  .cn-sub{display:block; font-size:.75rem; color:var(--faint);}
  .cn-here{color:var(--brand-2); font-weight:600;}
  .cn-actions{display:flex; gap:6px; flex:0 0 auto;}
  .cn-actions .btn{padding:5px 11px; font-size:.78rem;}
  @media(max-width:560px){
    .cnode{flex-wrap:wrap; padding-left:14px;}
    .cn-actions{margin-left:40px;}
  }
  /* Act captions threaded through the lesson list. */
  .ll-act{
    display:block; margin:12px 4px 4px; font:600 .64rem var(--mono);
    letter-spacing:.12em; text-transform:uppercase; color:var(--brand);
  }
  .lesson-list button.ll-map{font-weight:700; color:var(--brand-2);}
  .lesson-list button.ll-map.sel{color:var(--brand);}
  @media(max-width:760px){ .learn-layout{grid-template-columns:1fr;} }
  .lesson-list{position:sticky; top:64px; display:flex; flex-direction:column; gap:4px;}
  @media(max-width:760px){ .lesson-list{position:static; flex-direction:row; flex-wrap:wrap;} }
  .lesson-list button{
    appearance:none; text-align:left; cursor:pointer;
    border:1px solid transparent; border-radius:var(--radius-sm);
    background:none; padding:8px 12px; font:500 .86rem var(--sans); color:var(--muted);
  }
  .lesson-list button:hover{background:var(--surface); color:var(--ink);}
  .lesson-list button.sel{background:var(--surface); border-color:var(--line); color:var(--brand); font-weight:600; box-shadow:var(--shadow-sm);}
  .lesson-body figure{margin:14px 0; text-align:center;}
  .lesson-body figure figcaption{font-size:.8rem; color:var(--muted); margin-top:4px;}
  /* Hearable lesson figures (sound before sight): tap plays the notes or the
     rhythm; the affordance is the caption suffix and the border warming. */
  .lesson-body figure.hear{cursor:pointer;}
  .lesson-body figure.hear:hover .staff-fig{border-color:var(--brand);}
  .lesson-body figure.hear figcaption::after{content:' · tap to hear'; color:var(--faint);}
  #rhythmBpmSeg button small{display:block; font-size:.56rem; line-height:1.1; opacity:.72;
    text-transform:lowercase; letter-spacing:.02em;}
  .lesson-body .staff-fig{display:inline-block; background:var(--surface-2); border:1px solid var(--line); border-radius:var(--radius-sm); padding:8px 12px;}
  .lesson-nav{display:flex; justify-content:space-between; margin-top:18px;}

  /* Featured mnemonic callout: the famous staff acronyms, made the hero of the
     treble-staff and bass-staff lessons. Each initial letter is shown large with
     its word beneath, so the phrase is memorable at a glance. */
  .lesson-body .mnemonic{
    margin:16px 0; padding:16px 20px;
    background:var(--brand-tint); border:1px solid var(--line);
    border-left:4px solid var(--brand); border-radius:var(--radius-sm);
  }
  .mnemonic .mn-label{font:600 .74rem var(--sans); color:var(--brand); text-transform:uppercase; letter-spacing:.07em;}
  .mnemonic .mn-row{display:flex; flex-wrap:wrap; gap:10px 18px; margin:12px 0 2px; align-items:flex-end;}
  .mnemonic .mn-col{display:flex; flex-direction:column; align-items:center; min-width:1.2em;}
  .mnemonic .mn-let{font:700 2rem var(--serif); color:var(--brand); line-height:1;}
  .mnemonic .mn-phrase{margin:8px 0 0; font-family:var(--serif); font-weight:600; font-size:1.08rem; color:var(--muted);}
  .mnemonic .mn-phrase .hl{color:var(--brand); font-weight:700;}
  .mnemonic .mn-spell{display:block; margin-top:9px; font-size:.88rem; color:var(--muted);}
  .mnemonic .mn-spell b{font-family:var(--mono); letter-spacing:.22em; font-size:1.05rem; color:var(--brand);}

  /* Compact featured acronym reference (acro-strip): the same famous phrases, shown
     in a slim card. Used in the treble/bass Learn steps that are not the deep-dive
     Staff lesson, and in the Practice tab keyed to the current level's clef. */
  .acro-strip{
    margin:14px 0 4px; padding:11px 15px;
    background:var(--brand-tint); border:1px solid var(--line);
    border-left:4px solid var(--brand); border-radius:var(--radius-sm);
  }
  .acro-strip .as-clef{font:600 .72rem var(--sans); color:var(--brand); text-transform:uppercase; letter-spacing:.07em;}
  .acro-strip .as-row{display:flex; align-items:baseline; gap:8px 12px; margin-top:7px; flex-wrap:wrap;}
  .acro-strip .as-kind{min-width:50px; font:600 .78rem var(--sans); color:var(--muted);}
  .acro-strip .as-letters{font:700 1.1rem var(--serif); color:var(--brand); letter-spacing:.16em;}
  .acro-strip .as-phrase{font-family:var(--serif); font-weight:600; color:var(--muted); font-size:.95rem;}
  .acro-strip .as-phrase .hl{color:var(--brand);}
  .acro-strip .as-phrase b{font-family:var(--mono); letter-spacing:.18em; color:var(--brand); font-weight:600;}
  /* In Practice the strips (one per clef present) sit side by side, wrapping when narrow. */
  .prac-acro{display:flex; flex-wrap:wrap; gap:12px; margin:8px 0 2px;}
  .prac-acro:empty{display:none;}
  .prac-acro .acro-strip{flex:1 1 300px; margin:0;}

  /* Try-it task widget */
  .tryit{
    border:1px solid var(--line); border-left:4px solid var(--brand);
    background:var(--surface-2); border-radius:var(--radius-sm);
    padding:14px 16px; margin:16px 0;
  }
  .tryit .t-head{font:600 .78rem var(--sans); color:var(--brand); text-transform:uppercase; letter-spacing:.06em; margin-bottom:6px;}
  .tryit .t-row{display:flex; align-items:center; gap:16px; flex-wrap:wrap;}
  .tryit .t-prompt{font-size:1rem; font-weight:600;}
  .tryit .t-progress{display:flex; gap:5px;}
  .tryit .t-dot{width:11px; height:11px; border-radius:50%; background:var(--line-strong);}
  .tryit .t-dot.done{background:var(--good);}
  .tryit .t-dot.cur{background:var(--brand);}
  .tryit .t-fb{font-size:.86rem; min-height:1.3em;}
  .tryit .t-fb.ok{color:var(--good);}
  .tryit .t-fb.no{color:var(--bad);}
  .tryit.finished{border-left-color:var(--good);}

  /* ---- Meet the Keyboard: the guided dock tour (modes/meetkb.js) ----
     A dimming overlay whose spotlight hole glides between live targets (the
     dim IS the hole's huge box-shadow, so the framed control stays clickable
     underneath), plus a floating coach card. The wrapper is pointer-events:
     none and only the card re-enables them, so the tour never blocks the app:
     it directs attention, the real controls do the work. */
  #kbTour{position:fixed; inset:0; z-index:150; pointer-events:none;}
  #kbTour .kbt-hole{
    position:fixed; border-radius:12px;
    box-shadow:0 0 0 200vmax rgba(10,7,2,.52);
    border:2px solid rgba(240,200,104,.85);
    transition:left .38s cubic-bezier(.22,.9,.32,1), top .38s cubic-bezier(.22,.9,.32,1),
               width .38s cubic-bezier(.22,.9,.32,1), height .38s cubic-bezier(.22,.9,.32,1);
  }
  #kbTour .kbt-hole::after{
    content:''; position:absolute; inset:-3px; border-radius:15px;
    animation:kbtpulse 2.1s ease-out infinite;
  }
  @keyframes kbtpulse{
    0%{box-shadow:0 0 0 0 rgba(240,200,104,.5);}
    70%{box-shadow:0 0 0 11px rgba(240,200,104,0);}
    100%{box-shadow:0 0 0 0 rgba(240,200,104,0);}
  }
  #kbTour .kbt-card{
    position:fixed; pointer-events:auto; width:min(370px, 92vw);
    background:linear-gradient(180deg, var(--surface-2), var(--surface));
    border:1px solid var(--line-strong); border-left:4px solid var(--brand);
    border-radius:var(--radius-sm); box-shadow:var(--shadow);
    padding:13px 16px 11px;
    transition:left .38s cubic-bezier(.22,.9,.32,1), top .38s cubic-bezier(.22,.9,.32,1);
  }
  #kbTour .kbt-noanim{transition:none !important; animation:none !important;}
  #kbTour .kbt-top{display:flex; align-items:baseline; gap:10px;}
  #kbTour .kbt-kicker{font:600 .66rem var(--mono); letter-spacing:.13em; text-transform:uppercase; color:var(--brand);}
  #kbTour .kbt-count{margin-left:auto; font:600 .68rem var(--mono); color:var(--faint); white-space:nowrap;}
  #kbTour h3{margin:.45em 0 .3em; font-family:var(--serif); font-size:1.12rem;}
  #kbTour .kbt-text{margin:0; font-size:.85rem; color:var(--muted);}
  #kbTour .kbt-text b{color:var(--ink);}
  #kbTour .kbt-do{margin:9px 0 0; font-size:.86rem; font-weight:600; color:var(--brand-2);}
  #kbTour .kbt-do:empty{display:none;}
  #kbTour .kbt-do::before{content:'▸ '; color:var(--brand);}
  #kbTour .kbt-fb{font-size:.82rem; min-height:1.35em; margin-top:5px;}
  #kbTour .kbt-fb.ok{color:var(--good);}
  #kbTour .kbt-fb.no{color:var(--bad);}
  #kbTour .kbt-row{display:flex; align-items:center; gap:10px; margin-top:8px; flex-wrap:wrap;}
  #kbTour .kbt-row .spacer{flex:1;}
  #kbTour .kbt-dots{display:flex; gap:4px;}
  #kbTour .kbt-dots i{width:7px; height:7px; border-radius:50%; background:var(--line-strong);}
  #kbTour .kbt-dots i.done{background:var(--good);}
  #kbTour .kbt-dots i.cur{background:var(--brand);}
  #kbTour .kbt-skip{
    appearance:none; border:0; background:none; cursor:pointer; padding:2px 4px;
    font:500 .76rem var(--sans); color:var(--faint); text-decoration:underline dotted;
  }
  #kbTour .kbt-skip:hover{color:var(--muted);}
  #kbTour .kbt-complete{border-left-color:var(--good);}
  /* The C trick step: the tour hides every key label but the Cs (the user's
     Labels setting is untouched; the class comes off on step exit) and gently
     pulses each two-black-key group as the landmark to hunt from. The pulse
     yields to .down so a pressed key keeps its normal lit look, and its
     endpoints mirror .bk's resting shadow so the loop is seamless. */
  body.kbt-c-only .wk .klabel:not(.c-mark){display:none;}
  body.kbt-c-only .bk .klabel{display:none;}
  body.kbt-c-only .wk .klabel.c-mark{display:block;}
  /* Both keyframes keep the same shadow-list shape (outset halo, inset ring,
     inset lip) so the list interpolates instead of jumping at 50%; the black
     key also brightens its face, which reads far better on the night stage
     than a halo alone. */
  .bk.kbt-pair:not(.down){animation:kbtpair 1.7s ease-in-out infinite;}
  @keyframes kbtpair{
    0%, 100%{
      box-shadow:0 4px 7px rgba(0,0,0,.5), inset 0 0 0 0 rgba(240,200,104,0), inset 0 -2px 0 rgba(255,244,214,.12);
      filter:brightness(1);
    }
    50%{
      box-shadow:0 0 18px 5px rgba(240,200,104,.65), inset 0 0 0 2px rgba(240,200,104,.7), inset 0 -2px 0 rgba(255,244,214,.3);
      filter:brightness(1.85);
    }
  }
  /* The same pulse for a white key (the middle C step): a gold halo plus an
     inset ring, the hint style made to breathe. */
  .wk.kbt-pair:not(.down){animation:kbtpairw 1.7s ease-in-out infinite;}
  @keyframes kbtpairw{
    0%, 100%{box-shadow:0 0 0 0 rgba(240,200,104,0), inset 0 0 0 0 rgba(217,166,46,0);}
    50%{box-shadow:0 0 18px 4px rgba(240,200,104,.6), inset 0 0 0 3px rgba(217,166,46,.8);}
  }
  @media(prefers-reduced-motion:reduce){
    #kbTour .kbt-hole, #kbTour .kbt-card{transition:none;}
    #kbTour .kbt-hole::after{animation:none;}
    /* No pulse: a steady glow marks the keys instead. */
    .bk.kbt-pair:not(.down){
      animation:none;
      box-shadow:0 0 14px 3px rgba(240,200,104,.5), inset 0 0 0 2px rgba(240,200,104,.6), inset 0 -2px 0 rgba(255,244,214,.22);
      filter:brightness(1.4);
    }
    .wk.kbt-pair:not(.down){
      animation:none;
      box-shadow:0 0 14px 3px rgba(240,200,104,.5), inset 0 0 0 3px rgba(217,166,46,.7);
    }
  }

  /* ============ Practice & Test ============ */
  .quiz-stage{
    display:flex; flex-direction:column; align-items:center; gap:10px;
    padding:8px 0 4px;
  }
  .q-meta{display:flex; gap:18px; flex-wrap:wrap; justify-content:center; font-size:.85rem; color:var(--muted);}
  .q-meta b{color:var(--ink); font-family:var(--mono);}
  .staff-card{
    background:var(--surface-2); border:1px solid var(--line); border-radius:var(--radius);
    padding:10px 18px; box-shadow:var(--shadow-sm);
    transition:box-shadow .15s;
  }
  .staff-card.flash-ok{box-shadow:0 0 0 3px var(--good);}
  .staff-card.flash-no{box-shadow:0 0 0 3px var(--bad); animation:shake .3s;}
  @keyframes shake{
    0%,100%{transform:translateX(0);}
    25%{transform:translateX(-5px);}
    75%{transform:translateX(5px);}
  }
  .q-instr{font-size:.95rem; color:var(--muted);}
  .q-instr b{color:var(--ink);}
  .q-feedback{min-height:1.5em; font-weight:600; font-size:.98rem;}
  .q-feedback.ok{color:var(--good);}
  .q-feedback.no{color:var(--bad);}
  .stat-grid{
    display:grid; grid-template-columns:repeat(auto-fit,minmax(110px,1fr));
    gap:10px; margin-top:14px;
  }
  .stat-box{
    background:var(--surface-2); border:1px solid var(--line); border-radius:var(--radius-sm);
    padding:8px 12px; text-align:center;
  }
  .stat-box .v{font:600 1.25rem var(--mono);}
  .stat-box .l{font-size:.72rem; color:var(--muted); text-transform:uppercase; letter-spacing:.05em;}
  /* Tempo readout under the practice staff: live pace over the last few correct
     notes, the previous bar's pace, and a trend line across recent bars. */
  .tempo-card{
    display:flex; align-items:center; gap:8px 18px; flex-wrap:wrap; justify-content:center;
    width:min(460px,100%); margin:8px auto 0;
    background:var(--surface-2); border:1px solid var(--line); border-radius:var(--radius-sm);
    padding:8px 16px;
  }
  .tempo-now{display:flex; align-items:baseline; gap:5px; white-space:nowrap;}
  .tempo-note{font-family:var(--music); font-size:1.15rem; color:var(--brand); line-height:1;}
  .tempo-val{font:700 1.5rem var(--mono); color:var(--ink);}
  .tempo-unit{font-size:.7rem; color:var(--muted); text-transform:uppercase; letter-spacing:.06em;}
  .tempo-meta{display:flex; flex-direction:column; gap:1px; font-size:.75rem; color:var(--muted); line-height:1.35;}
  .tempo-meta b{font-family:var(--mono); color:var(--ink);}
  .tempo-cap{text-transform:uppercase; letter-spacing:.05em; font-size:.68rem; color:var(--faint);}
  .tempo-dim{color:var(--faint);}
  .tempo-spark{display:flex; align-items:center; margin-left:auto;}
  @media(max-width:520px){ .tempo-spark{margin:0 auto;} }
  .test-report .score-line{font-family:var(--serif); font-size:2.2rem; font-weight:700; margin:.2em 0;}
  .test-report .score-line .of{color:var(--faint); font-size:1.3rem;}
  .pass-banner{
    border-radius:var(--radius-sm); padding:10px 16px; font-weight:600; margin:10px 0;
  }
  .pass-banner.pass{background:var(--good-tint); color:var(--good);}
  .pass-banner.fail{background:var(--bad-tint); color:var(--bad);}
  .miss-list{display:flex; flex-wrap:wrap; gap:8px; margin-top:8px;}
  .miss-pill{
    display:inline-flex; align-items:center; gap:6px;
    border:1px solid var(--line-strong); border-radius:999px; padding:4px 12px;
    font:600 .82rem var(--mono); background:var(--surface-2);
  }
  .miss-pill.bad{border-color:var(--bad); color:var(--bad); background:var(--bad-tint);}

  /* ============ Songs (Intro Songs) ============ */
  /* The songs tab widens the shell: sheet music benefits from every pixel of
     width on large screens (more measures per system, larger engraving). */
  body.tab-songs main, body.tab-songs .masthead-inner, body.tab-songs footer{max-width:1400px;}
  /* The Songs (video/library) tab also widens, for a roomy presentation view. */
  body.tab-video main, body.tab-video .masthead-inner, body.tab-video footer{max-width:1180px;}
  .songs-layout{display:grid; grid-template-columns:250px minmax(0,1fr); gap:18px; align-items:start;}
  .song-side{position:sticky; top:64px; padding:14px 12px 10px;}
  .song-side h2{font-size:1.2rem; margin:.1em 0 .2em; padding:0 8px;}
  .song-side > .hint{margin:0 0 10px; padding:0 8px;}
  .song-list{display:flex; flex-direction:column; gap:4px;}
  .song-list button{
    appearance:none; text-align:left; cursor:pointer;
    border:1px solid transparent; border-radius:var(--radius-sm);
    background:none; padding:7px 10px; font:500 .86rem var(--sans); color:var(--muted);
    display:flex; flex-direction:column; gap:2px;
  }
  .song-list button:hover{background:var(--surface-2); color:var(--ink);}
  .song-list button.sel{background:var(--brand-tint); border-color:var(--brand); color:var(--ink);}
  .song-list button .t{font-weight:600;}
  .song-list button.sel .t{color:var(--brand);}
  .song-list button .s{display:flex; gap:9px; align-items:baseline; font-size:.73rem; color:var(--faint); flex-wrap:wrap;}
  .stars-inline{color:var(--gold); letter-spacing:1.5px;}
  .stars-inline .off{color:var(--line-strong);}
  @media(max-width:840px){
    .songs-layout{grid-template-columns:minmax(0,1fr);}
    .song-side{position:static;}
    .song-list{flex-direction:row; flex-wrap:wrap;}
    .song-list button{flex:1 1 150px;}
  }
  /* Without this, a wide sheet rendered before a resize props the grid track
     open at its old width and the re-measure never sees the new one. */
  .song-main{min-width:0;}
  .song-head{display:flex; align-items:baseline; gap:12px; flex-wrap:wrap;}
  .song-head h2{margin:0;}
  .song-sub{margin:2px 0 10px;}
  .song-meta{justify-content:flex-start; margin:8px 0 2px;}
  #songSheet{overflow-x:auto; padding:4px 0 2px;}
  #songSheet svg{display:block;}
  #songReport .pass-banner{margin:12px 0 4px;}
  #songReport .btn-row{margin:10px 0 4px;}
  /* Sheet note states, in the Studio ribbon's palette: upcoming notes golden,
     played notes fade with the glow removed, the current note brightens like a
     sounding ribbon note under its soft halo column, misses flash red. */
  svg.staff .nh-f{fill:var(--brand-2); filter:drop-shadow(0 0 5px rgba(240,200,104,.45));}
  svg.staff .nh-o{fill:none; stroke:var(--brand-2); stroke-width:1.9; filter:drop-shadow(0 0 5px rgba(240,200,104,.45));}
  svg.staff .ndot{fill:var(--brand-2);}
  svg.staff .bline{stroke:rgba(242,235,222,.5); stroke-width:1.3;}
  svg.staff .bline.thick{stroke-width:3.4;}
  #songSheet .snote .halo{fill:var(--brand); opacity:0; transition:opacity .12s;}
  #songSheet .snote.cur .halo{opacity:.13;}
  #songSheet .snote.cur .nh-f, #songSheet .snote.cur .ndot{fill:#FFE9B8;}
  #songSheet .snote.cur .nh-f{filter:drop-shadow(0 0 9px rgba(240,200,104,.85));}
  #songSheet .snote.cur .nh-o{stroke:#FFE9B8; filter:drop-shadow(0 0 9px rgba(240,200,104,.85));}
  #songSheet .snote.cur .stem{stroke:#FFE9B8;}
  #songSheet .snote.cur .acc{fill:#FFE9B8;}
  #songSheet .snote.played .nh-f, #songSheet .snote.played .ndot{fill:var(--faint);}
  #songSheet .snote.played .nh-f, #songSheet .snote.played .nh-o{filter:none;}
  #songSheet .snote.played .nh-o, #songSheet .snote.played .stem,
  #songSheet .snote.played .ledger{stroke:var(--faint);}
  #songSheet .snote.played .acc{fill:var(--faint);}
  #songSheet .snote.err .halo{fill:var(--bad); opacity:.16;}
  #songSheet .snote.err .nh-f, #songSheet .snote.err .ndot{fill:var(--bad);}
  #songSheet .snote.err .nh-f, #songSheet .snote.err .nh-o{filter:drop-shadow(0 0 7px rgba(224,138,114,.5));}
  #songSheet .snote.err .nh-o, #songSheet .snote.err .stem{stroke:var(--bad);}
  #songSheet .nlabel{display:none;}
  #songSheet.show-names .nlabel{display:inline;}

  /* ============ Video (YouTube study player) ============ */
  /* A custom transport over the YouTube IFrame API: the native controls are
     hidden and every move is driven through seekTo, so scrubbing, frame
     stepping and looping stay under our control. Sized to a comfortable
     reading width rather than sprawling, so it sits above the piano dock. */
  .yt-card{max-width:1120px; margin-left:auto; margin-right:auto;}
  .yt-below{margin-top:14px;}
  .yt-load{display:flex; gap:10px; margin:6px 0 0;}
  .yt-load input{
    flex:1; min-width:0; font:500 .92rem var(--sans); color:var(--ink);
    background:var(--surface); border:1px solid var(--line-strong);
    border-radius:var(--radius-sm); padding:9px 12px;
  }
  .yt-load input:focus{outline:none; border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-tint);}
  .yt-loaderr{color:var(--bad); font-size:.85rem; margin:8px 2px 0;}
  .yt-recent{display:flex; flex-wrap:wrap; gap:6px; margin:10px 0 0;}
  .yt-recent:empty{margin:0;}
  .yt-recent .yt-rlabel{font-size:.76rem; color:var(--faint); align-self:center; margin-right:2px;}
  .yt-recent .yt-chip{
    display:inline-flex; align-items:center; gap:6px; max-width:230px;
    border:1px solid var(--line-strong); border-radius:999px; background:var(--surface);
    color:var(--ink); font:600 .78rem var(--sans); padding:4px 6px 4px 11px; cursor:pointer;
  }
  .yt-recent .yt-chip:hover{background:var(--surface-2);}
  .yt-recent .yt-chip .txt{overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
  .yt-recent .yt-chip .x{
    border:0; background:none; cursor:pointer; color:var(--faint);
    font-size:1rem; line-height:1; padding:0 2px; border-radius:50%;
  }
  .yt-recent .yt-chip .x:hover{color:var(--bad);}

  /* ---- Song library (browsable / searchable / sortable / filterable catalog) ---- */
  .yt-library{margin:14px 0 0;}
  .yt-lib-head{display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:10px;}
  .yt-lib-head h3{margin:0; font-size:1rem;}
  .yt-lib-head .yt-lib-count{font-size:.78rem; color:var(--faint);}
  .yt-lib-head .spacer{flex:1;}
  .yt-lib-toggle{appearance:none; cursor:pointer; border:1px solid var(--line-strong); background:var(--surface);
    color:var(--muted); border-radius:var(--radius-sm); font:600 .78rem var(--sans); padding:5px 11px;}
  .yt-lib-toggle:hover{background:var(--surface-2); color:var(--ink);}
  .yt-lib-body[hidden]{display:none;}
  .yt-lib-bar{display:flex; flex-wrap:wrap; gap:8px 10px; align-items:center; margin-bottom:10px;}
  .yt-lib-search{flex:1; min-width:150px; max-width:340px; font:500 .88rem var(--sans); color:var(--ink);
    background:var(--surface); border:1px solid var(--line-strong); border-radius:var(--radius-sm); padding:8px 11px;}
  .yt-lib-search:focus{outline:none; border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-tint);}
  .yt-lib-bar select{font:600 .8rem var(--sans); color:var(--ink); background:var(--surface);
    border:1px solid var(--line-strong); border-radius:var(--radius-sm); padding:7px 8px;}
  .yt-lib-bar .yt-lbl{margin-left:4px;}
  .yt-lib-filters{display:flex; flex-wrap:wrap; gap:6px; margin-bottom:10px;}
  .yt-lib-chip{appearance:none; cursor:pointer; border:1px solid var(--line-strong); background:var(--surface);
    color:var(--muted); border-radius:999px; font:600 .74rem var(--sans); padding:4px 12px;}
  .yt-lib-chip:hover{background:var(--surface-2); color:var(--ink);}
  .yt-lib-chip.on{background:var(--brand); border-color:var(--brand); color:var(--brand-ink);}
  .yt-lib-grid{display:grid; grid-template-columns:repeat(auto-fill, minmax(210px, 1fr)); gap:10px;}
  .yt-lib-card{position:relative; text-align:left; cursor:pointer; border:1px solid var(--line);
    border-radius:var(--radius-sm); background:var(--surface); padding:11px 12px; display:flex; flex-direction:column; gap:3px;}
  .yt-lib-card:hover{border-color:var(--brand); background:var(--surface-2); box-shadow:var(--shadow-sm);}
  .yt-lib-card .t{font:600 .9rem var(--sans); color:var(--ink); line-height:1.25;}
  .yt-lib-card .a{font-size:.78rem; color:var(--muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
  .yt-lib-card .meta{display:flex; flex-wrap:wrap; gap:5px; margin-top:6px; align-items:center;}
  .yt-lib-badge{font:600 .64rem var(--sans); text-transform:uppercase; letter-spacing:.04em;
    padding:2px 7px; border-radius:999px; background:var(--surface-2); color:var(--muted); border:1px solid var(--line);}
  .yt-lib-badge.diff1{background:rgba(127,199,164,.14); color:#8FD4B2; border-color:rgba(127,199,164,.4);}
  .yt-lib-badge.diff2{background:rgba(122,163,209,.14); color:#9FC0E4; border-color:rgba(122,163,209,.4);}
  .yt-lib-badge.diff3{background:rgba(217,166,46,.14); color:#E4BE62; border-color:rgba(217,166,46,.4);}
  .yt-lib-badge.diff4{background:rgba(224,138,114,.14); color:#EDAA90; border-color:rgba(224,138,114,.4);}
  .yt-lib-badge.diff5{background:rgba(196,124,176,.14); color:#D9A3C9; border-color:rgba(196,124,176,.4);}
  .yt-lib-badge.mine{background:var(--brand-tint); color:var(--brand); border-color:var(--brand);}
  .yt-lib-badge.community{background:rgba(127,199,164,.12); color:#8FD4B2; border-color:rgba(127,199,164,.35);}
  .yt-lib-del{position:absolute; top:6px; right:8px; font:600 .78rem var(--sans); color:var(--faint);
    padding:2px 6px; border-radius:6px; line-height:1;}
  .yt-lib-del:hover{color:#EDAA90; background:var(--surface-2);}
  .yt-lib-dur{font-family:var(--mono); font-size:.72rem; color:var(--faint); margin-left:auto;}
  .yt-lib-empty{color:var(--faint); font-size:.85rem; padding:6px 2px;}

  .yt-stage{margin-top:16px;}
  .yt-load-hint{margin:8px 2px 0; font-size:.8rem;}
  .yt-load-hint .mono{font-family:var(--mono);}
  /* The presentation view: a relative dark box the layout engine fills with the
     chosen sources (video / sheet / roll) placed into a top and a bottom area.
     Inline it has a comfortable height; in fullscreen it fills the screen. All the
     source elements (.yt-frame, #ytFlow, #ytRoll) are positioned into it by JS. */
  .yt-view{
    position:relative; width:100%; height:clamp(330px, 56vh, 760px);
    background:#161311; border-radius:var(--radius-sm); overflow:hidden; box-shadow:var(--shadow-sm);
    touch-action:none;
  }
  .yt-frame{position:absolute; left:0; top:0; width:100%; height:100%; background:#000; overflow:hidden;}
  .yt-frame #ytPlayerHost, .yt-frame iframe{position:absolute; inset:0; width:100%; height:100%; border:0;}
  /* Jog surface over the iframe (a cross-origin iframe gives us no pointer events).
     A grab cursor reads as "drag to scrub"; a plain click plays/pauses. */
  .yt-scrub-overlay{position:absolute; inset:0; z-index:5; cursor:grab; touch-action:none; background:rgba(0,0,0,0);}
  .yt-scrub-overlay.jogging{cursor:grabbing;}
  /* Floating scrub readout: instant feedback while the video re-seeks ~10x/sec. */
  .yt-scrub-hud{
    position:absolute; top:12px; left:50%; transform:translateX(-50%); z-index:7;
    pointer-events:none; display:flex; align-items:baseline; gap:8px;
    padding:6px 13px; border-radius:999px; background:rgba(20,16,12,.82);
    box-shadow:0 2px 12px rgba(0,0,0,.4); white-space:nowrap;
  }
  .yt-scrub-hud .yt-scrub-time{font:700 1.05rem var(--mono); color:var(--overlay-ink); letter-spacing:.02em;}
  .yt-scrub-hud .yt-scrub-delta{font:600 .8rem var(--mono); color:#e6b877;}
  .yt-scrub-hud[hidden]{display:none;}
  /* Opaque cover over the YouTube chrome the IFrame API cannot remove (pre-play
     poster, end-of-video wall). Below the scrub overlay so a click still plays. */
  .yt-curtain{
    position:absolute; inset:0; z-index:4; background:#000; pointer-events:none;
    display:flex; align-items:center; justify-content:center;
  }
  .yt-curtain::after{ content:'\25B6'; color:rgba(255,255,255,.6); font-size:40px; line-height:1; }
  .yt-curtain[hidden]{display:none;}

  /* Area source pickers (top-left) + fullscreen corner button (top-right): overlays
     that float over the view, inline and in fullscreen alike. */
  .yt-fslayout{
    position:absolute; top:8px; left:10px; z-index:22;
    display:flex; align-items:center; gap:12px; flex-wrap:wrap;
    padding:5px 10px; border-radius:9px; background:rgba(18,14,10,.66); border:1px solid rgba(255,255,255,.22);
  }
  .yt-fslayout label{ display:inline-flex; align-items:center; gap:6px; color:var(--overlay-ink); font:600 .76rem var(--sans); }
  .yt-fslayout select{ appearance:auto; cursor:pointer; color:var(--overlay-ink); background:rgba(30,24,18,.96);
    border:1px solid rgba(255,255,255,.35); border-radius:7px; padding:4px 7px; font:600 .8rem var(--sans); }
  .yt-view-corner{ position:absolute; top:8px; right:10px; z-index:23; display:flex; gap:6px; }
  .yt-corner-btn{
    display:inline-flex; align-items:center; justify-content:center; width:38px; height:38px; padding:0;
    border-radius:8px; cursor:pointer; line-height:1; font-size:1.1rem;
    border:1px solid rgba(255,255,255,.3); background:rgba(18,14,10,.55); color:var(--overlay-ink);
  }
  .yt-corner-btn:hover{ background:rgba(46,34,22,.82); border-color:rgba(255,255,255,.6); }
  .yt-corner-btn[hidden]{ display:none; }

  /* Bottom overlay transport: floats over the bottom of the view. */
  .yt-fscontrols{
    position:absolute; left:12px; right:12px; bottom:10px; z-index:21;
    display:flex; align-items:center; gap:8px; flex-wrap:wrap; row-gap:6px;
    padding:6px 8px; border-radius:10px; background:rgba(18,14,10,.5);
  }
  .yt-fsbtn{
    display:inline-flex; align-items:center; justify-content:center; gap:5px;
    appearance:none; cursor:pointer; border-radius:8px; min-height:36px;
    border:1px solid rgba(255,255,255,.3); background:rgba(18,14,10,.62); color:var(--overlay-ink);
    font:600 .88rem var(--sans); padding:8px 12px; line-height:1;
  }
  .yt-fsbtn:hover{ background:rgba(46,34,22,.82); border-color:rgba(255,255,255,.55); }
  .yt-fstime{ color:var(--overlay-ink); font-size:.88rem; opacity:.92; font-family:var(--mono); }
  .yt-fsspace{ flex:1 1 auto; }
  .yt-fslbl{ color:var(--overlay-ink); font-size:.8rem; opacity:.85; }
  .yt-fsseg{ display:inline-flex; gap:4px; }
  .yt-fsseg button{
    appearance:none; cursor:pointer; min-height:32px; padding:5px 9px;
    border:1px solid rgba(255,255,255,.28); background:rgba(18,14,10,.55); color:var(--overlay-ink);
    font:600 .8rem var(--sans); line-height:1; border-radius:7px;
  }
  .yt-fsseg button:hover{ border-color:rgba(255,255,255,.55); }
  /* Selected-area state, shared by the two overlay button styles (identical rule). */
  .yt-fsbtn.on, .yt-fsseg button.sel{ background:var(--brand); border-color:var(--brand); color:var(--brand-ink); }
  /* Whole-song progress bar on the view: a slim clickable/draggable seek bar that
     takes its own row (order:-1) above the transport buttons. Kept short to spare
     vertical space; a taller invisible hit-pad makes it easy to grab. */
  .yt-fsprog{
    order:-1; flex:1 1 100%; position:relative; height:6px; border-radius:3px;
    background:rgba(255,255,255,.2); cursor:pointer; touch-action:none;
  }
  /* Taller invisible hit-pad, biased upward so it never covers the button row below. */
  .yt-fsprog::before{ content:''; position:absolute; left:0; right:0; top:-7px; bottom:-2px; }
  .yt-fsprog-fill{
    position:absolute; left:0; top:0; bottom:0; width:0; border-radius:3px;
    background:var(--brand-2); pointer-events:none;
  }
  .yt-fsprog:hover{ background:rgba(255,255,255,.3); }
  /* Loop indicators on the whole-song bar: an amber band between the loop edges
     (dimmed while the loop is off) and two draggable grips. Positions are set by
     renderLoop against t/dur. */
  .yt-fsprog-loop{
    position:absolute; top:-2px; bottom:-2px; border-radius:4px; pointer-events:none;
    background:rgba(217,154,60,.42);
    border-left:2px solid var(--amber); border-right:2px solid var(--amber);
  }
  .yt-fsprog-loop[hidden]{ display:none; }
  .yt-fsprog-loop.off{ opacity:.45; }
  .yt-fsprog-grip{
    position:absolute; top:50%; left:0; width:14px; height:14px; margin:-7px 0 0 -7px;
    border-radius:50%; background:var(--surface); border:2px solid var(--amber);
    box-shadow:0 1px 4px rgba(0,0,0,.5); cursor:ew-resize; touch-action:none; z-index:2;
  }
  .yt-fsprog-grip:hover, .yt-fsprog-grip.dragging{ background:var(--amber); }
  .yt-fsprog-grip.off{ opacity:.55; }
  .yt-fsprog-grip[hidden]{ display:none; }
  /* Pinned-timestamp ticks on the whole-song bar (click to jump), mirroring the
     detail timeline's pins; positioned by renderPins against t/dur. A wider
     invisible pad makes the thin tick easy to hit. */
  .yt-fsprog-pins{ position:absolute; inset:0; pointer-events:none; }
  .yt-fsprog-pin{
    position:absolute; top:-3px; bottom:-3px; width:2px; margin-left:-1px;
    background:var(--gold); border-radius:1px; pointer-events:auto; cursor:pointer; z-index:1;
  }
  .yt-fsprog-pin::after{ content:''; position:absolute; left:-4px; right:-4px; top:-3px; bottom:-3px; }
  .yt-fsprog-pin:hover{ background:var(--brand-2); box-shadow:0 0 6px rgba(240,200,104,.7); }
  /* Divider between the two areas (draggable); positioned + shown by JS. */
  .yt-fsdivider{
    position:absolute; left:0; right:0; height:12px; z-index:16; cursor:row-resize;
    background:rgba(255,255,255,.10); touch-action:none; display:none;
  }
  .yt-fsdivider:hover{ background:rgba(255,255,255,.2); }
  .yt-fsdivider::after{
    content:''; position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
    width:64px; height:4px; border-radius:2px; background:rgba(255,255,255,.6);
  }
  /* ---- Fullscreen (best viewed landscape on mobile): the view fills the screen
     and everything below it is hidden. The .fs-on class (toggled by JS) drives the
     layout for both the real Fullscreen API and a fixed-overlay fallback (iOS). ---- */
  #ytStage.fs-on{
    position:fixed; inset:0; z-index:9000; margin:0; max-width:none;
    width:100vw; height:100vh; height:100dvh; background:#000;
  }
  #ytStage.fs-on .yt-view{ height:100vh; height:100dvh; border-radius:0; box-shadow:none; }
  #ytStage.fs-on .yt-below{ display:none; }
  .yt-frame-msg{
    position:absolute; inset:0; z-index:6; display:flex; align-items:center; justify-content:center;
    text-align:center; padding:24px; color:var(--overlay-ink); background:rgba(20,16,12,.86);
    font-size:.95rem; line-height:1.5;
  }
  /* The class rule sets display, so the hidden attribute needs an explicit guard. */
  .yt-frame-msg[hidden]{display:none;}

  /* Scrubber */
  .yt-timeline{
    position:relative; height:26px; margin:14px 0 4px; border-radius:7px;
    background:var(--surface-2); border:1px solid var(--line); cursor:pointer;
    touch-action:none; user-select:none; -webkit-user-select:none;
  }
  .yt-timeline:focus-visible{outline:2px solid var(--brand); outline-offset:2px;}
  .yt-buf{position:absolute; left:0; top:0; bottom:0; width:0; background:var(--line-strong); border-radius:6px 0 0 6px;}
  .yt-played{position:absolute; left:0; top:0; bottom:0; width:0; background:var(--brand); opacity:.82; border-radius:6px 0 0 6px;}
  .yt-loopband{
    position:absolute; top:0; bottom:0; background:rgba(200,134,47,.22);
    border-left:2px solid var(--amber); border-right:2px solid var(--amber);
  }
  .yt-pins{position:absolute; inset:0; pointer-events:none;}
  .yt-pins .yt-pin{
    position:absolute; top:2px; bottom:2px; width:2px; margin-left:-1px;
    background:var(--gold); pointer-events:auto; cursor:pointer;
  }
  .yt-pins .yt-pin::after{content:''; position:absolute; left:-4px; right:-4px; top:0; bottom:0;}
  .yt-pins .yt-pin:hover{background:var(--amber); box-shadow:0 0 0 1px var(--amber);}
  .yt-head{
    position:absolute; top:-3px; bottom:-3px; width:3px; margin-left:-1.5px; left:0;
    background:var(--brand-2); border-radius:2px; box-shadow:0 0 0 1px rgba(255,255,255,.5);
  }
  .yt-grip{
    position:absolute; top:50%; width:15px; height:15px; margin:-7.5px 0 0 -7.5px;
    background:var(--surface); border:2px solid var(--amber); border-radius:50%;
    cursor:ew-resize; touch-action:none; box-shadow:var(--shadow-sm); z-index:2;
  }
  .yt-grip:hover, .yt-grip.dragging{background:var(--amber);}
  /* Overview minimap: whole video, with the zoom window as a draggable box. */
  .yt-overview{
    position:relative; height:14px; margin:2px 0 6px; border-radius:5px;
    background:var(--surface-2); border:1px solid var(--line);
    cursor:pointer; touch-action:none; user-select:none; -webkit-user-select:none;
  }
  .yt-overview[hidden]{display:none;}
  .yt-ov-loop{position:absolute; top:0; bottom:0; background:rgba(200,134,47,.25);}
  .yt-ov-loop[hidden]{display:none;}
  .yt-ov-pins{position:absolute; inset:0; pointer-events:none;}
  .yt-ov-pins .yt-ov-pin{position:absolute; top:2px; bottom:2px; width:1px; margin-left:-.5px; background:var(--gold);}
  .yt-ov-win{
    position:absolute; top:-1px; bottom:-1px; left:0; width:100%; min-width:6px;
    background:rgba(217,166,46,.14); border:1px solid var(--brand); border-radius:4px; cursor:grab;
  }
  .yt-ov-win.dragging{cursor:grabbing; background:rgba(217,166,46,.24);}
  .yt-zoomrow{display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin:2px 0; font-size:.82rem;}
  .yt-zoomrow .btn{padding:4px 11px; min-width:34px;}
  .yt-zoomrow .spacer{flex:1;}
  .yt-zoomrow #ytZoomLbl{font-family:var(--mono); color:var(--ink);}
  .yt-zoomhint{color:var(--faint);}
  @media(max-width:560px){ .yt-zoomhint{display:none;} }
  .yt-times{display:flex; justify-content:space-between; align-items:baseline; gap:12px; font-size:.82rem; color:var(--muted);}
  .yt-times .mono{font-family:var(--mono); color:var(--ink);}
  .yt-times #ytBufLbl{margin:0 auto;}

  /* Transport + option rows */
  .yt-transport{display:flex; flex-wrap:wrap; gap:8px; align-items:center; justify-content:center; margin:12px 0 4px;}
  .yt-transport .btn{padding:8px 12px;}
  .yt-play{min-width:56px; font-size:1rem;}
  .yt-row{display:flex; flex-wrap:wrap; gap:8px 10px; align-items:center; margin:12px 0 0; padding-top:12px; border-top:1px solid var(--line);}
  .yt-lbl{font:600 .78rem var(--sans); color:var(--muted); text-transform:uppercase; letter-spacing:.04em;}
  .yt-row .spacer{flex:1;}
  .yt-seg{display:inline-flex; gap:2px; background:var(--surface-2); border:1px solid var(--line); border-radius:999px; padding:2px;}
  .yt-seg button{
    appearance:none; border:0; background:none; cursor:pointer; border-radius:999px;
    font:600 .8rem var(--sans); color:var(--muted); padding:4px 11px;
  }
  .yt-seg button:hover{color:var(--ink);}
  .yt-seg button.sel{background:var(--brand); color:var(--brand-ink);}
  #ytFps{
    font:600 .82rem var(--sans); color:var(--ink); background:var(--surface);
    border:1px solid var(--line-strong); border-radius:var(--radius-sm); padding:6px 8px;
  }
  .yt-loop .btn.on{background:var(--brand-tint); border-color:var(--brand); color:var(--brand);}
  .yt-loopedit{display:inline-flex; flex-wrap:wrap; gap:6px 12px; align-items:center; font-size:.82rem; color:var(--muted);}
  .yt-loopedit[hidden]{display:none;}
  .yt-loopedit .grp{display:inline-flex; align-items:center; gap:5px;}
  .yt-loopedit .grp b{font-family:var(--mono); color:var(--ink); min-width:62px; text-align:right;}
  .yt-nudge{
    appearance:none; cursor:pointer; border:1px solid var(--line-strong); background:var(--surface);
    color:var(--muted); border-radius:6px; font:600 .82rem var(--mono); width:24px; height:24px; line-height:1; padding:0;
  }
  .yt-nudge:hover{color:var(--ink); background:var(--surface-2);}

  .yt-pinrow input{
    flex:1; min-width:120px; max-width:320px; font:500 .86rem var(--sans); color:var(--ink);
    background:var(--surface); border:1px solid var(--line-strong); border-radius:var(--radius-sm); padding:7px 11px;
  }
  .yt-pinrow input:focus{outline:none; border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-tint);}
  .yt-pinlist{display:flex; flex-direction:column; gap:4px; margin:12px 0 0;}
  .yt-pinlist:empty{margin:0;}
  .yt-pinlist .yt-pinrow-item{
    display:flex; align-items:center; gap:10px; padding:6px 4px 6px 10px;
    border:1px solid var(--line); border-radius:var(--radius-sm); background:var(--surface-2);
  }
  .yt-pinlist .yt-pinrow-item .t{font-family:var(--mono); font-weight:600; color:var(--brand); cursor:pointer;}
  .yt-pinlist .yt-pinrow-item .lbl{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:.88rem;}
  .yt-pinlist .yt-pinrow-item .go{padding:4px 10px; font-size:.78rem;}
  .yt-pinlist .yt-pinrow-item .del{
    border:0; background:none; cursor:pointer; color:var(--faint); font-size:1.1rem; line-height:1; padding:0 4px;
  }
  .yt-pinlist .yt-pinrow-item .del:hover{color:var(--bad);}
  .yt-help{margin-top:14px; font-size:.78rem;}
  .yt-help b{color:var(--muted); font-family:var(--mono); font-weight:600;}
  @media(max-width:560px){
    .yt-transport{gap:6px;}
    .yt-transport .btn{padding:8px 9px; font-size:.82rem;}
    .yt-help{display:none;}
  }

  /* ---- Flowing sheet-music ribbon (MusicXML synced to the video) ----
     A wide SVG of the whole score scrolls (via a GPU-composited translateX on
     one group) past a fixed playhead, driven by the same rAF tick as the video.
     The clef sits in a pinned left gutter that never scrolls. */
  .yt-sheet{margin:14px 0 0; padding-top:12px; border-top:1px solid var(--line);}
  .yt-sheet-head{display:flex; flex-wrap:wrap; gap:8px 12px; align-items:center; margin-bottom:8px;}
  .yt-sheet-head .yt-lbl{margin-right:2px;}
  .yt-sheet-status{font-size:.8rem; color:var(--muted); font-family:var(--mono);}
  .yt-sheet-status[hidden]{display:none;}
  .yt-audio-src{font-size:.75rem; color:var(--muted); font-family:var(--mono); white-space:nowrap;}
  .yt-audio-src[hidden]{display:none;}
  /* Audio-output picker: what the video tab plays (YouTube audio / local synth / MIDI out). */
  .yt-audioout{display:inline-flex; align-items:center; gap:6px;}
  .yt-audioout[hidden]{display:none;}
  .yt-audioout select{
    font:600 .82rem var(--sans); color:var(--ink); background:var(--surface);
    border:1px solid var(--line-strong); border-radius:var(--radius-sm); padding:6px 8px;
  }
  .yt-audio-note{margin:0 0 8px; font-size:.8rem;}
  .yt-audio-note[hidden]{display:none;}
  .yt-flow{
    position:relative; overflow:hidden; min-height:88px; background:var(--surface);
    border:1px solid var(--line-strong); border-radius:var(--radius-sm);
    /* none (not pan-y) so two-finger pinch and wheel drive zoom instead of the page. */
    touch-action:none; user-select:none; -webkit-user-select:none; cursor:grab;
  }
  .yt-flow[hidden]{display:none;}
  .yt-flow-scroll{position:absolute; top:0; left:0; will-change:transform; transform:translateZ(0);}
  /* ---- gutter edge fade ----
     Scrolled glyphs (barlines, bar numbers, anchors, notes) dissolve as they
     approach the pinned clef gutter instead of hard-clipping under its opaque
     edge. It is a STATIC mask on this wrapper, not a per-glyph opacity written
     from the paint loop: the wrapper never moves, so the mask is set once and
     the layer inside it stays a pure composited translate. (The per-frame
     version repainted and re-rastered the ribbon on every scroll step, which is
     what made the sheet stutter once notes started reaching the gutter.) The
     staff lines and the waveform live in the sibling, unmasked layer, so they
     still run into the gutter at full strength.
     The ramp reaches alpha 0 at --gutter-edge = the gutter width (GUTTER_W, 74)
     plus a shift, so a glyph's left-reaching parts (accidentals, ledgers) are
     gone before they could be seen sliding under the edge. */
  .yt-flow-fade{
    position:absolute; inset:0; z-index:1;
    --gutter-edge:94px; --fade-w:110px;
    -webkit-mask-image:linear-gradient(90deg, transparent 0 var(--gutter-edge), #000 calc(var(--gutter-edge) + var(--fade-w)));
    mask-image:linear-gradient(90deg, transparent 0 var(--gutter-edge), #000 calc(var(--gutter-edge) + var(--fade-w)));
    /* The masked layer is far wider than this box; without no-repeat the ramp
       would tile across it. Everything past the box is clipped by .yt-flow
       either way, so this only keeps the compositor's job simple. */
    -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  }
  .yt-flow-gutter{position:absolute; top:0; left:0; z-index:3; background:var(--surface);
    box-shadow:6px 0 8px -6px rgba(36,31,26,.28); pointer-events:none;}
  /* The playhead matches the front page's sheet preview: a slim gold line that
     fades out and thins toward both ends, wrapped in a soft glow (no hard ring). */
  .yt-flow-head{position:absolute; top:0; bottom:0; width:2px; margin-left:-1px; z-index:4;
    background:linear-gradient(180deg, transparent, var(--brand-2) 16% 84%, transparent);
    box-shadow:0 0 16px rgba(240,200,104,.75); pointer-events:none;}
  .yt-flow-msg{position:absolute; inset:0; z-index:5; display:flex; align-items:center;
    justify-content:center; text-align:center; padding:16px; color:var(--muted); font-size:.9rem;}
  .yt-flow-msg[hidden]{display:none;}
  /* Embedded zoom control, tucked into the top-right corner of the sheet view. */
  .yt-flow-zoom{position:absolute; top:6px; right:6px; z-index:6; display:inline-flex; gap:4px;}
  .yt-flow-zoom button{
    appearance:none; cursor:pointer; width:28px; height:28px; padding:0; line-height:1;
    border:1px solid var(--line-strong); border-radius:7px; background:rgba(22,17,11,.85);
    color:var(--ink); font:600 1rem var(--sans); box-shadow:var(--shadow-sm);
    display:inline-flex; align-items:center; justify-content:center;
  }
  .yt-flow-zoom button:hover{background:rgba(22,17,11,.97); border-color:var(--brand);}
  .yt-flow-zoom button:disabled{opacity:.4; cursor:default;}
  .yt-flow.arming{cursor:copy;}
  .yt-flow.arming .rb-note{cursor:copy;}
  .yt-flow.jogging{cursor:grabbing;}
  /* Empty sheet shows the "grab to scrub" hand; a note shows the pointing-finger
     hand to signal a different action (click plays the note, no seek/pause). A
     drag anywhere scrubs (grabbing); sync-point arming switches to the copy cursor. */
  .rb-note{cursor:pointer;}
  .yt-flow.jogging .rb-note{cursor:grabbing;}
  /* Hovering a note highlights it, so it is clear a click will play it. The base
     notes are already gold, so hover steps up to the bright tint. */
  .yt-flow:not(.jogging):not(.arming) .rb-note:hover .rb-head{fill:#FFE9B8;}
  .yt-flow:not(.jogging):not(.arming) .rb-note:hover .rb-stem,
  .yt-flow:not(.jogging):not(.arming) .rb-note:hover .rb-ledger{stroke:#FFE9B8;}
  .yt-flow:not(.jogging):not(.arming) .rb-note:hover .rb-acc{fill:#FFE9B8;}
  /* Ribbon SVG glyphs (own classes, independent of svg.staff). The look mirrors
     the front page's reading-demo staff: staff furniture softened to light-gray
     cream (barlines keep a touch more weight, the clef a soft .82 cream), and the
     notes GOLDEN (gold-2 heads/stems/accidentals with a very slight diffuse glow
     on the head). Sounding/hover notes brighten to #FFE9B8 with a stronger glow;
     past notes dim to faint and drop the glow. */
  .rb-svg, .rb-gutter-svg{display:block;}
  .rb-sline{stroke:rgba(242,235,222,.32); stroke-width:1.1;}
  .rb-bar{stroke:rgba(242,235,222,.5); stroke-width:1.3;}
  .rb-ledger{stroke:rgba(242,235,222,.6); stroke-width:1.3;}
  .rb-stem{stroke:var(--brand-2); stroke-width:1.5;}
  .rb-head{fill:var(--brand-2);}
  /* The head's diffuse glow: a painted radial gradient behind each head rather
     than a per-head blur filter, which costs a render surface per note and made
     every fresh scroll tile expensive to rasterize. */
  .rb-glow-in{stop-color:var(--brand-2); stop-opacity:.34;}
  .rb-glow-mid{stop-color:var(--brand-2); stop-opacity:.16;}
  .rb-glow-out{stop-color:var(--brand-2); stop-opacity:0;}
  .rb-halo{pointer-events:none;}
  .rb-acc{font-family:var(--music); fill:var(--brand-2);}
  .rb-clef{font-family:var(--music); fill:rgba(242,235,222,.82);}
  .rb-note.past .rb-head{fill:var(--faint);}
  .rb-note.past .rb-halo{display:none;}
  .rb-note.past .rb-stem, .rb-note.past .rb-ledger{stroke:var(--faint);}
  .rb-note.past .rb-acc{fill:var(--faint);}
  /* Only the handful of heads sounding right now carry a real blur filter: they
     are re-rastered on the class change anyway, and the brighter bloom is the
     point of the highlight. */
  .rb-note.sounding .rb-head{fill:#FFE9B8; filter:drop-shadow(0 0 9px rgba(240,200,104,.85));}
  .rb-note.sounding .rb-stem, .rb-note.sounding .rb-ledger{stroke:#FFE9B8;}
  .rb-note.sounding .rb-acc{fill:#FFE9B8;}
  .rb-anchor{stroke:var(--good); stroke-width:1.5; stroke-dasharray:3 3;}
  .rb-wave{fill:var(--amber); opacity:.17;}
  /* Bar numbers ride above the top staff; a paper-coloured halo keeps them legible
     over staff lines, notes and the waveform. The time signature lives in the
     pinned gutter, so it needs no halo. */
  .rb-barnum{font:600 10px var(--mono); fill:var(--muted); paint-order:stroke;
    stroke:var(--surface); stroke-width:3px; stroke-linejoin:round;}
  .rb-time{font-family:Georgia, 'Times New Roman', serif; font-weight:700; fill:rgba(242,235,222,.82);}
  .yt-sheet-controls .btn.capturing{background:var(--bad-tint); border-color:var(--bad); color:var(--bad);}
  .yt-sheet-controls{display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin:10px 0 0;}
  /* The class rule sets display, so the hidden attribute needs an explicit guard. */
  .yt-sheet-controls[hidden]{display:none;}
  .yt-sheet-controls .btn{padding:6px 11px; font-size:.82rem;}
  .yt-sheet-controls .btn.on{background:var(--brand-tint); border-color:var(--brand); color:var(--brand);}
  .yt-sheet-controls .spacer{flex:1;}
  .yt-sheet-controls .yt-zoomtip{opacity:.8;}
  .yt-audio-offset{display:inline-flex; align-items:center; gap:6px; flex-wrap:wrap;}
  .yt-audio-offset[hidden]{display:none;}
  .yt-audio-offset .yt-lbl{margin-right:2px;}
  #ytOffVal{min-width:54px; text-align:center; font-family:var(--mono);}
  .yt-sheet-hint{margin:8px 0 0; font-size:.78rem; color:var(--faint);}
  .yt-sheet-load{display:inline-flex; align-items:center; gap:8px;}
  /* Sync-point list header (collapsible). */
  .yt-synchead{display:flex; align-items:center; gap:10px; margin:10px 0 0;}
  .yt-synchead[hidden]{display:none;}
  .yt-synchead .hint{font-size:.78rem;}
  .yt-pinlist.collapsed{display:none;}
  @media(max-width:560px){ .yt-sheet-hint{display:none;} }

  /* Piano roll (falling notes): a source placed into an area of the view. The
     canvas fills whatever box the layout engine gives it. Dark so bars pop. */
  .yt-roll{position:absolute; overflow:hidden;}
  .yt-roll[hidden]{display:none;}
  .yt-roll-canvas{
    display:block; width:100%; height:100%;
    background:#161311; touch-action:none; cursor:grab;
  }
  /* Over a key on the roll's keyboard strip: the pointing-finger hand signals a
     different action (a click plays that key). A drag still scrubs (grabbing). */
  .yt-roll-canvas.overkey{cursor:pointer;}
  .yt-roll-canvas.jogging{cursor:grabbing;}

  /* Keyboard-area selection overlay (drag a rectangle over the keys). Sits above
     the scrub overlay (z5) so it captures the drag while arming. */
  .yt-kbsel{position:absolute; inset:0; z-index:8; cursor:crosshair; touch-action:none;
    background:rgba(20,16,12,.34); user-select:none; -webkit-user-select:none;}
  .yt-kbsel[hidden]{display:none;}
  .yt-kbbox{position:absolute; box-sizing:border-box; border:2px solid var(--brand-2);
    background:rgba(230,184,119,.22); box-shadow:0 0 0 9999px rgba(20,16,12,.34); pointer-events:none;}
  .yt-kbbox[hidden]{display:none;}
  .yt-kbsel-hint{position:absolute; top:10px; left:50%; transform:translateX(-50%);
    padding:6px 13px; border-radius:999px; background:rgba(20,16,12,.82); color:var(--overlay-ink);
    font:600 .82rem var(--sans); white-space:nowrap; pointer-events:none;}
  /* Song project: metadata, keyboard-area marker, and save/load. */
  .yt-project{margin-top:14px; padding:14px; border:1px solid var(--line); border-radius:var(--radius-sm); background:var(--surface);}
  .yt-proj-head{display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:12px;}
  .yt-proj-head .spacer{flex:1;}
  .yt-meta-grid{display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:10px; margin-bottom:10px;}
  .yt-meta-grid label{display:flex; flex-direction:column; gap:4px; font:600 .72rem var(--sans);
    color:var(--muted); text-transform:uppercase; letter-spacing:.04em;}
  .yt-meta-grid label.wide{grid-column:1 / -1;}
  .yt-meta-grid input{font:400 .92rem var(--sans); color:var(--ink); padding:8px 10px;
    border:1px solid var(--line-strong); border-radius:var(--radius-sm); background:var(--bg); text-transform:none; letter-spacing:normal;}
  .yt-meta-grid input:focus{outline:none; border-color:var(--brand); box-shadow:0 0 0 2px var(--brand-tint);}
  .yt-kbrow{display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-top:4px;}
  .yt-kbrow .hint{flex:1; min-width:160px;}
  #ytKbSelect.on{background:var(--brand-tint); border-color:var(--brand); color:var(--brand);}
  /* Make-sheet-from-video (PianoVision) controls */
  .yt-pvrow{margin-top:10px; padding-top:10px; border-top:1px dashed var(--line);}
  .yt-pvrow[hidden]{display:none;}
  .yt-pvhead{display:flex; align-items:center; gap:8px; flex-wrap:wrap;}
  .yt-pvopts{display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:8px 0 0;}
  .yt-pvopts label{display:inline-flex; align-items:center; gap:5px; font-size:.82rem; color:var(--muted);}
  .yt-pvopts select, .yt-pvopts input[type=number]{padding:4px 6px; font-size:.82rem;}
  .yt-pvopts input[type=number]{width:66px;}
  .yt-pv-oct{display:inline-flex; align-items:center; gap:4px; font-size:.82rem; color:var(--muted);}
  .yt-pv-oct .btn{padding:2px 9px;}
  .yt-pvrow .hint{display:block; margin-top:6px;}
  .yt-pv-status{align-self:center;}
  .yt-pv-status[hidden]{display:none;}
  #ytPvGen.busy{background:var(--bad-tint); border-color:var(--bad); color:var(--bad);}
  /* Live progress while transcribing, so a long analysis never looks frozen:
     a spinner (proves liveness), a "step X of N" label, a moving bar and a
     live detail (frame k/N, or playback mm:ss / mm:ss). */
  .yt-pvprog{margin:10px 0 2px;}
  .yt-pvprog[hidden]{display:none;}
  .yt-pvprog-row{display:flex; align-items:center; gap:8px; flex-wrap:wrap; font-size:.82rem; margin-bottom:6px;}
  .yt-pvprog-live{display:inline-flex; align-items:center; gap:8px;}
  .yt-pvprog-spin{width:13px; height:13px; flex:none; border-radius:50%;
    border:2px solid var(--line-strong); border-top-color:var(--brand); animation:pvspin .7s linear infinite;}
  .yt-pvprog-step{font-weight:700; color:var(--brand); white-space:nowrap;}
  .yt-pvprog-label{color:var(--ink);}
  .yt-pvprog-detail{color:var(--faint); font-size:.78rem; margin-left:auto;}
  .yt-pvprog-pct{font-weight:700; color:var(--ink); min-width:2.8em; text-align:right;}
  .yt-pvprog-track{position:relative; height:8px; border-radius:999px; overflow:hidden;
    background:var(--surface-2); border:1px solid var(--line);}
  .yt-pvprog-bar{position:absolute; top:0; bottom:0; left:0; width:0;
    border-radius:999px; background:linear-gradient(90deg, var(--brand), var(--brand-2)); transition:width .18s ease;}
  .yt-pvprog.indet .yt-pvprog-bar{width:34%; transition:none; animation:pvslide 1.05s ease-in-out infinite;}
  .yt-pvprog.indet .yt-pvprog-pct{visibility:hidden;}
  @keyframes pvspin{to{transform:rotate(360deg);}}
  @keyframes pvslide{0%{left:-34%;}100%{left:100%;}}
  @media(prefers-reduced-motion:reduce){
    .yt-pvprog-spin{animation:none;}
    .yt-pvprog.indet .yt-pvprog-bar{animation:none; left:0; width:100%; opacity:.5;}
  }
  @media(max-width:560px){ .yt-meta-grid{grid-template-columns:1fr;} }

  /* ============ Ranks ============ */
  table.ranks{width:100%; border-collapse:collapse; font-size:.9rem;}
  table.ranks th, table.ranks td{padding:8px 10px; text-align:left; border-bottom:1px solid var(--line);}
  table.ranks th{font:600 .72rem var(--sans); color:var(--muted); text-transform:uppercase; letter-spacing:.05em;}
  table.ranks td.stars{color:var(--gold); letter-spacing:2px;}
  table.ranks td.stars .off{color:var(--line-strong);}
  .rating-line{display:flex; align-items:baseline; gap:12px; flex-wrap:wrap;}
  .rating-line .big{font-family:var(--serif); font-size:2rem; font-weight:700; color:var(--brand);}
  .history-list{list-style:none; margin:8px 0 0; padding:0;}
  .history-list li{
    display:flex; gap:14px; align-items:baseline; flex-wrap:wrap;
    padding:8px 4px; border-bottom:1px solid var(--line); font-size:.88rem;
  }
  .history-list li .when{color:var(--faint); font-size:.78rem; margin-left:auto;}
  .history-list li .sc{font-family:var(--mono); font-weight:600;}
  .history-list li .sc.pass{color:var(--good);}
  .history-list li .sc.fail{color:var(--bad);}

  /* ============ Free play ============ */
  .play-stage{display:flex; flex-direction:column; align-items:center; gap:12px;}
  .play-note-name{font-family:var(--serif); font-size:2rem; font-weight:700; min-height:1.3em; color:var(--brand);}

  /* ============ Piano dock ============ */
  #dock{
    position:fixed; left:0; right:0; bottom:0; z-index:60;
    background:var(--surface); border-top:1px solid var(--line-strong);
    box-shadow:0 -14px 36px -16px rgba(0,0,0,.75);
  }
  .dock-bar{
    display:flex; align-items:center; gap:10px;
    padding:6px 14px; border-bottom:1px solid var(--line);
    font-size:.78rem; color:var(--muted);
  }
  .dock-bar .dock-title{font:600 .78rem var(--sans); color:var(--ink);}
  .dock-bar .spacer{flex:1;}
  .dock-bar button{
    appearance:none; border:1px solid var(--line-strong); background:var(--surface);
    border-radius:6px; cursor:pointer; font:600 .74rem var(--sans); color:var(--muted);
    padding:3px 9px;
  }
  .dock-bar button:hover{color:var(--ink); background:var(--surface-2);}
  .dock-bar button.on{background:var(--brand-tint); border-color:var(--brand); color:var(--brand);}
  /* Input / Output selectors: two grouped dropdowns replacing the old MIDI, Mic,
     Sound and Piano buttons. */
  .dock-bar .io-group{display:inline-flex; align-items:center; gap:5px;}
  .dock-bar .io-lab{font:600 .72rem var(--sans); color:var(--ink);}
  .dock-bar select{
    appearance:auto; border:1px solid var(--line-strong); background:var(--surface);
    border-radius:6px; cursor:pointer; font:600 .74rem var(--sans); color:var(--ink);
    padding:3px 6px;
  }
  .dock-bar select:hover{background:var(--surface-2);}
  .dock-bar .io-stat{
    font:600 .7rem var(--mono); color:var(--brand);
    max-width:150px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  .dock-bar .io-stat:empty{display:none;}
  @media(max-width:640px){
    #dockHint{display:none;}   /* phones: keep the dock compact */
    .dock-bar{padding:5px 10px;}
  }
  /* Keyboard navigator: octave buttons + a draggable minimap of the full range. */
  .dock-nav{
    display:flex; align-items:stretch; gap:8px;
    padding:6px 10px 5px; border-bottom:1px solid var(--line);
  }
  .oct-btn{
    appearance:none; cursor:pointer; border:1px solid var(--line-strong);
    background:var(--surface); border-radius:7px; color:var(--muted);
    font:600 .8rem var(--sans); padding:0 13px; min-height:30px;
    flex:0 0 auto; touch-action:manipulation;
  }
  .oct-btn:hover{color:var(--ink); background:var(--surface-2);}
  .oct-btn:active{background:var(--brand-tint);}
  #miniMap{
    position:relative; flex:1; min-width:0; height:30px;
    background:var(--surface-2); border:1px solid var(--line);
    border-radius:7px; overflow:hidden;
    cursor:grab; touch-action:none; user-select:none; -webkit-user-select:none;
  }
  #miniMap.dragging{cursor:grabbing;}
  #miniKeys{position:absolute; inset:0;}
  #miniKeys .mm-w{position:absolute; top:0; bottom:0; border-right:1px solid var(--line);}
  #miniKeys .mm-b{position:absolute; top:0; height:55%; background:#120E08; border-radius:0 0 2px 2px;}
  #miniKeys .mm-c{
    position:absolute; bottom:2px; width:5px; height:5px; margin-left:-2.5px;
    border-radius:50%; background:var(--brand); opacity:.7;
  }
  #miniRange{
    position:absolute; top:0; bottom:0; display:none;
    background:rgba(200,134,47,.22);
  }
  #miniView{
    position:absolute; top:0; bottom:0;
    border:2px solid var(--brand); border-radius:6px;
    background:rgba(217,166,46,.1); pointer-events:none;
  }
  /* Whole keyboard fits on screen: the navigator becomes a passive overview. */
  .dock-nav.mm-full{opacity:.35;}
  .dock-nav.mm-full #miniMap{cursor:default;}
  body.dock-collapsed .dock-nav{display:none;}
  #pianoScroll{
    overflow-x:auto; overflow-y:hidden; -webkit-overflow-scrolling:touch;
    scrollbar-width:none;   /* the navigator replaces the native scrollbar */
  }
  #pianoScroll::-webkit-scrollbar{display:none;}
  body.dock-collapsed #pianoScroll{display:none;}
  #piano{
    position:relative; height:150px; margin:0 auto;
    user-select:none; -webkit-user-select:none; touch-action:none;
  }
  .wk{
    position:absolute; top:0; height:150px; width:38px;
    background:linear-gradient(180deg, #D9D0BC 0%, #EFE8D8 55%, #F7F1E5 100%);
    border:1px solid #0F0C08; border-radius:0 0 5px 5px;
    cursor:pointer;
  }
  .wk .klabel{
    position:absolute; bottom:6px; left:0; right:0; text-align:center;
    font:500 .68rem var(--mono); color:#877C66; pointer-events:none;
  }
  .wk .klabel.c-mark{color:#8A6216; font-weight:600;}
  .bk{
    position:absolute; top:0; height:92px; width:24px;
    background:linear-gradient(180deg, #060504 0%, #191410 55%, #40382A 100%);
    border:1px solid #000; border-radius:0 0 4px 4px;
    cursor:pointer; z-index:2;
    box-shadow:0 4px 7px rgba(0,0,0,.5), inset 0 -2px 0 rgba(255,244,214,.12);
  }
  .bk .klabel{
    position:absolute; bottom:5px; left:0; right:0; text-align:center;
    font:500 .58rem var(--mono); color:rgba(255,255,255,.55); pointer-events:none;
  }
  .wk.down{
    background:linear-gradient(180deg, #B49B60 0%, #E8CE93 46%, #F7E7BC 100%);
    box-shadow:0 0 18px rgba(240,200,104,.45);
  }
  .bk.down{
    background:linear-gradient(180deg, #241B08 0%, #5C4715 60%, #93741F 100%);
    box-shadow:0 0 16px rgba(240,200,104,.4);
  }
  .wk.hl-good, .bk.hl-good{box-shadow:inset 0 0 0 3px var(--good);}
  .wk.hl-hint, .bk.hl-hint{box-shadow:inset 0 0 0 3px var(--amber);}
  .wk.hl-bad, .bk.hl-bad{box-shadow:inset 0 0 0 3px var(--bad);}
  /* Video sheet-sync glow: the keys the loaded score is sounding right now. A
     separate class from hl-good/hint/bad so clearHighlights never wipes it. */
  .wk.hl-play{box-shadow:inset 0 0 0 3px var(--brand); background:linear-gradient(#F7EBCB, #EFDCA9);}
  .bk.hl-play{box-shadow:inset 0 0 0 3px var(--brand); background:linear-gradient(#8A5A31, #4A2E15);}
  body.labels-none .klabel{display:none;}
  body.labels-c .wk .klabel:not(.c-mark){display:none;}
  body.labels-c .bk .klabel{display:none;}
  /* Floating note-name cue shown when a key is activated (dock tap or a piano-roll
     click). Fixed-position + high z-index so it also reads over the fullscreen
     study view. Points down at the key by default, up when flipped below. */
  #keyCue{
    position:fixed; z-index:10000; pointer-events:none;
    transform:translate(-50%, -100%);
    background:#1C160F; border:1px solid rgba(240,200,104,.55);
    color:var(--brand-2); font:700 .82rem var(--mono);
    padding:4px 10px; border-radius:8px; letter-spacing:.3px; white-space:nowrap;
    box-shadow:0 6px 18px -6px rgba(0,0,0,.7);
    opacity:0; transition:opacity .1s ease;
  }
  #keyCue.below{transform:translate(-50%, 0);}
  #keyCue.show{opacity:.98;}
  #keyCue::after{
    content:''; position:absolute; left:50%; bottom:-5px; margin-left:-5px;
    border:5px solid transparent; border-top-color:rgba(240,200,104,.55); border-bottom:0;
  }
  #keyCue.below::after{bottom:auto; top:-5px; border-top:0; border-bottom:5px solid rgba(240,200,104,.55);}
  @media(prefers-reduced-motion:reduce){ #keyCue{transition:none;} }

  /* Staff SVG, wearing the Studio sheet ribbon's palette everywhere: staff
     furniture softened to translucent cream, golden notes with a soft glow.
     Keep these numbers in step with the rb-* rules in the Video section. */
  svg.staff{display:block;}
  svg.staff .sline{stroke:rgba(242,235,222,.32); stroke-width:1.1;}
  svg.staff .ledger{stroke:rgba(242,235,222,.6); stroke-width:1.3;}
  svg.staff .stem{stroke:var(--brand-2); stroke-width:1.5;}
  svg.staff .nhead{fill:var(--brand-2); filter:drop-shadow(0 0 5px rgba(240,200,104,.45));}
  svg.staff text.clef, svg.staff text.acc{font-family:var(--music); fill:rgba(242,235,222,.82);}
  svg.staff .qnote text.acc{fill:var(--brand-2);}
  svg.staff text.nlabel{font:600 12px var(--mono); fill:var(--brand);}
  svg.staff .brace{stroke:rgba(242,235,222,.5); stroke-width:1.4; fill:none;}
  /* Practice sequences: the note under the cursor brightens like a sounding
     ribbon note, already-answered notes fade back with the glow removed. */
  svg.staff .qnote.cur .nhead{fill:#FFE9B8; filter:drop-shadow(0 0 9px rgba(240,200,104,.85));}
  svg.staff .qnote.cur .stem, svg.staff .qnote.cur .ledger{stroke:#FFE9B8;}
  svg.staff .qnote.cur text.acc{fill:#FFE9B8;}
  svg.staff .qnote.done .nhead{fill:var(--faint); filter:none;}
  svg.staff .qnote.done .stem, svg.staff .qnote.done .ledger{stroke:var(--faint);}
  svg.staff .qnote.done text.acc{fill:var(--faint);}

  /* ============ Progress, sprints, pacing, toasts ============ */
  /* Question staves scale down instead of overflowing narrow phones. Song
     sheets are excluded: squeezed systems there scroll on purpose. */
  .staff-card svg.staff, .tryit svg.staff, .staff-fig svg.staff{max-width:100%; height:auto;}
  .mode-seg{
    display:flex; gap:2px; background:var(--surface-2); border:1px solid var(--line);
    border-radius:999px; padding:3px; width:max-content; max-width:100%; margin:2px 0 14px;
  }
  .mode-seg button{
    appearance:none; border:0; background:none; cursor:pointer;
    font:600 .84rem var(--sans); color:var(--muted); padding:6px 14px; border-radius:999px;
  }
  .mode-seg button.sel{background:var(--brand); color:var(--brand-ink);}
  .crown{color:var(--amber); font-weight:700;}
  .tbars{display:flex; align-items:flex-end; gap:3px; height:48px; margin:10px 0 2px;}
  .tbars span{width:10px; border-radius:2px 2px 0 0; background:var(--good); opacity:.7;}
  .tbars span.no{background:var(--bad); opacity:.85;}
  .next-card{
    border:1px solid var(--line); border-left:4px solid var(--brand);
    background:var(--surface); border-radius:var(--radius); box-shadow:var(--shadow-sm);
    padding:14px 18px; margin-bottom:18px;
    display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  }
  .next-card .t{font:600 .74rem var(--sans); color:var(--brand); text-transform:uppercase; letter-spacing:.06em;}
  .next-card .why{color:var(--muted); font-size:.88rem; flex:1; min-width:200px;}
  .mastery-bar{height:5px; border-radius:3px; background:var(--line); overflow:hidden; margin-top:6px;}
  .mastery-bar i{display:block; height:100%; background:var(--good);}
  .mgrid{display:flex; flex-wrap:wrap; gap:6px; margin:6px 0 2px;}
  .mnote{
    appearance:none; cursor:pointer; border-radius:7px; padding:3px 8px;
    font:600 .78rem var(--mono); border:1px solid var(--line-strong);
    background:var(--surface); color:var(--muted);
  }
  .mnote.m-str{background:var(--bad-tint); border-color:var(--bad); color:var(--bad);}
  .mnote.m-lrn{background:rgba(217,166,46,.14); border-color:var(--amber); color:#E4BE62;}
  .mnote.m-acc{background:var(--good-tint); border-color:var(--good); color:var(--good);}
  .mnote.m-flu{background:var(--good); border-color:var(--good); color:#10231A;}
  .mlegend{display:flex; gap:12px; flex-wrap:wrap; font-size:.76rem; color:var(--muted); margin-top:12px; align-items:center;}
  .mlegend .mnote{cursor:default;}
  .spark polyline{fill:none; stroke:var(--brand); stroke-width:2;}
  .spark circle{fill:var(--brand);}
  .prog-tiles{display:grid; grid-template-columns:repeat(auto-fit,minmax(130px,1fr)); gap:10px;}
  .prac-controls{
    display:flex; gap:14px; flex-wrap:wrap; align-items:center;
    margin:2px 0 10px; font-size:.82rem; color:var(--muted);
  }
  .prac-controls .seg{display:inline-flex; gap:2px; background:var(--surface-2); border:1px solid var(--line); border-radius:999px; padding:2px; vertical-align:middle;}
  .prac-controls .seg button{
    appearance:none; border:0; background:none; cursor:pointer;
    font:600 .78rem var(--sans); color:var(--muted); padding:3px 10px; border-radius:999px;
  }
  .prac-controls .seg button.sel{background:var(--brand); color:var(--brand-ink);}
  #toasts{
    position:fixed; left:50%; transform:translateX(-50%);
    bottom:calc(var(--dock-h) + 26px); z-index:70;
    display:flex; flex-direction:column; gap:8px; align-items:center; pointer-events:none;
  }
  body.dock-collapsed #toasts{bottom:84px;}
  .toast{
    background:rgba(28,22,15,.96); color:var(--ink); border:1px solid rgba(240,200,104,.45);
    border-radius:999px; padding:9px 18px;
    font:600 .86rem var(--sans); box-shadow:var(--shadow);
    opacity:0; transform:translateY(8px); transition:opacity .25s, transform .25s;
  }
  .toast.show{opacity:.95; transform:translateY(0);}

  /* ============ Leaderboards ============ */
  .lb-controls{
    display:flex; gap:16px; flex-wrap:wrap; align-items:center;
    margin:8px 0 12px; font-size:.85rem; color:var(--muted);
  }
  .lb-controls input[type="text"]{
    border:1px solid var(--line-strong); border-radius:7px; padding:5px 9px;
    font:500 .85rem var(--sans); background:var(--surface); color:var(--ink); width:150px;
  }
  table.ranks tr.lb-me td{background:var(--brand-tint);}
  .lb-flag{width:20px; height:15px; border-radius:2px; vertical-align:-2px; margin-right:6px;}

  /* ============ Rhythm ============ */
  #rhythmSheet{overflow-x:auto; padding:6px 0 2px;}
  /* The rhythm line wears the Studio ribbon's palette too: furniture in
     translucent cream, tappable notes golden with a soft glow; rests stay
     cream furniture (they mark silence, gold marks what you play). */
  svg.rhythm .rline{stroke:rgba(242,235,222,.32); stroke-width:1.1;}
  svg.rhythm .rbar{stroke:rgba(242,235,222,.5); stroke-width:1.3;}
  svg.rhythm .beatnum{font:600 10px var(--mono); fill:var(--faint);}
  svg.rhythm .nh-f, svg.rhythm .ndot{fill:var(--brand-2);}
  svg.rhythm .nh-f{filter:drop-shadow(0 0 5px rgba(240,200,104,.45));}
  svg.rhythm .rrest rect{fill:rgba(242,235,222,.82);}
  svg.rhythm .nh-o{fill:none; stroke:var(--brand-2); stroke-width:1.9; filter:drop-shadow(0 0 5px rgba(240,200,104,.45));}
  svg.rhythm .stem{stroke:var(--brand-2); stroke-width:1.5;}
  svg.rhythm .beam{stroke:var(--brand-2); stroke-width:4.5;}
  svg.rhythm .flag{stroke:var(--brand-2); stroke-width:2.6; fill:none;}
  svg.rhythm .rnote.cur .flag{stroke:#FFE9B8;}
  svg.rhythm .rnote.hit .flag{stroke:var(--good);}
  svg.rhythm .rnote.miss .flag{stroke:var(--bad);}
  /* A tied note is held, not tapped: drawn a shade quieter, joined by its arc. */
  svg.rhythm .tie{stroke:var(--muted); stroke-width:1.9; fill:none; stroke-linecap:round;}
  svg.rhythm .rnote.tied .nh-o{stroke:var(--muted); filter:none;}
  svg.rhythm .rnote.tied .nh-f{fill:var(--muted); filter:none;}
  svg.rhythm .rnote.tied .stem{stroke:var(--muted);}
  svg.rhythm .rnote.tied.cur .tie{stroke:#FFE9B8;}
  /* Rhythm figures embedded in lessons sit on the paper panel like staff figs. */
  .rhythm-fig{overflow-x:auto;}
  /* Post-run early/late timeline: one chip per tappable onset. */
  .rhythm-offsets{display:flex; flex-wrap:wrap; gap:5px; margin:8px 0 2px;}
  .roff{
    font:600 .7rem var(--mono); border-radius:6px; padding:2px 7px;
    background:var(--surface-2); border:1px solid var(--line); color:var(--muted);
  }
  .roff.tight{color:var(--good); border-color:rgba(127,199,164,.45);}
  .roff.near{color:#E4BE62; border-color:rgba(217,166,46,.45);}
  .roff.wide{color:var(--bad); border-color:rgba(224,138,114,.45);}
  .roff.miss{color:var(--bad); background:var(--bad-tint);}
  svg.rhythm .rnote .halo{fill:var(--brand); opacity:0; transition:opacity .1s;}
  svg.rhythm .rnote.cur .halo{opacity:.14;}
  svg.rhythm .rnote.cur .nh-f{fill:#FFE9B8; filter:drop-shadow(0 0 9px rgba(240,200,104,.85));}
  svg.rhythm .rnote.cur .nh-o{filter:drop-shadow(0 0 9px rgba(240,200,104,.85));}
  svg.rhythm .rnote.cur .nh-o, svg.rhythm .rnote.cur .stem, svg.rhythm .rnote.cur .beam{stroke:#FFE9B8;}
  svg.rhythm .rnote.cur .ndot{fill:#FFE9B8;}
  svg.rhythm .rnote.hit .nh-f, svg.rhythm .rnote.hit .ndot{fill:var(--good);}
  svg.rhythm .rnote.hit .nh-f, svg.rhythm .rnote.hit .nh-o{filter:drop-shadow(0 0 7px rgba(127,199,164,.6));}
  svg.rhythm .rnote.hit .nh-o, svg.rhythm .rnote.hit .stem, svg.rhythm .rnote.hit .beam{stroke:var(--good);}
  svg.rhythm .rnote.miss .nh-f, svg.rhythm .rnote.miss .ndot{fill:var(--bad);}
  svg.rhythm .rnote.miss .nh-f, svg.rhythm .rnote.miss .nh-o{filter:drop-shadow(0 0 7px rgba(224,138,114,.5));}
  svg.rhythm .rnote.miss .nh-o, svg.rhythm .rnote.miss .stem, svg.rhythm .rnote.miss .beam{stroke:var(--bad);}

  /* ============ Scales ============ */
  /* Hand colours follow the Studio's piano-roll convention: right hand jade,
     left hand ember, so fingering numbers read the same across the app. */
  #panel-scales{--sc-rh:#7FC7A4; --sc-lh:#E5A176;}
  .sc-rh{color:var(--sc-rh);}
  .sc-lh{color:var(--sc-lh);}
  .scale-pickrow{display:flex; gap:12px; flex-wrap:wrap; align-items:center;}
  .scale-pickrow .mode-seg{margin:2px 0 8px;}
  #panel-scales .seg{display:inline-flex; gap:2px; background:var(--surface-2); border:1px solid var(--line); border-radius:999px; padding:2px; vertical-align:middle;}
  #panel-scales .seg button{
    appearance:none; border:0; background:none; cursor:pointer;
    font:600 .78rem var(--sans); color:var(--muted); padding:3px 10px; border-radius:999px;
  }
  #panel-scales .seg button.sel{background:var(--brand); color:var(--brand-ink);}
  .scale-formseg{margin:2px 0 8px;}
  .scale-chip .sc-min{font-weight:400; color:inherit; opacity:.7; margin-left:-4px;}
  .scale-chip .sc-sig{font:600 .68rem var(--mono); color:var(--faint);}
  .scale-chip.sel .sc-sig{color:var(--brand-ink); opacity:.75;}

  .scale-head{display:flex; gap:8px 18px; flex-wrap:wrap; align-items:baseline; justify-content:space-between; margin-top:14px;}
  .scale-title{display:flex; gap:12px; align-items:baseline; flex-wrap:wrap;}
  .scale-title h3{margin:0; font-size:1.35rem;}
  .scale-links{display:flex; gap:8px; flex-wrap:wrap; align-items:center;}
  .sc-kv{
    font:600 .78rem var(--mono); color:var(--brand-2);
    background:rgba(217,166,46,.1); border:1px solid rgba(217,166,46,.3);
    border-radius:999px; padding:3px 11px;
  }
  .sc-link{
    appearance:none; cursor:pointer; border-radius:999px;
    border:1px solid var(--line-strong); background:none;
    font:600 .78rem var(--sans); color:var(--muted); padding:3px 11px;
  }
  .sc-link:hover{color:var(--ink); background:var(--surface-2);}
  .sc-degrow{display:flex; gap:6px; flex-wrap:wrap; margin:10px 0 4px;}
  .sc-degpill{
    display:inline-flex; flex-direction:column; align-items:center; min-width:40px;
    background:var(--surface-2); border:1px solid var(--line); border-radius:var(--radius-sm);
    padding:4px 8px 3px; line-height:1.25;
  }
  .sc-degpill b{font:600 .92rem var(--sans); color:var(--ink);}
  .sc-degpill i{font:600 .64rem var(--mono); font-style:normal; color:var(--faint);}
  .sc-degpill.top{border-style:dashed; opacity:.8;}
  .sc-step{
    align-self:center; font:600 .6rem var(--mono); color:var(--faint);
    padding:0 1px; letter-spacing:-.02em;
  }
  .sc-melnote{max-width:72ch;}

  /* The two-octave keyboard diagram. Key faces stay recognizably white/black;
     in-scale keys take a warm wash, the tonics a stronger one. */
  .scale-diagram{margin:12px 0 4px; max-width:760px; overflow-x:auto;}
  /* Never shrink the keys below legibility: narrow phones scroll the diagram
     sideways instead (matching the fingering strip's behavior). */
  .scale-diagram svg{display:block; min-width:540px;}
  .scale-diagram .sd-wk{fill:#EFE9DC; stroke:#2A2217; stroke-width:1;}
  .scale-diagram .sd-wk.sd-in{fill:#F4E3B8;}
  .scale-diagram .sd-wk.sd-root{fill:#EFC868;}
  .scale-diagram .sd-bk{fill:#241E14; stroke:#0F0B06; stroke-width:1;}
  .scale-diagram .sd-bk.sd-in{fill:#5C4718; stroke:#8A6C25;}
  .scale-diagram .sd-bk.sd-root{fill:#8A6C25;}
  .scale-diagram .sd-dn{stroke:var(--sc-lh); stroke-dasharray:3 2;}
  .scale-diagram [data-midi]{cursor:pointer;}
  .scale-diagram .lit.sd-wk, .scale-diagram .sd-wk.lit{fill:#FFE9B8;}
  .scale-diagram .lit.sd-bk, .scale-diagram .sd-bk.lit{fill:#B08A2E;}
  .scale-diagram .sd-f circle{fill:rgba(22,17,11,.78); stroke-width:1.4;}
  .scale-diagram .sd-f text{font:700 10px var(--mono); fill:var(--ink);}
  .scale-diagram .sd-rh circle{stroke:var(--sc-rh);}
  .scale-diagram .sd-rh text{fill:var(--sc-rh);}
  .scale-diagram .sd-lh circle{stroke:var(--sc-lh);}
  .scale-diagram .sd-lh text{fill:var(--sc-lh);}

  .scale-striprow{margin:10px 0 2px;}
  .sc-stripctl{display:flex; gap:10px; flex-wrap:wrap; align-items:center; margin-bottom:8px;}
  .scale-strip{
    display:flex; gap:2px; overflow-x:auto; padding:8px 6px;
    background:var(--surface-2); border:1px solid var(--line); border-radius:var(--radius-sm);
  }
  .ss-rowlab, .ss-col{display:flex; flex-direction:column; align-items:center; gap:3px; min-width:34px;}
  .ss-rowlab{min-width:26px; color:var(--faint);}
  .ss-rowlab i{font:600 .6rem var(--sans); font-style:normal; text-transform:uppercase; letter-spacing:.04em;}
  .ss-col{border-radius:7px; padding:3px 2px; cursor:pointer;}
  .ss-col:hover{background:rgba(240,200,104,.08);}
  .ss-col.root .ss-note{color:var(--brand-2);}
  .ss-col.top{border:1px dashed var(--line-strong);}
  .ss-col.lit{background:rgba(240,200,104,.18); box-shadow:0 0 0 1px var(--brand);}
  .ss-note{font:600 .82rem var(--sans); color:var(--ink); white-space:nowrap;}
  .ss-f{
    font:700 .78rem var(--mono); font-style:normal; line-height:1;
    width:20px; height:20px; border-radius:999px;
    display:inline-flex; align-items:center; justify-content:center;
  }
  .ss-f.turn{box-shadow:0 0 0 1.6px currentColor; background:rgba(22,17,11,.5);}
  .sc-legend{max-width:78ch;}

  .scale-playrow{
    display:flex; gap:10px 16px; flex-wrap:wrap; align-items:center;
    margin-top:14px; font-size:.82rem; color:var(--muted);
  }

  /* ---- drills ---- */
  .drill-cards{display:grid; grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); gap:10px; margin:10px 0 14px;}
  .drill-card{
    appearance:none; cursor:pointer; text-align:left;
    background:var(--surface-2); border:1px solid var(--line); border-radius:var(--radius);
    padding:12px 14px; color:var(--ink);
    display:flex; flex-direction:column; gap:3px;
  }
  .drill-card:hover{border-color:var(--line-strong);}
  .drill-card.active{border-color:var(--brand); box-shadow:0 0 0 1px var(--brand);}
  .drill-card .dc-name{font-family:var(--serif); font-weight:600; font-size:1.02rem;}
  .drill-card .dc-sub{font:600 .7rem var(--sans); color:var(--brand); text-transform:uppercase; letter-spacing:.05em;}
  .drill-card .dc-done{font:600 .72rem var(--mono); color:var(--good);}
  .drill-card .dc-why{font-size:.76rem; line-height:1.4;}
  .drill-stage{min-height:60px; display:flex; flex-direction:column; align-items:center; gap:10px; text-align:center;}
  .drill-stage .q-meta{justify-content:center;}
  .drill-cue{display:flex; align-items:baseline; gap:10px; margin:4px 0;}
  .dcue-note{font-family:var(--serif); font-weight:700; font-size:2rem; color:var(--brand-2);}
  .dcue-f{display:inline-flex; gap:6px; font:700 1.5rem var(--mono);}
  .dcue-lbl{font-size:.74rem; color:var(--faint); text-transform:uppercase; letter-spacing:.05em;}
  .drill-report{max-width:56ch;}
  .drill-report h3{margin-top:.2em;}
  .drill-report .btn-row{justify-content:center; margin-top:10px;}
  .sc-record{color:var(--brand-2); font-weight:600;}

  .turn-row{display:flex; gap:6px; align-items:center; flex-wrap:wrap; justify-content:center;}
  .turn-pill{
    display:inline-flex; align-items:center; gap:6px;
    border:1px solid var(--line-strong); border-radius:999px; padding:5px 12px;
    font:600 .9rem var(--sans); background:var(--surface-2);
  }
  .turn-pill i{font:700 .8rem var(--mono); font-style:normal; color:var(--muted);}
  .turn-pill.turn{border-color:var(--brand); }
  .turn-pill.turn i{color:var(--brand-2);}
  .turn-pill.cur{background:rgba(240,200,104,.16); box-shadow:0 0 0 1px var(--brand);}
  .turn-arrow{color:var(--faint);}
  .rep-dot{
    display:inline-block; width:9px; height:9px; border-radius:999px;
    background:var(--line); margin-left:4px; vertical-align:middle;
  }
  .rep-dot.done{background:var(--good);}

  .ladder-rungs{display:flex; gap:6px; flex-wrap:wrap; justify-content:center; margin:6px 0 4px;}
  .ladder-rungs .rung{
    appearance:none; cursor:pointer; border-radius:var(--radius-sm);
    border:1px solid var(--line-strong); background:var(--surface-2);
    font:600 .85rem var(--mono); color:var(--muted); padding:7px 11px; position:relative;
  }
  .ladder-rungs .rung i{font-style:normal; color:var(--good); margin-left:3px;}
  .ladder-rungs .rung.passed{border-color:rgba(127,199,164,.5); color:var(--ink);}
  .ladder-rungs .rung.next{border-color:var(--brand);}
  .ladder-rungs .rung.sel{background:var(--brand); border-color:var(--brand); color:var(--brand-ink);}
  .ladder-rungs .rung.sel i{color:var(--brand-ink);}
  .ladder-dots{display:flex; gap:4px; flex-wrap:wrap; justify-content:center; margin:6px 0;}
  .ladder-dots .dot{
    width:12px; height:12px; border-radius:999px;
    background:var(--surface-2); border:1px solid var(--line-strong);
  }
  .ladder-dots .dot.cur{border-color:var(--brand); box-shadow:0 0 0 1px var(--brand);}
  .ladder-dots .dot.good{background:var(--good); border-color:var(--good);}
  .ladder-dots .dot.off{background:var(--amber); border-color:var(--amber);}
  .ladder-dots .dot.wrong{background:var(--bad); border-color:var(--bad);}
  .ladder-dots .dot.miss{background:var(--bad-tint); border-color:var(--bad);}

  @media (prefers-reduced-motion: reduce){
    .staff-card.flash-no{animation:none;}
    .toast{transition:none;}
  }

  footer{
    max-width:1040px; margin:10px auto 0; padding:0 20px 16px;
    font-size:.76rem; color:var(--faint);
  }
  footer a{color:var(--muted);}

  /* ============ Account chip, menu & dialogs ============ */
  .acct-area{display:flex; align-items:center; gap:8px; padding-bottom:8px; position:relative;}
  .acct-area[hidden]{display:none;}
  .acct-loading{color:var(--faint); font-size:.85rem; padding:0 6px;}
  .acct-signin{
    appearance:none; cursor:pointer; font:600 .82rem var(--sans);
    color:var(--brand-ink); background:linear-gradient(180deg, #EFC868, var(--brand));
    border:1px solid transparent;
    border-radius:999px; padding:6px 14px;
  }
  .acct-signin:hover{background:linear-gradient(180deg, #F6D88E, var(--brand-2));}
  .acct-chip{
    display:flex; align-items:center; gap:8px; cursor:pointer;
    background:var(--surface-2); border:1px solid var(--line-strong);
    border-radius:999px; padding:4px 12px 4px 4px; font:inherit; color:var(--ink);
  }
  .acct-chip:hover{border-color:var(--brand);}
  .acct-avatar{
    width:26px; height:26px; border-radius:50%; overflow:hidden; flex:0 0 auto;
    display:grid; place-items:center; background:var(--brand); color:var(--brand-ink);
    font:700 .8rem var(--sans);
  }
  .acct-avatar img{width:100%; height:100%; object-fit:cover;}
  .acct-name{font:600 .84rem var(--sans); max-width:120px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
  .acct-dot{width:8px; height:8px; border-radius:50%; background:var(--good); flex:0 0 auto;}
  .acct-dot.sync{background:var(--amber);}
  .acct-dot.err{background:var(--bad);}
  .acct-menu{
    position:absolute; top:calc(100% + 6px); right:0; z-index:50;
    min-width:220px; background:var(--surface); border:1px solid var(--line-strong);
    border-radius:var(--radius); box-shadow:var(--shadow); padding:12px;
    display:flex; flex-direction:column; gap:4px;
  }
  .acct-menu[hidden]{display:none;}
  .acct-menu .am-name{font:700 .95rem var(--serif);}
  .acct-menu .am-email{font-size:.78rem; color:var(--muted); word-break:break-all;}
  .acct-menu .am-sname{font-size:.82rem; color:var(--ink); margin-top:6px;}
  .acct-menu .am-status{font-size:.74rem; color:var(--faint); margin:2px 0 6px;}
  .am-btn{
    appearance:none; text-align:left; cursor:pointer; font:600 .84rem var(--sans);
    color:var(--ink); background:var(--surface-2); border:1px solid var(--line);
    border-radius:var(--radius-sm); padding:8px 10px;
  }
  .am-btn:hover{border-color:var(--brand); color:var(--brand);}
  .th-verified{color:var(--good); font-weight:700; margin-left:3px;}

  .overlay{
    position:fixed; inset:0; z-index:200; background:rgba(0,0,0,.58);
    display:flex; align-items:center; justify-content:center; padding:18px;
  }
  /* A class rule with display:flex would otherwise beat the UA [hidden] rule
     and leave dialogs always on screen (and intercepting clicks). */
  .overlay[hidden]{display:none;}
  .dialog{
    position:relative; width:100%; max-width:380px; background:var(--surface);
    border:1px solid var(--line-strong); border-radius:var(--radius);
    box-shadow:var(--shadow); padding:22px 22px 20px; max-height:90vh; overflow-y:auto;
  }
  .dialog h2{font-family:var(--serif); font-size:1.25rem; margin:0 0 8px;}
  .dialog .hint{margin:0 0 14px;}
  .dlg-close{
    position:absolute; top:10px; right:12px; appearance:none; border:0; background:none;
    cursor:pointer; font-size:1.5rem; line-height:1; color:var(--faint);
  }
  .dlg-close:hover{color:var(--ink);}
  .fld{display:block; font:600 .8rem var(--sans); color:var(--muted); margin:0 0 12px;}
  .fld input{
    display:block; width:100%; margin-top:5px; box-sizing:border-box;
    font:400 .95rem var(--sans); color:var(--ink);
    background:var(--surface-2); border:1px solid var(--line-strong);
    border-radius:var(--radius-sm); padding:10px 12px;
  }
  .fld input:focus{outline:2px solid var(--brand-tint); border-color:var(--brand);}
  .btn.block{display:block; width:100%; margin-top:6px;}
  .google-btn{display:flex; align-items:center; justify-content:center; gap:9px; width:100%;}
  .g-mark{
    display:inline-grid; place-items:center; width:20px; height:20px; border-radius:50%;
    background:#fff; border:1px solid var(--line-strong); color:#4285F4; font:700 .8rem var(--sans);
  }
  .auth-or{display:flex; align-items:center; gap:10px; margin:14px 0; color:var(--faint); font-size:.78rem;}
  .auth-or::before, .auth-or::after{content:""; flex:1; height:1px; background:var(--line);}
  .auth-forgot-row{text-align:right; margin:-4px 0 8px;}
  .linkish{
    appearance:none; border:0; background:none; cursor:pointer; padding:0;
    color:var(--brand); font:600 .82rem var(--sans); text-decoration:underline;
  }
  .auth-alt{margin:12px 0 0; font-size:.82rem; color:var(--muted); text-align:center;}
  .auth-msg{font-size:.82rem; margin:0 0 10px; padding:8px 10px; border-radius:var(--radius-sm);}
  .auth-msg.auth-err{background:var(--bad-tint); color:var(--bad);}
  .auth-msg.auth-ok{background:var(--good-tint); color:var(--good);}
