/* Cadência — tokens de design.
   Direção aprovada em design_handoff_cadencia/README.md (tema claro).
   Os apelidos no fim do bloco existem para este commit não quebrar as regras
   que ainda usam os nomes antigos. Removem-se no commit 5, depois da varredura. */

:root {
  /* Cor */
  --fundo: #F4F2ED;
  --superficie: #FFFFFF;
  --superficie-2: #FBFAF7;
  --tinta: #16181B;
  --tinta-media: #4A4F53;
  /* Era #6B6F73: 4,53:1 no papel e 4,10:1 no trilho, onde moram as opcoes nao
     escolhidas das alternancias. Um passo mais escura passa nos quatro chaos —
     4,55 no trilho, 5,02 no papel — e continua mais clara que a `--tinta-media`,
     entao a hierarquia nao se inverte. */
  --tinta-fraca: #64686C;
  /* SO PARA O QUE NAO E TEXTO. Da 2,88:1 no papel e 2,61:1 no trilho — abaixo
     dos 4,5 que o texto precisa. Todo `color:` que a usava passou para a
     `--tinta-fraca`; ela ficou para pontos e fios. */
  --tinta-fantasma: #8B9095;
  --fio: rgba(22, 24, 27, .09);
  --fio-forte: rgba(22, 24, 27, .26);
  --dominio: #0E6B5C;
  --dominio-fraco: #E9F0EC;
  --agora: #E8703A;
  /* Superficie tingida de `--agora`, para o bloco que fala da peca de
     conclusao. Entrou porque eu a usei com reserva e a minha propria regra
     proibe reserva de cor: ficha que morre com reserva se disfarca. */
  --agora-fraco: #FBEEE7;
  --trilho: #EAE7E0;
  --trilho-vazio: #EFEDE7;

  /* Sobre o bloco escuro do teclado e do transporte */
  --escuro-texto: #FFFFFF;
  --escuro-icone: #C9CDD0;
  --escuro-legenda: #9AA0A4;
  --escuro-tecla-preta: #1B1E21;
  /* O teclado e desenhado em canvas, e ate agora as cores dele estavam cravadas
     no `piano-keyboard.js` — azul, verde e vermelho de uma paleta que este app
     nao usa mais. A varredura de literais do commit 3 passou pelo CSS e nao pelo
     JS, entao aquelas 14 escaparam. Ficam aqui pelo mesmo motivo que todas as
     outras: uma fonte de verdade so, e o tema escuro do apendice A vai precisar
     trocar estas seis sem abrir arquivo de JavaScript. */
  --escuro-tecla-branca: #FFFFFF;
  --escuro-tecla-fio: rgba(22, 24, 27, .55);
  --tecla-a-tocar: #0E6B5C;
  --tecla-proxima: rgba(14, 107, 92, .30);
  --tecla-soando: rgba(232, 112, 58, .50);
  --tecla-errada: rgba(179, 38, 30, .55);
  --escuro-fio: rgba(255, 255, 255, .08);
  --escuro-fio-btn: rgba(255, 255, 255, .16);
  --escuro-fio-btn-hover: rgba(255, 255, 255, .40);
  --escuro-hover: rgba(255, 255, 255, .09);
  /* O trilho e a faixa do laco vivem sobre o bloco escuro, e por isso nao podem
     usar `--trilho`, que e cinza de papel claro. */
  --escuro-trilho: rgba(255, 255, 255, .14);
  --laco-faixa: rgba(232, 112, 58, .45);
  /* O fundo da proposta de laco. Ela mora no transporte ESCURO, e por isso e
     translucida: o `--agora-fraco` e opaco e claro, e sobre `--tinta` viraria
     uma placa de papel no meio do bloco escuro. */
  --agora-sobre-escuro: rgba(232, 112, 58, .16);

  /* Capas, enquanto não houver imagem */
  --capa-1: #DCE5DF;
  --capa-2: #E4E1D6;
  --capa-3: #DEE2E9;
  --capa-4: #E8DFD9;

  /* Tipografia.
     As duas famílias entram no commit 2, com @font-face local — até lá as
     pilhas de reserva (Georgia e system-ui) é que respondem. */
  --fonte-titulo: 'Newsreader', Georgia, 'Times New Roman', serif;
  --fonte-ui: 'Instrument Sans', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  --fonte-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;

  /* Forma */
  --raio-xg: 18px;
  --raio-g: 16px;
  --raio-m: 14px;
  --raio-btn: 12px;
  --raio-p: 11px;
  --raio-i: 10px;
  --raio-alt: 8px;
  --raio-barra: 3px;

  /* Sombra */
  --sombra-1: 0 1px 2px rgba(22, 24, 27, .06);
  --sombra-2: 0 4px 14px rgba(22, 24, 27, .24);

  /* Movimento */
  /* Veu sobre a interface, para dialogo e carregamento. E tinta com
     transparencia, nao preto: preto puro sobre papel claro fica sujo. */
  --veu: rgba(22, 24, 27, .60);
  --veu-forte: rgba(22, 24, 27, .78);
  /* O veu sob o que se le POR CIMA de uma capa — a duracao e o botao de
     apagar. Nao e o `--veu` (.60) nem o `--veu-forte` (.78): e o que ja estava
     pintado, e virou ficha com o valor que tinha, para a troca nao mudar a
     tela de ninguem. */
  --veu-capa: rgba(22, 24, 27, .72);
  /* Lavagens de tinta sobre papel: o hover e o apertar de controles claros. */
  --tinta-sopro: rgba(22, 24, 27, .04);
  --tinta-toque: rgba(22, 24, 27, .07);
  /* O brilho diagonal sobre a capa do cartao. */
  --capa-brilho: rgba(255, 255, 255, .28);

  /* O dominio em componentes, para compor transparencia sem cravar o hex de
     novo (o pulso do metronomo e a faixa de selecao precisam disso). */
  --dominio-rgb: 14, 107, 92;

  /* Faixa de aviso: a unica cor de alerta do desenho. Ambar, nao vermelho —
     aviso nao e erro. */
  --aviso-fundo: #FBF3E3;
  --aviso-fio: #E8D6AE;
  --aviso-tinta: #6B5320;

  /* Erro. Usado com parcimonia: no app quem sinaliza acerto e o dominio,
     e quem sinaliza o presente e o agora — vermelho so para falha real. */
  --erro: #B3261E;
  /* O `--erro` a 12 %: o fundo do hover de quem apaga. */
  --erro-sopro: rgba(179, 38, 30, .12);

  /* Sombra do bloco escuro sobre o papel, projetada para cima. */
  --sombra-transporte: 0 -2px 10px rgba(22, 24, 27, .18);

  --transition-fast: 120ms ease;
  --transition-normal: 200ms ease;
  --transition-slow: 320ms ease;

  /* Apelidos temporários — remover no commit 5 */
}

/* Fontes locais.

   A WKWebView do iPad abre o app a partir de arquivos locais e nao tem rede
   garantida. Servidas pelo Google Fonts, as duas familias simplesmente nao
   carregariam ali — e o app abriria em Georgia e system-ui, perdendo a
   identidade inteira sem nenhum erro visivel. Por isso os woff2 moram no
   repositorio e entram no cache do service worker.

   Sao os subconjuntos latin e latin-ext: cobrem o portugues (a Latin-1
   Supplement traz a, a-til, c-cedilha, e-agudo) sem carregar cirilico e grego.
   As duas fontes sao variaveis, entao um arquivo serve toda a faixa de peso. */

@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('../assets/fonts/InstrumentSans-normal-40fe78.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('../assets/fonts/InstrumentSans-normal-f587e7.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Newsreader';
  font-style: italic;
  font-weight: 300 400;
  font-display: swap;
  src: url('../assets/fonts/Newsreader-italic-34eec9.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Newsreader';
  font-style: italic;
  font-weight: 300 400;
  font-display: swap;
  src: url('../assets/fonts/Newsreader-italic-72c495.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 300 500;
  font-display: swap;
  src: url('../assets/fonts/Newsreader-normal-a6a2a4.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 300 500;
  font-display: swap;
  src: url('../assets/fonts/Newsreader-normal-f24c32.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}


@media (prefers-reduced-motion: reduce) {
  :root {
    --transition-fast: 0ms;
    --transition-normal: 0ms;
    --transition-slow: 0ms;
  }
}

/* Global Reset & Base */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  width: 100vw;
  min-height: 100vh;
  overflow-x: hidden;
  overflow-y: auto;
  background-color: var(--fundo);
  color: var(--tinta);
  font-family: var(--fonte-ui);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  scroll-behavior: smooth;
  user-select: none;
}

/* Layout */
/* A ALTURA DA TELA PRECISA SER DEFINIDA AQUI, e nao so pedida como minimo.
   ---------------------------------------------------------------------------
   Era `min-height: 100%`. Percentagem se resolve contra a altura do pai, e o
   `body` so tinha `min-height: 100vh` — altura AUTO. Uma percentagem contra
   altura automatica nao vale nada: o `#app-container` ficava sem altura
   definida e crescia com o conteudo.

   O efeito aparecia tres niveis abaixo. Com o `#main-view` sem altura definida,
   a faixa `1fr` da grade nao tinha o que repartir: `1fr` contra recipiente
   indefinido resolve pelo CONTEUDO, e a partitura passou a mandar na altura em
   vez de receber o que sobrava. O `#score-stage` media 430 px em qualquer
   janela — 360x640 ou 1440x900, sempre 430 — e o bloco inteiro somava 851 px
   numa tela de 640, empurrando o transporte para fora e fazendo a PAGINA rolar.
   Era isso que o `min-height: 0` do `#main-view` e do `#score-stage` tentavam
   resolver sem conseguir: eles deixam a faixa encolher, mas nao ha do que
   encolher enquanto ninguem disser de que altura a tela e.

   `dvh` antes de `vh` porque no celular a barra do navegador entra e sai: com
   `vh` a altura fica a da tela SEM a barra, e o transporte some atras dela. Os
   navegadores que nao conhecem `dvh` ignoram a segunda linha e ficam com a
   primeira. */
#app-container {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  min-height: 0;
  position: relative;
}

/* As quatro faixas do player.
   ---------------------------------------------------------------------------
   Era uma coluna flex em que cada faixa reivindicava altura por conta propria:
   `#piano-container` pedia 15vh entre 100 e 160 px, `#score-stage` pedia
   `flex: 1 1 auto` com 200 px de minimo, e em janela curta os dois brigavam —
   a partitura espremia o teclado ou o teclado empurrava o transporte para fora
   da tela.

   Em grade, a divisao e declarada de uma vez: barra e bloco escuro tomam o que
   precisam, e a partitura fica com o que sobra. Uma faixa nao pode mais tomar
   espaco de outra sem que isto esteja escrito aqui. */
#main-view {
  display: grid;
  /* A coluna precisa ser `minmax(0, 1fr)`, e nao o `auto` implicito: `auto`
     dimensiona pelo conteudo, e o conteudo aqui e uma partitura de centenas de
     milhares de pixels de largura. Com `auto` a coluna cresceu junto, o
     `#score-container` deixou de recortar, e a rolagem simplesmente sumiu —
     scrollWidth igual a clientWidth. E a irma do `min-height: 0`: em grade,
     faixa que nao declara o minimo nao encolhe. */
  grid-template-columns: minmax(0, 1fr);
  /* CINCO faixas, e cada filho diz em qual mora.
     -------------------------------------------------------------------------
     Aqui dizia `auto 1fr auto auto` — quatro faixas, sem dizer quem vai em
     qual. Mas `#main-view` tem CINCO filhos em fluxo, e na ordem do documento
     eles sao: barra, teclado, feedback, partitura, transporte. A colocacao
     automatica seguiu essa ordem e entregou a faixa `1fr` ao TECLADO, que tem
     altura fixa; a partitura caiu numa faixa `auto`, dimensionada pelo
     conteudo; e o transporte, sobrando, foi para uma quinta faixa implicita.

     Duas consequencias, as duas medidas:

     1. A partitura ficava do tamanho do desenho — 430 px em qualquer janela —
        em vez de receber o que sobrava. Era o `#score-stage` travado.
     2. O teclado era pintado LOGO ABAIXO DA BARRA, com a partitura embaixo
        dele e o transporte no fim. O desenho pede o contrario: partitura em
        cima, teclado e transporte formando um bloco escuro colado na base — e
        o raio superior do teclado e o inferior do transporte existem
        justamente porque os dois deveriam se encostar.

     Nenhum teste pegou: nada verificava a ORDEM VERTICAL das faixas, so que
     elas nao estouravam a largura. Agora a secao 30 verifica.

     Nomear a faixa de cada filho, em vez de confiar na ordem do documento,
     e o que impede isto de voltar quando alguem inserir um elemento no meio
     da marcacao. */
  grid-template-rows: auto minmax(0, 1fr) auto auto auto;
  flex-grow: 1;
  width: 100%;
  min-height: 0;
  background: var(--fundo);
}

#main-view > #app-bar { grid-row: 1; }
#main-view > #score-stage { grid-row: 2; }
#main-view > #feedback-container { grid-row: 3; }
#main-view > #piano-container { grid-row: 4; }
#main-view > #controls-bar { grid-row: 5; }

/* Teclado e transporte sao um bloco escuro continuo, encostado na base. O
   teclado arredonda so em cima, o transporte so embaixo, e entre os dois nao
   ha vao — e uma peca so, apoiada no papel. */
/* A altura do teclado e degrau, e o degrau e escolhido por consulta de ALTURA.
   ---------------------------------------------------------------------------
   A regra antiga pedia `15vh` limitado entre 100 e 160 px. Duas falhas:

   1. Em janela curta o teclado encolhia junto com tudo o mais e chegava a 100 px
      brigando com a partitura — que e a faixa flexivel — pelo mesmo espaco.
   2. Pior: as unicas quebras que o arquivo tinha eram de LARGURA. Girar o iPad
      de retrato (1024 de altura) para paisagem (768) nao mudava nada nas
      consultas, mas tirava 256 px da coluna. O teclado ficava do mesmo tamanho
      numa tela que perdeu um quarto da altura, e o transporte saia por baixo.

   Tres degraus fixos, escolhidos por `min-height`, resolvem os dois: a altura do
   teclado nao depende mais da largura, e nao encolhe continuamente — ela pula
   para o degrau que a janela comporta e para ali, deixando o resto do ganho para
   a partitura. Os valores 96/140/178 sao os do desenho.

   A base e 96 e nao 140 porque consulta de altura sem suporte (ou janela
   realmente curta) deve cair no degrau que sempre cabe, nunca no que nao cabe. */
:root {
  --altura-teclado: 96px;
}

@media (min-height: 700px) {
  :root { --altura-teclado: 140px; }
}

@media (min-height: 900px) {
  #partitura-topo { padding: 8px 16px 4px; }
  #partitura-andamento { font-size: 21px; }

  :root { --altura-teclado: 178px; }
}

#piano-container {
  position: relative;
  margin: 0 16px;
  background: var(--tinta);
  border-radius: var(--raio-xg) var(--raio-xg) 0 0;
  overflow: hidden;
  height: var(--altura-teclado);
  /* O leito das teclas nao encosta na borda do bloco: 14 px em cima e 16 nos
     lados deixam a moldura escura aparecer em volta, que e o que faz o teclado
     parecer assentado no instrumento em vez de colado na tela. Embaixo nao ha
     recuo — as teclas descem ate encontrar o transporte, e os dois formam um
     bloco escuro continuo. */
  padding: 14px 16px 0;
}

#piano-canvas {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: var(--raio-i) var(--raio-i) 0 0;
}

#feedback-container {
  flex: 0 0 auto;
  height: 56px;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}

/* O PAINEL DA PARTITURA.
   ---------------------------------------------------------------------------
   Antes a partitura era uma caixa branca com `--sombra-2` — 4px 14px a 24 % de
   preto, a sombra dos menus flutuantes. Ela dizia "isto paira sobre a tela", e
   a partitura nao paira: ela e a tela. Uma borda fina de `--fio` diz o mesmo
   contorno sem o peso, e o raio sobe de 12 para 18 para casar com o teclado,
   que ja tinha 18 em cima.

   A metade da esquerda e um tom mais quente: `--superficie-2`. A divisa nao
   fica no meio fixo — ela segue `--linha-frac`, a mesma fracao que posiciona a
   linha do agora. O que ja foi lido fica atras dela, o que vem pela frente
   fica na frente, e quem mudar a preferencia de posicao da linha nos ajustes
   move as duas juntas. */
#painel-partitura {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  margin: 0 16px 16px 16px;
  border-radius: var(--raio-xg);
  border: 1px solid var(--fio);
  background:
    linear-gradient(to right,
      var(--superficie-2) 0 calc(var(--linha-frac) * 100%),
      var(--superficie) calc(var(--linha-frac) * 100%) 100%);
  overflow: hidden;
}

/* O cabecalho do painel: o que a peca manda tocar, e onde ela esta agora. */
/* A ALTURA DAQUI E DISPUTADA COM A PAUTA, e a pauta ganha.
   Medido a 1024x768 com o Prelude: a caixa da partitura tem 425 px de folga e
   o sistema desenhado pede 406. Sobram 19. O cabecalho na medida do desenho —
   21 px em Newsreader, com 10 px de recuo em cima — pedia 37, e a pauta passava
   a rolar na vertical numa peca que cabia inteira.
   A fileira que existia antes deste painel, so com o indicador de compasso,
   custava 25. Esta custa menos que ela: o andamento sobe pela caixa alta e nao
   pelo recuo, e a semi­nima e o numero dividem a mesma linha de base. Onde ha
   altura de sobra — a partir de 900 px de janela, o mesmo degrau em que o
   teclado cresce — ele volta aos 21 do desenho. */
#partitura-topo {
  flex: 0 0 auto;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 2px 16px 2px;
}

#partitura-andamento {
  font-family: var(--fonte-titulo);
  font-style: italic;
  font-size: 17px;
  line-height: 1.1;
  color: var(--tinta-media);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* A indicacao de carater, no pe: "dolce", "espressivo". */
#partitura-carater {
  flex: 0 0 auto;
  margin: 0;
  padding: 2px 16px 10px;
  font-family: var(--fonte-titulo);
  font-style: italic;
  font-size: 18px;
  line-height: 1.2;
  color: var(--tinta-fraca);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Banner de Demonstração Guiada da Aula (Modo Cursos) */
.curso-demo-banner {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 16px;
  background: var(--tinta);
  color: var(--escuro-texto);
  border-bottom: 1px solid var(--escuro-fio);
  font-family: var(--fonte-ui);
  font-size: 13px;
  line-height: 1.3;
  z-index: 5;
}

.curso-demo-banner.hidden {
  display: none !important;
}

.curso-demo-info {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  min-width: 0;
}

.curso-demo-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: var(--raio-alt);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.curso-demo-badge.demo {
  background: var(--dominio);
  color: var(--escuro-texto);
}

.curso-demo-badge.pratica {
  background: var(--agora);
  color: var(--escuro-texto);
}

.curso-demo-badge svg {
  width: 14px;
  height: 14px;
}

.curso-demo-titulo {
  font-weight: 600;
  color: var(--escuro-texto);
  white-space: nowrap;
}

.curso-demo-dica {
  color: var(--escuro-legenda);
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 450px;
}

.curso-demo-acoes {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.curso-demo-btn-acao {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: var(--raio-btn);
  border: 1px solid var(--escuro-fio-btn);
  background: var(--escuro-hover);
  color: var(--escuro-texto);
  font-family: var(--fonte-ui);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition-fast), transform var(--transition-fast);
}

.curso-demo-btn-acao:hover {
  background: var(--escuro-trilho);
  border-color: var(--escuro-fio-btn-hover);
}

.curso-demo-btn-acao:active {
  transform: scale(0.97);
}

.curso-demo-btn-acao svg {
  width: 14px;
  height: 14px;
}

@media (max-width: 640px) {
  .curso-demo-dica {
    display: none;
  }
}

/* A pauta e a linha do agora dividem esta caixa, e so ela: antes a linha
   comecava no topo do palco e cruzava o indicador de compasso. */
#painel-corpo {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
}

#score-container {
  flex: 1 1 auto;
  min-width: 0;
  background-color: transparent;
  /* `auto` nos dois eixos, e nao `hidden` na vertical.
     Agora que a faixa da partitura recebe o que sobra em vez de mandar na
     altura, ela pode ficar mais baixa que o sistema desenhado — numa janela de
     500 px de altura sobram cerca de 240 para um sistema de 400. Com `hidden`,
     a pauta de baixo sumia calada; com `auto`, ela continua alcancavel.
     A rolagem horizontal, que o cursor conduz durante a execucao, nao muda:
     sao eixos independentes. */
  overflow-y: auto;
  overflow-x: auto;
  /* Eram 8 px em volta. A folga vertical aqui disputa com a pauta os mesmos
     pixels que o cabecalho do painel, e a pauta ganha: 4 em cima e embaixo
     devolvem os 8 que faltavam para o sistema do Prelude caber inteiro a
     1024x768. Na horizontal os 8 ficam — e ali que a partitura respira da
     borda do painel. */
  padding: 4px 8px;
  color: var(--tinta);
  /* Era 200px. Um piso em pixels aqui e um piso na grade inteira: a faixa `1fr`
     nao consegue encolher abaixo do que este filho exige, e em janela curta o
     que nao cabia saia pela base da tela. */
  min-height: 0;
}

#osmd-container {
  width: max-content;
  height: 100%;
}

/* O transporte: uma fileira, ou duas em tela estreita.
   ---------------------------------------------------------------------------
   Medido antes: a 360x640 esta barra tinha 236 px de altura em SETE fileiras —
   37 % da tela num celular, para uma peca que precisa da tela toda. Ela carregava
   tudo: os sete botoes, o andamento, o indicador de compasso, a ficha de quem
   toca, e uma linha de progresso de 4 px colada no topo.

   O que saiu daqui nao sumiu: foi para onde o desenho o poe. O andamento e a
   ficha de quem toca subiram para a linha de estado do cabecalho; o indicador de
   compasso foi para cima da partitura, que e onde o olho ja esta enquanto se
   toca. Nenhum botao foi removido.

   `align-content: center` alem do `align-items`: com `flex-wrap`, quem centra as
   FILEIRAS entre si e o `align-content`. Sem ele, as duas fileiras da tela
   estreita encostam no topo e sobra um vao embaixo. */
#controls-bar {
  min-height: 76px;
  margin: 0 16px 16px;
  background-color: var(--tinta);
  color: var(--escuro-texto);
  border-top: 1px solid var(--escuro-fio);
  border-radius: 0 0 var(--raio-xg) var(--raio-xg);
  position: relative;
  display: flex;
  flex-direction: row;
  align-items: center;
  align-content: center;
  justify-content: center;
  flex-wrap: wrap;
  padding: 10px 16px;
  gap: 10px;
}

/* O tocar/pausar do transporte ainda nao mora aqui — veja a nota no
   `index.html`. Estas regras esperam por ele. */

/* A barra de progresso e as tres legendas.
   ---------------------------------------------------------------------------
   Em tela larga ela ocupa o que sobra entre os botoes; em tela estreita ela
   toma a fileira inteira e os botoes ficam embaixo. `flex: 1 1 220px` diz as
   duas coisas de uma vez: cresce para ocupar o resto, e quebra a linha quando
   nao couberem 220 px. */
#progresso-caixa {
  flex: 1 1 220px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* TRES CAMADAS, e nao uma linha de 4 px no topo da barra:
     - o trilho, que e o quanto a peca tem;
     - a faixa do laco, que e o trecho em repeticao;
     - a posicao, que e onde a peca esta.
   A do meio e a que faltava, e e a que responde "por que a peca volta sozinha
   ao compasso 9?" sem abrir menu nenhum. */
#progress-container {
  position: relative;
  width: 100%;
  height: 6px;
  border-radius: var(--raio-barra);
  background-color: var(--escuro-trilho);
  overflow: visible;
}

#laco-faixa {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 0;
  border-radius: var(--raio-barra);
  background: var(--laco-faixa);
}

#progress-bar {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  height: 100%;
  width: 0%;
  border-radius: var(--raio-barra);
  background-color: var(--escuro-texto);
  transition: width 0.1s linear;
}

/* A alca de 13 px do desenho. Ela nao recebe toque — o transporte tem os botoes
   de compasso para isso —, entao fica fora do fluxo e sem eventos: e um sinal de
   posicao, e nao um controle disfarcado de controle. */
#progresso-alca {
  position: absolute;
  top: 50%;
  left: 0;
  width: 13px;
  height: 13px;
  margin-left: -6.5px;
  border-radius: 50%;
  background: var(--escuro-texto);
  transform: translateY(-50%);
  pointer-events: none;
  transition: left 0.1s linear;
}

#progresso-legendas {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  font-size: 12px;
  color: var(--escuro-legenda);
  font-variant-numeric: tabular-nums;
}

#laco-legenda {
  flex: 1 1 auto;
  text-align: center;
  color: var(--agora);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#laco-legenda.hidden { display: none; }

/* QUAL PECA ESTA ABERTA — titulo em Newsreader, compositor e trecho embaixo.
   `min-width: 0` com `flex: 1 1 auto` e o que permite o corte por reticencias:
   sem ele um titulo longo empurra os botoes da direita para fora da janela em
   vez de encolher. */
#peca-na-barra {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1px;
}

#peca-na-barra.hidden { display: none; }

#peca-titulo {
  font-family: var(--fonte-titulo);
  font-size: 20px;
  line-height: 1.15;
  color: var(--tinta);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#peca-subtitulo {
  font-size: 13px;
  line-height: 1.2;
  color: var(--tinta-fraca);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#peca-subtitulo:empty { display: none; }

/* O PLACAR, UMA PASTILHA SO.
   Eram tres fichas independentes, cada uma com sua borda e seu fundo. Uma so
   caixa, e dentro dela a porcentagem em `--dominio` e as tres contagens em
   corpo menor, separadas por um fio. */
/* `#stats-display.stats` tem especificidade maior que `.hidden`, entao sem
   esta linha a pastilha ficaria visivel no modo em que ela nem faz sentido —
   o placar so existe no Modo Seguir. */
#stats-display.stats.hidden { display: none; }

#stats-display.stats {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 10px;
  border-radius: var(--raio-i);
  border: 1px solid var(--fio);
  background: var(--superficie);
  white-space: nowrap;
}

#acertos-rotulo {
  font-size: 12px;
  color: var(--tinta-fraca);
}

#acertos-pct {
  font-size: 15px;
  font-weight: 600;
  color: var(--dominio);
  font-variant-numeric: tabular-nums;
}

.tally-grupo {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding-left: 8px;
  border-left: 1px solid var(--fio);
  font-size: 12px;
  color: var(--tinta-fraca);
  font-variant-numeric: tabular-nums;
}

/* A linha de estado do cabecalho. */
#barra-estado {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  overflow: hidden;
}

#barra-estado .chip {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Onde a peca esta, sobre a partitura.
   O ponto em `--agora` e a mesma marca da linha do agora: a cor nunca e a unica
   pista, e o numero esta escrito ao lado. */
#partitura-estado {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  /* O recuo e do `#partitura-topo` agora: eram 22 px porque a linha flutuava
     sobre o palco; dentro do painel ela se alinha com a borda dele. */
  padding: 0;
  white-space: nowrap;
  font-size: 13px;
  color: var(--tinta-fraca);
  font-variant-numeric: tabular-nums;
}

#partitura-estado .ponto-agora {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--agora);
}

/* Em tela estreita o transporte fica com o que se usa TOCANDO, e nada mais.
   ---------------------------------------------------------------------------
   E o que a tela de celular do desenho faz, e nao invencao minha: la o
   transporte tem 64 px e carrega tocar/pausar, uma ficha com o trecho em laco,
   a barra, e o tempo. Recomecar, parar, os dois botoes de compasso e o
   metronomo saem — e vao para o menu `⋯` do cabecalho, que existe em toda
   largura justamente para nao ser um caminho que so aparece no celular.

   `display: none` e nao `visibility`: o botao continua no documento e continua
   respondendo ao `.click()` que o menu dispara, entao nao ha duas versoes da
   mesma acao para se distanciarem.

   A legenda do laco tambem sai daqui: com 328 px de barra nao cabem tres
   legendas. Quem passa a dizer o trecho e o proprio botao de repetir, que
   ganha o intervalo ao lado do icone. */
@media (max-width: 560px) {
  #controls-bar { padding: 10px 12px; gap: 8px; }

  #progresso-caixa { flex: 1 1 100%; order: -1; }

  #controls-bar .transport-group #btn-stop,
  #controls-bar .measure-group #btn-prev-measure,
  #controls-bar .measure-group #btn-next-measure,
  #controls-bar #btn-metronome { display: none; }

  #laco-legenda { display: none; }

  /* O placar saiu daqui: ele e uma pastilha so, e mora no cabecalho. O que
     esta regra fazia — comprimir tres fichas de 286 px para caberem numa
     terceira fileira — deixou de ser preciso quando as tres viraram uma. */

  /* O botao de repetir vira a ficha do desenho: icone mais o intervalo. */
  #btn-loop-toggle {
    width: auto;
    min-width: 44px;
    padding: 0 12px;
    gap: 7px;
  }
}

/* O intervalo dentro do botao de repetir so aparece onde a legenda sai. */
#laco-intervalo { display: none; }
#laco-intervalo.hidden { display: none; }

@media (max-width: 560px) {
  #laco-intervalo:not(.hidden) {
    display: inline;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
  }
}

/* A barra de progresso mora junto do transporte, acima neste arquivo.
   Havia uma SEGUNDA copia destas duas regras aqui — a versao de 4 px colada no
   topo da barra, em verde — e, por vir depois com a mesma especificidade, era
   ela que valia. As tres camadas novas existiam e nao apareciam. */

/* Controls Bar Elements */
.transport-group, .tempo-group, .hand-group, .measure-group {
  display: flex;
  align-items: center;
  gap: 12px;
}

/*
 * 52px, e não 36. O destino é um iPad: a mão volta do teclado e acerta o botão
 * sem que o olho saia da partitura. A Apple recomenda 44pt como mínimo; a
 * folga extra é para o dedo que chega de lado.
 */
.control-btn {
  background: var(--trilho);
  border: none;
  border-radius: var(--raio-btn);
  width: 52px;
  height: 52px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--tinta);
  font-size: 18px;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.control-btn:hover {
  background: var(--escuro-hover);
}

.control-btn:active, .control-btn.active {
  background: var(--dominio);
  color: var(--escuro-texto);
}

/* Custom Range Slider */
input[type=range] {
  -webkit-appearance: none;
  width: 120px;
  background: transparent;
}

input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  height: 16px;
  width: 16px;
  border-radius: 50%;
  background: var(--dominio);
  cursor: pointer;
  margin-top: -6px;
}

input[type=range]::-webkit-slider-runnable-track {
  width: 100%;
  height: 4px;
  cursor: pointer;
  background: var(--trilho);
  border-radius: var(--raio-i);
}

#bpm-display {
  min-width: 3ch;
  font-family: var(--fonte-mono);
}

/* Select */
select {
  background-color: var(--trilho);
  color: var(--tinta);
  border: none;
  padding: 8px 12px;
  border-radius: var(--raio-i);
  font-family: var(--fonte-ui);
  font-size: 14px;
  cursor: pointer;
  outline: none;
}

/* Measure Indicator */
.mono-font {
  font-family: var(--fonte-mono);
  font-size: 14px;
  min-width: 90px;
  text-align: center;
}

/* A tela de entrada foi removida: o app abre no catálogo. O que ela tinha de
   próprio (o cartão, o ícone, a pilha de ações) saiu junto — os botões .btn
   continuam, porque servem ao aviso de erro e à tela de falha do catálogo. */

/* Buttons */
/* Botoes: tres classes, quatro estados.
   ---------------------------------------------------------------------------
   Antes havia `.btn-primary` e `.btn-secondary` com hover e mais nada. Sem
   estado PRESSIONADO, o toque no iPad nao dava retorno nenhum — o dedo cobre o
   botao e o hover nao existe em tela sensivel, entao a pessoa nao sabia se
   acertou o alvo. E o foco herdava um anel de 3 px em latao, cor que saiu do
   desenho.

   Os quatro estados de cada classe: repouso, ponteiro sobre, pressionado, e
   foco por teclado. Pressionado desce 1 px e encurta a sombra — o gesto de
   afundar, que funciona sem ponteiro. O anel de foco e sempre o mesmo: 2 px em
   --dominio com 2 px de afastamento, para a ordem de tabulacao ser legivel.

   Alvo minimo de 44 px em qualquer coisa acionavel, inclusive icone. */

.btn,
.btn-primario,
.btn-secundario {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 16px 26px;
  border-radius: var(--raio-btn);
  font-family: var(--fonte-ui);
  font-size: 16px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background-color var(--transition-fast),
              border-color var(--transition-fast),
              box-shadow var(--transition-fast),
              transform var(--transition-fast);
}

/* Primario: tinta solida. No hover o fundo passa a dominio — este e o gesto de
   cor que a interface toda repete, e por isso nao e brilho nem opacidade. */
.btn-primary,
.btn-primario {
  background-color: var(--tinta);
  color: var(--escuro-texto);
  box-shadow: var(--sombra-2);
}

.btn-primary:hover,
.btn-primario:hover {
  background-color: var(--dominio);
  box-shadow: 0 6px 18px rgba(var(--dominio-rgb), .30);
}

.btn-primary:active,
.btn-primario:active {
  transform: translateY(1px);
  box-shadow: var(--sombra-1);
}

/* Secundario: superficie com fio. No hover o fio escurece, e nada mais — o
   contorno e a unica coisa que muda, para nao competir com o primario. */
.btn-secondary,
.btn-secundario {
  background-color: var(--superficie);
  border-color: var(--fio);
  color: var(--tinta);
  box-shadow: var(--sombra-1);
}

.btn-secondary:hover,
.btn-secundario:hover {
  border-color: var(--fio-forte);
}

.btn-secondary:active,
.btn-secundario:active {
  transform: translateY(1px);
  box-shadow: none;
}

/* Alternancia: trilho cinza, pastilha branca no item ativo. O estado real mora
   em aria-pressed, nao na classe — quem le por voz precisa do mesmo sinal.

   ATENCAO: NADA NO APP RENDERIZA ESTA CLASSE HOJE. A pagina da peca, que e o
   unico lugar com este controle, monta `.peca-trilho > .peca-opcao` — outra
   implementacao do mesmo componente, com outras medidas (44 px de altura contra
   38 aqui) e outra paleta. Sao dois desenhos da mesma coisa, e dois desenhos da
   mesma coisa se afastam calados: os estados que faltavam foram consertados nos
   DOIS, e e a `.peca-opcao` que as verificacoes medem, porque e a que o dedo
   encosta. Unificar as duas e trabalho a parte — mexe na aparencia de uma tela
   que hoje esta certa. */
.alternancia {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--trilho);
  border-radius: var(--raio-p);
}

.alternancia > button {
  min-height: 38px;
  padding: 0 14px;
  border: 1px solid transparent;
  border-radius: var(--raio-alt);
  background: transparent;
  color: var(--tinta-media);
  font-family: var(--fonte-ui);
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color var(--transition-fast),
              color var(--transition-fast),
              border-color var(--transition-fast);
}

.alternancia > button:hover {
  background: var(--tinta-sopro);
  color: var(--tinta);
}

.alternancia > button[aria-pressed="true"] {
  background: var(--superficie);
  border-color: var(--fio);
  color: var(--tinta);
  box-shadow: var(--sombra-1);
}

/* O ITEM JA ATIVO TAMBEM RESPONDE AO PONTEIRO.
   A regra de `:hover` acima e vencida por esta, que vem depois com a mesma
   especificidade — entao passar o ponteiro sobre o item selecionado nao mudava
   nada, e a alternancia parecia travada justo no lugar em que o dedo esta.
   O fio escurece; o fundo nao, porque ele e o que diz que este e o escolhido. */
.alternancia > button[aria-pressed="true"]:hover {
  border-color: var(--fio-forte);
}

/* O PRESSIONAR. Faltava: a pastilha respondia ao ponteiro e ao teclado, e nao
   ao toque — no celular, onde nao ha hover, o botao nao dava sinal nenhum entre
   o dedo encostar e o estado trocar. O afundamento e pequeno de proposito: e um
   trilho de 44 px de altura, e um salto grande ali le como tremor. */
.alternancia > button:active {
  transform: translateY(1px);
  background: var(--tinta-toque);
}

.alternancia > button[aria-pressed="true"]:active {
  background: var(--superficie);
  box-shadow: none;
}

@media (prefers-reduced-motion: reduce) {
  .alternancia > button:active { transform: none; }
}

/* Um anel so, para tudo. Foco de teclado nunca fica invisivel. */
.btn:focus-visible,
.btn-primario:focus-visible,
.btn-secundario:focus-visible,
.alternancia > button:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .btn,
  .btn-primario,
  .btn-secundario,
  .alternancia > button {
    transition: none;
  }
  .btn-primary:active,
  .btn-primario:active,
  .btn-secondary:active,
  .btn-secundario:active {
    transform: none;
  }
}

/* Audio Unlock Overlay */
#audio-unlock-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: var(--veu);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 90;
}

.pulse-anim {
  animation: pulse 2s infinite;
}

@keyframes pulse {
  0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(var(--dominio-rgb), .7); }
  70% { transform: scale(1.05); box-shadow: 0 0 0 15px rgba(var(--dominio-rgb), 0); }
  100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(var(--dominio-rgb), 0); }
}

/* Loading Indicator */
#loading-indicator {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: var(--veu-forte);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  z-index: 110;
  color: var(--escuro-texto);
}

.spinner {
  width: 48px;
  height: 48px;
  border: 4px solid var(--trilho);
  border-top-color: var(--dominio);
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-bottom: 16px;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* Feedback Animations */
@keyframes feedback-pop-in {
  0% { transform: scale(0); opacity: 0; }
  60% { transform: scale(1.3); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

@keyframes feedback-fade-out {
  0% { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes feedback-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(4px); }
}

/* O sinal de acerto e erro fica sobre a linha do agora, no alto da partitura:
   é onde o olho de quem toca já está. A faixa própria que existia entre o
   teclado e a partitura sumiu — ninguém olhava para lá. */
.feedback-wrapper {
  position: absolute;
  left: calc(16px + (100% - 32px) * var(--linha-frac));
  top: 26px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  pointer-events: none;
  z-index: 4;
}

.feedback-icon {
  font-size: 32px;
  font-weight: bold;
  filter: drop-shadow(var(--sombra-2));
}

/*
 * Sem `feedback-fade-out` embutido na animação. Quem decide quando o sinal sai
 * é o JS, porque a resposta depende do modo: no Modo de espera o X fica até a
 * nota certa chegar, já que foi ele quem parou a música.
 */
.feedback-correct {
  animation: feedback-pop-in var(--transition-fast) ease-out forwards;
}

.feedback-wrong {
  animation: feedback-pop-in var(--transition-fast) ease-out forwards,
             feedback-shake 300ms ease-in-out;
}

.feedback-fadeout {
  animation: feedback-fade-out var(--transition-normal) ease-in forwards;
}

.feedback-streak {
  background: var(--veu-forte);
  color: var(--escuro-texto);
  padding: 5px 13px;
  border-radius: 16px;
  font-family: var(--fonte-mono);
  font-weight: bold;
  font-size: 17px;
}

/* A faixa antiga do feedback não guarda mais nada. Some, em vez de reservar
   56px de altura — no iPad em pé essa altura faz falta à partitura. */
#feedback-container {
  height: 0;
  overflow: visible;
}

/* Utility Classes */
.hidden {
  display: none !important;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

.fade-in {
  animation: fadeIn var(--transition-normal) forwards;
}

.fade-out {
  animation: fadeOut var(--transition-normal) forwards;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes fadeOut {
  from { opacity: 1; }
  to { opacity: 0; }
}

/* Telas estreitas — iPad em pé, sobretudo.
 *
 * Aqui havia um `.control-btn { width: 32px }`, que encolhia o alvo de toque
 * justamente no aparelho onde se toca com o dedo. Era remendo para a barra
 * caber: ela carregava tudo, precisava de 1030px e estourava. Agora o que não
 * se usa tocando mora nos menus, a barra cabe, e o botão pode ter o tamanho
 * que a mão precisa. O que sobra aqui é só apertar o espaçamento.
 */
@media (max-width: 1024px) {
  #controls-bar {
    padding: 10px 12px;
    gap: 8px;
  }

  #app-bar {
    padding: 10px 6px;
    gap: 4px;
  }

  /* A 360 px o cabecalho tem sete alvos de toque — voltar, o selo de ajustes,
     e os cinco da direita — e 7 x 52 nao cabe em 360. Em 44, que e o minimo
     que a mao pede, cabe: 308 de botao, 24 de vao e 16 de recuo dao 348.
     Medido antes: 416 px de conteudo em 360 de janela, com a pagina rolando
     de lado. */
  #app-bar .icon-btn {
    width: 44px;
    height: 44px;
    min-width: 44px;
  }


  /* A linha de estado sai do cabecalho a 360: o andamento e a ficha de quem
     toca sao texto, e texto perde para alvo de toque quando so um cabe. O
     andamento continua no menu de modo e velocidade, e o silencio do Modo
     Seguir continua dito pela ficha do transporte. */
  #barra-estado { display: none; }

  .mono-font {
    font-size: 12px;
  }
}

/* Library Overlay */
/* `fixed`, e não `absolute`: em `absolute` a sobreposição herdava a altura do
   conteúdo da página, que é menor que a tela, e as abas do catálogo paravam
   799px abaixo do topo numa tela de 1024 — com faixa morta embaixo delas. */
#library-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: var(--fundo);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  z-index: 105;
  display: flex;
  justify-content: center;
  align-items: center;
}

/* ==========================================================================
   A página da peça — trechos e escolhas antes da primeira nota
   ========================================================================== */

#peca-overlay {
  /* `fixed`, pelo mesmo motivo do catálogo: em `absolute` a sobreposição herda
     a altura do conteúdo da página, que é menor que a tela, e a coluna para no
     meio com faixa morta embaixo. */
  position: fixed;
  inset: 0;
  z-index: 106;
  background: var(--fundo);
  display: flex;
  justify-content: center;
  overflow-y: auto;
}

#peca-overlay.hidden { display: none; }

.peca {
  width: 100%;
  max-width: 1100px;
  padding: 20px 24px 40px;
}

.peca-topo {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 18px;
}

.peca-voltar {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 14px;
  border: none;
  border-radius: var(--raio-i);
  background: transparent;
  color: var(--tinta-media);
  font-family: var(--fonte-ui);
  font-size: 15px;
  cursor: pointer;
}

.peca-voltar:hover { background: var(--superficie); color: var(--tinta); }
.peca-voltar:focus-visible { outline: 2px solid var(--dominio); outline-offset: 2px; }

.peca-nivel {
  font-size: 13px;
  color: var(--tinta-fraca);
}

/* Uma coluna até 899, duas acima.
   A coluna da capa tem 428 px no desenho, e abaixo de ~900 de largura isso não
   deixa espaço para a lista de trechos, que é o conteúdo principal desta tela.
   Empilhado, a capa vira uma faixa e os trechos ficam com a largura toda. */
.peca-corpo {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 28px;
  align-content: start;
}

@media (min-width: 900px) {
  .peca-corpo {
    grid-template-columns: 380px minmax(0, 1fr);
    gap: 44px;
  }
}

.peca-lado {
  display: flex;
  flex-direction: column;
  gap: 18px;
  min-width: 0;
}

.peca-capa {
  width: 100%;
  aspect-ratio: 3 / 2;
  height: auto;
  border-radius: var(--raio-xg);
  overflow: hidden;
}

/* O gesto de cor que a interface repete: tinta em repouso, domínio ao toque. */
.peca-comecar {
  min-height: 64px;
  padding: 0 24px;
  border: none;
  border-radius: var(--raio-btn);
  background: var(--tinta);
  color: var(--escuro-texto);
  font-family: var(--fonte-ui);
  font-size: 17px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition-fast);
}

.peca-comecar:hover { background: var(--dominio); }
.peca-comecar:focus-visible { outline: 2px solid var(--dominio); outline-offset: 3px; }

.peca-selo {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  border-radius: var(--raio-i);
  background: var(--superficie);
  font-size: 13px;
  line-height: 1.45;
  color: var(--tinta-fraca);
}

.peca-selo-ponto {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  margin-top: 6px;
  border-radius: 50%;
  background: var(--dominio);
}

.peca-selo.sem-midi .peca-selo-ponto { background: var(--tinta-fantasma); }

/* O selo do teclado deixou de ser so uma frase: agora ele carrega a acao que
   resolve o estado em que esta, e a dica de como testar. */
.peca-midi {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

.peca-midi-acao {
  min-height: 44px;
  padding: 10px 16px;
  border-radius: var(--raio-btn);
  border: 1px solid var(--dominio);
  background: transparent;
  color: var(--dominio);
  font-family: var(--fonte-ui);
  font-size: 14px;
  cursor: pointer;
}

.peca-midi-acao:hover { background: var(--dominio-fraco); }

.peca-midi-acao:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: 2px;
}

.peca-midi-dica {
  margin: 0;
  font-size: 13px;
  color: var(--tinta-fraca);
}

.peca-principal {
  display: flex;
  flex-direction: column;
  gap: 26px;
  min-width: 0;
}

.peca-cabeca { display: flex; flex-direction: column; gap: 6px; }

.peca-opus {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--dominio);
}

.peca-titulo {
  font-family: var(--fonte-titulo);
  font-size: clamp(30px, 4.4vw, 44px);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.peca-compositor { font-size: 16px; color: var(--tinta-fraca); }

.peca-dados {
  display: flex;
  flex-wrap: wrap;
  gap: 20px 38px;
  padding: 18px 0;
  border-top: 1px solid var(--fio);
  border-bottom: 1px solid var(--fio);
}

.peca-dado { display: flex; flex-direction: column; gap: 6px; }

.peca-dado-rotulo {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--tinta-fraca);
}

.peca-dado-valor {
  font-family: var(--fonte-titulo);
  font-size: 24px;
  font-variant-numeric: tabular-nums;
}

/* Empurrado para a direita quando há espaço; na primeira linha quando não há.
   `margin-left: auto` num container que quebra linha empurra o item para a
   ponta da SUA linha, o que é o certo nos dois casos. */
.peca-progresso { margin-left: auto; }
.peca-progresso .peca-dado-valor { color: var(--dominio); }

.peca-barras { display: flex; align-items: center; gap: 4px; height: 24px; }

.peca-barras span {
  width: 18px;
  height: 5px;
  border-radius: var(--raio-barra);
  background: var(--trilho);
}

.peca-barras span.cheia { background: var(--dominio); }

/* --- os trechos ---------------------------------------------------------- */

.peca-trechos { display: flex; flex-direction: column; gap: 12px; }

.peca-trechos-topo {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
}

.peca-trechos-topo h3 {
  font-family: var(--fonte-titulo);
  font-size: 24px;
  font-weight: 400;
}

.peca-trechos-dica { font-size: 13px; color: var(--tinta-fraca); }

.peca-trechos-vazio {
  max-width: 62ch;
  font-size: 14px;
  line-height: 1.5;
  color: var(--tinta-fraca);
}

.peca-trechos-lista { display: flex; flex-direction: column; gap: 8px; }

.peca-trecho {
  display: flex;
  align-items: center;
  gap: 20px;
  width: 100%;
  min-height: 56px;
  padding: 14px 18px;
  border: 1px solid var(--fio);
  border-radius: var(--raio-btn);
  background: var(--superficie);
  color: var(--tinta);
  font-family: var(--fonte-ui);
  font-size: 15px;
  text-align: left;
  cursor: pointer;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}

.peca-trecho:hover { border-color: var(--fio-forte); }
.peca-trecho:focus-visible { outline: 2px solid var(--dominio); outline-offset: 2px; }

.peca-trecho-compassos {
  flex: 0 0 auto;
  width: 62px;
  color: var(--tinta-fraca);
  font-variant-numeric: tabular-nums;
}

.peca-trecho-nome {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.peca-trecho-trilho {
  flex: 0 0 auto;
  width: 120px;
  height: 5px;
  border-radius: var(--raio-barra);
  background: var(--trilho);
  overflow: hidden;
}

.peca-trecho-feito {
  display: block;
  height: 100%;
  border-radius: var(--raio-barra);
  background: var(--dominio);
}

.peca-trecho-estado {
  flex: 0 0 auto;
  width: 84px;
  text-align: right;
  font-size: 13px;
  color: var(--tinta-fraca);
  font-variant-numeric: tabular-nums;
}

.peca-trecho.dominado .peca-trecho-estado { color: var(--dominio); }

.peca-trecho.em-curso {
  border-width: 1.5px;
  border-color: var(--dominio);
}

.peca-trecho.em-curso .peca-trecho-nome { font-weight: 600; }
.peca-trecho.em-curso .peca-trecho-estado { color: var(--tinta-fraca); }

/* O escolhido, que é para onde o botão vai abrir. Fundo, e não só borda: a
   borda já distingue "em curso", e duas bordas verdes diferentes na mesma
   lista não se leem de relance. */
.peca-trecho.escolhido {
  background: var(--dominio-fraco);
  border-color: var(--dominio);
}

/* Em tela estreita a linha do trecho quebra em duas, com a barra e o estado
   embaixo: espremidos numa linha só, o nome ficaria com 40 px. */
@media (max-width: 560px) {
  .peca-trecho {
    flex-wrap: wrap;
    gap: 8px 14px;
  }

  .peca-trecho-nome { flex: 1 1 100%; order: -1; }
  .peca-trecho-trilho { flex: 1 1 auto; width: auto; }
}

/* --- as três alternâncias ------------------------------------------------ */

.peca-alternancias { display: flex; flex-direction: column; gap: 16px; }

.peca-grupo { display: flex; flex-direction: column; gap: 8px; }

.peca-grupo-rotulo {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--tinta-fraca);
}

.peca-trilho {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  border-radius: var(--raio-p);
  background: var(--trilho);
  max-width: 100%;
  flex-wrap: wrap;
}

.peca-opcao {
  min-height: 44px;
  padding: 0 18px;
  border: none;
  border-radius: var(--raio-alt);
  background: transparent;
  color: var(--tinta-fraca);
  font-family: var(--fonte-ui);
  font-size: 14px;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.peca-opcao:hover:not(.on):not(:disabled) { color: var(--tinta); }
.peca-opcao:focus-visible { outline: 2px solid var(--dominio); outline-offset: 2px; }

.peca-opcao.on {
  background: var(--superficie);
  color: var(--tinta);
  font-weight: 600;
}

/* Impedido, e não escondido: o aluno precisa saber que Esperar e Seguir
   existem, e por que não dá para escolhê-los agora. O motivo está no `title`,
   e o selo do teclado ao lado diz a mesma coisa por extenso. */
.peca-opcao:disabled {
  color: var(--tinta-fraca);
  cursor: not-allowed;
  opacity: 0.6;
}

/* O ITEM JA ESCOLHIDO TAMBEM RESPONDE, e o toque tambem tem resposta.
   O `:hover` acima traz o `:not(.on)`, entao passar o ponteiro sobre o item
   selecionado nao mudava nada — a alternancia parecia travada justo onde o dedo
   esta. E nao havia `:active` nenhum: no celular, onde nao ha ponteiro, entre
   encostar e a escolha trocar o botao nao dava sinal algum.
   O fio escurece no escolhido; o fundo nao, porque e ele que diz que este e o
   escolhido. O afundamento e de 1 px de proposito — num trilho de 44 px, salto
   maior le como tremor. */
.peca-opcao.on:hover {
  box-shadow: 0 0 0 1px var(--fio-forte);
}

.peca-opcao:active:not(:disabled) {
  transform: translateY(1px);
  background: var(--tinta-toque);
}

.peca-opcao.on:active {
  background: var(--superficie);
}

@media (prefers-reduced-motion: reduce) {
  .peca-opcao:active:not(:disabled) { transform: none; }
}

/* ==========================================================================
   O catálogo — Início, Músicas e Busca
   ========================================================================== */

.catalogo {
  width: 100%;
  max-width: 1100px;
  height: 100%;
  max-height: 100%;
  background: var(--fundo);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.catalogo-topo {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 18px 20px 10px;
}

.catalogo-topo h2 {
  font-size: 26px;
  font-weight: 600;
}

.catalogo-acoes {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
}

.catalogo-carregar {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 52px;
  padding: 12px 18px;
  border-radius: var(--raio-btn);
  border: 1px solid var(--dominio);
  background: transparent;
  color: var(--dominio);
  font-family: var(--fonte-ui);
  font-size: 14px;
  cursor: pointer;
}

/* NO CELULAR OS QUATRO VIRAM ICONE.
   ---------------------------------------------------------------------------
   MEDIDO a 390 px, com o quarto botao: a barra ia de 98 a 538 — Ajuda e
   Primeira vista inteiramente fora da tela, e a pagina NAO rola de lado, entao
   os dois eram inalcancaveis, nao apenas deslocados.
   Quatro alvos de 44 px mais tres vaos de 8 dao 200: cabem em 390 com o titulo
   do lado. O rotulo sai; o nome nao — ele esta no `aria-label`, e quem le por
   voz continua ouvindo "Ajuda". */
@media (max-width: 560px) {
  .catalogo-acoes { gap: 8px; }

  .catalogo-carregar {
    width: 44px;
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    justify-content: center;
  }

  .catalogo-carregar .rotulo { display: none; }
}

.catalogo-carregar:hover {
  background: var(--dominio-fraco);
}

.catalogo-carregar:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: 3px;
}

.catalogo-carregar span {
  font-size: 17px;
  line-height: 1;
}

.catalogo-corpo {
  flex: 1 1 auto;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 0 20px 20px;
}

.catalogo-secao {
  margin-top: 22px;
}

.catalogo-secao h3 {
  font-size: 13px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--tinta-fraca);
  margin-bottom: 12px;
}

/* A prateleira e a grade sao a mesma lista, contada de outro jeito.
   ---------------------------------------------------------------------------
   Era `repeat(auto-fill, minmax(300px, 1fr))`: uma regra so, que decidia
   sozinha quantas colunas cabiam. Com o cartao deitado de 98 px isso passava;
   com a vitrine 3:2 nao passa, porque o numero de colunas deixa de ser questao
   de caber e passa a ser questao de quanto a capa precisa medir para mostrar a
   peca. Em 1440 px, `auto-fill` daria quatro colunas de 350 — capas enormes
   para uma lista que se percorre. As faixas fixam o numero.

   Ate 767 px nem grade e: e prateleira que rola de lado, com um pedaco do
   cartao seguinte a vista. Esse pedaco e o indicio de que ha mais — sem ele, a
   prateleira parece uma lista que acabou. */
.catalogo-lista {
  display: grid;
  gap: 16px;
  grid-auto-flow: column;
  grid-auto-columns: 78%;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  /* Sem isto a lista mede pela soma dos cartoes e empurra a pagina inteira
     para o lado, em vez de rolar por dentro. E a mesma armadilha do
     `minmax(0, 1fr)` do `#main-view`: faixa que nao declara o minimo nao
     encolhe. */
  min-width: 0;
  /* A folga a direita e o que deixa o ultimo cartao encostar na margem, e nao
     colar na borda da tela quando a rolagem chega ao fim. */
  padding-right: 20px;
  margin-right: -20px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}

.catalogo-lista > * {
  scroll-snap-align: start;
}

@media (min-width: 768px) {
  .catalogo-lista {
    grid-auto-flow: row;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-auto-columns: auto;
    overflow-x: visible;
    overflow-y: visible;
    scroll-snap-type: none;
    gap: 22px;
    padding-right: 0;
    margin-right: 0;
  }
}

@media (min-width: 1024px) {
  .catalogo-lista { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 1280px) {
  .catalogo-lista { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* O cartão é um <button>: responde a toque, teclado e leitor de tela. */
/* A vitrine: a capa em cima, o texto embaixo.
   ---------------------------------------------------------------------------
   O cartao era deitado — 98 px de altura, capa de 110x74 a esquerda, texto a
   direita. Naquele tamanho a capa nao mostrava a peca: era um selo colorido.
   E o texto, espremido no que sobrava, truncava o titulo quase sempre.

   Em pe, a capa ocupa a largura do cartao em 3:2, que e a proporcao em que as
   fotos de `assets/capas/` foram baixadas — entram sem corte. O titulo ganha a
   largura inteira, e a duracao sai da linha de texto para um selo sobre a capa. */
.library-card {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  width: 100%;
  padding: 0;
  overflow: hidden;
  /* Ancora do selo de duracao e do botao de excluir, que passaram a flutuar
     sobre a capa em vez de disputar lugar na linha do texto. */
  position: relative;
  text-align: left;
  background: var(--superficie);
  border: 1px solid var(--trilho);
  border-radius: var(--raio-btn);
  color: var(--tinta);
  font-family: var(--fonte-ui);
  cursor: pointer;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}

.library-card:hover {
  background: var(--trilho);
  border-color: var(--dominio);
}

.library-card:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: 3px;
}

.card-capa {
  flex: 0 0 auto;
  /* 3:2, que e a proporcao das fotos: assim elas entram sem corte violento.
     As capas sao baixadas a 400px de largura justamente por isso. */
  width: 100%;
  aspect-ratio: 3 / 2;
  height: auto;
  border-radius: 0;
  background: linear-gradient(140deg, var(--capa-1), var(--capa-2));
  color: var(--dominio);
  font-size: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.card-texto {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  flex: 1 1 auto;
  padding: 12px 14px 14px;
}

/* Duas linhas, e nao uma com reticencias.
   Os titulos deste acervo sao longos por natureza — "Sonatina Op. 36 No. 1,
   Mov. 2" — e numa linha so praticamente todos terminavam em "…", o que
   apagava justamente o que distingue um movimento do outro. Com duas linhas e
   `line-clamp`, o corte so acontece quando o titulo passa mesmo de duas. */
.card-title {
  font-size: 16px;
  font-weight: 600;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

.card-composer {
  font-size: 14px;
  color: var(--tinta-fraca);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* O selo de duracao, sobre a capa. Fundo escuro proprio, e nao transparencia
   da tinta: por baixo dele pode passar tanto uma fotografia clara quanto uma
   escura, e so um fundo opaco garante o contraste nas duas. */
.card-duracao {
  position: absolute;
  top: 8px;
  left: 8px;
  /* Acima de 3, que e a camada da fotografia (`.card-capa-foto`): com 2, o
     selo ficava DEBAIXO da foto e simplesmente nao aparecia nas pecas que tem
     capa fotografica — que sao quase todas. */
  z-index: 4;
  padding: 3px 8px;
  border-radius: var(--raio-alt);
  background: var(--veu-capa);
  color: var(--escuro-texto);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.4;
  font-variant-numeric: tabular-nums;
}

/* A regua de dificuldade fecha o cartao, alinhada a direita.
   No cartao deitado ela era a terceira coluna; em pe, uma faixa propria — sem
   a folga de baixo ela encostaria na borda do cartao. */
.card-difficulty {
  flex: 0 0 auto;
  align-self: flex-end;
  padding: 0 14px 12px;
  font-size: 10px;
  letter-spacing: 1px;
  color: var(--dominio);
}

/* Filtros */
.filtro-bloco {
  margin-top: 16px;
}

.filtro-rotulo {
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--tinta-fraca);
  margin-bottom: 8px;
}

.filtro-faixa {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.filtro-pilula {
  min-height: 44px;
  padding: 10px 16px;
  border-radius: 999px;
  border: 1px solid var(--trilho);
  background: var(--superficie);
  color: var(--tinta-fraca);
  font-family: var(--fonte-ui);
  font-size: 13px;
  cursor: pointer;
}

.filtro-pilula.on {
  color: var(--dominio);
  border-color: var(--dominio);
  background: var(--dominio-fraco);
}

.filtro-pilula:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: 2px;
}

/* Campo de busca */
.catalogo-campo-busca {
  width: 100%;
  margin-top: 8px;
  padding: 15px 16px;
  border-radius: var(--raio-btn);
  border: 1px solid var(--trilho);
  background: var(--superficie);
  color: var(--tinta);
  font-family: var(--fonte-ui);
  font-size: 16px;
}

.catalogo-campo-busca:focus {
  outline: none;
  border-color: var(--dominio);
}

.library-empty {
  color: var(--tinta-fraca);
  text-align: center;
  padding: 48px 20px;
}

/* Abas, embaixo, onde o polegar alcanca.
   O `order` e o que as manda para a base: no DOM elas vem PRIMEIRO, para que a
   tabulacao alcance o menu antes dos cartoes (veja o comentario em
   `library-browser.js`). Aqui a coluna flex as devolve ao rodape, onde o dedo
   as procura — `order` muda a pintura, nunca a ordem de foco. */
.catalogo-abas {
  order: 3;
  flex: 0 0 auto;
  display: flex;
  border-top: 1px solid var(--trilho);
  background: var(--superficie);
}

.catalogo-aba {
  flex: 1;
  min-height: 60px;
  padding: 10px 4px 12px;
  border: none;
  background: transparent;
  color: var(--tinta-fraca);
  font-family: var(--fonte-ui);
  font-size: 11px;
  cursor: pointer;
}

.catalogo-aba .glifo {
  display: block;
  font-size: 20px;
  margin-bottom: 3px;
}

.catalogo-aba.on {
  color: var(--dominio);
}

.catalogo-aba:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: -3px;
}

/* A navegacao do catalogo troca de POSICAO, nao de conteudo.
   ---------------------------------------------------------------------------
   Ate 1023 px ela e a barra de abas acima: tres itens colados na base, onde o
   polegar alcanca. De 1024 em diante o polegar deixa de ser a medida — a mao
   esta no mouse ou no teclado, a tela e larga, e uma barra deitada na base
   desperdica largura e obriga o olho a ir ao rodape para trocar de secao. Ela
   levanta e vira coluna a esquerda.

   E a MESMA marcacao: os mesmos tres <button> dentro do mesmo <nav>, montados
   uma vez so pelo `_barraDeAbas()`. Nada aqui e duplicado, escondido ou
   remontado na troca de faixa — o que muda e onde a grade os coloca. Duas
   arvores para o mesmo menu seriam duas para manter, e a que nao esta na tela
   e a que apodrece.

   A COLUNA E `auto`, E NAO `236px`, de proposito. A tela de falha do catalogo
   (`render()` quando `this.catalog` e nulo) monta topo e corpo mas nao monta
   `<nav>` nenhum — ela e a saida de emergencia quando o library.json nao
   carrega. Com a coluna fixa em 236 px, essa tela ganharia uma faixa branca
   vazia de 236 px a esquerda da mensagem de erro. Com `auto`, a coluna sem
   conteudo mede zero e a mensagem ocupa a tela toda, que e o que ela precisa. */
@media (min-width: 1024px) {
  .catalogo {
    /* O teto de 1100 px servia a uma coluna so. Com a lateral ocupando 236, o
       conteudo cairia para 864 px e a grade de tres cartoes ficaria apertada
       justamente onde ha tela sobrando. */
    max-width: none;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas:
      "navegacao topo"
      "navegacao corpo";
  }

  .catalogo-topo {
    grid-area: topo;
    padding: 28px 32px 12px;
  }

  .catalogo-corpo {
    grid-area: corpo;
    padding: 0 32px 28px;
  }

  .catalogo-abas {
    grid-area: navegacao;
    width: 236px;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 2px;
    padding: 28px 22px 22px;
    border-top: none;
    border-right: 1px solid var(--fio);
  }

  .catalogo-aba {
    /* Deitada, `flex: 1` reparte a largura entre as abas. Em pe, repartiria a
       ALTURA: tres itens de um terco da coluna cada, esticados ate o rodape. */
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 46px;
    padding: 0 14px;
    border-radius: var(--raio-i);
    font-size: 15px;
    text-align: left;
    color: var(--tinta-media);
  }

  .catalogo-aba .glifo {
    display: inline-flex;
    align-items: center;
    font-size: 18px;
    margin-bottom: 0;
  }

  .catalogo-aba:hover:not(.on) {
    background: var(--fundo);
    color: var(--tinta);
  }

  .catalogo-aba.on {
    background: var(--dominio-fraco);
    color: var(--dominio);
    font-weight: 600;
  }

  .catalogo-aba:focus-visible {
    /* Deitada, o anel ia para dentro (`-3px`) porque a aba encosta na borda da
       tela. Em pe ela e um item com raio e folga em volta: o anel cabe fora. */
    outline-offset: 2px;
  }
}

/* Acima de 1280 a lateral ganha 28 px. Nao e enfeite: e onde a grade de
   cartoes passa de tres para quatro colunas, e o rotulo mais longo do menu
   deixa de precisar quebrar. */
@media (min-width: 1280px) {
  .catalogo-abas {
    width: 264px;
  }
}

/* O cartao de continuar — a peca que ficou pela metade.
   ---------------------------------------------------------------------------
   Nao e um `.library-card` maior: e outra coisa. O cartao da lista responde
   "que peca e esta?"; este responde "onde eu parei?", e por isso carrega barra
   de progresso, compasso e velocidade, que nenhum cartao da lista tem.

   Deitado de proposito, e sozinho no topo: e o unico cartao da tela que nao
   disputa a leitura com outro igual a ele. */
.cartao-continuar {
  display: flex;
  align-items: center;
  gap: 0;
  margin-top: 22px;
  background: var(--superficie);
  border: 1px solid var(--fio);
  border-radius: var(--raio-g);
  overflow: hidden;
}

.continuar-capa {
  /* A capa aqui e larga e fixa, e nao 3:2 de largura inteira como na vitrine:
     `.card-capa` sozinha esticaria para 100% e engoliria o cartao. */
  flex: 0 0 auto;
  width: 180px;
  aspect-ratio: 3 / 2;
  height: auto;
  border-radius: 0;
}

.continuar-corpo {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1 1 auto;
  min-width: 0;
  padding: 20px 24px;
}

.continuar-rotulo {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--dominio);
}

.continuar-nome {
  font-family: var(--fonte-titulo);
  font-size: 26px;
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--tinta);
  text-wrap: balance;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.continuar-trilho {
  width: min(230px, 100%);
  height: 5px;
  margin-top: 4px;
  border-radius: var(--raio-barra);
  background: var(--trilho);
  overflow: hidden;
}

.continuar-feito {
  display: block;
  height: 100%;
  border-radius: var(--raio-barra);
  background: var(--dominio);
}

.continuar-legenda {
  font-size: 13px;
  color: var(--tinta-fraca);
  font-variant-numeric: tabular-nums;
}

/* O gesto de cor que a interface repete: o botao e tinta em repouso e vira
   dominio ao toque. */
.continuar-btn {
  flex: 0 0 auto;
  min-height: 56px;
  margin: 0 24px;
  padding: 0 28px;
  border: none;
  border-radius: var(--raio-btn);
  background: var(--tinta);
  color: var(--escuro-texto);
  font-family: var(--fonte-ui);
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition-fast);
}

.continuar-btn:hover {
  background: var(--dominio);
}

.continuar-btn:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: 3px;
}

/* Em tela estreita o cartao vira coluna: deitado, sobrariam 60 px para o nome
   da obra entre a capa e o botao. */
@media (max-width: 640px) {
  .cartao-continuar {
    flex-direction: column;
    align-items: stretch;
  }

  .continuar-capa {
    width: 100%;
  }

  .continuar-btn {
    margin: 0 20px 20px;
  }
}

/* A proposta de repetir o trecho que nao saiu.
   ---------------------------------------------------------------------------
   Vive dentro do transporte, sobre o bloco escuro, e nao numa janela por cima
   da partitura: quem esta tocando nao pode ser parado por um aviso. Por isso
   ela e uma faixa, e nao um dialogo — nada aqui recebe foco a forca, nada
   escurece o resto, e a execucao continua enquanto ela esta na tela.

   O fundo e `--agora` esmaecido, e nao o verde de dominio: e a cor que este app
   usa para "aqui, agora" — a linha do agora e a nota que soa. Verde diria
   "conseguiu", que e o contrario do que acabou de acontecer. */
#proposta-laco {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px 6px 14px;
  border-radius: var(--raio-i);
  background: var(--agora-sobre-escuro);
  border: 1px solid var(--laco-faixa);
  color: var(--escuro-texto);
  font-size: 13px;
  line-height: 1.35;
}

#proposta-laco.hidden { display: none; }

#proposta-laco-texto {
  min-width: 0;
  font-variant-numeric: tabular-nums;
}

#btn-aceitar-laco {
  flex: 0 0 auto;
  min-height: 44px;
  padding: 0 14px;
  border: none;
  border-radius: var(--raio-alt);
  background: var(--escuro-texto);
  color: var(--tinta);
  font-family: var(--fonte-ui);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

#btn-aceitar-laco:hover { background: var(--agora); color: var(--escuro-texto); }

/* 44x44, como todo alvo de toque deste app.
   Escrevi este botao com 36 e um comentario explicando por que ali podia ser
   menor: dispensar acontece sozinho em doze segundos, e um alvo grande ao lado
   do botao que interessa convidaria ao toque errado. O argumento e razoavel e
   nao vale — a regra dos 44 px esta escrita no projeto e e VERIFICADA, e um
   botao que a pessoa de fato toca precisa do tamanho que a mao pede. Quem quer
   os dois botoes menos vizinhos afasta um do outro, e nao encolhe um deles. */
#btn-dispensar-laco {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  margin-left: 2px;
  border: none;
  border-radius: var(--raio-alt);
  background: transparent;
  color: var(--escuro-icone);
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
}

#btn-dispensar-laco:hover { background: var(--escuro-hover); color: var(--escuro-texto); }

#proposta-laco button:focus-visible {
  outline: 2px solid var(--escuro-texto);
  outline-offset: 2px;
}

/* Piano Roll Container */
#piano-roll-container {
  width: 100%;
  height: 100%;
  background-color: var(--fundo);
  border-radius: var(--raio-i);
  overflow: hidden;
}

#piano-roll-container canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* ==========================================================================
   Interface de toque — barra superior, linha do agora e menus
   ========================================================================== */

:root {
  /*
   * Onde a linha do agora fica, em fração da largura visível da partitura.
   * O usuário escolhe entre 0.5 (meio) e 0.35 (um terço, sobra leitura à
   * frente). O followCursor() do renderer lê exatamente este mesmo número —
   * se os dois discordarem, a linha deixa de cair sobre a nota que soa.
   */
  --linha-frac: 0.5;
}

/* Barra superior --------------------------------------------------------- */
#app-bar {
  flex: 0 0 auto;
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  min-height: 72px;
  background: var(--superficie);
  border-bottom: 1px solid var(--trilho);
}

#app-bar .bar-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
}

/* O vao aperta a 560 px. Esta regra mora AQUI, e nao na consulta de 1024 la em
   cima, porque `#app-bar .bar-right` aparece duas vezes no arquivo com a mesma
   especificidade — e a de baixo ganha. A primeira versao ficou escrita e sem
   efeito, e so a medicao mostrou: o aglomerado continuava com 260 px. */
@media (max-width: 560px) {
  #app-bar .bar-right { gap: 4px; }

  /* MEDIDO a 360 px: com o titulo e o botao de tocar em fluxo, a fileira pedia
     mais que a janela e a pagina rolava de lado. O que sai e o titulo.
     Nao e uma escolha entre "titulo" e "botao": o desenho poe o player do
     celular so em paisagem, onde a janela passa dos 560 e o titulo volta; e
     em retrato quem acabou de escolher a peca vem da pagina dela, que traz o
     nome em corpo 28. O botao de tocar cai para 52 px, que e o tamanho que o
     desenho da a ele no transporte, e continua acima dos 44 do dedo. */
  #peca-na-barra { display: none; }


  /* A 360 px o cabecalho nao tem onde por a pastilha. MEDIDO: em fluxo sobram
     16 px depois do voltar, do selo de ajustes e dos cinco botoes da direita —
     e o menor alvo que a mao aceita tem 44. Com ela, a barra ia a 478 px numa
     janela de 360 e a pagina rolava de lado.

     Some pelo mesmo motivo que o titulo: o desenho poe o player do celular so
     em paisagem, onde a janela passa dos 560 e a pastilha volta. E o placar
     nao se perde — ele reaparece inteiro, com as tres contagens, no resumo ao
     fim da sessao. O que estas duas linhas evitam e o contrario disso: uma
     pastilha espremida a 30 px, ilegivel, empurrando a barra para fora da
     tela. */
  #stats-display.stats { display: none; }

  /* O compositor cede a vez ao titulo, que e o que identifica a peca. O
     trecho em repeticao continua dito pelo proprio botao de repetir. */
  #peca-subtitulo { display: none; }
  #peca-titulo { font-size: 17px; }
}

.icon-btn {
  width: 52px;
  height: 52px;
  border-radius: var(--raio-btn);
  border: 1px solid var(--trilho);
  background: var(--trilho);
  color: var(--tinta-fraca);
  font-size: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}

.icon-btn:hover { color: var(--tinta); }

.icon-btn.on {
  color: var(--dominio);
  border-color: var(--dominio);
}

/* Mão apagada: a nota continua na tela, mas o app não a toca nem a cobra. */
.hand-btn:not(.on) { opacity: 0.45; }

/* TOCAR/PAUSAR, no transporte.
   ---------------------------------------------------------------------------
   O desenho: circulo de 52 px, branco, icone em `--tinta`, o primeiro controle
   da esquerda no bloco escuro. Branco sobre `--tinta` e o maior contraste que o
   bloco tem, e e o botao que mais se aperta — o olho acha ele sem procurar.

   Ele morou no cabecalho, verde e de 72 px, enquanto uma falha intermitente do
   Modo Seguir estava aberta. Ali ele tinha outras regras: entrar na fileira
   para nao cobrir o titulo da peca, e voltar a pairar a 560 px, onde o titulo
   some. As duas sairam junto com ele — eram regras sobre um lugar em que ele
   nao esta mais, e regra que sobra e regra que um dia ganha de outra calada. */
.fab {
  flex: 0 0 auto;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  border: none;
  background: var(--escuro-texto);
  color: var(--tinta);
  font-size: 20px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.fab:hover { filter: brightness(.92); }

.fab:active { transform: scale(.96); }

@media (prefers-reduced-motion: reduce) {
  .fab:active { transform: none; }
}

/* NA FAIXA DE PAISAGEM a pastilha existe, mas cede a contagem detalhada.
   Entre 561 e 900 px cabem o voltar, o botao de tocar, o selo, a pastilha e os
   cinco botoes da direita — e o que sobra para o titulo e o que decide se ele
   diz o nome da peca ou tres letras e reticencias. A proporcao fica, porque e
   ela que se le de relance tocando; os tres numeros voltam no resumo ao fim da
   sessao. O rotulo "Acertos" tambem sai, e o `aria-label` continua dizendo. */
@media (min-width: 561px) and (max-width: 900px) {
  #stats-display .tally-grupo,
  #stats-display #acertos-rotulo { display: none; }
  #stats-display.stats { padding: 4px 8px; }
}

.icon-btn:focus-visible,
.control-btn:focus-visible,
.menu-item:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: 3px;
}

/* No transporte escuro o anel verde do resto do app some contra `--tinta`:
   calculado pela formula de luminancia relativa, `--dominio` sobre `--tinta`
   da 2,78:1, abaixo dos 3:1 que um indicador de foco precisa. Branco sobre
   `--tinta` da 17,79:1. O anel aqui e branco, com o mesmo afastamento. */
.fab:focus-visible {
  outline: 2px solid var(--escuro-texto);
  outline-offset: 3px;
}

/* Partitura e a linha do agora -------------------------------------------- */
#score-stage {
  position: relative;
  display: flex;
  flex-direction: column;
  /* `min-height: 0` e o que permite a faixa 1fr encolher: sem isto o conteudo
     define um piso e a grade estoura a janela em tela curta. */
  min-height: 0;
}


/* A linha vive dentro do `#painel-corpo`, que e exatamente a caixa da pauta.
   A geometria horizontal NAO mudou: o painel tem 16 px de margem de cada lado,
   entao `100% * frac` medido aqui dentro cai no mesmo pixel que o antigo
   `16px + (100% - 32px) * frac` medido no palco. O que mudou e a vertical — a
   linha comeca no topo da PAUTA, e nao no topo do palco, onde antes cruzava o
   indicador de compasso. A verificacao no 1 e quem diz se o contrato do cursor
   continua de pe. */
/* A linha do agora nao se move durante a execucao — quem anda e a partitura,
   atras dela. O que muda de lugar e a PREFERENCIA de onde ela fica: meio da
   tela ou um terco, escolhida nos ajustes e escrita em `--linha-frac` pelo
   setLinhaPos() do renderer.
   
   Cheguei a trocar por `transform: translateX(calc((100cqw - 32px) * ...))`,
   e os testes passaram — mas por acaso: `cqw` sem `container-type` resolve
   contra a janela, e hoje o `#score-stage` ocupa a largura toda. Quando a
   barra lateral entrar, a linha iria para o lugar errado, e nenhum teste de
   hoje acusaria. `left: calc()` mede o bloco que contem de verdade. */
#play-line {
  position: absolute;
  left: calc(100% * var(--linha-frac));
  top: 0;
  bottom: 0;
  width: 3px;
  transform: translateX(-50%);
  background: var(--dominio);
  box-shadow: 0 0 0 10px rgba(var(--dominio-rgb), .12);
  pointer-events: none;
  z-index: 3;
}

#play-line::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -1px;
  transform: translateX(-50%);
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
  border-top: 11px solid var(--dominio);
}

/* A CONTAGEM DE ENTRADA, sobre a linha do agora.
   Ela fica onde o olho ja esta — na linha —, e nao num canto da tela. O numero
   e grande porque e para ser lido de relance com as maos no teclado, e some
   sozinho quando a peca comeca. O circulo em `--agora` e a mesma marca da
   linha: a cor nunca e a unica pista, e o numero esta escrito dentro dele. */
#contagem-entrada {
  position: absolute;
  left: calc(100% * var(--linha-frac));
  top: 50%;
  transform: translate(-50%, -50%);
  width: 84px;
  height: 84px;
  border-radius: 50%;
  background: var(--agora);
  color: var(--escuro-texto);
  font-family: var(--fonte-titulo);
  font-size: 40px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 4;
  box-shadow: 0 0 0 12px var(--agora-fraco);
}

#contagem-entrada.hidden { display: none; }

/* Uma pulsacao por batida, com o mesmo tempo da batida. Ela nao anima altura
   nem posicao: `transform` e `opacity` sao as duas coisas que o navegador
   resolve sem refazer layout, e esta caixa vive sobre a partitura enquanto o
   relogio ja esta prestes a andar. */
#contagem-entrada.batendo {
  animation: entrada-bate var(--duracao-batida, 500ms) ease-out;
}

@keyframes entrada-bate {
  from { transform: translate(-50%, -50%) scale(1.18); }
  to   { transform: translate(-50%, -50%) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  #contagem-entrada.batendo { animation: none; }
}

/* No modo MIDI não há partitura para alinhar, então a linha sai. */
#score-stage.modo-midi #play-line { display: none; }

/* Fichas de estado -------------------------------------------------------- */
.chip {
  font-family: var(--fonte-mono);
  font-size: 13px;
  color: var(--tinta);
  background: var(--trilho);
  border-radius: 999px;
  padding: 9px 14px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

#measure-indicator.chip,
#bpm-display.chip {
  min-width: 0;
}

.stats {
  display: flex;
  gap: 8px;
}

.tally {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
}

.dot-good { background: var(--dominio); }
.dot-bad  { background: var(--agora); }
.dot-none { background: var(--tinta-fraca); }

/* Menus suspensos --------------------------------------------------------- */
/*
 * O que não se toca durante a execução mora aqui. Foi assim que a barra
 * deixou de precisar de 1030px e de sumir no iPad em pé.
 */
.popover {
  position: absolute;
  top: 74px;
  right: 16px;
  z-index: 20;
  width: min(330px, calc(100vw - 32px));
  padding: 8px;
  background: var(--superficie);
  border: 1px solid var(--trilho);
  border-radius: var(--raio-xg);
  box-shadow: var(--sombra-2);
}

.menu-label {
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--tinta-fraca);
  padding: 12px 14px 6px;
}

.menu-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 52px;
  padding: 14px;
  border: none;
  border-radius: var(--raio-btn);
  background: transparent;
  color: var(--tinta);
  font-family: var(--fonte-ui);
  font-size: 15px;
  text-align: left;
  cursor: pointer;
}

.menu-item:hover { background: var(--trilho); }

.menu-item.sel {
  color: var(--dominio);
  background: var(--dominio-fraco);
  font-weight: 600;
}

.menu-item input[type="checkbox"] {
  width: 20px;
  height: 20px;
  accent-color: var(--dominio);
  cursor: pointer;
}

.menu-item .glyph {
  width: 24px;
  text-align: center;
  flex: 0 0 auto;
}

.menu-sep {
  height: 1px;
  background: var(--trilho);
  margin: 6px 10px;
}

.menu-slider {
  padding: 10px 14px 14px;
}

.menu-slider label {
  display: block;
  font-size: 13px;
  color: var(--tinta-fraca);
  margin-bottom: 8px;
}

.menu-slider input[type="range"] { width: 100%; }

/* ==========================================================================
   Aviso de erro — o que era alert() do navegador
   ========================================================================== */

#erro-aviso {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--veu-forte);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.erro-cartao {
  width: min(460px, 100%);
  padding: 28px;
  border-radius: var(--raio-xg);
  background: var(--superficie);
  border: 1px solid var(--trilho);
  box-shadow: var(--sombra-2);
}

.erro-marca {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--agora);
  margin-bottom: 10px;
}

#erro-titulo {
  font-size: 22px;
  font-weight: 600;
  margin-bottom: 10px;
  overflow-wrap: anywhere;
}

/*
 * O motivo aparece inteiro, e em fonte de código: quase sempre é uma resposta
 * de rede ou uma queixa do OSMD, e é exatamente esse texto que serve para
 * procurar o defeito depois. Resumir aqui seria esconder a única pista.
 */
.erro-detalhe {
  font-family: var(--fonte-mono);
  font-size: 13px;
  line-height: 1.5;
  color: var(--tinta-fraca);
  background: var(--fundo);
  border-radius: var(--raio-i);
  padding: 12px 14px;
  max-height: 180px;
  overflow-y: auto;
  overflow-wrap: anywhere;
  user-select: text;
}

.erro-acoes {
  display: flex;
  justify-content: flex-end;
  margin-top: 20px;
}

/* Saída da tela de falha do catálogo: sem a tela de entrada, é o único
   caminho que resta quando o library.json não carrega. */
.catalogo-saida {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 360px;
  margin: 0 auto;
}

/* ==========================================================================
   Marcador de trecho — escolher compassos com o dedo
   ========================================================================== */

/* A camada vive dentro do conteúdo que rola, e não sobre a janela: assim a
   faixa acompanha a partitura em vez de ficar parada na tela. */
#osmd-container {
  position: relative;
}

#marcador-camada {
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: 2;
  pointer-events: none;
}

/* Cinza, como texto marcado — e não a cor de acento. O destaque aqui é dizer
   "é isto que vai repetir", não chamar atenção para si. */
.marcador-faixa {
  position: absolute;
  inset: 0;
  background: rgba(var(--dominio-rgb), .10);
  border-left: 2px solid var(--dominio);
  border-right: 2px solid var(--dominio);
}

/* As alças e o ✕ vivem presos à janela, e não à partitura que rola: com um
   trecho maior que a tela, a ponta do fim ficava fora do campo visível e não
   havia como alcançá-la. Quando a ponta some, a alça encosta na borda. */
.marcador-alca,
.marcador-limpar {
  position: absolute;
  transform: translate(-50%, -50%);
  z-index: 6;
  padding: 0;
  cursor: pointer;
  touch-action: none;
}

.marcador-alca {
  width: 44px;
  height: 76px;
  border: none;
  border-radius: 10px;
  background: var(--superficie);
  color: var(--dominio);
  font-size: 19px;
  line-height: 1;
  cursor: ew-resize;
  box-shadow: var(--sombra-2);
}

/* Presa na borda: a ponta do trecho está fora da tela. O tom mais forte diz
   que aquela alça não está sobre a ponta, e sim esperando por ela. */
.marcador-alca-presa {
  background: var(--dominio);
  color: var(--escuro-texto);
}

.marcador-limpar {
  width: 52px;
  height: 52px;
  border: 2px solid var(--superficie);
  border-radius: 50%;
  background: var(--tinta);
  color: var(--escuro-texto);
  font-size: 19px;
}

.marcador-alca:focus-visible,
.marcador-limpar:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: 3px;
}

/* Ficha "quem toca agora" e a nota explicativa do acompanhamento.
   As duas existem porque o silêncio do Modo Seguir é proposital e invisível —
   e porque num iPad não há ponteiro para pousar sobre um `title`. */
#quem-toca {
  background: transparent;
  border: 1px solid var(--trilho);
  color: var(--tinta-fraca);
  font-family: var(--fonte-ui);
  font-size: 12px;
}

#quem-toca.chip-silencio {
  border-style: dashed;
}

.menu-nota {
  padding: 0 14px 12px 50px;
  margin-top: -6px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--tinta-fraca);
}

/* ---------------------------------------------------------------------------
   O que o normalizador mexeu na peca.
   Fica sob a barra de cima, discreta, sem bloquear a partitura: e informacao,
   e nao obstaculo. Mas visivel — o silencio e que seria o defeito.
   --------------------------------------------------------------------------- */
/* O que o normalizador mexeu nesta peca: um selo no cabecalho.
   ---------------------------------------------------------------------------
   Era uma faixa `fixed` no rodape, com ate 680 px de largura e a frase inteira
   a vista. Ela ja tinha saido do topo porque tapava o teclado; embaixo passou a
   competir com o transporte, e numa janela curta cobria os dois. E uma faixa
   daquele tamanho para uma informacao que a maioria das pecas nao tem e desenho
   caro: ocupa espaco permanente por um caso ocasional.

   Aqui e um selo do tamanho de um botao, ao lado dos outros do cabecalho, e a
   frase inteira mora na lista que ele abre. Mesma informacao, sem cobrir a
   partitura.

   `relative` porque a lista se ancora nele. */
#ajustes-aviso {
  position: relative;
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: 8px;
}

#ajustes-aviso.hidden { display: none; }

#btn-ajustes-resumo {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  /* 44 de altura, como todo alvo de toque deste app. Estes dois botoes nunca
     tinham sido medidos: viviam fora do `#app-bar` e do `#controls-bar`, e a
     varredura de alvos so olha esses dois. Mudar de lugar os revelou com 40 e
     21 px. */
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid var(--aviso-fio);
  border-radius: var(--raio-i);
  background: var(--aviso-fundo);
  color: var(--aviso-tinta);
  font-family: var(--fonte-ui);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  white-space: nowrap;
}

#btn-ajustes-fechar {
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--raio-i);
  background: transparent;
  color: var(--tinta-fraca);
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.7;
}
#btn-ajustes-fechar:hover { opacity: 1; }

/* A lista aberta e uma folha ancorada no selo, e nao mais uma parte da faixa.
   Alinhada a esquerda dele para nao sair da tela quando o cabecalho e estreito. */
#ajustes-lista {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 41;
  width: max-content;
  max-width: min(420px, calc(100vw - 32px));
  max-height: 50vh;
  overflow-y: auto;
  margin: 0;
  padding: 12px 14px 12px 30px;
  border-radius: var(--raio-btn);
  background: var(--superficie);
  border: 1px solid var(--fio);
  box-shadow: var(--sombra-2);
  color: var(--tinta);
  font-size: 13px;
}

#ajustes-lista.hidden { display: none; }

/* Em tela estreita o selo perde o texto e fica so o ponto.
   ---------------------------------------------------------------------------
   Medido: a 360 px de largura o selo com "3 ajustes" empurrava o cabecalho
   alem da janela e a PAGINA passava a rolar de lado — o defeito que a secao 30
   verifica em quatro larguras, e que apareceu no mesmo minuto em que o selo
   entrou ali.

   O texto sai, o ponto fica, e o alvo continua com 44 px. Quem usa leitor de
   tela nao perde nada: a frase inteira esta no `aria-label` do botao, que nao
   depende de haver texto visivel. */
@media (max-width: 560px) {
  #ajustes-aviso { margin-left: 0; }

  #btn-ajustes-resumo {
    width: 44px;
    padding: 0;
    justify-content: center;
    font-size: 0;
    gap: 0;
  }

  #ajustes-lista { left: auto; right: 0; }
}
#ajustes-lista li { margin-bottom: 8px; line-height: 1.45; }
#ajustes-lista li:last-child { margin-bottom: 0; }

#ajustes-lista li .ajuste-regra {
  font-weight: 600;
  opacity: 0.7;
  margin-right: 4px;
}

#ajustes-lista li.ajuste-limitacao { color: var(--tinta-fraca); }
#ajustes-lista li.ajuste-limitacao .ajuste-regra { font-weight: 500; }

/* O ponto do selo, e a pulsacao de uma vez so.
   ---------------------------------------------------------------------------
   Um selo pequeno no meio de quatro botoes de icone passa despercebido, e a
   informacao que ele carrega — o app mexeu na sua partitura — e justamente a
   que nao pode passar. Uma pulsacao ao abrir a peca chama o olho uma vez.

   UMA VEZ, e nao continuamente: um elemento que pisca sem parar vira ruido que
   se aprende a ignorar em dois minutos, e ainda atrapalha quem esta lendo a
   partitura ao lado. */
.ajustes-ponto {
  /* `inline-block`, e nao `flex: 0 0 auto`.
     O ponto e filho do `<span id="ajustes-resumo">`, que e inline — e num
     elemento inline `width` e `height` nao valem nada. Ele existia no DOM,
     media 0x0 e nao aparecia; o selo saia so com o texto. */
  display: inline-block;
  vertical-align: middle;
  width: 7px;
  height: 7px;
  margin-right: 7px;
  border-radius: 50%;
  background: var(--agora);
}

@keyframes ajustes-chamar {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.9); opacity: 0.55; }
}

/* O ponto de LIMITACAO e vazado, e nao cheio.
   Ajuste e coisa que o app fez; limitacao e coisa que o app so constatou — uma
   peca que provavelmente nao cabe nas maos. A cor e a mesma; a forma distingue
   as duas sem depender de cor nenhuma. */
.ajustes-ponto.limite {
  background: transparent;
  border: 2px solid var(--agora);
}

#ajustes-aviso.chamando .ajustes-ponto {
  animation: ajustes-chamar 1.1s ease-in-out 2;
}

@media (prefers-reduced-motion: reduce) {
  #ajustes-aviso.chamando .ajustes-ponto { animation: none; }
}

/* ---------------------------------------------------------------------------
   A capa do cartao.
   Duas camadas: o campo desenhado, que nunca falha, e a fotografia por cima
   quando existir. A pauta de cinco linhas e a inicial do compositor sao o
   desenho — sobrios de proposito, porque sao miniaturas e um catalogo de mil
   quadrinhos berrantes e ilegivel.
   --------------------------------------------------------------------------- */
.card-capa {
  position: relative;
  overflow: hidden;
  background: linear-gradient(140deg, var(--capa-a, var(--capa-1)), var(--capa-b, var(--capa-2)));
  isolation: isolate;
}

/* A pauta. */
.card-capa::before {
  content: "";
  position: absolute;
  inset: 30% 12% 30% 12%;
  background: repeating-linear-gradient(
    to bottom,
    var(--capa-brilho) 0 1px,
    transparent 1px 25%
  );
  z-index: 1;
}

/* A fotografia, quando existir, cobre tudo — e escurece um pouco, para a
   inicial continuar legivel sobre qualquer foto. */
.card-capa-foto {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 3;
  /* Sem texto por cima, a foto nao precisa mais ser escurecida. Fica so um
     leve recuo de saturacao, para o catalogo nao virar vitrine. */
  filter: saturate(0.88);
}
/* Com foto, a pauta desenhada some: ela e o motivo da capa vazia, e por cima
   de uma fotografia vira sujeira. */
.card-capa:has(.card-capa-foto)::before { opacity: 0; }

/* Filtro com muitos valores: lista de escolha em vez de faixa de pastilhas.
   145 compositores nao cabem numa faixa; numa lista cabem, e o sistema ja a
   desenha bem no iPad. */
.filtro-escolha {
  width: 100%;
  max-width: 420px;
  padding: 9px 12px;
  border-radius: var(--raio-i);
  background: var(--superficie);
  border: 1px solid var(--trilho);
  color: var(--tinta);
  font-family: var(--fonte-ui);
  font-size: 14px;
}
.filtro-escolha:focus-visible { outline: 2px solid var(--dominio); outline-offset: 2px; }

/* O botao que pede o proximo bloco de cartoes. E um botao de verdade, e nao
   uma sentinela invisivel: se o observador nao rodar — aba em segundo plano,
   pagina sem compositar quadros — o dedo continua tendo o que tocar. */
.catalogo-mais {
  display: block;
  width: 100%;
  margin-top: 12px;
  padding: 12px;
  border-radius: var(--raio-i);
  background: var(--superficie);
  border: 1px dashed var(--trilho);
  color: var(--tinta-fraca);
  font-family: var(--fonte-ui);
  font-size: 14px;
  cursor: pointer;
}
.catalogo-mais:hover { border-color: var(--dominio); color: var(--tinta); }
.catalogo-mais:focus-visible { outline: 2px solid var(--dominio); outline-offset: 2px; }

/* Botão de excluir partitura pessoal do usuário */
/* Excluir flutua sobre a capa, no canto oposto ao selo de duracao.
   `margin-left: auto` empurrava-o para a ponta da LINHA; num cartao em pe isso
   virava uma faixa de 44 px atravessada embaixo do texto. Sobre a capa ele nao
   ocupa altura nenhuma do cartao — e continua com os 44x44 que o dedo pede.
   O fundo e opaco pelo mesmo motivo do selo: por baixo passa foto clara e foto
   escura, e so assim o icone se ve nas duas. */
.card-delete-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 4;
  background: var(--veu-capa);
  border: none;
  color: var(--escuro-texto);
  font-size: 16px;
  padding: 8px;
  cursor: pointer;
  border-radius: var(--raio-i);
  transition: background var(--transition-fast);
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.card-delete-btn:hover {
  background: var(--erro);
}

.card-delete-btn:focus-visible {
  outline: 2px solid var(--escuro-texto);
  outline-offset: -2px;
}
.card-delete-btn:hover {
  color: var(--agora);
  background: var(--erro-sopro);
}

/* Onboarding Modal */
.onboarding-overlay {
  position: fixed;
  inset: 0;
  background: var(--veu);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.onboarding-overlay.hidden {
  display: none !important;
}

.onboarding-card {
  background: var(--superficie);
  border: 1px solid var(--trilho);
  border-radius: var(--raio-xg);
  max-width: 480px;
  width: 100%;
  padding: 28px;
  box-shadow: var(--sombra-2);
  animation: modalFadeIn 0.3s ease-out;
}

@keyframes modalFadeIn {
  from { opacity: 0; transform: translateY(16px) scale(0.97); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.onboarding-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24px;
}

.onboarding-dots {
  display: flex;
  gap: 8px;
}

.onboarding-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--trilho);
  transition: background var(--transition-fast);
}

.onboarding-dot.active {
  background: var(--dominio);
  width: 24px;
  border-radius: 10px;
}

.onboarding-skip {
  background: transparent;
  border: none;
  color: var(--tinta-fraca);
  font-size: 14px;
  font-family: var(--fonte-ui);
  cursor: pointer;
  padding: 6px 10px;
  border-radius: var(--raio-i);
}
.onboarding-skip:hover {
  color: var(--tinta);
}

.onboarding-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 16px;
}

.onboarding-icon {
  font-size: 48px;
  line-height: 1;
}

.onboarding-body h2 {
  font-size: 22px;
  font-weight: 600;
  color: var(--tinta);
}

.onboarding-desc {
  font-size: 15px;
  line-height: 1.5;
  color: var(--tinta-fraca);
}

.onboarding-actions {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
  margin-top: 12px;
}

.onboarding-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  margin-top: 8px;
}

.onboarding-btn {
  width: 100%;
  min-height: 48px;
  font-size: 15px;
  font-weight: 500;
}

/* Practice Summary Overlay ------------------------------------------------ */
/* O resumo de fim de sessao.
   ---------------------------------------------------------------------------
   O cartao pedia `var(--bg-surface, #1e2433)` e `var(--radius-lg, 16px)` —
   fichas de uma paleta que o redesenho aposentou. Como elas nao existem mais no
   `:root`, valia a RESERVA: um cartao azul-escuro no meio de uma interface de
   papel claro, com o texto claro que o acompanhava. Ninguem tinha visto porque
   a tela so aparece ao terminar uma peca inteira.

   Aqui ele usa as fichas de verdade, e nenhuma reserva embutida: ficha que nao
   existe passa a aparecer como defeito, em vez de se disfarcar de cor. */
.resumo-veu {
  position: fixed;
  inset: 0;
  background: var(--veu);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 1000;
  animation: fadeIn 0.25s ease-out;
}

.resumo-veu.hidden { display: none; }

.resumo-cartao {
  width: 100%;
  max-width: 440px;
  padding: 28px 26px 24px;
  display: flex;
  flex-direction: column;
  gap: 22px;
  background: var(--superficie);
  border: 1px solid var(--fio);
  border-radius: var(--raio-xg);
  color: var(--tinta);
  box-shadow: var(--sombra-2);
}

.resumo-cabeca { display: flex; flex-direction: column; gap: 4px; }

.resumo-cabeca h2 {
  font-family: var(--fonte-titulo);
  font-size: 30px;
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.resumo-peca {
  font-size: 15px;
  color: var(--tinta-fraca);
}

/* Quatro numeros em duas colunas. Em quatro colunas o "100%" da precisao
   ficaria do tamanho do "0:47" do tempo, e o que interessa deixaria de saltar. */
.resumo-numeros {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.resumo-dado {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 14px 16px;
  border-radius: var(--raio-btn);
  background: var(--fundo);
}

.resumo-dado.destaque { background: var(--dominio-fraco); }

.resumo-valor {
  font-family: var(--fonte-titulo);
  font-size: 26px;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.resumo-dado.destaque .resumo-valor { color: var(--dominio); }
.resumo-dado.certo .resumo-valor { color: var(--dominio); }

/* O erro NAO ganha um vermelho novo.
   `--agora` e a cor que este app usa para "aqui, agora" — a linha do agora, a
   nota que soa, a proposta de repetir. Erro e onde se vai estudar em seguida, e
   nao uma reprovacao; vermelho de alerta diria a outra coisa. O `--erro` fica
   reservado para o que impede o app de funcionar. */
.resumo-dado.errado .resumo-valor { color: var(--agora); }

.resumo-rotulo {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--tinta-fraca);
}

.resumo-achados {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 18px;
  border-top: 1px solid var(--fio);
}

.resumo-achado {
  font-size: 14px;
  line-height: 1.45;
  color: var(--tinta-media);
}

.resumo-achado-rotulo {
  display: block;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--tinta-fraca);
  margin-bottom: 2px;
}

.resumo-achado.bom .resumo-achado-rotulo { color: var(--dominio); }

.resumo-rodape {
  display: flex;
  gap: 10px;
}

/* O gesto de cor que a interface repete: tinta em repouso, dominio ao toque. */
.resumo-btn {
  flex: 1 1 auto;
  min-height: 56px;
  padding: 0 20px;
  border: none;
  border-radius: var(--raio-btn);
  background: var(--tinta);
  color: var(--escuro-texto);
  font-family: var(--fonte-ui);
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition-fast);
}

.resumo-btn:hover { background: var(--dominio); }
.resumo-btn:focus-visible { outline: 2px solid var(--dominio); outline-offset: 3px; }

.resumo-btn-secundario {
  flex: 0 0 auto;
  min-height: 56px;
  padding: 0 16px;
  border: 1px solid var(--fio);
  border-radius: var(--raio-btn);
  background: var(--superficie-2);
  color: var(--tinta);
  font-family: var(--fonte-ui);
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}

.resumo-btn-secundario:hover {
  background: var(--dominio-fraco);
  border-color: var(--dominio);
}

.resumo-btn-secundario:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: 3px;
}


/* ============================================================
   Ícones desenhados
   ============================================================
   Antes os ícones eram caracteres, e cada aparelho os desenhava com a fonte
   que tinha: no iPad, ✋ e 🤚 saíam como emoji coloridos ao lado de glifos
   monocromáticos, com pesos que não combinavam. Agora são SVG do próprio app.

   O tamanho vem do `font-size` do botão (o SVG mede 1em), então toda a régua
   de tamanhos que já existia continua valendo, sem uma segunda tabela. */
.icone {
  width: 1em;
  height: 1em;
  /* `inline-block` e nao `block`: o mesmo icone precisa servir dentro de um
     botao em flex E no meio de um titulo, sem quebrar a linha. */
  display: inline-block;
  vertical-align: -0.125em;
  flex: none;
  /* O traço não pode engrossar junto com o ícone quando ele cresce. */
  vector-effect: non-scaling-stroke;
}

/* A mão é um desenho só, espelhado. Duas cópias seriam duas chances de ficarem
   diferentes na próxima vez que alguém mexer numa delas. */
#btn-hand-left .icone { transform: scaleX(-1); }

/* Dentro de um item de menu o ícone fica ao lado do texto, e precisa da mesma
   caixa que o `.glyph` de antes ocupava, senão o menu perde o alinhamento. */
.menu-item .glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25em;
}

/* Selo de licença restrita no cartão do catálogo.
   Só aparece em peça cujo acervo proíbe uso comercial — hoje, o ASAP. É o que
   torna visível, sem abrir nada, quais peças sairiam se o app passasse a
   cobrar. As peças em CC0 não ganham selo: não há o que ressalvar. */
.card-licenca {
  display: inline-block;
  margin-top: 2px;
  padding: 1px 6px;
  border-radius: 999px;
  /* Duas fichas mortas com reserva de paleta escura, como as da secao de
     Cursos: `--borda` e `--text-secondary` nao existem no `:root` desde o
     commit 5 do handoff, e o selo saía com contorno branco translucido e texto
     cinza-claro sobre o cartao claro. */
  border: 1px solid var(--fio-forte);
  font-size: 0.66rem;
  letter-spacing: 0.02em;
  color: var(--tinta-fraca);
  white-space: nowrap;
}

/* ============================================================
   Cursos Interativos: grandes cards, videos e exercicios
   ============================================================
   ESTA SECAO FOI ESCRITA PARA A PALETA ESCURA ANTIGA, e sobreviveu a ela.

   Os nomes das fichas continuaram; os significados inverteram. `--tinta` era o
   texto BRANCO de uma pagina escura e hoje e a tinta quase-preta do papel — e
   as regras daqui pediam `var(--tinta, #ffffff)` sobre `var(--bg-surface,
   #181d28)`. Medido antes do conserto: titulo do modulo em rgb(22,24,27) sobre
   cartao rgb(24,29,40), e o chip de nivel ativo com texto rgb(17,20,28) sobre
   fundo rgb(22,24,27). Quase-preto sobre quase-preto, ilegivel nos dois casos.

   Duas causas, e a segunda e a que interessa:

   1. `--bg-surface`, `--radius-md`, `--radius-lg`, `--borda` e
      `--text-secondary` sao apelidos que o commit 5 do handoff removeu do
      `:root`. Ficha que nao existe faz valer a RESERVA, e as reservas aqui
      eram as cores escuras: o cartao continuou escuro sem que nada acusasse.

   2. Onde a ficha existe, a reserva nunca dispara — e foi por isso que o
      defeito passou meses invisivel. `var(--tinta, #ffffff)` resolve para a
      tinta nova, correta como cor e errada como PAPEL: era texto de fundo
      escuro aplicado sobre fundo claro.

   Por isso nao ha nenhuma reserva de cor nesta secao. Ficha que morrer daqui
   para frente deixa a regra invalida e aparece na primeira olhada, em vez de se
   disfarcar. O teste da secao 36 falha se alguma voltar.

   O leitor de video continua ESCURO de proposito: ali o escuro e a tela do
   video, e nao sobra de paleta. Ele usa as fichas `--escuro-*`, as mesmas do
   bloco do teclado e do transporte. */

.cursos-niveis-bar {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
  overflow-x: auto;
  padding-bottom: 4px;
  -webkit-overflow-scrolling: touch;
}

.curso-nivel-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 10px 18px;
  border-radius: var(--raio-btn);
  border: 1px solid var(--fio);
  background: var(--superficie);
  color: var(--tinta-media);
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 500;
  cursor: pointer;
  transition: border-color var(--transition-fast), color var(--transition-fast),
              background var(--transition-fast);
  white-space: nowrap;
}

.curso-nivel-btn .nivel-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--trilho);
  font-size: 0.8rem;
  font-weight: 700;
}

.curso-nivel-btn:hover {
  border-color: var(--fio-forte);
  color: var(--tinta);
}

.curso-nivel-btn:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: 2px;
}

/* Ativo: invertido, como o botao primario da interface. O texto vai em
   `--escuro-texto`, e nao no `#11141c` de antes — aquele numero era o FUNDO da
   pagina escura, usado como cor de texto sobre um fundo que naquela epoca era
   branco. Com a paleta nova ele virou quase-preto sobre quase-preto. */
.curso-nivel-btn.on {
  background: var(--tinta);
  color: var(--escuro-texto);
  border-color: var(--tinta);
}

.curso-nivel-btn.on .nivel-num {
  background: var(--escuro-fio-btn);
  color: var(--escuro-texto);
}

.curso-nivel-banner {
  background: var(--superficie-2);
  border: 1px solid var(--fio);
  border-radius: var(--raio-g);
  padding: 20px 24px;
  margin-bottom: 28px;
}

.curso-nivel-banner h3 {
  margin: 0 0 6px 0;
  font-family: var(--fonte-titulo);
  font-size: 1.5rem;
  font-weight: 400;
  color: var(--tinta);
}

.curso-nivel-banner .nivel-subtitulo {
  margin: 0;
  font-size: 0.95rem;
  color: var(--tinta-fraca);
  line-height: 1.45;
}

.cursos-trilha {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

/* Card do Módulo */
.modulo-card {
  background: var(--superficie);
  border: 1px solid var(--fio);
  border-radius: var(--raio-g);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.modulo-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--fio);
}

.modulo-badge {
  display: inline-block;
  padding: 3px 8px;
  border-radius: 6px;
  background: var(--trilho);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--tinta-media);
  margin-bottom: 6px;
}

.modulo-titulo {
  margin: 0 0 4px 0;
  font-family: var(--fonte-titulo);
  font-size: 1.4rem;
  font-weight: 400;
  color: var(--tinta);
}

.modulo-subtitulo {
  margin: 0;
  font-size: 0.9rem;
  color: var(--tinta-fraca);
}

.modulo-progresso-grupo {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 120px;
}

.modulo-progresso-barra-fundo {
  flex: 1;
  height: 8px;
  background: var(--trilho);
  border-radius: 999px;
  overflow: hidden;
}

/* Progresso e DOMINIO, e nao `--agora`.
   A ficha `--agora` marca "aqui, neste instante" — a linha do agora, a nota que
   soa, a proposta de repetir. Barra de progresso e o quanto ja saiu, que e o
   verde de dominio. A regra antiga pedia `var(--agora, #48bb78)`: verde na
   reserva, laranja na ficha. As duas cores para a mesma coisa. */
.modulo-progresso-barra-preenchimento {
  height: 100%;
  background: var(--dominio);
  border-radius: 999px;
  transition: width 0.4s ease;
}

.modulo-progresso-texto {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--tinta-media);
  font-variant-numeric: tabular-nums;
}

/* Grade de Grandes Cards de Aula */
.modulo-aulas-grand-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 20px;
}

@media (min-width: 860px) {
  .modulo-aulas-grand-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.aula-grand-card {
  background: var(--fundo);
  border: 1px solid var(--fio);
  border-radius: var(--raio-m);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: transform 0.2s ease, border-color 0.2s ease;
}

.aula-grand-card:hover {
  border-color: var(--fio-forte);
  transform: translateY(-2px);
}

@media (prefers-reduced-motion: reduce) {
  .aula-grand-card:hover { transform: none; }
}

.aula-grand-card.concluida {
  border-color: var(--dominio);
}

/* O leitor de vídeo: escuro de propósito ------------------------------------
   Aqui o escuro não é sobra de paleta — é a tela do vídeo. Usa as fichas
   `--escuro-*`, as mesmas do bloco do teclado e do transporte, para o dia em
   que o tema escuro do apêndice A entrar e elas mudarem de uma vez. */
.aula-video-container {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--tinta);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

.aula-video-mockup {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: var(--tinta);
  position: relative;
  padding: 16px;
  text-align: center;
}

.video-overlay-badge {
  position: absolute;
  top: 10px;
  right: 10px;
  background: var(--veu-forte);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  padding: 3px 8px;
  border-radius: 6px;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--escuro-texto);
  display: flex;
  align-items: center;
  gap: 5px;
  z-index: 2;
}

.video-preview-visual {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  z-index: 1;
}

.video-icone-central {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--escuro-fio-btn);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--escuro-texto);
  font-size: 1.2rem;
  transition: transform 0.2s ease, background 0.2s ease;
}

.aula-grand-card:hover .video-icone-central {
  transform: scale(1.1);
  background: var(--escuro-fio-btn-hover);
}

@media (prefers-reduced-motion: reduce) {
  .aula-grand-card:hover .video-icone-central { transform: none; }
}

/* Legenda SOBRE o vídeo: `--escuro-legenda`, e não `--tinta-fraca`.
   `--tinta-fraca` é cinza de papel claro; sobre a tela escura do vídeo ficava
   em 1,8:1. */
.video-legenda-ia {
  font-size: 0.8rem;
  color: var(--escuro-legenda);
  max-width: 90%;
  line-height: 1.35;
}

.aula-info-container {
  padding: 18px;
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 10px;
}

.aula-tag-linha {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.aula-numero-tag {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--tinta-fraca);
}

.aula-status-tag.ok {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--dominio);
  background: var(--dominio-fraco);
  padding: 2px 7px;
  border-radius: 4px;
}

.aula-titulo {
  margin: 0;
  font-family: var(--fonte-titulo);
  font-size: 1.2rem;
  font-weight: 400;
  color: var(--tinta);
}

.aula-conceito {
  margin: 0;
  font-size: 0.88rem;
  color: var(--tinta-media);
  line-height: 1.45;
}

.aula-dicas-lista {
  margin: 4px 0 10px 0;
  padding-left: 18px;
  font-size: 0.82rem;
  color: var(--tinta-fraca);
  line-height: 1.4;
}

.aula-dicas-lista li {
  margin-bottom: 4px;
}

.aula-praticar-btn {
  margin-top: auto;
  width: 100%;
  min-height: 44px;
  padding: 10px 14px;
  border-radius: var(--raio-i);
  border: 1px solid var(--fio);
  background: var(--superficie);
  color: var(--tinta);
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: background var(--transition-fast), color var(--transition-fast),
              border-color var(--transition-fast);
}

.aula-praticar-btn:hover {
  background: var(--tinta);
  color: var(--escuro-texto);
  border-color: var(--tinta);
}

.aula-praticar-btn:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: 2px;
}

/* Música de Conclusão */
.modulo-musica-conclusao {
  background: var(--agora-fraco);
  border: 1px solid var(--fio);
  border-radius: var(--raio-m);
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

@media (min-width: 640px) {
  .modulo-musica-conclusao {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

.musica-conclusao-header {
  display: flex;
  align-items: center;
  gap: 14px;
}

.musica-trofeu-icone {
  font-size: 1.8rem;
  color: var(--agora);
  flex: none;
}

/* O rótulo em versalete vai em `--tinta-media`, e não em `--agora`.
   Laranja sobre papel claro dá 2,9:1, e isto é texto de 0,72rem em maiúsculas —
   abaixo dos 4,5:1 que a seção 6 do handoff exige. A cor fica no ícone, que é
   grande, e o texto fica legível. */
.musica-conclusao-tag {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--tinta-media);
  margin-bottom: 2px;
}

.musica-conclusao-titulo {
  margin: 0 0 2px 0;
  font-family: var(--fonte-titulo);
  font-size: 1.15rem;
  font-weight: 400;
  color: var(--tinta);
}

.musica-autor {
  font-size: 0.9rem;
  color: var(--tinta-fraca);
  font-weight: 400;
}

.musica-conclusao-desc {
  margin: 0;
  font-size: 0.84rem;
  color: var(--tinta-fraca);
}

/* Texto ESCURO sobre o laranja, e não claro: branco sobre `--agora` dá 3,2:1,
   e a tinta dá 5,5:1. */
.musica-tocar-btn {
  min-height: 44px;
  padding: 10px 18px;
  border-radius: var(--raio-i);
  border: none;
  background: var(--agora);
  color: var(--tinta);
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  white-space: nowrap;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.musica-tocar-btn:hover {
  opacity: 0.92;
  transform: scale(1.02);
}

.musica-tocar-btn:focus-visible {
  outline: 2px solid var(--tinta);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .musica-tocar-btn:hover { transform: none; }
}

/* Banco Permanente de Exercícios Rápidos */
.modulo-exercicios-section {
  background: var(--fundo);
  border: 1px solid var(--fio);
  border-radius: var(--raio-m);
  padding: 16px 18px;
}

.exercicios-section-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
}

.exercicios-raio-icone {
  color: var(--dominio);
  font-size: 1.1rem;
}

.exercicios-section-titulo {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--tinta);
}

.exercicios-rapidos-lista {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
}

@media (min-width: 768px) {
  .exercicios-rapidos-lista {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.exercicio-rapido-item {
  background: var(--superficie);
  border: 1px solid var(--fio);
  border-radius: var(--raio-alt);
  padding: 10px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.ex-item-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.ex-item-titulo {
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--tinta);
}

.ex-item-autor {
  font-size: 0.76rem;
  color: var(--tinta-fraca);
}

.ex-item-desc {
  margin: 2px 0 0 0;
  font-size: 0.78rem;
  color: var(--tinta-fraca);
}

.ex-treinar-btn {
  min-height: 44px;
  padding: 6px 12px;
  border-radius: 6px;
  border: 1px solid var(--fio);
  background: var(--superficie-2);
  color: var(--tinta);
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.ex-treinar-btn:hover {
  background: var(--tinta);
  color: var(--escuro-texto);
}

.ex-treinar-btn:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: 2px;
}

/* Itens em preparação (aguardandoImportacao) */
.aula-praticar-btn.desabilitado,
.ex-treinar-btn.desabilitado,
.musica-tocar-btn.desabilitado,
.curso-video-praticar-btn.desabilitado {
  opacity: 0.55;
  cursor: not-allowed;
  pointer-events: none;
  background: var(--trilho);
  border-color: var(--fio);
  color: var(--tinta-fraca);
}

.aula-destaque-proxima {
  border-color: var(--dominio);
}

.aula-proxima-tag {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--dominio);
  background: var(--dominio-fraco);
  padding: 2px 6px;
  border-radius: 4px;
}

.aula-meta-detalhes {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 6px 0;
  font-size: 0.8rem;
  color: var(--tinta-fraca);
}

.aula-meta-item {
  display: flex;
  gap: 6px;
}

.aula-meta-rotulo {
  font-weight: 600;
  color: var(--tinta-media);
}

.curso-video-stage-aviso {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--escuro-texto);
  margin: 8px 0 4px 0;
}

/* O CELULAR DEITADO NA ESTANTE: altura ate 480 px.
   ===========================================================================
   O handoff pede partitura, teclado e transporte visiveis "em qualquer altura
   acima de 380 px". MEDIDO a 640 x 380, antes desta consulta: barra 72,
   partitura 63, teclado 96, e o transporte com 133 px em DUAS fileiras, mais
   16 de margem — 35 % da tela para os botoes, 17 % para a musica.

   Por que nenhuma regra existente salvava: todas as que compactam o transporte
   sao de LARGURA (ate 560 px). Um celular deitado tem 640 de largura — largo
   demais para a regra de celular, baixo demais para a de tela grande. E as
   unicas consultas de altura do arquivo eram de `min-height`, que AUMENTAM o
   teclado.

   O que muda aqui e o que ja muda a 560 px de largura, pelo mesmo motivo:
   parar, os dois compassos e o metronomo vao para o menu `⋯`, que existe em
   toda largura; a legenda do laco vai para dentro do botao de repetir. Os
   botoes descem para 44 px — o minimo do dedo, e nao menos. O pe do painel
   sai; o andamento, no topo, fica.

   ESTE BLOCO MORA NO FIM DO ARQUIVO, e nao ao lado das outras consultas:
   `.fab`, `.control-btn` e o bloco de 1024 px sao declarados antes, com a mesma
   especificidade. Escrito acima deles, perderia calado — ja aconteceu duas
   vezes neste arquivo, e nas duas so a medicao mostrou.

   Vale tambem para uma janela de computador encolhida a menos de 480 px de
   altura. Ali o efeito e o mesmo, e pelo mesmo motivo: sem ele a partitura
   some. */
@media (max-height: 480px) {
  #app-bar {
    min-height: 52px;
    padding-top: 4px;
    padding-bottom: 4px;
  }

  #controls-bar {
    min-height: 0;
    padding: 4px 12px;
    gap: 8px;
    margin-bottom: 8px;
  }

  #controls-bar .transport-group #btn-stop,
  #controls-bar .measure-group #btn-prev-measure,
  #controls-bar .measure-group #btn-next-measure,
  #controls-bar #btn-metronome { display: none; }

  #controls-bar .control-btn,
  #controls-bar .fab {
    width: 44px;
    height: 44px;
  }

  #laco-legenda { display: none; }

  #btn-loop-toggle {
    width: auto;
    min-width: 44px;
    padding: 0 12px;
    gap: 7px;
  }

  #laco-intervalo:not(.hidden) {
    display: inline;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
  }

  #painel-partitura { margin-bottom: 8px; }
  #partitura-carater { display: none; }

  /* Sem o teclado, o transporte fica sozinho — e ele so arredondava embaixo,
     porque os dois eram um bloco escuro continuo: o teclado fechava em cima, o
     transporte embaixo. Sozinho, ele precisa dos quatro cantos, ou fica com a
     aresta de um bloco que nao esta mais la. */
  #controls-bar { border-radius: var(--raio-xg); }

  /* O TECLADO ILUSTRATIVO CEDE O ESPACO, e nao a musica.
     MEDIDO a 640x380, com a margem de pagina ja zerada: a faixa da partitura
     tem 137 px e o sistema pede 169 — 38 % das pautas. As duas saidas eram
     encolher a musica a 81 % do tamanho, ou recolher os 96 px do teclado.
     Recolhido, a faixa vai a 233 e o sistema cabe inteiro, em tamanho natural.
     Quem esta lendo partitura numa tela de 380 px precisa das pautas; o
     desenho do teclado ali e ilustracao. */
  #piano-container { display: none; }
}


/* ==========================================================================
   OMR — Modal de Importação e Transcrição de Partituras via IA
   ========================================================================== */

.omr-overlay {
  position: fixed;
  inset: 0;
  z-index: 150;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: var(--veu-forte);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.omr-overlay.hidden {
  display: none !important;
}

.omr-card {
  width: min(520px, 100%);
  background: var(--superficie);
  border: 1px solid var(--trilho);
  border-radius: var(--raio-xg);
  box-shadow: var(--sombra-2);
  padding: 30px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  animation: omrFadeIn 0.25s ease-out;
}

@keyframes omrFadeIn {
  from { opacity: 0; transform: scale(0.96); }
  to { opacity: 1; transform: scale(1); }
}

.omr-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 20px;
  background: var(--dominio-fraco);
  color: var(--dominio);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  width: fit-content;
  margin-bottom: 8px;
}

.omr-badge-erro {
  background: var(--agora-fraco);
  color: var(--agora);
}

.omr-titulo {
  font-family: var(--fonte-titulo);
  font-size: 24px;
  font-weight: 600;
  color: var(--tinta);
  margin: 0;
  line-height: 1.25;
}

.omr-arquivo-nome {
  font-size: 14px;
  color: var(--tinta-fraca);
  margin: 4px 0 0 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.omr-progress-container {
  width: 100%;
  height: 8px;
  background: var(--trilho);
  border-radius: 4px;
  overflow: hidden;
  position: relative;
}

.omr-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--dominio) 0%, var(--agora) 100%);
  border-radius: 4px;
  transition: width 0.4s ease;
}

.omr-steps-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 4px;
}

.omr-step {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 14px;
  border-radius: var(--raio-g);
  transition: all 0.25s ease;
}

.omr-step.ativo {
  background: var(--superficie-2);
  border: 1px solid var(--fio);
}

.omr-step.concluido {
  opacity: 0.85;
}

.omr-step.pendente {
  opacity: 0.45;
}

.omr-step-icon {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 600;
  flex-shrink: 0;
  position: relative;
}

.omr-step.pendente .omr-step-icon {
  background: var(--trilho);
  color: var(--tinta-fraca);
}

.omr-step.pendente .omr-step-spinner,
.omr-step.pendente .omr-step-check {
  display: none;
}

.omr-step.ativo .omr-step-icon {
  background: var(--dominio-fraco);
  color: var(--dominio);
}

.omr-step.ativo .omr-step-num,
.omr-step.ativo .omr-step-check {
  display: none;
}

.omr-step.ativo .omr-step-spinner {
  display: block;
  width: 16px;
  height: 16px;
  border: 2px solid var(--dominio);
  border-top-color: transparent;
  border-radius: 50%;
  animation: omrSpin 0.8s linear infinite;
}

@keyframes omrSpin {
  to { transform: rotate(360deg); }
}

.omr-step.concluido .omr-step-icon {
  background: var(--dominio);
  color: var(--escuro-texto);
}

.omr-step.concluido .omr-step-num,
.omr-step.concluido .omr-step-spinner {
  display: none;
}

.omr-step.concluido .omr-step-check {
  display: block;
}

.omr-step-text {
  font-size: 14px;
  font-weight: 500;
  color: var(--tinta);
}

.omr-rodape {
  display: flex;
  justify-content: flex-end;
  margin-top: 10px;
}

.omr-rodape-erro {
  gap: 10px;
}

.omr-erro-caixa {
  background: var(--fundo);
  border: 1px solid var(--trilho);
  border-radius: var(--raio-i);
  padding: 14px;
  max-height: 160px;
  overflow-y: auto;
}

.omr-erro-detalhe {
  font-family: var(--fonte-mono);
  font-size: 13px;
  line-height: 1.5;
  color: var(--tinta-media);
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Botão de Importar PDF no Catálogo */
/* O BOTAO SO EXISTE COM O `omr` LIGADO, E ONDE HA QUEM CONVERTA.
 *
 * Com o interruptor `omr` desligado (js/recursos.js, o MVP) o botao nem e
 * criado. Ligado, o omr-importer.js escreve no <html> quem pode converter:
 * `data-omr-leitor="aparelho"` quando o leitor vetorial carregou (le PDF
 * vetorial sem servidor), e `data-omr-servidor="local"` quando a sonda achou
 * um servidor. Qualquer dos dois mostra o botao.
 *
 * O padrao e esconder, e nao mostrar: se o script nao carregar, o botao nao
 * aparece, em vez de aparecer quebrado. */
.catalogo-importar-pdf {
  display: none;
}

:root[data-omr-servidor="local"] .catalogo-importar-pdf,
:root[data-omr-leitor="aparelho"] .catalogo-importar-pdf {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 52px;
  padding: 12px 18px;
  border-radius: var(--raio-btn);
  background: var(--dominio-fraco);
  color: var(--dominio);
  border: 1px solid var(--dominio);
  font-family: var(--fonte-ui);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
}

.catalogo-importar-pdf:hover {
  background: var(--dominio);
  color: var(--escuro-texto);
  border-color: var(--dominio);
}

.catalogo-importar-pdf:focus-visible {
  outline: 2px solid var(--dominio);
  outline-offset: 3px;
}


